@shard-for-obsidian/cli 0.2.0 → 0.2.4

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
@@ -989,7 +989,7 @@ async function pushCommand(opts) {
989
989
  digest: mainJsResult.digest,
990
990
  size: mainJsResult.size,
991
991
  annotations: {
992
- "org.opencontainers.image.title": "main.js"
992
+ "vnd.obsidianmd.layer.filename": "main.js"
993
993
  }
994
994
  });
995
995
  logger.log(
@@ -1005,7 +1005,7 @@ async function pushCommand(opts) {
1005
1005
  digest: stylesCssResult.digest,
1006
1006
  size: stylesCssResult.size,
1007
1007
  annotations: {
1008
- "org.opencontainers.image.title": "styles.css"
1008
+ "vnd.obsidianmd.layer.filename": "styles.css"
1009
1009
  }
1010
1010
  });
1011
1011
  logger.log(
@@ -1015,14 +1015,19 @@ async function pushCommand(opts) {
1015
1015
  const githubUrl = deriveGitHubUrl(ref.remoteName);
1016
1016
  const manifest = plugin.manifest.parsed;
1017
1017
  const annotations = {
1018
- "org.opencontainers.image.created": (/* @__PURE__ */ new Date()).toISOString(),
1019
- "org.opencontainers.image.source": githubUrl,
1020
- "org.opencontainers.image.version": manifest.version,
1021
- "org.opencontainers.image.description": manifest.description,
1022
- "org.opencontainers.image.authors": manifest.author
1018
+ "vnd.obsidianmd.plugin.id": manifest.id,
1019
+ "vnd.obsidianmd.plugin.name": manifest.name,
1020
+ "vnd.obsidianmd.plugin.version": manifest.version,
1021
+ "vnd.obsidianmd.plugin.description": manifest.description,
1022
+ "vnd.obsidianmd.plugin.author": manifest.author,
1023
+ "vnd.obsidianmd.plugin.repo": githubUrl,
1024
+ "vnd.obsidianmd.plugin.published-at": (/* @__PURE__ */ new Date()).toISOString()
1023
1025
  };
1024
1026
  if (manifest.authorUrl) {
1025
- annotations["org.opencontainers.image.url"] = manifest.authorUrl;
1027
+ annotations["vnd.obsidianmd.plugin.author-url"] = manifest.authorUrl;
1028
+ }
1029
+ if (manifest.minAppVersion) {
1030
+ annotations["vnd.obsidianmd.plugin.min-app-version"] = manifest.minAppVersion;
1026
1031
  }
1027
1032
  logger.log("Pushing plugin manifest...");
1028
1033
  const manifestPushResult = await client.pushPluginManifest({
@@ -1076,7 +1081,7 @@ async function pullCommand(opts) {
1076
1081
  logger.log(`Wrote manifest.json (${manifestJson.length} bytes)`);
1077
1082
  const files = ["manifest.json"];
1078
1083
  for (const layer of manifest.layers) {
1079
- const filename = layer.annotations?.["org.opencontainers.image.title"];
1084
+ const filename = layer.annotations?.["vnd.obsidianmd.layer.filename"];
1080
1085
  if (!filename) {
1081
1086
  throw new Error(
1082
1087
  `Layer ${layer.digest} missing required filename annotation`
@@ -1297,7 +1302,7 @@ var PluginConverter = class {
1297
1302
  digest: mainJsResult.digest,
1298
1303
  size: mainJsResult.size,
1299
1304
  annotations: {
1300
- "org.opencontainers.image.title": "main.js"
1305
+ "vnd.obsidianmd.layer.filename": "main.js"
1301
1306
  }
1302
1307
  });
1303
1308
  if (pluginData.stylesCss) {
@@ -1309,19 +1314,26 @@ var PluginConverter = class {
1309
1314
  digest: stylesCssResult.digest,
1310
1315
  size: stylesCssResult.size,
1311
1316
  annotations: {
1312
- "org.opencontainers.image.title": "styles.css"
1317
+ "vnd.obsidianmd.layer.filename": "styles.css"
1313
1318
  }
1314
1319
  });
1315
1320
  }
1316
1321
  const annotations = {
1317
- "org.opencontainers.image.created": (/* @__PURE__ */ new Date()).toISOString(),
1318
- "org.opencontainers.image.source": githubRepo,
1319
- "org.opencontainers.image.version": pluginData.manifest.version,
1320
- "org.opencontainers.image.description": pluginData.manifest.description,
1321
- "org.opencontainers.image.authors": pluginData.manifest.author
1322
+ "vnd.obsidianmd.plugin.id": pluginData.manifest.id,
1323
+ "vnd.obsidianmd.plugin.name": pluginData.manifest.name,
1324
+ "vnd.obsidianmd.plugin.version": pluginData.manifest.version,
1325
+ "vnd.obsidianmd.plugin.description": pluginData.manifest.description,
1326
+ "vnd.obsidianmd.plugin.author": pluginData.manifest.author,
1327
+ "vnd.obsidianmd.plugin.repo": githubRepo,
1328
+ "vnd.obsidianmd.plugin.published-at": (/* @__PURE__ */ new Date()).toISOString(),
1329
+ "vnd.obsidianmd.plugin.converted": "true",
1330
+ "vnd.obsidianmd.plugin.original-repo": "obsidianmd/obsidian-releases"
1322
1331
  };
1323
1332
  if (pluginData.manifest.authorUrl) {
1324
- annotations["org.opencontainers.image.url"] = pluginData.manifest.authorUrl;
1333
+ annotations["vnd.obsidianmd.plugin.author-url"] = pluginData.manifest.authorUrl;
1334
+ }
1335
+ if (pluginData.manifest.minAppVersion) {
1336
+ annotations["vnd.obsidianmd.plugin.min-app-version"] = pluginData.manifest.minAppVersion;
1325
1337
  }
1326
1338
  const manifestPushResult = await client.pushPluginManifest({
1327
1339
  ref: ref.tag || pluginData.manifest.version,
@@ -1434,11 +1446,112 @@ var MarketplaceClient = class {
1434
1446
  }
1435
1447
  };
1436
1448
 
1449
+ // src/lib/oci-tags.ts
1450
+ function parseAuthChallenge(header) {
1451
+ const realmMatch = /realm="([^"]+)"/.exec(header);
1452
+ const serviceMatch = /service="([^"]+)"/.exec(header);
1453
+ const scopeMatch = /scope="([^"]+)"/.exec(header);
1454
+ if (!realmMatch || !serviceMatch || !scopeMatch) {
1455
+ return null;
1456
+ }
1457
+ return {
1458
+ realm: realmMatch[1],
1459
+ service: serviceMatch[1],
1460
+ scope: scopeMatch[1]
1461
+ };
1462
+ }
1463
+ async function getRegistryToken(challenge, adapter, githubToken) {
1464
+ const url = `${challenge.realm}?service=${challenge.service}&scope=${challenge.scope}`;
1465
+ const headers = {
1466
+ Accept: "application/json"
1467
+ };
1468
+ if (githubToken) {
1469
+ const basicAuth = Buffer.from(`token:${githubToken}`).toString("base64");
1470
+ headers.Authorization = `Basic ${basicAuth}`;
1471
+ }
1472
+ try {
1473
+ const response = await adapter.fetch(url, { headers });
1474
+ if (!response.ok) {
1475
+ return null;
1476
+ }
1477
+ const data = await response.json();
1478
+ return data.token || null;
1479
+ } catch {
1480
+ return null;
1481
+ }
1482
+ }
1483
+ async function queryOciTags(opts) {
1484
+ const { registryUrl, adapter, token } = opts;
1485
+ const ref = parseRepoAndRef(registryUrl);
1486
+ const url = `https://${ref.index.name}/v2/${ref.remoteName}/tags/list`;
1487
+ const headers = {
1488
+ Accept: "application/json"
1489
+ };
1490
+ let response = await adapter.fetch(url, { headers });
1491
+ if (response.status === 401 && token) {
1492
+ const wwwAuth = response.headers.get("www-authenticate");
1493
+ if (wwwAuth) {
1494
+ const challenge = parseAuthChallenge(wwwAuth);
1495
+ if (challenge) {
1496
+ const registryToken = await getRegistryToken(challenge, adapter, token);
1497
+ if (registryToken) {
1498
+ headers.Authorization = `Bearer ${registryToken}`;
1499
+ response = await adapter.fetch(url, { headers });
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+ if (!response.ok) {
1505
+ throw new Error(
1506
+ `Failed to query OCI tags: ${response.status} ${response.statusText}`
1507
+ );
1508
+ }
1509
+ const data = await response.json();
1510
+ return data.tags || [];
1511
+ }
1512
+ async function queryTagMetadata(opts) {
1513
+ const { registryUrl, tag, adapter, token } = opts;
1514
+ const ref = parseRepoAndRef(registryUrl);
1515
+ const url = `https://${ref.index.name}/v2/${ref.remoteName}/manifests/${tag}`;
1516
+ const headers = {
1517
+ Accept: "application/vnd.oci.image.manifest.v1+json"
1518
+ };
1519
+ let response = await adapter.fetch(url, { headers });
1520
+ if (response.status === 401 && token) {
1521
+ const wwwAuth = response.headers.get("www-authenticate");
1522
+ if (wwwAuth) {
1523
+ const challenge = parseAuthChallenge(wwwAuth);
1524
+ if (challenge) {
1525
+ const registryToken = await getRegistryToken(challenge, adapter, token);
1526
+ if (registryToken) {
1527
+ headers.Authorization = `Bearer ${registryToken}`;
1528
+ response = await adapter.fetch(url, { headers });
1529
+ }
1530
+ }
1531
+ }
1532
+ }
1533
+ if (!response.ok) {
1534
+ throw new Error(
1535
+ `Failed to query tag metadata: ${response.status} ${response.statusText}`
1536
+ );
1537
+ }
1538
+ const manifest = await response.json();
1539
+ const publishedAt = manifest.created || (/* @__PURE__ */ new Date()).toISOString();
1540
+ const layerSizes = manifest.layers?.map((l) => l.size) || [];
1541
+ const size = layerSizes.reduce((sum, s) => sum + s, 0);
1542
+ const annotations = manifest.annotations || {};
1543
+ return {
1544
+ publishedAt,
1545
+ size,
1546
+ annotations
1547
+ };
1548
+ }
1549
+
1437
1550
  // src/commands/marketplace.ts
1438
1551
  import * as fs3 from "node:fs/promises";
1439
1552
  import * as path3 from "node:path";
1440
1553
  async function marketplaceRegisterCommand(opts) {
1441
- const { repository, token, logger, adapter } = opts;
1554
+ const { repository, token, introduction, logger, adapter } = opts;
1442
1555
  logger.log(`Fetching plugin metadata from ${repository}...`);
1443
1556
  const ref = parseRepoAndRef(repository);
1444
1557
  const client = new OciRegistryClient({
@@ -1457,57 +1570,56 @@ async function marketplaceRegisterCommand(opts) {
1457
1570
  const name = pluginManifest.name;
1458
1571
  const author = pluginManifest.author;
1459
1572
  const description = pluginManifest.description || "";
1460
- const version = pluginManifest.version;
1461
1573
  const minObsidianVersion = pluginManifest.minAppVersion;
1462
1574
  const authorUrl = pluginManifest.authorUrl;
1463
1575
  let gitHubRepoUrl;
1464
- if (ociManifest.annotations && ociManifest.annotations["org.opencontainers.image.source"]) {
1465
- const source = ociManifest.annotations["org.opencontainers.image.source"];
1466
- if (source.startsWith("http")) {
1467
- gitHubRepoUrl = source;
1468
- } else {
1469
- gitHubRepoUrl = `https://github.com/${source}`;
1470
- }
1576
+ if (ociManifest.annotations && ociManifest.annotations["vnd.obsidianmd.plugin.repo"]) {
1577
+ gitHubRepoUrl = ociManifest.annotations["vnd.obsidianmd.plugin.repo"];
1471
1578
  }
1472
1579
  const registryUrl = ref.canonicalName;
1473
1580
  logger.log(`Plugin ID: ${pluginId}`);
1474
1581
  logger.log(`Name: ${name}`);
1475
1582
  logger.log(`Author: ${author}`);
1476
- logger.log(`Version: ${version}`);
1477
1583
  logger.log(`Registry URL: ${registryUrl}`);
1478
1584
  if (gitHubRepoUrl) {
1479
1585
  logger.log(`Repository: ${gitHubRepoUrl}`);
1480
1586
  }
1481
- let yamlContent = `id: ${pluginId}
1587
+ let frontmatter = `---
1588
+ id: ${pluginId}
1482
1589
  registryUrl: ${registryUrl}
1483
1590
  name: ${name}
1484
1591
  author: ${author}
1485
1592
  description: ${description}
1486
- version: ${version}
1487
1593
  `;
1488
1594
  if (gitHubRepoUrl) {
1489
- yamlContent += `repository: ${gitHubRepoUrl}
1595
+ frontmatter += `repository: ${gitHubRepoUrl}
1490
1596
  `;
1491
1597
  }
1492
1598
  if (minObsidianVersion) {
1493
- yamlContent += `minObsidianVersion: ${minObsidianVersion}
1599
+ frontmatter += `minObsidianVersion: ${minObsidianVersion}
1494
1600
  `;
1495
1601
  }
1496
1602
  if (authorUrl) {
1497
- yamlContent += `authorUrl: ${authorUrl}
1603
+ frontmatter += `authorUrl: ${authorUrl}
1498
1604
  `;
1499
1605
  }
1500
- yamlContent += `updatedAt: ${(/* @__PURE__ */ new Date()).toISOString()}
1606
+ frontmatter += `---
1607
+ `;
1608
+ let markdownContent = frontmatter;
1609
+ if (introduction) {
1610
+ markdownContent += `
1611
+ ${introduction}
1501
1612
  `;
1613
+ }
1502
1614
  const marketplacePath = await findMarketplaceDir();
1503
1615
  const pluginsDir = path3.join(marketplacePath, "plugins");
1504
- const yamlPath = path3.join(pluginsDir, `${pluginId}.yml`);
1616
+ const mdPath = path3.join(pluginsDir, `${pluginId}.md`);
1505
1617
  await fs3.mkdir(pluginsDir, { recursive: true });
1506
- await fs3.writeFile(yamlPath, yamlContent, "utf-8");
1507
- logger.success(`Successfully registered plugin to ${yamlPath}`);
1618
+ await fs3.writeFile(mdPath, markdownContent, "utf-8");
1619
+ logger.success(`Successfully registered plugin to ${mdPath}`);
1508
1620
  logger.log(`
1509
1621
  Next steps:`);
1510
- logger.log(`1. Review the generated YAML file`);
1622
+ logger.log(`1. Review the generated markdown file`);
1511
1623
  logger.log(`2. Commit and push to the marketplace repository`);
1512
1624
  logger.log(`3. Submit a pull request to add your plugin to the marketplace`);
1513
1625
  return {
@@ -1515,12 +1627,11 @@ Next steps:`);
1515
1627
  name,
1516
1628
  author,
1517
1629
  description,
1518
- version,
1519
1630
  registryUrl,
1520
1631
  repository: gitHubRepoUrl,
1521
1632
  minObsidianVersion,
1522
1633
  authorUrl,
1523
- yamlPath
1634
+ mdPath
1524
1635
  };
1525
1636
  }
1526
1637
  async function findMarketplaceDir() {
@@ -1552,7 +1663,9 @@ Found ${plugins.length} plugins:
1552
1663
  for (const plugin of plugins) {
1553
1664
  logger.log(`${plugin.name} (${plugin.id})`);
1554
1665
  logger.log(` Author: ${plugin.author}`);
1555
- logger.log(` Version: ${plugin.version}`);
1666
+ if (plugin.versions && plugin.versions.length > 0) {
1667
+ logger.log(` Latest Version: ${plugin.versions[0].tag}`);
1668
+ }
1556
1669
  logger.log(` Registry: ${plugin.registryUrl}`);
1557
1670
  if (plugin.description) {
1558
1671
  logger.log(` Description: ${plugin.description}`);
@@ -1577,7 +1690,9 @@ Found ${plugins.length} matching plugin(s):
1577
1690
  for (const plugin of plugins) {
1578
1691
  logger.log(`${plugin.name} (${plugin.id})`);
1579
1692
  logger.log(` Author: ${plugin.author}`);
1580
- logger.log(` Version: ${plugin.version}`);
1693
+ if (plugin.versions && plugin.versions.length > 0) {
1694
+ logger.log(` Latest Version: ${plugin.versions[0].tag}`);
1695
+ }
1581
1696
  logger.log(` Registry: ${plugin.registryUrl}`);
1582
1697
  if (plugin.description) {
1583
1698
  logger.log(` Description: ${plugin.description}`);
@@ -1599,7 +1714,6 @@ async function marketplaceInfoCommand(opts) {
1599
1714
  logger.log(`Plugin: ${plugin.name}`);
1600
1715
  logger.log("=".repeat(60) + "\n");
1601
1716
  logger.log(`ID: ${plugin.id}`);
1602
- logger.log(`Version: ${plugin.version}`);
1603
1717
  logger.log(`Author: ${plugin.author}`);
1604
1718
  if (plugin.authorUrl) {
1605
1719
  logger.log(`Author URL: ${plugin.authorUrl}`);
@@ -1619,11 +1733,24 @@ Registry URL: ${plugin.registryUrl}`);
1619
1733
  if (plugin.tags && plugin.tags.length > 0) {
1620
1734
  logger.log(`Tags: ${plugin.tags.join(", ")}`);
1621
1735
  }
1622
- logger.log(`Last Updated: ${plugin.updatedAt}`);
1736
+ if (plugin.versions && plugin.versions.length > 0) {
1737
+ logger.log(`
1738
+ Available Versions (${plugin.versions.length}):`);
1739
+ for (const version of plugin.versions.slice(0, 5)) {
1740
+ const date = new Date(version.publishedAt).toISOString().split("T")[0];
1741
+ logger.log(` - ${version.tag} (${date})`);
1742
+ }
1743
+ if (plugin.versions.length > 5) {
1744
+ logger.log(` ... and ${plugin.versions.length - 5} more`);
1745
+ }
1746
+ }
1623
1747
  logger.log("\n" + "=".repeat(60));
1624
1748
  logger.log("Installation:");
1625
1749
  logger.log("=".repeat(60) + "\n");
1626
- logger.log(`shard pull ${plugin.registryUrl}:${plugin.version} --output <path>`);
1750
+ const latestVersion = plugin.versions && plugin.versions.length > 0 ? plugin.versions[0].tag : "latest";
1751
+ logger.log(
1752
+ `shard pull ${plugin.registryUrl}:${latestVersion} --output <path>`
1753
+ );
1627
1754
  logger.log(
1628
1755
  `shard marketplace install ${plugin.id} # (coming soon)`
1629
1756
  );
@@ -1637,8 +1764,9 @@ async function marketplaceInstallCommand(opts) {
1637
1764
  if (!plugin) {
1638
1765
  throw new Error(`Plugin "${pluginId}" not found in marketplace`);
1639
1766
  }
1640
- logger.log(`Found: ${plugin.name} v${plugin.version} by ${plugin.author}`);
1641
- const versionToInstall = version || plugin.version;
1767
+ const latestVersion = plugin.versions && plugin.versions.length > 0 ? plugin.versions[0].tag : "latest";
1768
+ logger.log(`Found: ${plugin.name} v${latestVersion} by ${plugin.author}`);
1769
+ const versionToInstall = version || latestVersion;
1642
1770
  const repository = `${plugin.registryUrl}:${versionToInstall}`;
1643
1771
  logger.log(`Installing from ${repository}...`);
1644
1772
  const pullResult = await pullCommand({
@@ -1653,11 +1781,41 @@ async function marketplaceInstallCommand(opts) {
1653
1781
  );
1654
1782
  return { plugin, pullResult };
1655
1783
  }
1784
+ async function marketplaceVersionsCommand(opts) {
1785
+ const { registryUrl, token, logger, adapter } = opts;
1786
+ logger.log(`Querying versions for ${registryUrl}...`);
1787
+ const tags = await queryOciTags({ registryUrl, token, adapter });
1788
+ if (tags.length === 0) {
1789
+ logger.log("No versions found");
1790
+ return [];
1791
+ }
1792
+ logger.log(`
1793
+ Found ${tags.length} version(s):
1794
+ `);
1795
+ const versions = [];
1796
+ for (const tag of tags) {
1797
+ const metadata = await queryTagMetadata({
1798
+ registryUrl,
1799
+ tag,
1800
+ token,
1801
+ adapter
1802
+ });
1803
+ versions.push({ tag, ...metadata });
1804
+ const sizeKB = (metadata.size / 1024).toFixed(0);
1805
+ const date = new Date(metadata.publishedAt).toISOString().split("T")[0];
1806
+ logger.log(`- ${tag} (published ${date}, ${sizeKB} KB)`);
1807
+ if (metadata.annotations["vnd.obsidianmd.plugin.commit"]) {
1808
+ const sha = metadata.annotations["vnd.obsidianmd.plugin.commit"];
1809
+ logger.log(` Commit: ${sha.substring(0, 7)}`);
1810
+ }
1811
+ }
1812
+ return versions;
1813
+ }
1656
1814
  async function marketplaceUpdateCommand(opts) {
1657
1815
  const { logger } = opts;
1658
1816
  logger.log("Updating marketplace entry...");
1659
1817
  logger.log(
1660
- "Note: This will overwrite the existing YAML file with fresh metadata from GHCR\n"
1818
+ "Note: This will overwrite the existing markdown file with fresh metadata from GHCR\n"
1661
1819
  );
1662
1820
  return marketplaceRegisterCommand(opts);
1663
1821
  }
@@ -1738,6 +1896,7 @@ Marketplace Subcommands:
1738
1896
  install <plugin-id> Install a plugin by ID
1739
1897
  register <repository> Register plugin to marketplace
1740
1898
  update <repository> Update marketplace entry
1899
+ versions <registryUrl> List all available versions for a plugin
1741
1900
 
1742
1901
  Push Options:
1743
1902
  <directory> Path to plugin build output (e.g., ./dist)
@@ -1783,6 +1942,7 @@ Examples:
1783
1942
  shard marketplace install obsidian-git --output ./plugins/obsidian-git
1784
1943
  shard marketplace register ghcr.io/user/my-plugin:1.0.0
1785
1944
  shard marketplace update ghcr.io/user/my-plugin:1.0.1
1945
+ shard marketplace versions ghcr.io/user/my-plugin
1786
1946
  `;
1787
1947
  async function main() {
1788
1948
  let args;
@@ -1877,7 +2037,7 @@ async function main() {
1877
2037
  const subcommand = args.positionals[1];
1878
2038
  if (!subcommand) {
1879
2039
  throw new Error(
1880
- "Marketplace command requires a subcommand. Available: list, search, info, install, register, update"
2040
+ "Marketplace command requires a subcommand. Available: list, search, info, install, register, update, versions"
1881
2041
  );
1882
2042
  }
1883
2043
  const token = resolveAuthToken(args.values.token);
@@ -1970,9 +2130,26 @@ async function main() {
1970
2130
  console.log(JSON.stringify(result, null, 2));
1971
2131
  }
1972
2132
  process.exit(0);
2133
+ } else if (subcommand === "versions") {
2134
+ if (args.positionals.length < 3) {
2135
+ throw new Error(
2136
+ "Marketplace versions command requires <registryUrl>"
2137
+ );
2138
+ }
2139
+ const registryUrl = args.positionals[2];
2140
+ const result = await marketplaceVersionsCommand({
2141
+ registryUrl,
2142
+ token,
2143
+ logger,
2144
+ adapter
2145
+ });
2146
+ if (args.values.json) {
2147
+ console.log(JSON.stringify(result, null, 2));
2148
+ }
2149
+ process.exit(0);
1973
2150
  } else {
1974
2151
  throw new Error(
1975
- `Unknown marketplace subcommand: ${subcommand}. Available: list, search, info, install, register, update`
2152
+ `Unknown marketplace subcommand: ${subcommand}. Available: list, search, info, install, register, update, versions`
1976
2153
  );
1977
2154
  }
1978
2155
  } else {
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../../shard-lib/dist/parsing/IndexParser.js", "../../shard-lib/dist/utils/ValidationUtils.js", "../../shard-lib/dist/parsing/RepoParser.js", "../../shard-lib/dist/utils/DigestUtils.js", "../../shard-lib/dist/types/ManifestTypes.js", "../../shard-lib/dist/ghcr/GhcrConstants.js", "../../shard-lib/dist/errors/RegistryErrors.js", "../../shard-lib/dist/parsing/LinkHeaderParser.js", "../../shard-lib/dist/client/OciRegistryClient.js", "../src/lib/plugin.ts", "../src/commands/push.ts", "../src/commands/pull.ts", "../src/lib/community-plugins.ts", "../src/lib/community-cache.ts", "../src/lib/github-release.ts", "../src/lib/converter.ts", "../src/commands/convert.ts", "../src/lib/marketplace-client.ts", "../src/commands/marketplace.ts", "../src/lib/auth.ts", "../src/lib/logger.ts", "../src/adapters/node-fetch-adapter.ts"],
4
- "sourcesContent": ["import { parseArgs } from \"node:util\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { convertCommand } from \"./commands/convert.js\";\nimport {\n marketplaceRegisterCommand,\n marketplaceListCommand,\n marketplaceSearchCommand,\n marketplaceInfoCommand,\n marketplaceInstallCommand,\n marketplaceUpdateCommand,\n} from \"./commands/marketplace.js\";\nimport { resolveAuthToken } from \"./lib/auth.js\";\nimport { Logger } from \"./lib/logger.js\";\nimport { NodeFetchAdapter } from \"./adapters/node-fetch-adapter.js\";\n\nconst USAGE = `\nUsage: shard <command> [options]\n\nCommands:\n push <directory> <repository> Push a plugin to GHCR\n pull <repository> Pull a plugin from GHCR\n convert <plugin-id> <repository> Convert legacy plugin to OCI format\n marketplace <subcommand> Manage marketplace plugins\n\nMarketplace Subcommands:\n list List all marketplace plugins\n search <keyword> Search for plugins\n info <plugin-id> Show detailed plugin information\n install <plugin-id> Install a plugin by ID\n register <repository> Register plugin to marketplace\n update <repository> Update marketplace entry\n\nPush Options:\n <directory> Path to plugin build output (e.g., ./dist)\n <repository> GHCR repository (e.g., ghcr.io/user/plugin)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nPull Options:\n <repository> Full reference with tag (e.g., ghcr.io/user/plugin:1.0.0)\n --output <dir> Where to extract files (required)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nConvert Options:\n <plugin-id> Plugin ID from community list (e.g., obsidian-git)\n <repository> GHCR repository (e.g., ghcr.io/user/plugin)\n --version <version> Specific version to convert (defaults to latest)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nMarketplace Options:\n --output <dir> Output directory for install command\n --version <version> Specific version to install (defaults to latest)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nEnvironment Variables:\n GITHUB_TOKEN GitHub token (alternative to --token)\n GH_TOKEN GitHub token (gh CLI compatibility)\n\nExamples:\n shard push ./dist ghcr.io/user/my-plugin\n shard pull ghcr.io/user/my-plugin:1.0.0 --output ./plugin\n shard convert obsidian-git ghcr.io/user/obsidian-git\n shard convert calendar ghcr.io/user/calendar --version 1.5.3\n shard marketplace list\n shard marketplace search \"calendar\"\n shard marketplace info obsidian-git\n shard marketplace install obsidian-git --output ./plugins/obsidian-git\n shard marketplace register ghcr.io/user/my-plugin:1.0.0\n shard marketplace update ghcr.io/user/my-plugin:1.0.1\n`;\n\ninterface CliArgs {\n values: {\n token?: string;\n json?: boolean;\n help?: boolean;\n output?: string;\n version?: string;\n };\n positionals: string[];\n}\n\nasync function main() {\n // Parse command line arguments\n let args: CliArgs;\n try {\n args = parseArgs({\n options: {\n token: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n output: { type: \"string\" },\n version: { type: \"string\" },\n },\n allowPositionals: true,\n }) as CliArgs;\n } catch (err) {\n console.error(\n `Error parsing arguments: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.error(USAGE);\n process.exit(1);\n }\n\n // Show help\n if (args.values.help || args.positionals.length === 0) {\n console.log(USAGE);\n process.exit(0);\n }\n\n // Get command\n const command = args.positionals[0];\n const logger = new Logger(args.values.json);\n const adapter = new NodeFetchAdapter();\n\n try {\n if (command === \"push\") {\n // Parse push arguments\n if (args.positionals.length < 3) {\n throw new Error(\"Push command requires <directory> and <repository>\");\n }\n\n const directory = args.positionals[1];\n const repository = args.positionals[2];\n const token = resolveAuthToken(args.values.token);\n\n // Execute push\n const result = await pushCommand({\n directory,\n repository,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"pull\") {\n // Parse pull arguments\n if (args.positionals.length < 2) {\n throw new Error(\"Pull command requires <repository>\");\n }\n\n if (!args.values.output) {\n throw new Error(\"Pull command requires --output flag\");\n }\n\n const repository = args.positionals[1];\n const output = args.values.output;\n const token = resolveAuthToken(args.values.token);\n\n // Execute pull\n const result = await pullCommand({\n repository,\n output,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"convert\") {\n // Parse convert arguments\n if (args.positionals.length < 3) {\n throw new Error(\n \"Convert command requires <plugin-id> and <repository>\",\n );\n }\n\n const pluginId = args.positionals[1];\n const repository = args.positionals[2];\n const version = args.values.version;\n const token = resolveAuthToken(args.values.token);\n\n // Execute convert\n const result = await convertCommand({\n pluginId,\n repository,\n version,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"marketplace\") {\n // Parse marketplace subcommand\n const subcommand = args.positionals[1];\n\n if (!subcommand) {\n throw new Error(\n \"Marketplace command requires a subcommand. Available: list, search, info, install, register, update\",\n );\n }\n\n const token = resolveAuthToken(args.values.token);\n\n if (subcommand === \"list\") {\n // List all plugins\n const result = await marketplaceListCommand({\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"search\") {\n // Search for plugins\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace search command requires <keyword>\");\n }\n\n const keyword = args.positionals[2];\n const result = await marketplaceSearchCommand({\n keyword,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"info\") {\n // Show plugin info\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace info command requires <plugin-id>\");\n }\n\n const pluginId = args.positionals[2];\n const result = await marketplaceInfoCommand({\n pluginId,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"install\") {\n // Install plugin by ID\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace install command requires <plugin-id>\");\n }\n\n if (!args.values.output) {\n throw new Error(\"Marketplace install command requires --output flag\");\n }\n\n const pluginId = args.positionals[2];\n const output = args.values.output;\n const version = args.values.version;\n\n const result = await marketplaceInstallCommand({\n pluginId,\n output,\n version,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"register\") {\n // Register plugin to marketplace\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace register command requires <repository>\");\n }\n\n const repository = args.positionals[2];\n const result = await marketplaceRegisterCommand({\n repository,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"update\") {\n // Update marketplace entry\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace update command requires <repository>\");\n }\n\n const repository = args.positionals[2];\n const result = await marketplaceUpdateCommand({\n repository,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else {\n throw new Error(\n `Unknown marketplace subcommand: ${subcommand}. Available: list, search, info, install, register, update`,\n );\n }\n } else {\n throw new Error(`Unknown command: ${command}`);\n }\n } catch (err) {\n logger.error(err instanceof Error ? err.message : String(err));\n if (args.values.json) {\n console.log(\n JSON.stringify(\n {\n error: err instanceof Error ? err.message : String(err),\n },\n null,\n 2,\n ),\n );\n }\n process.exit(1);\n }\n}\n\nvoid main();\n", "// --- globals\n// See `INDEXNAME` in docker/docker.git:registry/config.go.\nexport const DEFAULT_INDEX_NAME = \"docker.io\";\nexport const DEFAULT_INDEX_URL = \"https://registry-1.docker.io\";\nexport const DEFAULT_LOGIN_SERVERNAME = \"https://index.docker.io/v1/\";\n/**\n * Parse a docker index name or index URL.\n *\n * Examples:\n * docker.io (no scheme implies 'https')\n * index.docker.io (normalized to docker.io)\n * https://docker.io\n * http://localhost:5000\n * https://index.docker.io/v1/ (special case)\n *\n * Special case: `docker` still refers to \"https://index.docker.io/v1/\"\n * when dealing with auth (including in its json file).\n *\n * @param {String} arg: Optional. Index name (optionally with leading scheme).\n */\nexport function parseIndex(arg) {\n if (!arg || arg === DEFAULT_LOGIN_SERVERNAME) {\n // Default index.\n return {\n scheme: \"https\",\n name: DEFAULT_INDEX_NAME,\n official: true,\n };\n }\n // Optional protocol/scheme.\n let indexName;\n let scheme = \"https\";\n const protoSepIdx = arg.indexOf(\"://\");\n if (protoSepIdx !== -1) {\n const foundScheme = arg.slice(0, protoSepIdx);\n if (foundScheme !== \"http\" && foundScheme !== \"https\") {\n throw new Error(\"invalid index scheme, must be \" + '\"http\" or \"https\": ' + arg);\n }\n scheme = foundScheme;\n indexName = arg.slice(protoSepIdx + 3);\n }\n else {\n scheme = isLocalhost(arg) ? \"http\" : \"https\";\n indexName = arg;\n }\n if (!indexName) {\n throw new Error(\"invalid index, empty host: \" + arg);\n }\n else if (indexName.indexOf(\".\") === -1 &&\n indexName.indexOf(\":\") === -1 &&\n indexName !== \"localhost\") {\n throw new Error(`invalid index, \"${indexName}\" does not look like a valid host: ${arg}`);\n }\n else {\n // Allow a trailing '/' as from some URL builder functions that\n // add a default '/' path to a URL, e.g. 'https://docker.io/'.\n if (indexName[indexName.length - 1] === \"/\") {\n indexName = indexName.slice(0, indexName.length - 1);\n }\n // Ensure no trailing repo.\n if (indexName.indexOf(\"/\") !== -1) {\n throw new Error(\"invalid index, trailing repo: \" + arg);\n }\n }\n // Per docker.git's `ValidateIndexName`.\n if (indexName === \"index.\" + DEFAULT_INDEX_NAME) {\n indexName = DEFAULT_INDEX_NAME;\n }\n const index = {\n name: indexName,\n official: indexName === DEFAULT_INDEX_NAME,\n scheme,\n };\n // Disallow official and 'http'.\n if (index.official && index.scheme === \"http\") {\n throw new Error(\"invalid index, plaintext HTTP to official index \" +\n \"is disallowed: \" +\n arg);\n }\n return index;\n}\n/**\n * Similar in spirit to docker.git:registry/endpoint.go#NewEndpoint().\n */\nexport function urlFromIndex(index, scheme) {\n if (index.official) {\n // v1\n if (scheme != null && scheme !== \"https\")\n throw new Error(`Unencrypted communication with docker.io is not allowed`);\n return DEFAULT_INDEX_URL;\n }\n else {\n if (scheme != null && scheme !== \"https\" && scheme !== \"http\")\n throw new Error(`Non-HTTP communication with docker registries is not allowed`);\n return `${scheme ?? index.scheme}://${index.name}`;\n }\n}\nexport function isLocalhost(host) {\n const lead = host.split(\":\")[0];\n if (lead === \"localhost\" || lead === \"127.0.0.1\" || host.includes(\"::1\")) {\n return true;\n }\n else {\n return false;\n }\n}\n", "export function splitIntoTwo(str, sep) {\n const slashIdx = str.indexOf(sep);\n return slashIdx == -1\n ? [str]\n : [str.slice(0, slashIdx), str.slice(slashIdx + 1)];\n}\n", "import { parseIndex } from \"./IndexParser.js\";\nimport { splitIntoTwo } from \"../utils/ValidationUtils.js\";\n// JSSTYLED\n// 'DEFAULTTAG' from https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/graph/tags.go#L25\nexport const DEFAULT_TAG = \"latest\";\nconst VALID_NS = /^[a-z0-9._-]*$/;\nconst VALID_REPO = /^[a-z0-9_/.-]*$/;\n/**\n * Parse a docker repo and tag string: [INDEX/]REPO[:TAG|@DIGEST]\n *\n * Examples:\n * busybox\n * google/python\n * docker.io/ubuntu\n * localhost:5000/blarg\n * http://localhost:5000/blarg\n *\n * Dev Notes:\n * - This is meant to mimic\n * docker.git:registry/config.go#ServiceConfig.NewRepositoryInfo\n * as much as reasonable -- with the addition that we maintain the\n * 'tag' field. Also, that we accept the scheme on the \"INDEX\" is\n * different than docker.git's parsing.\n * - TODO: what about the '@digest' digest alternative to a tag? See:\n * // JSSTYLED\n * https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/pkg/parsers/parsers.go#L68\n *\n * @param arg {String} The docker repo string to parse. See examples above.\n * @param defaultIndex {Object|String} Optional. The default index to use\n * if not specified with `arg`. If not given the default is 'docker.io'.\n * If given it may either be a string, e.g. 'https://myreg.example.com',\n * or parsed index object, as from `parseIndex()`.\n */\nexport function parseRepo(arg, defaultIndex) {\n let index;\n // Strip off optional leading `INDEX/`, parse it to `info.index` and\n // leave the rest in `remoteName`.\n let remoteNameRaw;\n const protoSepIdx = arg.indexOf(\"://\");\n if (protoSepIdx !== -1) {\n // (A) repo with a protocol, e.g. 'https://host/repo'.\n const slashIdx = arg.indexOf(\"/\", protoSepIdx + 3);\n if (slashIdx === -1) {\n throw new Error('invalid repository name, no \"/REPO\" after ' + \"hostame: \" + arg);\n }\n const indexName = arg.slice(0, slashIdx);\n remoteNameRaw = arg.slice(slashIdx + 1);\n index = parseIndex(indexName);\n }\n else {\n const parts = splitIntoTwo(arg, \"/\");\n if (parts.length === 1 ||\n /* or if parts[0] doesn't look like a hostname or IP */\n (parts[0].indexOf(\".\") === -1 &&\n parts[0].indexOf(\":\") === -1 &&\n parts[0] !== \"localhost\")) {\n // (B) repo without leading 'INDEX/'.\n if (defaultIndex === undefined) {\n index = parseIndex();\n }\n else if (typeof defaultIndex === \"string\") {\n index = parseIndex(defaultIndex);\n }\n else {\n index = defaultIndex;\n }\n remoteNameRaw = arg;\n }\n else {\n // (C) repo with leading 'INDEX/' (without protocol).\n index = parseIndex(parts[0]);\n remoteNameRaw = parts[1];\n }\n }\n // Validate remoteName (docker `validateRemoteName`).\n const nameParts = splitIntoTwo(remoteNameRaw, \"/\");\n let ns = \"\", name;\n if (nameParts.length === 2) {\n name = nameParts[1];\n // Validate ns.\n ns = nameParts[0];\n if (ns.length < 2 || ns.length > 255) {\n throw new Error(\"invalid repository namespace, must be between \" +\n \"2 and 255 characters: \" +\n ns);\n }\n if (!VALID_NS.test(ns)) {\n throw new Error(\"invalid repository namespace, may only contain \" +\n \"[a-z0-9._-] characters: \" +\n ns);\n }\n if (ns[0] === \"-\" && ns[ns.length - 1] === \"-\") {\n throw new Error(\"invalid repository namespace, cannot start or \" +\n \"end with a hypen: \" +\n ns);\n }\n if (ns.indexOf(\"--\") !== -1) {\n throw new Error(\"invalid repository namespace, cannot contain \" +\n \"consecutive hyphens: \" +\n ns);\n }\n }\n else {\n name = remoteNameRaw;\n if (index.official) {\n ns = \"library\";\n }\n }\n // Validate name.\n if (!VALID_REPO.test(name)) {\n throw new Error(\"invalid repository name, may only contain \" +\n \"[a-z0-9_/.-] characters: \" +\n name);\n }\n const isLibrary = index.official && ns === \"library\";\n const remoteName = ns ? `${ns}/${name}` : name;\n const localName = index.official\n ? isLibrary\n ? name\n : remoteName\n : `${index.name}/${remoteName}`;\n const canonicalName = index.official\n ? `${parseIndex().name}/${localName}`\n : localName;\n return {\n index,\n official: isLibrary,\n remoteName,\n localName,\n canonicalName,\n };\n}\n/**\n * Parse a docker repo and tag/digest string: [INDEX/]REPO[:TAG|@DIGEST|:TAG@DIGEST]\n *\n * Examples:\n * busybox\n * busybox:latest\n * google/python:3.3\n * docker.io/ubuntu\n * localhost:5000/blarg\n * http://localhost:5000/blarg:latest\n * google/python:3.3@sha256:fb9f16730ac6316afa4d97caa51302199...\n * alpine@sha256:fb9f16730ac6316afa4d97caa5130219927bfcecf0b0...\n *\n * Dev Notes:\n * - TODO Validation on digest and tag would be nice.\n *\n * @param arg {String} The docker repo:tag string to parse. See examples above.\n * @param defaultIndex {Object|String} Optional. The default index to use\n * if not specified with `arg`. If not given the default is 'docker.io'.\n * If given it may either be a string, e.g. 'https://myreg.example.com',\n * or parsed index object, as from `parseIndex()`.\n */\nexport function parseRepoAndRef(arg, defaultIndex) {\n // Parse off the tag/digest per\n // https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/pkg/parsers/parsers.go#L69\n let digest = null;\n let tag = null;\n const atIdx = arg.lastIndexOf(\"@\");\n if (atIdx !== -1) {\n digest = arg.slice(atIdx + 1);\n arg = arg.slice(0, atIdx);\n }\n else {\n tag = DEFAULT_TAG;\n }\n const colonIdx = arg.lastIndexOf(\":\");\n const slashIdx = arg.lastIndexOf(\"/\");\n if (colonIdx !== -1 && colonIdx > slashIdx) {\n tag = arg.slice(colonIdx + 1);\n arg = arg.slice(0, colonIdx);\n }\n const repo = parseRepo(arg, defaultIndex);\n return {\n ...repo,\n digest,\n tag,\n canonicalRef: [\n repo.canonicalName,\n tag ? `:${tag}` : \"\",\n digest ? `@${digest}` : \"\",\n ].join(\"\"),\n };\n}\nexport const parseRepoAndTag = parseRepoAndRef;\n", "export function encodeHex(data) {\n return [...new Uint8Array(data)]\n .map((x) => x.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n/**\n * Calculate the 'Docker-Content-Digest' header for the given manifest.\n *\n * @returns {Promise<String>} The docker digest string.\n * @throws {InvalidContentError} if there is a problem parsing the manifest.\n */\nexport async function digestFromManifestStr(manifestStr) {\n let manifest;\n try {\n manifest = JSON.parse(manifestStr);\n }\n catch (thrown) {\n const err = thrown;\n throw new Error(`could not parse manifest: ${err.message}\\n${manifestStr}`);\n }\n if (manifest.schemaVersion === 1) {\n throw new Error(`schemaVersion 1 is not supported by /x/docker_registry_client.`);\n }\n const hash = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(manifestStr));\n return `sha256:${encodeHex(hash)}`;\n}\n", "// Media type constants for Docker and OCI manifests\nexport const MEDIATYPE_MANIFEST_V2 = \"application/vnd.docker.distribution.manifest.v2+json\";\nexport const MEDIATYPE_MANIFEST_LIST_V2 = \"application/vnd.docker.distribution.manifest.list.v2+json\";\nexport const MEDIATYPE_OCI_MANIFEST_V1 = \"application/vnd.oci.image.manifest.v1+json\";\nexport const MEDIATYPE_OCI_MANIFEST_INDEX_V1 = \"application/vnd.oci.image.index.v1+json\";\nexport const MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1 = \"application/vnd.obsidianmd.plugin-manifest.v1+json\";\nexport const DEFAULT_USERAGENT = `open-obsidian-plugin-spec/0.1.0`;\n", "export const REALM = \"https://ghcr.io/token\";\nexport const SERVICE = \"ghcr.io\";\nexport const SCOPE_REPO_PREFIX = \"repository:\";\nexport const SCOPE_PULL_SUFFIX = \":pull\";\n", "/*\n * Error classes that docker-registry-client may produce.\n */\n/** Base class for custom error classes. */\nexport class ApiError extends Error {\n constructor(message) {\n super(message);\n this.name = new.target.name;\n Error.captureStackTrace?.(this, new.target);\n }\n}\nexport class HttpError extends ApiError {\n resp;\n errors;\n name = \"HttpError\";\n constructor(resp, errors, message) {\n super(message);\n this.resp = resp;\n this.errors = errors;\n }\n}\nexport class BadDigestError extends ApiError {\n name = \"BadDigestError\";\n}\nexport class InvalidContentError extends ApiError {\n name = \"InvalidContentError\";\n}\nexport class InternalError extends ApiError {\n name = \"InternalError\";\n}\nexport class ManifestVerificationError extends ApiError {\n name = \"ManifestVerificationError\";\n}\nexport class InvalidManifestError extends ApiError {\n name = \"InvalidManifestError\";\n}\nexport class DownloadError extends ApiError {\n name = \"DownloadError\";\n}\nexport class UploadError extends ApiError {\n name = \"UploadError\";\n}\nexport class BlobReadError extends ApiError {\n name = \"BlobReadError\";\n}\n// export class UnauthorizedError extends HttpError {\n// readonly name = 'UnauthorizedError';\n// readonly statusCode = 401;\n// }\nexport class TooManyRedirectsError extends ApiError {\n name = \"TooManyRedirectsError\";\n}\n", "const linkRegex = /^<([^>]+)>(?:\\s*;\\s*(.+))?$/;\nexport function parseLinkHeader(rawHeader) {\n if (!rawHeader)\n return [];\n return rawHeader\n .split(\",\")\n .slice(0, 5) // Arbitrary limit to how many links we are willing to parse\n .flatMap((piece) => {\n const matches = piece.trim().match(linkRegex);\n if (!matches)\n return [];\n const { rel, ...params } = matches[2]\n ?.split(\";\")\n .map((param) => param.trim().split(\"=\"))\n .reduce((acc, [key, value]) => {\n if (!value)\n return acc;\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.slice(1, -1);\n }\n acc[key] = value;\n return acc;\n }, {}) ?? {};\n if (!rel)\n return [];\n return [\n {\n rel,\n url: matches[1],\n params,\n },\n ];\n });\n}\n", "import { urlFromIndex } from \"../parsing/IndexParser.js\";\nimport { parseRepo } from \"../parsing/RepoParser.js\";\nimport { splitIntoTwo } from \"../utils/ValidationUtils.js\";\nimport { encodeHex, digestFromManifestStr } from \"../utils/DigestUtils.js\";\nimport { MEDIATYPE_MANIFEST_V2, MEDIATYPE_MANIFEST_LIST_V2, MEDIATYPE_OCI_MANIFEST_V1, MEDIATYPE_OCI_MANIFEST_INDEX_V1, MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1, } from \"../types/ManifestTypes.js\";\nimport { REALM, SERVICE } from \"../ghcr/GhcrConstants.js\";\nimport * as e from \"../errors/RegistryErrors.js\";\nimport { parseLinkHeader } from \"../parsing/LinkHeaderParser.js\";\nconst DEFAULT_USERAGENT = `open-obsidian-plugin-spec/0.1.0`;\n// Use globalThis.crypto (available in browsers/Electron/Node 18+)\nconst getCrypto = () => {\n if (!globalThis.crypto) {\n throw new Error(\"crypto API not available. This library requires Node.js 18+ or a modern browser environment.\");\n }\n return globalThis.crypto;\n};\n/*\n * Set the \"Authorization\" HTTP header into the headers object from the given\n * auth info.\n * - Bearer auth if `token`.\n * - Else, Basic auth if `username`.\n * - Else, if the authorization key exists, then it is removed from headers.\n */\nfunction _setAuthHeaderFromAuthInfo(headers, authInfo) {\n if (authInfo?.type === \"Bearer\") {\n headers[\"authorization\"] = \"Bearer \" + authInfo.token;\n }\n else if (authInfo?.type === \"Basic\") {\n const credentials = `${authInfo.username ?? \"\"}:${authInfo.password ?? \"\"}`;\n headers[\"authorization\"] = \"Basic \" + btoa(credentials);\n }\n else {\n delete headers[\"authorization\"];\n }\n return headers;\n}\n/**\n * Special handling of errors from the registry server.\n *\n * Some registry errors will use a custom error format, so detect those\n * and convert these as necessary.\n *\n * Example JSON response for a missing repo:\n * {\n * \"jse_shortmsg\": \"\",\n * \"jse_info\": {},\n * \"message\": \"{\\\"errors\\\":[{\\\"code\\\":\\\"UNAUTHORIZED\\\",\\\"message\\\":\\\"...}\\n\",\n * \"body\": {\n * \"errors\": [{\n * \"code\": \"UNAUTHORIZED\",\n * \"message\": \"authentication required\",\n * \"detail\": [{\n * \"Type\": \"repository\",\n * \"Class\": \"\",\n * \"Name\": \"library/idontexist\",\n * \"Action\": \"pull\"\n * }]\n * }]\n * }\n * }\n *\n * Example JSON response for bad username/password:\n * {\n * \"statusCode\": 401,\n * \"jse_shortmsg\":\"\",\n * \"jse_info\":{},\n * \"message\":\"{\\\"details\\\":\\\"incorrect username or password\\\"}\\n\",\n * \"body\":{\n * \"details\": \"incorrect username or password\"\n * }\n * }\n *\n * Example AWS token error:\n * {\n * \"statusCode\": 400,\n * \"errors\": [\n * {\n * \"code\": \"DENIED\",\n * \"message\": \"Your Authorization Token is invalid.\"\n * }\n * ]\n * }\n */\nfunction _getRegistryErrorMessage(err) {\n const e = err;\n if (e.body && typeof e.body === \"object\" && e.body !== null) {\n const body = e.body;\n if (Array.isArray(body.errors) && body.errors[0]) {\n return body.errors[0].message;\n }\n else if (body.details) {\n return body.details;\n }\n }\n if (Array.isArray(e.errors) && e.errors[0]) {\n return e.errors[0].message;\n }\n else if (e.message) {\n return e.message;\n }\n else if (e.details) {\n return e.details;\n }\n return String(err);\n}\n/**\n * Return a scope string to be used for an auth request. Example:\n * repository:library/nginx:pull\n */\nfunction _makeAuthScope(resource, name, actions) {\n return `${resource}:${name}:${actions.join(\",\")}`;\n}\n/*\n * Parse the 'Docker-Content-Digest' header.\n *\n * @throws {BadDigestError} if the value is missing or malformed\n */\nfunction _parseDockerContentDigest(dcd) {\n if (!dcd)\n throw new e.BadDigestError('missing \"Docker-Content-Digest\" header');\n const errPre = `could not parse Docker-Content-Digest header \"${dcd}\": `;\n // E.g. docker-content-digest: sha256:887f7ecfd0bda3...\n const parts = splitIntoTwo(dcd, \":\");\n if (parts.length !== 2)\n throw new e.BadDigestError(errPre + JSON.stringify(dcd));\n if (parts[0] !== \"sha256\")\n throw new e.BadDigestError(errPre + \"Unsupported hash algorithm \" + JSON.stringify(parts[0]));\n return {\n raw: dcd,\n algorithm: parts[0],\n expectedDigest: parts[1],\n async validate(buffer) {\n switch (this.algorithm) {\n case \"sha256\": {\n const hashBuffer = await getCrypto().subtle.digest(\"SHA-256\", buffer);\n const digest = encodeHex(hashBuffer);\n if (this.expectedDigest !== digest) {\n throw new e.BadDigestError(`Docker-Content-Digest mismatch (expected: ${this.expectedDigest}, got: ${digest})`);\n }\n return;\n }\n default:\n throw new e.BadDigestError(`Unsupported hash algorithm ${this.algorithm}`);\n }\n },\n };\n}\nexport class OciRegistryClient {\n version = 2;\n insecure;\n repo;\n acceptOCIManifests;\n acceptManifestLists;\n username;\n password;\n scopes;\n _loggedIn;\n _loggedInScope;\n _authInfo;\n _headers;\n _url;\n _userAgent;\n _adapter;\n /**\n * Create a new GHCR client for a particular repository.\n *\n * @param opts.insecure {Boolean} Optional. Default false. Set to true\n * to *not* fail on an invalid or this-signed server certificate.\n * @param opts.adapter {FetchAdapter} Required. HTTP adapter for making requests.\n * ... TODO: lots more to document\n *\n */\n constructor(opts) {\n this.insecure = Boolean(opts.insecure);\n if (opts.repo) {\n this.repo = opts.repo;\n }\n else if (opts.name) {\n this.repo = parseRepo(opts.name);\n }\n else\n throw new Error(`name or repo required`);\n this.acceptOCIManifests = opts.acceptOCIManifests ?? true;\n this.acceptManifestLists = opts.acceptManifestLists ?? false;\n this.username = opts.username;\n this.password = opts.password;\n this.scopes = opts.scopes ?? [\"pull\"];\n this._loggedIn = false;\n this._loggedInScope = null; // Keeps track of the login type.\n this._authInfo = null;\n this._headers = {};\n if (opts.token) {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"Bearer\",\n token: opts.token,\n });\n }\n else if (opts.username || opts.password) {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"Basic\",\n username: opts.username ?? \"\",\n password: opts.password ?? \"\",\n });\n }\n else {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"None\",\n });\n }\n this._url = urlFromIndex(this.repo.index, opts.scheme);\n this._userAgent = opts.userAgent || DEFAULT_USERAGENT;\n this._adapter = opts.adapter;\n }\n /**\n * Login V2\n *\n * Typically one does not need to call this function directly because most\n * methods of a `GHCRClient` will automatically login as necessary.\n *\n * @param opts {Object}\n * - opts.scope {String} Optional. A scope string passed in for\n * bearer/token auth. If this is just a login request where the token\n * won't be used, then the empty string (the default) is sufficient.\n * // JSSTYLED\n * See <https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md#requesting-a-token>\n * @return an object with authentication info\n */\n async performLogin(opts) {\n return {\n type: \"Bearer\",\n token: await this._getToken({\n realm: REALM,\n service: SERVICE,\n scopes: opts.scope ? [opts.scope] : [],\n }),\n };\n }\n /**\n * Get an auth token.\n *\n * See: docker/docker.git:registry/token.go\n */\n async _getToken(opts) {\n // - add https:// prefix (or http) if none on 'realm'\n let tokenUrl = opts.realm;\n const match = /^(\\w+):\\/\\//.exec(tokenUrl);\n if (!match) {\n tokenUrl = (this.insecure ? \"http\" : \"https\") + \"://\" + tokenUrl;\n }\n else if (match[1] && [\"http\", \"https\"].indexOf(match[1]) === -1) {\n // TODO: Verify the logic above\n throw new Error(\"unsupported scheme for \" +\n `WWW-Authenticate realm \"${opts.realm}\": \"${match[1]}\"`);\n }\n // - GET $realm\n // ?service=$service\n // (&scope=$scope)*\n // (&account=$username)\n // Authorization: Basic ...\n const headers = {};\n const query = new URLSearchParams();\n if (opts.service) {\n query.set(\"service\", opts.service);\n }\n if (opts.scopes && opts.scopes.length) {\n for (const scope of opts.scopes) {\n query.append(\"scope\", scope); // intentionally singular 'scope'\n }\n }\n if (this.username) {\n query.set(\"account\", this.username);\n _setAuthHeaderFromAuthInfo(headers, {\n type: \"Basic\",\n username: this.username,\n password: this.password ?? \"\",\n });\n }\n if (query.toString()) {\n tokenUrl += \"?\" + query.toString();\n }\n // log.trace({tokenUrl: tokenUrl}, '_getToken: url');\n headers[\"user-agent\"] = this._userAgent;\n const resp = await this._adapter.fetch(tokenUrl, {\n method: \"GET\",\n headers: headers,\n });\n if (resp.status === 401) {\n // Convert *all* 401 errors to use a generic error constructor\n // with a simple error message.\n const body = await resp.json();\n const errMsg = _getRegistryErrorMessage(body);\n throw new Error(`Registry auth failed: ${errMsg}`);\n }\n if (resp.status !== 200) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${tokenUrl}`);\n }\n const body = (await resp.json());\n if (typeof body?.token !== \"string\") {\n console.error(\"TODO: auth resp:\", body);\n throw new Error(\"authorization \" + \"server did not include a token in the response\");\n }\n return body.token;\n }\n /**\n * Get a registry session (i.e. login to the registry).\n *\n * Typically one does not need to call this method directly because most\n * methods of a client will automatically login as necessary.\n *\n * @param opts {Object} Optional.\n * - opts.scope {String} Optional. Scope to use in the auth Bearer token.\n *\n * Side-effects:\n * - On success, all of `this._loggedIn*`, `this._authInfo`, and\n * `this._headers.authorization` are set.\n */\n async login(opts = {}) {\n const scope = opts.scope ||\n _makeAuthScope(\"repository\", this.repo.remoteName, this.scopes);\n if (this._loggedIn && this._loggedInScope === scope) {\n return;\n }\n const authInfo = await this.performLogin({\n scope: scope,\n });\n this._loggedIn = true;\n this._loggedInScope = scope;\n this._authInfo = authInfo;\n _setAuthHeaderFromAuthInfo(this._headers, authInfo);\n // this.log.trace({err: err, loggedIn: this._loggedIn}, 'login: done');\n }\n async listTags(props = {}) {\n const searchParams = new URLSearchParams();\n if (props.pageSize != null)\n searchParams.set(\"n\", `${props.pageSize}`);\n if (props.startingAfter != null)\n searchParams.set(\"last\", props.startingAfter);\n await this.login();\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName)}/tags/list`, this._url);\n url.search = searchParams.toString();\n const headers = { ...this._headers, \"user-agent\": this._userAgent };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers,\n });\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n return (await resp.json());\n }\n async listAllTags(props = {}) {\n const pages = [];\n for await (const page of this.listTagsPaginated(props)) {\n pages.push(page);\n }\n const firstPage = pages.shift();\n for (const nextPage of pages) {\n firstPage.tags = [...firstPage.tags, ...nextPage.tags];\n }\n return firstPage;\n }\n async *listTagsPaginated(props = {}) {\n await this.login();\n let path = `/v2/${encodeURI(this.repo.remoteName)}/tags/list`;\n if (props.pageSize != null) {\n path += `?n=${props.pageSize}`;\n }\n while (path) {\n const url = new URL(path, this._url);\n const headers = { ...this._headers, \"user-agent\": this._userAgent };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers,\n });\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n const linkHeader = resp.headers.get(\"link\");\n const links = parseLinkHeader(linkHeader ?? null);\n const nextLink = links.find((x) => x.rel == \"next\");\n // If there's no next link then we use a null to end the loop.\n path = nextLink?.url ?? null;\n yield (await resp.json());\n }\n }\n /*\n * Get an image manifest. `ref` is either a tag or a digest.\n * <https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest>\n *\n * Note that docker-content-digest header can be undefined, so if you\n * need a manifest digest, use the `digestFromManifestStr` function.\n */\n async getManifest(opts) {\n const acceptOCIManifests = opts.acceptOCIManifests ?? this.acceptOCIManifests;\n const acceptManifestLists = opts.acceptManifestLists ?? this.acceptManifestLists;\n await this.login();\n const headers = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n };\n const acceptTypes = [MEDIATYPE_MANIFEST_V2];\n if (acceptManifestLists) {\n acceptTypes.push(MEDIATYPE_MANIFEST_LIST_V2);\n }\n if (acceptOCIManifests) {\n acceptTypes.push(MEDIATYPE_OCI_MANIFEST_V1);\n if (acceptManifestLists) {\n acceptTypes.push(MEDIATYPE_OCI_MANIFEST_INDEX_V1);\n }\n }\n headers[\"accept\"] = acceptTypes.join(\", \");\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName ?? \"\")}/manifests/${encodeURI(opts.ref)}`, this._url);\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers: headers,\n redirect: opts.followRedirects == false ? \"manual\" : \"follow\",\n });\n if (resp.status === 401) {\n const body = await resp.json();\n const errMsg = _getRegistryErrorMessage(body);\n throw new Error(`Manifest ${JSON.stringify(opts.ref)} Not Found: ${errMsg}`);\n }\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n const manifest = (await resp.json());\n if (manifest.schemaVersion === 1) {\n throw new Error(`schemaVersion 1 is not supported by /x/docker_registry_client.`);\n }\n return { resp, manifest };\n }\n /**\n * Makes a http request to the given url, following any redirects, then fires\n * the callback(err, req, responses) with the result.\n *\n * Note that 'responses' is an *array* of Response objects, with\n * the last response being at the end of the array. When there is more than\n * one response, it means a redirect has been followed.\n */\n async _makeHttpRequest(opts) {\n const followRedirects = opts.followRedirects ?? true;\n const maxRedirects = opts.maxRedirects ?? 3;\n let numRedirs = 0;\n const req = {\n path: opts.path,\n headers: opts.headers,\n };\n const ress = new Array();\n while (numRedirs < maxRedirects) {\n numRedirs += 1;\n const url = new URL(req.path, this._url);\n const headers = {\n ...req.headers,\n \"user-agent\": this._userAgent,\n };\n const resp = await this._adapter.fetch(url.toString(), {\n method: opts.method,\n headers: headers,\n redirect: \"manual\",\n });\n ress.push(resp);\n if (!followRedirects)\n return ress;\n if (!(resp.status === 302 || resp.status === 307))\n return ress;\n const location = resp.headers.get(\"location\");\n if (!location)\n return ress;\n const loc = new URL(location, url);\n // this.log.trace({numRedirs: numRedirs, loc: loc}, 'got redir response');\n req.path = loc.toString();\n req.headers = {};\n }\n throw new e.TooManyRedirectsError(`maximum number of redirects (${maxRedirects}) hit`);\n }\n async _headOrGetBlob(method, digest) {\n await this.login();\n return await this._makeHttpRequest({\n method: method,\n path: `/v2/${encodeURI(this.repo.remoteName ?? \"\")}/blobs/${encodeURI(digest)}`,\n headers: this._headers,\n });\n }\n /*\n * Get an image file blob -- just the headers. See `getBlob`.\n *\n * <https://docs.docker.com/registry/spec/api/#get-blob>\n * <https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest>\n *\n * This endpoint can return 3xx redirects. The first response often redirects\n * to an object CDN, which would then return the raw data.\n *\n * Interesting headers:\n * - `ress[0].headers.get('docker-content-digest')` is the digest of the\n * content to be downloaded\n * - `ress[-1].headers.get('content-length')` is the number of bytes to download\n * - `ress[-1].headers[*]` as appropriate for HTTP caching, range gets, etc.\n */\n async headBlob(opts) {\n const resp = await this._headOrGetBlob(\"HEAD\", opts.digest);\n // No need to cancel body - fetch returns complete responses\n return resp;\n }\n /**\n * Download a blob and return its ArrayBuffer.\n * <https://docs.docker.com/registry/spec/api/#get-blob>\n *\n * @return\n * The `buffer` is the blob's content as an ArrayBuffer.\n * `ress` (plural of 'res') is an array of responses\n * after following redirects. The full set of responses are returned mainly because\n * headers on both the first, e.g. 'Docker-Content-Digest', and last,\n * e.g. 'Content-Length', might be interesting.\n */\n async downloadBlob(opts) {\n const ress = await this._headOrGetBlob(\"GET\", opts.digest);\n const lastResp = ress[ress.length - 1];\n if (!lastResp) {\n throw new e.BlobReadError(`No response available for blob ${opts.digest}`);\n }\n const buffer = await lastResp.arrayBuffer();\n const dcdHeader = ress[0]?.headers.get(\"docker-content-digest\");\n if (dcdHeader) {\n const dcdInfo = _parseDockerContentDigest(dcdHeader);\n if (dcdInfo.raw !== opts.digest) {\n throw new e.BadDigestError(`Docker-Content-Digest header, ${dcdInfo.raw}, does not match ` +\n `given digest, ${opts.digest}`);\n }\n // Validate the digest\n await dcdInfo.validate(buffer);\n }\n return { ress, buffer };\n }\n /**\n * Upload a blob using POST then PUT workflow.\n * <https://github.com/opencontainers/distribution-spec/blob/main/spec.md#post-then-put>\n *\n * @param opts.data The blob data as ArrayBuffer or Uint8Array\n * @param opts.digest Optional digest. If not provided, it will be calculated.\n * @returns Object with digest and size of the uploaded blob\n */\n async pushBlob(opts) {\n await this.login();\n // Convert to ArrayBuffer if needed\n const buffer = opts.data instanceof Uint8Array\n ? new Uint8Array(opts.data).buffer\n : opts.data;\n // Calculate digest\n const hashBuffer = await getCrypto().subtle.digest(\"SHA-256\", buffer);\n const digest = `sha256:${encodeHex(hashBuffer)}`;\n // Step 1: POST to initiate upload\n const postUrl = new URL(`/v2/${encodeURI(this.repo.remoteName)}/blobs/uploads/`, this._url);\n const postHeaders = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-length\": \"0\",\n };\n const postResp = await this._adapter.fetch(postUrl.toString(), {\n method: \"POST\",\n headers: postHeaders,\n });\n if (postResp.status !== 202) {\n throw new Error(`Failed to initiate blob upload: HTTP ${postResp.status}`);\n }\n // Get upload URL from Location header\n const uploadLocation = postResp.headers.get(\"location\");\n if (!uploadLocation) {\n throw new Error(\"No Location header in POST response\");\n }\n // Step 2: PUT to upload blob\n const uploadUrl = new URL(uploadLocation, this._url);\n uploadUrl.searchParams.set(\"digest\", digest);\n const putHeaders = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-type\": \"application/octet-stream\",\n \"content-length\": buffer.byteLength.toString(),\n };\n const putResp = await this._adapter.fetch(uploadUrl.toString(), {\n method: \"PUT\",\n headers: putHeaders,\n body: buffer,\n });\n if (putResp.status !== 201) {\n throw new Error(`Failed to upload blob: HTTP ${putResp.status}`);\n }\n // Verify digest from response\n const returnedDigest = putResp.headers.get(\"docker-content-digest\");\n if (returnedDigest && returnedDigest !== digest) {\n throw new e.BadDigestError(`Digest mismatch: expected ${digest}, got ${returnedDigest}`);\n }\n return { digest, size: buffer.byteLength };\n }\n /**\n * Upload an image manifest.\n * <https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-manifests>\n *\n * @param opts.ref The tag or digest to push to\n * @param opts.manifest The manifest object to upload\n * @param opts.mediaType Optional media type (defaults to OCI manifest type)\n * @returns Object with digest and size of the uploaded manifest\n */\n async pushManifest(opts) {\n await this.login();\n const manifestStr = JSON.stringify(opts.manifest);\n const manifestBuffer = new TextEncoder().encode(manifestStr);\n // Calculate digest\n const digest = await digestFromManifestStr(manifestStr);\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName)}/manifests/${encodeURI(opts.ref)}`, this._url);\n const headers = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-type\": opts.mediaType || \"application/vnd.oci.image.manifest.v1+json\",\n \"content-length\": manifestBuffer.byteLength.toString(),\n };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"PUT\",\n headers,\n body: manifestBuffer,\n });\n if (resp.status !== 201) {\n throw new Error(`Failed to push manifest: HTTP ${resp.status}`);\n }\n // Verify digest from response\n const returnedDigest = resp.headers.get(\"docker-content-digest\");\n if (returnedDigest && returnedDigest !== digest) {\n throw new e.BadDigestError(`Digest mismatch: expected ${digest}, got ${returnedDigest}`);\n }\n return { digest, size: manifestBuffer.byteLength };\n }\n /**\n * Push a plugin manifest as a config blob and create an OCI manifest.\n * This follows the OCI spec where the Obsidian manifest is stored as the config.\n *\n * @param opts.ref The tag or digest to push to\n * @param opts.pluginManifest The Obsidian plugin manifest\n * @param opts.layers The layer descriptors (main.js, styles.css, etc.)\n * @param opts.annotations Optional annotations for the OCI manifest\n * @returns Object with digest, configDigest, and the created manifest\n */\n async pushPluginManifest(opts) {\n // Step 1: Push plugin manifest as config blob\n const manifestStr = JSON.stringify(opts.pluginManifest);\n const manifestBuffer = new TextEncoder().encode(manifestStr);\n const configResult = await this.pushBlob({\n data: manifestBuffer,\n });\n // Step 2: Build OCI manifest with plugin manifest as config\n const manifest = {\n schemaVersion: 2,\n mediaType: MEDIATYPE_OCI_MANIFEST_V1,\n artifactType: \"application/vnd.obsidian.plugin.v1+json\",\n config: {\n mediaType: MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1,\n digest: configResult.digest,\n size: configResult.size,\n },\n layers: opts.layers,\n annotations: opts.annotations,\n };\n // Step 3: Push the OCI manifest\n const manifestResult = await this.pushManifest({\n ref: opts.ref,\n manifest,\n mediaType: MEDIATYPE_OCI_MANIFEST_V1,\n });\n return {\n digest: manifestResult.digest,\n configDigest: configResult.digest,\n manifest,\n };\n }\n /**\n * Pull a plugin manifest by extracting it from the OCI config blob.\n * This follows the OCI spec where the Obsidian manifest is stored as the config.\n *\n * @param opts.ref The tag or digest to pull\n * @returns Object with the plugin manifest, OCI manifest, and digests\n */\n async pullPluginManifest(opts) {\n // Step 1: Pull the OCI manifest\n const manifestResult = await this.getManifest({ ref: opts.ref });\n const manifest = manifestResult.manifest;\n // Step 2: Validate manifest has config\n if (!(\"config\" in manifest) || !manifest.config) {\n throw new Error(\"Manifest does not contain a config\");\n }\n const ociManifest = manifest;\n const manifestDigest = manifestResult.resp.headers.get(\"docker-content-digest\") || \"\";\n // Step 3: Pull the config blob\n const { buffer: configBuffer } = await this.downloadBlob({\n digest: ociManifest.config.digest,\n });\n // Step 4: Parse the plugin manifest from config\n const configText = new TextDecoder().decode(configBuffer);\n const pluginManifest = JSON.parse(configText);\n return {\n pluginManifest,\n manifest: ociManifest,\n manifestDigest,\n configDigest: ociManifest.config.digest,\n };\n }\n}\n", "import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ObsidianManifest } from \"shard-lib\";\n\nexport interface DiscoveredPlugin {\n directory: string;\n manifest: {\n path: string;\n content: ArrayBuffer;\n parsed: ObsidianManifest;\n };\n mainJs: {\n path: string;\n content: ArrayBuffer;\n };\n stylesCss?: {\n path: string;\n content: ArrayBuffer;\n };\n}\n\n/**\n * Discover plugin files in a directory.\n * Finds manifest.json (required), main.js (required), and styles.css (optional).\n *\n * @param directory - Directory to scan for plugin files\n * @returns Discovered plugin information\n * @throws Error if required files are missing or invalid\n */\nexport async function discoverPlugin(\n directory: string,\n): Promise<DiscoveredPlugin> {\n // Resolve absolute path\n const absDirectory = path.resolve(directory);\n\n // Check directory exists\n try {\n const stat = await fs.stat(absDirectory);\n if (!stat.isDirectory()) {\n throw new Error(`Not a directory: ${directory}`);\n }\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`Directory not found: ${directory}`);\n }\n throw err;\n }\n\n // Find manifest.json (required)\n const manifestPath = path.join(absDirectory, \"manifest.json\");\n let manifestContent: ArrayBuffer;\n let manifestParsed: ObsidianManifest;\n\n try {\n const buffer = await fs.readFile(manifestPath);\n manifestContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n\n // Parse and validate manifest\n const text = new TextDecoder().decode(manifestContent);\n const parsed = JSON.parse(text) as Record<string, unknown>;\n\n // Validate required fields\n if (!parsed.version || typeof parsed.version !== \"string\") {\n throw new Error('manifest.json missing required \"version\" field');\n }\n if (!parsed.id || typeof parsed.id !== \"string\") {\n throw new Error('manifest.json missing required \"id\" field');\n }\n if (!parsed.name || typeof parsed.name !== \"string\") {\n throw new Error('manifest.json missing required \"name\" field');\n }\n if (!parsed.minAppVersion || typeof parsed.minAppVersion !== \"string\") {\n throw new Error('manifest.json missing required \"minAppVersion\" field');\n }\n if (!parsed.description || typeof parsed.description !== \"string\") {\n throw new Error('manifest.json missing required \"description\" field');\n }\n if (!parsed.author || typeof parsed.author !== \"string\") {\n throw new Error('manifest.json missing required \"author\" field');\n }\n\n manifestParsed = parsed as unknown as ObsidianManifest;\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`manifest.json not found in ${directory}`);\n }\n if (err instanceof SyntaxError) {\n throw new Error(`Could not parse manifest.json: ${err.message}`);\n }\n throw err;\n }\n\n // Find main.js (required)\n const mainJsPath = path.join(absDirectory, \"main.js\");\n let mainJsContent: ArrayBuffer;\n\n try {\n const buffer = await fs.readFile(mainJsPath);\n mainJsContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`main.js not found in ${directory}`);\n }\n throw err;\n }\n\n // Find styles.css (optional)\n const stylesCssPath = path.join(absDirectory, \"styles.css\");\n let stylesCssContent: ArrayBuffer | undefined;\n\n try {\n const buffer = await fs.readFile(stylesCssPath);\n stylesCssContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n // styles.css is optional, ignore error\n stylesCssContent = undefined;\n } else {\n throw err;\n }\n }\n\n return {\n directory: absDirectory,\n manifest: {\n path: manifestPath,\n content: manifestContent,\n parsed: manifestParsed,\n },\n mainJs: {\n path: mainJsPath,\n content: mainJsContent,\n },\n ...(stylesCssContent && {\n stylesCss: {\n path: stylesCssPath,\n content: stylesCssContent,\n },\n }),\n };\n}\n", "import { OciRegistryClient, parseRepoAndRef } from \"shard-lib\";\nimport type {\n ManifestOCIDescriptor,\n FetchAdapter,\n ObsidianManifest,\n} from \"shard-lib\";\nimport { discoverPlugin } from \"../lib/plugin.js\";\nimport { Logger } from \"../lib/logger.js\";\n\n/**\n * Derive GitHub repository URL from registry remote name.\n * Takes the first two path components to form owner/repo.\n *\n * Examples:\n * shard-for-obsidian/shard -> https://github.com/shard-for-obsidian/shard\n * shard-for-obsidian/shard/plugin -> https://github.com/shard-for-obsidian/shard\n */\nfunction deriveGitHubUrl(remoteName: string): string {\n const parts = remoteName.split('/');\n if (parts.length < 2) {\n throw new Error(\n `Cannot derive GitHub URL from ${remoteName}. Need at least owner/repo format.`,\n );\n }\n\n const owner = parts[0];\n const repo = parts[1];\n return `https://github.com/${owner}/${repo}`;\n}\n\nexport interface PushOptions {\n directory: string;\n repository: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface PushResult {\n digest: string;\n tag: string;\n size: number;\n repository: string;\n}\n\n/**\n * Push an Obsidian plugin to GHCR.\n *\n * @param opts - Push options\n * @returns Push result with digest and tag\n */\nexport async function pushCommand(opts: PushOptions): Promise<PushResult> {\n const { directory, repository, token, logger, adapter } = opts;\n\n // Step 1: Discover plugin files\n logger.log(`Discovering plugin files in ${directory}...`);\n const plugin = await discoverPlugin(directory);\n const version = plugin.manifest.parsed.version;\n logger.log(`Found plugin version ${version}`);\n\n // Step 2: Parse repository and add version tag\n const fullRef = repository.includes(\":\")\n ? repository\n : `${repository}:${version}`;\n logger.log(`Pushing to ${fullRef}...`);\n\n const ref = parseRepoAndRef(fullRef);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n scopes: [\"push\", \"pull\"],\n });\n\n // Step 3: Push each file as a blob\n const layers: ManifestOCIDescriptor[] = [];\n\n // No longer need to push manifest.json as a layer - it's now in the config\n\n // Push main.js\n logger.log(\"Pushing main.js...\");\n const mainJsResult = await client.pushBlob({\n data: plugin.mainJs.content,\n });\n layers.push({\n mediaType: \"application/javascript\",\n digest: mainJsResult.digest,\n size: mainJsResult.size,\n annotations: {\n \"org.opencontainers.image.title\": \"main.js\",\n },\n });\n logger.log(\n `Pushed main.js: ${mainJsResult.digest.slice(0, 19)}... (${mainJsResult.size} bytes)`,\n );\n\n // Push styles.css if present\n if (plugin.stylesCss) {\n logger.log(\"Pushing styles.css...\");\n const stylesCssResult = await client.pushBlob({\n data: plugin.stylesCss.content,\n });\n layers.push({\n mediaType: \"text/css\",\n digest: stylesCssResult.digest,\n size: stylesCssResult.size,\n annotations: {\n \"org.opencontainers.image.title\": \"styles.css\",\n },\n });\n logger.log(\n `Pushed styles.css: ${stylesCssResult.digest.slice(0, 19)}... (${stylesCssResult.size} bytes)`,\n );\n }\n\n // Step 4: Derive GitHub URL and prepare annotations\n const githubUrl = deriveGitHubUrl(ref.remoteName);\n const manifest = plugin.manifest.parsed;\n\n const annotations: Record<string, string> = {\n \"org.opencontainers.image.created\": new Date().toISOString(),\n \"org.opencontainers.image.source\": githubUrl,\n \"org.opencontainers.image.version\": manifest.version,\n \"org.opencontainers.image.description\": manifest.description,\n \"org.opencontainers.image.authors\": manifest.author,\n };\n\n // Add optional fields if present\n if (manifest.authorUrl) {\n annotations[\"org.opencontainers.image.url\"] = manifest.authorUrl;\n }\n\n // Step 5: Push plugin manifest using new method\n logger.log(\"Pushing plugin manifest...\");\n const manifestPushResult = await client.pushPluginManifest({\n ref: ref.tag || version,\n pluginManifest: manifest as unknown as ObsidianManifest,\n layers,\n annotations,\n });\n\n logger.success(`Successfully pushed ${fullRef}`);\n logger.log(`Manifest digest: ${manifestPushResult.digest}`);\n logger.log(`GitHub repository: ${githubUrl}`);\n\n // Calculate total size from manifest\n const totalSize = manifestPushResult.manifest.layers.reduce(\n (sum, layer) => sum + layer.size,\n 0,\n );\n\n return {\n digest: manifestPushResult.digest,\n tag: ref.tag || version,\n size: totalSize,\n repository: fullRef,\n };\n}\n", "import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { OciRegistryClient, parseRepoAndRef } from \"shard-lib\";\nimport type { FetchAdapter } from \"shard-lib\";\nimport { Logger } from \"../lib/logger.js\";\n\nexport interface PullOptions {\n repository: string;\n output: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface PullResult {\n files: string[];\n output: string;\n digest: string;\n}\n\n/**\n * Pull an Obsidian plugin from GHCR.\n *\n * @param opts - Pull options\n * @returns Pull result with extracted files\n */\nexport async function pullCommand(opts: PullOptions): Promise<PullResult> {\n const { repository, output, token, logger, adapter } = opts;\n\n // Step 1: Parse repository reference\n logger.log(`Pulling ${repository}...`);\n const ref = parseRepoAndRef(repository);\n\n if (!ref.tag && !ref.digest) {\n throw new Error(\"Repository reference must include tag or digest\");\n }\n\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n });\n\n // Step 2: Fetch manifest and extract plugin manifest from config\n logger.log(\"Fetching manifest...\");\n const refString = ref.tag || ref.digest || \"\";\n const pullResult = await client.pullPluginManifest({ ref: refString });\n const manifest = pullResult.manifest;\n\n logger.log(`Manifest digest: ${pullResult.manifestDigest}`);\n\n // Step 3: Create output directory if needed\n const absOutput = path.resolve(output);\n logger.log(`Creating output directory: ${absOutput}`);\n await fs.mkdir(absOutput, { recursive: true });\n\n // Step 4: Write manifest.json from config\n const manifestPath = path.join(absOutput, \"manifest.json\");\n const manifestJson = JSON.stringify(pullResult.pluginManifest, null, 2);\n await fs.writeFile(manifestPath, manifestJson, \"utf-8\");\n logger.log(`Wrote manifest.json (${manifestJson.length} bytes)`);\n\n const files: string[] = [\"manifest.json\"];\n\n // Step 5: Download and extract each layer\n for (const layer of manifest.layers) {\n // Extract filename from annotation\n const filename = layer.annotations?.[\"org.opencontainers.image.title\"];\n if (!filename) {\n throw new Error(\n `Layer ${layer.digest} missing required filename annotation`,\n );\n }\n\n logger.log(`Downloading ${filename}...`);\n\n // Download blob\n const blobResult = await client.downloadBlob({\n digest: layer.digest,\n });\n\n // Write to output directory\n const filePath = path.join(absOutput, filename);\n const buffer = Buffer.from(blobResult.buffer);\n await fs.writeFile(filePath, buffer);\n\n logger.log(`Wrote ${filename} (${buffer.length} bytes)`);\n files.push(filename);\n }\n\n logger.success(`Successfully pulled ${repository}`);\n logger.log(`Files extracted to: ${absOutput}`);\n\n return {\n files,\n output: absOutput,\n digest: pullResult.manifestDigest,\n };\n}\n", "/**\n * URL to the Obsidian community plugins JSON file\n */\nexport const COMMUNITY_PLUGINS_URL =\n \"https://raw.githubusercontent.com/obsidianmd/obsidian-releases/refs/heads/master/community-plugins.json\";\n\n/**\n * Represents a community plugin entry from the Obsidian marketplace\n */\nexport interface CommunityPlugin {\n /** Plugin ID (used in folder name and as identifier) */\n id: string;\n /** Display name of the plugin */\n name: string;\n /** Author name */\n author: string;\n /** Plugin description */\n description: string;\n /** GitHub repository in format \"owner/repo\" */\n repo: string;\n}\n", "import type { FetchAdapter } from \"shard-lib\";\nimport {\n COMMUNITY_PLUGINS_URL,\n type CommunityPlugin,\n} from \"./community-plugins.js\";\n\n/**\n * Cache for Obsidian community plugins.\n * Fetches and caches the list of community plugins from the official repository.\n */\nexport class CommunityPluginsCache {\n private adapter: FetchAdapter;\n private plugins: CommunityPlugin[] | null = null;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * Fetch the list of community plugins.\n * Results are cached for subsequent calls.\n *\n * @returns Array of community plugins\n * @throws Error if fetch fails\n */\n async fetch(): Promise<CommunityPlugin[]> {\n // Return cached data if available\n if (this.plugins !== null) {\n return this.plugins;\n }\n\n // Fetch from URL\n const response = await this.adapter.fetch(COMMUNITY_PLUGINS_URL);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch community plugins: ${response.status}`);\n }\n\n const plugins = (await response.json()) as CommunityPlugin[];\n this.plugins = plugins;\n return plugins;\n }\n\n /**\n * Find a plugin by ID.\n * Fetches the plugin list if not already cached.\n *\n * @param id - Plugin ID to search for\n * @returns Plugin if found, undefined otherwise\n */\n async findPlugin(id: string): Promise<CommunityPlugin | undefined> {\n const plugins = await this.fetch();\n return plugins.find((plugin) => plugin.id === id);\n }\n}\n", "import type { FetchAdapter } from \"shard-lib\";\n\n/**\n * Represents a GitHub release asset\n */\nexport interface GitHubReleaseAsset {\n /** Name of the asset file */\n name: string;\n /** URL to download the asset */\n browser_download_url: string;\n}\n\n/**\n * Represents a GitHub release\n */\nexport interface GitHubRelease {\n /** Tag name of the release (e.g., \"1.2.3\") */\n tag_name: string;\n /** Array of release assets */\n assets: GitHubReleaseAsset[];\n}\n\n/**\n * Fetcher for GitHub releases.\n * Provides methods to fetch releases from the GitHub API.\n */\nexport class GitHubReleaseFetcher {\n private adapter: FetchAdapter;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * Fetch the latest release from a GitHub repository.\n *\n * @param repo - Repository in format \"owner/repo\"\n * @param token - Optional GitHub token for authentication\n * @returns Latest release information\n * @throws Error if fetch fails\n */\n async fetchLatestRelease(\n repo: string,\n token?: string,\n ): Promise<GitHubRelease> {\n const url = `https://api.github.com/repos/${repo}/releases/latest`;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await this.adapter.fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch latest release: ${response.status}`);\n }\n\n return (await response.json()) as GitHubRelease;\n }\n\n /**\n * Fetch a specific release by tag from a GitHub repository.\n *\n * @param repo - Repository in format \"owner/repo\"\n * @param tag - Tag name (e.g., \"1.2.3\")\n * @param token - Optional GitHub token for authentication\n * @returns Release information\n * @throws Error if fetch fails\n */\n async fetchReleaseByTag(\n repo: string,\n tag: string,\n token?: string,\n ): Promise<GitHubRelease> {\n const url = `https://api.github.com/repos/${repo}/releases/tags/${tag}`;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await this.adapter.fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch release ${tag}: ${response.status}`);\n }\n\n return (await response.json()) as GitHubRelease;\n }\n}\n", "import type {\n FetchAdapter,\n ObsidianManifest,\n ManifestOCIDescriptor,\n} from \"shard-lib\";\nimport { OciRegistryClient, parseRepoAndRef } from \"shard-lib\";\nimport { CommunityPluginsCache } from \"./community-cache.js\";\nimport { GitHubReleaseFetcher } from \"./github-release.js\";\n\n/**\n * Options for converting a plugin\n */\nexport interface ConvertPluginOptions {\n /** Plugin ID from community plugins list */\n pluginId: string;\n /** Optional specific version to convert (defaults to latest) */\n version?: string;\n /** Target OCI repository */\n repository: string;\n /** GitHub token for authentication */\n token: string;\n}\n\n/**\n * Result of a plugin conversion\n */\nexport interface ConvertPluginResult {\n /** Plugin ID */\n pluginId: string;\n /** Plugin version */\n version: string;\n /** Target repository with tag */\n repository: string;\n /** GitHub repository URL */\n githubRepo: string;\n /** Parsed manifest */\n manifest: ObsidianManifest;\n /** main.js content */\n mainJs: string;\n /** styles.css content (if present) */\n stylesCss?: string;\n}\n\n/**\n * Options for pushing to registry\n */\nexport interface PushToRegistryOptions {\n /** Repository with tag */\n repository: string;\n /** GitHub repository URL */\n githubRepo: string;\n /** GitHub token */\n token: string;\n /** Plugin data to push */\n pluginData: {\n manifest: ObsidianManifest;\n mainJs: string;\n stylesCss?: string;\n };\n}\n\n/**\n * Result of pushing to registry\n */\nexport interface PushToRegistryResult {\n /** Manifest digest */\n digest: string;\n /** Tag */\n tag: string;\n /** Size */\n size: number;\n /** Repository */\n repository: string;\n}\n\n/**\n * Converts legacy Obsidian plugins to OCI format.\n * Fetches plugins from GitHub releases and pushes to OCI registry.\n */\nexport class PluginConverter {\n private adapter: FetchAdapter;\n private communityCache: CommunityPluginsCache;\n private releaseFetcher: GitHubReleaseFetcher;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n this.communityCache = new CommunityPluginsCache(adapter);\n this.releaseFetcher = new GitHubReleaseFetcher(adapter);\n }\n\n /**\n * Convert a plugin from GitHub releases to OCI format.\n *\n * @param options - Conversion options\n * @returns Conversion result with plugin data\n * @throws Error if plugin not found or conversion fails\n */\n async convertPlugin(\n options: ConvertPluginOptions,\n ): Promise<ConvertPluginResult> {\n const { pluginId, version, repository, token } = options;\n\n // Step 1: Find plugin in community list\n const plugin = await this.communityCache.findPlugin(pluginId);\n if (!plugin) {\n throw new Error(`Plugin \"${pluginId}\" not found in community plugins`);\n }\n\n // Step 2: Fetch release from GitHub\n const release = version\n ? await this.releaseFetcher.fetchReleaseByTag(plugin.repo, version, token)\n : await this.releaseFetcher.fetchLatestRelease(plugin.repo, token);\n\n // Step 3: Find required assets\n const manifestAsset = release.assets.find(\n (a) => a.name === \"manifest.json\",\n );\n const mainJsAsset = release.assets.find((a) => a.name === \"main.js\");\n const stylesCssAsset = release.assets.find((a) => a.name === \"styles.css\");\n\n if (!manifestAsset) {\n throw new Error(\"manifest.json not found in release\");\n }\n if (!mainJsAsset) {\n throw new Error(\"main.js not found in release\");\n }\n\n // Step 4: Download assets\n const manifestResponse = await this.adapter.fetch(\n manifestAsset.browser_download_url,\n );\n if (!manifestResponse.ok) {\n throw new Error(\n `Failed to download manifest.json: ${manifestResponse.status}`,\n );\n }\n const manifestJson = await manifestResponse.text();\n const manifest = JSON.parse(manifestJson) as ObsidianManifest;\n\n const mainJsResponse = await this.adapter.fetch(\n mainJsAsset.browser_download_url,\n );\n if (!mainJsResponse.ok) {\n throw new Error(`Failed to download main.js: ${mainJsResponse.status}`);\n }\n const mainJs = await mainJsResponse.text();\n\n let stylesCss: string | undefined;\n if (stylesCssAsset) {\n const stylesCssResponse = await this.adapter.fetch(\n stylesCssAsset.browser_download_url,\n );\n if (!stylesCssResponse.ok) {\n throw new Error(\n `Failed to download styles.css: ${stylesCssResponse.status}`,\n );\n }\n stylesCss = await stylesCssResponse.text();\n }\n\n // Step 5: Build result\n const fullRepository = repository.includes(\":\")\n ? repository\n : `${repository}:${release.tag_name}`;\n\n return {\n pluginId,\n version: release.tag_name,\n repository: fullRepository,\n githubRepo: plugin.repo,\n manifest,\n mainJs,\n stylesCss,\n };\n }\n\n /**\n * Push plugin data to OCI registry.\n *\n * @param options - Push options\n * @returns Push result\n * @throws Error if push fails\n */\n async pushToRegistry(\n options: PushToRegistryOptions,\n ): Promise<PushToRegistryResult> {\n const { repository, githubRepo, token, pluginData } = options;\n\n // Parse repository reference\n const ref = parseRepoAndRef(repository);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter: this.adapter,\n scopes: [\"push\", \"pull\"],\n });\n\n // Push blobs\n const layers: ManifestOCIDescriptor[] = [];\n\n // Push main.js\n const mainJsResult = await client.pushBlob({\n data: new TextEncoder().encode(pluginData.mainJs),\n });\n layers.push({\n mediaType: \"application/javascript\",\n digest: mainJsResult.digest,\n size: mainJsResult.size,\n annotations: {\n \"org.opencontainers.image.title\": \"main.js\",\n },\n });\n\n // Push styles.css if present\n if (pluginData.stylesCss) {\n const stylesCssResult = await client.pushBlob({\n data: new TextEncoder().encode(pluginData.stylesCss),\n });\n layers.push({\n mediaType: \"text/css\",\n digest: stylesCssResult.digest,\n size: stylesCssResult.size,\n annotations: {\n \"org.opencontainers.image.title\": \"styles.css\",\n },\n });\n }\n\n // Push manifest with OCI annotations\n const annotations: Record<string, string> = {\n \"org.opencontainers.image.created\": new Date().toISOString(),\n \"org.opencontainers.image.source\": githubRepo,\n \"org.opencontainers.image.version\": pluginData.manifest.version,\n \"org.opencontainers.image.description\": pluginData.manifest.description,\n \"org.opencontainers.image.authors\": pluginData.manifest.author,\n };\n\n // Add optional fields if present\n if (pluginData.manifest.authorUrl) {\n annotations[\"org.opencontainers.image.url\"] = pluginData.manifest.authorUrl;\n }\n\n const manifestPushResult = await client.pushPluginManifest({\n ref: ref.tag || pluginData.manifest.version,\n pluginManifest: pluginData.manifest,\n layers,\n annotations,\n });\n\n // Calculate total size from manifest\n const totalSize = manifestPushResult.manifest.layers.reduce(\n (sum, layer) => sum + layer.size,\n 0,\n );\n\n return {\n digest: manifestPushResult.digest,\n tag: ref.tag || pluginData.manifest.version,\n size: totalSize,\n repository,\n };\n }\n}\n", "import type { FetchAdapter } from \"shard-lib\";\nimport { PluginConverter } from \"../lib/converter.js\";\nimport { Logger } from \"../lib/logger.js\";\n\nexport interface ConvertOptions {\n pluginId: string;\n repository: string;\n version?: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface ConvertResult {\n pluginId: string;\n version: string;\n repository: string;\n digest: string;\n size: number;\n}\n\n/**\n * Convert a legacy Obsidian plugin from GitHub releases to OCI format.\n *\n * @param opts - Convert options\n * @returns Convert result with digest and repository\n */\nexport async function convertCommand(\n opts: ConvertOptions,\n): Promise<ConvertResult> {\n const { pluginId, repository, version, token, logger, adapter } = opts;\n\n // Step 1: Create converter\n const converter = new PluginConverter(adapter);\n\n // Step 2: Convert plugin from GitHub releases\n logger.log(`Converting plugin \"${pluginId}\"...`);\n if (version) {\n logger.log(`Using specific version: ${version}`);\n } else {\n logger.log(\"Using latest version\");\n }\n\n const convertResult = await converter.convertPlugin({\n pluginId,\n version,\n repository,\n token,\n });\n\n logger.log(\n `Downloaded plugin ${convertResult.pluginId} v${convertResult.version}`,\n );\n logger.log(` - manifest.json: ${convertResult.manifest.name}`);\n logger.log(` - main.js: ${convertResult.mainJs.length} bytes`);\n if (convertResult.stylesCss) {\n logger.log(` - styles.css: ${convertResult.stylesCss.length} bytes`);\n }\n\n // Step 3: Push to OCI registry\n logger.log(`\\nPushing to ${convertResult.repository}...`);\n const pushResult = await converter.pushToRegistry({\n repository: convertResult.repository,\n githubRepo: convertResult.githubRepo,\n token,\n pluginData: {\n manifest: convertResult.manifest,\n mainJs: convertResult.mainJs,\n stylesCss: convertResult.stylesCss,\n },\n });\n\n logger.success(\n `Successfully converted and pushed ${convertResult.pluginId} v${convertResult.version}`,\n );\n logger.log(`Manifest digest: ${pushResult.digest}`);\n logger.log(`Repository: ${pushResult.repository}`);\n\n return {\n pluginId: convertResult.pluginId,\n version: convertResult.version,\n repository: pushResult.repository,\n digest: pushResult.digest,\n size: pushResult.size,\n };\n}\n", "import type { FetchAdapter } from \"shard-lib\";\n\nexport interface MarketplacePlugin {\n // Primary identifiers\n id: string;\n registryUrl: string; // ghcr.io/owner/repo (PRIMARY)\n\n // Metadata from manifest\n name: string;\n author: string;\n description: string;\n version: string; // Latest published version\n\n // Optional metadata\n license?: string;\n minObsidianVersion?: string;\n authorUrl?: string;\n\n // Derived/optional\n repository?: string; // GitHub URL derived from org.opencontainers.image.source\n tags?: string[]; // For categorization\n\n // Marketplace metadata\n updatedAt: string; // ISO 8601 timestamp\n}\n\nexport interface MarketplaceIndex {\n plugins: MarketplacePlugin[];\n}\n\nexport const DEFAULT_MARKETPLACE_URL =\n \"https://shard-for-obsidian.github.io/shard/plugins.json\";\n\n/**\n * Client for fetching marketplace data from the registry.\n */\nexport class MarketplaceClient {\n constructor(\n private adapter: FetchAdapter,\n private marketplaceUrl: string = DEFAULT_MARKETPLACE_URL,\n ) {}\n\n /**\n * Fetch all plugins from the marketplace.\n */\n async fetchPlugins(): Promise<MarketplacePlugin[]> {\n const response = await this.adapter.fetch(this.marketplaceUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch marketplace data: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as MarketplaceIndex;\n\n if (!data.plugins || !Array.isArray(data.plugins)) {\n throw new Error(\"Invalid marketplace data format\");\n }\n\n return data.plugins;\n }\n\n /**\n * Find a plugin by ID.\n */\n async findPluginById(pluginId: string): Promise<MarketplacePlugin | null> {\n const plugins = await this.fetchPlugins();\n return plugins.find((p) => p.id === pluginId) || null;\n }\n\n /**\n * Search plugins by keyword (searches in name, description, author, tags).\n */\n async searchPlugins(keyword: string): Promise<MarketplacePlugin[]> {\n const plugins = await this.fetchPlugins();\n const lowerKeyword = keyword.toLowerCase();\n\n return plugins.filter(\n (p) =>\n p.name.toLowerCase().includes(lowerKeyword) ||\n p.description.toLowerCase().includes(lowerKeyword) ||\n p.author.toLowerCase().includes(lowerKeyword) ||\n p.id.toLowerCase().includes(lowerKeyword) ||\n p.tags?.some((tag) => tag.toLowerCase().includes(lowerKeyword)),\n );\n }\n}\n", "import { OciRegistryClient, parseRepoAndRef } from \"shard-lib\";\nimport type { FetchAdapter } from \"shard-lib\";\nimport { Logger } from \"../lib/logger.js\";\nimport { MarketplaceClient } from \"../lib/marketplace-client.js\";\nimport type { MarketplacePlugin } from \"../lib/marketplace-client.js\";\nimport { pullCommand } from \"./pull.js\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport interface MarketplaceRegisterOptions {\n repository: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface MarketplaceRegisterResult {\n pluginId: string;\n name: string;\n author: string;\n description: string;\n version: string;\n registryUrl: string;\n repository?: string;\n license?: string;\n minObsidianVersion?: string;\n authorUrl?: string;\n yamlPath: string;\n}\n\n/**\n * Register a plugin to the Shard marketplace.\n * Pulls plugin metadata from OCI registry and creates a YAML file.\n *\n * @param opts - Marketplace register options\n * @returns Register result with plugin metadata\n */\nexport async function marketplaceRegisterCommand(\n opts: MarketplaceRegisterOptions,\n): Promise<MarketplaceRegisterResult> {\n const { repository, token, logger, adapter } = opts;\n\n // Step 1: Parse repository reference\n logger.log(`Fetching plugin metadata from ${repository}...`);\n const ref = parseRepoAndRef(repository);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n scopes: [\"pull\"],\n });\n\n // Step 2: Pull plugin manifest\n const manifestResult = await client.pullPluginManifest({\n ref: ref.tag || \"latest\",\n });\n\n const pluginManifest = manifestResult.pluginManifest;\n const ociManifest = manifestResult.manifest;\n\n // Step 3: Extract metadata from plugin manifest\n const pluginId = pluginManifest.id;\n const name = pluginManifest.name;\n const author = pluginManifest.author;\n const description = pluginManifest.description || \"\";\n const version = pluginManifest.version;\n const minObsidianVersion = pluginManifest.minAppVersion;\n const authorUrl = pluginManifest.authorUrl;\n\n // Step 4: Get repository URL from annotations\n let gitHubRepoUrl: string | undefined;\n if (\n ociManifest.annotations &&\n ociManifest.annotations[\"org.opencontainers.image.source\"]\n ) {\n const source = ociManifest.annotations[\"org.opencontainers.image.source\"];\n // Ensure it's a full GitHub URL\n if (source.startsWith(\"http\")) {\n gitHubRepoUrl = source;\n } else {\n // Convert short form to full URL\n gitHubRepoUrl = `https://github.com/${source}`;\n }\n }\n\n // Step 5: Build registry URL (use canonical name which includes registry host)\n const registryUrl = ref.canonicalName;\n\n logger.log(`Plugin ID: ${pluginId}`);\n logger.log(`Name: ${name}`);\n logger.log(`Author: ${author}`);\n logger.log(`Version: ${version}`);\n logger.log(`Registry URL: ${registryUrl}`);\n if (gitHubRepoUrl) {\n logger.log(`Repository: ${gitHubRepoUrl}`);\n }\n\n // Step 6: Generate enhanced YAML content\n let yamlContent = `id: ${pluginId}\nregistryUrl: ${registryUrl}\nname: ${name}\nauthor: ${author}\ndescription: ${description}\nversion: ${version}\n`;\n\n if (gitHubRepoUrl) {\n yamlContent += `repository: ${gitHubRepoUrl}\\n`;\n }\n\n if (minObsidianVersion) {\n yamlContent += `minObsidianVersion: ${minObsidianVersion}\\n`;\n }\n\n if (authorUrl) {\n yamlContent += `authorUrl: ${authorUrl}\\n`;\n }\n\n // Add timestamp\n yamlContent += `updatedAt: ${new Date().toISOString()}\\n`;\n\n // Step 7: Find marketplace directory (walk up from cwd)\n const marketplacePath = await findMarketplaceDir();\n const pluginsDir = path.join(marketplacePath, \"plugins\");\n const yamlPath = path.join(pluginsDir, `${pluginId}.yml`);\n\n // Step 8: Ensure plugins directory exists\n await fs.mkdir(pluginsDir, { recursive: true });\n\n // Step 9: Write YAML file\n await fs.writeFile(yamlPath, yamlContent, \"utf-8\");\n\n logger.success(`Successfully registered plugin to ${yamlPath}`);\n logger.log(`\\nNext steps:`);\n logger.log(`1. Review the generated YAML file`);\n logger.log(`2. Commit and push to the marketplace repository`);\n logger.log(`3. Submit a pull request to add your plugin to the marketplace`);\n\n return {\n pluginId,\n name,\n author,\n description,\n version,\n registryUrl,\n repository: gitHubRepoUrl,\n minObsidianVersion,\n authorUrl,\n yamlPath,\n };\n}\n\n/**\n * Find the marketplace directory by walking up from cwd.\n * Looks for a directory containing marketplace/plugins/.\n */\nasync function findMarketplaceDir(): Promise<string> {\n let currentDir = process.cwd();\n const root = path.parse(currentDir).root;\n\n while (currentDir !== root) {\n const marketplacePath = path.join(currentDir, \"marketplace\");\n try {\n const stat = await fs.stat(marketplacePath);\n if (stat.isDirectory()) {\n return marketplacePath;\n }\n } catch {\n // Directory doesn't exist, continue searching\n }\n\n // Move up one directory\n currentDir = path.dirname(currentDir);\n }\n\n throw new Error(\n \"Could not find marketplace directory. \" +\n \"Please run this command from within the marketplace repository.\",\n );\n}\n\n/**\n * List all plugins in the marketplace.\n */\nexport async function marketplaceListCommand(opts: {\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin[]> {\n const { logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(\"Fetching marketplace plugins...\");\n const plugins = await client.fetchPlugins();\n\n logger.log(`\\nFound ${plugins.length} plugins:\\n`);\n\n for (const plugin of plugins) {\n logger.log(`${plugin.name} (${plugin.id})`);\n logger.log(` Author: ${plugin.author}`);\n logger.log(` Version: ${plugin.version}`);\n logger.log(` Registry: ${plugin.registryUrl}`);\n if (plugin.description) {\n logger.log(` Description: ${plugin.description}`);\n }\n logger.log(\"\");\n }\n\n return plugins;\n}\n\n/**\n * Search for plugins in the marketplace.\n */\nexport async function marketplaceSearchCommand(opts: {\n keyword: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin[]> {\n const { keyword, logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(`Searching for \"${keyword}\"...`);\n const plugins = await client.searchPlugins(keyword);\n\n if (plugins.length === 0) {\n logger.log(`\\nNo plugins found matching \"${keyword}\"`);\n return [];\n }\n\n logger.log(`\\nFound ${plugins.length} matching plugin(s):\\n`);\n\n for (const plugin of plugins) {\n logger.log(`${plugin.name} (${plugin.id})`);\n logger.log(` Author: ${plugin.author}`);\n logger.log(` Version: ${plugin.version}`);\n logger.log(` Registry: ${plugin.registryUrl}`);\n if (plugin.description) {\n logger.log(` Description: ${plugin.description}`);\n }\n logger.log(\"\");\n }\n\n return plugins;\n}\n\n/**\n * Display detailed information about a plugin.\n */\nexport async function marketplaceInfoCommand(opts: {\n pluginId: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin | null> {\n const { pluginId, logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(`Fetching plugin \"${pluginId}\"...`);\n const plugin = await client.findPluginById(pluginId);\n\n if (!plugin) {\n logger.error(`Plugin \"${pluginId}\" not found in marketplace`);\n return null;\n }\n\n logger.log(\"\\n\" + \"=\".repeat(60));\n logger.log(`Plugin: ${plugin.name}`);\n logger.log(\"=\".repeat(60) + \"\\n\");\n\n logger.log(`ID: ${plugin.id}`);\n logger.log(`Version: ${plugin.version}`);\n logger.log(`Author: ${plugin.author}`);\n if (plugin.authorUrl) {\n logger.log(`Author URL: ${plugin.authorUrl}`);\n }\n logger.log(`Description: ${plugin.description}`);\n logger.log(`\\nRegistry URL: ${plugin.registryUrl}`);\n if (plugin.repository) {\n logger.log(`Repository: ${plugin.repository}`);\n }\n if (plugin.license) {\n logger.log(`License: ${plugin.license}`);\n }\n if (plugin.minObsidianVersion) {\n logger.log(`Min Obsidian Version: ${plugin.minObsidianVersion}`);\n }\n if (plugin.tags && plugin.tags.length > 0) {\n logger.log(`Tags: ${plugin.tags.join(\", \")}`);\n }\n logger.log(`Last Updated: ${plugin.updatedAt}`);\n\n logger.log(\"\\n\" + \"=\".repeat(60));\n logger.log(\"Installation:\");\n logger.log(\"=\".repeat(60) + \"\\n\");\n logger.log(`shard pull ${plugin.registryUrl}:${plugin.version} --output <path>`);\n logger.log(\n `shard marketplace install ${plugin.id} # (coming soon)`,\n );\n\n return plugin;\n}\n\n/**\n * Install a plugin from the marketplace by ID.\n */\nexport async function marketplaceInstallCommand(opts: {\n pluginId: string;\n output: string;\n version?: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<{ plugin: MarketplacePlugin; pullResult: unknown }> {\n const { pluginId, output, version, token, logger, adapter, marketplaceUrl } =\n opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n // Step 1: Find plugin in marketplace\n logger.log(`Looking up plugin \"${pluginId}\" in marketplace...`);\n const plugin = await client.findPluginById(pluginId);\n\n if (!plugin) {\n throw new Error(`Plugin \"${pluginId}\" not found in marketplace`);\n }\n\n logger.log(`Found: ${plugin.name} v${plugin.version} by ${plugin.author}`);\n\n // Step 2: Determine version to install\n const versionToInstall = version || plugin.version;\n const repository = `${plugin.registryUrl}:${versionToInstall}`;\n\n logger.log(`Installing from ${repository}...`);\n\n // Step 3: Use pull command to install\n const pullResult = await pullCommand({\n repository,\n output,\n token,\n logger,\n adapter,\n });\n\n logger.success(\n `Successfully installed ${plugin.name} v${versionToInstall} to ${output}`,\n );\n\n return { plugin, pullResult };\n}\n\n/**\n * Update a marketplace entry by re-registering from GHCR.\n */\nexport async function marketplaceUpdateCommand(opts: {\n repository: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}): Promise<MarketplaceRegisterResult> {\n const { logger } = opts;\n\n logger.log(\"Updating marketplace entry...\");\n logger.log(\n \"Note: This will overwrite the existing YAML file with fresh metadata from GHCR\\n\",\n );\n\n // Just call the register command - it will overwrite the existing file\n return marketplaceRegisterCommand(opts);\n}\n", "/**\n * Resolve GitHub authentication token from multiple sources.\n * Priority: CLI flag -> GITHUB_TOKEN -> GH_TOKEN -> error\n *\n * @param cliToken - Token provided via CLI flag\n * @returns Resolved token\n * @throws Error if no token is found\n */\nexport function resolveAuthToken(cliToken?: string): string {\n // Priority 1: CLI flag\n if (cliToken) {\n return cliToken;\n }\n\n // Priority 2: GITHUB_TOKEN environment variable (CI/CD)\n const githubToken = process.env.GITHUB_TOKEN;\n if (githubToken) {\n return githubToken;\n }\n\n // Priority 3: GH_TOKEN environment variable (gh CLI)\n const ghToken = process.env.GH_TOKEN;\n if (ghToken) {\n return ghToken;\n }\n\n // No token found\n throw new Error(\n \"GitHub token required. Use --token flag or set GITHUB_TOKEN environment variable\",\n );\n}\n", "/**\n * Simple logger that writes to stderr for progress messages.\n * This allows JSON output on stdout while still showing progress.\n */\nexport class Logger {\n private silent: boolean;\n\n constructor(silent = false) {\n this.silent = silent;\n }\n\n /**\n * Log a message to stderr\n */\n log(message: string): void {\n if (!this.silent) {\n process.stderr.write(message + \"\\n\");\n }\n }\n\n /**\n * Log an error message to stderr\n */\n error(message: string): void {\n if (!this.silent) {\n process.stderr.write(`Error: ${message}\\n`);\n }\n }\n\n /**\n * Log a success message to stderr\n */\n success(message: string): void {\n if (!this.silent) {\n process.stderr.write(`Success: ${message}\\n`);\n }\n }\n}\n", "import type { FetchAdapter } from \"shard-lib\";\n\n/**\n * Adapter for Node.js native fetch API.\n * Thin wrapper that passes through to native fetch.\n */\nexport class NodeFetchAdapter implements FetchAdapter {\n async fetch(input: string | Request, init?: RequestInit): Promise<Response> {\n // Use native Node.js fetch\n return fetch(input, init);\n }\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/index.ts", "../../shard-lib/dist/parsing/IndexParser.js", "../../shard-lib/dist/utils/ValidationUtils.js", "../../shard-lib/dist/parsing/RepoParser.js", "../../shard-lib/dist/utils/DigestUtils.js", "../../shard-lib/dist/types/ManifestTypes.js", "../../shard-lib/dist/ghcr/GhcrConstants.js", "../../shard-lib/dist/errors/RegistryErrors.js", "../../shard-lib/dist/parsing/LinkHeaderParser.js", "../../shard-lib/dist/client/OciRegistryClient.js", "../src/lib/plugin.ts", "../src/commands/push.ts", "../src/commands/pull.ts", "../src/lib/community-plugins.ts", "../src/lib/community-cache.ts", "../src/lib/github-release.ts", "../src/lib/converter.ts", "../src/commands/convert.ts", "../src/lib/marketplace-client.ts", "../src/lib/oci-tags.ts", "../src/commands/marketplace.ts", "../src/lib/auth.ts", "../src/lib/logger.ts", "../src/adapters/node-fetch-adapter.ts"],
4
+ "sourcesContent": ["import { parseArgs } from \"node:util\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { convertCommand } from \"./commands/convert.js\";\nimport {\n marketplaceRegisterCommand,\n marketplaceListCommand,\n marketplaceSearchCommand,\n marketplaceInfoCommand,\n marketplaceInstallCommand,\n marketplaceUpdateCommand,\n marketplaceVersionsCommand,\n} from \"./commands/marketplace.js\";\nimport { resolveAuthToken } from \"./lib/auth.js\";\nimport { Logger } from \"./lib/logger.js\";\nimport { NodeFetchAdapter } from \"./adapters/node-fetch-adapter.js\";\n\nconst USAGE = `\nUsage: shard <command> [options]\n\nCommands:\n push <directory> <repository> Push a plugin to GHCR\n pull <repository> Pull a plugin from GHCR\n convert <plugin-id> <repository> Convert legacy plugin to OCI format\n marketplace <subcommand> Manage marketplace plugins\n\nMarketplace Subcommands:\n list List all marketplace plugins\n search <keyword> Search for plugins\n info <plugin-id> Show detailed plugin information\n install <plugin-id> Install a plugin by ID\n register <repository> Register plugin to marketplace\n update <repository> Update marketplace entry\n versions <registryUrl> List all available versions for a plugin\n\nPush Options:\n <directory> Path to plugin build output (e.g., ./dist)\n <repository> GHCR repository (e.g., ghcr.io/user/plugin)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nPull Options:\n <repository> Full reference with tag (e.g., ghcr.io/user/plugin:1.0.0)\n --output <dir> Where to extract files (required)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nConvert Options:\n <plugin-id> Plugin ID from community list (e.g., obsidian-git)\n <repository> GHCR repository (e.g., ghcr.io/user/plugin)\n --version <version> Specific version to convert (defaults to latest)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nMarketplace Options:\n --output <dir> Output directory for install command\n --version <version> Specific version to install (defaults to latest)\n --token <pat> GitHub Personal Access Token\n --json Output JSON result to stdout\n --help Show help\n\nEnvironment Variables:\n GITHUB_TOKEN GitHub token (alternative to --token)\n GH_TOKEN GitHub token (gh CLI compatibility)\n\nExamples:\n shard push ./dist ghcr.io/user/my-plugin\n shard pull ghcr.io/user/my-plugin:1.0.0 --output ./plugin\n shard convert obsidian-git ghcr.io/user/obsidian-git\n shard convert calendar ghcr.io/user/calendar --version 1.5.3\n shard marketplace list\n shard marketplace search \"calendar\"\n shard marketplace info obsidian-git\n shard marketplace install obsidian-git --output ./plugins/obsidian-git\n shard marketplace register ghcr.io/user/my-plugin:1.0.0\n shard marketplace update ghcr.io/user/my-plugin:1.0.1\n shard marketplace versions ghcr.io/user/my-plugin\n`;\n\ninterface CliArgs {\n values: {\n token?: string;\n json?: boolean;\n help?: boolean;\n output?: string;\n version?: string;\n };\n positionals: string[];\n}\n\nasync function main() {\n // Parse command line arguments\n let args: CliArgs;\n try {\n args = parseArgs({\n options: {\n token: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n output: { type: \"string\" },\n version: { type: \"string\" },\n },\n allowPositionals: true,\n }) as CliArgs;\n } catch (err) {\n console.error(\n `Error parsing arguments: ${err instanceof Error ? err.message : String(err)}`,\n );\n console.error(USAGE);\n process.exit(1);\n }\n\n // Show help\n if (args.values.help || args.positionals.length === 0) {\n console.log(USAGE);\n process.exit(0);\n }\n\n // Get command\n const command = args.positionals[0];\n const logger = new Logger(args.values.json);\n const adapter = new NodeFetchAdapter();\n\n try {\n if (command === \"push\") {\n // Parse push arguments\n if (args.positionals.length < 3) {\n throw new Error(\"Push command requires <directory> and <repository>\");\n }\n\n const directory = args.positionals[1];\n const repository = args.positionals[2];\n const token = resolveAuthToken(args.values.token);\n\n // Execute push\n const result = await pushCommand({\n directory,\n repository,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"pull\") {\n // Parse pull arguments\n if (args.positionals.length < 2) {\n throw new Error(\"Pull command requires <repository>\");\n }\n\n if (!args.values.output) {\n throw new Error(\"Pull command requires --output flag\");\n }\n\n const repository = args.positionals[1];\n const output = args.values.output;\n const token = resolveAuthToken(args.values.token);\n\n // Execute pull\n const result = await pullCommand({\n repository,\n output,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"convert\") {\n // Parse convert arguments\n if (args.positionals.length < 3) {\n throw new Error(\n \"Convert command requires <plugin-id> and <repository>\",\n );\n }\n\n const pluginId = args.positionals[1];\n const repository = args.positionals[2];\n const version = args.values.version;\n const token = resolveAuthToken(args.values.token);\n\n // Execute convert\n const result = await convertCommand({\n pluginId,\n repository,\n version,\n token,\n logger,\n adapter,\n });\n\n // Output result\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (command === \"marketplace\") {\n // Parse marketplace subcommand\n const subcommand = args.positionals[1];\n\n if (!subcommand) {\n throw new Error(\n \"Marketplace command requires a subcommand. Available: list, search, info, install, register, update, versions\",\n );\n }\n\n const token = resolveAuthToken(args.values.token);\n\n if (subcommand === \"list\") {\n // List all plugins\n const result = await marketplaceListCommand({\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"search\") {\n // Search for plugins\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace search command requires <keyword>\");\n }\n\n const keyword = args.positionals[2];\n const result = await marketplaceSearchCommand({\n keyword,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"info\") {\n // Show plugin info\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace info command requires <plugin-id>\");\n }\n\n const pluginId = args.positionals[2];\n const result = await marketplaceInfoCommand({\n pluginId,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"install\") {\n // Install plugin by ID\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace install command requires <plugin-id>\");\n }\n\n if (!args.values.output) {\n throw new Error(\"Marketplace install command requires --output flag\");\n }\n\n const pluginId = args.positionals[2];\n const output = args.values.output;\n const version = args.values.version;\n\n const result = await marketplaceInstallCommand({\n pluginId,\n output,\n version,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"register\") {\n // Register plugin to marketplace\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace register command requires <repository>\");\n }\n\n const repository = args.positionals[2];\n const result = await marketplaceRegisterCommand({\n repository,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"update\") {\n // Update marketplace entry\n if (args.positionals.length < 3) {\n throw new Error(\"Marketplace update command requires <repository>\");\n }\n\n const repository = args.positionals[2];\n const result = await marketplaceUpdateCommand({\n repository,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else if (subcommand === \"versions\") {\n // List all available versions for a registry URL\n if (args.positionals.length < 3) {\n throw new Error(\n \"Marketplace versions command requires <registryUrl>\",\n );\n }\n\n const registryUrl = args.positionals[2];\n const result = await marketplaceVersionsCommand({\n registryUrl,\n token,\n logger,\n adapter,\n });\n\n if (args.values.json) {\n console.log(JSON.stringify(result, null, 2));\n }\n process.exit(0);\n } else {\n throw new Error(\n `Unknown marketplace subcommand: ${subcommand}. Available: list, search, info, install, register, update, versions`,\n );\n }\n } else {\n throw new Error(`Unknown command: ${command}`);\n }\n } catch (err) {\n logger.error(err instanceof Error ? err.message : String(err));\n if (args.values.json) {\n console.log(\n JSON.stringify(\n {\n error: err instanceof Error ? err.message : String(err),\n },\n null,\n 2,\n ),\n );\n }\n process.exit(1);\n }\n}\n\nvoid main();\n", "// --- globals\n// See `INDEXNAME` in docker/docker.git:registry/config.go.\nexport const DEFAULT_INDEX_NAME = \"docker.io\";\nexport const DEFAULT_INDEX_URL = \"https://registry-1.docker.io\";\nexport const DEFAULT_LOGIN_SERVERNAME = \"https://index.docker.io/v1/\";\n/**\n * Parse a docker index name or index URL.\n *\n * Examples:\n * docker.io (no scheme implies 'https')\n * index.docker.io (normalized to docker.io)\n * https://docker.io\n * http://localhost:5000\n * https://index.docker.io/v1/ (special case)\n *\n * Special case: `docker` still refers to \"https://index.docker.io/v1/\"\n * when dealing with auth (including in its json file).\n *\n * @param {String} arg: Optional. Index name (optionally with leading scheme).\n */\nexport function parseIndex(arg) {\n if (!arg || arg === DEFAULT_LOGIN_SERVERNAME) {\n // Default index.\n return {\n scheme: \"https\",\n name: DEFAULT_INDEX_NAME,\n official: true,\n };\n }\n // Optional protocol/scheme.\n let indexName;\n let scheme = \"https\";\n const protoSepIdx = arg.indexOf(\"://\");\n if (protoSepIdx !== -1) {\n const foundScheme = arg.slice(0, protoSepIdx);\n if (foundScheme !== \"http\" && foundScheme !== \"https\") {\n throw new Error(\"invalid index scheme, must be \" + '\"http\" or \"https\": ' + arg);\n }\n scheme = foundScheme;\n indexName = arg.slice(protoSepIdx + 3);\n }\n else {\n scheme = isLocalhost(arg) ? \"http\" : \"https\";\n indexName = arg;\n }\n if (!indexName) {\n throw new Error(\"invalid index, empty host: \" + arg);\n }\n else if (indexName.indexOf(\".\") === -1 &&\n indexName.indexOf(\":\") === -1 &&\n indexName !== \"localhost\") {\n throw new Error(`invalid index, \"${indexName}\" does not look like a valid host: ${arg}`);\n }\n else {\n // Allow a trailing '/' as from some URL builder functions that\n // add a default '/' path to a URL, e.g. 'https://docker.io/'.\n if (indexName[indexName.length - 1] === \"/\") {\n indexName = indexName.slice(0, indexName.length - 1);\n }\n // Ensure no trailing repo.\n if (indexName.indexOf(\"/\") !== -1) {\n throw new Error(\"invalid index, trailing repo: \" + arg);\n }\n }\n // Per docker.git's `ValidateIndexName`.\n if (indexName === \"index.\" + DEFAULT_INDEX_NAME) {\n indexName = DEFAULT_INDEX_NAME;\n }\n const index = {\n name: indexName,\n official: indexName === DEFAULT_INDEX_NAME,\n scheme,\n };\n // Disallow official and 'http'.\n if (index.official && index.scheme === \"http\") {\n throw new Error(\"invalid index, plaintext HTTP to official index \" +\n \"is disallowed: \" +\n arg);\n }\n return index;\n}\n/**\n * Similar in spirit to docker.git:registry/endpoint.go#NewEndpoint().\n */\nexport function urlFromIndex(index, scheme) {\n if (index.official) {\n // v1\n if (scheme != null && scheme !== \"https\")\n throw new Error(`Unencrypted communication with docker.io is not allowed`);\n return DEFAULT_INDEX_URL;\n }\n else {\n if (scheme != null && scheme !== \"https\" && scheme !== \"http\")\n throw new Error(`Non-HTTP communication with docker registries is not allowed`);\n return `${scheme ?? index.scheme}://${index.name}`;\n }\n}\nexport function isLocalhost(host) {\n const lead = host.split(\":\")[0];\n if (lead === \"localhost\" || lead === \"127.0.0.1\" || host.includes(\"::1\")) {\n return true;\n }\n else {\n return false;\n }\n}\n", "export function splitIntoTwo(str, sep) {\n const slashIdx = str.indexOf(sep);\n return slashIdx == -1\n ? [str]\n : [str.slice(0, slashIdx), str.slice(slashIdx + 1)];\n}\n", "import { parseIndex } from \"./IndexParser.js\";\nimport { splitIntoTwo } from \"../utils/ValidationUtils.js\";\n// JSSTYLED\n// 'DEFAULTTAG' from https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/graph/tags.go#L25\nexport const DEFAULT_TAG = \"latest\";\nconst VALID_NS = /^[a-z0-9._-]*$/;\nconst VALID_REPO = /^[a-z0-9_/.-]*$/;\n/**\n * Parse a docker repo and tag string: [INDEX/]REPO[:TAG|@DIGEST]\n *\n * Examples:\n * busybox\n * google/python\n * docker.io/ubuntu\n * localhost:5000/blarg\n * http://localhost:5000/blarg\n *\n * Dev Notes:\n * - This is meant to mimic\n * docker.git:registry/config.go#ServiceConfig.NewRepositoryInfo\n * as much as reasonable -- with the addition that we maintain the\n * 'tag' field. Also, that we accept the scheme on the \"INDEX\" is\n * different than docker.git's parsing.\n * - TODO: what about the '@digest' digest alternative to a tag? See:\n * // JSSTYLED\n * https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/pkg/parsers/parsers.go#L68\n *\n * @param arg {String} The docker repo string to parse. See examples above.\n * @param defaultIndex {Object|String} Optional. The default index to use\n * if not specified with `arg`. If not given the default is 'docker.io'.\n * If given it may either be a string, e.g. 'https://myreg.example.com',\n * or parsed index object, as from `parseIndex()`.\n */\nexport function parseRepo(arg, defaultIndex) {\n let index;\n // Strip off optional leading `INDEX/`, parse it to `info.index` and\n // leave the rest in `remoteName`.\n let remoteNameRaw;\n const protoSepIdx = arg.indexOf(\"://\");\n if (protoSepIdx !== -1) {\n // (A) repo with a protocol, e.g. 'https://host/repo'.\n const slashIdx = arg.indexOf(\"/\", protoSepIdx + 3);\n if (slashIdx === -1) {\n throw new Error('invalid repository name, no \"/REPO\" after ' + \"hostame: \" + arg);\n }\n const indexName = arg.slice(0, slashIdx);\n remoteNameRaw = arg.slice(slashIdx + 1);\n index = parseIndex(indexName);\n }\n else {\n const parts = splitIntoTwo(arg, \"/\");\n if (parts.length === 1 ||\n /* or if parts[0] doesn't look like a hostname or IP */\n (parts[0].indexOf(\".\") === -1 &&\n parts[0].indexOf(\":\") === -1 &&\n parts[0] !== \"localhost\")) {\n // (B) repo without leading 'INDEX/'.\n if (defaultIndex === undefined) {\n index = parseIndex();\n }\n else if (typeof defaultIndex === \"string\") {\n index = parseIndex(defaultIndex);\n }\n else {\n index = defaultIndex;\n }\n remoteNameRaw = arg;\n }\n else {\n // (C) repo with leading 'INDEX/' (without protocol).\n index = parseIndex(parts[0]);\n remoteNameRaw = parts[1];\n }\n }\n // Validate remoteName (docker `validateRemoteName`).\n const nameParts = splitIntoTwo(remoteNameRaw, \"/\");\n let ns = \"\", name;\n if (nameParts.length === 2) {\n name = nameParts[1];\n // Validate ns.\n ns = nameParts[0];\n if (ns.length < 2 || ns.length > 255) {\n throw new Error(\"invalid repository namespace, must be between \" +\n \"2 and 255 characters: \" +\n ns);\n }\n if (!VALID_NS.test(ns)) {\n throw new Error(\"invalid repository namespace, may only contain \" +\n \"[a-z0-9._-] characters: \" +\n ns);\n }\n if (ns[0] === \"-\" && ns[ns.length - 1] === \"-\") {\n throw new Error(\"invalid repository namespace, cannot start or \" +\n \"end with a hypen: \" +\n ns);\n }\n if (ns.indexOf(\"--\") !== -1) {\n throw new Error(\"invalid repository namespace, cannot contain \" +\n \"consecutive hyphens: \" +\n ns);\n }\n }\n else {\n name = remoteNameRaw;\n if (index.official) {\n ns = \"library\";\n }\n }\n // Validate name.\n if (!VALID_REPO.test(name)) {\n throw new Error(\"invalid repository name, may only contain \" +\n \"[a-z0-9_/.-] characters: \" +\n name);\n }\n const isLibrary = index.official && ns === \"library\";\n const remoteName = ns ? `${ns}/${name}` : name;\n const localName = index.official\n ? isLibrary\n ? name\n : remoteName\n : `${index.name}/${remoteName}`;\n const canonicalName = index.official\n ? `${parseIndex().name}/${localName}`\n : localName;\n return {\n index,\n official: isLibrary,\n remoteName,\n localName,\n canonicalName,\n };\n}\n/**\n * Parse a docker repo and tag/digest string: [INDEX/]REPO[:TAG|@DIGEST|:TAG@DIGEST]\n *\n * Examples:\n * busybox\n * busybox:latest\n * google/python:3.3\n * docker.io/ubuntu\n * localhost:5000/blarg\n * http://localhost:5000/blarg:latest\n * google/python:3.3@sha256:fb9f16730ac6316afa4d97caa51302199...\n * alpine@sha256:fb9f16730ac6316afa4d97caa5130219927bfcecf0b0...\n *\n * Dev Notes:\n * - TODO Validation on digest and tag would be nice.\n *\n * @param arg {String} The docker repo:tag string to parse. See examples above.\n * @param defaultIndex {Object|String} Optional. The default index to use\n * if not specified with `arg`. If not given the default is 'docker.io'.\n * If given it may either be a string, e.g. 'https://myreg.example.com',\n * or parsed index object, as from `parseIndex()`.\n */\nexport function parseRepoAndRef(arg, defaultIndex) {\n // Parse off the tag/digest per\n // https://github.com/docker/docker/blob/0c7b51089c8cd7ef3510a9b40edaa139a7ca91aa/pkg/parsers/parsers.go#L69\n let digest = null;\n let tag = null;\n const atIdx = arg.lastIndexOf(\"@\");\n if (atIdx !== -1) {\n digest = arg.slice(atIdx + 1);\n arg = arg.slice(0, atIdx);\n }\n else {\n tag = DEFAULT_TAG;\n }\n const colonIdx = arg.lastIndexOf(\":\");\n const slashIdx = arg.lastIndexOf(\"/\");\n if (colonIdx !== -1 && colonIdx > slashIdx) {\n tag = arg.slice(colonIdx + 1);\n arg = arg.slice(0, colonIdx);\n }\n const repo = parseRepo(arg, defaultIndex);\n return {\n ...repo,\n digest,\n tag,\n canonicalRef: [\n repo.canonicalName,\n tag ? `:${tag}` : \"\",\n digest ? `@${digest}` : \"\",\n ].join(\"\"),\n };\n}\nexport const parseRepoAndTag = parseRepoAndRef;\n", "export function encodeHex(data) {\n return [...new Uint8Array(data)]\n .map((x) => x.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n/**\n * Calculate the 'Docker-Content-Digest' header for the given manifest.\n *\n * @returns {Promise<String>} The docker digest string.\n * @throws {InvalidContentError} if there is a problem parsing the manifest.\n */\nexport async function digestFromManifestStr(manifestStr) {\n let manifest;\n try {\n manifest = JSON.parse(manifestStr);\n }\n catch (thrown) {\n const err = thrown;\n throw new Error(`could not parse manifest: ${err.message}\\n${manifestStr}`);\n }\n if (manifest.schemaVersion === 1) {\n throw new Error(`schemaVersion 1 is not supported by /x/docker_registry_client.`);\n }\n const hash = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(manifestStr));\n return `sha256:${encodeHex(hash)}`;\n}\n", "// Media type constants for Docker and OCI manifests\nexport const MEDIATYPE_MANIFEST_V2 = \"application/vnd.docker.distribution.manifest.v2+json\";\nexport const MEDIATYPE_MANIFEST_LIST_V2 = \"application/vnd.docker.distribution.manifest.list.v2+json\";\nexport const MEDIATYPE_OCI_MANIFEST_V1 = \"application/vnd.oci.image.manifest.v1+json\";\nexport const MEDIATYPE_OCI_MANIFEST_INDEX_V1 = \"application/vnd.oci.image.index.v1+json\";\nexport const MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1 = \"application/vnd.obsidianmd.plugin-manifest.v1+json\";\nexport const DEFAULT_USERAGENT = `open-obsidian-plugin-spec/0.1.0`;\n", "export const REALM = \"https://ghcr.io/token\";\nexport const SERVICE = \"ghcr.io\";\nexport const SCOPE_REPO_PREFIX = \"repository:\";\nexport const SCOPE_PULL_SUFFIX = \":pull\";\n", "/*\n * Error classes that docker-registry-client may produce.\n */\n/** Base class for custom error classes. */\nexport class ApiError extends Error {\n constructor(message) {\n super(message);\n this.name = new.target.name;\n Error.captureStackTrace?.(this, new.target);\n }\n}\nexport class HttpError extends ApiError {\n resp;\n errors;\n name = \"HttpError\";\n constructor(resp, errors, message) {\n super(message);\n this.resp = resp;\n this.errors = errors;\n }\n}\nexport class BadDigestError extends ApiError {\n name = \"BadDigestError\";\n}\nexport class InvalidContentError extends ApiError {\n name = \"InvalidContentError\";\n}\nexport class InternalError extends ApiError {\n name = \"InternalError\";\n}\nexport class ManifestVerificationError extends ApiError {\n name = \"ManifestVerificationError\";\n}\nexport class InvalidManifestError extends ApiError {\n name = \"InvalidManifestError\";\n}\nexport class DownloadError extends ApiError {\n name = \"DownloadError\";\n}\nexport class UploadError extends ApiError {\n name = \"UploadError\";\n}\nexport class BlobReadError extends ApiError {\n name = \"BlobReadError\";\n}\n// export class UnauthorizedError extends HttpError {\n// readonly name = 'UnauthorizedError';\n// readonly statusCode = 401;\n// }\nexport class TooManyRedirectsError extends ApiError {\n name = \"TooManyRedirectsError\";\n}\n", "const linkRegex = /^<([^>]+)>(?:\\s*;\\s*(.+))?$/;\nexport function parseLinkHeader(rawHeader) {\n if (!rawHeader)\n return [];\n return rawHeader\n .split(\",\")\n .slice(0, 5) // Arbitrary limit to how many links we are willing to parse\n .flatMap((piece) => {\n const matches = piece.trim().match(linkRegex);\n if (!matches)\n return [];\n const { rel, ...params } = matches[2]\n ?.split(\";\")\n .map((param) => param.trim().split(\"=\"))\n .reduce((acc, [key, value]) => {\n if (!value)\n return acc;\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.slice(1, -1);\n }\n acc[key] = value;\n return acc;\n }, {}) ?? {};\n if (!rel)\n return [];\n return [\n {\n rel,\n url: matches[1],\n params,\n },\n ];\n });\n}\n", "import { urlFromIndex } from \"../parsing/IndexParser.js\";\nimport { parseRepo } from \"../parsing/RepoParser.js\";\nimport { splitIntoTwo } from \"../utils/ValidationUtils.js\";\nimport { encodeHex, digestFromManifestStr } from \"../utils/DigestUtils.js\";\nimport { MEDIATYPE_MANIFEST_V2, MEDIATYPE_MANIFEST_LIST_V2, MEDIATYPE_OCI_MANIFEST_V1, MEDIATYPE_OCI_MANIFEST_INDEX_V1, MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1, } from \"../types/ManifestTypes.js\";\nimport { REALM, SERVICE } from \"../ghcr/GhcrConstants.js\";\nimport * as e from \"../errors/RegistryErrors.js\";\nimport { parseLinkHeader } from \"../parsing/LinkHeaderParser.js\";\nconst DEFAULT_USERAGENT = `open-obsidian-plugin-spec/0.1.0`;\n// Use globalThis.crypto (available in browsers/Electron/Node 18+)\nconst getCrypto = () => {\n if (!globalThis.crypto) {\n throw new Error(\"crypto API not available. This library requires Node.js 18+ or a modern browser environment.\");\n }\n return globalThis.crypto;\n};\n/*\n * Set the \"Authorization\" HTTP header into the headers object from the given\n * auth info.\n * - Bearer auth if `token`.\n * - Else, Basic auth if `username`.\n * - Else, if the authorization key exists, then it is removed from headers.\n */\nfunction _setAuthHeaderFromAuthInfo(headers, authInfo) {\n if (authInfo?.type === \"Bearer\") {\n headers[\"authorization\"] = \"Bearer \" + authInfo.token;\n }\n else if (authInfo?.type === \"Basic\") {\n const credentials = `${authInfo.username ?? \"\"}:${authInfo.password ?? \"\"}`;\n headers[\"authorization\"] = \"Basic \" + btoa(credentials);\n }\n else {\n delete headers[\"authorization\"];\n }\n return headers;\n}\n/**\n * Special handling of errors from the registry server.\n *\n * Some registry errors will use a custom error format, so detect those\n * and convert these as necessary.\n *\n * Example JSON response for a missing repo:\n * {\n * \"jse_shortmsg\": \"\",\n * \"jse_info\": {},\n * \"message\": \"{\\\"errors\\\":[{\\\"code\\\":\\\"UNAUTHORIZED\\\",\\\"message\\\":\\\"...}\\n\",\n * \"body\": {\n * \"errors\": [{\n * \"code\": \"UNAUTHORIZED\",\n * \"message\": \"authentication required\",\n * \"detail\": [{\n * \"Type\": \"repository\",\n * \"Class\": \"\",\n * \"Name\": \"library/idontexist\",\n * \"Action\": \"pull\"\n * }]\n * }]\n * }\n * }\n *\n * Example JSON response for bad username/password:\n * {\n * \"statusCode\": 401,\n * \"jse_shortmsg\":\"\",\n * \"jse_info\":{},\n * \"message\":\"{\\\"details\\\":\\\"incorrect username or password\\\"}\\n\",\n * \"body\":{\n * \"details\": \"incorrect username or password\"\n * }\n * }\n *\n * Example AWS token error:\n * {\n * \"statusCode\": 400,\n * \"errors\": [\n * {\n * \"code\": \"DENIED\",\n * \"message\": \"Your Authorization Token is invalid.\"\n * }\n * ]\n * }\n */\nfunction _getRegistryErrorMessage(err) {\n const e = err;\n if (e.body && typeof e.body === \"object\" && e.body !== null) {\n const body = e.body;\n if (Array.isArray(body.errors) && body.errors[0]) {\n return body.errors[0].message;\n }\n else if (body.details) {\n return body.details;\n }\n }\n if (Array.isArray(e.errors) && e.errors[0]) {\n return e.errors[0].message;\n }\n else if (e.message) {\n return e.message;\n }\n else if (e.details) {\n return e.details;\n }\n return String(err);\n}\n/**\n * Return a scope string to be used for an auth request. Example:\n * repository:library/nginx:pull\n */\nfunction _makeAuthScope(resource, name, actions) {\n return `${resource}:${name}:${actions.join(\",\")}`;\n}\n/*\n * Parse the 'Docker-Content-Digest' header.\n *\n * @throws {BadDigestError} if the value is missing or malformed\n */\nfunction _parseDockerContentDigest(dcd) {\n if (!dcd)\n throw new e.BadDigestError('missing \"Docker-Content-Digest\" header');\n const errPre = `could not parse Docker-Content-Digest header \"${dcd}\": `;\n // E.g. docker-content-digest: sha256:887f7ecfd0bda3...\n const parts = splitIntoTwo(dcd, \":\");\n if (parts.length !== 2)\n throw new e.BadDigestError(errPre + JSON.stringify(dcd));\n if (parts[0] !== \"sha256\")\n throw new e.BadDigestError(errPre + \"Unsupported hash algorithm \" + JSON.stringify(parts[0]));\n return {\n raw: dcd,\n algorithm: parts[0],\n expectedDigest: parts[1],\n async validate(buffer) {\n switch (this.algorithm) {\n case \"sha256\": {\n const hashBuffer = await getCrypto().subtle.digest(\"SHA-256\", buffer);\n const digest = encodeHex(hashBuffer);\n if (this.expectedDigest !== digest) {\n throw new e.BadDigestError(`Docker-Content-Digest mismatch (expected: ${this.expectedDigest}, got: ${digest})`);\n }\n return;\n }\n default:\n throw new e.BadDigestError(`Unsupported hash algorithm ${this.algorithm}`);\n }\n },\n };\n}\nexport class OciRegistryClient {\n version = 2;\n insecure;\n repo;\n acceptOCIManifests;\n acceptManifestLists;\n username;\n password;\n scopes;\n _loggedIn;\n _loggedInScope;\n _authInfo;\n _headers;\n _url;\n _userAgent;\n _adapter;\n /**\n * Create a new GHCR client for a particular repository.\n *\n * @param opts.insecure {Boolean} Optional. Default false. Set to true\n * to *not* fail on an invalid or this-signed server certificate.\n * @param opts.adapter {FetchAdapter} Required. HTTP adapter for making requests.\n * ... TODO: lots more to document\n *\n */\n constructor(opts) {\n this.insecure = Boolean(opts.insecure);\n if (opts.repo) {\n this.repo = opts.repo;\n }\n else if (opts.name) {\n this.repo = parseRepo(opts.name);\n }\n else\n throw new Error(`name or repo required`);\n this.acceptOCIManifests = opts.acceptOCIManifests ?? true;\n this.acceptManifestLists = opts.acceptManifestLists ?? false;\n this.username = opts.username;\n this.password = opts.password;\n this.scopes = opts.scopes ?? [\"pull\"];\n this._loggedIn = false;\n this._loggedInScope = null; // Keeps track of the login type.\n this._authInfo = null;\n this._headers = {};\n if (opts.token) {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"Bearer\",\n token: opts.token,\n });\n }\n else if (opts.username || opts.password) {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"Basic\",\n username: opts.username ?? \"\",\n password: opts.password ?? \"\",\n });\n }\n else {\n _setAuthHeaderFromAuthInfo(this._headers, {\n type: \"None\",\n });\n }\n this._url = urlFromIndex(this.repo.index, opts.scheme);\n this._userAgent = opts.userAgent || DEFAULT_USERAGENT;\n this._adapter = opts.adapter;\n }\n /**\n * Login V2\n *\n * Typically one does not need to call this function directly because most\n * methods of a `GHCRClient` will automatically login as necessary.\n *\n * @param opts {Object}\n * - opts.scope {String} Optional. A scope string passed in for\n * bearer/token auth. If this is just a login request where the token\n * won't be used, then the empty string (the default) is sufficient.\n * // JSSTYLED\n * See <https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md#requesting-a-token>\n * @return an object with authentication info\n */\n async performLogin(opts) {\n return {\n type: \"Bearer\",\n token: await this._getToken({\n realm: REALM,\n service: SERVICE,\n scopes: opts.scope ? [opts.scope] : [],\n }),\n };\n }\n /**\n * Get an auth token.\n *\n * See: docker/docker.git:registry/token.go\n */\n async _getToken(opts) {\n // - add https:// prefix (or http) if none on 'realm'\n let tokenUrl = opts.realm;\n const match = /^(\\w+):\\/\\//.exec(tokenUrl);\n if (!match) {\n tokenUrl = (this.insecure ? \"http\" : \"https\") + \"://\" + tokenUrl;\n }\n else if (match[1] && [\"http\", \"https\"].indexOf(match[1]) === -1) {\n // TODO: Verify the logic above\n throw new Error(\"unsupported scheme for \" +\n `WWW-Authenticate realm \"${opts.realm}\": \"${match[1]}\"`);\n }\n // - GET $realm\n // ?service=$service\n // (&scope=$scope)*\n // (&account=$username)\n // Authorization: Basic ...\n const headers = {};\n const query = new URLSearchParams();\n if (opts.service) {\n query.set(\"service\", opts.service);\n }\n if (opts.scopes && opts.scopes.length) {\n for (const scope of opts.scopes) {\n query.append(\"scope\", scope); // intentionally singular 'scope'\n }\n }\n if (this.username) {\n query.set(\"account\", this.username);\n _setAuthHeaderFromAuthInfo(headers, {\n type: \"Basic\",\n username: this.username,\n password: this.password ?? \"\",\n });\n }\n if (query.toString()) {\n tokenUrl += \"?\" + query.toString();\n }\n // log.trace({tokenUrl: tokenUrl}, '_getToken: url');\n headers[\"user-agent\"] = this._userAgent;\n const resp = await this._adapter.fetch(tokenUrl, {\n method: \"GET\",\n headers: headers,\n });\n if (resp.status === 401) {\n // Convert *all* 401 errors to use a generic error constructor\n // with a simple error message.\n const body = await resp.json();\n const errMsg = _getRegistryErrorMessage(body);\n throw new Error(`Registry auth failed: ${errMsg}`);\n }\n if (resp.status !== 200) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${tokenUrl}`);\n }\n const body = (await resp.json());\n if (typeof body?.token !== \"string\") {\n console.error(\"TODO: auth resp:\", body);\n throw new Error(\"authorization \" + \"server did not include a token in the response\");\n }\n return body.token;\n }\n /**\n * Get a registry session (i.e. login to the registry).\n *\n * Typically one does not need to call this method directly because most\n * methods of a client will automatically login as necessary.\n *\n * @param opts {Object} Optional.\n * - opts.scope {String} Optional. Scope to use in the auth Bearer token.\n *\n * Side-effects:\n * - On success, all of `this._loggedIn*`, `this._authInfo`, and\n * `this._headers.authorization` are set.\n */\n async login(opts = {}) {\n const scope = opts.scope ||\n _makeAuthScope(\"repository\", this.repo.remoteName, this.scopes);\n if (this._loggedIn && this._loggedInScope === scope) {\n return;\n }\n const authInfo = await this.performLogin({\n scope: scope,\n });\n this._loggedIn = true;\n this._loggedInScope = scope;\n this._authInfo = authInfo;\n _setAuthHeaderFromAuthInfo(this._headers, authInfo);\n // this.log.trace({err: err, loggedIn: this._loggedIn}, 'login: done');\n }\n async listTags(props = {}) {\n const searchParams = new URLSearchParams();\n if (props.pageSize != null)\n searchParams.set(\"n\", `${props.pageSize}`);\n if (props.startingAfter != null)\n searchParams.set(\"last\", props.startingAfter);\n await this.login();\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName)}/tags/list`, this._url);\n url.search = searchParams.toString();\n const headers = { ...this._headers, \"user-agent\": this._userAgent };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers,\n });\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n return (await resp.json());\n }\n async listAllTags(props = {}) {\n const pages = [];\n for await (const page of this.listTagsPaginated(props)) {\n pages.push(page);\n }\n const firstPage = pages.shift();\n for (const nextPage of pages) {\n firstPage.tags = [...firstPage.tags, ...nextPage.tags];\n }\n return firstPage;\n }\n async *listTagsPaginated(props = {}) {\n await this.login();\n let path = `/v2/${encodeURI(this.repo.remoteName)}/tags/list`;\n if (props.pageSize != null) {\n path += `?n=${props.pageSize}`;\n }\n while (path) {\n const url = new URL(path, this._url);\n const headers = { ...this._headers, \"user-agent\": this._userAgent };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers,\n });\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n const linkHeader = resp.headers.get(\"link\");\n const links = parseLinkHeader(linkHeader ?? null);\n const nextLink = links.find((x) => x.rel == \"next\");\n // If there's no next link then we use a null to end the loop.\n path = nextLink?.url ?? null;\n yield (await resp.json());\n }\n }\n /*\n * Get an image manifest. `ref` is either a tag or a digest.\n * <https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest>\n *\n * Note that docker-content-digest header can be undefined, so if you\n * need a manifest digest, use the `digestFromManifestStr` function.\n */\n async getManifest(opts) {\n const acceptOCIManifests = opts.acceptOCIManifests ?? this.acceptOCIManifests;\n const acceptManifestLists = opts.acceptManifestLists ?? this.acceptManifestLists;\n await this.login();\n const headers = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n };\n const acceptTypes = [MEDIATYPE_MANIFEST_V2];\n if (acceptManifestLists) {\n acceptTypes.push(MEDIATYPE_MANIFEST_LIST_V2);\n }\n if (acceptOCIManifests) {\n acceptTypes.push(MEDIATYPE_OCI_MANIFEST_V1);\n if (acceptManifestLists) {\n acceptTypes.push(MEDIATYPE_OCI_MANIFEST_INDEX_V1);\n }\n }\n headers[\"accept\"] = acceptTypes.join(\", \");\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName ?? \"\")}/manifests/${encodeURI(opts.ref)}`, this._url);\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"GET\",\n headers: headers,\n redirect: opts.followRedirects == false ? \"manual\" : \"follow\",\n });\n if (resp.status === 401) {\n const body = await resp.json();\n const errMsg = _getRegistryErrorMessage(body);\n throw new Error(`Manifest ${JSON.stringify(opts.ref)} Not Found: ${errMsg}`);\n }\n if (!resp.ok) {\n throw new Error(`Unexpected HTTP ${resp.status} from ${url.toString()}`);\n }\n const manifest = (await resp.json());\n if (manifest.schemaVersion === 1) {\n throw new Error(`schemaVersion 1 is not supported by /x/docker_registry_client.`);\n }\n return { resp, manifest };\n }\n /**\n * Makes a http request to the given url, following any redirects, then fires\n * the callback(err, req, responses) with the result.\n *\n * Note that 'responses' is an *array* of Response objects, with\n * the last response being at the end of the array. When there is more than\n * one response, it means a redirect has been followed.\n */\n async _makeHttpRequest(opts) {\n const followRedirects = opts.followRedirects ?? true;\n const maxRedirects = opts.maxRedirects ?? 3;\n let numRedirs = 0;\n const req = {\n path: opts.path,\n headers: opts.headers,\n };\n const ress = new Array();\n while (numRedirs < maxRedirects) {\n numRedirs += 1;\n const url = new URL(req.path, this._url);\n const headers = {\n ...req.headers,\n \"user-agent\": this._userAgent,\n };\n const resp = await this._adapter.fetch(url.toString(), {\n method: opts.method,\n headers: headers,\n redirect: \"manual\",\n });\n ress.push(resp);\n if (!followRedirects)\n return ress;\n if (!(resp.status === 302 || resp.status === 307))\n return ress;\n const location = resp.headers.get(\"location\");\n if (!location)\n return ress;\n const loc = new URL(location, url);\n // this.log.trace({numRedirs: numRedirs, loc: loc}, 'got redir response');\n req.path = loc.toString();\n req.headers = {};\n }\n throw new e.TooManyRedirectsError(`maximum number of redirects (${maxRedirects}) hit`);\n }\n async _headOrGetBlob(method, digest) {\n await this.login();\n return await this._makeHttpRequest({\n method: method,\n path: `/v2/${encodeURI(this.repo.remoteName ?? \"\")}/blobs/${encodeURI(digest)}`,\n headers: this._headers,\n });\n }\n /*\n * Get an image file blob -- just the headers. See `getBlob`.\n *\n * <https://docs.docker.com/registry/spec/api/#get-blob>\n * <https://docs.docker.com/registry/spec/api/#pulling-an-image-manifest>\n *\n * This endpoint can return 3xx redirects. The first response often redirects\n * to an object CDN, which would then return the raw data.\n *\n * Interesting headers:\n * - `ress[0].headers.get('docker-content-digest')` is the digest of the\n * content to be downloaded\n * - `ress[-1].headers.get('content-length')` is the number of bytes to download\n * - `ress[-1].headers[*]` as appropriate for HTTP caching, range gets, etc.\n */\n async headBlob(opts) {\n const resp = await this._headOrGetBlob(\"HEAD\", opts.digest);\n // No need to cancel body - fetch returns complete responses\n return resp;\n }\n /**\n * Download a blob and return its ArrayBuffer.\n * <https://docs.docker.com/registry/spec/api/#get-blob>\n *\n * @return\n * The `buffer` is the blob's content as an ArrayBuffer.\n * `ress` (plural of 'res') is an array of responses\n * after following redirects. The full set of responses are returned mainly because\n * headers on both the first, e.g. 'Docker-Content-Digest', and last,\n * e.g. 'Content-Length', might be interesting.\n */\n async downloadBlob(opts) {\n const ress = await this._headOrGetBlob(\"GET\", opts.digest);\n const lastResp = ress[ress.length - 1];\n if (!lastResp) {\n throw new e.BlobReadError(`No response available for blob ${opts.digest}`);\n }\n const buffer = await lastResp.arrayBuffer();\n const dcdHeader = ress[0]?.headers.get(\"docker-content-digest\");\n if (dcdHeader) {\n const dcdInfo = _parseDockerContentDigest(dcdHeader);\n if (dcdInfo.raw !== opts.digest) {\n throw new e.BadDigestError(`Docker-Content-Digest header, ${dcdInfo.raw}, does not match ` +\n `given digest, ${opts.digest}`);\n }\n // Validate the digest\n await dcdInfo.validate(buffer);\n }\n return { ress, buffer };\n }\n /**\n * Upload a blob using POST then PUT workflow.\n * <https://github.com/opencontainers/distribution-spec/blob/main/spec.md#post-then-put>\n *\n * @param opts.data The blob data as ArrayBuffer or Uint8Array\n * @param opts.digest Optional digest. If not provided, it will be calculated.\n * @returns Object with digest and size of the uploaded blob\n */\n async pushBlob(opts) {\n await this.login();\n // Convert to ArrayBuffer if needed\n const buffer = opts.data instanceof Uint8Array\n ? new Uint8Array(opts.data).buffer\n : opts.data;\n // Calculate digest\n const hashBuffer = await getCrypto().subtle.digest(\"SHA-256\", buffer);\n const digest = `sha256:${encodeHex(hashBuffer)}`;\n // Step 1: POST to initiate upload\n const postUrl = new URL(`/v2/${encodeURI(this.repo.remoteName)}/blobs/uploads/`, this._url);\n const postHeaders = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-length\": \"0\",\n };\n const postResp = await this._adapter.fetch(postUrl.toString(), {\n method: \"POST\",\n headers: postHeaders,\n });\n if (postResp.status !== 202) {\n throw new Error(`Failed to initiate blob upload: HTTP ${postResp.status}`);\n }\n // Get upload URL from Location header\n const uploadLocation = postResp.headers.get(\"location\");\n if (!uploadLocation) {\n throw new Error(\"No Location header in POST response\");\n }\n // Step 2: PUT to upload blob\n const uploadUrl = new URL(uploadLocation, this._url);\n uploadUrl.searchParams.set(\"digest\", digest);\n const putHeaders = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-type\": \"application/octet-stream\",\n \"content-length\": buffer.byteLength.toString(),\n };\n const putResp = await this._adapter.fetch(uploadUrl.toString(), {\n method: \"PUT\",\n headers: putHeaders,\n body: buffer,\n });\n if (putResp.status !== 201) {\n throw new Error(`Failed to upload blob: HTTP ${putResp.status}`);\n }\n // Verify digest from response\n const returnedDigest = putResp.headers.get(\"docker-content-digest\");\n if (returnedDigest && returnedDigest !== digest) {\n throw new e.BadDigestError(`Digest mismatch: expected ${digest}, got ${returnedDigest}`);\n }\n return { digest, size: buffer.byteLength };\n }\n /**\n * Upload an image manifest.\n * <https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-manifests>\n *\n * @param opts.ref The tag or digest to push to\n * @param opts.manifest The manifest object to upload\n * @param opts.mediaType Optional media type (defaults to OCI manifest type)\n * @returns Object with digest and size of the uploaded manifest\n */\n async pushManifest(opts) {\n await this.login();\n const manifestStr = JSON.stringify(opts.manifest);\n const manifestBuffer = new TextEncoder().encode(manifestStr);\n // Calculate digest\n const digest = await digestFromManifestStr(manifestStr);\n const url = new URL(`/v2/${encodeURI(this.repo.remoteName)}/manifests/${encodeURI(opts.ref)}`, this._url);\n const headers = {\n ...this._headers,\n \"user-agent\": this._userAgent,\n \"content-type\": opts.mediaType || \"application/vnd.oci.image.manifest.v1+json\",\n \"content-length\": manifestBuffer.byteLength.toString(),\n };\n const resp = await this._adapter.fetch(url.toString(), {\n method: \"PUT\",\n headers,\n body: manifestBuffer,\n });\n if (resp.status !== 201) {\n throw new Error(`Failed to push manifest: HTTP ${resp.status}`);\n }\n // Verify digest from response\n const returnedDigest = resp.headers.get(\"docker-content-digest\");\n if (returnedDigest && returnedDigest !== digest) {\n throw new e.BadDigestError(`Digest mismatch: expected ${digest}, got ${returnedDigest}`);\n }\n return { digest, size: manifestBuffer.byteLength };\n }\n /**\n * Push a plugin manifest as a config blob and create an OCI manifest.\n * This follows the OCI spec where the Obsidian manifest is stored as the config.\n *\n * @param opts.ref The tag or digest to push to\n * @param opts.pluginManifest The Obsidian plugin manifest\n * @param opts.layers The layer descriptors (main.js, styles.css, etc.)\n * @param opts.annotations Optional annotations for the OCI manifest\n * @returns Object with digest, configDigest, and the created manifest\n */\n async pushPluginManifest(opts) {\n // Step 1: Push plugin manifest as config blob\n const manifestStr = JSON.stringify(opts.pluginManifest);\n const manifestBuffer = new TextEncoder().encode(manifestStr);\n const configResult = await this.pushBlob({\n data: manifestBuffer,\n });\n // Step 2: Build OCI manifest with plugin manifest as config\n const manifest = {\n schemaVersion: 2,\n mediaType: MEDIATYPE_OCI_MANIFEST_V1,\n artifactType: \"application/vnd.obsidian.plugin.v1+json\",\n config: {\n mediaType: MEDIATYPE_OBSIDIAN_PLUGIN_CONFIG_V1,\n digest: configResult.digest,\n size: configResult.size,\n },\n layers: opts.layers,\n annotations: opts.annotations,\n };\n // Step 3: Push the OCI manifest\n const manifestResult = await this.pushManifest({\n ref: opts.ref,\n manifest,\n mediaType: MEDIATYPE_OCI_MANIFEST_V1,\n });\n return {\n digest: manifestResult.digest,\n configDigest: configResult.digest,\n manifest,\n };\n }\n /**\n * Pull a plugin manifest by extracting it from the OCI config blob.\n * This follows the OCI spec where the Obsidian manifest is stored as the config.\n *\n * @param opts.ref The tag or digest to pull\n * @returns Object with the plugin manifest, OCI manifest, and digests\n */\n async pullPluginManifest(opts) {\n // Step 1: Pull the OCI manifest\n const manifestResult = await this.getManifest({ ref: opts.ref });\n const manifest = manifestResult.manifest;\n // Step 2: Validate manifest has config\n if (!(\"config\" in manifest) || !manifest.config) {\n throw new Error(\"Manifest does not contain a config\");\n }\n const ociManifest = manifest;\n const manifestDigest = manifestResult.resp.headers.get(\"docker-content-digest\") || \"\";\n // Step 3: Pull the config blob\n const { buffer: configBuffer } = await this.downloadBlob({\n digest: ociManifest.config.digest,\n });\n // Step 4: Parse the plugin manifest from config\n const configText = new TextDecoder().decode(configBuffer);\n const pluginManifest = JSON.parse(configText);\n return {\n pluginManifest,\n manifest: ociManifest,\n manifestDigest,\n configDigest: ociManifest.config.digest,\n };\n }\n}\n", "import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type { ObsidianManifest } from \"@shard-for-obsidian/lib\";\n\nexport interface DiscoveredPlugin {\n directory: string;\n manifest: {\n path: string;\n content: ArrayBuffer;\n parsed: ObsidianManifest;\n };\n mainJs: {\n path: string;\n content: ArrayBuffer;\n };\n stylesCss?: {\n path: string;\n content: ArrayBuffer;\n };\n}\n\n/**\n * Discover plugin files in a directory.\n * Finds manifest.json (required), main.js (required), and styles.css (optional).\n *\n * @param directory - Directory to scan for plugin files\n * @returns Discovered plugin information\n * @throws Error if required files are missing or invalid\n */\nexport async function discoverPlugin(\n directory: string,\n): Promise<DiscoveredPlugin> {\n // Resolve absolute path\n const absDirectory = path.resolve(directory);\n\n // Check directory exists\n try {\n const stat = await fs.stat(absDirectory);\n if (!stat.isDirectory()) {\n throw new Error(`Not a directory: ${directory}`);\n }\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`Directory not found: ${directory}`);\n }\n throw err;\n }\n\n // Find manifest.json (required)\n const manifestPath = path.join(absDirectory, \"manifest.json\");\n let manifestContent: ArrayBuffer;\n let manifestParsed: ObsidianManifest;\n\n try {\n const buffer = await fs.readFile(manifestPath);\n manifestContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n\n // Parse and validate manifest\n const text = new TextDecoder().decode(manifestContent);\n const parsed = JSON.parse(text) as Record<string, unknown>;\n\n // Validate required fields\n if (!parsed.version || typeof parsed.version !== \"string\") {\n throw new Error('manifest.json missing required \"version\" field');\n }\n if (!parsed.id || typeof parsed.id !== \"string\") {\n throw new Error('manifest.json missing required \"id\" field');\n }\n if (!parsed.name || typeof parsed.name !== \"string\") {\n throw new Error('manifest.json missing required \"name\" field');\n }\n if (!parsed.minAppVersion || typeof parsed.minAppVersion !== \"string\") {\n throw new Error('manifest.json missing required \"minAppVersion\" field');\n }\n if (!parsed.description || typeof parsed.description !== \"string\") {\n throw new Error('manifest.json missing required \"description\" field');\n }\n if (!parsed.author || typeof parsed.author !== \"string\") {\n throw new Error('manifest.json missing required \"author\" field');\n }\n\n manifestParsed = parsed as unknown as ObsidianManifest;\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`manifest.json not found in ${directory}`);\n }\n if (err instanceof SyntaxError) {\n throw new Error(`Could not parse manifest.json: ${err.message}`);\n }\n throw err;\n }\n\n // Find main.js (required)\n const mainJsPath = path.join(absDirectory, \"main.js\");\n let mainJsContent: ArrayBuffer;\n\n try {\n const buffer = await fs.readFile(mainJsPath);\n mainJsContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n throw new Error(`main.js not found in ${directory}`);\n }\n throw err;\n }\n\n // Find styles.css (optional)\n const stylesCssPath = path.join(absDirectory, \"styles.css\");\n let stylesCssContent: ArrayBuffer | undefined;\n\n try {\n const buffer = await fs.readFile(stylesCssPath);\n stylesCssContent = buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength,\n );\n } catch (err) {\n if (\n err &&\n typeof err === \"object\" &&\n \"code\" in err &&\n err.code === \"ENOENT\"\n ) {\n // styles.css is optional, ignore error\n stylesCssContent = undefined;\n } else {\n throw err;\n }\n }\n\n return {\n directory: absDirectory,\n manifest: {\n path: manifestPath,\n content: manifestContent,\n parsed: manifestParsed,\n },\n mainJs: {\n path: mainJsPath,\n content: mainJsContent,\n },\n ...(stylesCssContent && {\n stylesCss: {\n path: stylesCssPath,\n content: stylesCssContent,\n },\n }),\n };\n}\n", "import { OciRegistryClient, parseRepoAndRef } from \"@shard-for-obsidian/lib\";\nimport type {\n ManifestOCIDescriptor,\n FetchAdapter,\n ObsidianManifest,\n} from \"@shard-for-obsidian/lib\";\nimport { discoverPlugin } from \"../lib/plugin.js\";\nimport { Logger } from \"../lib/logger.js\";\n\n/**\n * Derive GitHub repository URL from registry remote name.\n * Takes the first two path components to form owner/repo.\n *\n * Examples:\n * shard-for-obsidian/shard -> https://github.com/shard-for-obsidian/shard\n * shard-for-obsidian/shard/plugin -> https://github.com/shard-for-obsidian/shard\n */\nfunction deriveGitHubUrl(remoteName: string): string {\n const parts = remoteName.split('/');\n if (parts.length < 2) {\n throw new Error(\n `Cannot derive GitHub URL from ${remoteName}. Need at least owner/repo format.`,\n );\n }\n\n const owner = parts[0];\n const repo = parts[1];\n return `https://github.com/${owner}/${repo}`;\n}\n\nexport interface PushOptions {\n directory: string;\n repository: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface PushResult {\n digest: string;\n tag: string;\n size: number;\n repository: string;\n}\n\n/**\n * Push an Obsidian plugin to GHCR.\n *\n * @param opts - Push options\n * @returns Push result with digest and tag\n */\nexport async function pushCommand(opts: PushOptions): Promise<PushResult> {\n const { directory, repository, token, logger, adapter } = opts;\n\n // Step 1: Discover plugin files\n logger.log(`Discovering plugin files in ${directory}...`);\n const plugin = await discoverPlugin(directory);\n const version = plugin.manifest.parsed.version;\n logger.log(`Found plugin version ${version}`);\n\n // Step 2: Parse repository and add version tag\n const fullRef = repository.includes(\":\")\n ? repository\n : `${repository}:${version}`;\n logger.log(`Pushing to ${fullRef}...`);\n\n const ref = parseRepoAndRef(fullRef);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n scopes: [\"push\", \"pull\"],\n });\n\n // Step 3: Push each file as a blob\n const layers: ManifestOCIDescriptor[] = [];\n\n // No longer need to push manifest.json as a layer - it's now in the config\n\n // Push main.js\n logger.log(\"Pushing main.js...\");\n const mainJsResult = await client.pushBlob({\n data: plugin.mainJs.content,\n });\n layers.push({\n mediaType: \"application/javascript\",\n digest: mainJsResult.digest,\n size: mainJsResult.size,\n annotations: {\n \"vnd.obsidianmd.layer.filename\": \"main.js\",\n },\n });\n logger.log(\n `Pushed main.js: ${mainJsResult.digest.slice(0, 19)}... (${mainJsResult.size} bytes)`,\n );\n\n // Push styles.css if present\n if (plugin.stylesCss) {\n logger.log(\"Pushing styles.css...\");\n const stylesCssResult = await client.pushBlob({\n data: plugin.stylesCss.content,\n });\n layers.push({\n mediaType: \"text/css\",\n digest: stylesCssResult.digest,\n size: stylesCssResult.size,\n annotations: {\n \"vnd.obsidianmd.layer.filename\": \"styles.css\",\n },\n });\n logger.log(\n `Pushed styles.css: ${stylesCssResult.digest.slice(0, 19)}... (${stylesCssResult.size} bytes)`,\n );\n }\n\n // Step 4: Derive GitHub URL and prepare annotations\n const githubUrl = deriveGitHubUrl(ref.remoteName);\n const manifest = plugin.manifest.parsed;\n\n const annotations: Record<string, string> = {\n \"vnd.obsidianmd.plugin.id\": manifest.id,\n \"vnd.obsidianmd.plugin.name\": manifest.name,\n \"vnd.obsidianmd.plugin.version\": manifest.version,\n \"vnd.obsidianmd.plugin.description\": manifest.description,\n \"vnd.obsidianmd.plugin.author\": manifest.author,\n \"vnd.obsidianmd.plugin.repo\": githubUrl,\n \"vnd.obsidianmd.plugin.published-at\": new Date().toISOString(),\n };\n\n // Add optional fields if present\n if (manifest.authorUrl) {\n annotations[\"vnd.obsidianmd.plugin.author-url\"] = manifest.authorUrl;\n }\n if (manifest.minAppVersion) {\n annotations[\"vnd.obsidianmd.plugin.min-app-version\"] = manifest.minAppVersion;\n }\n\n // Step 5: Push plugin manifest using new method\n logger.log(\"Pushing plugin manifest...\");\n const manifestPushResult = await client.pushPluginManifest({\n ref: ref.tag || version,\n pluginManifest: manifest as unknown as ObsidianManifest,\n layers,\n annotations,\n });\n\n logger.success(`Successfully pushed ${fullRef}`);\n logger.log(`Manifest digest: ${manifestPushResult.digest}`);\n logger.log(`GitHub repository: ${githubUrl}`);\n\n // Calculate total size from manifest\n const totalSize = manifestPushResult.manifest.layers.reduce(\n (sum, layer) => sum + layer.size,\n 0,\n );\n\n return {\n digest: manifestPushResult.digest,\n tag: ref.tag || version,\n size: totalSize,\n repository: fullRef,\n };\n}\n", "import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { OciRegistryClient, parseRepoAndRef } from \"@shard-for-obsidian/lib\";\nimport type { FetchAdapter } from \"@shard-for-obsidian/lib\";\nimport { Logger } from \"../lib/logger.js\";\n\nexport interface PullOptions {\n repository: string;\n output: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface PullResult {\n files: string[];\n output: string;\n digest: string;\n}\n\n/**\n * Pull an Obsidian plugin from GHCR.\n *\n * @param opts - Pull options\n * @returns Pull result with extracted files\n */\nexport async function pullCommand(opts: PullOptions): Promise<PullResult> {\n const { repository, output, token, logger, adapter } = opts;\n\n // Step 1: Parse repository reference\n logger.log(`Pulling ${repository}...`);\n const ref = parseRepoAndRef(repository);\n\n if (!ref.tag && !ref.digest) {\n throw new Error(\"Repository reference must include tag or digest\");\n }\n\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n });\n\n // Step 2: Fetch manifest and extract plugin manifest from config\n logger.log(\"Fetching manifest...\");\n const refString = ref.tag || ref.digest || \"\";\n const pullResult = await client.pullPluginManifest({ ref: refString });\n const manifest = pullResult.manifest;\n\n logger.log(`Manifest digest: ${pullResult.manifestDigest}`);\n\n // Step 3: Create output directory if needed\n const absOutput = path.resolve(output);\n logger.log(`Creating output directory: ${absOutput}`);\n await fs.mkdir(absOutput, { recursive: true });\n\n // Step 4: Write manifest.json from config\n const manifestPath = path.join(absOutput, \"manifest.json\");\n const manifestJson = JSON.stringify(pullResult.pluginManifest, null, 2);\n await fs.writeFile(manifestPath, manifestJson, \"utf-8\");\n logger.log(`Wrote manifest.json (${manifestJson.length} bytes)`);\n\n const files: string[] = [\"manifest.json\"];\n\n // Step 5: Download and extract each layer\n for (const layer of manifest.layers) {\n // Extract filename from annotation\n const filename = layer.annotations?.[\"vnd.obsidianmd.layer.filename\"];\n if (!filename) {\n throw new Error(\n `Layer ${layer.digest} missing required filename annotation`,\n );\n }\n\n logger.log(`Downloading ${filename}...`);\n\n // Download blob\n const blobResult = await client.downloadBlob({\n digest: layer.digest,\n });\n\n // Write to output directory\n const filePath = path.join(absOutput, filename);\n const buffer = Buffer.from(blobResult.buffer);\n await fs.writeFile(filePath, buffer);\n\n logger.log(`Wrote ${filename} (${buffer.length} bytes)`);\n files.push(filename);\n }\n\n logger.success(`Successfully pulled ${repository}`);\n logger.log(`Files extracted to: ${absOutput}`);\n\n return {\n files,\n output: absOutput,\n digest: pullResult.manifestDigest,\n };\n}\n", "/**\n * URL to the Obsidian community plugins JSON file\n */\nexport const COMMUNITY_PLUGINS_URL =\n \"https://raw.githubusercontent.com/obsidianmd/obsidian-releases/refs/heads/master/community-plugins.json\";\n\n/**\n * Represents a community plugin entry from the Obsidian marketplace\n */\nexport interface CommunityPlugin {\n /** Plugin ID (used in folder name and as identifier) */\n id: string;\n /** Display name of the plugin */\n name: string;\n /** Author name */\n author: string;\n /** Plugin description */\n description: string;\n /** GitHub repository in format \"owner/repo\" */\n repo: string;\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\nimport {\n COMMUNITY_PLUGINS_URL,\n type CommunityPlugin,\n} from \"./community-plugins.js\";\n\n/**\n * Cache for Obsidian community plugins.\n * Fetches and caches the list of community plugins from the official repository.\n */\nexport class CommunityPluginsCache {\n private adapter: FetchAdapter;\n private plugins: CommunityPlugin[] | null = null;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * Fetch the list of community plugins.\n * Results are cached for subsequent calls.\n *\n * @returns Array of community plugins\n * @throws Error if fetch fails\n */\n async fetch(): Promise<CommunityPlugin[]> {\n // Return cached data if available\n if (this.plugins !== null) {\n return this.plugins;\n }\n\n // Fetch from URL\n const response = await this.adapter.fetch(COMMUNITY_PLUGINS_URL);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch community plugins: ${response.status}`);\n }\n\n const plugins = (await response.json()) as CommunityPlugin[];\n this.plugins = plugins;\n return plugins;\n }\n\n /**\n * Find a plugin by ID.\n * Fetches the plugin list if not already cached.\n *\n * @param id - Plugin ID to search for\n * @returns Plugin if found, undefined otherwise\n */\n async findPlugin(id: string): Promise<CommunityPlugin | undefined> {\n const plugins = await this.fetch();\n return plugins.find((plugin) => plugin.id === id);\n }\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\n\n/**\n * Represents a GitHub release asset\n */\nexport interface GitHubReleaseAsset {\n /** Name of the asset file */\n name: string;\n /** URL to download the asset */\n browser_download_url: string;\n}\n\n/**\n * Represents a GitHub release\n */\nexport interface GitHubRelease {\n /** Tag name of the release (e.g., \"1.2.3\") */\n tag_name: string;\n /** Array of release assets */\n assets: GitHubReleaseAsset[];\n}\n\n/**\n * Fetcher for GitHub releases.\n * Provides methods to fetch releases from the GitHub API.\n */\nexport class GitHubReleaseFetcher {\n private adapter: FetchAdapter;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n }\n\n /**\n * Fetch the latest release from a GitHub repository.\n *\n * @param repo - Repository in format \"owner/repo\"\n * @param token - Optional GitHub token for authentication\n * @returns Latest release information\n * @throws Error if fetch fails\n */\n async fetchLatestRelease(\n repo: string,\n token?: string,\n ): Promise<GitHubRelease> {\n const url = `https://api.github.com/repos/${repo}/releases/latest`;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await this.adapter.fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch latest release: ${response.status}`);\n }\n\n return (await response.json()) as GitHubRelease;\n }\n\n /**\n * Fetch a specific release by tag from a GitHub repository.\n *\n * @param repo - Repository in format \"owner/repo\"\n * @param tag - Tag name (e.g., \"1.2.3\")\n * @param token - Optional GitHub token for authentication\n * @returns Release information\n * @throws Error if fetch fails\n */\n async fetchReleaseByTag(\n repo: string,\n tag: string,\n token?: string,\n ): Promise<GitHubRelease> {\n const url = `https://api.github.com/repos/${repo}/releases/tags/${tag}`;\n const headers: Record<string, string> = {\n Accept: \"application/vnd.github.v3+json\",\n };\n\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n const response = await this.adapter.fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch release ${tag}: ${response.status}`);\n }\n\n return (await response.json()) as GitHubRelease;\n }\n}\n", "import type {\n FetchAdapter,\n ObsidianManifest,\n ManifestOCIDescriptor,\n} from \"@shard-for-obsidian/lib\";\nimport { OciRegistryClient, parseRepoAndRef } from \"@shard-for-obsidian/lib\";\nimport { CommunityPluginsCache } from \"./community-cache.js\";\nimport { GitHubReleaseFetcher } from \"./github-release.js\";\n\n/**\n * Options for converting a plugin\n */\nexport interface ConvertPluginOptions {\n /** Plugin ID from community plugins list */\n pluginId: string;\n /** Optional specific version to convert (defaults to latest) */\n version?: string;\n /** Target OCI repository */\n repository: string;\n /** GitHub token for authentication */\n token: string;\n}\n\n/**\n * Result of a plugin conversion\n */\nexport interface ConvertPluginResult {\n /** Plugin ID */\n pluginId: string;\n /** Plugin version */\n version: string;\n /** Target repository with tag */\n repository: string;\n /** GitHub repository URL */\n githubRepo: string;\n /** Parsed manifest */\n manifest: ObsidianManifest;\n /** main.js content */\n mainJs: string;\n /** styles.css content (if present) */\n stylesCss?: string;\n}\n\n/**\n * Options for pushing to registry\n */\nexport interface PushToRegistryOptions {\n /** Repository with tag */\n repository: string;\n /** GitHub repository URL */\n githubRepo: string;\n /** GitHub token */\n token: string;\n /** Plugin data to push */\n pluginData: {\n manifest: ObsidianManifest;\n mainJs: string;\n stylesCss?: string;\n };\n}\n\n/**\n * Result of pushing to registry\n */\nexport interface PushToRegistryResult {\n /** Manifest digest */\n digest: string;\n /** Tag */\n tag: string;\n /** Size */\n size: number;\n /** Repository */\n repository: string;\n}\n\n/**\n * Converts legacy Obsidian plugins to OCI format.\n * Fetches plugins from GitHub releases and pushes to OCI registry.\n */\nexport class PluginConverter {\n private adapter: FetchAdapter;\n private communityCache: CommunityPluginsCache;\n private releaseFetcher: GitHubReleaseFetcher;\n\n constructor(adapter: FetchAdapter) {\n this.adapter = adapter;\n this.communityCache = new CommunityPluginsCache(adapter);\n this.releaseFetcher = new GitHubReleaseFetcher(adapter);\n }\n\n /**\n * Convert a plugin from GitHub releases to OCI format.\n *\n * @param options - Conversion options\n * @returns Conversion result with plugin data\n * @throws Error if plugin not found or conversion fails\n */\n async convertPlugin(\n options: ConvertPluginOptions,\n ): Promise<ConvertPluginResult> {\n const { pluginId, version, repository, token } = options;\n\n // Step 1: Find plugin in community list\n const plugin = await this.communityCache.findPlugin(pluginId);\n if (!plugin) {\n throw new Error(`Plugin \"${pluginId}\" not found in community plugins`);\n }\n\n // Step 2: Fetch release from GitHub\n const release = version\n ? await this.releaseFetcher.fetchReleaseByTag(plugin.repo, version, token)\n : await this.releaseFetcher.fetchLatestRelease(plugin.repo, token);\n\n // Step 3: Find required assets\n const manifestAsset = release.assets.find(\n (a) => a.name === \"manifest.json\",\n );\n const mainJsAsset = release.assets.find((a) => a.name === \"main.js\");\n const stylesCssAsset = release.assets.find((a) => a.name === \"styles.css\");\n\n if (!manifestAsset) {\n throw new Error(\"manifest.json not found in release\");\n }\n if (!mainJsAsset) {\n throw new Error(\"main.js not found in release\");\n }\n\n // Step 4: Download assets\n const manifestResponse = await this.adapter.fetch(\n manifestAsset.browser_download_url,\n );\n if (!manifestResponse.ok) {\n throw new Error(\n `Failed to download manifest.json: ${manifestResponse.status}`,\n );\n }\n const manifestJson = await manifestResponse.text();\n const manifest = JSON.parse(manifestJson) as ObsidianManifest;\n\n const mainJsResponse = await this.adapter.fetch(\n mainJsAsset.browser_download_url,\n );\n if (!mainJsResponse.ok) {\n throw new Error(`Failed to download main.js: ${mainJsResponse.status}`);\n }\n const mainJs = await mainJsResponse.text();\n\n let stylesCss: string | undefined;\n if (stylesCssAsset) {\n const stylesCssResponse = await this.adapter.fetch(\n stylesCssAsset.browser_download_url,\n );\n if (!stylesCssResponse.ok) {\n throw new Error(\n `Failed to download styles.css: ${stylesCssResponse.status}`,\n );\n }\n stylesCss = await stylesCssResponse.text();\n }\n\n // Step 5: Build result\n const fullRepository = repository.includes(\":\")\n ? repository\n : `${repository}:${release.tag_name}`;\n\n return {\n pluginId,\n version: release.tag_name,\n repository: fullRepository,\n githubRepo: plugin.repo,\n manifest,\n mainJs,\n stylesCss,\n };\n }\n\n /**\n * Push plugin data to OCI registry.\n *\n * @param options - Push options\n * @returns Push result\n * @throws Error if push fails\n */\n async pushToRegistry(\n options: PushToRegistryOptions,\n ): Promise<PushToRegistryResult> {\n const { repository, githubRepo, token, pluginData } = options;\n\n // Parse repository reference\n const ref = parseRepoAndRef(repository);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter: this.adapter,\n scopes: [\"push\", \"pull\"],\n });\n\n // Push blobs\n const layers: ManifestOCIDescriptor[] = [];\n\n // Push main.js\n const mainJsResult = await client.pushBlob({\n data: new TextEncoder().encode(pluginData.mainJs),\n });\n layers.push({\n mediaType: \"application/javascript\",\n digest: mainJsResult.digest,\n size: mainJsResult.size,\n annotations: {\n \"vnd.obsidianmd.layer.filename\": \"main.js\",\n },\n });\n\n // Push styles.css if present\n if (pluginData.stylesCss) {\n const stylesCssResult = await client.pushBlob({\n data: new TextEncoder().encode(pluginData.stylesCss),\n });\n layers.push({\n mediaType: \"text/css\",\n digest: stylesCssResult.digest,\n size: stylesCssResult.size,\n annotations: {\n \"vnd.obsidianmd.layer.filename\": \"styles.css\",\n },\n });\n }\n\n // Push manifest with vendor annotations\n const annotations: Record<string, string> = {\n \"vnd.obsidianmd.plugin.id\": pluginData.manifest.id,\n \"vnd.obsidianmd.plugin.name\": pluginData.manifest.name,\n \"vnd.obsidianmd.plugin.version\": pluginData.manifest.version,\n \"vnd.obsidianmd.plugin.description\": pluginData.manifest.description,\n \"vnd.obsidianmd.plugin.author\": pluginData.manifest.author,\n \"vnd.obsidianmd.plugin.repo\": githubRepo,\n \"vnd.obsidianmd.plugin.published-at\": new Date().toISOString(),\n \"vnd.obsidianmd.plugin.converted\": \"true\",\n \"vnd.obsidianmd.plugin.original-repo\": \"obsidianmd/obsidian-releases\",\n };\n\n // Add optional fields if present\n if (pluginData.manifest.authorUrl) {\n annotations[\"vnd.obsidianmd.plugin.author-url\"] = pluginData.manifest.authorUrl;\n }\n if (pluginData.manifest.minAppVersion) {\n annotations[\"vnd.obsidianmd.plugin.min-app-version\"] = pluginData.manifest.minAppVersion;\n }\n\n const manifestPushResult = await client.pushPluginManifest({\n ref: ref.tag || pluginData.manifest.version,\n pluginManifest: pluginData.manifest,\n layers,\n annotations,\n });\n\n // Calculate total size from manifest\n const totalSize = manifestPushResult.manifest.layers.reduce(\n (sum, layer) => sum + layer.size,\n 0,\n );\n\n return {\n digest: manifestPushResult.digest,\n tag: ref.tag || pluginData.manifest.version,\n size: totalSize,\n repository,\n };\n }\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\nimport { PluginConverter } from \"../lib/converter.js\";\nimport { Logger } from \"../lib/logger.js\";\n\nexport interface ConvertOptions {\n pluginId: string;\n repository: string;\n version?: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface ConvertResult {\n pluginId: string;\n version: string;\n repository: string;\n digest: string;\n size: number;\n}\n\n/**\n * Convert a legacy Obsidian plugin from GitHub releases to OCI format.\n *\n * @param opts - Convert options\n * @returns Convert result with digest and repository\n */\nexport async function convertCommand(\n opts: ConvertOptions,\n): Promise<ConvertResult> {\n const { pluginId, repository, version, token, logger, adapter } = opts;\n\n // Step 1: Create converter\n const converter = new PluginConverter(adapter);\n\n // Step 2: Convert plugin from GitHub releases\n logger.log(`Converting plugin \"${pluginId}\"...`);\n if (version) {\n logger.log(`Using specific version: ${version}`);\n } else {\n logger.log(\"Using latest version\");\n }\n\n const convertResult = await converter.convertPlugin({\n pluginId,\n version,\n repository,\n token,\n });\n\n logger.log(\n `Downloaded plugin ${convertResult.pluginId} v${convertResult.version}`,\n );\n logger.log(` - manifest.json: ${convertResult.manifest.name}`);\n logger.log(` - main.js: ${convertResult.mainJs.length} bytes`);\n if (convertResult.stylesCss) {\n logger.log(` - styles.css: ${convertResult.stylesCss.length} bytes`);\n }\n\n // Step 3: Push to OCI registry\n logger.log(`\\nPushing to ${convertResult.repository}...`);\n const pushResult = await converter.pushToRegistry({\n repository: convertResult.repository,\n githubRepo: convertResult.githubRepo,\n token,\n pluginData: {\n manifest: convertResult.manifest,\n mainJs: convertResult.mainJs,\n stylesCss: convertResult.stylesCss,\n },\n });\n\n logger.success(\n `Successfully converted and pushed ${convertResult.pluginId} v${convertResult.version}`,\n );\n logger.log(`Manifest digest: ${pushResult.digest}`);\n logger.log(`Repository: ${pushResult.repository}`);\n\n return {\n pluginId: convertResult.pluginId,\n version: convertResult.version,\n repository: pushResult.repository,\n digest: pushResult.digest,\n size: pushResult.size,\n };\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\n\nexport interface PluginVersion {\n tag: string;\n publishedAt: string; // ISO 8601\n size: number; // bytes\n annotations: Record<string, string>;\n}\n\nexport interface MarketplacePlugin {\n // Primary identifiers\n id: string;\n registryUrl: string; // ghcr.io/owner/repo (PRIMARY)\n\n // Metadata from manifest\n name: string;\n author: string;\n description: string;\n\n // Optional metadata\n license?: string;\n minObsidianVersion?: string;\n authorUrl?: string;\n\n // Derived/optional\n repository?: string; // GitHub URL derived from vnd.obsidianmd.plugin.repo\n tags?: string[]; // For categorization\n\n // New fields\n introduction?: string; // Markdown content from file body\n versions?: PluginVersion[]; // All available versions from OCI\n}\n\nexport interface MarketplaceIndex {\n plugins: MarketplacePlugin[];\n generatedAt: string; // ISO 8601 timestamp\n}\n\nexport const DEFAULT_MARKETPLACE_URL =\n \"https://shard-for-obsidian.github.io/shard/plugins.json\";\n\n/**\n * Client for fetching marketplace data from the registry.\n */\nexport class MarketplaceClient {\n constructor(\n private adapter: FetchAdapter,\n private marketplaceUrl: string = DEFAULT_MARKETPLACE_URL,\n ) {}\n\n /**\n * Fetch all plugins from the marketplace.\n */\n async fetchPlugins(): Promise<MarketplacePlugin[]> {\n const response = await this.adapter.fetch(this.marketplaceUrl);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch marketplace data: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as MarketplaceIndex;\n\n if (!data.plugins || !Array.isArray(data.plugins)) {\n throw new Error(\"Invalid marketplace data format\");\n }\n\n return data.plugins;\n }\n\n /**\n * Find a plugin by ID.\n */\n async findPluginById(pluginId: string): Promise<MarketplacePlugin | null> {\n const plugins = await this.fetchPlugins();\n return plugins.find((p) => p.id === pluginId) || null;\n }\n\n /**\n * Search plugins by keyword (searches in name, description, author, tags).\n */\n async searchPlugins(keyword: string): Promise<MarketplacePlugin[]> {\n const plugins = await this.fetchPlugins();\n const lowerKeyword = keyword.toLowerCase();\n\n return plugins.filter(\n (p) =>\n p.name.toLowerCase().includes(lowerKeyword) ||\n p.description.toLowerCase().includes(lowerKeyword) ||\n p.author.toLowerCase().includes(lowerKeyword) ||\n p.id.toLowerCase().includes(lowerKeyword) ||\n p.tags?.some((tag) => tag.toLowerCase().includes(lowerKeyword)),\n );\n }\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\nimport { parseRepoAndRef } from \"@shard-for-obsidian/lib\";\n\nexport interface QueryOciTagsOptions {\n registryUrl: string;\n adapter: FetchAdapter;\n token?: string;\n}\n\nexport interface QueryTagMetadataOptions {\n registryUrl: string;\n tag: string;\n adapter: FetchAdapter;\n token?: string;\n}\n\ninterface AuthChallenge {\n realm: string;\n service: string;\n scope: string;\n}\n\nexport interface TagMetadata {\n publishedAt: string;\n size: number;\n annotations: Record<string, string>;\n}\n\n/**\n * Parse WWW-Authenticate header to extract auth challenge.\n */\nfunction parseAuthChallenge(header: string): AuthChallenge | null {\n // Format: Bearer realm=\"...\",service=\"...\",scope=\"...\"\n const realmMatch = /realm=\"([^\"]+)\"/.exec(header);\n const serviceMatch = /service=\"([^\"]+)\"/.exec(header);\n const scopeMatch = /scope=\"([^\"]+)\"/.exec(header);\n\n if (!realmMatch || !serviceMatch || !scopeMatch) {\n return null;\n }\n\n return {\n realm: realmMatch[1],\n service: serviceMatch[1],\n scope: scopeMatch[1],\n };\n}\n\n/**\n * Exchange GitHub token for OCI registry token.\n */\nasync function getRegistryToken(\n challenge: AuthChallenge,\n adapter: FetchAdapter,\n githubToken: string,\n): Promise<string | null> {\n const url = `${challenge.realm}?service=${challenge.service}&scope=${challenge.scope}`;\n\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n };\n\n // For GHCR, we need to use Basic auth with the GitHub token\n // Username can be anything, password is the token\n if (githubToken) {\n const basicAuth = Buffer.from(`token:${githubToken}`).toString(\"base64\");\n headers.Authorization = `Basic ${basicAuth}`;\n }\n\n try {\n const response = await adapter.fetch(url, { headers });\n\n if (!response.ok) {\n return null;\n }\n\n const data = (await response.json()) as { token?: string };\n return data.token || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Query all available tags from an OCI registry.\n */\nexport async function queryOciTags(\n opts: QueryOciTagsOptions,\n): Promise<string[]> {\n const { registryUrl, adapter, token } = opts;\n const ref = parseRepoAndRef(registryUrl);\n\n // OCI Distribution API: GET /v2/<name>/tags/list\n const url = `https://${ref.index.name}/v2/${ref.remoteName}/tags/list`;\n\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n };\n\n // Try initial request\n let response = await adapter.fetch(url, { headers });\n\n // If 401, try to exchange token and retry\n if (response.status === 401 && token) {\n const wwwAuth = response.headers.get(\"www-authenticate\");\n if (wwwAuth) {\n const challenge = parseAuthChallenge(wwwAuth);\n if (challenge) {\n const registryToken = await getRegistryToken(challenge, adapter, token);\n if (registryToken) {\n headers.Authorization = `Bearer ${registryToken}`;\n response = await adapter.fetch(url, { headers });\n }\n }\n }\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to query OCI tags: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = (await response.json()) as { tags?: string[] };\n\n return data.tags || [];\n}\n\n/**\n * Query metadata for a specific tag.\n */\nexport async function queryTagMetadata(\n opts: QueryTagMetadataOptions,\n): Promise<TagMetadata> {\n const { registryUrl, tag, adapter, token } = opts;\n const ref = parseRepoAndRef(registryUrl);\n\n // OCI Distribution API: GET /v2/<name>/manifests/<tag>\n const url = `https://${ref.index.name}/v2/${ref.remoteName}/manifests/${tag}`;\n\n const headers: Record<string, string> = {\n Accept: \"application/vnd.oci.image.manifest.v1+json\",\n };\n\n // Try initial request\n let response = await adapter.fetch(url, { headers });\n\n // If 401, try to exchange token and retry\n if (response.status === 401 && token) {\n const wwwAuth = response.headers.get(\"www-authenticate\");\n if (wwwAuth) {\n const challenge = parseAuthChallenge(wwwAuth);\n if (challenge) {\n const registryToken = await getRegistryToken(challenge, adapter, token);\n if (registryToken) {\n headers.Authorization = `Bearer ${registryToken}`;\n response = await adapter.fetch(url, { headers });\n }\n }\n }\n }\n\n if (!response.ok) {\n throw new Error(\n `Failed to query tag metadata: ${response.status} ${response.statusText}`,\n );\n }\n\n const manifest = (await response.json()) as {\n created?: string;\n config?: { size: number };\n layers?: Array<{ size: number }>;\n annotations?: Record<string, string>;\n };\n\n // Extract metadata\n const publishedAt = manifest.created || new Date().toISOString();\n const layerSizes = manifest.layers?.map((l) => l.size) || [];\n const size = layerSizes.reduce((sum, s) => sum + s, 0);\n const annotations = manifest.annotations || {};\n\n return {\n publishedAt,\n size,\n annotations,\n };\n}\n", "import { OciRegistryClient, parseRepoAndRef } from \"@shard-for-obsidian/lib\";\nimport type { FetchAdapter } from \"@shard-for-obsidian/lib\";\nimport { Logger } from \"../lib/logger.js\";\nimport { MarketplaceClient } from \"../lib/marketplace-client.js\";\nimport type { MarketplacePlugin } from \"../lib/marketplace-client.js\";\nimport { queryOciTags, queryTagMetadata } from \"../lib/oci-tags.js\";\nimport type { TagMetadata } from \"../lib/oci-tags.js\";\nimport { pullCommand } from \"./pull.js\";\nimport * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nexport interface MarketplaceRegisterOptions {\n repository: string;\n token: string;\n introduction?: string;\n logger: Logger;\n adapter: FetchAdapter;\n}\n\nexport interface MarketplaceRegisterResult {\n pluginId: string;\n name: string;\n author: string;\n description: string;\n registryUrl: string;\n repository?: string;\n license?: string;\n minObsidianVersion?: string;\n authorUrl?: string;\n mdPath: string;\n}\n\n/**\n * Register a plugin to the Shard marketplace.\n * Pulls plugin metadata from OCI registry and creates a markdown file with frontmatter.\n *\n * @param opts - Marketplace register options\n * @returns Register result with plugin metadata\n */\nexport async function marketplaceRegisterCommand(\n opts: MarketplaceRegisterOptions,\n): Promise<MarketplaceRegisterResult> {\n const { repository, token, introduction, logger, adapter } = opts;\n\n // Step 1: Parse repository reference\n logger.log(`Fetching plugin metadata from ${repository}...`);\n const ref = parseRepoAndRef(repository);\n const client = new OciRegistryClient({\n repo: ref,\n username: \"github\",\n password: token,\n adapter,\n scopes: [\"pull\"],\n });\n\n // Step 2: Pull plugin manifest\n const manifestResult = await client.pullPluginManifest({\n ref: ref.tag || \"latest\",\n });\n\n const pluginManifest = manifestResult.pluginManifest;\n const ociManifest = manifestResult.manifest;\n\n // Step 3: Extract metadata from plugin manifest\n const pluginId = pluginManifest.id;\n const name = pluginManifest.name;\n const author = pluginManifest.author;\n const description = pluginManifest.description || \"\";\n const minObsidianVersion = pluginManifest.minAppVersion;\n const authorUrl = pluginManifest.authorUrl;\n\n // Step 4: Get repository URL from annotations\n let gitHubRepoUrl: string | undefined;\n if (\n ociManifest.annotations &&\n ociManifest.annotations[\"vnd.obsidianmd.plugin.repo\"]\n ) {\n gitHubRepoUrl = ociManifest.annotations[\"vnd.obsidianmd.plugin.repo\"];\n }\n\n // Step 5: Build registry URL (use canonical name which includes registry host)\n const registryUrl = ref.canonicalName;\n\n logger.log(`Plugin ID: ${pluginId}`);\n logger.log(`Name: ${name}`);\n logger.log(`Author: ${author}`);\n logger.log(`Registry URL: ${registryUrl}`);\n if (gitHubRepoUrl) {\n logger.log(`Repository: ${gitHubRepoUrl}`);\n }\n\n // Step 6: Generate markdown with YAML frontmatter\n let frontmatter = `---\nid: ${pluginId}\nregistryUrl: ${registryUrl}\nname: ${name}\nauthor: ${author}\ndescription: ${description}\n`;\n\n if (gitHubRepoUrl) {\n frontmatter += `repository: ${gitHubRepoUrl}\\n`;\n }\n\n if (minObsidianVersion) {\n frontmatter += `minObsidianVersion: ${minObsidianVersion}\\n`;\n }\n\n if (authorUrl) {\n frontmatter += `authorUrl: ${authorUrl}\\n`;\n }\n\n frontmatter += `---\\n`;\n\n // Add introduction content if provided\n let markdownContent = frontmatter;\n if (introduction) {\n markdownContent += `\\n${introduction}\\n`;\n }\n\n // Step 7: Find marketplace directory (walk up from cwd)\n const marketplacePath = await findMarketplaceDir();\n const pluginsDir = path.join(marketplacePath, \"plugins\");\n const mdPath = path.join(pluginsDir, `${pluginId}.md`);\n\n // Step 8: Ensure plugins directory exists\n await fs.mkdir(pluginsDir, { recursive: true });\n\n // Step 9: Write markdown file\n await fs.writeFile(mdPath, markdownContent, \"utf-8\");\n\n logger.success(`Successfully registered plugin to ${mdPath}`);\n logger.log(`\\nNext steps:`);\n logger.log(`1. Review the generated markdown file`);\n logger.log(`2. Commit and push to the marketplace repository`);\n logger.log(`3. Submit a pull request to add your plugin to the marketplace`);\n\n return {\n pluginId,\n name,\n author,\n description,\n registryUrl,\n repository: gitHubRepoUrl,\n minObsidianVersion,\n authorUrl,\n mdPath,\n };\n}\n\n/**\n * Find the marketplace directory by walking up from cwd.\n * Looks for a directory containing marketplace/plugins/.\n */\nasync function findMarketplaceDir(): Promise<string> {\n let currentDir = process.cwd();\n const root = path.parse(currentDir).root;\n\n while (currentDir !== root) {\n const marketplacePath = path.join(currentDir, \"marketplace\");\n try {\n const stat = await fs.stat(marketplacePath);\n if (stat.isDirectory()) {\n return marketplacePath;\n }\n } catch {\n // Directory doesn't exist, continue searching\n }\n\n // Move up one directory\n currentDir = path.dirname(currentDir);\n }\n\n throw new Error(\n \"Could not find marketplace directory. \" +\n \"Please run this command from within the marketplace repository.\",\n );\n}\n\n/**\n * List all plugins in the marketplace.\n */\nexport async function marketplaceListCommand(opts: {\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin[]> {\n const { logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(\"Fetching marketplace plugins...\");\n const plugins = await client.fetchPlugins();\n\n logger.log(`\\nFound ${plugins.length} plugins:\\n`);\n\n for (const plugin of plugins) {\n logger.log(`${plugin.name} (${plugin.id})`);\n logger.log(` Author: ${plugin.author}`);\n // Display latest version if available\n if (plugin.versions && plugin.versions.length > 0) {\n logger.log(` Latest Version: ${plugin.versions[0].tag}`);\n }\n logger.log(` Registry: ${plugin.registryUrl}`);\n if (plugin.description) {\n logger.log(` Description: ${plugin.description}`);\n }\n logger.log(\"\");\n }\n\n return plugins;\n}\n\n/**\n * Search for plugins in the marketplace.\n */\nexport async function marketplaceSearchCommand(opts: {\n keyword: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin[]> {\n const { keyword, logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(`Searching for \"${keyword}\"...`);\n const plugins = await client.searchPlugins(keyword);\n\n if (plugins.length === 0) {\n logger.log(`\\nNo plugins found matching \"${keyword}\"`);\n return [];\n }\n\n logger.log(`\\nFound ${plugins.length} matching plugin(s):\\n`);\n\n for (const plugin of plugins) {\n logger.log(`${plugin.name} (${plugin.id})`);\n logger.log(` Author: ${plugin.author}`);\n // Display latest version if available\n if (plugin.versions && plugin.versions.length > 0) {\n logger.log(` Latest Version: ${plugin.versions[0].tag}`);\n }\n logger.log(` Registry: ${plugin.registryUrl}`);\n if (plugin.description) {\n logger.log(` Description: ${plugin.description}`);\n }\n logger.log(\"\");\n }\n\n return plugins;\n}\n\n/**\n * Display detailed information about a plugin.\n */\nexport async function marketplaceInfoCommand(opts: {\n pluginId: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<MarketplacePlugin | null> {\n const { pluginId, logger, adapter, marketplaceUrl } = opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n logger.log(`Fetching plugin \"${pluginId}\"...`);\n const plugin = await client.findPluginById(pluginId);\n\n if (!plugin) {\n logger.error(`Plugin \"${pluginId}\" not found in marketplace`);\n return null;\n }\n\n logger.log(\"\\n\" + \"=\".repeat(60));\n logger.log(`Plugin: ${plugin.name}`);\n logger.log(\"=\".repeat(60) + \"\\n\");\n\n logger.log(`ID: ${plugin.id}`);\n logger.log(`Author: ${plugin.author}`);\n if (plugin.authorUrl) {\n logger.log(`Author URL: ${plugin.authorUrl}`);\n }\n logger.log(`Description: ${plugin.description}`);\n logger.log(`\\nRegistry URL: ${plugin.registryUrl}`);\n if (plugin.repository) {\n logger.log(`Repository: ${plugin.repository}`);\n }\n if (plugin.license) {\n logger.log(`License: ${plugin.license}`);\n }\n if (plugin.minObsidianVersion) {\n logger.log(`Min Obsidian Version: ${plugin.minObsidianVersion}`);\n }\n if (plugin.tags && plugin.tags.length > 0) {\n logger.log(`Tags: ${plugin.tags.join(\", \")}`);\n }\n\n // Display available versions\n if (plugin.versions && plugin.versions.length > 0) {\n logger.log(`\\nAvailable Versions (${plugin.versions.length}):`);\n for (const version of plugin.versions.slice(0, 5)) {\n const date = new Date(version.publishedAt).toISOString().split(\"T\")[0];\n logger.log(` - ${version.tag} (${date})`);\n }\n if (plugin.versions.length > 5) {\n logger.log(` ... and ${plugin.versions.length - 5} more`);\n }\n }\n\n logger.log(\"\\n\" + \"=\".repeat(60));\n logger.log(\"Installation:\");\n logger.log(\"=\".repeat(60) + \"\\n\");\n const latestVersion =\n plugin.versions && plugin.versions.length > 0\n ? plugin.versions[0].tag\n : \"latest\";\n logger.log(\n `shard pull ${plugin.registryUrl}:${latestVersion} --output <path>`,\n );\n logger.log(\n `shard marketplace install ${plugin.id} # (coming soon)`,\n );\n\n return plugin;\n}\n\n/**\n * Install a plugin from the marketplace by ID.\n */\nexport async function marketplaceInstallCommand(opts: {\n pluginId: string;\n output: string;\n version?: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n marketplaceUrl?: string;\n}): Promise<{ plugin: MarketplacePlugin; pullResult: unknown }> {\n const { pluginId, output, version, token, logger, adapter, marketplaceUrl } =\n opts;\n\n const client = new MarketplaceClient(adapter, marketplaceUrl);\n\n // Step 1: Find plugin in marketplace\n logger.log(`Looking up plugin \"${pluginId}\" in marketplace...`);\n const plugin = await client.findPluginById(pluginId);\n\n if (!plugin) {\n throw new Error(`Plugin \"${pluginId}\" not found in marketplace`);\n }\n\n // Get latest version if available\n const latestVersion =\n plugin.versions && plugin.versions.length > 0\n ? plugin.versions[0].tag\n : \"latest\";\n\n logger.log(`Found: ${plugin.name} v${latestVersion} by ${plugin.author}`);\n\n // Step 2: Determine version to install\n const versionToInstall = version || latestVersion;\n const repository = `${plugin.registryUrl}:${versionToInstall}`;\n\n logger.log(`Installing from ${repository}...`);\n\n // Step 3: Use pull command to install\n const pullResult = await pullCommand({\n repository,\n output,\n token,\n logger,\n adapter,\n });\n\n logger.success(\n `Successfully installed ${plugin.name} v${versionToInstall} to ${output}`,\n );\n\n return { plugin, pullResult };\n}\n\n/**\n * Query and display all available versions for a plugin registry.\n */\nexport async function marketplaceVersionsCommand(opts: {\n registryUrl: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}): Promise<Array<{ tag: string } & TagMetadata>> {\n const { registryUrl, token, logger, adapter } = opts;\n\n logger.log(`Querying versions for ${registryUrl}...`);\n\n // Query all tags\n const tags = await queryOciTags({ registryUrl, token, adapter });\n\n if (tags.length === 0) {\n logger.log(\"No versions found\");\n return [];\n }\n\n logger.log(`\\nFound ${tags.length} version(s):\\n`);\n\n // Query metadata for each tag\n const versions: Array<{ tag: string } & TagMetadata> = [];\n\n for (const tag of tags) {\n const metadata = await queryTagMetadata({\n registryUrl,\n tag,\n token,\n adapter,\n });\n\n versions.push({ tag, ...metadata });\n\n // Format size\n const sizeKB = (metadata.size / 1024).toFixed(0);\n\n // Format date\n const date = new Date(metadata.publishedAt).toISOString().split(\"T\")[0];\n\n logger.log(`- ${tag} (published ${date}, ${sizeKB} KB)`);\n\n // Show commit SHA if available\n if (metadata.annotations[\"vnd.obsidianmd.plugin.commit\"]) {\n const sha = metadata.annotations[\"vnd.obsidianmd.plugin.commit\"];\n logger.log(` Commit: ${sha.substring(0, 7)}`);\n }\n }\n\n return versions;\n}\n\n/**\n * Update a marketplace entry by re-registering from GHCR.\n */\nexport async function marketplaceUpdateCommand(opts: {\n repository: string;\n token: string;\n logger: Logger;\n adapter: FetchAdapter;\n}): Promise<MarketplaceRegisterResult> {\n const { logger } = opts;\n\n logger.log(\"Updating marketplace entry...\");\n logger.log(\n \"Note: This will overwrite the existing markdown file with fresh metadata from GHCR\\n\",\n );\n\n // Just call the register command - it will overwrite the existing file\n return marketplaceRegisterCommand(opts);\n}\n", "/**\n * Resolve GitHub authentication token from multiple sources.\n * Priority: CLI flag -> GITHUB_TOKEN -> GH_TOKEN -> error\n *\n * @param cliToken - Token provided via CLI flag\n * @returns Resolved token\n * @throws Error if no token is found\n */\nexport function resolveAuthToken(cliToken?: string): string {\n // Priority 1: CLI flag\n if (cliToken) {\n return cliToken;\n }\n\n // Priority 2: GITHUB_TOKEN environment variable (CI/CD)\n const githubToken = process.env.GITHUB_TOKEN;\n if (githubToken) {\n return githubToken;\n }\n\n // Priority 3: GH_TOKEN environment variable (gh CLI)\n const ghToken = process.env.GH_TOKEN;\n if (ghToken) {\n return ghToken;\n }\n\n // No token found\n throw new Error(\n \"GitHub token required. Use --token flag or set GITHUB_TOKEN environment variable\",\n );\n}\n", "/**\n * Simple logger that writes to stderr for progress messages.\n * This allows JSON output on stdout while still showing progress.\n */\nexport class Logger {\n private silent: boolean;\n\n constructor(silent = false) {\n this.silent = silent;\n }\n\n /**\n * Log a message to stderr\n */\n log(message: string): void {\n if (!this.silent) {\n process.stderr.write(message + \"\\n\");\n }\n }\n\n /**\n * Log an error message to stderr\n */\n error(message: string): void {\n if (!this.silent) {\n process.stderr.write(`Error: ${message}\\n`);\n }\n }\n\n /**\n * Log a success message to stderr\n */\n success(message: string): void {\n if (!this.silent) {\n process.stderr.write(`Success: ${message}\\n`);\n }\n }\n}\n", "import type { FetchAdapter } from \"@shard-for-obsidian/lib\";\n\n/**\n * Adapter for Node.js native fetch API.\n * Thin wrapper that passes through to native fetch.\n */\nexport class NodeFetchAdapter implements FetchAdapter {\n async fetch(input: string | Request, init?: RequestInit): Promise<Response> {\n // Use native Node.js fetch\n return fetch(input, init);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["body", "path", "stat", "fs", "path", "fs", "path", "stat"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shard-for-obsidian/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.4",
4
4
  "description": "Shard CLI tool to push and pull plugins from GHCR",
5
5
  "type": "module",
6
6
  "author": "Andrew Gillis",
@@ -21,16 +21,6 @@
21
21
  "access": "public",
22
22
  "provenance": true
23
23
  },
24
- "scripts": {
25
- "build": "node esbuild.config.mjs",
26
- "build:prod": "node esbuild.config.mjs production",
27
- "clean": "rimraf dist",
28
- "ts-check": "tsc --noEmit",
29
- "lint": "eslint .",
30
- "test": "vitest run",
31
- "test:watch": "vitest",
32
- "test:ui": "vitest --ui"
33
- },
34
24
  "keywords": [
35
25
  "shard",
36
26
  "plugin",
@@ -44,11 +34,23 @@
44
34
  "node": ">=18.0.0"
45
35
  },
46
36
  "dependencies": {
47
- "@shard-for-obsidian/lib": "workspace:*"
37
+ "gray-matter": "^4.0.3",
38
+ "@shard-for-obsidian/lib": "0.2.4"
48
39
  },
49
40
  "devDependencies": {
50
41
  "@types/node": "^25.2.0",
51
42
  "@vitest/ui": "^4.0.18",
52
43
  "vitest": "^4.0.18"
44
+ },
45
+ "scripts": {
46
+ "start": "tsx src/index.ts",
47
+ "build": "node esbuild.config.mjs",
48
+ "build:prod": "node esbuild.config.mjs production",
49
+ "clean": "rimraf dist",
50
+ "ts-check": "tsc --noEmit",
51
+ "lint": "eslint .",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "test:ui": "vitest --ui"
53
55
  }
54
- }
56
+ }