storeshot 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/server.ts","../src/project-store.ts","../src/device-mockups.ts","../src/image-metadata.ts","../src/screenshot-area.ts","../src/shared.ts"],"sourcesContent":["import path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { Command, Option } from \"commander\"\nimport open from \"open\"\n\nimport { startServer } from \"./server.js\"\n\nconst sourceFile = fileURLToPath(import.meta.url)\nconst packageRoot = path.resolve(path.dirname(sourceFile), \"..\")\nconst isSourceExecution = path.extname(sourceFile) === \".ts\"\n\nconst program = new Command()\n .name(\"storeshot\")\n .description(\"Manage app store screenshots locally\")\n .version(\"0.1.0\")\n\nprogram\n .command(\"dev\")\n .description(\"Open a StoreShot workspace for a local directory\")\n .argument(\"[directory]\", \"project directory\", \".\")\n .addOption(new Option(\"-p, --port <port>\", \"local server port\").default(\"4173\"))\n .addOption(new Option(\"--host <host>\", \"local server host\").default(\"127.0.0.1\"))\n .option(\"--no-open\", \"do not open a browser\")\n .action(async (directory: string, options: { port: string; host: string; open: boolean }) => {\n const port = Number(options.port)\n if (!Number.isInteger(port) || port < 1 || port > 65_535) {\n throw new Error(\"Port must be an integer between 1 and 65535\")\n }\n\n const projectDirectory = path.resolve(directory)\n const service = await startServer({\n host: options.host,\n port,\n packageRoot,\n projectDirectory,\n useVite: isSourceExecution,\n })\n const url = `http://${options.host}:${port}`\n\n console.log(`\\n StoreShot is ready at ${url}`)\n console.log(` Project: ${service.store.root}\\n`)\n\n if (options.open) await open(url)\n\n const shutdown = async () => {\n await service.close()\n process.exit(0)\n }\n process.once(\"SIGINT\", shutdown)\n process.once(\"SIGTERM\", shutdown)\n })\n\nprogram.parseAsync().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n console.error(`storeshot: ${message}`)\n process.exitCode = 1\n})\n","import { createReadStream } from \"node:fs\"\nimport { readFile, stat } from \"node:fs/promises\"\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport path from \"node:path\"\n\nimport type { ViteDevServer } from \"vite\"\n\nimport { DuplicateAssetError, ProjectStore } from \"./project-store.js\"\nimport type { StoreShotConfig, AssetCategory, CreateSetInput, ScreenshotSet, UpdateAssetMetadataInput, UpdateSetMetadataInput } from \"./shared.js\"\n\nconst MAX_REQUEST_BYTES = 25 * 1024 * 1024\n\ninterface StartServerOptions {\n host: string\n port: number\n packageRoot: string\n projectDirectory: string\n useVite: boolean\n}\n\nexport async function startServer(options: StartServerOptions) {\n const store = new ProjectStore(options.projectDirectory)\n await store.initialize()\n\n let vite: ViteDevServer | undefined\n if (options.useVite) {\n const { createServer: createViteServer } = await import(\"vite\")\n vite = await createViteServer({\n configFile: path.join(options.packageRoot, \"vite.config.ts\"),\n server: { middlewareMode: true },\n appType: \"spa\",\n })\n }\n\n const server = createServer(async (request, response) => {\n try {\n if ((request.url ?? \"\").startsWith(\"/api/\")) assertAllowedBrowserRequest(request, options.host)\n if (await handleApiRequest(request, response, store)) return\n if (vite) {\n vite.middlewares(request, response)\n return\n }\n await serveBuiltFrontend(request, response, path.join(options.packageRoot, \"dist/ui\"))\n } catch (error) {\n const failure = httpFailureFor(error, request)\n if (failure.status >= 500) console.error(error)\n if (!response.headersSent) sendJson(response, failure.status, { error: failure.message, ...(failure.code ? { code: failure.code } : {}) })\n else response.end()\n }\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(options.port, options.host, resolve)\n })\n\n return {\n store,\n port: (server.address() as AddressInfo).port,\n close: async () => {\n await vite?.close()\n await new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()))\n })\n },\n }\n}\n\nasync function handleApiRequest(\n request: IncomingMessage,\n response: ServerResponse,\n store: ProjectStore,\n): Promise<boolean> {\n const url = new URL(request.url ?? \"/\", \"http://localhost\")\n\n if (request.method === \"GET\" && url.pathname === \"/api/project\") {\n sendJson(response, 200, await store.readProject())\n return true\n }\n\n if (request.method === \"GET\" && url.pathname === \"/api/mockup-bundles\") {\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleImportFileMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)\\/([^/]+)\\/files\\/(.+)$/)\n if (request.method === \"PUT\" && mockupBundleImportFileMatch) {\n const importId = decodeURIComponent(mockupBundleImportFileMatch[1])\n const bundleId = decodeURIComponent(mockupBundleImportFileMatch[2])\n const relativePath = mockupBundleImportFileMatch[3].split(\"/\").map(decodeURIComponent).join(\"/\")\n await store.writeMockupBundleImportFile(importId, bundleId, relativePath, await readBody(request))\n response.writeHead(204).end()\n return true\n }\n\n const mockupBundleImportMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)\\/([^/]+)$/)\n if (request.method === \"PUT\" && mockupBundleImportMatch) {\n const importId = decodeURIComponent(mockupBundleImportMatch[1])\n const bundleId = decodeURIComponent(mockupBundleImportMatch[2])\n await store.commitMockupBundleImport(importId, bundleId, await readJsonBody(request))\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleImportDiscardMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)$/)\n if (request.method === \"DELETE\" && mockupBundleImportDiscardMatch) {\n await store.discardMockupBundleImport(decodeURIComponent(mockupBundleImportDiscardMatch[1]))\n response.writeHead(204).end()\n return true\n }\n\n const mockupBundleMatch = url.pathname.match(/^\\/api\\/mockup-bundles\\/([^/]+)$/)\n if (request.method === \"PUT\" && mockupBundleMatch) {\n const bundleId = decodeURIComponent(mockupBundleMatch[1])\n await store.writeMockupBundleManifest(bundleId, await readJsonBody(request))\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleFileMatch = url.pathname.match(/^\\/api\\/mockup-bundle-files\\/([^/]+)\\/(.+)$/)\n if (mockupBundleFileMatch) {\n const bundleId = decodeURIComponent(mockupBundleFileMatch[1])\n const relativePath = mockupBundleFileMatch[2].split(\"/\").map(decodeURIComponent).join(\"/\")\n if (request.method === \"PUT\") {\n await store.writeMockupBundleFile(bundleId, relativePath, await readBody(request))\n response.writeHead(204).end()\n return true\n }\n if (request.method === \"GET\") {\n const target = await store.resolveExistingMockupBundleFile(bundleId, relativePath)\n const metadata = await stat(target)\n response.writeHead(200, {\n \"Content-Type\": contentTypeFor(target),\n \"Content-Length\": metadata.size,\n \"Cache-Control\": \"no-store\",\n \"X-Content-Type-Options\": \"nosniff\",\n ...(path.extname(target).toLowerCase() === \".svg\" ? { \"Content-Security-Policy\": \"default-src 'none'; style-src 'unsafe-inline'; sandbox\" } : {}),\n })\n createReadStream(target).pipe(response)\n return true\n }\n }\n\n if (request.method === \"PATCH\" && url.pathname === \"/api/config\") {\n const config = await store.writeConfig((await readJsonBody(request)) as StoreShotConfig)\n sendJson(response, 200, config)\n return true\n }\n\n if (request.method === \"POST\" && url.pathname === \"/api/assets\") {\n const category = url.searchParams.get(\"category\")\n const filename = url.searchParams.get(\"filename\")\n if (!category || !filename) {\n sendJson(response, 400, { error: \"A category and filename are required\" })\n return true\n }\n let replaced = false\n try {\n const result = await store.addAsset(category, filename, await readBody(request))\n replaced = result.replaced\n } catch (error) {\n if (error instanceof DuplicateAssetError) {\n sendJson(response, 409, { error: error.message, code: \"DUPLICATE_ASSET\" })\n return true\n }\n throw error\n }\n sendJson(response, replaced ? 200 : 201, { replaced })\n return true\n }\n\n const assetMatch = url.pathname.match(/^\\/api\\/assets\\/([^/]+)\\/([^/]+)$/)\n if (assetMatch) {\n const category = decodeURIComponent(assetMatch[1]) as AssetCategory\n const filename = decodeURIComponent(assetMatch[2])\n if (request.method === \"GET\") {\n const target = await store.resolveExistingAsset(category, filename)\n const metadata = await stat(target)\n response.writeHead(200, {\n \"Content-Type\": contentTypeFor(target),\n \"Content-Length\": metadata.size,\n \"Cache-Control\": \"no-store\",\n \"X-Content-Type-Options\": \"nosniff\",\n ...(path.extname(target).toLowerCase() === \".svg\" ? { \"Content-Security-Policy\": \"default-src 'none'; style-src 'unsafe-inline'; sandbox\" } : {}),\n })\n createReadStream(target).pipe(response)\n return true\n }\n\n if (request.method === \"DELETE\") {\n await store.deleteAsset(category, filename)\n response.writeHead(204).end()\n return true\n }\n\n if (request.method === \"PATCH\") {\n await store.updateAssetMetadata(category, filename, (await readJsonBody(request)) as UpdateAssetMetadataInput)\n sendJson(response, 200, await store.readProject())\n return true\n }\n }\n\n if (request.method === \"POST\" && url.pathname === \"/api/sets\") {\n const set = await store.createSet((await readJsonBody(request)) as CreateSetInput)\n sendJson(response, 201, set)\n return true\n }\n\n const duplicateSetMatch = url.pathname.match(/^\\/api\\/sets\\/([^/]+)\\/duplicate$/)\n if (request.method === \"POST\" && duplicateSetMatch) {\n const set = await store.duplicateSet(decodeURIComponent(duplicateSetMatch[1]))\n sendJson(response, 201, set)\n return true\n }\n\n const setMatch = url.pathname.match(/^\\/api\\/sets\\/([^/]+)$/)\n if (setMatch) {\n const id = decodeURIComponent(setMatch[1])\n if (request.method === \"PATCH\") {\n const set = await store.updateSetMetadata(id, (await readJsonBody(request)) as UpdateSetMetadataInput)\n sendJson(response, 200, set)\n return true\n }\n if (request.method === \"PUT\") {\n const set = await store.writeSet(id, (await readJsonBody(request)) as ScreenshotSet)\n sendJson(response, 200, set)\n return true\n }\n if (request.method === \"DELETE\") {\n await store.deleteSet(id)\n response.writeHead(204).end()\n return true\n }\n }\n\n if (url.pathname.startsWith(\"/api/\")) {\n sendJson(response, 404, { error: \"Not found\" })\n return true\n }\n return false\n}\n\nasync function serveBuiltFrontend(request: IncomingMessage, response: ServerResponse, uiDirectory: string) {\n const url = new URL(request.url ?? \"/\", \"http://localhost\")\n const relativePath = url.pathname === \"/\" ? \"index.html\" : decodeURIComponent(url.pathname.slice(1))\n const candidate = path.resolve(uiDirectory, relativePath)\n const safeRoot = `${path.resolve(uiDirectory)}${path.sep}`\n const target = candidate.startsWith(safeRoot) ? candidate : path.join(uiDirectory, \"index.html\")\n\n try {\n const metadata = await stat(target)\n if (!metadata.isFile()) throw new Error(\"Not a file\")\n const body = await readFile(target)\n response.writeHead(200, { \"Content-Type\": contentTypeFor(target), \"Content-Length\": body.length })\n response.end(body)\n } catch {\n const body = await readFile(path.join(uiDirectory, \"index.html\"))\n response.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n response.end(body)\n }\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n const contentType = request.headers[\"content-type\"]?.split(\";\", 1)[0]?.trim().toLowerCase()\n if (contentType !== \"application/json\") throw new HttpError(415, \"Request body must use application/json\")\n const body = await readBody(request)\n try {\n return JSON.parse(body.toString(\"utf8\"))\n } catch {\n throw new HttpError(400, \"Request body must be valid JSON\")\n }\n}\n\nasync function readBody(request: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of request) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n size += buffer.length\n if (size > MAX_REQUEST_BYTES) throw new HttpError(413, \"Request is larger than 25 MB\")\n chunks.push(buffer)\n }\n return Buffer.concat(chunks)\n}\n\nclass HttpError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nfunction assertAllowedBrowserRequest(request: IncomingMessage, configuredHost: string): void {\n const host = request.headers.host\n if (!host) throw new HttpError(400, \"A Host header is required\")\n\n let hostUrl: URL\n try {\n hostUrl = new URL(`http://${host}`)\n } catch {\n throw new HttpError(400, \"The Host header is invalid\")\n }\n const configuredHostname = normalizedHostname(configuredHost)\n if (!isLoopbackHostname(hostUrl.hostname) && hostUrl.hostname !== configuredHostname) {\n throw new HttpError(403, \"This StoreShot server does not accept requests for that host\")\n }\n\n const origin = request.headers.origin\n if (!origin) return\n let originUrl: URL\n try {\n originUrl = new URL(origin)\n } catch {\n throw new HttpError(403, \"The request origin is invalid\")\n }\n if ((originUrl.protocol !== \"http:\" && originUrl.protocol !== \"https:\") || originUrl.host !== host) {\n throw new HttpError(403, \"Cross-origin API requests are not allowed\")\n }\n}\n\nfunction normalizedHostname(host: string): string {\n try {\n return new URL(`http://${host}`).hostname\n } catch {\n return host.replace(/^\\[|\\]$/g, \"\")\n }\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\"\n}\n\nfunction httpFailureFor(error: unknown, request: IncomingMessage): HttpError {\n if (error instanceof HttpError) return error\n if (error instanceof DuplicateAssetError) return new HttpError(409, error.message, \"DUPLICATE_ASSET\")\n const code = (error as NodeJS.ErrnoException | undefined)?.code\n if (code === \"ENOENT\") return new HttpError(404, \"The requested project file was not found\")\n if (code === \"EACCES\" || code === \"EPERM\") return new HttpError(403, \"StoreShot cannot access that project file\")\n if (isMutation(request) && error instanceof Error && !code) return new HttpError(400, error.message)\n return new HttpError(500, \"StoreShot could not complete the request\")\n}\n\nfunction isMutation(request: IncomingMessage): boolean {\n return request.method === \"POST\" || request.method === \"PUT\" || request.method === \"PATCH\" || request.method === \"DELETE\"\n}\n\nfunction sendJson(response: ServerResponse, status: number, value: unknown) {\n const body = JSON.stringify(value)\n response.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Content-Length\": Buffer.byteLength(body),\n })\n response.end(body)\n}\n\nfunction contentTypeFor(filename: string): string {\n switch (path.extname(filename).toLowerCase()) {\n case \".html\": return \"text/html; charset=utf-8\"\n case \".js\": return \"text/javascript; charset=utf-8\"\n case \".css\": return \"text/css; charset=utf-8\"\n case \".png\": return \"image/png\"\n case \".jpg\":\n case \".jpeg\": return \"image/jpeg\"\n case \".webp\": return \"image/webp\"\n case \".svg\": return \"image/svg+xml\"\n case \".md\":\n case \".txt\": return \"text/plain; charset=utf-8\"\n default: return \"application/octet-stream\"\n }\n}\n","import { createHash, randomUUID } from \"node:crypto\"\nimport { constants } from \"node:fs\"\nimport { access, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport {\n MOCKUP_BUNDLE_FILENAME,\n bundleAssetPaths,\n emptyDeviceMockupCatalog,\n isSafeBundlePath,\n mergeDeviceMockupCatalogs,\n parseMockupBundleManifest,\n resolveMockupBundle,\n type DeviceMockupCatalog,\n type MockupBundleManifest,\n} from \"./device-mockups.js\"\nimport { detectScreenshotDeviceType, readImageMetadata } from \"./image-metadata.js\"\nimport { cloneScreenshotArea } from \"./screenshot-area.js\"\n\nimport {\n ASSET_CATEGORIES,\n type StoreShotConfig,\n type StoreShotProject,\n type Asset,\n type AssetCategory,\n type CanvasElement,\n type CreateSetInput,\n type FontWeight,\n type ImageElementSource,\n type ScreenshotArea,\n type ScreenshotSet,\n SCREENSHOT_DEVICE_TYPES,\n type ScreenshotDeviceType,\n type UpdateAssetMetadataInput,\n type UpdateSetMetadataInput,\n} from \"./shared.js\"\n\nexport const CONFIG_FILENAME = \"storeshot.json\"\nexport const ASSETS_DIRECTORY = \"assets\"\nexport const SETS_DIRECTORY = \"sets\"\nexport const ASSET_METADATA_FILENAME = \".storeshot-metadata.json\"\nexport const MOCKUP_BUNDLES_DIRECTORY = \"mockup-bundles\"\nconst MOCKUP_IMPORTS_DIRECTORY = \".imports\"\n\nconst supportedExtensions = new Set([\".png\", \".jpg\", \".jpeg\", \".webp\", \".svg\"])\nconst supportedMockupBundleExtensions = new Set([\".jpeg\", \".jpg\", \".md\", \".png\", \".svg\", \".txt\", \".webp\"])\nconst safeIdentifierPattern = /^[a-z0-9][a-z0-9-]*$/\nconst hexColorPattern = /^#[0-9a-f]{6}$/i\n\nexport class ProjectStore {\n readonly root: string\n readonly configPath: string\n readonly assetsPath: string\n readonly setsPath: string\n readonly mockupBundlesPath: string\n readonly mockupImportsPath: string\n private readonly operations = new Map<string, Promise<void>>()\n private readonly assetHashes = new Map<string, { hash: string; mtimeMs: number; size: number }>()\n\n constructor(directory: string) {\n this.root = path.resolve(directory)\n this.configPath = path.join(this.root, CONFIG_FILENAME)\n this.assetsPath = path.join(this.root, ASSETS_DIRECTORY)\n this.setsPath = path.join(this.root, SETS_DIRECTORY)\n this.mockupBundlesPath = path.join(this.root, MOCKUP_BUNDLES_DIRECTORY)\n this.mockupImportsPath = path.join(this.mockupBundlesPath, MOCKUP_IMPORTS_DIRECTORY)\n }\n\n async initialize(): Promise<void> {\n await mkdir(this.root, { recursive: true })\n await this.assertManagedDirectory(this.root)\n await this.ensureManagedDirectory(this.assetsPath, this.root)\n await this.ensureManagedDirectory(this.setsPath, this.root)\n await this.ensureManagedDirectory(this.mockupBundlesPath, this.root)\n await rm(this.mockupImportsPath, { recursive: true, force: true })\n await this.ensureManagedDirectory(this.mockupImportsPath, this.mockupBundlesPath)\n for (const category of ASSET_CATEGORIES) {\n await this.ensureManagedDirectory(path.join(this.assetsPath, category), this.assetsPath)\n }\n\n try {\n await access(this.configPath, constants.F_OK)\n } catch {\n await this.writeConfig({\n version: 1,\n appName: path.basename(this.root),\n platforms: [\"ios\"],\n })\n }\n }\n\n async readProject(): Promise<StoreShotProject> {\n const [config, assets, sets] = await Promise.all([this.readConfig(), this.listAssets(), this.listSets()])\n return { directory: this.root, config, assets, sets }\n }\n\n async readConfig(): Promise<StoreShotConfig> {\n const value: unknown = JSON.parse(await this.readManagedFile(this.configPath, this.root, \"utf8\"))\n return parseConfig(value)\n }\n\n async writeConfig(config: StoreShotConfig): Promise<StoreShotConfig> {\n const value = parseConfig(config)\n await this.runExclusive(this.configPath, async () => {\n await this.assertSafeWriteTarget(this.configPath, this.root)\n await writeJson(this.configPath, value)\n })\n return value\n }\n\n async listAssets(): Promise<Record<AssetCategory, Asset[]>> {\n const entries = await Promise.all(\n ASSET_CATEGORIES.map(async (category) => [category, await this.listAssetsInCategory(category)] as const),\n )\n return Object.fromEntries(entries) as Record<AssetCategory, Asset[]>\n }\n\n async deleteAsset(category: AssetCategory, filename: string): Promise<void> {\n const target = await this.resolveExistingAsset(category, filename)\n await this.runExclusive(target, async () => unlink(target))\n this.assetHashes.delete(target)\n await this.updateAssetMetadataFile((metadata) => {\n delete metadata[`${category}/${filename}`]\n })\n }\n\n async updateAssetMetadata(category: AssetCategory, filename: string, input: UpdateAssetMetadataInput): Promise<void> {\n await this.resolveExistingAsset(category, filename)\n if (category !== \"screenshots\") throw new Error(\"Device type can only be set for raw screenshots\")\n const deviceType = input.deviceType\n if (deviceType !== null && !SCREENSHOT_DEVICE_TYPES.includes(deviceType)) throw new Error(\"Unsupported screenshot device type\")\n await this.updateAssetMetadataFile((metadata) => {\n const id = `${category}/${filename}`\n if (deviceType === null) delete metadata[id]\n else metadata[id] = { deviceType }\n })\n }\n\n async addAsset(category: string, filename: string, contents: Buffer): Promise<{ replaced: boolean }> {\n const target = this.resolveAsset(category, filename)\n assertValidImage(filename, contents)\n return this.runExclusive(\"asset-catalog\", async () => {\n await this.assertSafeWriteTarget(target, path.dirname(target))\n const incomingHash = hash(contents)\n const replaced = await access(target, constants.F_OK).then(() => true).catch(() => false)\n\n for (const assetCategory of ASSET_CATEGORIES) {\n const directory = path.join(this.assetsPath, assetCategory)\n const entries = await readdir(directory, { withFileTypes: true })\n for (const entry of entries) {\n if (!entry.isFile() || !supportedExtensions.has(path.extname(entry.name).toLowerCase())) continue\n const existingPath = path.join(directory, entry.name)\n if (existingPath === target) continue\n if (await this.hashAsset(existingPath, directory) === incomingHash) {\n throw new DuplicateAssetError(`${assetCategory}/${entry.name}`)\n }\n }\n }\n\n await writeFileAtomically(target, contents)\n const metadata = await stat(target)\n this.assetHashes.set(target, { hash: incomingHash, mtimeMs: metadata.mtimeMs, size: metadata.size })\n return { replaced }\n })\n }\n\n resolveAsset(category: string, filename: string): string {\n if (!isAssetCategory(category)) throw new Error(\"Unsupported asset category\")\n\n const safeName = path.basename(filename)\n const extension = path.extname(safeName).toLowerCase()\n if (safeName !== filename || !supportedExtensions.has(extension)) {\n throw new Error(\"Unsupported asset filename\")\n }\n\n return path.join(this.assetsPath, category, safeName)\n }\n\n async resolveExistingAsset(category: string, filename: string): Promise<string> {\n const target = this.resolveAsset(category, filename)\n await this.assertRegularFile(target)\n const resolved = await realpath(target)\n await this.assertContained(resolved, path.join(this.assetsPath, category))\n return resolved\n }\n\n async listSets(): Promise<ScreenshotSet[]> {\n const entries = await readdir(this.setsPath, { withFileTypes: true })\n const sets = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && path.extname(entry.name) === \".json\")\n .map(async (entry) => parseSet(JSON.parse(await this.readManagedFile(path.join(this.setsPath, entry.name), this.setsPath, \"utf8\")))),\n )\n return sets.sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n async createSet(input: CreateSetInput): Promise<ScreenshotSet> {\n const value = parseCreateSetInput(input)\n const now = new Date().toISOString()\n const id = `${slugify(value.name)}-${randomUUID().slice(0, 8)}`\n const areaId = `area-${randomUUID()}`\n const set: ScreenshotSet = {\n version: 1,\n id,\n name: value.name,\n locale: value.locale,\n device: value.device,\n canvas: { width: value.width, height: value.height },\n areas: [\n {\n id: areaId,\n name: \"Screenshot 1\",\n background: \"#245f4a\",\n elements: [\n {\n id: `element-${randomUUID()}`,\n type: \"text\",\n text: \"Your headline\",\n x: Math.round(value.width * 0.08),\n y: Math.round(value.height * 0.07),\n width: Math.round(value.width * 0.84),\n height: Math.round(value.height * 0.2),\n rotation: 0,\n opacity: 1,\n fontFamily: \"Geist Variable\",\n fontSize: Math.max(48, Math.round(value.width * 0.09)),\n fontWeight: 700,\n color: \"#ffffff\",\n textAlign: \"center\",\n },\n ],\n },\n ],\n createdAt: now,\n updatedAt: now,\n }\n const target = this.resolveSet(id)\n await this.runExclusive(target, async () => {\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, set)\n })\n return set\n }\n\n async duplicateSet(id: string): Promise<ScreenshotSet> {\n const source = await this.readSet(id)\n const existingSets = await this.listSets()\n const name = duplicateName(source.name, existingSets.map((set) => set.name))\n const now = new Date().toISOString()\n const duplicate: ScreenshotSet = {\n ...structuredClone(source),\n id: `${slugify(name)}-${randomUUID().slice(0, 8)}`,\n name,\n areas: source.areas.map((area) => cloneScreenshotArea(area, { idFactory: randomUUID })),\n createdAt: now,\n updatedAt: now,\n }\n const target = this.resolveSet(duplicate.id)\n await this.runExclusive(target, async () => {\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, duplicate)\n })\n return duplicate\n }\n\n async writeSet(id: string, set: ScreenshotSet): Promise<ScreenshotSet> {\n if (id !== set.id) throw new Error(\"Set id cannot be changed\")\n const target = this.resolveSet(id)\n return this.runExclusive(target, async () => {\n const value = parseSet({ ...set, updatedAt: new Date().toISOString() })\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, value)\n return value\n })\n }\n\n async updateSetMetadata(id: string, input: UpdateSetMetadataInput): Promise<ScreenshotSet> {\n const metadata = parseSetMetadataInput(input)\n const target = this.resolveSet(id)\n return this.runExclusive(target, async () => {\n const current = parseSet(JSON.parse(await this.readManagedFile(target, this.setsPath, \"utf8\")))\n const value = parseSet({ ...current, ...metadata, updatedAt: new Date().toISOString() })\n await writeJson(target, value)\n return value\n })\n }\n\n async deleteSet(id: string): Promise<void> {\n const target = this.resolveSet(id)\n await this.runExclusive(target, async () => {\n await this.assertRegularFile(target)\n await unlink(target)\n })\n }\n\n async listMockupCatalog(): Promise<DeviceMockupCatalog> {\n const entries = await readdir(this.mockupBundlesPath, { withFileTypes: true })\n const catalogs = (await Promise.all(entries\n .filter((entry) => entry.isDirectory() && safeIdentifierPattern.test(entry.name))\n .map(async (entry) => {\n const manifestPath = path.join(this.mockupBundlesPath, entry.name, MOCKUP_BUNDLE_FILENAME)\n let contents: string\n try {\n contents = await this.readManagedFile(manifestPath, path.dirname(manifestPath), \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined\n throw error\n }\n const manifest = parseMockupBundleManifest(JSON.parse(contents))\n if (manifest.id !== entry.name) throw new Error(`Mockup bundle folder ${entry.name} does not match manifest id ${manifest.id}`)\n return resolveMockupBundle(\n manifest,\n `/api/mockup-bundle-files/${encodeURIComponent(manifest.id)}/`,\n \"project\",\n )\n }))).filter((catalog): catalog is DeviceMockupCatalog => catalog !== undefined)\n return catalogs.length > 0 ? mergeDeviceMockupCatalogs(...catalogs) : emptyDeviceMockupCatalog()\n }\n\n async writeMockupBundleManifest(bundleId: string, input: unknown): Promise<MockupBundleManifest> {\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const manifest = parseMockupBundleManifest(input)\n if (manifest.id !== bundleId) throw new Error(\"Mockup bundle id cannot be changed\")\n const bundleDirectory = path.join(this.mockupBundlesPath, bundleId)\n await this.ensureManagedDirectory(bundleDirectory, this.mockupBundlesPath)\n await Promise.all(bundleAssetPaths(manifest).map(async (relativePath) => {\n await this.resolveExistingMockupBundleFile(bundleId, relativePath)\n }))\n const manifestPath = path.join(bundleDirectory, MOCKUP_BUNDLE_FILENAME)\n await this.runExclusive(manifestPath, async () => writeJson(manifestPath, manifest))\n return manifest\n }\n\n async writeMockupBundleFile(bundleId: string, relativePath: string, contents: Buffer): Promise<void> {\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const target = this.resolveMockupBundleFile(bundleId, relativePath)\n if (isImageFile(relativePath)) assertValidImage(relativePath, contents)\n await this.ensureManagedDirectory(path.dirname(target), this.mockupBundlesPath)\n await this.assertSafeWriteTarget(target, path.dirname(target))\n await this.runExclusive(target, async () => writeFileAtomically(target, contents))\n }\n\n async writeMockupBundleImportFile(importId: string, bundleId: string, relativePath: string, contents: Buffer): Promise<void> {\n this.assertMockupImportId(importId)\n this.resolveMockupBundleFile(bundleId, relativePath)\n if (isImageFile(relativePath)) assertValidImage(relativePath, contents)\n const bundleDirectory = path.join(this.mockupImportsPath, importId, bundleId)\n const target = path.resolve(bundleDirectory, relativePath)\n if (!target.startsWith(`${bundleDirectory}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the import\")\n await this.ensureManagedDirectory(path.dirname(target), this.mockupImportsPath)\n await this.assertSafeWriteTarget(target, path.dirname(target))\n await this.runExclusive(target, async () => writeFileAtomically(target, contents))\n }\n\n async commitMockupBundleImport(importId: string, bundleId: string, input: unknown): Promise<MockupBundleManifest> {\n this.assertMockupImportId(importId)\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const manifest = parseMockupBundleManifest(input)\n if (manifest.id !== bundleId) throw new Error(\"Mockup bundle id cannot be changed\")\n\n const importDirectory = path.join(this.mockupImportsPath, importId)\n const stagedBundle = path.join(importDirectory, bundleId)\n await this.assertManagedDirectory(stagedBundle)\n await Promise.all(bundleAssetPaths(manifest).map(async (relativePath) => {\n const target = path.resolve(stagedBundle, relativePath)\n if (!target.startsWith(`${stagedBundle}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the import\")\n await this.readManagedFile(target, stagedBundle)\n }))\n await writeJson(path.join(stagedBundle, MOCKUP_BUNDLE_FILENAME), manifest)\n\n const finalBundle = path.join(this.mockupBundlesPath, bundleId)\n const backupBundle = path.join(this.mockupBundlesPath, `.${bundleId}.${randomUUID()}.backup`)\n await this.runExclusive(`mockup-bundle:${bundleId}`, async () => {\n let hasBackup = false\n try {\n const metadata = await lstat(finalBundle)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new Error(\"Mockup bundle must be a regular directory\")\n await rename(finalBundle, backupBundle)\n hasBackup = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n\n try {\n await rename(stagedBundle, finalBundle)\n } catch (error) {\n if (hasBackup) await rename(backupBundle, finalBundle)\n throw error\n }\n if (hasBackup) await rm(backupBundle, { recursive: true, force: true }).catch(() => undefined)\n await rm(importDirectory, { recursive: true, force: true }).catch(() => undefined)\n })\n return manifest\n }\n\n async discardMockupBundleImport(importId: string): Promise<void> {\n this.assertMockupImportId(importId)\n const target = path.join(this.mockupImportsPath, importId)\n const relative = path.relative(this.mockupImportsPath, target)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"Mockup import is outside the project boundary\")\n await rm(target, { recursive: true, force: true })\n }\n\n resolveMockupBundleFile(bundleId: string, relativePath: string): string {\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (!isSafeBundlePath(relativePath) || relativePath === MOCKUP_BUNDLE_FILENAME) {\n throw new Error(\"Unsupported mockup bundle file path\")\n }\n const extension = path.extname(relativePath).toLowerCase()\n if (path.basename(relativePath) !== \"LICENSE\" && !supportedMockupBundleExtensions.has(extension)) {\n throw new Error(\"Unsupported mockup bundle file type\")\n }\n const bundleRoot = path.join(this.mockupBundlesPath, bundleId)\n const target = path.resolve(bundleRoot, relativePath)\n if (!target.startsWith(`${bundleRoot}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the bundle\")\n return target\n }\n\n async resolveExistingMockupBundleFile(bundleId: string, relativePath: string): Promise<string> {\n const bundleRoot = await realpath(path.join(this.mockupBundlesPath, bundleId))\n await this.assertContained(bundleRoot, this.mockupBundlesPath)\n await this.assertRegularFile(this.resolveMockupBundleFile(bundleId, relativePath))\n const target = await realpath(this.resolveMockupBundleFile(bundleId, relativePath))\n if (!target.startsWith(`${bundleRoot}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the bundle\")\n return target\n }\n\n private async listAssetsInCategory(category: AssetCategory): Promise<Asset[]> {\n const directory = path.join(this.assetsPath, category)\n const entries = await readdir(directory, { withFileTypes: true })\n const files = entries\n .filter((entry) => entry.isFile() && supportedExtensions.has(path.extname(entry.name).toLowerCase()))\n .sort((a, b) => a.name.localeCompare(b.name))\n\n const assetMetadata = await this.readAssetMetadata()\n return Promise.all(\n files.map(async (file) => {\n const filename = path.join(directory, file.name)\n const [metadata, contents] = await Promise.all([stat(filename), this.readManagedFile(filename, directory)])\n const dimensions = readImageMetadata(contents)\n const detectedDeviceType = category === \"screenshots\" && dimensions\n ? detectScreenshotDeviceType(dimensions.width, dimensions.height)\n : undefined\n const deviceTypeOverride = assetMetadata[`${category}/${file.name}`]?.deviceType\n return {\n id: `${category}/${file.name}`,\n category,\n name: file.name,\n url: `/api/assets/${category}/${encodeURIComponent(file.name)}?v=${Math.trunc(metadata.mtimeMs)}`,\n size: metadata.size,\n modifiedAt: metadata.mtime.toISOString(),\n ...(dimensions ?? {}),\n ...(detectedDeviceType ? {\n detectedDeviceType,\n deviceTypeOverride,\n deviceType: deviceTypeOverride ?? detectedDeviceType,\n } : {}),\n }\n }),\n )\n }\n\n private async readAssetMetadata(): Promise<AssetMetadata> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n try {\n const value: unknown = JSON.parse(await this.readManagedFile(target, this.assetsPath, \"utf8\"))\n if (!isRecord(value) || value.version !== 1 || !isRecord(value.assets)) return {}\n return Object.fromEntries(Object.entries(value.assets).flatMap(([id, entry]) => {\n if (!isRecord(entry) || !SCREENSHOT_DEVICE_TYPES.includes(entry.deviceType as ScreenshotDeviceType)) return []\n return [[id, { deviceType: entry.deviceType as ScreenshotDeviceType }]]\n }))\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {}\n throw error\n }\n }\n\n private async writeAssetMetadata(assets: AssetMetadata): Promise<void> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n await this.assertSafeWriteTarget(target, this.assetsPath)\n await writeJson(target, { version: 1, assets })\n }\n\n private async updateAssetMetadataFile(update: (metadata: AssetMetadata) => void): Promise<void> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n await this.runExclusive(target, async () => {\n const metadata = await this.readAssetMetadata()\n update(metadata)\n await this.writeAssetMetadata(metadata)\n })\n }\n\n private async hashAsset(filename: string, boundary: string): Promise<string> {\n const metadata = await stat(filename)\n const cached = this.assetHashes.get(filename)\n if (cached && cached.mtimeMs === metadata.mtimeMs && cached.size === metadata.size) return cached.hash\n const value = hash(await this.readManagedFile(filename, boundary))\n this.assetHashes.set(filename, { hash: value, mtimeMs: metadata.mtimeMs, size: metadata.size })\n return value\n }\n\n private async readSet(id: string): Promise<ScreenshotSet> {\n const target = this.resolveSet(id)\n return parseSet(JSON.parse(await this.readManagedFile(target, this.setsPath, \"utf8\")))\n }\n\n private async runExclusive<T>(key: string, operation: () => Promise<T>): Promise<T> {\n const previous = this.operations.get(key) ?? Promise.resolve()\n const result = previous.catch(() => undefined).then(operation)\n const tail = result.then(() => undefined, () => undefined)\n this.operations.set(key, tail)\n try {\n return await result\n } finally {\n if (this.operations.get(key) === tail) this.operations.delete(key)\n }\n }\n\n private async assertManagedDirectory(directory: string): Promise<void> {\n const metadata = await lstat(directory)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) {\n throw new Error(`${path.relative(this.root, directory) || \".\"} must be a regular project directory`)\n }\n await this.assertContained(await realpath(directory), this.root, true)\n }\n\n private async ensureManagedDirectory(directory: string, boundary: string): Promise<void> {\n await this.assertManagedDirectory(boundary)\n const relative = path.relative(boundary, directory)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"Directory is outside the project boundary\")\n let current = boundary\n for (const segment of relative.split(path.sep).filter(Boolean)) {\n current = path.join(current, segment)\n try {\n await mkdir(current)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error\n }\n const metadata = await lstat(current)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new Error(\"Project directories cannot be symbolic links\")\n }\n await this.assertContained(await realpath(directory), boundary, true)\n }\n\n private async assertSafeWriteTarget(target: string, boundary: string): Promise<void> {\n await this.assertManagedDirectory(boundary)\n const relative = path.relative(boundary, target)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"File is outside the project boundary\")\n try {\n const metadata = await lstat(target)\n if (metadata.isSymbolicLink() || !metadata.isFile()) throw new Error(\"Project files must be regular files\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n }\n\n private async readManagedFile(filename: string, boundary: string): Promise<Buffer>\n private async readManagedFile(filename: string, boundary: string, encoding: BufferEncoding): Promise<string>\n private async readManagedFile(filename: string, boundary: string, encoding?: BufferEncoding): Promise<Buffer | string> {\n await this.assertRegularFile(filename)\n await this.assertContained(await realpath(filename), boundary)\n return encoding ? readFile(filename, encoding) : readFile(filename)\n }\n\n private async assertRegularFile(filename: string): Promise<void> {\n const metadata = await lstat(filename)\n if (!metadata.isFile() || metadata.isSymbolicLink()) throw new Error(\"Project files must be regular files\")\n }\n\n private async assertContained(candidate: string, boundary: string, allowEqual = false): Promise<void> {\n const resolvedBoundary = await realpath(boundary)\n if ((allowEqual && candidate === resolvedBoundary) || candidate.startsWith(`${resolvedBoundary}${path.sep}`)) return\n throw new Error(\"File is outside the project boundary\")\n }\n\n private assertMockupImportId(importId: string): void {\n if (!safeIdentifierPattern.test(importId)) throw new Error(\"Unsupported mockup import id\")\n }\n\n private resolveSet(id: string): string {\n if (!safeIdentifierPattern.test(id)) throw new Error(\"Unsupported set id\")\n return path.join(this.setsPath, `${id}.json`)\n }\n}\n\ntype AssetMetadata = Record<string, { deviceType: ScreenshotDeviceType }>\n\nexport class DuplicateAssetError extends Error {\n constructor(readonly existingAssetId: string) {\n super(`This file is already in the asset catalog as ${existingAssetId}`)\n }\n}\n\nfunction hash(contents: Buffer): string {\n return createHash(\"sha256\").update(contents).digest(\"hex\")\n}\n\nfunction parseConfig(value: unknown): StoreShotConfig {\n if (!isRecord(value)) throw new Error(\"storeshot.json must contain a JSON object\")\n\n const appName = readString(value.appName, \"appName\")\n const platforms = Array.isArray(value.platforms)\n ? value.platforms.filter((platform): platform is \"ios\" | \"android\" => platform === \"ios\" || platform === \"android\")\n : []\n if (platforms.length === 0) throw new Error(\"platforms must include ios or android\")\n\n return { version: 1, appName, platforms: [...new Set(platforms)] }\n}\n\nfunction parseCreateSetInput(value: unknown): CreateSetInput {\n if (!isRecord(value)) throw new Error(\"Set details must be an object\")\n return {\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n width: readDimension(value.width, \"Canvas width\"),\n height: readDimension(value.height, \"Canvas height\"),\n }\n}\n\nfunction duplicateName(sourceName: string, existingNames: string[]): string {\n const names = new Set(existingNames.map((name) => name.toLocaleLowerCase()))\n const baseName = `${sourceName} copy`\n if (!names.has(baseName.toLocaleLowerCase())) return baseName\n\n let copyNumber = 2\n while (names.has(`${baseName} ${copyNumber}`.toLocaleLowerCase())) copyNumber += 1\n return `${baseName} ${copyNumber}`\n}\n\nfunction parseSetMetadataInput(value: unknown): UpdateSetMetadataInput {\n if (!isRecord(value)) throw new Error(\"Set settings must be an object\")\n return {\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n }\n}\n\nfunction parseSet(value: unknown): ScreenshotSet {\n if (!isRecord(value)) throw new Error(\"Set file must contain an object\")\n\n const id = readString(value.id, \"Set id\")\n if (!safeIdentifierPattern.test(id)) throw new Error(\"Set id is invalid\")\n if (!isRecord(value.canvas)) throw new Error(\"Set canvas is invalid\")\n if (!Array.isArray(value.areas) || value.areas.length === 0) throw new Error(\"A set needs at least one screenshot area\")\n\n return {\n version: 1,\n id,\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n canvas: {\n width: readDimension(value.canvas.width, \"Canvas width\"),\n height: readDimension(value.canvas.height, \"Canvas height\"),\n },\n areas: value.areas.map(parseArea),\n createdAt: readString(value.createdAt, \"Created time\"),\n updatedAt: readString(value.updatedAt, \"Updated time\"),\n }\n}\n\nfunction parseArea(value: unknown): ScreenshotArea {\n if (!isRecord(value)) throw new Error(\"Screenshot area is invalid\")\n const background = readString(value.background, \"Area background\")\n if (!hexColorPattern.test(background)) throw new Error(\"Area background must be a hex color\")\n if (!Array.isArray(value.elements)) throw new Error(\"Area elements must be an array\")\n return {\n id: readString(value.id, \"Area id\"),\n name: readString(value.name, \"Area name\"),\n background,\n elements: value.elements.map(parseElement),\n }\n}\n\nfunction parseImageSource(value: unknown, legacyAssetId?: unknown): ImageElementSource {\n if (isRecord(value)) {\n if (value.kind === \"builtin\") return { kind: \"builtin\", id: readString(value.id, \"Built-in artwork id\") }\n if (value.kind === \"asset\") return { kind: \"asset\", assetId: readString(value.assetId, \"Asset id\") }\n throw new Error(\"Image source type is invalid\")\n }\n if (legacyAssetId !== undefined) return { kind: \"asset\", assetId: readString(legacyAssetId, \"Asset id\") }\n throw new Error(\"Image source is invalid\")\n}\n\nfunction parseElement(value: unknown): CanvasElement {\n if (!isRecord(value)) throw new Error(\"Canvas element is invalid\")\n const base = {\n id: readString(value.id, \"Element id\"),\n x: readNumber(value.x, \"Element x\"),\n y: readNumber(value.y, \"Element y\"),\n width: readDimension(value.width, \"Element width\"),\n height: readDimension(value.height, \"Element height\"),\n rotation: readNumber(value.rotation, \"Element rotation\"),\n opacity: readOptionalRange(value.opacity, 1, 0, 1, \"Element opacity\"),\n }\n\n if (value.type === \"image\") {\n if (value.fit !== \"contain\" && value.fit !== \"cover\") throw new Error(\"Image fit is invalid\")\n const source = parseImageSource(value.source, value.assetId)\n const fill = value.fill === undefined ? undefined : readString(value.fill, \"Image fill\")\n if (fill !== undefined && !hexColorPattern.test(fill)) throw new Error(\"Image fill must be a hex color\")\n return { ...base, type: \"image\", source, fit: value.fit, ...(fill === undefined ? {} : { fill }) }\n }\n\n if (value.type === \"mockup\") {\n return {\n ...base,\n type: \"mockup\",\n mockupId: readString(value.mockupId, \"Device mockup id\"),\n assetId: readString(value.assetId, \"Asset id\"),\n }\n }\n\n if (value.type === \"element\") {\n const source = parseImageSource(value.source)\n const fill = value.fill === undefined ? undefined : readString(value.fill, \"Image fill\")\n if (fill !== undefined && !hexColorPattern.test(fill)) throw new Error(\"Image fill must be a hex color\")\n return {\n ...base,\n type: \"image\",\n source,\n fit: \"contain\",\n ...(fill === undefined ? {} : { fill }),\n }\n }\n\n if (value.type === \"text\") {\n const fontWeight = Number(value.fontWeight)\n if (!Number.isInteger(fontWeight) || fontWeight < 100 || fontWeight > 900 || fontWeight % 100 !== 0) {\n throw new Error(\"Text weight is invalid\")\n }\n if (value.textAlign !== \"left\" && value.textAlign !== \"center\" && value.textAlign !== \"right\") {\n throw new Error(\"Text alignment is invalid\")\n }\n const color = readString(value.color, \"Text color\")\n if (!hexColorPattern.test(color)) throw new Error(\"Text color must be a hex color\")\n const lineHeight = value.lineHeight === undefined\n ? undefined\n : readDimension(value.lineHeight, \"Text line height\")\n return {\n ...base,\n type: \"text\",\n text: typeof value.text === \"string\" ? value.text : \"\",\n fontFamily: readOptionalString(value.fontFamily, \"Geist Variable\"),\n fontSize: readDimension(value.fontSize, \"Font size\"),\n fontWeight: fontWeight as FontWeight,\n ...(lineHeight === undefined ? {} : { lineHeight }),\n color,\n textAlign: value.textAlign,\n }\n }\n\n if (value.type === \"shape\") {\n if (value.shape !== \"rectangle\") throw new Error(\"Shape type is invalid\")\n const fill = readString(value.fill, \"Shape fill\")\n if (!hexColorPattern.test(fill)) throw new Error(\"Shape fill must be a hex color\")\n return {\n ...base,\n type: \"shape\",\n shape: value.shape,\n fill,\n cornerRadius: readOptionalRange(value.cornerRadius, 0, 0, 10_000, \"Shape corner radius\"),\n }\n }\n\n throw new Error(\"Unsupported canvas element type\")\n}\n\nfunction readString(value: unknown, name: string): string {\n const result = typeof value === \"string\" ? value.trim() : \"\"\n if (!result) throw new Error(`${name} must be a non-empty string`)\n return result\n}\n\nfunction readNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${name} must be a number`)\n return value\n}\n\nfunction readOptionalRange(value: unknown, fallback: number, min: number, max: number, name: string): number {\n if (value === undefined) return fallback\n const result = readNumber(value, name)\n if (result < min || result > max) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction readOptionalString(value: unknown, fallback: string): string {\n return typeof value === \"string\" && value.trim() ? value.trim() : fallback\n}\n\nfunction readDimension(value: unknown, name: string): number {\n const result = readNumber(value, name)\n if (result <= 0 || result > 20_000) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction isAssetCategory(value: string): value is AssetCategory {\n return ASSET_CATEGORIES.includes(value as AssetCategory)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction slugify(value: string): string {\n const result = value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n return result || \"set\"\n}\n\nasync function writeJson(filename: string, value: unknown): Promise<void> {\n await writeFileAtomically(filename, `${JSON.stringify(value, null, 2)}\\n`)\n}\n\nasync function writeFileAtomically(filename: string, contents: Buffer | string): Promise<void> {\n const temporary = path.join(path.dirname(filename), `.${path.basename(filename)}.${randomUUID()}.tmp`)\n try {\n await writeFile(temporary, contents, { flag: \"wx\" })\n await rename(temporary, filename)\n } finally {\n await unlink(temporary).catch((error: NodeJS.ErrnoException) => {\n if (error.code !== \"ENOENT\") throw error\n })\n }\n}\n\nfunction isImageFile(filename: string): boolean {\n return supportedExtensions.has(path.extname(filename).toLowerCase())\n}\n\nfunction assertValidImage(filename: string, contents: Buffer): void {\n if (!isImageFile(filename) || !readImageMetadata(contents)) throw new Error(\"The uploaded file is not a valid supported image\")\n}\n","export const MOCKUP_BUNDLE_FILENAME = \"storeshot-mockups.json\"\nexport const MOCKUP_BUNDLE_FORMAT = \"storeshot-mockup-bundle\"\n\nexport interface Point {\n x: number\n y: number\n}\n\nexport type DevicePlatform = \"iphone\" | \"ipad\" | \"mac\" | \"watch\"\nexport type DeviceMockupStyle =\n | \"3d\"\n | \"colored\"\n | \"colored-3d\"\n | \"handheld\"\n | \"handheld-dim\"\n | \"handheld-silhouette\"\n | \"handheld-styles\"\n | \"standard\"\n | \"textured\"\n\nexport type ProjectiveTransform = readonly [\n readonly [number, number, number],\n readonly [number, number, number],\n readonly [number, number, number],\n]\n\nexport interface RectMockupScreen {\n kind: \"rect\"\n x: number\n y: number\n width: number\n height: number\n cornerRadius: number\n}\n\nexport interface PerspectiveMockupScreen {\n kind: \"projective\"\n /** Maps normalized screenshot coordinates into normalized frame coordinates. */\n transform: ProjectiveTransform\n /** Elliptical source-image corner radius, normalized to the screenshot plane. */\n sourceCornerRadius: Point\n}\n\nexport type MockupScreen = PerspectiveMockupScreen | RectMockupScreen\n\nexport interface MockupBundleLicense {\n name: string\n url?: string\n file?: string\n}\n\nexport interface MockupBundleSource {\n name?: string\n url: string\n revision?: string\n}\n\n/** Portable, folder-based StoreShot device mockup definition. */\nexport interface MockupBundleEntry {\n id: string\n groupId: string\n groupName: string\n name: string\n description: string\n platform: DevicePlatform\n style: DeviceMockupStyle\n frame: string\n thumbnail?: string\n width: number\n height: number\n screen: MockupScreen\n}\n\nexport interface MockupBundleManifest {\n format: typeof MOCKUP_BUNDLE_FORMAT\n version: 1\n id: string\n name: string\n author: string\n license: MockupBundleLicense\n source?: MockupBundleSource\n mockups: MockupBundleEntry[]\n}\n\ninterface DeviceMockupBase {\n id: string\n bundleId: string\n groupId: string\n name: string\n description: string\n platform: DevicePlatform\n style: DeviceMockupStyle\n frameUrl: string\n thumbnailUrl: string\n width: number\n height: number\n}\n\nexport interface DeviceMockup extends DeviceMockupBase {\n screen: MockupScreen\n}\n\nexport interface DeviceMockupGroup {\n id: string\n bundleId: string\n name: string\n platform: DevicePlatform\n style: DeviceMockupStyle\n thumbnailUrl: string\n count: number\n}\n\nexport interface MockupBundleSummary {\n id: string\n name: string\n author: string\n license: MockupBundleLicense\n source?: MockupBundleSource\n mockupCount: number\n origin: \"built-in\" | \"project\"\n}\n\nexport interface DeviceMockupCatalog {\n bundles: MockupBundleSummary[]\n groups: DeviceMockupGroup[]\n mockups: DeviceMockup[]\n}\n\nconst identifierPattern = /^[a-z0-9][a-z0-9-]*$/\nconst styles = new Set<DeviceMockupStyle>([\n \"3d\",\n \"colored\",\n \"colored-3d\",\n \"handheld\",\n \"handheld-dim\",\n \"handheld-silhouette\",\n \"handheld-styles\",\n \"standard\",\n \"textured\",\n])\nconst platforms = new Set<DevicePlatform>([\"iphone\", \"ipad\", \"mac\", \"watch\"])\nconst frameExtensions = new Set([\".jpeg\", \".jpg\", \".png\", \".svg\", \".webp\"])\n\nexport function emptyDeviceMockupCatalog(): DeviceMockupCatalog {\n return { bundles: [], groups: [], mockups: [] }\n}\n\nexport function parseMockupBundleManifest(value: unknown): MockupBundleManifest {\n if (!isRecord(value)) throw new Error(`${MOCKUP_BUNDLE_FILENAME} must contain a JSON object`)\n if (value.format !== MOCKUP_BUNDLE_FORMAT || value.version !== 1) {\n throw new Error(\"Unsupported StoreShot mockup bundle format\")\n }\n if (!Array.isArray(value.mockups) || value.mockups.length === 0) {\n throw new Error(\"A mockup bundle must contain at least one mockup\")\n }\n\n const id = readIdentifier(value.id, \"Bundle id\")\n const mockups = value.mockups.map(parseMockupEntry)\n const entryIds = new Set<string>()\n for (const mockup of mockups) {\n if (entryIds.has(mockup.id)) throw new Error(`Duplicate mockup id: ${mockup.id}`)\n entryIds.add(mockup.id)\n }\n\n return {\n format: MOCKUP_BUNDLE_FORMAT,\n version: 1,\n id,\n name: readString(value.name, \"Bundle name\"),\n author: readString(value.author, \"Bundle author\"),\n license: parseLicense(value.license),\n ...(value.source === undefined ? {} : { source: parseSource(value.source) }),\n mockups,\n }\n}\n\nexport function resolveMockupBundle(\n manifest: MockupBundleManifest,\n baseUrl: string,\n origin: MockupBundleSummary[\"origin\"],\n): DeviceMockupCatalog {\n const bundlePrefix = `${manifest.id}/`\n const mockups: DeviceMockup[] = manifest.mockups.map((entry) => ({\n ...entry,\n id: `${bundlePrefix}${entry.id}`,\n bundleId: manifest.id,\n groupId: `${bundlePrefix}${entry.groupId}`,\n frameUrl: `${baseUrl}${encodeBundlePath(entry.frame)}`,\n thumbnailUrl: `${baseUrl}${encodeBundlePath(entry.thumbnail ?? entry.frame)}`,\n }))\n\n const groupEntries = new Map<string, DeviceMockup[]>()\n for (const mockup of mockups) {\n const entries = groupEntries.get(mockup.groupId) ?? []\n entries.push(mockup)\n groupEntries.set(mockup.groupId, entries)\n }\n\n return {\n bundles: [{\n id: manifest.id,\n name: manifest.name,\n author: manifest.author,\n license: manifest.license,\n ...(manifest.source ? { source: manifest.source } : {}),\n mockupCount: mockups.length,\n origin,\n }],\n groups: [...groupEntries.entries()].map(([id, entries]) => ({\n id,\n bundleId: manifest.id,\n name: manifest.mockups.find((entry) => `${bundlePrefix}${entry.groupId}` === id)?.groupName ?? entries[0].name,\n platform: entries[0].platform,\n style: entries[0].style,\n thumbnailUrl: entries[0].thumbnailUrl,\n count: entries.length,\n })),\n mockups,\n }\n}\n\nexport function mergeDeviceMockupCatalogs(...catalogs: DeviceMockupCatalog[]): DeviceMockupCatalog {\n const result = emptyDeviceMockupCatalog()\n const bundleIds = new Set<string>()\n const groupIds = new Set<string>()\n const mockupIds = new Set<string>()\n\n for (const catalog of catalogs) {\n for (const bundle of catalog.bundles) {\n if (bundleIds.has(bundle.id)) continue\n bundleIds.add(bundle.id)\n result.bundles.push(bundle)\n }\n for (const group of catalog.groups) {\n if (groupIds.has(group.id)) continue\n groupIds.add(group.id)\n result.groups.push(group)\n }\n for (const mockup of catalog.mockups) {\n if (mockupIds.has(mockup.id)) continue\n mockupIds.add(mockup.id)\n result.mockups.push(mockup)\n }\n }\n return result\n}\n\nexport function deviceMockupById(catalog: DeviceMockupCatalog, id: string): DeviceMockup | undefined {\n return catalog.mockups.find((mockup) => mockup.id === id)\n}\n\nexport function bundleAssetPaths(manifest: MockupBundleManifest): string[] {\n const paths = new Set<string>()\n if (manifest.license.file) paths.add(manifest.license.file)\n for (const mockup of manifest.mockups) {\n paths.add(mockup.frame)\n if (mockup.thumbnail) paths.add(mockup.thumbnail)\n }\n return [...paths]\n}\n\nexport function isSafeBundlePath(value: string): boolean {\n if (!value || value.startsWith(\"/\") || value.includes(\"\\\\\")) return false\n const parts = value.split(\"/\")\n return parts.every((part) => part.length > 0 && part !== \".\" && part !== \"..\")\n}\n\nfunction parseMockupEntry(value: unknown): MockupBundleEntry {\n if (!isRecord(value)) throw new Error(\"Mockup entry must be an object\")\n const platform = readString(value.platform, \"Mockup platform\") as DevicePlatform\n const style = readString(value.style, \"Mockup style\") as DeviceMockupStyle\n if (!platforms.has(platform)) throw new Error(`Unsupported mockup platform: ${platform}`)\n if (!styles.has(style)) throw new Error(`Unsupported mockup style: ${style}`)\n const frame = readFramePath(value.frame, \"Mockup frame\")\n const thumbnail = value.thumbnail === undefined ? undefined : readFramePath(value.thumbnail, \"Mockup thumbnail\")\n return {\n id: readIdentifier(value.id, \"Mockup id\"),\n groupId: readIdentifier(value.groupId, \"Mockup group id\"),\n groupName: readString(value.groupName, \"Mockup group name\"),\n name: readString(value.name, \"Mockup name\"),\n description: readString(value.description, \"Mockup description\"),\n platform,\n style,\n frame,\n ...(thumbnail ? { thumbnail } : {}),\n width: readDimension(value.width, \"Mockup width\"),\n height: readDimension(value.height, \"Mockup height\"),\n screen: parseScreen(value.screen),\n }\n}\n\nfunction parseScreen(value: unknown): MockupScreen {\n if (!isRecord(value)) throw new Error(\"Mockup screen must be an object\")\n if (value.kind === \"rect\") {\n return {\n kind: \"rect\",\n x: readNumber(value.x, \"Screen x\"),\n y: readNumber(value.y, \"Screen y\"),\n width: readDimension(value.width, \"Screen width\"),\n height: readDimension(value.height, \"Screen height\"),\n cornerRadius: readNonNegative(value.cornerRadius, \"Screen corner radius\"),\n }\n }\n if (value.kind === \"projective\") {\n if (!Array.isArray(value.transform) || value.transform.length !== 3) throw new Error(\"Projective transform must have three rows\")\n const transform = value.transform.map((row) => {\n if (!Array.isArray(row) || row.length !== 3) throw new Error(\"Each projective transform row must have three numbers\")\n return row.map((entry) => readNumber(entry, \"Projective transform value\")) as [number, number, number]\n }) as [\n [number, number, number],\n [number, number, number],\n [number, number, number],\n ]\n if (!isRecord(value.sourceCornerRadius)) throw new Error(\"Projective source corner radius must be an object\")\n return {\n kind: \"projective\",\n transform,\n sourceCornerRadius: {\n x: readNonNegative(value.sourceCornerRadius.x, \"Source corner radius x\"),\n y: readNonNegative(value.sourceCornerRadius.y, \"Source corner radius y\"),\n },\n }\n }\n throw new Error(\"Unsupported mockup screen geometry\")\n}\n\nfunction parseLicense(value: unknown): MockupBundleLicense {\n if (!isRecord(value)) throw new Error(\"Bundle license must be an object\")\n const file = value.file === undefined ? undefined : readBundlePath(value.file, \"License file\")\n return {\n name: readString(value.name, \"License name\"),\n ...(value.url === undefined ? {} : { url: readString(value.url, \"License URL\") }),\n ...(file ? { file } : {}),\n }\n}\n\nfunction parseSource(value: unknown): MockupBundleSource {\n if (!isRecord(value)) throw new Error(\"Bundle source must be an object\")\n return {\n ...(value.name === undefined ? {} : { name: readString(value.name, \"Source name\") }),\n url: readString(value.url, \"Source URL\"),\n ...(value.revision === undefined ? {} : { revision: readString(value.revision, \"Source revision\") }),\n }\n}\n\nfunction readFramePath(value: unknown, name: string): string {\n const result = readBundlePath(value, name)\n const extensionIndex = result.lastIndexOf(\".\")\n const extension = extensionIndex >= 0 ? result.slice(extensionIndex).toLowerCase() : \"\"\n if (!frameExtensions.has(extension)) throw new Error(`${name} has an unsupported file type`)\n return result\n}\n\nfunction readBundlePath(value: unknown, name: string): string {\n const result = readString(value, name)\n if (!isSafeBundlePath(result)) throw new Error(`${name} must be a relative path inside the bundle`)\n return result\n}\n\nfunction readIdentifier(value: unknown, name: string): string {\n const result = readString(value, name)\n if (!identifierPattern.test(result)) throw new Error(`${name} must use lowercase letters, numbers, and hyphens`)\n return result\n}\n\nfunction readString(value: unknown, name: string): string {\n const result = typeof value === \"string\" ? value.trim() : \"\"\n if (!result) throw new Error(`${name} must be a non-empty string`)\n return result\n}\n\nfunction readNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${name} must be a number`)\n return value\n}\n\nfunction readDimension(value: unknown, name: string): number {\n const result = readNumber(value, name)\n if (result <= 0 || result > 20_000) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction readNonNegative(value: unknown, name: string): number {\n const result = readNumber(value, name)\n if (result < 0 || result > 20_000) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction encodeBundlePath(value: string): string {\n return value.split(\"/\").map(encodeURIComponent).join(\"/\")\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n","import type { DetectedScreenshotDeviceType } from \"./shared.js\"\n\nexport interface ImageMetadata {\n width: number\n height: number\n}\n\nexport function readImageMetadata(contents: Buffer): ImageMetadata | undefined {\n return readPngMetadata(contents) ?? readJpegMetadata(contents) ?? readWebpMetadata(contents) ?? readSvgMetadata(contents)\n}\n\nfunction readSvgMetadata(contents: Buffer): ImageMetadata | undefined {\n const source = contents.subarray(0, 64 * 1024).toString(\"utf8\")\n const svg = source.match(/<svg\\b[^>]*>/i)?.[0]\n if (!svg) return undefined\n\n const width = readSvgLength(svg, \"width\")\n const height = readSvgLength(svg, \"height\")\n if (width && height) return validDimensions(width, height)\n\n const viewBox = svg.match(/\\bviewBox\\s*=\\s*[\"']\\s*([-+\\d.e]+)[\\s,]+([-+\\d.e]+)[\\s,]+([-+\\d.e]+)[\\s,]+([-+\\d.e]+)\\s*[\"']/i)\n if (!viewBox) return undefined\n return validDimensions(Number(viewBox[3]), Number(viewBox[4]))\n}\n\nfunction readSvgLength(svg: string, attribute: \"height\" | \"width\"): number | undefined {\n const match = svg.match(new RegExp(`\\\\b${attribute}\\\\s*=\\\\s*[\"']\\\\s*([-+\\\\d.e]+)`, \"i\"))\n const value = match ? Number(match[1]) : NaN\n return Number.isFinite(value) && value > 0 ? value : undefined\n}\n\nexport function detectScreenshotDeviceType(width: number, height: number): DetectedScreenshotDeviceType {\n const shortSide = Math.min(width, height)\n const longSide = Math.max(width, height)\n const ratio = longSide / shortSide\n const dimensions = `${shortSide}x${longSide}`\n\n if (WATCH_SCREENSHOT_DIMENSIONS.has(dimensions)) return \"watch\"\n if (IPAD_SCREENSHOT_DIMENSIONS.has(dimensions)) return \"ipad\"\n if (IPHONE_SCREENSHOT_DIMENSIONS.has(dimensions) && (height > width || longSide >= 2_200)) return \"iphone\"\n if (longSide <= 700 && ratio <= 1.4) return \"watch\"\n if (shortSide >= 1_400 && ratio >= 1.25 && ratio <= 1.45) return \"ipad\"\n if (height > width && ratio >= 1.65) return \"iphone\"\n if (width > height && ratio >= 1.45) return \"mac\"\n if (shortSide >= 1_000 && ratio >= 1.25 && ratio <= 1.45) return \"ipad\"\n return \"unknown\"\n}\n\nconst IPHONE_SCREENSHOT_DIMENSIONS = new Set([\n \"640x1136\", \"750x1334\", \"828x1792\", \"1080x1920\", \"1125x2436\", \"1170x2532\",\n \"1179x2556\", \"1206x2622\", \"1242x2208\", \"1242x2688\", \"1284x2778\", \"1290x2796\", \"1320x2868\",\n])\nconst IPAD_SCREENSHOT_DIMENSIONS = new Set([\n \"1536x2048\", \"1668x2224\", \"1668x2388\", \"2048x2732\", \"2064x2752\",\n])\nconst WATCH_SCREENSHOT_DIMENSIONS = new Set([\n \"368x448\", \"396x484\", \"416x496\", \"422x514\",\n])\n\nfunction readPngMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 24 || contents.toString(\"ascii\", 1, 4) !== \"PNG\") return undefined\n return validDimensions(contents.readUInt32BE(16), contents.readUInt32BE(20))\n}\n\nfunction readJpegMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 4 || contents[0] !== 0xff || contents[1] !== 0xd8) return undefined\n let offset = 2\n while (offset + 8 < contents.length) {\n if (contents[offset] !== 0xff) {\n offset += 1\n continue\n }\n const marker = contents[offset + 1]\n offset += 2\n if (marker === 0xd8 || marker === 0xd9) continue\n if (offset + 2 > contents.length) return undefined\n const length = contents.readUInt16BE(offset)\n if (length < 2 || offset + length > contents.length) return undefined\n if (isJpegStartOfFrame(marker) && length >= 7) {\n return validDimensions(contents.readUInt16BE(offset + 5), contents.readUInt16BE(offset + 3))\n }\n offset += length\n }\n return undefined\n}\n\nfunction isJpegStartOfFrame(marker: number): boolean {\n return marker >= 0xc0 && marker <= 0xcf && ![0xc4, 0xc8, 0xcc].includes(marker)\n}\n\nfunction readWebpMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 30 || contents.toString(\"ascii\", 0, 4) !== \"RIFF\" || contents.toString(\"ascii\", 8, 12) !== \"WEBP\") return undefined\n const type = contents.toString(\"ascii\", 12, 16)\n if (type === \"VP8X\") {\n return validDimensions(readUInt24LE(contents, 24) + 1, readUInt24LE(contents, 27) + 1)\n }\n if (type === \"VP8 \" && contents.length >= 30 && contents[23] === 0x9d && contents[24] === 0x01 && contents[25] === 0x2a) {\n return validDimensions(contents.readUInt16LE(26) & 0x3fff, contents.readUInt16LE(28) & 0x3fff)\n }\n if (type === \"VP8L\" && contents.length >= 25 && contents[20] === 0x2f) {\n const bits = contents.readUInt32LE(21)\n return validDimensions((bits & 0x3fff) + 1, ((bits >>> 14) & 0x3fff) + 1)\n }\n return undefined\n}\n\nfunction readUInt24LE(contents: Buffer, offset: number): number {\n return contents[offset] | (contents[offset + 1] << 8) | (contents[offset + 2] << 16)\n}\n\nfunction validDimensions(width: number, height: number): ImageMetadata | undefined {\n return width > 0 && height > 0 ? { width, height } : undefined\n}\n","import type { CanvasElement, ScreenshotArea } from \"./shared.js\"\n\nexport type IdFactory = () => string\n\ninterface CloneElementOptions {\n idFactory?: IdFactory\n offsetX?: number\n offsetY?: number\n}\n\ninterface CloneAreaOptions {\n idFactory?: IdFactory\n name?: string\n}\n\nconst defaultIdFactory: IdFactory = () => globalThis.crypto.randomUUID()\n\nexport function cloneCanvasElement(\n element: CanvasElement,\n { idFactory = defaultIdFactory, offsetX = 0, offsetY = 0 }: CloneElementOptions = {},\n): CanvasElement {\n return {\n ...structuredClone(element),\n id: `element-${idFactory()}`,\n x: element.x + offsetX,\n y: element.y + offsetY,\n }\n}\n\nexport function cloneScreenshotArea(\n area: ScreenshotArea,\n { idFactory = defaultIdFactory, name = area.name }: CloneAreaOptions = {},\n): ScreenshotArea {\n return {\n ...structuredClone(area),\n id: `area-${idFactory()}`,\n name,\n elements: area.elements.map((element) => cloneCanvasElement(element, { idFactory })),\n }\n}\n","export const ASSET_CATEGORIES = [\"screenshots\", \"brand\", \"logos\", \"other\"] as const\n\nexport type AssetCategory = (typeof ASSET_CATEGORIES)[number]\n\nexport const SCREENSHOT_DEVICE_TYPES = [\"iphone\", \"ipad\", \"mac\", \"watch\"] as const\nexport type ScreenshotDeviceType = (typeof SCREENSHOT_DEVICE_TYPES)[number]\nexport type DetectedScreenshotDeviceType = ScreenshotDeviceType | \"unknown\"\n\nexport interface StoreShotConfig {\n version: 1\n appName: string\n platforms: Array<\"ios\" | \"android\">\n}\n\nexport interface Asset {\n id: string\n category: AssetCategory\n name: string\n url: string\n size: number\n modifiedAt: string\n width?: number\n height?: number\n /** The dimension-based classification before a user override is applied. */\n detectedDeviceType?: DetectedScreenshotDeviceType\n /** An explicit local catalog override. */\n deviceTypeOverride?: ScreenshotDeviceType\n /** The effective type used for mockup recommendations. */\n deviceType?: DetectedScreenshotDeviceType\n}\n\nexport interface UpdateAssetMetadataInput {\n deviceType: ScreenshotDeviceType | null\n}\n\ninterface CanvasElementBase {\n id: string\n x: number\n y: number\n width: number\n height: number\n rotation: number\n opacity: number\n}\n\nexport type ImageElementSource =\n | { kind: \"builtin\"; id: string }\n | { kind: \"asset\"; assetId: string }\n\n/** A project image or built-in vector artwork placed on a screenshot. */\nexport interface ImageElement extends CanvasElementBase {\n type: \"image\"\n source: ImageElementSource\n fit: \"contain\" | \"cover\"\n /** Replaces the visible pixels while preserving their alpha. Omit to use the source colors. */\n fill?: string\n}\n\nexport interface DeviceMockupElement extends CanvasElementBase {\n type: \"mockup\"\n mockupId: string\n assetId: string\n}\n\nexport type FontWeight = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900\nexport const DEFAULT_TEXT_LINE_HEIGHT_RATIO = 1.05\n\nexport interface TextElement extends CanvasElementBase {\n type: \"text\"\n text: string\n fontFamily: string\n fontSize: number\n fontWeight: FontWeight\n /** Absolute line height in canvas pixels. When omitted, the renderer derives it from the font size. */\n lineHeight?: number\n color: string\n textAlign: \"left\" | \"center\" | \"right\"\n}\n\nexport interface ShapeElement extends CanvasElementBase {\n type: \"shape\"\n shape: \"rectangle\"\n fill: string\n cornerRadius: number\n}\n\nexport type CanvasElement = DeviceMockupElement | ImageElement | ShapeElement | TextElement\n\nexport interface ScreenshotArea {\n id: string\n name: string\n background: string\n elements: CanvasElement[]\n}\n\nexport interface ScreenshotSet {\n version: 1\n id: string\n name: string\n locale: string\n device: string\n canvas: {\n width: number\n height: number\n }\n areas: ScreenshotArea[]\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateSetInput {\n name: string\n locale: string\n device: string\n width: number\n height: number\n}\n\nexport interface UpdateSetMetadataInput {\n name: string\n locale: string\n device: string\n}\n\nexport interface StoreShotProject {\n directory: string\n config: StoreShotConfig\n assets: Record<AssetCategory, Asset[]>\n sets: ScreenshotSet[]\n}\n"],"mappings":"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","names":["path","readFile","stat","path","isRecord","readString","platforms","readDimension","readNumber","path","stat","readFile","path"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/project-store.ts","../src/image-metadata.ts","../src/screenshot-area.ts","../src/server.ts","../src/validation.ts"],"sourcesContent":["import { constants } from \"node:fs\"\nimport { access, readFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\n\nimport { Command, Option } from \"commander\"\nimport open from \"open\"\n\nimport { ASSET_CATEGORIES, SCREENSHOT_DEVICE_TYPES, type AssetCategory, type ScreenshotDeviceType, type ScreenshotSet } from \"./shared.js\"\nimport { CONFIG_FILENAME, ProjectStore, parseScreenshotSet } from \"./project-store.js\"\nimport { startServer } from \"./server.js\"\nimport { validateProject, type ValidationReport } from \"./validation.js\"\n\nconst sourceFile = fileURLToPath(import.meta.url)\nconst packageRoot = path.resolve(path.dirname(sourceFile), \"..\")\nconst isSourceExecution = path.extname(sourceFile) === \".ts\"\n\nconst DEVICE_PRESETS = {\n iphone: { device: \"iPhone\", width: 1320, height: 2868 },\n ipad: { device: \"iPad\", width: 2064, height: 2752 },\n watch: { device: \"Apple Watch\", width: 422, height: 514 },\n mac: { device: \"Mac\", width: 2880, height: 1800 },\n} as const\n\ninterface GlobalOptions {\n json: boolean\n project: string\n}\n\nexport function createCli(): Command {\n const program = new Command()\n .name(\"storeshot\")\n .description(\"Manage app store screenshots locally\")\n .version(\"0.1.0\")\n .option(\"-C, --project <directory>\", \"project directory\", \".\")\n .option(\"--json\", \"write machine-readable JSON\")\n .showSuggestionAfterError()\n .addHelpText(\"after\", `\nAgent workflow:\n storeshot -C ./screenshots status --json\n storeshot -C ./screenshots validate --json\n storeshot -C ./screenshots set show <id>\n storeshot -C ./screenshots render --set <id> --scale 0.25 --json\n\nComplex canvas edits can be written as complete set JSON documents with\n\"set write\", or edited directly in sets/ and checked with \"validate\".`)\n\n program\n .command(\"init\")\n .description(\"Initialize a StoreShot project\")\n .argument(\"[directory]\", \"project directory\")\n .option(\"--app-name <name>\", \"application name\")\n .option(\"--platform <platform...>\", \"ios, android, or both\")\n .action(async (directory: string | undefined, options: { appName?: string; platform?: string[] }) => {\n const target = path.resolve(directory ?? projectDirectory(program))\n const configPath = path.join(target, CONFIG_FILENAME)\n const created = !await fileExists(configPath)\n const store = new ProjectStore(target)\n await store.initialize()\n const current = await store.readConfig()\n const platforms = options.platform ? parsePlatforms(options.platform) : current.platforms\n const config = options.appName || options.platform\n ? await store.writeConfig({ ...current, appName: options.appName ?? current.appName, platforms })\n : current\n emit(program, `Initialized ${store.root}\\nConfig: ${store.configPath}`, { ok: true, created, directory: store.root, config })\n })\n\n program\n .command(\"status\")\n .alias(\"inspect\")\n .description(\"Summarize the project for a human or agent\")\n .action(async () => {\n const store = await openProject(program)\n const project = await store.readProject()\n const assets = Object.values(project.assets).flat()\n const value = {\n ok: true,\n project: {\n directory: project.directory,\n configPath: store.configPath,\n appName: project.config.appName,\n platforms: project.config.platforms,\n },\n summary: {\n assets: assets.length,\n screenshots: project.assets.screenshots.length,\n sets: project.sets.length,\n areas: project.sets.reduce((total, set) => total + set.areas.length, 0),\n },\n sets: project.sets.map((set) => ({\n id: set.id,\n name: set.name,\n locale: set.locale,\n device: set.device,\n canvas: set.canvas,\n areas: set.areas.length,\n path: path.join(store.setsPath, `${set.id}.json`),\n })),\n }\n const lines = [\n `${project.config.appName} — ${project.directory}`,\n `${value.summary.sets} sets, ${value.summary.areas} screenshots, ${value.summary.assets} assets`,\n ...value.sets.map((set) => ` ${set.id} ${set.locale} · ${set.device} · ${set.areas} screenshots`),\n ]\n emit(program, lines.join(\"\\n\"), value)\n })\n\n program\n .command(\"validate\")\n .description(\"Validate project files and cross-references\")\n .option(\"--strict\", \"treat warnings as failures\")\n .action(async (options: { strict?: boolean }) => {\n const validation = await validateProject(projectDirectory(program), packageRoot)\n const failed = !validation.report.ok || Boolean(options.strict && validation.report.warnings.length > 0)\n emit(program, formatValidation(validation.report), { ...validation.report, ok: !failed })\n if (failed) process.exitCode = 1\n })\n\n program\n .command(\"render\")\n .description(\"Render screenshot sets to PNG files\")\n .option(\"--set <id>\", \"render one set (repeatable)\", collect, [])\n .option(\"--area <id-or-number>\", \"render one area by id, exact name, or 1-based number\")\n .option(\"-o, --output <directory>\", \"output directory (default: <project>/renders)\")\n .option(\"--scale <scale>\", \"render scale from 0 to 1\", \"1\")\n .option(\"--clean\", \"remove each selected set's existing output directory first\")\n .action(async (options: { set: string[]; area?: string; output?: string; scale: string; clean?: boolean }) => {\n const directory = projectDirectory(program)\n const validation = await validateProject(directory, packageRoot)\n if (!validation.report.ok || !validation.assets) {\n emit(program, formatValidation(validation.report), { ...validation.report, ok: false })\n process.exitCode = 1\n return\n }\n const selectedSets = options.set.length === 0\n ? validation.sets\n : options.set.map((id) => {\n const set = validation.sets.find((candidate) => candidate.id === id)\n if (!set) throw new Error(`Unknown set id: ${id}`)\n return set\n })\n if (selectedSets.length === 0) throw new Error(\"The project has no screenshot sets to render\")\n const scale = parseNumber(options.scale, \"Scale\")\n const store = await openProject(program)\n const { renderScreenshotSets } = await import(\"./node-renderer.js\")\n const result = await renderScreenshotSets({\n clean: Boolean(options.clean),\n outputDirectory: path.resolve(options.output ?? path.join(directory, \"renders\")),\n packageRoot,\n scale,\n sets: selectedSets,\n store,\n ...(options.area ? { area: options.area } : {}),\n })\n emit(\n program,\n [`Rendered ${result.files.length} PNG file${result.files.length === 1 ? \"\" : \"s\"} to ${result.outputDirectory}`, ...result.files.map((file) => ` ${file.path}`)].join(\"\\n\"),\n { ok: true, render: result, warnings: validation.report.warnings },\n )\n })\n\n configureConfigCommands(program)\n configureSetCommands(program)\n configureAssetCommands(program)\n configureDevCommand(program)\n return program\n}\n\nfunction configureConfigCommands(program: Command): void {\n const config = program.command(\"config\").description(\"Inspect or update storeshot.json\")\n\n config.command(\"get\").description(\"Print the project configuration\").action(async () => {\n const store = await openProject(program)\n const value = await store.readConfig()\n emitDocument(program, value, { ok: true, config: value })\n })\n\n config\n .command(\"set\")\n .description(\"Update project configuration\")\n .option(\"--app-name <name>\", \"application name\")\n .option(\"--platform <platform...>\", \"ios, android, or both\")\n .action(async (options: { appName?: string; platform?: string[] }) => {\n if (!options.appName && !options.platform) throw new Error(\"Provide --app-name or --platform\")\n const store = await openProject(program)\n const current = await store.readConfig()\n const value = await store.writeConfig({\n ...current,\n appName: options.appName ?? current.appName,\n platforms: options.platform ? parsePlatforms(options.platform) : current.platforms,\n })\n emit(program, `Updated ${store.configPath}`, { ok: true, config: value })\n })\n}\n\nfunction configureSetCommands(program: Command): void {\n const set = program.command(\"set\").alias(\"sets\").description(\"Create, inspect, edit, duplicate, or delete screenshot sets\")\n\n set.command(\"list\").description(\"List screenshot sets\").action(async () => {\n const store = await openProject(program)\n const sets = await store.listSets()\n emit(\n program,\n sets.length === 0 ? \"No screenshot sets\" : sets.map((value) => `${value.id}\\t${value.locale}\\t${value.device}\\t${value.name}`).join(\"\\n\"),\n { ok: true, sets },\n )\n })\n\n set.command(\"show\").description(\"Print one complete set document\").argument(\"<id>\", \"set id\").action(async (id: string) => {\n const store = await openProject(program)\n const value = await store.readSet(id)\n emitDocument(program, value, { ok: true, set: value, path: path.join(store.setsPath, `${id}.json`) })\n })\n\n set\n .command(\"create\")\n .description(\"Create a screenshot set\")\n .requiredOption(\"--name <name>\", \"set name\")\n .requiredOption(\"--locale <locale>\", \"locale identifier\")\n .addOption(new Option(\"--preset <preset>\", \"iphone, ipad, watch, or mac\").choices(Object.keys(DEVICE_PRESETS)).default(\"iphone\"))\n .option(\"--device <name>\", \"device label\")\n .option(\"--width <pixels>\", \"custom canvas width\")\n .option(\"--height <pixels>\", \"custom canvas height\")\n .action(async (options: { name: string; locale: string; preset: keyof typeof DEVICE_PRESETS; device?: string; width?: string; height?: string }) => {\n if ((options.width && !options.height) || (!options.width && options.height)) throw new Error(\"Provide both --width and --height\")\n const preset = DEVICE_PRESETS[options.preset]\n const store = await openProject(program)\n const value = await store.createSet({\n name: options.name,\n locale: options.locale,\n device: options.device ?? preset.device,\n width: options.width ? parseInteger(options.width, \"Canvas width\") : preset.width,\n height: options.height ? parseInteger(options.height, \"Canvas height\") : preset.height,\n })\n emit(program, `Created ${value.id} at ${path.join(store.setsPath, `${value.id}.json`)}`, { ok: true, set: value })\n })\n\n set\n .command(\"update\")\n .description(\"Update common set metadata\")\n .argument(\"<id>\", \"set id\")\n .option(\"--name <name>\", \"set name\")\n .option(\"--locale <locale>\", \"locale identifier\")\n .option(\"--device <name>\", \"device label\")\n .action(async (id: string, options: { name?: string; locale?: string; device?: string }) => {\n if (!options.name && !options.locale && !options.device) throw new Error(\"Provide --name, --locale, or --device\")\n const store = await openProject(program)\n const current = await store.readSet(id)\n const value = await store.updateSetMetadata(id, {\n name: options.name ?? current.name,\n locale: options.locale ?? current.locale,\n device: options.device ?? current.device,\n })\n emit(program, `Updated ${id}`, { ok: true, set: value })\n })\n\n set\n .command(\"write\")\n .description(\"Replace a complete set document with schema-validated JSON\")\n .argument(\"<id>\", \"set id\")\n .requiredOption(\"--file <file>\", \"JSON file, or - for stdin\")\n .action(async (id: string, options: { file: string }) => {\n const input = options.file === \"-\" ? await readStandardInput() : await readFile(path.resolve(options.file), \"utf8\")\n let document: unknown\n try {\n document = JSON.parse(input)\n } catch {\n throw new Error(\"Set input must be valid JSON\")\n }\n const value = parseScreenshotSet(document)\n if (value.id !== id) throw new Error(`Set input id ${value.id} does not match ${id}`)\n const store = await openProject(program)\n const saved = await store.writeSet(id, value)\n emit(program, `Wrote ${path.join(store.setsPath, `${id}.json`)}`, { ok: true, set: saved })\n })\n\n set.command(\"duplicate\").description(\"Duplicate a set with fresh object ids\").argument(\"<id>\", \"set id\").action(async (id: string) => {\n const store = await openProject(program)\n const value = await store.duplicateSet(id)\n emit(program, `Created duplicate ${value.id}`, { ok: true, set: value })\n })\n\n set\n .command(\"delete\")\n .description(\"Delete a screenshot set\")\n .argument(\"<id>\", \"set id\")\n .requiredOption(\"--yes\", \"confirm deletion\")\n .action(async (id: string) => {\n const store = await openProject(program)\n await store.deleteSet(id)\n emit(program, `Deleted ${id}`, { ok: true, deleted: id })\n })\n}\n\nfunction configureAssetCommands(program: Command): void {\n const asset = program.command(\"asset\").alias(\"assets\").description(\"List, add, classify, or remove project assets\")\n\n asset\n .command(\"list\")\n .description(\"List project assets\")\n .addOption(new Option(\"--category <category>\", \"filter by category\").choices([...ASSET_CATEGORIES]))\n .action(async (options: { category?: AssetCategory }) => {\n const store = await openProject(program)\n const catalog = await store.listAssets()\n const assets = options.category ? catalog[options.category] : Object.values(catalog).flat()\n emit(\n program,\n assets.length === 0 ? \"No assets\" : assets.map((value) => `${value.id}\\t${value.width ?? \"?\"}x${value.height ?? \"?\"}\\t${value.size} bytes`).join(\"\\n\"),\n { ok: true, assets },\n )\n })\n\n asset\n .command(\"add\")\n .description(\"Copy image files into the project asset catalog\")\n .argument(\"<files...>\", \"image files\")\n .addOption(new Option(\"--category <category>\", \"asset category\").choices([...ASSET_CATEGORIES]).default(\"screenshots\"))\n .option(\"--replace\", \"allow replacement of an existing same-name asset\")\n .action(async (files: string[], options: { category: AssetCategory; replace?: boolean }) => {\n const store = await openProject(program)\n const added: Array<{ id: string; replaced: boolean }> = []\n for (const source of files) {\n const filename = path.basename(source)\n const target = store.resolveAsset(options.category, filename)\n if (!options.replace && await fileExists(target)) throw new Error(`${options.category}/${filename} already exists; pass --replace to overwrite it`)\n const result = await store.addAsset(options.category, filename, await readFile(path.resolve(source)))\n added.push({ id: `${options.category}/${filename}`, replaced: result.replaced })\n }\n emit(program, added.map((entry) => `${entry.replaced ? \"Replaced\" : \"Added\"} ${entry.id}`).join(\"\\n\"), { ok: true, assets: added })\n })\n\n asset\n .command(\"set-device\")\n .description(\"Override or clear raw screenshot device classification\")\n .argument(\"<id>\", \"asset id such as screenshots/home.png\")\n .argument(\"<device>\", \"iphone, ipad, mac, watch, or auto\")\n .action(async (id: string, device: ScreenshotDeviceType | \"auto\") => {\n if (device !== \"auto\" && !SCREENSHOT_DEVICE_TYPES.includes(device)) throw new Error(\"Device must be iphone, ipad, mac, watch, or auto\")\n const { category, filename } = parseAssetId(id)\n const store = await openProject(program)\n await store.updateAssetMetadata(category, filename, { deviceType: device === \"auto\" ? null : device })\n emit(program, `Updated ${id}`, { ok: true, assetId: id, deviceType: device === \"auto\" ? null : device })\n })\n\n asset\n .command(\"remove\")\n .description(\"Delete assets that are not referenced by screenshot sets\")\n .argument(\"<ids...>\", \"asset ids\")\n .requiredOption(\"--yes\", \"confirm deletion\")\n .option(\"--force\", \"delete even when a set references the asset\")\n .action(async (ids: string[], options: { force?: boolean }) => {\n const store = await openProject(program)\n const sets = await store.listSets()\n for (const id of ids) {\n const references = assetReferences(id, sets)\n if (references.length > 0 && !options.force) throw new Error(`${id} is referenced by ${references.join(\", \")}; pass --force to delete it anyway`)\n }\n for (const id of ids) {\n const { category, filename } = parseAssetId(id)\n await store.deleteAsset(category, filename)\n }\n emit(program, ids.map((id) => `Deleted ${id}`).join(\"\\n\"), { ok: true, deleted: ids })\n })\n}\n\nfunction configureDevCommand(program: Command): void {\n program\n .command(\"dev\")\n .description(\"Open a live StoreShot workspace for a local directory\")\n .argument(\"[directory]\", \"project directory\")\n .addOption(new Option(\"-p, --port <port>\", \"local server port\").default(\"4173\"))\n .addOption(new Option(\"--host <host>\", \"local server host\").default(\"127.0.0.1\"))\n .option(\"--no-open\", \"do not open a browser\")\n .action(async (directory: string | undefined, options: { port: string; host: string; open: boolean }) => {\n const port = parseInteger(options.port, \"Port\")\n if (port > 65_535) throw new Error(\"Port must be an integer between 1 and 65535\")\n const projectDirectory = path.resolve(directory ?? globalOptions(program).project)\n const service = await startServer({ host: options.host, port, packageRoot, projectDirectory, useVite: isSourceExecution })\n const url = `http://${options.host}:${service.port}`\n if (globalOptions(program).json) console.log(JSON.stringify({ ok: true, url, directory: service.store.root }))\n else console.log(`\\n StoreShot is ready at ${url}\\n Project: ${service.store.root}\\n Filesystem changes refresh the preview automatically.\\n`)\n if (options.open) await open(url)\n const shutdown = async () => {\n await service.close()\n process.exit(0)\n }\n process.once(\"SIGINT\", shutdown)\n process.once(\"SIGTERM\", shutdown)\n })\n}\n\nasync function openProject(program: Command): Promise<ProjectStore> {\n const store = new ProjectStore(projectDirectory(program))\n try {\n await access(store.configPath, constants.R_OK)\n } catch {\n throw new Error(`No StoreShot project found at ${store.root}; run storeshot init first`)\n }\n await store.readConfig()\n return store\n}\n\nfunction globalOptions(program: Command): GlobalOptions {\n return program.opts() as GlobalOptions\n}\n\nfunction projectDirectory(program: Command): string {\n return path.resolve(globalOptions(program).project)\n}\n\nfunction emit(program: Command, human: string, json: unknown): void {\n console.log(globalOptions(program).json ? JSON.stringify(json, null, 2) : human)\n}\n\nfunction emitDocument(program: Command, document: unknown, json: unknown): void {\n console.log(JSON.stringify(globalOptions(program).json ? json : document, null, 2))\n}\n\nfunction formatValidation(report: ValidationReport): string {\n const lines = [\n report.ok ? `Valid StoreShot project: ${report.directory}` : `Invalid StoreShot project: ${report.directory}`,\n `${report.summary.sets} sets, ${report.summary.areas} screenshots, ${report.summary.assets} assets`,\n ]\n for (const entry of [...report.errors, ...report.warnings]) {\n lines.push(`${entry.severity === \"error\" ? \"error\" : \"warning\"} [${entry.code}] ${entry.path}: ${entry.message}`)\n }\n return lines.join(\"\\n\")\n}\n\nfunction parsePlatforms(values: string[]): Array<\"ios\" | \"android\"> {\n const platforms = [...new Set(values.flatMap((value) => value.split(\",\")).map((value) => value.trim().toLowerCase()))]\n if (platforms.length === 0 || platforms.some((value) => value !== \"ios\" && value !== \"android\")) {\n throw new Error(\"Platforms must be ios, android, or both\")\n }\n return platforms as Array<\"ios\" | \"android\">\n}\n\nfunction parseInteger(value: string, name: string): number {\n const result = Number(value)\n if (!Number.isInteger(result) || result <= 0) throw new Error(`${name} must be a positive integer`)\n return result\n}\n\nfunction parseNumber(value: string, name: string): number {\n const result = Number(value)\n if (!Number.isFinite(result)) throw new Error(`${name} must be a number`)\n return result\n}\n\nfunction parseAssetId(id: string): { category: AssetCategory; filename: string } {\n const separator = id.indexOf(\"/\")\n const category = id.slice(0, separator) as AssetCategory\n const filename = id.slice(separator + 1)\n if (separator < 1 || !ASSET_CATEGORIES.includes(category) || !filename || filename.includes(\"/\")) throw new Error(`Invalid asset id: ${id}`)\n return { category, filename }\n}\n\nfunction assetReferences(assetId: string, sets: ScreenshotSet[]): string[] {\n return sets.flatMap((set) => set.areas.some((area) => area.elements.some((element) =>\n (element.type === \"mockup\" && element.assetId === assetId)\n || (element.type === \"image\" && element.source.kind === \"asset\" && element.source.assetId === assetId),\n )) ? [set.id] : [])\n}\n\nasync function readStandardInput(): Promise<string> {\n const chunks: Buffer[] = []\n for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n return Buffer.concat(chunks).toString(\"utf8\")\n}\n\nasync function fileExists(filename: string): Promise<boolean> {\n return access(filename, constants.F_OK).then(() => true).catch(() => false)\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value]\n}\n\nconst program = createCli()\nprogram.parseAsync().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n if (globalOptions(program).json) console.error(JSON.stringify({ ok: false, error: { message } }, null, 2))\n else console.error(`storeshot: ${message}`)\n process.exitCode = 1\n})\n","import { createHash, randomUUID } from \"node:crypto\"\nimport { constants } from \"node:fs\"\nimport { access, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport {\n MOCKUP_BUNDLE_FILENAME,\n bundleAssetPaths,\n emptyDeviceMockupCatalog,\n isSafeBundlePath,\n mergeDeviceMockupCatalogs,\n parseMockupBundleManifest,\n resolveMockupBundle,\n type DeviceMockupCatalog,\n type MockupBundleManifest,\n} from \"./device-mockups.js\"\nimport { detectScreenshotDeviceType, readImageMetadata } from \"./image-metadata.js\"\nimport { cloneScreenshotArea } from \"./screenshot-area.js\"\n\nimport {\n ASSET_CATEGORIES,\n type StoreShotConfig,\n type StoreShotProject,\n type Asset,\n type AssetCategory,\n type CanvasElement,\n type CreateSetInput,\n type FontWeight,\n type ImageElementSource,\n type ScreenshotArea,\n type ScreenshotSet,\n SCREENSHOT_DEVICE_TYPES,\n type ScreenshotDeviceType,\n type UpdateAssetMetadataInput,\n type UpdateSetMetadataInput,\n} from \"./shared.js\"\n\nexport const CONFIG_FILENAME = \"storeshot.json\"\nexport const ASSETS_DIRECTORY = \"assets\"\nexport const SETS_DIRECTORY = \"sets\"\nexport const ASSET_METADATA_FILENAME = \".storeshot-metadata.json\"\nexport const MOCKUP_BUNDLES_DIRECTORY = \"mockup-bundles\"\nconst MOCKUP_IMPORTS_DIRECTORY = \".imports\"\n\nconst supportedExtensions = new Set([\".png\", \".jpg\", \".jpeg\", \".webp\", \".svg\"])\nconst supportedMockupBundleExtensions = new Set([\".jpeg\", \".jpg\", \".md\", \".png\", \".svg\", \".txt\", \".webp\"])\nconst safeIdentifierPattern = /^[a-z0-9][a-z0-9-]*$/\nconst hexColorPattern = /^#[0-9a-f]{6}$/i\n\nexport class ProjectStore {\n readonly root: string\n readonly configPath: string\n readonly assetsPath: string\n readonly setsPath: string\n readonly mockupBundlesPath: string\n readonly mockupImportsPath: string\n private readonly operations = new Map<string, Promise<void>>()\n private readonly assetHashes = new Map<string, { hash: string; mtimeMs: number; size: number }>()\n\n constructor(directory: string) {\n this.root = path.resolve(directory)\n this.configPath = path.join(this.root, CONFIG_FILENAME)\n this.assetsPath = path.join(this.root, ASSETS_DIRECTORY)\n this.setsPath = path.join(this.root, SETS_DIRECTORY)\n this.mockupBundlesPath = path.join(this.root, MOCKUP_BUNDLES_DIRECTORY)\n this.mockupImportsPath = path.join(this.mockupBundlesPath, MOCKUP_IMPORTS_DIRECTORY)\n }\n\n async initialize(): Promise<void> {\n await mkdir(this.root, { recursive: true })\n await this.assertManagedDirectory(this.root)\n await this.ensureManagedDirectory(this.assetsPath, this.root)\n await this.ensureManagedDirectory(this.setsPath, this.root)\n await this.ensureManagedDirectory(this.mockupBundlesPath, this.root)\n await rm(this.mockupImportsPath, { recursive: true, force: true })\n await this.ensureManagedDirectory(this.mockupImportsPath, this.mockupBundlesPath)\n for (const category of ASSET_CATEGORIES) {\n await this.ensureManagedDirectory(path.join(this.assetsPath, category), this.assetsPath)\n }\n\n try {\n await access(this.configPath, constants.F_OK)\n } catch {\n await this.writeConfig({\n version: 1,\n appName: path.basename(this.root),\n platforms: [\"ios\"],\n })\n }\n }\n\n async readProject(): Promise<StoreShotProject> {\n const [config, assets, sets] = await Promise.all([this.readConfig(), this.listAssets(), this.listSets()])\n return { directory: this.root, config, assets, sets }\n }\n\n async readConfig(): Promise<StoreShotConfig> {\n const value: unknown = JSON.parse(await this.readManagedFile(this.configPath, this.root, \"utf8\"))\n return parseStoreShotConfig(value)\n }\n\n async writeConfig(config: StoreShotConfig): Promise<StoreShotConfig> {\n const value = parseStoreShotConfig(config)\n await this.runExclusive(this.configPath, async () => {\n await this.assertSafeWriteTarget(this.configPath, this.root)\n await writeJson(this.configPath, value)\n })\n return value\n }\n\n async listAssets(): Promise<Record<AssetCategory, Asset[]>> {\n const entries = await Promise.all(\n ASSET_CATEGORIES.map(async (category) => [category, await this.listAssetsInCategory(category)] as const),\n )\n return Object.fromEntries(entries) as Record<AssetCategory, Asset[]>\n }\n\n async deleteAsset(category: AssetCategory, filename: string): Promise<void> {\n const target = await this.resolveExistingAsset(category, filename)\n await this.runExclusive(target, async () => unlink(target))\n this.assetHashes.delete(target)\n await this.updateAssetMetadataFile((metadata) => {\n delete metadata[`${category}/${filename}`]\n })\n }\n\n async updateAssetMetadata(category: AssetCategory, filename: string, input: UpdateAssetMetadataInput): Promise<void> {\n await this.resolveExistingAsset(category, filename)\n if (category !== \"screenshots\") throw new Error(\"Device type can only be set for raw screenshots\")\n const deviceType = input.deviceType\n if (deviceType !== null && !SCREENSHOT_DEVICE_TYPES.includes(deviceType)) throw new Error(\"Unsupported screenshot device type\")\n await this.updateAssetMetadataFile((metadata) => {\n const id = `${category}/${filename}`\n if (deviceType === null) delete metadata[id]\n else metadata[id] = { deviceType }\n })\n }\n\n async addAsset(category: string, filename: string, contents: Buffer): Promise<{ replaced: boolean }> {\n const target = this.resolveAsset(category, filename)\n assertValidImage(filename, contents)\n return this.runExclusive(\"asset-catalog\", async () => {\n await this.assertSafeWriteTarget(target, path.dirname(target))\n const incomingHash = hash(contents)\n const replaced = await access(target, constants.F_OK).then(() => true).catch(() => false)\n\n for (const assetCategory of ASSET_CATEGORIES) {\n const directory = path.join(this.assetsPath, assetCategory)\n const entries = await readdir(directory, { withFileTypes: true })\n for (const entry of entries) {\n if (!entry.isFile() || !supportedExtensions.has(path.extname(entry.name).toLowerCase())) continue\n const existingPath = path.join(directory, entry.name)\n if (existingPath === target) continue\n if (await this.hashAsset(existingPath, directory) === incomingHash) {\n throw new DuplicateAssetError(`${assetCategory}/${entry.name}`)\n }\n }\n }\n\n await writeFileAtomically(target, contents)\n const metadata = await stat(target)\n this.assetHashes.set(target, { hash: incomingHash, mtimeMs: metadata.mtimeMs, size: metadata.size })\n return { replaced }\n })\n }\n\n resolveAsset(category: string, filename: string): string {\n if (!isAssetCategory(category)) throw new Error(\"Unsupported asset category\")\n\n const safeName = path.basename(filename)\n const extension = path.extname(safeName).toLowerCase()\n if (safeName !== filename || !supportedExtensions.has(extension)) {\n throw new Error(\"Unsupported asset filename\")\n }\n\n return path.join(this.assetsPath, category, safeName)\n }\n\n async resolveExistingAsset(category: string, filename: string): Promise<string> {\n const target = this.resolveAsset(category, filename)\n await this.assertRegularFile(target)\n const resolved = await realpath(target)\n await this.assertContained(resolved, path.join(this.assetsPath, category))\n return resolved\n }\n\n async listSets(): Promise<ScreenshotSet[]> {\n const entries = await readdir(this.setsPath, { withFileTypes: true })\n const sets = await Promise.all(\n entries\n .filter((entry) => entry.isFile() && path.extname(entry.name) === \".json\")\n .map(async (entry) => parseScreenshotSet(JSON.parse(await this.readManagedFile(path.join(this.setsPath, entry.name), this.setsPath, \"utf8\")))),\n )\n return sets.sort((a, b) => a.createdAt.localeCompare(b.createdAt))\n }\n\n async createSet(input: CreateSetInput): Promise<ScreenshotSet> {\n const value = parseCreateSetInput(input)\n const now = new Date().toISOString()\n const id = `${slugify(value.name)}-${randomUUID().slice(0, 8)}`\n const areaId = `area-${randomUUID()}`\n const set: ScreenshotSet = {\n version: 1,\n id,\n name: value.name,\n locale: value.locale,\n device: value.device,\n canvas: { width: value.width, height: value.height },\n areas: [\n {\n id: areaId,\n name: \"Screenshot 1\",\n background: \"#245f4a\",\n elements: [\n {\n id: `element-${randomUUID()}`,\n type: \"text\",\n text: \"Your headline\",\n x: Math.round(value.width * 0.08),\n y: Math.round(value.height * 0.07),\n width: Math.round(value.width * 0.84),\n height: Math.round(value.height * 0.2),\n rotation: 0,\n opacity: 1,\n fontFamily: \"Geist Variable\",\n fontSize: Math.max(48, Math.round(value.width * 0.09)),\n fontWeight: 700,\n color: \"#ffffff\",\n textAlign: \"center\",\n },\n ],\n },\n ],\n createdAt: now,\n updatedAt: now,\n }\n const target = this.resolveSet(id)\n await this.runExclusive(target, async () => {\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, set)\n })\n return set\n }\n\n async duplicateSet(id: string): Promise<ScreenshotSet> {\n const source = await this.readSet(id)\n const existingSets = await this.listSets()\n const name = duplicateName(source.name, existingSets.map((set) => set.name))\n const now = new Date().toISOString()\n const duplicate: ScreenshotSet = {\n ...structuredClone(source),\n id: `${slugify(name)}-${randomUUID().slice(0, 8)}`,\n name,\n areas: source.areas.map((area) => cloneScreenshotArea(area, { idFactory: randomUUID })),\n createdAt: now,\n updatedAt: now,\n }\n const target = this.resolveSet(duplicate.id)\n await this.runExclusive(target, async () => {\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, duplicate)\n })\n return duplicate\n }\n\n async writeSet(id: string, set: ScreenshotSet): Promise<ScreenshotSet> {\n if (id !== set.id) throw new Error(\"Set id cannot be changed\")\n const target = this.resolveSet(id)\n return this.runExclusive(target, async () => {\n const value = parseScreenshotSet({ ...set, updatedAt: new Date().toISOString() })\n await this.assertSafeWriteTarget(target, this.setsPath)\n await writeJson(target, value)\n return value\n })\n }\n\n async updateSetMetadata(id: string, input: UpdateSetMetadataInput): Promise<ScreenshotSet> {\n const metadata = parseSetMetadataInput(input)\n const target = this.resolveSet(id)\n return this.runExclusive(target, async () => {\n const current = parseScreenshotSet(JSON.parse(await this.readManagedFile(target, this.setsPath, \"utf8\")))\n const value = parseScreenshotSet({ ...current, ...metadata, updatedAt: new Date().toISOString() })\n await writeJson(target, value)\n return value\n })\n }\n\n async deleteSet(id: string): Promise<void> {\n const target = this.resolveSet(id)\n await this.runExclusive(target, async () => {\n await this.assertRegularFile(target)\n await unlink(target)\n })\n }\n\n async listMockupCatalog(): Promise<DeviceMockupCatalog> {\n const entries = await readdir(this.mockupBundlesPath, { withFileTypes: true })\n const catalogs = (await Promise.all(entries\n .filter((entry) => entry.isDirectory() && safeIdentifierPattern.test(entry.name))\n .map(async (entry) => {\n const manifestPath = path.join(this.mockupBundlesPath, entry.name, MOCKUP_BUNDLE_FILENAME)\n let contents: string\n try {\n contents = await this.readManagedFile(manifestPath, path.dirname(manifestPath), \"utf8\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined\n throw error\n }\n const manifest = parseMockupBundleManifest(JSON.parse(contents))\n if (manifest.id !== entry.name) throw new Error(`Mockup bundle folder ${entry.name} does not match manifest id ${manifest.id}`)\n return resolveMockupBundle(\n manifest,\n `/api/mockup-bundle-files/${encodeURIComponent(manifest.id)}/`,\n \"project\",\n )\n }))).filter((catalog): catalog is DeviceMockupCatalog => catalog !== undefined)\n return catalogs.length > 0 ? mergeDeviceMockupCatalogs(...catalogs) : emptyDeviceMockupCatalog()\n }\n\n async writeMockupBundleManifest(bundleId: string, input: unknown): Promise<MockupBundleManifest> {\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const manifest = parseMockupBundleManifest(input)\n if (manifest.id !== bundleId) throw new Error(\"Mockup bundle id cannot be changed\")\n const bundleDirectory = path.join(this.mockupBundlesPath, bundleId)\n await this.ensureManagedDirectory(bundleDirectory, this.mockupBundlesPath)\n await Promise.all(bundleAssetPaths(manifest).map(async (relativePath) => {\n await this.resolveExistingMockupBundleFile(bundleId, relativePath)\n }))\n const manifestPath = path.join(bundleDirectory, MOCKUP_BUNDLE_FILENAME)\n await this.runExclusive(manifestPath, async () => writeJson(manifestPath, manifest))\n return manifest\n }\n\n async writeMockupBundleFile(bundleId: string, relativePath: string, contents: Buffer): Promise<void> {\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const target = this.resolveMockupBundleFile(bundleId, relativePath)\n if (isImageFile(relativePath)) assertValidImage(relativePath, contents)\n await this.ensureManagedDirectory(path.dirname(target), this.mockupBundlesPath)\n await this.assertSafeWriteTarget(target, path.dirname(target))\n await this.runExclusive(target, async () => writeFileAtomically(target, contents))\n }\n\n async writeMockupBundleImportFile(importId: string, bundleId: string, relativePath: string, contents: Buffer): Promise<void> {\n this.assertMockupImportId(importId)\n this.resolveMockupBundleFile(bundleId, relativePath)\n if (isImageFile(relativePath)) assertValidImage(relativePath, contents)\n const bundleDirectory = path.join(this.mockupImportsPath, importId, bundleId)\n const target = path.resolve(bundleDirectory, relativePath)\n if (!target.startsWith(`${bundleDirectory}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the import\")\n await this.ensureManagedDirectory(path.dirname(target), this.mockupImportsPath)\n await this.assertSafeWriteTarget(target, path.dirname(target))\n await this.runExclusive(target, async () => writeFileAtomically(target, contents))\n }\n\n async commitMockupBundleImport(importId: string, bundleId: string, input: unknown): Promise<MockupBundleManifest> {\n this.assertMockupImportId(importId)\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (bundleId === \"frameup-free\") throw new Error(\"frameup-free is reserved for StoreShot's built-in bundle\")\n const manifest = parseMockupBundleManifest(input)\n if (manifest.id !== bundleId) throw new Error(\"Mockup bundle id cannot be changed\")\n\n const importDirectory = path.join(this.mockupImportsPath, importId)\n const stagedBundle = path.join(importDirectory, bundleId)\n await this.assertManagedDirectory(stagedBundle)\n await Promise.all(bundleAssetPaths(manifest).map(async (relativePath) => {\n const target = path.resolve(stagedBundle, relativePath)\n if (!target.startsWith(`${stagedBundle}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the import\")\n await this.readManagedFile(target, stagedBundle)\n }))\n await writeJson(path.join(stagedBundle, MOCKUP_BUNDLE_FILENAME), manifest)\n\n const finalBundle = path.join(this.mockupBundlesPath, bundleId)\n const backupBundle = path.join(this.mockupBundlesPath, `.${bundleId}.${randomUUID()}.backup`)\n await this.runExclusive(`mockup-bundle:${bundleId}`, async () => {\n let hasBackup = false\n try {\n const metadata = await lstat(finalBundle)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new Error(\"Mockup bundle must be a regular directory\")\n await rename(finalBundle, backupBundle)\n hasBackup = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n\n try {\n await rename(stagedBundle, finalBundle)\n } catch (error) {\n if (hasBackup) await rename(backupBundle, finalBundle)\n throw error\n }\n if (hasBackup) await rm(backupBundle, { recursive: true, force: true }).catch(() => undefined)\n await rm(importDirectory, { recursive: true, force: true }).catch(() => undefined)\n })\n return manifest\n }\n\n async discardMockupBundleImport(importId: string): Promise<void> {\n this.assertMockupImportId(importId)\n const target = path.join(this.mockupImportsPath, importId)\n const relative = path.relative(this.mockupImportsPath, target)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"Mockup import is outside the project boundary\")\n await rm(target, { recursive: true, force: true })\n }\n\n resolveMockupBundleFile(bundleId: string, relativePath: string): string {\n if (!safeIdentifierPattern.test(bundleId)) throw new Error(\"Unsupported mockup bundle id\")\n if (!isSafeBundlePath(relativePath) || relativePath === MOCKUP_BUNDLE_FILENAME) {\n throw new Error(\"Unsupported mockup bundle file path\")\n }\n const extension = path.extname(relativePath).toLowerCase()\n if (path.basename(relativePath) !== \"LICENSE\" && !supportedMockupBundleExtensions.has(extension)) {\n throw new Error(\"Unsupported mockup bundle file type\")\n }\n const bundleRoot = path.join(this.mockupBundlesPath, bundleId)\n const target = path.resolve(bundleRoot, relativePath)\n if (!target.startsWith(`${bundleRoot}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the bundle\")\n return target\n }\n\n async resolveExistingMockupBundleFile(bundleId: string, relativePath: string): Promise<string> {\n const bundleRoot = await realpath(path.join(this.mockupBundlesPath, bundleId))\n await this.assertContained(bundleRoot, this.mockupBundlesPath)\n await this.assertRegularFile(this.resolveMockupBundleFile(bundleId, relativePath))\n const target = await realpath(this.resolveMockupBundleFile(bundleId, relativePath))\n if (!target.startsWith(`${bundleRoot}${path.sep}`)) throw new Error(\"Mockup bundle file is outside the bundle\")\n return target\n }\n\n private async listAssetsInCategory(category: AssetCategory): Promise<Asset[]> {\n const directory = path.join(this.assetsPath, category)\n const entries = await readdir(directory, { withFileTypes: true })\n const files = entries\n .filter((entry) => entry.isFile() && supportedExtensions.has(path.extname(entry.name).toLowerCase()))\n .sort((a, b) => a.name.localeCompare(b.name))\n\n const assetMetadata = await this.readAssetMetadata()\n return Promise.all(\n files.map(async (file) => {\n const filename = path.join(directory, file.name)\n const [metadata, contents] = await Promise.all([stat(filename), this.readManagedFile(filename, directory)])\n const dimensions = readImageMetadata(contents)\n const detectedDeviceType = category === \"screenshots\" && dimensions\n ? detectScreenshotDeviceType(dimensions.width, dimensions.height)\n : undefined\n const deviceTypeOverride = assetMetadata[`${category}/${file.name}`]?.deviceType\n return {\n id: `${category}/${file.name}`,\n category,\n name: file.name,\n url: `/api/assets/${category}/${encodeURIComponent(file.name)}?v=${Math.trunc(metadata.mtimeMs)}`,\n size: metadata.size,\n modifiedAt: metadata.mtime.toISOString(),\n ...(dimensions ?? {}),\n ...(detectedDeviceType ? {\n detectedDeviceType,\n deviceTypeOverride,\n deviceType: deviceTypeOverride ?? detectedDeviceType,\n } : {}),\n }\n }),\n )\n }\n\n private async readAssetMetadata(): Promise<AssetMetadata> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n try {\n const value: unknown = JSON.parse(await this.readManagedFile(target, this.assetsPath, \"utf8\"))\n if (!isRecord(value) || value.version !== 1 || !isRecord(value.assets)) return {}\n return Object.fromEntries(Object.entries(value.assets).flatMap(([id, entry]) => {\n if (!isRecord(entry) || !SCREENSHOT_DEVICE_TYPES.includes(entry.deviceType as ScreenshotDeviceType)) return []\n return [[id, { deviceType: entry.deviceType as ScreenshotDeviceType }]]\n }))\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return {}\n throw error\n }\n }\n\n private async writeAssetMetadata(assets: AssetMetadata): Promise<void> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n await this.assertSafeWriteTarget(target, this.assetsPath)\n await writeJson(target, { version: 1, assets })\n }\n\n private async updateAssetMetadataFile(update: (metadata: AssetMetadata) => void): Promise<void> {\n const target = path.join(this.assetsPath, ASSET_METADATA_FILENAME)\n await this.runExclusive(target, async () => {\n const metadata = await this.readAssetMetadata()\n update(metadata)\n await this.writeAssetMetadata(metadata)\n })\n }\n\n private async hashAsset(filename: string, boundary: string): Promise<string> {\n const metadata = await stat(filename)\n const cached = this.assetHashes.get(filename)\n if (cached && cached.mtimeMs === metadata.mtimeMs && cached.size === metadata.size) return cached.hash\n const value = hash(await this.readManagedFile(filename, boundary))\n this.assetHashes.set(filename, { hash: value, mtimeMs: metadata.mtimeMs, size: metadata.size })\n return value\n }\n\n async readSet(id: string): Promise<ScreenshotSet> {\n const target = this.resolveSet(id)\n return parseScreenshotSet(JSON.parse(await this.readManagedFile(target, this.setsPath, \"utf8\")))\n }\n\n private async runExclusive<T>(key: string, operation: () => Promise<T>): Promise<T> {\n const previous = this.operations.get(key) ?? Promise.resolve()\n const result = previous.catch(() => undefined).then(operation)\n const tail = result.then(() => undefined, () => undefined)\n this.operations.set(key, tail)\n try {\n return await result\n } finally {\n if (this.operations.get(key) === tail) this.operations.delete(key)\n }\n }\n\n private async assertManagedDirectory(directory: string): Promise<void> {\n const metadata = await lstat(directory)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) {\n throw new Error(`${path.relative(this.root, directory) || \".\"} must be a regular project directory`)\n }\n await this.assertContained(await realpath(directory), this.root, true)\n }\n\n private async ensureManagedDirectory(directory: string, boundary: string): Promise<void> {\n await this.assertManagedDirectory(boundary)\n const relative = path.relative(boundary, directory)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"Directory is outside the project boundary\")\n let current = boundary\n for (const segment of relative.split(path.sep).filter(Boolean)) {\n current = path.join(current, segment)\n try {\n await mkdir(current)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error\n }\n const metadata = await lstat(current)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new Error(\"Project directories cannot be symbolic links\")\n }\n await this.assertContained(await realpath(directory), boundary, true)\n }\n\n private async assertSafeWriteTarget(target: string, boundary: string): Promise<void> {\n await this.assertManagedDirectory(boundary)\n const relative = path.relative(boundary, target)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"File is outside the project boundary\")\n try {\n const metadata = await lstat(target)\n if (metadata.isSymbolicLink() || !metadata.isFile()) throw new Error(\"Project files must be regular files\")\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n }\n\n private async readManagedFile(filename: string, boundary: string): Promise<Buffer>\n private async readManagedFile(filename: string, boundary: string, encoding: BufferEncoding): Promise<string>\n private async readManagedFile(filename: string, boundary: string, encoding?: BufferEncoding): Promise<Buffer | string> {\n await this.assertRegularFile(filename)\n await this.assertContained(await realpath(filename), boundary)\n return encoding ? readFile(filename, encoding) : readFile(filename)\n }\n\n private async assertRegularFile(filename: string): Promise<void> {\n const metadata = await lstat(filename)\n if (!metadata.isFile() || metadata.isSymbolicLink()) throw new Error(\"Project files must be regular files\")\n }\n\n private async assertContained(candidate: string, boundary: string, allowEqual = false): Promise<void> {\n const resolvedBoundary = await realpath(boundary)\n if ((allowEqual && candidate === resolvedBoundary) || candidate.startsWith(`${resolvedBoundary}${path.sep}`)) return\n throw new Error(\"File is outside the project boundary\")\n }\n\n private assertMockupImportId(importId: string): void {\n if (!safeIdentifierPattern.test(importId)) throw new Error(\"Unsupported mockup import id\")\n }\n\n private resolveSet(id: string): string {\n if (!safeIdentifierPattern.test(id)) throw new Error(\"Unsupported set id\")\n return path.join(this.setsPath, `${id}.json`)\n }\n}\n\ntype AssetMetadata = Record<string, { deviceType: ScreenshotDeviceType }>\n\nexport class DuplicateAssetError extends Error {\n constructor(readonly existingAssetId: string) {\n super(`This file is already in the asset catalog as ${existingAssetId}`)\n }\n}\n\nfunction hash(contents: Buffer): string {\n return createHash(\"sha256\").update(contents).digest(\"hex\")\n}\n\nexport function parseStoreShotConfig(value: unknown): StoreShotConfig {\n if (!isRecord(value)) throw new Error(\"storeshot.json must contain a JSON object\")\n if (value.version !== 1) throw new Error(\"Unsupported storeshot.json version\")\n\n const appName = readString(value.appName, \"appName\")\n if (!Array.isArray(value.platforms) || value.platforms.length === 0\n || value.platforms.some((platform) => platform !== \"ios\" && platform !== \"android\")) {\n throw new Error(\"platforms must contain only ios or android\")\n }\n const platforms = value.platforms as Array<\"ios\" | \"android\">\n\n return { version: 1, appName, platforms: [...new Set(platforms)] }\n}\n\nfunction parseCreateSetInput(value: unknown): CreateSetInput {\n if (!isRecord(value)) throw new Error(\"Set details must be an object\")\n return {\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n width: readDimension(value.width, \"Canvas width\"),\n height: readDimension(value.height, \"Canvas height\"),\n }\n}\n\nfunction duplicateName(sourceName: string, existingNames: string[]): string {\n const names = new Set(existingNames.map((name) => name.toLocaleLowerCase()))\n const baseName = `${sourceName} copy`\n if (!names.has(baseName.toLocaleLowerCase())) return baseName\n\n let copyNumber = 2\n while (names.has(`${baseName} ${copyNumber}`.toLocaleLowerCase())) copyNumber += 1\n return `${baseName} ${copyNumber}`\n}\n\nfunction parseSetMetadataInput(value: unknown): UpdateSetMetadataInput {\n if (!isRecord(value)) throw new Error(\"Set settings must be an object\")\n return {\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n }\n}\n\nexport function parseScreenshotSet(value: unknown): ScreenshotSet {\n if (!isRecord(value)) throw new Error(\"Set file must contain an object\")\n if (value.version !== 1) throw new Error(\"Unsupported set file version\")\n\n const id = readString(value.id, \"Set id\")\n if (!safeIdentifierPattern.test(id)) throw new Error(\"Set id is invalid\")\n if (!isRecord(value.canvas)) throw new Error(\"Set canvas is invalid\")\n if (!Array.isArray(value.areas) || value.areas.length === 0) throw new Error(\"A set needs at least one screenshot area\")\n\n return {\n version: 1,\n id,\n name: readString(value.name, \"Set name\"),\n locale: readString(value.locale, \"Locale\"),\n device: readString(value.device, \"Device\"),\n canvas: {\n width: readDimension(value.canvas.width, \"Canvas width\"),\n height: readDimension(value.canvas.height, \"Canvas height\"),\n },\n areas: value.areas.map(parseArea),\n createdAt: readString(value.createdAt, \"Created time\"),\n updatedAt: readString(value.updatedAt, \"Updated time\"),\n }\n}\n\nfunction parseArea(value: unknown): ScreenshotArea {\n if (!isRecord(value)) throw new Error(\"Screenshot area is invalid\")\n const background = readString(value.background, \"Area background\")\n if (!hexColorPattern.test(background)) throw new Error(\"Area background must be a hex color\")\n if (!Array.isArray(value.elements)) throw new Error(\"Area elements must be an array\")\n return {\n id: readString(value.id, \"Area id\"),\n name: readString(value.name, \"Area name\"),\n background,\n elements: value.elements.map(parseElement),\n }\n}\n\nfunction parseImageSource(value: unknown, legacyAssetId?: unknown): ImageElementSource {\n if (isRecord(value)) {\n if (value.kind === \"builtin\") return { kind: \"builtin\", id: readString(value.id, \"Built-in artwork id\") }\n if (value.kind === \"asset\") return { kind: \"asset\", assetId: readString(value.assetId, \"Asset id\") }\n throw new Error(\"Image source type is invalid\")\n }\n if (legacyAssetId !== undefined) return { kind: \"asset\", assetId: readString(legacyAssetId, \"Asset id\") }\n throw new Error(\"Image source is invalid\")\n}\n\nfunction parseElement(value: unknown): CanvasElement {\n if (!isRecord(value)) throw new Error(\"Canvas element is invalid\")\n const base = {\n id: readString(value.id, \"Element id\"),\n x: readNumber(value.x, \"Element x\"),\n y: readNumber(value.y, \"Element y\"),\n width: readDimension(value.width, \"Element width\"),\n height: readDimension(value.height, \"Element height\"),\n rotation: readNumber(value.rotation, \"Element rotation\"),\n opacity: readOptionalRange(value.opacity, 1, 0, 1, \"Element opacity\"),\n flipX: readOptionalBoolean(value.flipX, false, \"Element horizontal flip\"),\n flipY: readOptionalBoolean(value.flipY, false, \"Element vertical flip\"),\n }\n\n if (value.type === \"image\") {\n if (value.fit !== \"contain\" && value.fit !== \"cover\") throw new Error(\"Image fit is invalid\")\n const source = parseImageSource(value.source, value.assetId)\n const fill = value.fill === undefined ? undefined : readString(value.fill, \"Image fill\")\n if (fill !== undefined && !hexColorPattern.test(fill)) throw new Error(\"Image fill must be a hex color\")\n return { ...base, type: \"image\", source, fit: value.fit, ...(fill === undefined ? {} : { fill }) }\n }\n\n if (value.type === \"mockup\") {\n return {\n ...base,\n type: \"mockup\",\n mockupId: readString(value.mockupId, \"Device mockup id\"),\n assetId: readString(value.assetId, \"Asset id\"),\n }\n }\n\n if (value.type === \"element\") {\n const source = parseImageSource(value.source)\n const fill = value.fill === undefined ? undefined : readString(value.fill, \"Image fill\")\n if (fill !== undefined && !hexColorPattern.test(fill)) throw new Error(\"Image fill must be a hex color\")\n return {\n ...base,\n type: \"image\",\n source,\n fit: \"contain\",\n ...(fill === undefined ? {} : { fill }),\n }\n }\n\n if (value.type === \"text\") {\n const fontWeight = Number(value.fontWeight)\n if (!Number.isInteger(fontWeight) || fontWeight < 100 || fontWeight > 900 || fontWeight % 100 !== 0) {\n throw new Error(\"Text weight is invalid\")\n }\n if (value.textAlign !== \"left\" && value.textAlign !== \"center\" && value.textAlign !== \"right\") {\n throw new Error(\"Text alignment is invalid\")\n }\n const color = readString(value.color, \"Text color\")\n if (!hexColorPattern.test(color)) throw new Error(\"Text color must be a hex color\")\n const lineHeight = value.lineHeight === undefined\n ? undefined\n : readDimension(value.lineHeight, \"Text line height\")\n return {\n ...base,\n type: \"text\",\n text: typeof value.text === \"string\" ? value.text : \"\",\n fontFamily: readOptionalString(value.fontFamily, \"Geist Variable\"),\n fontSize: readDimension(value.fontSize, \"Font size\"),\n fontWeight: fontWeight as FontWeight,\n ...(lineHeight === undefined ? {} : { lineHeight }),\n color,\n textAlign: value.textAlign,\n }\n }\n\n if (value.type === \"shape\") {\n if (value.shape !== \"rectangle\") throw new Error(\"Shape type is invalid\")\n const fill = readString(value.fill, \"Shape fill\")\n if (!hexColorPattern.test(fill)) throw new Error(\"Shape fill must be a hex color\")\n return {\n ...base,\n type: \"shape\",\n shape: value.shape,\n fill,\n cornerRadius: readOptionalRange(value.cornerRadius, 0, 0, 10_000, \"Shape corner radius\"),\n }\n }\n\n throw new Error(\"Unsupported canvas element type\")\n}\n\nfunction readString(value: unknown, name: string): string {\n const result = typeof value === \"string\" ? value.trim() : \"\"\n if (!result) throw new Error(`${name} must be a non-empty string`)\n return result\n}\n\nfunction readNumber(value: unknown, name: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new Error(`${name} must be a number`)\n return value\n}\n\nfunction readOptionalRange(value: unknown, fallback: number, min: number, max: number, name: string): number {\n if (value === undefined) return fallback\n const result = readNumber(value, name)\n if (result < min || result > max) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction readOptionalBoolean(value: unknown, fallback: boolean, name: string): boolean {\n if (value === undefined) return fallback\n if (typeof value !== \"boolean\") throw new Error(`${name} must be a boolean`)\n return value\n}\n\nfunction readOptionalString(value: unknown, fallback: string): string {\n return typeof value === \"string\" && value.trim() ? value.trim() : fallback\n}\n\nfunction readDimension(value: unknown, name: string): number {\n const result = readNumber(value, name)\n if (result <= 0 || result > 20_000) throw new Error(`${name} is outside the supported range`)\n return result\n}\n\nfunction isAssetCategory(value: string): value is AssetCategory {\n return ASSET_CATEGORIES.includes(value as AssetCategory)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction slugify(value: string): string {\n const result = value\n .normalize(\"NFKD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n return result || \"set\"\n}\n\nasync function writeJson(filename: string, value: unknown): Promise<void> {\n await writeFileAtomically(filename, `${JSON.stringify(value, null, 2)}\\n`)\n}\n\nasync function writeFileAtomically(filename: string, contents: Buffer | string): Promise<void> {\n const temporary = path.join(path.dirname(filename), `.${path.basename(filename)}.${randomUUID()}.tmp`)\n try {\n await writeFile(temporary, contents, { flag: \"wx\" })\n await rename(temporary, filename)\n } finally {\n await unlink(temporary).catch((error: NodeJS.ErrnoException) => {\n if (error.code !== \"ENOENT\") throw error\n })\n }\n}\n\nfunction isImageFile(filename: string): boolean {\n return supportedExtensions.has(path.extname(filename).toLowerCase())\n}\n\nfunction assertValidImage(filename: string, contents: Buffer): void {\n if (!isImageFile(filename) || !readImageMetadata(contents)) throw new Error(\"The uploaded file is not a valid supported image\")\n}\n","import type { DetectedScreenshotDeviceType } from \"./shared.js\"\n\nexport interface ImageMetadata {\n width: number\n height: number\n}\n\nexport function readImageMetadata(contents: Buffer): ImageMetadata | undefined {\n return readPngMetadata(contents) ?? readJpegMetadata(contents) ?? readWebpMetadata(contents) ?? readSvgMetadata(contents)\n}\n\nfunction readSvgMetadata(contents: Buffer): ImageMetadata | undefined {\n const source = contents.subarray(0, 64 * 1024).toString(\"utf8\")\n const svg = source.match(/<svg\\b[^>]*>/i)?.[0]\n if (!svg) return undefined\n\n const width = readSvgLength(svg, \"width\")\n const height = readSvgLength(svg, \"height\")\n if (width && height) return validDimensions(width, height)\n\n const viewBox = svg.match(/\\bviewBox\\s*=\\s*[\"']\\s*([-+\\d.e]+)[\\s,]+([-+\\d.e]+)[\\s,]+([-+\\d.e]+)[\\s,]+([-+\\d.e]+)\\s*[\"']/i)\n if (!viewBox) return undefined\n return validDimensions(Number(viewBox[3]), Number(viewBox[4]))\n}\n\nfunction readSvgLength(svg: string, attribute: \"height\" | \"width\"): number | undefined {\n const match = svg.match(new RegExp(`\\\\b${attribute}\\\\s*=\\\\s*[\"']\\\\s*([-+\\\\d.e]+)`, \"i\"))\n const value = match ? Number(match[1]) : NaN\n return Number.isFinite(value) && value > 0 ? value : undefined\n}\n\nexport function detectScreenshotDeviceType(width: number, height: number): DetectedScreenshotDeviceType {\n const shortSide = Math.min(width, height)\n const longSide = Math.max(width, height)\n const ratio = longSide / shortSide\n const dimensions = `${shortSide}x${longSide}`\n\n if (WATCH_SCREENSHOT_DIMENSIONS.has(dimensions)) return \"watch\"\n if (IPAD_SCREENSHOT_DIMENSIONS.has(dimensions)) return \"ipad\"\n if (IPHONE_SCREENSHOT_DIMENSIONS.has(dimensions) && (height > width || longSide >= 2_200)) return \"iphone\"\n if (longSide <= 700 && ratio <= 1.4) return \"watch\"\n if (shortSide >= 1_400 && ratio >= 1.25 && ratio <= 1.45) return \"ipad\"\n if (height > width && ratio >= 1.65) return \"iphone\"\n if (width > height && ratio >= 1.45) return \"mac\"\n if (shortSide >= 1_000 && ratio >= 1.25 && ratio <= 1.45) return \"ipad\"\n return \"unknown\"\n}\n\nconst IPHONE_SCREENSHOT_DIMENSIONS = new Set([\n \"640x1136\", \"750x1334\", \"828x1792\", \"1080x1920\", \"1125x2436\", \"1170x2532\",\n \"1179x2556\", \"1206x2622\", \"1242x2208\", \"1242x2688\", \"1284x2778\", \"1290x2796\", \"1320x2868\",\n])\nconst IPAD_SCREENSHOT_DIMENSIONS = new Set([\n \"1536x2048\", \"1668x2224\", \"1668x2388\", \"2048x2732\", \"2064x2752\",\n])\nconst WATCH_SCREENSHOT_DIMENSIONS = new Set([\n \"368x448\", \"396x484\", \"416x496\", \"422x514\",\n])\n\nfunction readPngMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 24 || contents.toString(\"ascii\", 1, 4) !== \"PNG\") return undefined\n return validDimensions(contents.readUInt32BE(16), contents.readUInt32BE(20))\n}\n\nfunction readJpegMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 4 || contents[0] !== 0xff || contents[1] !== 0xd8) return undefined\n let offset = 2\n while (offset + 8 < contents.length) {\n if (contents[offset] !== 0xff) {\n offset += 1\n continue\n }\n const marker = contents[offset + 1]\n offset += 2\n if (marker === 0xd8 || marker === 0xd9) continue\n if (offset + 2 > contents.length) return undefined\n const length = contents.readUInt16BE(offset)\n if (length < 2 || offset + length > contents.length) return undefined\n if (isJpegStartOfFrame(marker) && length >= 7) {\n return validDimensions(contents.readUInt16BE(offset + 5), contents.readUInt16BE(offset + 3))\n }\n offset += length\n }\n return undefined\n}\n\nfunction isJpegStartOfFrame(marker: number): boolean {\n return marker >= 0xc0 && marker <= 0xcf && ![0xc4, 0xc8, 0xcc].includes(marker)\n}\n\nfunction readWebpMetadata(contents: Buffer): ImageMetadata | undefined {\n if (contents.length < 30 || contents.toString(\"ascii\", 0, 4) !== \"RIFF\" || contents.toString(\"ascii\", 8, 12) !== \"WEBP\") return undefined\n const type = contents.toString(\"ascii\", 12, 16)\n if (type === \"VP8X\") {\n return validDimensions(readUInt24LE(contents, 24) + 1, readUInt24LE(contents, 27) + 1)\n }\n if (type === \"VP8 \" && contents.length >= 30 && contents[23] === 0x9d && contents[24] === 0x01 && contents[25] === 0x2a) {\n return validDimensions(contents.readUInt16LE(26) & 0x3fff, contents.readUInt16LE(28) & 0x3fff)\n }\n if (type === \"VP8L\" && contents.length >= 25 && contents[20] === 0x2f) {\n const bits = contents.readUInt32LE(21)\n return validDimensions((bits & 0x3fff) + 1, ((bits >>> 14) & 0x3fff) + 1)\n }\n return undefined\n}\n\nfunction readUInt24LE(contents: Buffer, offset: number): number {\n return contents[offset] | (contents[offset + 1] << 8) | (contents[offset + 2] << 16)\n}\n\nfunction validDimensions(width: number, height: number): ImageMetadata | undefined {\n return width > 0 && height > 0 ? { width, height } : undefined\n}\n","import type { CanvasElement, ScreenshotArea } from \"./shared.js\"\n\nexport type IdFactory = () => string\n\ninterface CloneElementOptions {\n idFactory?: IdFactory\n offsetX?: number\n offsetY?: number\n}\n\ninterface CloneAreaOptions {\n idFactory?: IdFactory\n name?: string\n}\n\nconst defaultIdFactory: IdFactory = () => globalThis.crypto.randomUUID()\n\nexport function cloneCanvasElement(\n element: CanvasElement,\n { idFactory = defaultIdFactory, offsetX = 0, offsetY = 0 }: CloneElementOptions = {},\n): CanvasElement {\n return {\n ...structuredClone(element),\n id: `element-${idFactory()}`,\n x: element.x + offsetX,\n y: element.y + offsetY,\n }\n}\n\nexport function cloneScreenshotArea(\n area: ScreenshotArea,\n { idFactory = defaultIdFactory, name = area.name }: CloneAreaOptions = {},\n): ScreenshotArea {\n return {\n ...structuredClone(area),\n id: `area-${idFactory()}`,\n name,\n elements: area.elements.map((element) => cloneCanvasElement(element, { idFactory })),\n }\n}\n","import { createReadStream, watch, type FSWatcher } from \"node:fs\"\nimport { readFile, stat } from \"node:fs/promises\"\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport type { AddressInfo } from \"node:net\"\nimport path from \"node:path\"\n\nimport type { ViteDevServer } from \"vite\"\n\nimport { DuplicateAssetError, ProjectStore } from \"./project-store.js\"\nimport type { StoreShotConfig, AssetCategory, CreateSetInput, ScreenshotSet, UpdateAssetMetadataInput, UpdateSetMetadataInput } from \"./shared.js\"\n\nconst MAX_REQUEST_BYTES = 25 * 1024 * 1024\n\ninterface StartServerOptions {\n host: string\n port: number\n packageRoot: string\n projectDirectory: string\n useVite: boolean\n}\n\nexport async function startServer(options: StartServerOptions) {\n const store = new ProjectStore(options.projectDirectory)\n await store.initialize()\n const projectEvents = new ProjectEventHub(store.root)\n\n let vite: ViteDevServer | undefined\n if (options.useVite) {\n const { createServer: createViteServer } = await import(\"vite\")\n vite = await createViteServer({\n configFile: path.join(options.packageRoot, \"vite.config.ts\"),\n server: { middlewareMode: true },\n appType: \"spa\",\n })\n }\n\n const server = createServer(async (request, response) => {\n try {\n if ((request.url ?? \"\").startsWith(\"/api/\")) assertAllowedBrowserRequest(request, options.host)\n if (await handleApiRequest(request, response, store, projectEvents)) return\n if (vite) {\n vite.middlewares(request, response)\n return\n }\n await serveBuiltFrontend(request, response, path.join(options.packageRoot, \"dist/ui\"))\n } catch (error) {\n const failure = httpFailureFor(error, request)\n if (failure.status >= 500) console.error(error)\n if (!response.headersSent) sendJson(response, failure.status, { error: failure.message, ...(failure.code ? { code: failure.code } : {}) })\n else response.end()\n }\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(options.port, options.host, resolve)\n })\n\n return {\n store,\n port: (server.address() as AddressInfo).port,\n close: async () => {\n projectEvents.close()\n await vite?.close()\n await new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()))\n })\n },\n }\n}\n\nasync function handleApiRequest(\n request: IncomingMessage,\n response: ServerResponse,\n store: ProjectStore,\n projectEvents: ProjectEventHub,\n): Promise<boolean> {\n const url = new URL(request.url ?? \"/\", \"http://localhost\")\n\n if (request.method === \"GET\" && url.pathname === \"/api/events\") {\n projectEvents.subscribe(request, response)\n return true\n }\n\n if (request.method === \"GET\" && url.pathname === \"/api/project\") {\n sendJson(response, 200, await store.readProject())\n return true\n }\n\n if (request.method === \"GET\" && url.pathname === \"/api/mockup-bundles\") {\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleImportFileMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)\\/([^/]+)\\/files\\/(.+)$/)\n if (request.method === \"PUT\" && mockupBundleImportFileMatch) {\n const importId = decodeURIComponent(mockupBundleImportFileMatch[1])\n const bundleId = decodeURIComponent(mockupBundleImportFileMatch[2])\n const relativePath = mockupBundleImportFileMatch[3].split(\"/\").map(decodeURIComponent).join(\"/\")\n await store.writeMockupBundleImportFile(importId, bundleId, relativePath, await readBody(request))\n response.writeHead(204).end()\n return true\n }\n\n const mockupBundleImportMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)\\/([^/]+)$/)\n if (request.method === \"PUT\" && mockupBundleImportMatch) {\n const importId = decodeURIComponent(mockupBundleImportMatch[1])\n const bundleId = decodeURIComponent(mockupBundleImportMatch[2])\n await store.commitMockupBundleImport(importId, bundleId, await readJsonBody(request))\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleImportDiscardMatch = url.pathname.match(/^\\/api\\/mockup-bundle-imports\\/([^/]+)$/)\n if (request.method === \"DELETE\" && mockupBundleImportDiscardMatch) {\n await store.discardMockupBundleImport(decodeURIComponent(mockupBundleImportDiscardMatch[1]))\n response.writeHead(204).end()\n return true\n }\n\n const mockupBundleMatch = url.pathname.match(/^\\/api\\/mockup-bundles\\/([^/]+)$/)\n if (request.method === \"PUT\" && mockupBundleMatch) {\n const bundleId = decodeURIComponent(mockupBundleMatch[1])\n await store.writeMockupBundleManifest(bundleId, await readJsonBody(request))\n sendJson(response, 200, await store.listMockupCatalog())\n return true\n }\n\n const mockupBundleFileMatch = url.pathname.match(/^\\/api\\/mockup-bundle-files\\/([^/]+)\\/(.+)$/)\n if (mockupBundleFileMatch) {\n const bundleId = decodeURIComponent(mockupBundleFileMatch[1])\n const relativePath = mockupBundleFileMatch[2].split(\"/\").map(decodeURIComponent).join(\"/\")\n if (request.method === \"PUT\") {\n await store.writeMockupBundleFile(bundleId, relativePath, await readBody(request))\n response.writeHead(204).end()\n return true\n }\n if (request.method === \"GET\") {\n const target = await store.resolveExistingMockupBundleFile(bundleId, relativePath)\n const metadata = await stat(target)\n response.writeHead(200, {\n \"Content-Type\": contentTypeFor(target),\n \"Content-Length\": metadata.size,\n \"Cache-Control\": \"no-store\",\n \"X-Content-Type-Options\": \"nosniff\",\n ...(path.extname(target).toLowerCase() === \".svg\" ? { \"Content-Security-Policy\": \"default-src 'none'; style-src 'unsafe-inline'; sandbox\" } : {}),\n })\n createReadStream(target).pipe(response)\n return true\n }\n }\n\n if (request.method === \"PATCH\" && url.pathname === \"/api/config\") {\n const config = await store.writeConfig((await readJsonBody(request)) as StoreShotConfig)\n sendJson(response, 200, config)\n return true\n }\n\n if (request.method === \"POST\" && url.pathname === \"/api/assets\") {\n const category = url.searchParams.get(\"category\")\n const filename = url.searchParams.get(\"filename\")\n if (!category || !filename) {\n sendJson(response, 400, { error: \"A category and filename are required\" })\n return true\n }\n let replaced = false\n try {\n const result = await store.addAsset(category, filename, await readBody(request))\n replaced = result.replaced\n } catch (error) {\n if (error instanceof DuplicateAssetError) {\n sendJson(response, 409, { error: error.message, code: \"DUPLICATE_ASSET\" })\n return true\n }\n throw error\n }\n sendJson(response, replaced ? 200 : 201, { replaced })\n return true\n }\n\n const assetMatch = url.pathname.match(/^\\/api\\/assets\\/([^/]+)\\/([^/]+)$/)\n if (assetMatch) {\n const category = decodeURIComponent(assetMatch[1]) as AssetCategory\n const filename = decodeURIComponent(assetMatch[2])\n if (request.method === \"GET\") {\n const target = await store.resolveExistingAsset(category, filename)\n const metadata = await stat(target)\n response.writeHead(200, {\n \"Content-Type\": contentTypeFor(target),\n \"Content-Length\": metadata.size,\n \"Cache-Control\": \"no-store\",\n \"X-Content-Type-Options\": \"nosniff\",\n ...(path.extname(target).toLowerCase() === \".svg\" ? { \"Content-Security-Policy\": \"default-src 'none'; style-src 'unsafe-inline'; sandbox\" } : {}),\n })\n createReadStream(target).pipe(response)\n return true\n }\n\n if (request.method === \"DELETE\") {\n await store.deleteAsset(category, filename)\n response.writeHead(204).end()\n return true\n }\n\n if (request.method === \"PATCH\") {\n await store.updateAssetMetadata(category, filename, (await readJsonBody(request)) as UpdateAssetMetadataInput)\n sendJson(response, 200, await store.readProject())\n return true\n }\n }\n\n if (request.method === \"POST\" && url.pathname === \"/api/sets\") {\n const set = await store.createSet((await readJsonBody(request)) as CreateSetInput)\n sendJson(response, 201, set)\n return true\n }\n\n const duplicateSetMatch = url.pathname.match(/^\\/api\\/sets\\/([^/]+)\\/duplicate$/)\n if (request.method === \"POST\" && duplicateSetMatch) {\n const set = await store.duplicateSet(decodeURIComponent(duplicateSetMatch[1]))\n sendJson(response, 201, set)\n return true\n }\n\n const setMatch = url.pathname.match(/^\\/api\\/sets\\/([^/]+)$/)\n if (setMatch) {\n const id = decodeURIComponent(setMatch[1])\n if (request.method === \"PATCH\") {\n const set = await store.updateSetMetadata(id, (await readJsonBody(request)) as UpdateSetMetadataInput)\n sendJson(response, 200, set)\n return true\n }\n if (request.method === \"PUT\") {\n const set = await store.writeSet(id, (await readJsonBody(request)) as ScreenshotSet)\n sendJson(response, 200, set)\n return true\n }\n if (request.method === \"DELETE\") {\n await store.deleteSet(id)\n response.writeHead(204).end()\n return true\n }\n }\n\n if (url.pathname.startsWith(\"/api/\")) {\n sendJson(response, 404, { error: \"Not found\" })\n return true\n }\n return false\n}\n\nasync function serveBuiltFrontend(request: IncomingMessage, response: ServerResponse, uiDirectory: string) {\n const url = new URL(request.url ?? \"/\", \"http://localhost\")\n const relativePath = url.pathname === \"/\" ? \"index.html\" : decodeURIComponent(url.pathname.slice(1))\n const candidate = path.resolve(uiDirectory, relativePath)\n const safeRoot = `${path.resolve(uiDirectory)}${path.sep}`\n const target = candidate.startsWith(safeRoot) ? candidate : path.join(uiDirectory, \"index.html\")\n\n try {\n const metadata = await stat(target)\n if (!metadata.isFile()) throw new Error(\"Not a file\")\n const body = await readFile(target)\n response.writeHead(200, { \"Content-Type\": contentTypeFor(target), \"Content-Length\": body.length })\n response.end(body)\n } catch {\n const body = await readFile(path.join(uiDirectory, \"index.html\"))\n response.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n response.end(body)\n }\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n const contentType = request.headers[\"content-type\"]?.split(\";\", 1)[0]?.trim().toLowerCase()\n if (contentType !== \"application/json\") throw new HttpError(415, \"Request body must use application/json\")\n const body = await readBody(request)\n try {\n return JSON.parse(body.toString(\"utf8\"))\n } catch {\n throw new HttpError(400, \"Request body must be valid JSON\")\n }\n}\n\nasync function readBody(request: IncomingMessage): Promise<Buffer> {\n const chunks: Buffer[] = []\n let size = 0\n for await (const chunk of request) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n size += buffer.length\n if (size > MAX_REQUEST_BYTES) throw new HttpError(413, \"Request is larger than 25 MB\")\n chunks.push(buffer)\n }\n return Buffer.concat(chunks)\n}\n\nclass HttpError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nfunction assertAllowedBrowserRequest(request: IncomingMessage, configuredHost: string): void {\n const host = request.headers.host\n if (!host) throw new HttpError(400, \"A Host header is required\")\n\n let hostUrl: URL\n try {\n hostUrl = new URL(`http://${host}`)\n } catch {\n throw new HttpError(400, \"The Host header is invalid\")\n }\n const configuredHostname = normalizedHostname(configuredHost)\n if (!isLoopbackHostname(hostUrl.hostname) && hostUrl.hostname !== configuredHostname) {\n throw new HttpError(403, \"This StoreShot server does not accept requests for that host\")\n }\n\n const origin = request.headers.origin\n if (!origin) return\n let originUrl: URL\n try {\n originUrl = new URL(origin)\n } catch {\n throw new HttpError(403, \"The request origin is invalid\")\n }\n if ((originUrl.protocol !== \"http:\" && originUrl.protocol !== \"https:\") || originUrl.host !== host) {\n throw new HttpError(403, \"Cross-origin API requests are not allowed\")\n }\n}\n\nfunction normalizedHostname(host: string): string {\n try {\n return new URL(`http://${host}`).hostname\n } catch {\n return host.replace(/^\\[|\\]$/g, \"\")\n }\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n return hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\"\n}\n\nfunction httpFailureFor(error: unknown, request: IncomingMessage): HttpError {\n if (error instanceof HttpError) return error\n if (error instanceof DuplicateAssetError) return new HttpError(409, error.message, \"DUPLICATE_ASSET\")\n const code = (error as NodeJS.ErrnoException | undefined)?.code\n if (code === \"ENOENT\") return new HttpError(404, \"The requested project file was not found\")\n if (code === \"EACCES\" || code === \"EPERM\") return new HttpError(403, \"StoreShot cannot access that project file\")\n if (isMutation(request) && error instanceof Error && !code) return new HttpError(400, error.message)\n return new HttpError(500, \"StoreShot could not complete the request\")\n}\n\nfunction isMutation(request: IncomingMessage): boolean {\n return request.method === \"POST\" || request.method === \"PUT\" || request.method === \"PATCH\" || request.method === \"DELETE\"\n}\n\nfunction sendJson(response: ServerResponse, status: number, value: unknown) {\n const body = JSON.stringify(value)\n response.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Content-Length\": Buffer.byteLength(body),\n })\n response.end(body)\n}\n\nfunction contentTypeFor(filename: string): string {\n switch (path.extname(filename).toLowerCase()) {\n case \".html\": return \"text/html; charset=utf-8\"\n case \".js\": return \"text/javascript; charset=utf-8\"\n case \".css\": return \"text/css; charset=utf-8\"\n case \".png\": return \"image/png\"\n case \".jpg\":\n case \".jpeg\": return \"image/jpeg\"\n case \".webp\": return \"image/webp\"\n case \".svg\": return \"image/svg+xml\"\n case \".md\":\n case \".txt\": return \"text/plain; charset=utf-8\"\n default: return \"application/octet-stream\"\n }\n}\n\ntype ProjectChangeScope = \"assets\" | \"config\" | \"mockups\" | \"project\" | \"sets\"\n\nclass ProjectEventHub {\n private readonly clients = new Set<ServerResponse>()\n private readonly scopes = new Set<ProjectChangeScope>()\n private readonly watcher: FSWatcher\n private readonly heartbeat: ReturnType<typeof setInterval>\n private broadcastTimer: ReturnType<typeof setTimeout> | undefined\n private revision = 0\n\n constructor(root: string) {\n this.watcher = watch(root, { recursive: true, encoding: \"utf8\" }, (_event, filename) => {\n const relativePath = typeof filename === \"string\" ? filename.split(path.sep).join(\"/\") : \"\"\n const scope = changeScope(relativePath)\n if (!scope) return\n this.scopes.add(scope)\n if (this.broadcastTimer) clearTimeout(this.broadcastTimer)\n this.broadcastTimer = setTimeout(() => this.broadcast(), 75)\n })\n this.watcher.on(\"error\", (error) => console.error(\"StoreShot project watcher failed\", error))\n this.heartbeat = setInterval(() => {\n for (const response of this.clients) response.write(\": keep-alive\\n\\n\")\n }, 15_000)\n this.heartbeat.unref()\n }\n\n subscribe(request: IncomingMessage, response: ServerResponse): void {\n response.writeHead(200, {\n \"Content-Type\": \"text/event-stream; charset=utf-8\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n })\n response.write(`event: ready\\ndata: ${JSON.stringify({ revision: this.revision })}\\n\\n`)\n this.clients.add(response)\n request.once(\"close\", () => this.clients.delete(response))\n }\n\n close(): void {\n if (this.broadcastTimer) clearTimeout(this.broadcastTimer)\n clearInterval(this.heartbeat)\n this.watcher.close()\n for (const response of this.clients) response.end()\n this.clients.clear()\n }\n\n private broadcast(): void {\n this.broadcastTimer = undefined\n if (this.scopes.size === 0) return\n this.revision += 1\n const data = JSON.stringify({ revision: this.revision, scopes: [...this.scopes].sort() })\n this.scopes.clear()\n for (const response of this.clients) response.write(`event: project\\ndata: ${data}\\n\\n`)\n }\n}\n\nfunction changeScope(relativePath: string): ProjectChangeScope | undefined {\n if (!relativePath) return \"project\"\n if (relativePath === \"storeshot.json\" || relativePath.startsWith(\".storeshot.json.\")) return \"config\"\n if (relativePath === \"sets\" || relativePath.startsWith(\"sets/\")) return \"sets\"\n if (relativePath === \"assets\" || relativePath.startsWith(\"assets/\")) return \"assets\"\n if (relativePath.startsWith(\"mockup-bundles/.imports/\")) return undefined\n if (relativePath === \"mockup-bundles\" || relativePath.startsWith(\"mockup-bundles/\")) return \"mockups\"\n if (relativePath === \"renders\" || relativePath.startsWith(\"renders/\")) return undefined\n return \"project\"\n}\n","import { lstat, readFile, readdir } from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport { BUILT_IN_ARTWORK } from \"./artwork.js\"\nimport {\n MOCKUP_BUNDLE_FILENAME,\n mergeDeviceMockupCatalogs,\n parseMockupBundleManifest,\n resolveMockupBundle,\n type DeviceMockupCatalog,\n} from \"./device-mockups.js\"\nimport { resolvePackagePublicDirectory } from \"./package-assets.js\"\nimport {\n ASSETS_DIRECTORY,\n CONFIG_FILENAME,\n MOCKUP_BUNDLES_DIRECTORY,\n ProjectStore,\n SETS_DIRECTORY,\n parseScreenshotSet,\n parseStoreShotConfig,\n} from \"./project-store.js\"\nimport type { Asset, AssetCategory, ScreenshotSet, StoreShotConfig } from \"./shared.js\"\n\nexport type ValidationSeverity = \"error\" | \"warning\"\n\nexport interface ValidationIssue {\n severity: ValidationSeverity\n code: string\n path: string\n message: string\n}\n\nexport interface ValidationReport {\n ok: boolean\n directory: string\n errors: ValidationIssue[]\n warnings: ValidationIssue[]\n summary: {\n assets: number\n sets: number\n screenshots: number\n areas: number\n }\n}\n\nexport interface ProjectValidation {\n report: ValidationReport\n config?: StoreShotConfig\n assets?: Record<AssetCategory, Asset[]>\n sets: ScreenshotSet[]\n mockupCatalog?: DeviceMockupCatalog\n}\n\nexport async function validateProject(directory: string, packageRoot: string): Promise<ProjectValidation> {\n const root = path.resolve(directory)\n const issues: ValidationIssue[] = []\n const store = new ProjectStore(root)\n let config: StoreShotConfig | undefined\n let assets: Record<AssetCategory, Asset[]> | undefined\n let mockupCatalog: DeviceMockupCatalog | undefined\n const sets: ScreenshotSet[] = []\n\n if (!await checkDirectory(root, \".\", issues)) return validationResult(root, issues, sets)\n\n const configPath = path.join(root, CONFIG_FILENAME)\n try {\n config = parseStoreShotConfig(JSON.parse(await readRegularFile(configPath, root)))\n } catch (error) {\n issues.push(issue(\"error\", \"config.invalid\", CONFIG_FILENAME, messageFor(error)))\n }\n\n const assetsReady = await checkDirectory(path.join(root, ASSETS_DIRECTORY), ASSETS_DIRECTORY, issues)\n const setsReady = await checkDirectory(path.join(root, SETS_DIRECTORY), SETS_DIRECTORY, issues)\n const mockupsReady = await checkDirectory(path.join(root, MOCKUP_BUNDLES_DIRECTORY), MOCKUP_BUNDLES_DIRECTORY, issues)\n\n if (setsReady) {\n const entries = await readdir(store.setsPath, { withFileTypes: true })\n for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {\n if (!entry.name.endsWith(\".json\")) continue\n const relativePath = `${SETS_DIRECTORY}/${entry.name}`\n if (!entry.isFile() || entry.isSymbolicLink()) {\n issues.push(issue(\"error\", \"set.notRegularFile\", relativePath, \"Set documents must be regular JSON files\"))\n continue\n }\n try {\n const set = parseScreenshotSet(JSON.parse(await readRegularFile(path.join(store.setsPath, entry.name), store.setsPath)))\n sets.push(set)\n if (entry.name !== `${set.id}.json`) {\n issues.push(issue(\"error\", \"set.filenameMismatch\", relativePath, `Set id ${set.id} must be stored in ${set.id}.json`))\n }\n } catch (error) {\n issues.push(issue(\"error\", \"set.invalid\", relativePath, messageFor(error)))\n }\n }\n }\n\n if (assetsReady) {\n try {\n assets = await store.listAssets()\n for (const asset of Object.values(assets).flat()) {\n if (!asset.width || !asset.height) {\n issues.push(issue(\"error\", \"asset.invalidImage\", `${ASSETS_DIRECTORY}/${asset.id}`, \"Asset is not a valid supported image\"))\n }\n }\n } catch (error) {\n issues.push(issue(\"error\", \"assets.invalid\", ASSETS_DIRECTORY, messageFor(error)))\n }\n }\n\n if (mockupsReady) {\n try {\n const [builtInCatalog, projectCatalog] = await Promise.all([\n loadBuiltInMockupCatalog(packageRoot),\n store.listMockupCatalog(),\n ])\n mockupCatalog = mergeDeviceMockupCatalogs(builtInCatalog, projectCatalog)\n } catch (error) {\n issues.push(issue(\"error\", \"mockups.invalid\", MOCKUP_BUNDLES_DIRECTORY, messageFor(error)))\n }\n }\n\n validateSetSemantics(sets, assets, mockupCatalog, issues)\n return validationResult(root, issues, sets, config, assets, mockupCatalog)\n}\n\nasync function loadBuiltInMockupCatalog(packageRoot: string): Promise<DeviceMockupCatalog> {\n const publicDirectory = await resolvePackagePublicDirectory(packageRoot)\n const bundleDirectory = path.join(publicDirectory, \"mockup-bundles/frameup-free\")\n const manifest = parseMockupBundleManifest(JSON.parse(await readRegularFile(\n path.join(bundleDirectory, MOCKUP_BUNDLE_FILENAME),\n bundleDirectory,\n )))\n return resolveMockupBundle(manifest, \"/mockup-bundles/frameup-free/\", \"built-in\")\n}\n\nfunction validateSetSemantics(\n sets: ScreenshotSet[],\n assets: Record<AssetCategory, Asset[]> | undefined,\n mockupCatalog: DeviceMockupCatalog | undefined,\n issues: ValidationIssue[],\n): void {\n const setIds = new Set<string>()\n const assetIds = new Set(Object.values(assets ?? {}).flat().map((asset) => asset.id))\n const mockupIds = new Set(mockupCatalog?.mockups.map((mockup) => mockup.id) ?? [])\n const artworkIds = new Set(BUILT_IN_ARTWORK.map((artwork) => artwork.id))\n\n for (const set of sets) {\n const setPath = `${SETS_DIRECTORY}/${set.id}.json`\n if (setIds.has(set.id)) issues.push(issue(\"error\", \"set.duplicateId\", setPath, `Duplicate set id: ${set.id}`))\n setIds.add(set.id)\n\n try {\n Intl.getCanonicalLocales(set.locale)\n } catch {\n issues.push(issue(\"warning\", \"set.locale\", setPath, `${set.locale} is not a recognized locale identifier`))\n }\n if (!isIsoTimestamp(set.createdAt)) issues.push(issue(\"warning\", \"set.createdAt\", setPath, \"createdAt should be an ISO 8601 timestamp\"))\n if (!isIsoTimestamp(set.updatedAt)) issues.push(issue(\"warning\", \"set.updatedAt\", setPath, \"updatedAt should be an ISO 8601 timestamp\"))\n if (set.areas.length > 10) issues.push(issue(\"warning\", \"set.areaCount\", setPath, \"Apple App Store sets normally contain at most 10 screenshots\"))\n\n const ids = new Set<string>()\n for (const area of set.areas) {\n if (ids.has(area.id)) issues.push(issue(\"error\", \"set.duplicateObjectId\", setPath, `Duplicate area or element id: ${area.id}`))\n ids.add(area.id)\n for (const element of area.elements) {\n if (ids.has(element.id)) issues.push(issue(\"error\", \"set.duplicateObjectId\", setPath, `Duplicate area or element id: ${element.id}`))\n ids.add(element.id)\n if (element.type === \"mockup\") {\n if (!assetIds.has(element.assetId)) issues.push(issue(\"error\", \"reference.asset\", setPath, `Element ${element.id} references missing asset ${element.assetId}`))\n if (!mockupIds.has(element.mockupId)) issues.push(issue(\"error\", \"reference.mockup\", setPath, `Element ${element.id} references missing mockup ${element.mockupId}`))\n } else if (element.type === \"image\" && element.source.kind === \"asset\" && !assetIds.has(element.source.assetId)) {\n issues.push(issue(\"error\", \"reference.asset\", setPath, `Element ${element.id} references missing asset ${element.source.assetId}`))\n } else if (element.type === \"image\" && element.source.kind === \"builtin\" && !artworkIds.has(element.source.id)) {\n issues.push(issue(\"error\", \"reference.artwork\", setPath, `Element ${element.id} references missing built-in artwork ${element.source.id}`))\n }\n }\n }\n }\n}\n\nasync function checkDirectory(directory: string, displayPath: string, issues: ValidationIssue[]): Promise<boolean> {\n try {\n const metadata = await lstat(directory)\n if (!metadata.isDirectory() || metadata.isSymbolicLink()) throw new Error(\"must be a regular directory\")\n return true\n } catch (error) {\n issues.push(issue(\"error\", \"project.directory\", displayPath, messageFor(error)))\n return false\n }\n}\n\nasync function readRegularFile(filename: string, boundary: string): Promise<string> {\n const metadata = await lstat(filename)\n if (!metadata.isFile() || metadata.isSymbolicLink()) throw new Error(\"must be a regular file\")\n const relative = path.relative(boundary, filename)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) throw new Error(\"is outside the project boundary\")\n return readFile(filename, \"utf8\")\n}\n\nfunction validationResult(\n directory: string,\n issues: ValidationIssue[],\n sets: ScreenshotSet[],\n config?: StoreShotConfig,\n assets?: Record<AssetCategory, Asset[]>,\n mockupCatalog?: DeviceMockupCatalog,\n): ProjectValidation {\n const errors = issues.filter((entry) => entry.severity === \"error\")\n const warnings = issues.filter((entry) => entry.severity === \"warning\")\n const allAssets = Object.values(assets ?? {}).flat()\n return {\n report: {\n ok: errors.length === 0,\n directory,\n errors,\n warnings,\n summary: {\n assets: allAssets.length,\n sets: sets.length,\n screenshots: assets?.screenshots.length ?? 0,\n areas: sets.reduce((total, set) => total + set.areas.length, 0),\n },\n },\n ...(config ? { config } : {}),\n ...(assets ? { assets } : {}),\n sets,\n ...(mockupCatalog ? { mockupCatalog } : {}),\n }\n}\n\nfunction issue(severity: ValidationSeverity, code: string, issuePath: string, message: string): ValidationIssue {\n return { severity, code, path: issuePath, message }\n}\n\nfunction messageFor(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction isIsoTimestamp(value: string): boolean {\n const date = new Date(value)\n return !Number.isNaN(date.getTime()) && date.toISOString() === value\n}\n"],"mappings":"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","names":["constants","access","readFile","path","readFile","stat","path","path","stat","readFile","lstat","readFile","readdir","path","packageRoot","path","readdir","lstat","readFile","path","program","readFile","projectDirectory","access","constants"]}