@powerhousedao/registry 6.0.0-dev.189 → 6.0.0-dev.191

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/cli.mjs CHANGED
@@ -189,6 +189,38 @@ var CdnCache = class {
189
189
  };
190
190
  //#endregion
191
191
  //#region src/packages.ts
192
+ /**
193
+ * Read dist-tags, the full version list, and the local-publish flag for a
194
+ * package from verdaccio's on-disk storage (`{storagePath}/{name}/package.json`).
195
+ *
196
+ * `locallyPublished` is tri-state:
197
+ * - `true` → storage metadata has `_attachments` (tarball uploaded here).
198
+ * - `false` → storage metadata exists but `_attachments` is empty (proxy
199
+ * from the npm uplink only; no local publish at this registry).
200
+ * - `undefined` → metadata file wasn't readable. Happens with non-filesystem
201
+ * backends (S3, etc.) or if verdaccio stores metadata elsewhere.
202
+ * Callers should treat this as "unknown" and default to including
203
+ * the package, to avoid filtering the whole /packages list to an
204
+ * empty array on deployments where we can't observe _attachments.
205
+ */
206
+ function readPackageMetadata(storagePath, packageName) {
207
+ if (!storagePath) return { locallyPublished: void 0 };
208
+ try {
209
+ const metadataPath = path.join(storagePath, packageName, "package.json");
210
+ const raw = fs.readFileSync(metadataPath, "utf-8");
211
+ const parsed = JSON.parse(raw);
212
+ const distTags = parsed["dist-tags"];
213
+ const versions = (parsed.versions ? Object.keys(parsed.versions) : []).slice().sort(compareSemver);
214
+ const locallyPublished = !!parsed._attachments && Object.keys(parsed._attachments).length > 0;
215
+ return {
216
+ distTags: distTags && Object.keys(distTags).length > 0 ? distTags : void 0,
217
+ versions: versions.length > 0 ? versions : void 0,
218
+ locallyPublished
219
+ };
220
+ } catch {
221
+ return { locallyPublished: void 0 };
222
+ }
223
+ }
192
224
  function readManifest(dir) {
193
225
  const candidates = [
194
226
  path.join(dir, "powerhouse.manifest.json"),
@@ -243,7 +275,7 @@ function getDocumentTypesFromManifest(manifest) {
243
275
  documentTypes.push(...(documentModels ?? []).map((dm) => dm.id), ...(editors ?? []).flatMap((e) => e.documentTypes).filter((dt) => dt !== void 0), ...(subgraphs ?? []).flatMap((e) => e.documentTypes).filter((dt) => dt !== void 0));
244
276
  return documentTypes;
245
277
  }
246
- function scanPackages(cdnCachePath) {
278
+ function scanPackages(cdnCachePath, storagePath) {
247
279
  const absDir = path.resolve(cdnCachePath);
248
280
  const packages = [];
249
281
  let entries;
@@ -270,12 +302,16 @@ function scanPackages(cdnCachePath) {
270
302
  const manifestDir = getLatestVersionDir(pkgDir) ?? pkgDir;
271
303
  const manifest = readManifest(manifestDir);
272
304
  const name = manifest?.name ?? dirName;
305
+ const { distTags, versions, locallyPublished } = readPackageMetadata(storagePath, name);
306
+ if (locallyPublished === false) continue;
273
307
  packages.push({
274
308
  name,
275
309
  path: `/-/cdn/${dirName}`,
276
310
  manifest,
277
311
  documentTypes: getDocumentTypesFromManifest(manifest),
278
- version: readPackageJsonVersion(manifestDir)
312
+ version: readPackageJsonVersion(manifestDir),
313
+ distTags,
314
+ versions
279
315
  });
280
316
  }
281
317
  } else {
@@ -283,12 +319,16 @@ function scanPackages(cdnCachePath) {
283
319
  const manifestDir = getLatestVersionDir(pkgDir) ?? pkgDir;
284
320
  const manifest = readManifest(manifestDir);
285
321
  const name = manifest?.name ?? entry.name;
322
+ const { distTags, versions, locallyPublished } = readPackageMetadata(storagePath, name);
323
+ if (locallyPublished === false) continue;
286
324
  packages.push({
287
325
  name,
288
326
  path: `/-/cdn/${entry.name}`,
289
327
  manifest,
290
328
  documentTypes: getDocumentTypesFromManifest(manifest),
291
- version: readPackageJsonVersion(manifestDir)
329
+ version: readPackageJsonVersion(manifestDir),
330
+ distTags,
331
+ versions
292
332
  });
293
333
  }
294
334
  }
@@ -356,7 +396,7 @@ function createPowerhouseRouter(config, sse, webhooks) {
356
396
  res.status(204).end();
357
397
  });
358
398
  router.get("/packages", (req, res) => {
359
- const packages = scanPackages(config.cdnCachePath);
399
+ const packages = scanPackages(config.cdnCachePath, config.storagePath);
360
400
  const documentType = req.query.documentType;
361
401
  if (documentType) {
362
402
  const filtered = packages.filter((pkg) => pkg.manifest?.documentModels?.some((m) => m.id === documentType));
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["#resolveFile","#extractWithLock","#extractionLocks","#channels","#clients","#storagePath","#predefined","#dynamic","#load","#save","#filePath"],"sources":["../src/constants.ts","../src/semver.ts","../src/cdn.ts","../src/packages.ts","../src/middleware.ts","../src/notifications/manager.ts","../src/notifications/sse.ts","../src/notifications/webhook.ts","../src/verdaccio-config.ts","../src/run.ts","../cli.ts"],"sourcesContent":["export const DEFAULT_PORT = 8080;\nexport const DEFAULT_STORAGE_DIR_NAME = \"./storage\" as const;\nexport const DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME = \"./cdn-cache\" as const;\n","/**\n * Compare two semver version strings for sorting.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n *\n * Handles numeric component comparison (so \"1.0.10\" > \"1.0.9\")\n * and prerelease ordering (release > prerelease).\n */\nexport function compareSemver(a: string, b: string): number {\n const [coreA, preA] = a.split(\"-\", 2);\n const [coreB, preB] = b.split(\"-\", 2);\n\n const partsA = coreA.split(\".\").map(Number);\n const partsB = coreB.split(\".\").map(Number);\n\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const na = partsA[i] ?? 0;\n const nb = partsB[i] ?? 0;\n if (na !== nb) return na - nb;\n }\n\n // Equal core versions — release (no prerelease) sorts after prerelease\n if (!preA && preB) return 1;\n if (preA && !preB) return -1;\n if (preA && preB) return preA < preB ? -1 : preA > preB ? 1 : 0;\n\n return 0;\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { extract } from \"tar\";\nimport { compareSemver } from \"./semver.js\";\n\n/**\n * Parse a package specifier into name and version/tag.\n * Supports:\n * \"@scope/pkg\" -> { name: \"@scope/pkg\", tag: undefined }\n * \"@scope/pkg@dev\" -> { name: \"@scope/pkg\", tag: \"dev\" }\n * \"@scope/pkg@1.0.0\" -> { name: \"@scope/pkg\", tag: \"1.0.0\" }\n * \"pkg@latest\" -> { name: \"pkg\", tag: \"latest\" }\n */\nexport function parsePackageSpec(spec: string): {\n name: string;\n tag: string | undefined;\n} {\n // For scoped packages (@scope/name@tag), split on the last @\n // For unscoped packages (name@tag), split on the first @\n if (spec.startsWith(\"@\")) {\n // Scoped: find the @ after the scope/name portion\n const lastAt = spec.lastIndexOf(\"@\");\n if (lastAt > 0 && lastAt !== spec.indexOf(\"@\")) {\n return { name: spec.slice(0, lastAt), tag: spec.slice(lastAt + 1) };\n }\n return { name: spec, tag: undefined };\n }\n const atIndex = spec.indexOf(\"@\");\n if (atIndex > 0) {\n return { name: spec.slice(0, atIndex), tag: spec.slice(atIndex + 1) };\n }\n return { name: spec, tag: undefined };\n}\n\nexport class CdnCache {\n #extractionLocks = new Map<string, Promise<void>>();\n\n constructor(\n private registryUrl: string,\n private cdnCachePath: string,\n ) {}\n\n async getFileByVersion(\n packageName: string,\n version: string,\n filePath: string,\n ): Promise<string | null> {\n const versionDir = path.join(this.cdnCachePath, packageName, version);\n\n // Check all possible paths before attempting extraction\n const resolved = this.#resolveFile(versionDir, filePath);\n if (resolved) return resolved;\n\n // File not found in any location — extract tarball and try again\n await this.#extractWithLock(packageName, version);\n\n return this.#resolveFile(versionDir, filePath);\n }\n\n #resolveFile(versionDir: string, filePath: string): string | null {\n // Check direct path first, then fall back to cdn/ and dist/cdn/ subdirectories\n // (npm tarballs contain files under dist/, bun bundles go to cdn/)\n const candidates = [\n path.join(versionDir, filePath),\n path.join(versionDir, \"cdn\", filePath),\n path.join(versionDir, \"dist\", \"cdn\", filePath),\n path.join(versionDir, \"dist\", filePath),\n ];\n\n for (const candidate of candidates) {\n if (this.isSafePath(candidate) && fs.existsSync(candidate))\n return candidate;\n }\n\n return null;\n }\n\n async #extractWithLock(packageName: string, version: string): Promise<void> {\n const key = `${packageName}@${version}`;\n const existing = this.#extractionLocks.get(key);\n if (existing) return existing;\n\n const promise = this.extractTarball(packageName, version).finally(() => {\n this.#extractionLocks.delete(key);\n });\n this.#extractionLocks.set(key, promise);\n return promise;\n }\n\n getLatestCachedVersion(packageName: string): string | null {\n const pkgDir = path.join(this.cdnCachePath, packageName);\n try {\n const entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n const versions = entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n if (versions.length === 0) return null;\n versions.sort(compareSemver);\n return versions[versions.length - 1];\n } catch {\n return null;\n }\n }\n\n /**\n * Resolve a version for a package. If tag is a semver version that exists\n * in the registry, return it directly. If tag is a dist-tag name (e.g.\n * \"dev\", \"latest\"), resolve it to the concrete version. If no tag is\n * provided, prefer \"latest\", then fall back to any available dist-tag.\n */\n async resolveVersion(\n packageName: string,\n tag?: string,\n ): Promise<string | null> {\n try {\n const url = `${this.registryUrl}/${encodeURIComponent(packageName)}`;\n const res = await fetch(url, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) return null;\n const metadata = (await res.json()) as Record<string, unknown>;\n const distTags = metadata[\"dist-tags\"] as\n | Record<string, string>\n | undefined;\n const versions = metadata[\"versions\"] as\n | Record<string, unknown>\n | undefined;\n\n if (tag) {\n // If the tag matches an exact version in the registry, use it directly\n if (versions && tag in versions) return tag;\n // Otherwise treat it as a dist-tag name\n if (distTags && tag in distTags) return distTags[tag];\n // Tag not found\n return null;\n }\n\n if (!distTags) return null;\n // No tag specified: prefer \"latest\", fall back to any available tag\n return distTags.latest ?? Object.values(distTags)[0] ?? null;\n } catch {\n return null;\n }\n }\n\n async extractTarball(packageName: string, version: string): Promise<void> {\n const shortName = packageName.startsWith(\"@\")\n ? packageName.split(\"/\")[1]\n : packageName;\n const tarballUrl = `${this.registryUrl}/${encodeURIComponent(packageName)}/-/${shortName}-${version}.tgz`;\n\n let res: Response;\n try {\n res = await fetch(tarballUrl);\n if (!res.ok || !res.body) return;\n } catch {\n return;\n }\n\n const destDir = path.join(this.cdnCachePath, packageName, version);\n fs.mkdirSync(destDir, { recursive: true });\n\n const tmpFile = path.join(\n destDir,\n `.tmp-tarball-${crypto.randomUUID()}.tgz`,\n );\n try {\n const fileStream = fs.createWriteStream(tmpFile);\n await pipeline(Readable.fromWeb(res.body as never), fileStream);\n await extract({ file: tmpFile, cwd: destDir, strip: 1 });\n } finally {\n fs.rmSync(tmpFile, { force: true });\n }\n }\n\n invalidate(packageName: string): void {\n const cacheDir = path.join(this.cdnCachePath, packageName);\n if (!this.isSafePath(cacheDir)) return;\n fs.rmSync(cacheDir, { recursive: true, force: true });\n }\n\n /** Remove all cached version directories except the specified one. */\n pruneOldVersions(packageName: string, keepVersion: string): void {\n const pkgDir = path.join(this.cdnCachePath, packageName);\n try {\n const entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name !== keepVersion) {\n const dir = path.join(pkgDir, entry.name);\n if (this.isSafePath(dir)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n }\n }\n } catch {\n // ignore — directory may not exist yet\n }\n }\n\n private isSafePath(filePath: string): boolean {\n const resolved = path.resolve(filePath);\n const cacheRoot = path.resolve(this.cdnCachePath);\n return resolved.startsWith(cacheRoot + path.sep) || resolved === cacheRoot;\n }\n}\n","import type { Manifest } from \"@powerhousedao/shared\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { compareSemver } from \"./semver.js\";\nimport type { PackageInfo } from \"./types.js\";\n\nfunction readManifest(dir: string): Manifest | null {\n const candidates = [\n path.join(dir, \"powerhouse.manifest.json\"),\n path.join(dir, \"cdn\", \"powerhouse.manifest.json\"),\n path.join(dir, \"dist\", \"powerhouse.manifest.json\"),\n ];\n for (const manifestPath of candidates) {\n try {\n const raw = fs.readFileSync(manifestPath, \"utf-8\");\n return JSON.parse(raw) as Manifest;\n } catch {\n // try next candidate\n }\n }\n return null;\n}\n\nfunction readPackageJsonVersion(dir: string): string | undefined {\n try {\n const raw = fs.readFileSync(path.join(dir, \"package.json\"), \"utf-8\");\n const pkg = JSON.parse(raw) as { version?: unknown };\n return typeof pkg.version === \"string\" ? pkg.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getLatestVersionDir(pkgDir: string): string | null {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n } catch {\n return null;\n }\n const versions = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n if (versions.length === 0) return null;\n versions.sort(compareSemver);\n return path.join(pkgDir, versions[versions.length - 1]);\n}\n\nexport function loadPackage(\n cdnCachePath: string,\n name: string,\n version?: string,\n): PackageInfo | null {\n const pkgDir = path.join(cdnCachePath, name);\n const versionDir = version\n ? path.join(pkgDir, version)\n : getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n\n if (!manifest) {\n return null;\n }\n return {\n name: manifest.name ?? name,\n path: `/-/cdn/${name}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n };\n}\n\nfunction getDocumentTypesFromManifest(manifest: Manifest | undefined | null) {\n if (!manifest) return [];\n\n const documentTypes: string[] = [];\n const { apps, documentModels, editors, subgraphs } = manifest;\n\n if (apps?.length) {\n documentTypes.push(\"powerhouse/document-drive\");\n }\n documentTypes.push(\n ...(documentModels ?? []).map((dm) => dm.id),\n ...(editors ?? [])\n .flatMap((e) => e.documentTypes)\n .filter((dt) => dt !== undefined),\n ...(subgraphs ?? [])\n .flatMap((e) => e.documentTypes)\n .filter((dt) => dt !== undefined),\n );\n\n return documentTypes;\n}\n\nexport function scanPackages(cdnCachePath: string): PackageInfo[] {\n const absDir = path.resolve(cdnCachePath);\n const packages: PackageInfo[] = [];\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(absDir, { withFileTypes: true });\n } catch {\n return packages;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n if (entry.name.startsWith(\"@\")) {\n const scopeDir = path.join(absDir, entry.name);\n let scopedEntries: fs.Dirent[];\n try {\n scopedEntries = fs.readdirSync(scopeDir, { withFileTypes: true });\n } catch (error) {\n console.log(error);\n continue;\n }\n for (const scopedEntry of scopedEntries) {\n if (!scopedEntry.isDirectory()) continue;\n const dirName = `${entry.name}/${scopedEntry.name}`;\n const pkgDir = path.join(scopeDir, scopedEntry.name);\n const versionDir = getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n const name = manifest?.name ?? dirName;\n packages.push({\n name,\n path: `/-/cdn/${dirName}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n });\n }\n } else {\n const pkgDir = path.join(absDir, entry.name);\n const versionDir = getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n const name = manifest?.name ?? entry.name;\n packages.push({\n name,\n path: `/-/cdn/${entry.name}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n });\n }\n }\n\n return packages;\n}\n\nexport function findPackagesByDocumentType(\n packagesDir: string,\n documentType: string,\n): PackageInfo[] {\n const allPackages = scanPackages(packagesDir);\n\n return allPackages.filter((pkg) => {\n if (!pkg.manifest?.documentModels) {\n return false;\n }\n return pkg.manifest.documentModels.some((dm) => dm.id === documentType);\n });\n}\n","import express, {\n Router,\n type NextFunction,\n type Request,\n type Response,\n} from \"express\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { CdnCache, parsePackageSpec } from \"./cdn.js\";\nimport type { SSEChannel } from \"./notifications/sse.js\";\nimport type { NotificationChannel } from \"./notifications/types.js\";\nimport type { WebhookChannel } from \"./notifications/webhook.js\";\nimport {\n findPackagesByDocumentType,\n loadPackage,\n scanPackages,\n} from \"./packages.js\";\nimport type { RegistryConfig } from \"./types.js\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".wasm\": \"application/wasm\",\n \".map\": \"application/json\",\n \".html\": \"text/html\",\n \".svg\": \"image/svg+xml\",\n};\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n return MIME_TYPES[ext] ?? \"application/octet-stream\";\n}\n\nexport function createPowerhouseRouter(\n config: RegistryConfig,\n sse: SSEChannel,\n webhooks: WebhookChannel,\n): Router {\n const cdn = new CdnCache(\n `http://localhost:${config.port}`,\n config.cdnCachePath,\n );\n const router = Router();\n\n // CORS on every response\n router.use((_req: Request, res: Response, next: NextFunction) => {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n next();\n });\n\n // SSE endpoint for publish notifications\n router.get(\"/-/events\", (_req: Request, res: Response) => {\n sse.addClient(res);\n });\n\n // Webhook management\n router.get(\"/-/webhooks\", (_req: Request, res: Response) => {\n res.json(webhooks.getWebhooks());\n });\n\n router.post(\"/-/webhooks\", express.json(), (req: Request, res: Response) => {\n const { endpoint, headers } = req.body as {\n endpoint?: string;\n headers?: Record<string, string>;\n };\n if (!endpoint) {\n res.status(400).json({ error: \"Missing required field: endpoint\" });\n return;\n }\n webhooks.addWebhook({ endpoint, headers });\n res.status(201).json({ endpoint, headers });\n });\n\n router.delete(\n \"/-/webhooks\",\n express.json(),\n (req: Request, res: Response) => {\n const { endpoint } = req.body as { endpoint?: string };\n if (!endpoint) {\n res.status(400).json({ error: \"Missing required field: endpoint\" });\n return;\n }\n const removed = webhooks.removeWebhook(endpoint);\n if (!removed) {\n res.status(404).json({ error: \"Webhook not found\" });\n return;\n }\n res.status(204).end();\n },\n );\n\n // Package listing API\n router.get(\"/packages\", (req: Request, res: Response) => {\n const packages = scanPackages(config.cdnCachePath);\n const documentType = req.query.documentType as string | undefined;\n if (documentType) {\n const filtered = packages.filter((pkg) =>\n pkg.manifest?.documentModels?.some((m) => m.id === documentType),\n );\n res.json(filtered);\n return;\n }\n res.json(packages);\n });\n\n // Find packages by document type - returns array of package names\n router.get(\"/packages/by-document-type\", (req: Request, res: Response) => {\n const documentType = req.query.type;\n\n if (typeof documentType !== \"string\" || !documentType) {\n res.status(400).json({ error: \"Missing required query parameter: type\" });\n return;\n }\n\n const packages = findPackagesByDocumentType(\n config.cdnCachePath,\n documentType,\n );\n const packageNames = packages.map((pkg) => pkg.name);\n res.json(packageNames);\n });\n\n // Single package info\n router.get(\"/packages/*name\", async (req: Request, res: Response) => {\n const raw = (req.params as Record<string, string[]>).name.join(\"/\");\n const { name, tag } = parsePackageSpec(raw);\n const version =\n (await cdn.resolveVersion(name, tag)) ?? cdn.getLatestCachedVersion(name);\n const pkg = loadPackage(config.cdnCachePath, name, version ?? undefined);\n if (!pkg) {\n res.status(404).send(\"Package not found\");\n return;\n }\n res.json(pkg);\n });\n\n // CDN file serving\n router.get(\"/-/cdn/*path\", async (req: Request, res: Response) => {\n const parts = (req.params as Record<string, string[]>).path;\n const fullPath = parts.join(\"/\");\n\n // Parse scoped or unscoped package specifier from the path\n let packageSpec: string;\n let filePath: string;\n\n if (fullPath.startsWith(\"@\")) {\n // Scoped: @scope/pkg@1.0.0/file.js -> packageSpec = @scope/pkg@1.0.0, filePath = file.js\n const segments = fullPath.split(\"/\");\n if (segments.length < 2) {\n res.status(400).send(\"Invalid package path\");\n return;\n }\n packageSpec = `${segments[0]}/${segments[1]}`;\n filePath = segments.slice(2).join(\"/\") || \"index.js\";\n } else {\n // Unscoped: pkg@1.0.0/file.js -> packageSpec = pkg@1.0.0, filePath = file.js\n const segments = fullPath.split(\"/\");\n packageSpec = segments[0];\n filePath = segments.slice(1).join(\"/\") || \"index.js\";\n }\n\n const { name: packageName, tag } = parsePackageSpec(packageSpec);\n const version =\n (await cdn.resolveVersion(packageName, tag)) ??\n cdn.getLatestCachedVersion(packageName);\n if (!version) {\n res.status(404).send(\"File not found\");\n return;\n }\n\n const resolved = await cdn.getFileByVersion(packageName, version, filePath);\n if (!resolved) {\n res.status(404).send(\"File not found\");\n return;\n }\n\n res.setHeader(\"Content-Type\", getContentType(filePath));\n const content = fs.readFileSync(resolved);\n res.send(content);\n });\n\n return router;\n}\n\nexport function createPublishHook(\n config: RegistryConfig,\n notifications: NotificationChannel,\n) {\n const cdn = new CdnCache(\n `http://localhost:${config.port}`,\n config.cdnCachePath,\n );\n\n return (req: Request, res: Response, next: NextFunction) => {\n // Only intercept PUT requests to npm publish endpoints\n if (req.method !== \"PUT\") {\n next();\n return;\n }\n\n const originalEnd = res.end.bind(res);\n res.end = function (\n this: Response,\n chunk?: unknown,\n encoding?: unknown,\n cb?: () => void,\n ) {\n const urlPath = req.path.replace(/^\\//, \"\");\n if (\n res.statusCode < 200 ||\n res.statusCode >= 300 ||\n !urlPath ||\n urlPath.startsWith(\"-\")\n ) {\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n }\n const packageName = decodeURIComponent(urlPath);\n const versionsObj = (req.body as { versions: Record<string, unknown> })\n .versions;\n const versions = Object.keys(versionsObj);\n const version = versions.at(0);\n if (!version) {\n console.error(`[registry] No version found for ${packageName}`);\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n }\n if (versions.length > 1) {\n console.warn(\n `[registry] Multiple versions published for ${packageName}: ${JSON.stringify(versions)}`,\n );\n }\n\n cdn\n .extractTarball(packageName, version)\n .then(() => {\n notifications.notifyPublish({ packageName, version });\n })\n .catch((err) => {\n console.error(\n `[registry] Failed to extract ${packageName} to CDN cache:`,\n err,\n );\n });\n\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n };\n\n next();\n };\n}\n","import type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nexport class NotificationManager implements NotificationChannel {\n #channels: NotificationChannel[];\n\n constructor(channels: NotificationChannel[]) {\n this.#channels = channels;\n }\n\n notifyPublish(event: PublishEvent): void {\n for (const channel of this.#channels) {\n channel.notifyPublish(event);\n }\n }\n}\n","import type { Response } from \"express\";\nimport type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nexport class SSEChannel implements NotificationChannel {\n #clients = new Set<Response>();\n\n addClient(res: Response): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n res.write(\"event: connected\\ndata: {}\\n\\n\");\n\n this.#clients.add(res);\n res.on(\"close\", () => {\n this.#clients.delete(res);\n });\n }\n\n notifyPublish(event: PublishEvent): void {\n const payload = `event: publish\\ndata: ${JSON.stringify(event)}\\n\\n`;\n for (const client of this.#clients) {\n try {\n client.write(payload);\n } catch (err) {\n console.error(\"[registry] SSE client write failed:\", err);\n this.#clients.delete(client);\n }\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { NotifyConfig, WebhookConfig } from \"../types.js\";\nimport type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nconst WEBHOOKS_FILE = \"webhooks.json\";\n\nexport class WebhookChannel implements NotificationChannel {\n #predefined: WebhookConfig[];\n #dynamic: WebhookConfig[];\n #storagePath: string;\n\n constructor(storagePath: string, config?: NotifyConfig) {\n this.#storagePath = storagePath;\n this.#predefined = config?.webhooks ?? [];\n this.#dynamic = this.#load();\n }\n\n getWebhooks(): WebhookConfig[] {\n return [...this.#predefined, ...this.#dynamic];\n }\n\n addWebhook(webhook: WebhookConfig): void {\n const exists = this.getWebhooks().some(\n (w) => w.endpoint === webhook.endpoint,\n );\n if (exists) return;\n this.#dynamic.push(webhook);\n this.#save();\n }\n\n removeWebhook(endpoint: string): boolean {\n const before = this.#dynamic.length;\n this.#dynamic = this.#dynamic.filter((w) => w.endpoint !== endpoint);\n if (this.#dynamic.length === before) return false;\n this.#save();\n return true;\n }\n\n notifyPublish(event: PublishEvent): void {\n for (const webhook of this.getWebhooks()) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...webhook.headers,\n };\n\n fetch(webhook.endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(event),\n }).catch((err: unknown) => {\n console.error(`[registry] Webhook to ${webhook.endpoint} failed:`, err);\n });\n }\n }\n\n #filePath(): string {\n return path.join(this.#storagePath, WEBHOOKS_FILE);\n }\n\n #load(): WebhookConfig[] {\n try {\n const raw = fs.readFileSync(this.#filePath(), \"utf-8\");\n return JSON.parse(raw) as WebhookConfig[];\n } catch {\n return [];\n }\n }\n\n #save(): void {\n fs.mkdirSync(this.#storagePath, { recursive: true });\n fs.writeFileSync(this.#filePath(), JSON.stringify(this.#dynamic, null, 2));\n }\n}\n","import path from \"node:path\";\nimport type { RegistryConfig } from \"./types.js\";\n\nexport function buildVerdaccioConfig(config: RegistryConfig) {\n const htpasswdPath = path.join(config.storagePath, \"htpasswd\");\n\n const uplinkUrl = config.uplink ?? \"https://registry.npmjs.org/\";\n\n const base: Record<string, unknown> = {\n storage: config.storagePath,\n self_path: \"./\",\n auth: {\n htpasswd: {\n file: htpasswdPath,\n },\n },\n uplinks: {\n npmjs: {\n url: uplinkUrl,\n maxage: \"15m\",\n timeout: \"30s\",\n cache: true,\n },\n },\n packages: {\n \"@powerhousedao/*\": {\n access: \"$all\",\n publish: \"$authenticated\",\n unpublish: \"$authenticated\",\n proxy: \"npmjs\",\n },\n \"**\": {\n access: \"$all\",\n publish: \"$authenticated\",\n unpublish: \"$authenticated\",\n proxy: \"npmjs\",\n },\n },\n web: {\n enable: config.webEnabled !== false,\n title: \"Powerhouse Registry\",\n logo: \"https://raw.githubusercontent.com/powerhouse-inc/powerhouse/main/packages/registry/static/logo.svg\",\n favicon: \"/-/static/favicon.ico\",\n primary_color: \"#38C780\",\n darkMode: true,\n },\n server: {\n keepAliveTimeout: 60,\n },\n log: {\n type: \"stdout\",\n format: \"pretty\",\n level: \"warn\",\n },\n max_body_size: config.maxBodySize ?? \"300mb\",\n };\n\n if (config.s3) {\n base.store = {\n \"aws-s3-storage\": {\n bucket: config.s3.bucket,\n endpoint: config.s3.endpoint,\n region: config.s3.region,\n s3ForcePathStyle: config.s3.s3ForcePathStyle ?? true,\n ...(config.s3.keyPrefix && { keyPrefix: config.s3.keyPrefix }),\n ...(config.s3.accessKeyId && { accessKeyId: config.s3.accessKeyId }),\n ...(config.s3.secretAccessKey && {\n secretAccessKey: config.s3.secretAccessKey,\n }),\n },\n };\n }\n\n return base;\n}\n","import express from \"express\";\nimport { findUp } from \"find-up\";\nimport { mkdir } from \"node:fs/promises\";\nimport type { Server } from \"node:http\";\nimport path from \"node:path\";\nimport { runServer } from \"verdaccio\";\nimport { createPowerhouseRouter, createPublishHook } from \"./middleware.js\";\nimport { NotificationManager } from \"./notifications/manager.js\";\nimport { SSEChannel } from \"./notifications/sse.js\";\nimport { WebhookChannel } from \"./notifications/webhook.js\";\nimport type { RegistryCommandArgs, RegistryConfig } from \"./types.js\";\nimport { buildVerdaccioConfig } from \"./verdaccio-config.js\";\n\nasync function resolveDir(dir: string): Promise<string> {\n if (path.isAbsolute(dir)) {\n await mkdir(dir, { recursive: true });\n return dir;\n }\n const found = await findUp(dir, { type: \"directory\" });\n if (!found) {\n await mkdir(dir, { recursive: true });\n return dir;\n }\n return found;\n}\n\nexport async function runRegistry(args: RegistryCommandArgs) {\n const {\n port,\n storageDir,\n cdnCacheDir,\n uplink,\n webEnabled,\n webhooks,\n s3AccessKeyId,\n s3Bucket,\n s3Endpoint,\n s3ForcePathStyle,\n s3KeyPrefix,\n s3Region,\n s3SecretAccessKey,\n } = args;\n const storagePath = await resolveDir(storageDir);\n const cdnCachePath = await resolveDir(cdnCacheDir);\n\n console.log({\n storagePath,\n cdnCachePath,\n });\n\n const webhookConfigs = webhooks\n ?.split(\",\")\n .map((url) => url.trim())\n .filter(Boolean)\n .map((endpoint) => ({ endpoint }));\n\n const config: RegistryConfig = {\n port,\n storagePath,\n cdnCachePath,\n uplink,\n webEnabled,\n ...(webhookConfigs?.length && {\n notify: { webhooks: webhookConfigs },\n }),\n ...(s3Bucket &&\n s3Endpoint &&\n s3Region && {\n s3: {\n bucket: s3Bucket,\n endpoint: s3Endpoint,\n region: s3Region,\n accessKeyId: s3AccessKeyId,\n secretAccessKey: s3SecretAccessKey,\n keyPrefix: s3KeyPrefix,\n s3ForcePathStyle,\n },\n }),\n };\n // Ensure directories exist (for relative paths resolved via findUp)\n await mkdir(storagePath, { recursive: true });\n await mkdir(cdnCachePath, { recursive: true });\n\n const verdaccioConfig = buildVerdaccioConfig(config);\n\n // verdaccio's runServer returns Promise<any> (upstream type limitation)\n const verdaccioServer = (await runServer(verdaccioConfig)) as Server;\n const verdaccioHandler = verdaccioServer.listeners(\"request\")[0] as (\n ...args: unknown[]\n ) => void;\n\n const app = express();\n\n const sseChannel = new SSEChannel();\n const webhookChannel = new WebhookChannel(config.storagePath, config.notify);\n const notifications = new NotificationManager([sseChannel, webhookChannel]);\n\n // Serve static assets (logo, etc.)\n const staticDir = await findUp(\"static\", { type: \"directory\" });\n if (staticDir) {\n app.use(\"/-/static\", express.static(staticDir));\n }\n\n // Our routes take priority over Verdaccio\n app.use(createPowerhouseRouter(config, sseChannel, webhookChannel));\n app.use(createPublishHook(config, notifications));\n\n // Verdaccio handles everything else (npm protocol, web UI, auth)\n app.use((req, res) => verdaccioHandler(req, res));\n\n const server = app.listen(port, () => {\n console.log(`Powerhouse Registry running on http://localhost:${port}`);\n console.log(` CDN: http://localhost:${port}/-/cdn/`);\n console.log(` Packages: http://localhost:${port}/packages`);\n console.log(` npm: http://localhost:${port}/`);\n console.log(` Storage: ${storagePath}`);\n console.log(` CDN cache: ${cdnCachePath}`);\n if (config.s3) {\n console.log(` S3: ${config.s3.endpoint}/${config.s3.bucket}`);\n }\n });\n\n return server;\n}\n","import {\n binary,\n command,\n flag,\n number,\n option,\n optional,\n run,\n string,\n} from \"cmd-ts\";\nimport {\n DEFAULT_PORT,\n DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME,\n DEFAULT_STORAGE_DIR_NAME,\n} from \"./src/constants.js\";\nimport { runRegistry } from \"./src/run.js\";\n\nexport const registryCommand = command({\n name: \"Package registry\",\n args: {\n port: option({\n long: \"port\",\n type: number,\n defaultValue: () => Number(process.env.PORT) || DEFAULT_PORT,\n defaultValueIsSerializable: true,\n }),\n storageDir: option({\n long: \"storage-dir\",\n type: string,\n defaultValue: () =>\n process.env.REGISTRY_STORAGE || DEFAULT_STORAGE_DIR_NAME,\n defaultValueIsSerializable: true,\n }),\n cdnCacheDir: option({\n long: \"cdn-cache-dir\",\n type: string,\n defaultValue: () =>\n process.env.REGISTRY_CDN_CACHE || DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME,\n defaultValueIsSerializable: true,\n }),\n uplink: option({\n long: \"uplink\",\n type: optional(string),\n defaultValue: () => process.env.REGISTRY_UPLINK,\n defaultValueIsSerializable: true,\n }),\n s3Bucket: option({\n long: \"s3-bucket\",\n type: optional(string),\n defaultValue: () => process.env.S3_BUCKET,\n defaultValueIsSerializable: true,\n }),\n s3Endpoint: option({\n long: \"s3-endpoint\",\n type: optional(string),\n defaultValue: () => process.env.S3_ENDPOINT,\n defaultValueIsSerializable: true,\n }),\n s3Region: option({\n long: \"s3-region\",\n type: optional(string),\n defaultValue: () => process.env.S3_REGION,\n defaultValueIsSerializable: true,\n }),\n s3AccessKeyId: option({\n long: \"s3-access-key-id\",\n type: optional(string),\n defaultValue: () => process.env.S3_ACCESS_KEY_ID,\n defaultValueIsSerializable: true,\n }),\n s3SecretAccessKey: option({\n long: \"s3-secret-access-key\",\n type: optional(string),\n defaultValue: () => process.env.S3_SECRET_ACCESS_KEY,\n defaultValueIsSerializable: true,\n }),\n s3KeyPrefix: option({\n long: \"s3-key-prefix\",\n type: optional(string),\n defaultValue: () => process.env.S3_KEY_PREFIX,\n defaultValueIsSerializable: true,\n }),\n s3ForcePathStyle: flag({\n long: \"s3-force-path-style\",\n defaultValue: () => process.env.S3_FORCE_PATH_STYLE !== \"false\",\n defaultValueIsSerializable: true,\n }),\n webEnabled: flag({\n long: \"web-enabled\",\n defaultValue: () => process.env.REGISTRY_WEB !== \"false\",\n defaultValueIsSerializable: true,\n }),\n webhooks: option({\n long: \"webhook\",\n type: optional(string),\n description: \"Comma-separated webhook URLs to notify on publish\",\n defaultValue: () => process.env.REGISTRY_WEBHOOKS,\n defaultValueIsSerializable: true,\n }),\n },\n handler: async (args) => {\n console.log(args);\n\n try {\n await runRegistry(args);\n } catch (error) {\n console.error(\"Failed to start registry:\");\n console.error(error);\n process.exit(1);\n }\n },\n});\n\nconst registryCli = binary(registryCommand);\n\nawait run(registryCli, process.argv);\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["#resolveFile","#extractWithLock","#extractionLocks","#channels","#clients","#storagePath","#predefined","#dynamic","#load","#save","#filePath"],"sources":["../src/constants.ts","../src/semver.ts","../src/cdn.ts","../src/packages.ts","../src/middleware.ts","../src/notifications/manager.ts","../src/notifications/sse.ts","../src/notifications/webhook.ts","../src/verdaccio-config.ts","../src/run.ts","../cli.ts"],"sourcesContent":["export const DEFAULT_PORT = 8080;\nexport const DEFAULT_STORAGE_DIR_NAME = \"./storage\" as const;\nexport const DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME = \"./cdn-cache\" as const;\n","/**\n * Compare two semver version strings for sorting.\n * Returns negative if a < b, positive if a > b, 0 if equal.\n *\n * Handles numeric component comparison (so \"1.0.10\" > \"1.0.9\")\n * and prerelease ordering (release > prerelease).\n */\nexport function compareSemver(a: string, b: string): number {\n const [coreA, preA] = a.split(\"-\", 2);\n const [coreB, preB] = b.split(\"-\", 2);\n\n const partsA = coreA.split(\".\").map(Number);\n const partsB = coreB.split(\".\").map(Number);\n\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const na = partsA[i] ?? 0;\n const nb = partsB[i] ?? 0;\n if (na !== nb) return na - nb;\n }\n\n // Equal core versions — release (no prerelease) sorts after prerelease\n if (!preA && preB) return 1;\n if (preA && !preB) return -1;\n if (preA && preB) return preA < preB ? -1 : preA > preB ? 1 : 0;\n\n return 0;\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Readable } from \"node:stream\";\nimport { pipeline } from \"node:stream/promises\";\nimport { extract } from \"tar\";\nimport { compareSemver } from \"./semver.js\";\n\n/**\n * Parse a package specifier into name and version/tag.\n * Supports:\n * \"@scope/pkg\" -> { name: \"@scope/pkg\", tag: undefined }\n * \"@scope/pkg@dev\" -> { name: \"@scope/pkg\", tag: \"dev\" }\n * \"@scope/pkg@1.0.0\" -> { name: \"@scope/pkg\", tag: \"1.0.0\" }\n * \"pkg@latest\" -> { name: \"pkg\", tag: \"latest\" }\n */\nexport function parsePackageSpec(spec: string): {\n name: string;\n tag: string | undefined;\n} {\n // For scoped packages (@scope/name@tag), split on the last @\n // For unscoped packages (name@tag), split on the first @\n if (spec.startsWith(\"@\")) {\n // Scoped: find the @ after the scope/name portion\n const lastAt = spec.lastIndexOf(\"@\");\n if (lastAt > 0 && lastAt !== spec.indexOf(\"@\")) {\n return { name: spec.slice(0, lastAt), tag: spec.slice(lastAt + 1) };\n }\n return { name: spec, tag: undefined };\n }\n const atIndex = spec.indexOf(\"@\");\n if (atIndex > 0) {\n return { name: spec.slice(0, atIndex), tag: spec.slice(atIndex + 1) };\n }\n return { name: spec, tag: undefined };\n}\n\nexport class CdnCache {\n #extractionLocks = new Map<string, Promise<void>>();\n\n constructor(\n private registryUrl: string,\n private cdnCachePath: string,\n ) {}\n\n async getFileByVersion(\n packageName: string,\n version: string,\n filePath: string,\n ): Promise<string | null> {\n const versionDir = path.join(this.cdnCachePath, packageName, version);\n\n // Check all possible paths before attempting extraction\n const resolved = this.#resolveFile(versionDir, filePath);\n if (resolved) return resolved;\n\n // File not found in any location — extract tarball and try again\n await this.#extractWithLock(packageName, version);\n\n return this.#resolveFile(versionDir, filePath);\n }\n\n #resolveFile(versionDir: string, filePath: string): string | null {\n // Check direct path first, then fall back to cdn/ and dist/cdn/ subdirectories\n // (npm tarballs contain files under dist/, bun bundles go to cdn/)\n const candidates = [\n path.join(versionDir, filePath),\n path.join(versionDir, \"cdn\", filePath),\n path.join(versionDir, \"dist\", \"cdn\", filePath),\n path.join(versionDir, \"dist\", filePath),\n ];\n\n for (const candidate of candidates) {\n if (this.isSafePath(candidate) && fs.existsSync(candidate))\n return candidate;\n }\n\n return null;\n }\n\n async #extractWithLock(packageName: string, version: string): Promise<void> {\n const key = `${packageName}@${version}`;\n const existing = this.#extractionLocks.get(key);\n if (existing) return existing;\n\n const promise = this.extractTarball(packageName, version).finally(() => {\n this.#extractionLocks.delete(key);\n });\n this.#extractionLocks.set(key, promise);\n return promise;\n }\n\n getLatestCachedVersion(packageName: string): string | null {\n const pkgDir = path.join(this.cdnCachePath, packageName);\n try {\n const entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n const versions = entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n if (versions.length === 0) return null;\n versions.sort(compareSemver);\n return versions[versions.length - 1];\n } catch {\n return null;\n }\n }\n\n /**\n * Resolve a version for a package. If tag is a semver version that exists\n * in the registry, return it directly. If tag is a dist-tag name (e.g.\n * \"dev\", \"latest\"), resolve it to the concrete version. If no tag is\n * provided, prefer \"latest\", then fall back to any available dist-tag.\n */\n async resolveVersion(\n packageName: string,\n tag?: string,\n ): Promise<string | null> {\n try {\n const url = `${this.registryUrl}/${encodeURIComponent(packageName)}`;\n const res = await fetch(url, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) return null;\n const metadata = (await res.json()) as Record<string, unknown>;\n const distTags = metadata[\"dist-tags\"] as\n | Record<string, string>\n | undefined;\n const versions = metadata[\"versions\"] as\n | Record<string, unknown>\n | undefined;\n\n if (tag) {\n // If the tag matches an exact version in the registry, use it directly\n if (versions && tag in versions) return tag;\n // Otherwise treat it as a dist-tag name\n if (distTags && tag in distTags) return distTags[tag];\n // Tag not found\n return null;\n }\n\n if (!distTags) return null;\n // No tag specified: prefer \"latest\", fall back to any available tag\n return distTags.latest ?? Object.values(distTags)[0] ?? null;\n } catch {\n return null;\n }\n }\n\n async extractTarball(packageName: string, version: string): Promise<void> {\n const shortName = packageName.startsWith(\"@\")\n ? packageName.split(\"/\")[1]\n : packageName;\n const tarballUrl = `${this.registryUrl}/${encodeURIComponent(packageName)}/-/${shortName}-${version}.tgz`;\n\n let res: Response;\n try {\n res = await fetch(tarballUrl);\n if (!res.ok || !res.body) return;\n } catch {\n return;\n }\n\n const destDir = path.join(this.cdnCachePath, packageName, version);\n fs.mkdirSync(destDir, { recursive: true });\n\n const tmpFile = path.join(\n destDir,\n `.tmp-tarball-${crypto.randomUUID()}.tgz`,\n );\n try {\n const fileStream = fs.createWriteStream(tmpFile);\n await pipeline(Readable.fromWeb(res.body as never), fileStream);\n await extract({ file: tmpFile, cwd: destDir, strip: 1 });\n } finally {\n fs.rmSync(tmpFile, { force: true });\n }\n }\n\n invalidate(packageName: string): void {\n const cacheDir = path.join(this.cdnCachePath, packageName);\n if (!this.isSafePath(cacheDir)) return;\n fs.rmSync(cacheDir, { recursive: true, force: true });\n }\n\n /** Remove all cached version directories except the specified one. */\n pruneOldVersions(packageName: string, keepVersion: string): void {\n const pkgDir = path.join(this.cdnCachePath, packageName);\n try {\n const entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name !== keepVersion) {\n const dir = path.join(pkgDir, entry.name);\n if (this.isSafePath(dir)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n }\n }\n } catch {\n // ignore — directory may not exist yet\n }\n }\n\n private isSafePath(filePath: string): boolean {\n const resolved = path.resolve(filePath);\n const cacheRoot = path.resolve(this.cdnCachePath);\n return resolved.startsWith(cacheRoot + path.sep) || resolved === cacheRoot;\n }\n}\n","import type { Manifest } from \"@powerhousedao/shared\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { compareSemver } from \"./semver.js\";\nimport type { PackageInfo } from \"./types.js\";\n\n/**\n * Read dist-tags, the full version list, and the local-publish flag for a\n * package from verdaccio's on-disk storage (`{storagePath}/{name}/package.json`).\n *\n * `locallyPublished` is tri-state:\n * - `true` → storage metadata has `_attachments` (tarball uploaded here).\n * - `false` → storage metadata exists but `_attachments` is empty (proxy\n * from the npm uplink only; no local publish at this registry).\n * - `undefined` → metadata file wasn't readable. Happens with non-filesystem\n * backends (S3, etc.) or if verdaccio stores metadata elsewhere.\n * Callers should treat this as \"unknown\" and default to including\n * the package, to avoid filtering the whole /packages list to an\n * empty array on deployments where we can't observe _attachments.\n */\nfunction readPackageMetadata(\n storagePath: string | undefined,\n packageName: string,\n): {\n distTags?: Record<string, string>;\n versions?: string[];\n locallyPublished: boolean | undefined;\n} {\n if (!storagePath) return { locallyPublished: undefined };\n try {\n const metadataPath = path.join(storagePath, packageName, \"package.json\");\n const raw = fs.readFileSync(metadataPath, \"utf-8\");\n const parsed = JSON.parse(raw) as {\n \"dist-tags\"?: Record<string, string>;\n versions?: Record<string, unknown>;\n _attachments?: Record<string, unknown>;\n };\n const distTags = parsed[\"dist-tags\"];\n const rawVersions = parsed.versions ? Object.keys(parsed.versions) : [];\n const versions = rawVersions.slice().sort(compareSemver);\n const locallyPublished =\n !!parsed._attachments && Object.keys(parsed._attachments).length > 0;\n return {\n distTags:\n distTags && Object.keys(distTags).length > 0 ? distTags : undefined,\n versions: versions.length > 0 ? versions : undefined,\n locallyPublished,\n };\n } catch {\n return { locallyPublished: undefined };\n }\n}\n\nfunction readManifest(dir: string): Manifest | null {\n const candidates = [\n path.join(dir, \"powerhouse.manifest.json\"),\n path.join(dir, \"cdn\", \"powerhouse.manifest.json\"),\n path.join(dir, \"dist\", \"powerhouse.manifest.json\"),\n ];\n for (const manifestPath of candidates) {\n try {\n const raw = fs.readFileSync(manifestPath, \"utf-8\");\n return JSON.parse(raw) as Manifest;\n } catch {\n // try next candidate\n }\n }\n return null;\n}\n\nfunction readPackageJsonVersion(dir: string): string | undefined {\n try {\n const raw = fs.readFileSync(path.join(dir, \"package.json\"), \"utf-8\");\n const pkg = JSON.parse(raw) as { version?: unknown };\n return typeof pkg.version === \"string\" ? pkg.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction getLatestVersionDir(pkgDir: string): string | null {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(pkgDir, { withFileTypes: true });\n } catch {\n return null;\n }\n const versions = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n if (versions.length === 0) return null;\n versions.sort(compareSemver);\n return path.join(pkgDir, versions[versions.length - 1]);\n}\n\nexport function loadPackage(\n cdnCachePath: string,\n name: string,\n version?: string,\n): PackageInfo | null {\n const pkgDir = path.join(cdnCachePath, name);\n const versionDir = version\n ? path.join(pkgDir, version)\n : getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n\n if (!manifest) {\n return null;\n }\n return {\n name: manifest.name ?? name,\n path: `/-/cdn/${name}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n };\n}\n\nfunction getDocumentTypesFromManifest(manifest: Manifest | undefined | null) {\n if (!manifest) return [];\n\n const documentTypes: string[] = [];\n const { apps, documentModels, editors, subgraphs } = manifest;\n\n if (apps?.length) {\n documentTypes.push(\"powerhouse/document-drive\");\n }\n documentTypes.push(\n ...(documentModels ?? []).map((dm) => dm.id),\n ...(editors ?? [])\n .flatMap((e) => e.documentTypes)\n .filter((dt) => dt !== undefined),\n ...(subgraphs ?? [])\n .flatMap((e) => e.documentTypes)\n .filter((dt) => dt !== undefined),\n );\n\n return documentTypes;\n}\n\nexport function scanPackages(\n cdnCachePath: string,\n storagePath?: string,\n): PackageInfo[] {\n const absDir = path.resolve(cdnCachePath);\n const packages: PackageInfo[] = [];\n\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(absDir, { withFileTypes: true });\n } catch {\n return packages;\n }\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n if (entry.name.startsWith(\"@\")) {\n const scopeDir = path.join(absDir, entry.name);\n let scopedEntries: fs.Dirent[];\n try {\n scopedEntries = fs.readdirSync(scopeDir, { withFileTypes: true });\n } catch (error) {\n console.log(error);\n continue;\n }\n for (const scopedEntry of scopedEntries) {\n if (!scopedEntry.isDirectory()) continue;\n const dirName = `${entry.name}/${scopedEntry.name}`;\n const pkgDir = path.join(scopeDir, scopedEntry.name);\n const versionDir = getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n const name = manifest?.name ?? dirName;\n const { distTags, versions, locallyPublished } = readPackageMetadata(\n storagePath,\n name,\n );\n // Drop npm-uplink passthroughs from the default listing. Only\n // skip when we can affirmatively tell the package is a proxy\n // (no `_attachments` in filesystem-backed storage). When the flag\n // is `undefined` (no storagePath, or non-filesystem backend where\n // we can't read verdaccio's metadata) we include the entry — the\n // alternative would be filtering everything to `[]` on S3 deploys.\n if (locallyPublished === false) continue;\n packages.push({\n name,\n path: `/-/cdn/${dirName}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n distTags,\n versions,\n });\n }\n } else {\n const pkgDir = path.join(absDir, entry.name);\n const versionDir = getLatestVersionDir(pkgDir);\n const manifestDir = versionDir ?? pkgDir;\n const manifest = readManifest(manifestDir);\n const name = manifest?.name ?? entry.name;\n const { distTags, versions, locallyPublished } = readPackageMetadata(\n storagePath,\n name,\n );\n if (locallyPublished === false) continue;\n packages.push({\n name,\n path: `/-/cdn/${entry.name}`,\n manifest,\n documentTypes: getDocumentTypesFromManifest(manifest),\n version: readPackageJsonVersion(manifestDir),\n distTags,\n versions,\n });\n }\n }\n\n return packages;\n}\n\nexport function findPackagesByDocumentType(\n packagesDir: string,\n documentType: string,\n): PackageInfo[] {\n const allPackages = scanPackages(packagesDir);\n\n return allPackages.filter((pkg) => {\n if (!pkg.manifest?.documentModels) {\n return false;\n }\n return pkg.manifest.documentModels.some((dm) => dm.id === documentType);\n });\n}\n","import express, {\n Router,\n type NextFunction,\n type Request,\n type Response,\n} from \"express\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { CdnCache, parsePackageSpec } from \"./cdn.js\";\nimport type { SSEChannel } from \"./notifications/sse.js\";\nimport type { NotificationChannel } from \"./notifications/types.js\";\nimport type { WebhookChannel } from \"./notifications/webhook.js\";\nimport {\n findPackagesByDocumentType,\n loadPackage,\n scanPackages,\n} from \"./packages.js\";\nimport type { RegistryConfig } from \"./types.js\";\n\nconst MIME_TYPES: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".wasm\": \"application/wasm\",\n \".map\": \"application/json\",\n \".html\": \"text/html\",\n \".svg\": \"image/svg+xml\",\n};\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n return MIME_TYPES[ext] ?? \"application/octet-stream\";\n}\n\nexport function createPowerhouseRouter(\n config: RegistryConfig,\n sse: SSEChannel,\n webhooks: WebhookChannel,\n): Router {\n const cdn = new CdnCache(\n `http://localhost:${config.port}`,\n config.cdnCachePath,\n );\n const router = Router();\n\n // CORS on every response\n router.use((_req: Request, res: Response, next: NextFunction) => {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n next();\n });\n\n // SSE endpoint for publish notifications\n router.get(\"/-/events\", (_req: Request, res: Response) => {\n sse.addClient(res);\n });\n\n // Webhook management\n router.get(\"/-/webhooks\", (_req: Request, res: Response) => {\n res.json(webhooks.getWebhooks());\n });\n\n router.post(\"/-/webhooks\", express.json(), (req: Request, res: Response) => {\n const { endpoint, headers } = req.body as {\n endpoint?: string;\n headers?: Record<string, string>;\n };\n if (!endpoint) {\n res.status(400).json({ error: \"Missing required field: endpoint\" });\n return;\n }\n webhooks.addWebhook({ endpoint, headers });\n res.status(201).json({ endpoint, headers });\n });\n\n router.delete(\n \"/-/webhooks\",\n express.json(),\n (req: Request, res: Response) => {\n const { endpoint } = req.body as { endpoint?: string };\n if (!endpoint) {\n res.status(400).json({ error: \"Missing required field: endpoint\" });\n return;\n }\n const removed = webhooks.removeWebhook(endpoint);\n if (!removed) {\n res.status(404).json({ error: \"Webhook not found\" });\n return;\n }\n res.status(204).end();\n },\n );\n\n // Package listing API\n router.get(\"/packages\", (req: Request, res: Response) => {\n const packages = scanPackages(config.cdnCachePath, config.storagePath);\n const documentType = req.query.documentType as string | undefined;\n if (documentType) {\n const filtered = packages.filter((pkg) =>\n pkg.manifest?.documentModels?.some((m) => m.id === documentType),\n );\n res.json(filtered);\n return;\n }\n res.json(packages);\n });\n\n // Find packages by document type - returns array of package names\n router.get(\"/packages/by-document-type\", (req: Request, res: Response) => {\n const documentType = req.query.type;\n\n if (typeof documentType !== \"string\" || !documentType) {\n res.status(400).json({ error: \"Missing required query parameter: type\" });\n return;\n }\n\n const packages = findPackagesByDocumentType(\n config.cdnCachePath,\n documentType,\n );\n const packageNames = packages.map((pkg) => pkg.name);\n res.json(packageNames);\n });\n\n // Single package info\n router.get(\"/packages/*name\", async (req: Request, res: Response) => {\n const raw = (req.params as Record<string, string[]>).name.join(\"/\");\n const { name, tag } = parsePackageSpec(raw);\n const version =\n (await cdn.resolveVersion(name, tag)) ?? cdn.getLatestCachedVersion(name);\n const pkg = loadPackage(config.cdnCachePath, name, version ?? undefined);\n if (!pkg) {\n res.status(404).send(\"Package not found\");\n return;\n }\n res.json(pkg);\n });\n\n // CDN file serving\n router.get(\"/-/cdn/*path\", async (req: Request, res: Response) => {\n const parts = (req.params as Record<string, string[]>).path;\n const fullPath = parts.join(\"/\");\n\n // Parse scoped or unscoped package specifier from the path\n let packageSpec: string;\n let filePath: string;\n\n if (fullPath.startsWith(\"@\")) {\n // Scoped: @scope/pkg@1.0.0/file.js -> packageSpec = @scope/pkg@1.0.0, filePath = file.js\n const segments = fullPath.split(\"/\");\n if (segments.length < 2) {\n res.status(400).send(\"Invalid package path\");\n return;\n }\n packageSpec = `${segments[0]}/${segments[1]}`;\n filePath = segments.slice(2).join(\"/\") || \"index.js\";\n } else {\n // Unscoped: pkg@1.0.0/file.js -> packageSpec = pkg@1.0.0, filePath = file.js\n const segments = fullPath.split(\"/\");\n packageSpec = segments[0];\n filePath = segments.slice(1).join(\"/\") || \"index.js\";\n }\n\n const { name: packageName, tag } = parsePackageSpec(packageSpec);\n const version =\n (await cdn.resolveVersion(packageName, tag)) ??\n cdn.getLatestCachedVersion(packageName);\n if (!version) {\n res.status(404).send(\"File not found\");\n return;\n }\n\n const resolved = await cdn.getFileByVersion(packageName, version, filePath);\n if (!resolved) {\n res.status(404).send(\"File not found\");\n return;\n }\n\n res.setHeader(\"Content-Type\", getContentType(filePath));\n const content = fs.readFileSync(resolved);\n res.send(content);\n });\n\n return router;\n}\n\nexport function createPublishHook(\n config: RegistryConfig,\n notifications: NotificationChannel,\n) {\n const cdn = new CdnCache(\n `http://localhost:${config.port}`,\n config.cdnCachePath,\n );\n\n return (req: Request, res: Response, next: NextFunction) => {\n // Only intercept PUT requests to npm publish endpoints\n if (req.method !== \"PUT\") {\n next();\n return;\n }\n\n const originalEnd = res.end.bind(res);\n res.end = function (\n this: Response,\n chunk?: unknown,\n encoding?: unknown,\n cb?: () => void,\n ) {\n const urlPath = req.path.replace(/^\\//, \"\");\n if (\n res.statusCode < 200 ||\n res.statusCode >= 300 ||\n !urlPath ||\n urlPath.startsWith(\"-\")\n ) {\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n }\n const packageName = decodeURIComponent(urlPath);\n const versionsObj = (req.body as { versions: Record<string, unknown> })\n .versions;\n const versions = Object.keys(versionsObj);\n const version = versions.at(0);\n if (!version) {\n console.error(`[registry] No version found for ${packageName}`);\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n }\n if (versions.length > 1) {\n console.warn(\n `[registry] Multiple versions published for ${packageName}: ${JSON.stringify(versions)}`,\n );\n }\n\n cdn\n .extractTarball(packageName, version)\n .then(() => {\n notifications.notifyPublish({ packageName, version });\n })\n .catch((err) => {\n console.error(\n `[registry] Failed to extract ${packageName} to CDN cache:`,\n err,\n );\n });\n\n return originalEnd(chunk, encoding as BufferEncoding, cb);\n };\n\n next();\n };\n}\n","import type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nexport class NotificationManager implements NotificationChannel {\n #channels: NotificationChannel[];\n\n constructor(channels: NotificationChannel[]) {\n this.#channels = channels;\n }\n\n notifyPublish(event: PublishEvent): void {\n for (const channel of this.#channels) {\n channel.notifyPublish(event);\n }\n }\n}\n","import type { Response } from \"express\";\nimport type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nexport class SSEChannel implements NotificationChannel {\n #clients = new Set<Response>();\n\n addClient(res: Response): void {\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n res.write(\"event: connected\\ndata: {}\\n\\n\");\n\n this.#clients.add(res);\n res.on(\"close\", () => {\n this.#clients.delete(res);\n });\n }\n\n notifyPublish(event: PublishEvent): void {\n const payload = `event: publish\\ndata: ${JSON.stringify(event)}\\n\\n`;\n for (const client of this.#clients) {\n try {\n client.write(payload);\n } catch (err) {\n console.error(\"[registry] SSE client write failed:\", err);\n this.#clients.delete(client);\n }\n }\n }\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { NotifyConfig, WebhookConfig } from \"../types.js\";\nimport type { NotificationChannel, PublishEvent } from \"./types.js\";\n\nconst WEBHOOKS_FILE = \"webhooks.json\";\n\nexport class WebhookChannel implements NotificationChannel {\n #predefined: WebhookConfig[];\n #dynamic: WebhookConfig[];\n #storagePath: string;\n\n constructor(storagePath: string, config?: NotifyConfig) {\n this.#storagePath = storagePath;\n this.#predefined = config?.webhooks ?? [];\n this.#dynamic = this.#load();\n }\n\n getWebhooks(): WebhookConfig[] {\n return [...this.#predefined, ...this.#dynamic];\n }\n\n addWebhook(webhook: WebhookConfig): void {\n const exists = this.getWebhooks().some(\n (w) => w.endpoint === webhook.endpoint,\n );\n if (exists) return;\n this.#dynamic.push(webhook);\n this.#save();\n }\n\n removeWebhook(endpoint: string): boolean {\n const before = this.#dynamic.length;\n this.#dynamic = this.#dynamic.filter((w) => w.endpoint !== endpoint);\n if (this.#dynamic.length === before) return false;\n this.#save();\n return true;\n }\n\n notifyPublish(event: PublishEvent): void {\n for (const webhook of this.getWebhooks()) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...webhook.headers,\n };\n\n fetch(webhook.endpoint, {\n method: \"POST\",\n headers,\n body: JSON.stringify(event),\n }).catch((err: unknown) => {\n console.error(`[registry] Webhook to ${webhook.endpoint} failed:`, err);\n });\n }\n }\n\n #filePath(): string {\n return path.join(this.#storagePath, WEBHOOKS_FILE);\n }\n\n #load(): WebhookConfig[] {\n try {\n const raw = fs.readFileSync(this.#filePath(), \"utf-8\");\n return JSON.parse(raw) as WebhookConfig[];\n } catch {\n return [];\n }\n }\n\n #save(): void {\n fs.mkdirSync(this.#storagePath, { recursive: true });\n fs.writeFileSync(this.#filePath(), JSON.stringify(this.#dynamic, null, 2));\n }\n}\n","import path from \"node:path\";\nimport type { RegistryConfig } from \"./types.js\";\n\nexport function buildVerdaccioConfig(config: RegistryConfig) {\n const htpasswdPath = path.join(config.storagePath, \"htpasswd\");\n\n const uplinkUrl = config.uplink ?? \"https://registry.npmjs.org/\";\n\n const base: Record<string, unknown> = {\n storage: config.storagePath,\n self_path: \"./\",\n auth: {\n htpasswd: {\n file: htpasswdPath,\n },\n },\n uplinks: {\n npmjs: {\n url: uplinkUrl,\n maxage: \"15m\",\n timeout: \"30s\",\n cache: true,\n },\n },\n packages: {\n \"@powerhousedao/*\": {\n access: \"$all\",\n publish: \"$authenticated\",\n unpublish: \"$authenticated\",\n proxy: \"npmjs\",\n },\n \"**\": {\n access: \"$all\",\n publish: \"$authenticated\",\n unpublish: \"$authenticated\",\n proxy: \"npmjs\",\n },\n },\n web: {\n enable: config.webEnabled !== false,\n title: \"Powerhouse Registry\",\n logo: \"https://raw.githubusercontent.com/powerhouse-inc/powerhouse/main/packages/registry/static/logo.svg\",\n favicon: \"/-/static/favicon.ico\",\n primary_color: \"#38C780\",\n darkMode: true,\n },\n server: {\n keepAliveTimeout: 60,\n },\n log: {\n type: \"stdout\",\n format: \"pretty\",\n level: \"warn\",\n },\n max_body_size: config.maxBodySize ?? \"300mb\",\n };\n\n if (config.s3) {\n base.store = {\n \"aws-s3-storage\": {\n bucket: config.s3.bucket,\n endpoint: config.s3.endpoint,\n region: config.s3.region,\n s3ForcePathStyle: config.s3.s3ForcePathStyle ?? true,\n ...(config.s3.keyPrefix && { keyPrefix: config.s3.keyPrefix }),\n ...(config.s3.accessKeyId && { accessKeyId: config.s3.accessKeyId }),\n ...(config.s3.secretAccessKey && {\n secretAccessKey: config.s3.secretAccessKey,\n }),\n },\n };\n }\n\n return base;\n}\n","import express from \"express\";\nimport { findUp } from \"find-up\";\nimport { mkdir } from \"node:fs/promises\";\nimport type { Server } from \"node:http\";\nimport path from \"node:path\";\nimport { runServer } from \"verdaccio\";\nimport { createPowerhouseRouter, createPublishHook } from \"./middleware.js\";\nimport { NotificationManager } from \"./notifications/manager.js\";\nimport { SSEChannel } from \"./notifications/sse.js\";\nimport { WebhookChannel } from \"./notifications/webhook.js\";\nimport type { RegistryCommandArgs, RegistryConfig } from \"./types.js\";\nimport { buildVerdaccioConfig } from \"./verdaccio-config.js\";\n\nasync function resolveDir(dir: string): Promise<string> {\n if (path.isAbsolute(dir)) {\n await mkdir(dir, { recursive: true });\n return dir;\n }\n const found = await findUp(dir, { type: \"directory\" });\n if (!found) {\n await mkdir(dir, { recursive: true });\n return dir;\n }\n return found;\n}\n\nexport async function runRegistry(args: RegistryCommandArgs) {\n const {\n port,\n storageDir,\n cdnCacheDir,\n uplink,\n webEnabled,\n webhooks,\n s3AccessKeyId,\n s3Bucket,\n s3Endpoint,\n s3ForcePathStyle,\n s3KeyPrefix,\n s3Region,\n s3SecretAccessKey,\n } = args;\n const storagePath = await resolveDir(storageDir);\n const cdnCachePath = await resolveDir(cdnCacheDir);\n\n console.log({\n storagePath,\n cdnCachePath,\n });\n\n const webhookConfigs = webhooks\n ?.split(\",\")\n .map((url) => url.trim())\n .filter(Boolean)\n .map((endpoint) => ({ endpoint }));\n\n const config: RegistryConfig = {\n port,\n storagePath,\n cdnCachePath,\n uplink,\n webEnabled,\n ...(webhookConfigs?.length && {\n notify: { webhooks: webhookConfigs },\n }),\n ...(s3Bucket &&\n s3Endpoint &&\n s3Region && {\n s3: {\n bucket: s3Bucket,\n endpoint: s3Endpoint,\n region: s3Region,\n accessKeyId: s3AccessKeyId,\n secretAccessKey: s3SecretAccessKey,\n keyPrefix: s3KeyPrefix,\n s3ForcePathStyle,\n },\n }),\n };\n // Ensure directories exist (for relative paths resolved via findUp)\n await mkdir(storagePath, { recursive: true });\n await mkdir(cdnCachePath, { recursive: true });\n\n const verdaccioConfig = buildVerdaccioConfig(config);\n\n // verdaccio's runServer returns Promise<any> (upstream type limitation)\n const verdaccioServer = (await runServer(verdaccioConfig)) as Server;\n const verdaccioHandler = verdaccioServer.listeners(\"request\")[0] as (\n ...args: unknown[]\n ) => void;\n\n const app = express();\n\n const sseChannel = new SSEChannel();\n const webhookChannel = new WebhookChannel(config.storagePath, config.notify);\n const notifications = new NotificationManager([sseChannel, webhookChannel]);\n\n // Serve static assets (logo, etc.)\n const staticDir = await findUp(\"static\", { type: \"directory\" });\n if (staticDir) {\n app.use(\"/-/static\", express.static(staticDir));\n }\n\n // Our routes take priority over Verdaccio\n app.use(createPowerhouseRouter(config, sseChannel, webhookChannel));\n app.use(createPublishHook(config, notifications));\n\n // Verdaccio handles everything else (npm protocol, web UI, auth)\n app.use((req, res) => verdaccioHandler(req, res));\n\n const server = app.listen(port, () => {\n console.log(`Powerhouse Registry running on http://localhost:${port}`);\n console.log(` CDN: http://localhost:${port}/-/cdn/`);\n console.log(` Packages: http://localhost:${port}/packages`);\n console.log(` npm: http://localhost:${port}/`);\n console.log(` Storage: ${storagePath}`);\n console.log(` CDN cache: ${cdnCachePath}`);\n if (config.s3) {\n console.log(` S3: ${config.s3.endpoint}/${config.s3.bucket}`);\n }\n });\n\n return server;\n}\n","import {\n binary,\n command,\n flag,\n number,\n option,\n optional,\n run,\n string,\n} from \"cmd-ts\";\nimport {\n DEFAULT_PORT,\n DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME,\n DEFAULT_STORAGE_DIR_NAME,\n} from \"./src/constants.js\";\nimport { runRegistry } from \"./src/run.js\";\n\nexport const registryCommand = command({\n name: \"Package registry\",\n args: {\n port: option({\n long: \"port\",\n type: number,\n defaultValue: () => Number(process.env.PORT) || DEFAULT_PORT,\n defaultValueIsSerializable: true,\n }),\n storageDir: option({\n long: \"storage-dir\",\n type: string,\n defaultValue: () =>\n process.env.REGISTRY_STORAGE || DEFAULT_STORAGE_DIR_NAME,\n defaultValueIsSerializable: true,\n }),\n cdnCacheDir: option({\n long: \"cdn-cache-dir\",\n type: string,\n defaultValue: () =>\n process.env.REGISTRY_CDN_CACHE || DEFAULT_REGISTRY_CDN_CACHE_DIR_NAME,\n defaultValueIsSerializable: true,\n }),\n uplink: option({\n long: \"uplink\",\n type: optional(string),\n defaultValue: () => process.env.REGISTRY_UPLINK,\n defaultValueIsSerializable: true,\n }),\n s3Bucket: option({\n long: \"s3-bucket\",\n type: optional(string),\n defaultValue: () => process.env.S3_BUCKET,\n defaultValueIsSerializable: true,\n }),\n s3Endpoint: option({\n long: \"s3-endpoint\",\n type: optional(string),\n defaultValue: () => process.env.S3_ENDPOINT,\n defaultValueIsSerializable: true,\n }),\n s3Region: option({\n long: \"s3-region\",\n type: optional(string),\n defaultValue: () => process.env.S3_REGION,\n defaultValueIsSerializable: true,\n }),\n s3AccessKeyId: option({\n long: \"s3-access-key-id\",\n type: optional(string),\n defaultValue: () => process.env.S3_ACCESS_KEY_ID,\n defaultValueIsSerializable: true,\n }),\n s3SecretAccessKey: option({\n long: \"s3-secret-access-key\",\n type: optional(string),\n defaultValue: () => process.env.S3_SECRET_ACCESS_KEY,\n defaultValueIsSerializable: true,\n }),\n s3KeyPrefix: option({\n long: \"s3-key-prefix\",\n type: optional(string),\n defaultValue: () => process.env.S3_KEY_PREFIX,\n defaultValueIsSerializable: true,\n }),\n s3ForcePathStyle: flag({\n long: \"s3-force-path-style\",\n defaultValue: () => process.env.S3_FORCE_PATH_STYLE !== \"false\",\n defaultValueIsSerializable: true,\n }),\n webEnabled: flag({\n long: \"web-enabled\",\n defaultValue: () => process.env.REGISTRY_WEB !== \"false\",\n defaultValueIsSerializable: true,\n }),\n webhooks: option({\n long: \"webhook\",\n type: optional(string),\n description: \"Comma-separated webhook URLs to notify on publish\",\n defaultValue: () => process.env.REGISTRY_WEBHOOKS,\n defaultValueIsSerializable: true,\n }),\n },\n handler: async (args) => {\n console.log(args);\n\n try {\n await runRegistry(args);\n } catch (error) {\n console.error(\"Failed to start registry:\");\n console.error(error);\n process.exit(1);\n }\n },\n});\n\nconst registryCli = binary(registryCommand);\n\nawait run(registryCli, process.argv);\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerhousedao/registry",
3
- "version": "6.0.0-dev.189",
3
+ "version": "6.0.0-dev.191",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "tar": "^7.5.11",
26
26
  "verdaccio": "^6.5.0",
27
27
  "verdaccio-aws-s3-storage": "^10.4.0",
28
- "@powerhousedao/shared": "6.0.0-dev.189"
28
+ "@powerhousedao/shared": "6.0.0-dev.191"
29
29
  },
30
30
  "devDependencies": {
31
31
  "tsdown": "0.21.1",