@ryndesign/preview 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,7 +48,7 @@ export function useWebSocket() {
48
48
  useEffect(() => {
49
49
  function connect() {
50
50
  const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
51
- const ws = new WebSocket(`${protocol}//${location.host}`);
51
+ const ws = new WebSocket(`${protocol}//${location.host}/ws`);
52
52
  wsRef.current = ws;
53
53
 
54
54
  ws.onopen = () => {
package/dist/index.cjs CHANGED
@@ -38,7 +38,9 @@ module.exports = __toCommonJS(index_exports);
38
38
  var import_vite = require("vite");
39
39
  var import_ws = require("ws");
40
40
  var import_node_http = __toESM(require("http"), 1);
41
+ var import_node_net = __toESM(require("net"), 1);
41
42
  var import_node_path2 = __toESM(require("path"), 1);
43
+ var import_node_child_process = require("child_process");
42
44
 
43
45
  // src/server/api-routes.ts
44
46
  function setupApiRoutes(builder) {
@@ -345,13 +347,66 @@ ${f.content}`).join("\n\n");
345
347
  };
346
348
 
347
349
  // src/server/index.ts
350
+ function isPortInUse(port) {
351
+ return new Promise((resolve) => {
352
+ const tester = import_node_net.default.createServer().once("error", () => resolve(true)).once("listening", () => {
353
+ tester.close();
354
+ resolve(false);
355
+ }).listen(port);
356
+ });
357
+ }
358
+ function killProcessOnPort(port) {
359
+ try {
360
+ if (process.platform === "win32") {
361
+ const result = (0, import_node_child_process.execSync)(`netstat -ano | findstr :${port}`, { encoding: "utf-8" });
362
+ const pid = result.trim().split(/\s+/).pop();
363
+ if (pid) {
364
+ (0, import_node_child_process.execSync)(`taskkill /PID ${pid} /F`);
365
+ return true;
366
+ }
367
+ } else {
368
+ (0, import_node_child_process.execSync)(`lsof -ti:${port} | xargs kill -9`, { stdio: "pipe" });
369
+ return true;
370
+ }
371
+ } catch {
372
+ }
373
+ return false;
374
+ }
348
375
  async function startPreviewServer(options = {}) {
349
376
  const port = options.port ?? 4400;
350
377
  const cwd = process.cwd();
378
+ if (await isPortInUse(port)) {
379
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
380
+ if (isTTY) {
381
+ const readline = await import("readline");
382
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
383
+ const answer = await new Promise((resolve) => {
384
+ rl.question(`
385
+ Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);
386
+ });
387
+ rl.close();
388
+ if (answer.toLowerCase() === "y") {
389
+ if (killProcessOnPort(port)) {
390
+ console.log(` Killed process on port ${port}.`);
391
+ await new Promise((r) => setTimeout(r, 500));
392
+ } else {
393
+ console.error(` Could not kill process on port ${port}.`);
394
+ process.exit(1);
395
+ }
396
+ } else {
397
+ console.log(" Aborted.");
398
+ process.exit(0);
399
+ }
400
+ } else {
401
+ console.error(`
402
+ Port ${port} is already in use. Use --port to specify a different port.`);
403
+ process.exit(1);
404
+ }
405
+ }
351
406
  const builder = new IncrementalBuilder(cwd, options.configPath);
352
407
  await builder.initialBuild();
353
408
  const server = import_node_http.default.createServer();
354
- const wss = new import_ws.WebSocketServer({ server });
409
+ const wss = new import_ws.WebSocketServer({ noServer: true });
355
410
  setupWsHandler(wss, builder);
356
411
  let reactPlugin;
357
412
  try {
@@ -368,6 +423,13 @@ async function startPreviewServer(options = {}) {
368
423
  plugins: reactPlugin ? [reactPlugin] : [],
369
424
  appType: "spa"
370
425
  });
426
+ server.on("upgrade", (req, socket, head) => {
427
+ if (req.url === "/ws") {
428
+ wss.handleUpgrade(req, socket, head, (ws) => {
429
+ wss.emit("connection", ws, req);
430
+ });
431
+ }
432
+ });
371
433
  const apiHandler = setupApiRoutes(builder);
372
434
  server.on("request", (req, res) => {
373
435
  if (req.url?.startsWith("/api/")) {
@@ -381,7 +443,7 @@ async function startPreviewServer(options = {}) {
381
443
  console.log(`
382
444
  \u{1F3A8} RynDesign Preview`);
383
445
  console.log(` \u279C Local: http://localhost:${port}/`);
384
- console.log(` \u279C WS: ws://localhost:${port}/
446
+ console.log(` \u279C WS: ws://localhost:${port}/ws
385
447
  `);
386
448
  if (options.open) {
387
449
  import("child_process").then((cp) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["export { startPreviewServer } from './server/index.js';\nexport type { PreviewServerOptions } from './server/index.js';\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport path from 'node:path';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup WebSocket\n const wss = new WebSocketServer({ server });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["import_node_path","path","path","fs","http","createViteServer","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["export { startPreviewServer } from './server/index.js';\nexport type { PreviewServerOptions } from './server/index.js';\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["import_node_path","path","path","fs","net","http","createViteServer","path"]}
package/dist/index.js CHANGED
@@ -1,8 +1,17 @@
1
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.5.4/node_modules/tsup/assets/esm_shims.js
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
7
+
1
8
  // src/server/index.ts
2
9
  import { createServer as createViteServer } from "vite";
3
10
  import { WebSocketServer } from "ws";
4
11
  import http from "http";
5
- import path2 from "path";
12
+ import net from "net";
13
+ import path3 from "path";
14
+ import { execSync } from "child_process";
6
15
 
7
16
  // src/server/api-routes.ts
8
17
  function setupApiRoutes(builder) {
@@ -41,8 +50,8 @@ function setupApiRoutes(builder) {
41
50
  body += chunk;
42
51
  });
43
52
  req.on("end", async () => {
44
- const { path: path3, value, theme } = JSON.parse(body);
45
- await builder.updateToken(path3, value, theme);
53
+ const { path: path4, value, theme } = JSON.parse(body);
54
+ await builder.updateToken(path4, value, theme);
46
55
  json(res, { success: true });
47
56
  });
48
57
  } else if (pathname === "/api/generated" && req.method === "GET") {
@@ -175,7 +184,7 @@ function setupWatcher(builder, wss, cwd) {
175
184
  // src/server/incremental-build.ts
176
185
  import { buildTokenSet, loadComponents, resolveComponent } from "@ryndesign/core";
177
186
  import fs from "fs/promises";
178
- import path from "path";
187
+ import path2 from "path";
179
188
  var IncrementalBuilder = class {
180
189
  tokenSet = null;
181
190
  components = [];
@@ -196,12 +205,12 @@ var IncrementalBuilder = class {
196
205
  const componentPatterns = ["components/**/*.component.json"];
197
206
  let themes = void 0;
198
207
  try {
199
- const configPath = path.resolve(this.cwd, configFile);
208
+ const configPath = path2.resolve(this.cwd, configFile);
200
209
  const content = await fs.readFile(configPath, "utf-8");
201
210
  if (content.includes("dark")) {
202
211
  themes = {
203
212
  default: "light",
204
- dark: { file: path.resolve(this.cwd, "tokens/dark.tokens.json") }
213
+ dark: { file: path2.resolve(this.cwd, "tokens/dark.tokens.json") }
205
214
  };
206
215
  }
207
216
  } catch {
@@ -252,7 +261,7 @@ var IncrementalBuilder = class {
252
261
  const ctx = {
253
262
  tokenSet: this.tokenSet,
254
263
  config: { outDir: "generated" },
255
- outputDir: path.resolve(this.cwd, "generated"),
264
+ outputDir: path2.resolve(this.cwd, "generated"),
256
265
  helpers: createGeneratorHelpers(),
257
266
  components: this.components
258
267
  };
@@ -283,7 +292,7 @@ ${f.content}`).join("\n\n");
283
292
  return this.generatedFiles.get(platform) ?? [];
284
293
  }
285
294
  async updateToken(tokenPath, value, theme) {
286
- const filePath = theme ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`) : path.resolve(this.cwd, "tokens/semantic.tokens.json");
295
+ const filePath = theme ? path2.resolve(this.cwd, `tokens/${theme}.tokens.json`) : path2.resolve(this.cwd, "tokens/semantic.tokens.json");
287
296
  try {
288
297
  const content = await fs.readFile(filePath, "utf-8");
289
298
  const tree = JSON.parse(content);
@@ -309,13 +318,66 @@ ${f.content}`).join("\n\n");
309
318
  };
310
319
 
311
320
  // src/server/index.ts
321
+ function isPortInUse(port) {
322
+ return new Promise((resolve) => {
323
+ const tester = net.createServer().once("error", () => resolve(true)).once("listening", () => {
324
+ tester.close();
325
+ resolve(false);
326
+ }).listen(port);
327
+ });
328
+ }
329
+ function killProcessOnPort(port) {
330
+ try {
331
+ if (process.platform === "win32") {
332
+ const result = execSync(`netstat -ano | findstr :${port}`, { encoding: "utf-8" });
333
+ const pid = result.trim().split(/\s+/).pop();
334
+ if (pid) {
335
+ execSync(`taskkill /PID ${pid} /F`);
336
+ return true;
337
+ }
338
+ } else {
339
+ execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: "pipe" });
340
+ return true;
341
+ }
342
+ } catch {
343
+ }
344
+ return false;
345
+ }
312
346
  async function startPreviewServer(options = {}) {
313
347
  const port = options.port ?? 4400;
314
348
  const cwd = process.cwd();
349
+ if (await isPortInUse(port)) {
350
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
351
+ if (isTTY) {
352
+ const readline = await import("readline");
353
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
354
+ const answer = await new Promise((resolve) => {
355
+ rl.question(`
356
+ Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);
357
+ });
358
+ rl.close();
359
+ if (answer.toLowerCase() === "y") {
360
+ if (killProcessOnPort(port)) {
361
+ console.log(` Killed process on port ${port}.`);
362
+ await new Promise((r) => setTimeout(r, 500));
363
+ } else {
364
+ console.error(` Could not kill process on port ${port}.`);
365
+ process.exit(1);
366
+ }
367
+ } else {
368
+ console.log(" Aborted.");
369
+ process.exit(0);
370
+ }
371
+ } else {
372
+ console.error(`
373
+ Port ${port} is already in use. Use --port to specify a different port.`);
374
+ process.exit(1);
375
+ }
376
+ }
315
377
  const builder = new IncrementalBuilder(cwd, options.configPath);
316
378
  await builder.initialBuild();
317
379
  const server = http.createServer();
318
- const wss = new WebSocketServer({ server });
380
+ const wss = new WebSocketServer({ noServer: true });
319
381
  setupWsHandler(wss, builder);
320
382
  let reactPlugin;
321
383
  try {
@@ -324,7 +386,7 @@ async function startPreviewServer(options = {}) {
324
386
  } catch {
325
387
  }
326
388
  const vite = await createViteServer({
327
- root: path2.resolve(__dirname, "../client"),
389
+ root: path3.resolve(__dirname, "../client"),
328
390
  server: {
329
391
  middlewareMode: true,
330
392
  hmr: { server }
@@ -332,6 +394,13 @@ async function startPreviewServer(options = {}) {
332
394
  plugins: reactPlugin ? [reactPlugin] : [],
333
395
  appType: "spa"
334
396
  });
397
+ server.on("upgrade", (req, socket, head) => {
398
+ if (req.url === "/ws") {
399
+ wss.handleUpgrade(req, socket, head, (ws) => {
400
+ wss.emit("connection", ws, req);
401
+ });
402
+ }
403
+ });
335
404
  const apiHandler = setupApiRoutes(builder);
336
405
  server.on("request", (req, res) => {
337
406
  if (req.url?.startsWith("/api/")) {
@@ -345,7 +414,7 @@ async function startPreviewServer(options = {}) {
345
414
  console.log(`
346
415
  \u{1F3A8} RynDesign Preview`);
347
416
  console.log(` \u279C Local: http://localhost:${port}/`);
348
- console.log(` \u279C WS: ws://localhost:${port}/
417
+ console.log(` \u279C WS: ws://localhost:${port}/ws
349
418
  `);
350
419
  if (options.open) {
351
420
  import("child_process").then((cp) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport path from 'node:path';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup WebSocket\n const wss = new WebSocketServer({ server });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["path","path","path"]}
1
+ {"version":3,"sources":["../../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.5.4/node_modules/tsup/assets/esm_shims.js","../src/server/index.ts","../src/server/api-routes.ts","../src/server/ws-handler.ts","../src/server/watcher.ts","../src/server/incremental-build.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import { createServer as createViteServer } from 'vite';\nimport { WebSocketServer } from 'ws';\nimport http from 'node:http';\nimport net from 'node:net';\nimport path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { setupApiRoutes } from './api-routes.js';\nimport { setupWsHandler } from './ws-handler.js';\nimport { setupWatcher } from './watcher.js';\nimport { IncrementalBuilder } from './incremental-build.js';\n\nexport interface PreviewServerOptions {\n port?: number;\n open?: boolean;\n configPath?: string;\n}\n\nfunction isPortInUse(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const tester = net.createServer()\n .once('error', () => resolve(true))\n .once('listening', () => {\n tester.close();\n resolve(false);\n })\n .listen(port);\n });\n}\n\nfunction killProcessOnPort(port: number): boolean {\n try {\n if (process.platform === 'win32') {\n const result = execSync(`netstat -ano | findstr :${port}`, { encoding: 'utf-8' });\n const pid = result.trim().split(/\\s+/).pop();\n if (pid) {\n execSync(`taskkill /PID ${pid} /F`);\n return true;\n }\n } else {\n execSync(`lsof -ti:${port} | xargs kill -9`, { stdio: 'pipe' });\n return true;\n }\n } catch {\n // No process found or kill failed\n }\n return false;\n}\n\nexport async function startPreviewServer(options: PreviewServerOptions = {}): Promise<void> {\n const port = options.port ?? 4400;\n const cwd = process.cwd();\n\n // Check if port is in use\n if (await isPortInUse(port)) {\n const isTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n if (isTTY) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(`\\n Port ${port} is already in use. Kill the existing process and restart? (y/N) `, resolve);\n });\n rl.close();\n\n if (answer.toLowerCase() === 'y') {\n if (killProcessOnPort(port)) {\n console.log(` Killed process on port ${port}.`);\n await new Promise(r => setTimeout(r, 500));\n } else {\n console.error(` Could not kill process on port ${port}.`);\n process.exit(1);\n }\n } else {\n console.log(' Aborted.');\n process.exit(0);\n }\n } else {\n console.error(`\\n Port ${port} is already in use. Use --port to specify a different port.`);\n process.exit(1);\n }\n }\n\n // Initialize incremental builder\n const builder = new IncrementalBuilder(cwd, options.configPath);\n await builder.initialBuild();\n\n // Create HTTP server\n const server = http.createServer();\n\n // Setup preview WebSocket in noServer mode to avoid Vite HMR conflict\n const wss = new WebSocketServer({ noServer: true });\n setupWsHandler(wss, builder);\n\n // Create Vite dev server for client SPA\n let reactPlugin;\n try {\n const mod = await import('@vitejs/plugin-react');\n reactPlugin = (mod.default ?? mod)();\n } catch {\n // Plugin not available, proceed without it\n }\n\n const vite = await createViteServer({\n root: path.resolve(__dirname, '../client'),\n server: {\n middlewareMode: true,\n hmr: { server },\n },\n plugins: reactPlugin ? [reactPlugin] : [],\n appType: 'spa',\n });\n\n // Route WebSocket upgrades: /ws → preview, everything else → Vite HMR\n server.on('upgrade', (req, socket, head) => {\n if (req.url === '/ws') {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req);\n });\n }\n // Other upgrade requests (Vite HMR) are handled by Vite automatically\n });\n\n // Setup API routes\n const apiHandler = setupApiRoutes(builder);\n\n // Handle requests\n server.on('request', (req, res) => {\n if (req.url?.startsWith('/api/')) {\n apiHandler(req, res);\n } else {\n vite.middlewares(req, res);\n }\n });\n\n // Setup file watcher\n setupWatcher(builder, wss, cwd);\n\n // Start server\n server.listen(port, () => {\n console.log(`\\n 🎨 RynDesign Preview`);\n console.log(` ➜ Local: http://localhost:${port}/`);\n console.log(` ➜ WS: ws://localhost:${port}/ws\\n`);\n\n if (options.open) {\n import('child_process').then(cp => {\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';\n cp.exec(`${cmd} http://localhost:${port}/`);\n }).catch(() => {});\n }\n });\n\n // Graceful shutdown\n process.on('SIGINT', () => {\n wss.close();\n vite.close();\n server.close();\n process.exit(0);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\ntype RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;\n\nexport function setupApiRoutes(builder: IncrementalBuilder): RequestHandler {\n return (req, res) => {\n const url = new URL(req.url ?? '/', `http://${req.headers.host}`);\n const pathname = url.pathname;\n\n // CORS headers\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n if (pathname === '/api/tokens' && req.method === 'GET') {\n json(res, builder.getTokenSet());\n } else if (pathname === '/api/themes' && req.method === 'GET') {\n json(res, builder.getThemes());\n } else if (pathname === '/api/components' && req.method === 'GET') {\n json(res, builder.getComponents());\n } else if (pathname === '/api/snippets' && req.method === 'GET') {\n const platform = url.searchParams.get('platform') ?? 'react';\n const component = url.searchParams.get('component') ?? undefined;\n const type = url.searchParams.get('type') ?? undefined;\n builder.generateSnippets(platform, component, type).then(code => {\n json(res, { code });\n }).catch(err => {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n });\n return; // async handling\n } else if (pathname === '/api/tokens' && req.method === 'PUT') {\n let body = '';\n req.on('data', chunk => { body += chunk; });\n req.on('end', async () => {\n const { path, value, theme } = JSON.parse(body);\n await builder.updateToken(path, value, theme);\n json(res, { success: true });\n });\n } else if (pathname === '/api/generated' && req.method === 'GET') {\n const platform = url.searchParams.get('platform');\n json(res, builder.getGeneratedFiles(platform ?? undefined));\n } else {\n res.writeHead(404);\n json(res, { error: 'Not found' });\n }\n } catch (err) {\n res.writeHead(500);\n json(res, { error: (err as Error).message });\n }\n };\n}\n\nfunction json(res: ServerResponse, data: unknown): void {\n if (!res.headersSent) {\n res.setHeader('Content-Type', 'application/json');\n }\n res.end(JSON.stringify(data));\n}\n","import type { WebSocketServer, WebSocket } from 'ws';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport interface WsMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface TokenUpdateMessage extends WsMessage {\n type: 'token-update';\n theme?: string;\n path: string;\n value: unknown;\n}\n\nexport interface ThemeChangeMessage extends WsMessage {\n type: 'theme-change';\n theme: string;\n}\n\nexport interface RebuildCompleteMessage extends WsMessage {\n type: 'rebuild-complete';\n changedTokens: string[];\n timestamp: number;\n}\n\nexport function setupWsHandler(wss: WebSocketServer, builder: IncrementalBuilder): void {\n wss.on('connection', (ws: WebSocket) => {\n console.log('Preview client connected');\n\n // Send initial state\n ws.send(JSON.stringify({\n type: 'init',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n\n ws.on('message', async (data: Buffer) => {\n try {\n const message = JSON.parse(data.toString()) as WsMessage;\n\n switch (message.type) {\n case 'token-update': {\n const update = message as TokenUpdateMessage;\n await builder.updateToken(update.path, update.value, update.theme);\n\n // Broadcast rebuild complete to all clients\n broadcast(wss, {\n type: 'rebuild-complete',\n changedTokens: [update.path],\n timestamp: Date.now(),\n });\n break;\n }\n\n case 'theme-change': {\n const themeMsg = message as ThemeChangeMessage;\n broadcast(wss, {\n type: 'theme-switched',\n theme: themeMsg.theme,\n tokens: builder.getThemeTokens(themeMsg.theme),\n });\n break;\n }\n\n case 'request-state': {\n ws.send(JSON.stringify({\n type: 'full-state',\n tokenSet: builder.getTokenSet(),\n themes: builder.getThemes(),\n components: builder.getComponents(),\n }));\n break;\n }\n }\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'error',\n message: (err as Error).message,\n }));\n }\n });\n\n ws.on('close', () => {\n console.log('Preview client disconnected');\n });\n });\n}\n\nfunction broadcast(wss: WebSocketServer, message: Record<string, unknown>): void {\n const data = JSON.stringify(message);\n for (const client of wss.clients) {\n if (client.readyState === 1) { // WebSocket.OPEN\n client.send(data);\n }\n }\n}\n","import type { WebSocketServer } from 'ws';\nimport { watch } from 'chokidar';\nimport type { IncrementalBuilder } from './incremental-build.js';\n\nexport function setupWatcher(\n builder: IncrementalBuilder,\n wss: WebSocketServer,\n cwd: string\n): void {\n const watcher = watch(\n ['tokens/**/*.tokens.json', 'components/**/*.component.json'],\n {\n cwd,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 300,\n pollInterval: 50,\n },\n }\n );\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const handleChange = (changedPath: string) => {\n if (debounceTimer) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(async () => {\n console.log(`File changed: ${changedPath}`);\n\n try {\n await builder.rebuild();\n\n // Broadcast to all connected clients\n const data = JSON.stringify({\n type: 'rebuild-complete',\n changedTokens: [],\n timestamp: Date.now(),\n tokenSet: builder.getTokenSet(),\n components: builder.getComponents(),\n });\n\n for (const client of wss.clients) {\n if (client.readyState === 1) {\n client.send(data);\n }\n }\n } catch (err) {\n console.error('Rebuild failed:', (err as Error).message);\n }\n }, 300);\n };\n\n watcher.on('change', handleChange);\n watcher.on('add', handleChange);\n watcher.on('unlink', handleChange);\n}\n","import { buildTokenSet, loadComponents, resolveComponent, type RawTokenTree } from '@ryndesign/core';\nimport type { ResolvedTokenSet, GeneratedFile, ResolvedComponent, GeneratorPlugin } from '@ryndesign/plugin-api';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport class IncrementalBuilder {\n private tokenSet: ResolvedTokenSet | null = null;\n private components: ResolvedComponent[] = [];\n private generatedFiles: Map<string, GeneratedFile[]> = new Map();\n private generators: GeneratorPlugin[] = [];\n private cwd: string;\n private configPath?: string;\n\n constructor(cwd: string, configPath?: string) {\n this.cwd = cwd;\n this.configPath = configPath;\n }\n\n async initialBuild(): Promise<void> {\n await this.rebuild();\n }\n\n async rebuild(): Promise<void> {\n const configFile = this.configPath ?? 'ryndesign.config.ts';\n\n const tokens = ['tokens/**/*.tokens.json'];\n const componentPatterns = ['components/**/*.component.json'];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let themes: any = undefined;\n\n try {\n const configPath = path.resolve(this.cwd, configFile);\n const content = await fs.readFile(configPath, 'utf-8');\n if (content.includes('dark')) {\n themes = {\n default: 'light',\n dark: { file: path.resolve(this.cwd, 'tokens/dark.tokens.json') },\n };\n }\n } catch {\n // Use defaults\n }\n\n this.tokenSet = await buildTokenSet({\n tokens,\n basePath: this.cwd,\n themes,\n });\n\n // Load and resolve components\n try {\n const componentDefs = await loadComponents(componentPatterns, this.cwd);\n this.components = componentDefs.map(def => resolveComponent(def, this.tokenSet!));\n } catch {\n this.components = [];\n }\n }\n\n getTokenSet(): ResolvedTokenSet | null {\n return this.tokenSet;\n }\n\n getThemes(): Record<string, unknown> {\n if (!this.tokenSet) return {};\n return {\n default: this.tokenSet.themes.default,\n available: Object.keys(this.tokenSet.themes.themes),\n themes: this.tokenSet.themes.themes,\n };\n }\n\n getThemeTokens(theme: string): Record<string, unknown> {\n if (!this.tokenSet) return {};\n const themeData = this.tokenSet.themes.themes[theme];\n if (!themeData) return {};\n return {\n name: themeData.name,\n tokens: themeData.tokens,\n };\n }\n\n getComponents(): ResolvedComponent[] {\n return this.components;\n }\n\n setGenerators(generators: GeneratorPlugin[]): void {\n this.generators = generators;\n }\n\n async generateSnippets(platform: string, componentName?: string, type?: string): Promise<string> {\n if (!this.tokenSet) return '';\n\n const generator = this.generators.find(g => g.name === platform);\n if (!generator) return `// Generator for \"${platform}\" not available`;\n\n const { createGeneratorHelpers } = await import('@ryndesign/core');\n const ctx = {\n tokenSet: this.tokenSet,\n config: { outDir: 'generated' },\n outputDir: path.resolve(this.cwd, 'generated'),\n helpers: createGeneratorHelpers(),\n components: this.components,\n };\n\n try {\n if (type === 'tokens') {\n const files = await generator.generateTokens(ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n\n if (componentName) {\n const comp = this.components.find(c => c.definition.name === componentName);\n if (comp) {\n const files = await generator.generateComponent(comp, ctx);\n return files.map(f => `// ${f.path}\\n${f.content}`).join('\\n\\n');\n }\n return `// Component \"${componentName}\" not found`;\n }\n\n return '// Specify a component or type=tokens';\n } catch (err) {\n return `// Error: ${(err as Error).message}`;\n }\n }\n\n getGeneratedFiles(platform?: string): GeneratedFile[] {\n if (!platform) {\n return Array.from(this.generatedFiles.values()).flat();\n }\n return this.generatedFiles.get(platform) ?? [];\n }\n\n async updateToken(tokenPath: string, value: unknown, theme?: string): Promise<void> {\n const filePath = theme\n ? path.resolve(this.cwd, `tokens/${theme}.tokens.json`)\n : path.resolve(this.cwd, 'tokens/semantic.tokens.json');\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const tree = JSON.parse(content) as RawTokenTree;\n\n const parts = tokenPath.split('.');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]];\n }\n\n const lastKey = parts[parts.length - 1];\n if (current[lastKey] && typeof current[lastKey] === 'object' && '$value' in current[lastKey]) {\n current[lastKey].$value = value;\n } else {\n current[lastKey] = { $type: 'color', $value: value };\n }\n\n await fs.writeFile(filePath, JSON.stringify(tree, null, 2), 'utf-8');\n await this.rebuild();\n } catch (err) {\n console.error(`Failed to update token: ${(err as Error).message}`);\n throw err;\n }\n }\n}\n"],"mappings":"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","names":["path","path","path","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryndesign/preview",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Preview server for RynDesign design system",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,8 +36,8 @@
36
36
  "react-dom": "^19.2.4",
37
37
  "vite": "^8.0.0",
38
38
  "ws": "^8.18.0",
39
- "@ryndesign/plugin-api": "0.1.1",
40
- "@ryndesign/core": "0.1.1"
39
+ "@ryndesign/core": "0.1.1",
40
+ "@ryndesign/plugin-api": "0.1.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/react": "^19.2.14",