@wix/web50-cli 0.1.1 → 0.1.3

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.
Files changed (108) hide show
  1. package/bin/web5.js +1 -2
  2. package/dist/cjs/auth/deviceFlow.js +96 -17
  3. package/dist/cjs/auth/deviceFlow.js.map +1 -1
  4. package/dist/cjs/auth/index.js +40 -10
  5. package/dist/cjs/auth/index.js.map +1 -1
  6. package/dist/cjs/cli.js +3 -3
  7. package/dist/cjs/cli.js.map +1 -1
  8. package/dist/cjs/commands/bundle.js +12 -4
  9. package/dist/cjs/commands/bundle.js.map +1 -1
  10. package/dist/cjs/commands/conversation.js.map +1 -1
  11. package/dist/cjs/commands/conversationWizard.js +36 -12
  12. package/dist/cjs/commands/conversationWizard.js.map +1 -1
  13. package/dist/cjs/commands/deploy.js +55 -10
  14. package/dist/cjs/commands/deploy.js.map +1 -1
  15. package/dist/cjs/commands/ecom.js +239 -0
  16. package/dist/cjs/commands/ecom.js.map +1 -0
  17. package/dist/cjs/commands/embed.js +41 -52
  18. package/dist/cjs/commands/embed.js.map +1 -1
  19. package/dist/cjs/commands/init.js +34 -3
  20. package/dist/cjs/commands/init.js.map +1 -1
  21. package/dist/cjs/commands/instructions.js +147 -51
  22. package/dist/cjs/commands/instructions.js.map +1 -1
  23. package/dist/cjs/commands/login.js +8 -4
  24. package/dist/cjs/commands/login.js.map +1 -1
  25. package/dist/cjs/commands/serve.js.map +1 -1
  26. package/dist/cjs/commands/validate.js +368 -16
  27. package/dist/cjs/commands/validate.js.map +1 -1
  28. package/dist/cjs/commands/whoami.js.map +1 -1
  29. package/dist/cjs/templates/aiInstructionsSchema.js +5 -1
  30. package/dist/cjs/templates/aiInstructionsSchema.js.map +1 -1
  31. package/dist/cjs/templates/cmsMappingSchema.js +132 -0
  32. package/dist/cjs/templates/cmsMappingSchema.js.map +1 -0
  33. package/dist/cjs/templates/embedDocs.js +488 -0
  34. package/dist/cjs/templates/embedDocs.js.map +1 -0
  35. package/dist/cjs/utils/project.js +13 -0
  36. package/dist/cjs/utils/project.js.map +1 -1
  37. package/dist/cjs/utils/wixApi.js +3 -1
  38. package/dist/cjs/utils/wixApi.js.map +1 -1
  39. package/dist/esm/auth/deviceFlow.js +95 -17
  40. package/dist/esm/auth/deviceFlow.js.map +1 -1
  41. package/dist/esm/auth/index.js +40 -11
  42. package/dist/esm/auth/index.js.map +1 -1
  43. package/dist/esm/cli.js +3 -3
  44. package/dist/esm/cli.js.map +1 -1
  45. package/dist/esm/commands/bundle.js +12 -4
  46. package/dist/esm/commands/bundle.js.map +1 -1
  47. package/dist/esm/commands/conversation.js.map +1 -1
  48. package/dist/esm/commands/conversationWizard.js +36 -12
  49. package/dist/esm/commands/conversationWizard.js.map +1 -1
  50. package/dist/esm/commands/deploy.js +55 -10
  51. package/dist/esm/commands/deploy.js.map +1 -1
  52. package/dist/esm/commands/ecom.js +234 -0
  53. package/dist/esm/commands/ecom.js.map +1 -0
  54. package/dist/esm/commands/embed.js +42 -52
  55. package/dist/esm/commands/embed.js.map +1 -1
  56. package/dist/esm/commands/init.js +34 -3
  57. package/dist/esm/commands/init.js.map +1 -1
  58. package/dist/esm/commands/instructions.js +152 -53
  59. package/dist/esm/commands/instructions.js.map +1 -1
  60. package/dist/esm/commands/login.js +8 -4
  61. package/dist/esm/commands/login.js.map +1 -1
  62. package/dist/esm/commands/serve.js.map +1 -1
  63. package/dist/esm/commands/validate.js +373 -19
  64. package/dist/esm/commands/validate.js.map +1 -1
  65. package/dist/esm/commands/whoami.js.map +1 -1
  66. package/dist/esm/templates/aiInstructionsSchema.js +5 -1
  67. package/dist/esm/templates/aiInstructionsSchema.js.map +1 -1
  68. package/dist/esm/templates/cmsMappingSchema.js +128 -0
  69. package/dist/esm/templates/cmsMappingSchema.js.map +1 -0
  70. package/dist/esm/templates/embedDocs.js +484 -0
  71. package/dist/esm/templates/embedDocs.js.map +1 -0
  72. package/dist/esm/utils/project.js +15 -0
  73. package/dist/esm/utils/project.js.map +1 -1
  74. package/dist/esm/utils/wixApi.js +4 -2
  75. package/dist/esm/utils/wixApi.js.map +1 -1
  76. package/dist/types/auth/deviceFlow.d.ts +1 -1
  77. package/dist/types/auth/deviceFlow.d.ts.map +1 -1
  78. package/dist/types/auth/index.d.ts +2 -1
  79. package/dist/types/auth/index.d.ts.map +1 -1
  80. package/dist/types/commands/bundle.d.ts.map +1 -1
  81. package/dist/types/commands/conversation.d.ts.map +1 -1
  82. package/dist/types/commands/conversationWizard.d.ts.map +1 -1
  83. package/dist/types/commands/deploy.d.ts.map +1 -1
  84. package/dist/types/commands/ecom.d.ts +3 -0
  85. package/dist/types/commands/ecom.d.ts.map +1 -0
  86. package/dist/types/commands/embed.d.ts.map +1 -1
  87. package/dist/types/commands/init.d.ts.map +1 -1
  88. package/dist/types/commands/instructions.d.ts.map +1 -1
  89. package/dist/types/commands/login.d.ts.map +1 -1
  90. package/dist/types/commands/serve.d.ts.map +1 -1
  91. package/dist/types/commands/validate.d.ts +4 -2
  92. package/dist/types/commands/validate.d.ts.map +1 -1
  93. package/dist/types/commands/whoami.d.ts.map +1 -1
  94. package/dist/types/templates/aiInstructionsSchema.d.ts.map +1 -1
  95. package/dist/types/templates/cmsMappingSchema.d.ts +2 -0
  96. package/dist/types/templates/cmsMappingSchema.d.ts.map +1 -0
  97. package/dist/types/templates/embedDocs.d.ts +2 -0
  98. package/dist/types/templates/embedDocs.d.ts.map +1 -0
  99. package/dist/types/utils/project.d.ts +3 -0
  100. package/dist/types/utils/project.d.ts.map +1 -1
  101. package/dist/types/utils/wixApi.d.ts.map +1 -1
  102. package/package.json +2 -2
  103. package/dist/cjs/commands/getClientId.js +0 -60
  104. package/dist/cjs/commands/getClientId.js.map +0 -1
  105. package/dist/esm/commands/getClientId.js +0 -56
  106. package/dist/esm/commands/getClientId.js.map +0 -1
  107. package/dist/types/commands/getClientId.d.ts +0 -3
  108. package/dist/types/commands/getClientId.d.ts.map +0 -1
@@ -37,8 +37,12 @@ const statusCmd = new _commander.Command('status').description('Show current aut
37
37
  }
38
38
  (0, _print.success)('Authenticated');
39
39
  (0, _print.info)(`Method: ${authMethod}`);
40
- if (siteId) (0, _print.info)(`Site ID: ${siteId}`);
41
- if (expiresAt) (0, _print.info)(`Expires: ${expiresAt}${expired ? ' (expired)' : ''}`);
40
+ if (siteId) {
41
+ (0, _print.info)(`Site ID: ${siteId}`);
42
+ }
43
+ if (expiresAt) {
44
+ (0, _print.info)(`Expires: ${expiresAt}${expired ? ' (expired)' : ''}`);
45
+ }
42
46
  } catch (err_) {
43
47
  (0, _print.error)(err_ instanceof Error ? err_.message : String(err_));
44
48
  process.exit(1);
@@ -47,9 +51,9 @@ const statusCmd = new _commander.Command('status').description('Show current aut
47
51
 
48
52
  // ── login switch-site ─────────────────────────────────────────────────────────
49
53
 
50
- const switchSiteCmd = new _commander.Command('switch-site').description('Re-scope authentication to a different site without re-authenticating').requiredOption('--site-id <msid>', 'Target site ID (msid)').action(async opts => {
54
+ const switchSiteCmd = new _commander.Command('switch-site').description('Switch to a different web5 site (interactive picker)').action(async () => {
51
55
  try {
52
- await (0, _auth.switchSite)(opts.siteId);
56
+ await (0, _auth.switchSite)();
53
57
  } catch (err_) {
54
58
  (0, _print.error)(err_ instanceof Error ? err_.message : String(err_));
55
59
  process.exit(1);
@@ -1 +1 @@
1
- {"version":3,"names":["_commander","require","_auth","_secretStore","_print","statusCmd","Command","description","action","creds","readCredentials","isJsonMode","console","log","JSON","stringify","authenticated","info","authMethod","api_key","siteId","site_id","expiresAt","expires_at","Date","toISOString","expired","now","success","err_","error","Error","message","String","process","exit","switchSiteCmd","requiredOption","opts","switchSite","loginCommand","exports","option","apiKey","env","WEB5_API_KEY","login","logs","noBrowser","browser","addCommand"],"sources":["../../../src/commands/login.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { login, switchSite } from '../auth';\nimport { readCredentials } from '../auth/secretStore';\nimport { error, success, info, isJsonMode } from '../utils/print';\n\n// ── login status ──────────────────────────────────────────────────────────────\n\nconst statusCmd = new Command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n const creds = await readCredentials();\n if (!creds) {\n if (isJsonMode()) {\n console.log(JSON.stringify({ authenticated: false }));\n } else {\n info('Not authenticated. Run `web5 login` to sign in.');\n }\n return;\n }\n\n const authMethod = creds.api_key ? 'api-key' : 'device-flow';\n const siteId = creds.site_id ?? null;\n const expiresAt = creds.expires_at\n ? new Date(creds.expires_at).toISOString()\n : null;\n const expired = creds.expires_at ? creds.expires_at < Date.now() : false;\n\n if (isJsonMode()) {\n console.log(\n JSON.stringify({ authenticated: true, authMethod, siteId, expiresAt, expired }),\n );\n return;\n }\n\n success('Authenticated');\n info(`Method: ${authMethod}`);\n if (siteId) info(`Site ID: ${siteId}`);\n if (expiresAt) info(`Expires: ${expiresAt}${expired ? ' (expired)' : ''}`);\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n\n// ── login switch-site ─────────────────────────────────────────────────────────\n\nconst switchSiteCmd = new Command('switch-site')\n .description('Re-scope authentication to a different site without re-authenticating')\n .requiredOption('--site-id <msid>', 'Target site ID (msid)')\n .action(async (opts: { siteId: string }) => {\n try {\n await switchSite(opts.siteId);\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n\n// ── login (root) ──────────────────────────────────────────────────────────────\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with the Web5 platform')\n .option('--api-key <key>', 'Authenticate using an API key instead of browser flow')\n .option('--logs', 'Enable verbose debug logging for the auth flow')\n .option('--site-id <msid>', 'Site ID (msid) to scope the session to (skips interactive prompt)')\n .option('--no-browser', 'Skip opening the browser — print the verification URL instead')\n .action(async (opts: { apiKey?: string; logs?: boolean; siteId?: string; browser: boolean }) => {\n try {\n const apiKey = process.env.WEB5_API_KEY ?? opts.apiKey;\n await login(apiKey, opts.logs ?? false, {\n siteId: opts.siteId,\n noBrowser: !opts.browser,\n });\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n })\n .addCommand(statusCmd)\n .addCommand(switchSiteCmd);\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_commander","require","_auth","_secretStore","_print","statusCmd","Command","description","action","creds","readCredentials","isJsonMode","console","log","JSON","stringify","authenticated","info","authMethod","api_key","siteId","site_id","expiresAt","expires_at","Date","toISOString","expired","now","success","err_","error","Error","message","String","process","exit","switchSiteCmd","switchSite","loginCommand","exports","option","opts","apiKey","env","WEB5_API_KEY","login","logs","noBrowser","browser","addCommand"],"sources":["../../../src/commands/login.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { login, switchSite } from '../auth';\nimport { readCredentials } from '../auth/secretStore';\nimport { error, success, info, isJsonMode } from '../utils/print';\n\n// ── login status ──────────────────────────────────────────────────────────────\n\nconst statusCmd = new Command('status')\n .description('Show current authentication status')\n .action(async () => {\n try {\n const creds = await readCredentials();\n if (!creds) {\n if (isJsonMode()) {\n console.log(JSON.stringify({ authenticated: false }));\n } else {\n info('Not authenticated. Run `web5 login` to sign in.');\n }\n return;\n }\n\n const authMethod = creds.api_key ? 'api-key' : 'device-flow';\n const siteId = creds.site_id ?? null;\n const expiresAt = creds.expires_at\n ? new Date(creds.expires_at).toISOString()\n : null;\n const expired = creds.expires_at ? creds.expires_at < Date.now() : false;\n\n if (isJsonMode()) {\n console.log(\n JSON.stringify({\n authenticated: true,\n authMethod,\n siteId,\n expiresAt,\n expired,\n }),\n );\n return;\n }\n\n success('Authenticated');\n info(`Method: ${authMethod}`);\n if (siteId) {\n info(`Site ID: ${siteId}`);\n }\n if (expiresAt) {\n info(`Expires: ${expiresAt}${expired ? ' (expired)' : ''}`);\n }\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n\n// ── login switch-site ─────────────────────────────────────────────────────────\n\nconst switchSiteCmd = new Command('switch-site')\n .description('Switch to a different web5 site (interactive picker)')\n .action(async () => {\n try {\n await switchSite();\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n\n// ── login (root) ──────────────────────────────────────────────────────────────\n\nexport const loginCommand = new Command('login')\n .description('Authenticate with the Web5 platform')\n .option(\n '--api-key <key>',\n 'Authenticate using an API key instead of browser flow',\n )\n .option('--logs', 'Enable verbose debug logging for the auth flow')\n .option(\n '--site-id <msid>',\n 'Site ID (msid) to scope the session to (skips interactive prompt)',\n )\n .option(\n '--no-browser',\n 'Skip opening the browser — print the verification URL instead',\n )\n .action(\n async (opts: {\n apiKey?: string;\n logs?: boolean;\n siteId?: string;\n browser: boolean;\n }) => {\n try {\n const apiKey = process.env.WEB5_API_KEY ?? opts.apiKey;\n await login(apiKey, opts.logs ?? false, {\n siteId: opts.siteId,\n noBrowser: !opts.browser,\n });\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n },\n )\n .addCommand(statusCmd)\n .addCommand(switchSiteCmd);\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["_commander","require","path","_interopRequireWildcard","fs","http","_child_process","_print","_project","_bundle","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DEFAULT_PORT","MIME_TYPES","startServer","distDir","corsOrigin","server","createServer","req","res","setHeader","method","writeHead","end","urlPath","url","filePath","join","startsWith","existsSync","statSync","isDirectory","ext","extname","contentType","createReadStream","pipe","serveCommand","exports","Command","description","option","String","action","opts","projectRoot","findProjectRoot","process","cwd","error","exit","port","parseInt","isNaN","bundle","runBundle","watch","viteBin","watcher","spawn","shell","stdio","on","err_","message","listen","files","readdirSync","isJsonMode","console","log","JSON","stringify","map","success","file","info","open","openPkg","Promise","resolve","then","Error"],"sources":["../../../src/commands/serve.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as http from 'http';\nimport { spawn } from 'child_process';\nimport { success, error, info, isJsonMode } from '../utils/print';\nimport { findProjectRoot } from '../utils/project';\nimport { runBundle } from './bundle';\n\nconst DEFAULT_PORT = 4001;\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.map': 'application/json',\n};\n\nfunction startServer(\n distDir: string,\n corsOrigin: string,\n): http.Server {\n const server = http.createServer((req, res) => {\n res.setHeader('Access-Control-Allow-Origin', corsOrigin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', '*');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const urlPath = req.url === '/' ? '' : req.url ?? '';\n const filePath = path.join(distDir, urlPath);\n\n // Prevent path traversal outside distDir\n if (!filePath.startsWith(distDir)) {\n res.writeHead(403);\n res.end('Forbidden');\n return;\n }\n\n if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {\n res.writeHead(404);\n res.end('Not found');\n return;\n }\n\n const ext = path.extname(filePath);\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.setHeader('Content-Type', contentType);\n res.writeHead(200);\n fs.createReadStream(filePath).pipe(res);\n });\n\n return server;\n}\n\nexport const serveCommand = new Command('serve')\n .description('Bundle components and serve them on http://localhost:<port> with CORS enabled')\n .option('--port <n>', 'Port to listen on', String(DEFAULT_PORT))\n .option('--no-bundle', 'Serve existing dist/cdn/ without rebuilding')\n .option('--watch', 'Re-bundle on source changes (starts vite --watch alongside server)')\n .option('--open', 'Open the served URL in your browser after start')\n .option('--cors-origin <origin>', 'Restrict CORS Allow-Origin header', '*')\n .action(async (opts: {\n port: string;\n bundle: boolean;\n watch?: boolean;\n open?: boolean;\n corsOrigin: string;\n }) => {\n try {\n const projectRoot = findProjectRoot(process.cwd());\n if (!projectRoot) {\n error(\n 'No web5.config.json found. Run this command from within a Web5 project.',\n );\n process.exit(1);\n }\n\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n error(`Invalid port: ${opts.port}`);\n process.exit(1);\n }\n\n const distDir = path.join(projectRoot, 'dist', 'cdn');\n\n // ── Bundle (unless --no-bundle) ─────────────────────────────────────────\n if (opts.bundle !== false) {\n await runBundle(projectRoot);\n }\n\n if (!fs.existsSync(distDir)) {\n error(\n `Bundle output not found at ${distDir}. Run \\`web5 bundle\\` first or remove --no-bundle.`,\n );\n process.exit(1);\n }\n\n // ── Watch mode: spawn vite --watch in background ────────────────────────\n if (opts.watch) {\n const viteBin = path.join(projectRoot, 'node_modules', '.bin', 'vite');\n if (!fs.existsSync(viteBin)) {\n error('vite not found. Run `npm install` in your project first.');\n process.exit(1);\n }\n const watcher = spawn(\n `\"${viteBin}\"`,\n ['build', '--config', 'src/vite.cdn.config.ts', '--watch'],\n { cwd: projectRoot, shell: true, stdio: 'inherit' },\n );\n watcher.on('error', (err_) => error(`Watch process error: ${err_.message}`));\n }\n\n // ── Start HTTP server ───────────────────────────────────────────────────\n const server = startServer(distDir, opts.corsOrigin);\n const url = `http://localhost:${port}`;\n\n server.listen(port, async () => {\n const files = fs.readdirSync(distDir);\n\n if (isJsonMode()) {\n console.log(JSON.stringify({ url, port, files: files.map((f) => `${url}/${f}`) }));\n } else {\n success(`Serving on ${url}`);\n for (const file of files) {\n info(` ${url}/${file}`);\n }\n if (opts.watch) {\n info('Watch mode active — rebuilds automatically on file changes.');\n }\n info('Press Ctrl+C to stop.');\n }\n\n if (opts.open) {\n const openPkg = (await import('open')).default;\n await openPkg(url);\n }\n });\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n });\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_commander","require","path","_interopRequireWildcard","fs","http","_child_process","_print","_project","_bundle","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DEFAULT_PORT","MIME_TYPES","startServer","distDir","corsOrigin","server","createServer","req","res","setHeader","method","writeHead","end","urlPath","url","filePath","join","startsWith","existsSync","statSync","isDirectory","ext","extname","contentType","createReadStream","pipe","serveCommand","exports","Command","description","option","String","action","opts","projectRoot","findProjectRoot","process","cwd","error","exit","port","parseInt","isNaN","bundle","runBundle","watch","viteBin","watcher","spawn","shell","stdio","on","err_","message","listen","files","readdirSync","isJsonMode","console","log","JSON","stringify","map","success","file","info","open","openPkg","Promise","resolve","then","Error"],"sources":["../../../src/commands/serve.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as http from 'http';\nimport { spawn } from 'child_process';\nimport { success, error, info, isJsonMode } from '../utils/print';\nimport { findProjectRoot } from '../utils/project';\nimport { runBundle } from './bundle';\n\nconst DEFAULT_PORT = 4001;\n\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.map': 'application/json',\n};\n\nfunction startServer(distDir: string, corsOrigin: string): http.Server {\n const server = http.createServer((req, res) => {\n res.setHeader('Access-Control-Allow-Origin', corsOrigin);\n res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', '*');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const urlPath = req.url === '/' ? '' : req.url ?? '';\n const filePath = path.join(distDir, urlPath);\n\n // Prevent path traversal outside distDir\n if (!filePath.startsWith(distDir)) {\n res.writeHead(403);\n res.end('Forbidden');\n return;\n }\n\n if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {\n res.writeHead(404);\n res.end('Not found');\n return;\n }\n\n const ext = path.extname(filePath);\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.setHeader('Content-Type', contentType);\n res.writeHead(200);\n fs.createReadStream(filePath).pipe(res);\n });\n\n return server;\n}\n\nexport const serveCommand = new Command('serve')\n .description(\n 'Bundle components and serve them on http://localhost:<port> with CORS enabled',\n )\n .option('--port <n>', 'Port to listen on', String(DEFAULT_PORT))\n .option('--no-bundle', 'Serve existing dist/cdn/ without rebuilding')\n .option(\n '--watch',\n 'Re-bundle on source changes (starts vite --watch alongside server)',\n )\n .option('--open', 'Open the served URL in your browser after start')\n .option('--cors-origin <origin>', 'Restrict CORS Allow-Origin header', '*')\n .action(\n async (opts: {\n port: string;\n bundle: boolean;\n watch?: boolean;\n open?: boolean;\n corsOrigin: string;\n }) => {\n try {\n const projectRoot = findProjectRoot(process.cwd());\n if (!projectRoot) {\n error(\n 'No web5.config.json found. Run this command from within a Web5 project.',\n );\n process.exit(1);\n }\n\n const port = parseInt(opts.port, 10);\n if (isNaN(port) || port < 1 || port > 65535) {\n error(`Invalid port: ${opts.port}`);\n process.exit(1);\n }\n\n const distDir = path.join(projectRoot, 'dist', 'cdn');\n\n // ── Bundle (unless --no-bundle) ─────────────────────────────────────────\n if (opts.bundle !== false) {\n await runBundle(projectRoot);\n }\n\n if (!fs.existsSync(distDir)) {\n error(\n `Bundle output not found at ${distDir}. Run \\`web5 bundle\\` first or remove --no-bundle.`,\n );\n process.exit(1);\n }\n\n // ── Watch mode: spawn vite --watch in background ────────────────────────\n if (opts.watch) {\n const viteBin = path.join(\n projectRoot,\n 'node_modules',\n '.bin',\n 'vite',\n );\n if (!fs.existsSync(viteBin)) {\n error('vite not found. Run `npm install` in your project first.');\n process.exit(1);\n }\n const watcher = spawn(\n `\"${viteBin}\"`,\n ['build', '--config', 'src/vite.cdn.config.ts', '--watch'],\n { cwd: projectRoot, shell: true, stdio: 'inherit' },\n );\n watcher.on('error', (err_) =>\n error(`Watch process error: ${err_.message}`),\n );\n }\n\n // ── Start HTTP server ───────────────────────────────────────────────────\n const server = startServer(distDir, opts.corsOrigin);\n const url = `http://localhost:${port}`;\n\n server.listen(port, async () => {\n const files = fs.readdirSync(distDir);\n\n if (isJsonMode()) {\n console.log(\n JSON.stringify({\n url,\n port,\n files: files.map((f) => `${url}/${f}`),\n }),\n );\n } else {\n success(`Serving on ${url}`);\n for (const file of files) {\n info(` ${url}/${file}`);\n }\n if (opts.watch) {\n info(\n 'Watch mode active — rebuilds automatically on file changes.',\n );\n }\n info('Press Ctrl+C to stop.');\n }\n\n if (opts.open) {\n const openPkg = (await import('open')).default;\n await openPkg(url);\n }\n });\n } catch (err_) {\n error(err_ instanceof Error ? err_.message : String(err_));\n process.exit(1);\n }\n },\n );\n"],"mappings":"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","ignoreList":[]}
@@ -12,6 +12,7 @@ var path = _interopRequireWildcard(require("path"));
12
12
  var _chalk = _interopRequireDefault(require("chalk"));
13
13
  var _print = require("../utils/print");
14
14
  var _cmsSchemaSchema = require("../templates/cmsSchemaSchema");
15
+ var _cmsMappingSchema = require("../templates/cmsMappingSchema");
15
16
  var _aiInstructionsSchema = require("../templates/aiInstructionsSchema");
16
17
  var _actionYamlSchema = require("../templates/actionYamlSchema");
17
18
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -19,6 +20,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
19
20
 
20
21
  const SCHEMAS = {
21
22
  'cms-schema.yaml': (0, _jsYaml.load)((0, _cmsSchemaSchema.cmsSchemaSchemaTemplate)()),
23
+ 'cms-mapping.yaml': (0, _jsYaml.load)((0, _cmsMappingSchema.cmsMappingSchemaTemplate)()),
22
24
  'prompt-instructions.yaml': (0, _jsYaml.load)((0, _aiInstructionsSchema.aiInstructionsSchemaTemplate)()),
23
25
  'action.yaml': (0, _jsYaml.load)((0, _actionYamlSchema.actionYamlSchemaTemplate)())
24
26
  };
@@ -296,6 +298,91 @@ function buildCmsSchemaDomain(root) {
296
298
  }]
297
299
  };
298
300
  }
301
+ function buildCmsMappingDomain(root) {
302
+ const filePath = path.join(root, 'src', 'configuration', 'cms', 'cms-mapping.yaml');
303
+ const fileName = 'cms-mapping.yaml';
304
+ const ajv = new _2.default({
305
+ allErrors: true,
306
+ strict: false
307
+ });
308
+ const schema = SCHEMAS[fileName];
309
+ let parsed;
310
+ let fileExists = false;
311
+ let yamlOk = false;
312
+ return {
313
+ name: 'CMS Mapping',
314
+ checks: [{
315
+ label: `${fileName} — file exists`,
316
+ run() {
317
+ fileExists = (0, _fs.existsSync)(filePath);
318
+ if (fileExists) {
319
+ return {
320
+ ok: true,
321
+ errors: []
322
+ };
323
+ }
324
+ return {
325
+ ok: false,
326
+ errors: [{
327
+ message: `File not found: ${filePath}`,
328
+ fix: `Create 'src/configuration/cms/cms-mapping.yaml' in your project.`
329
+ }]
330
+ };
331
+ }
332
+ }, {
333
+ label: `${fileName} — valid YAML`,
334
+ run() {
335
+ if (!fileExists) {
336
+ return {
337
+ ok: false,
338
+ errors: [{
339
+ message: 'skipped — file does not exist'
340
+ }]
341
+ };
342
+ }
343
+ const result = tryParseYaml(filePath);
344
+ if (result.err !== undefined) {
345
+ return {
346
+ ok: false,
347
+ errors: [{
348
+ message: result.err,
349
+ fix: 'Fix the YAML syntax error above.'
350
+ }]
351
+ };
352
+ }
353
+ parsed = result.data;
354
+ yamlOk = true;
355
+ return {
356
+ ok: true,
357
+ errors: []
358
+ };
359
+ }
360
+ }, {
361
+ label: `${fileName} — schema valid`,
362
+ run() {
363
+ if (!yamlOk) {
364
+ return {
365
+ ok: false,
366
+ errors: [{
367
+ message: 'skipped — YAML parse failed'
368
+ }]
369
+ };
370
+ }
371
+ const validate = ajv.compile(schema);
372
+ if (validate(parsed)) {
373
+ return {
374
+ ok: true,
375
+ errors: []
376
+ };
377
+ }
378
+ return {
379
+ ok: false,
380
+ errors: (validate.errors ?? []).map(e => formatAjvError(e))
381
+ };
382
+ }
383
+ }]
384
+ };
385
+ }
299
386
  function buildActionsDomain(root) {
300
387
  const actionsDir = path.join(root, 'src', 'actions');
301
388
  const registryPath = path.join(root, 'src', 'createRegistry.ts');
@@ -669,6 +756,260 @@ function buildActionsDomain(root) {
669
756
  };
670
757
  }
671
758
 
759
+ // ── Sections helpers ──────────────────────────────────────────────────────────
760
+
761
+ /**
762
+ * Extracts the text of every `.register(...)` call that has a component array.
763
+ * Uses bracket-counting to handle nesting correctly.
764
+ * Skips system registrations that have no `[` (e.g. SkipNodesSectionDefinition).
765
+ */
766
+ function extractRegisterBlocks(content) {
767
+ const blocks = [];
768
+ const marker = '.register(';
769
+ let searchFrom = 0;
770
+ let start = content.indexOf(marker, searchFrom);
771
+ while (start !== -1) {
772
+ let depth = 0;
773
+ let i = start + marker.length - 1; // position of the opening '('
774
+ while (i < content.length) {
775
+ const ch = content[i];
776
+ if (ch === '(') {
777
+ depth++;
778
+ } else if (ch === ')') {
779
+ depth--;
780
+ if (depth === 0) {
781
+ break;
782
+ }
783
+ }
784
+ i++;
785
+ }
786
+ const block = content.slice(start, i + 1);
787
+ if (block.includes('[')) {
788
+ blocks.push(block);
789
+ }
790
+ searchFrom = i + 1;
791
+ start = content.indexOf(marker, searchFrom);
792
+ }
793
+ return blocks;
794
+ }
795
+
796
+ /**
797
+ * Scans all import lines that reference a `sections/` path and returns a
798
+ * Map<localName, stem>. Handles aliases and multi-name imports:
799
+ * import { KpiSection as KpiSectionComponent } from '...sections/KpiSection'
800
+ * → "KpiSectionComponent" → "KpiSection"
801
+ */
802
+ function buildSectionImportMap(content) {
803
+ const map = new Map();
804
+ const re = /import\s*\{([^}]+)\}\s*from\s*['"][^'"]*sections\/(\w+)['"]/g;
805
+ let m = re.exec(content);
806
+ while (m !== null) {
807
+ const stem = m[2];
808
+ const names = m[1].split(',');
809
+ for (const raw of names) {
810
+ const token = raw.trim();
811
+ if (!token) {
812
+ continue;
813
+ }
814
+ const asParts = token.split(/\s+as\s+/);
815
+ const localName = (asParts[1] ?? asParts[0]).trim();
816
+ if (localName) {
817
+ map.set(localName, stem);
818
+ }
819
+ }
820
+ m = re.exec(content);
821
+ }
822
+ return map;
823
+ }
824
+
825
+ // ── Sections domain ────────────────────────────────────────────────────────────
826
+
827
+ function buildSectionsDomain(root) {
828
+ const registryPath = path.join(root, 'src', 'createRegistry.ts');
829
+ const sectionsDir = path.join(root, 'src', 'components', 'sections');
830
+ let registryExists = false;
831
+ let registryContent = '';
832
+ let tsxFiles = [];
833
+ return {
834
+ name: 'Sections',
835
+ checks: [
836
+ // ── Check 1: createRegistry.ts exists ────────────────────────────────
837
+ {
838
+ label: 'createRegistry.ts — file exists',
839
+ run() {
840
+ registryExists = (0, _fs.existsSync)(registryPath);
841
+ if (!registryExists) {
842
+ return {
843
+ ok: false,
844
+ errors: [{
845
+ message: 'src/createRegistry.ts not found',
846
+ fix: 'Create src/createRegistry.ts and export a createRegistry() function that registers your section components.'
847
+ }]
848
+ };
849
+ }
850
+ registryContent = readText(registryPath);
851
+ tsxFiles = (0, _fs.existsSync)(sectionsDir) ? (0, _fs.readdirSync)(sectionsDir).filter(f => f.endsWith('.tsx')) : [];
852
+ return {
853
+ ok: true,
854
+ errors: []
855
+ };
856
+ }
857
+ },
858
+ // ── Check 2: all .tsx files imported in createRegistry.ts ─────────────
859
+ {
860
+ label: 'src/components/sections/ — all .tsx files imported in createRegistry.ts',
861
+ run() {
862
+ if (!registryExists) {
863
+ return {
864
+ ok: false,
865
+ errors: [{
866
+ message: 'skipped — createRegistry.ts not found'
867
+ }]
868
+ };
869
+ }
870
+ const errors = [];
871
+ for (const file of tsxFiles) {
872
+ const stem = path.basename(file, '.tsx');
873
+ if (!registryContent.includes(`sections/${stem}`)) {
874
+ errors.push({
875
+ message: `'${stem}.tsx' is not imported in src/createRegistry.ts`,
876
+ fix: `Add: import { ${stem} } from './components/sections/${stem}';`
877
+ });
878
+ }
879
+ }
880
+ return errors.length === 0 ? {
881
+ ok: true,
882
+ errors: []
883
+ } : {
884
+ ok: false,
885
+ errors
886
+ };
887
+ }
888
+ },
889
+ // ── Check 3: all .tsx files wired into a .register() call ─────────────
890
+ {
891
+ label: 'src/components/sections/ — all .tsx files wired into .register()',
892
+ run() {
893
+ if (!registryExists) {
894
+ return {
895
+ ok: false,
896
+ errors: [{
897
+ message: 'skipped — createRegistry.ts not found'
898
+ }]
899
+ };
900
+ }
901
+ const importMap = buildSectionImportMap(registryContent);
902
+ const blocks = extractRegisterBlocks(registryContent);
903
+ const blockText = blocks.join('\n');
904
+ const errors = [];
905
+ for (const file of tsxFiles) {
906
+ var _find;
907
+ const stem = path.basename(file, '.tsx');
908
+ // Find the local name for this stem (may have been aliased on import)
909
+ const localName = ((_find = [...importMap.entries()].find(([, s]) => s === stem)) == null ? void 0 : _find[0]) ?? stem;
910
+ if (!blockText.includes(localName)) {
911
+ errors.push({
912
+ message: `'${localName}' (${stem}.tsx) is imported but not passed to any .register() call`,
913
+ fix: `Add { component: ${localName} } inside a .register(new <Definition>(), [...]) call in src/createRegistry.ts.`
914
+ });
915
+ }
916
+ }
917
+ return errors.length === 0 ? {
918
+ ok: true,
919
+ errors: []
920
+ } : {
921
+ ok: false,
922
+ errors
923
+ };
924
+ }
925
+ },
926
+ // ── Check 4: every .register() block has a catch-all entry ────────────
927
+ {
928
+ label: 'createRegistry.ts — all .register() blocks have a catch-all component',
929
+ run() {
930
+ if (!registryExists) {
931
+ return {
932
+ ok: false,
933
+ errors: [{
934
+ message: 'skipped — createRegistry.ts not found'
935
+ }]
936
+ };
937
+ }
938
+ const blocks = extractRegisterBlocks(registryContent);
939
+ const errors = [];
940
+ for (const block of blocks) {
941
+ const defMatch = block.match(/\.register\(\s*new\s+(\w+)/);
942
+ const defName = defMatch ? defMatch[1] : '(unknown)';
943
+
944
+ // Split on "{ component:" to isolate each entry
945
+ const entries = block.split('{ component:').slice(1);
946
+ if (entries.length === 0) {
947
+ continue;
948
+ }
949
+ const allHaveIntent = entries.every(entry => entry.includes('intent:'));
950
+ if (allHaveIntent) {
951
+ errors.push({
952
+ message: `'${defName}' has no catch-all component — every entry specifies an intent`,
953
+ fix: `Add a catch-all entry to the .register(new ${defName}(), [...]) call:\n { component: YourDefaultComponent }`
954
+ });
955
+ }
956
+ }
957
+ return errors.length === 0 ? {
958
+ ok: true,
959
+ errors: []
960
+ } : {
961
+ ok: false,
962
+ errors
963
+ };
964
+ }
965
+ },
966
+ // ── Check 5: all component refs in .register() resolve to a .tsx file ─
967
+ {
968
+ label: 'createRegistry.ts — all .register() component references resolve to a .tsx file',
969
+ run() {
970
+ if (!registryExists) {
971
+ return {
972
+ ok: false,
973
+ errors: [{
974
+ message: 'skipped — createRegistry.ts not found'
975
+ }]
976
+ };
977
+ }
978
+ const importMap = buildSectionImportMap(registryContent);
979
+ const blocks = extractRegisterBlocks(registryContent);
980
+ const errors = [];
981
+ for (const block of blocks) {
982
+ const refs = [...block.matchAll(/\{\s*component:\s*(\w+)/g)].map(m => m[1]);
983
+ for (const ref of refs) {
984
+ const stem = importMap.get(ref);
985
+ if (stem === undefined) {
986
+ errors.push({
987
+ message: `Component '${ref}' used in .register() has no matching import from sections/`,
988
+ fix: `Add: import { ${ref} } from './components/sections/${ref}'; or check the import alias.`
989
+ });
990
+ continue;
991
+ }
992
+ const filePath = path.join(sectionsDir, `${stem}.tsx`);
993
+ if (!(0, _fs.existsSync)(filePath)) {
994
+ errors.push({
995
+ message: `Component '${ref}' maps to '${stem}.tsx' which does not exist in src/components/sections/`,
996
+ fix: `Create src/components/sections/${stem}.tsx, or remove the stale .register() entry from src/createRegistry.ts.`
997
+ });
998
+ }
999
+ }
1000
+ }
1001
+ return errors.length === 0 ? {
1002
+ ok: true,
1003
+ errors: []
1004
+ } : {
1005
+ ok: false,
1006
+ errors
1007
+ };
1008
+ }
1009
+ }]
1010
+ };
1011
+ }
1012
+
672
1013
  // ── Rendering ─────────────────────────────────────────────────────────────────
673
1014
 
674
1015
  function printDomain(domain, results, verbose) {
@@ -831,16 +1172,22 @@ function buildScriptsDomain(root) {
831
1172
 
832
1173
  // ── Domain selection ──────────────────────────────────────────────────────────
833
1174
 
1175
+ const DOMAIN_NAME_MAP = {
1176
+ ai: 'AI Instructions',
1177
+ cms: 'CMS Schema',
1178
+ 'cms-mapping': 'CMS Mapping',
1179
+ scripts: 'Build Scripts',
1180
+ actions: 'Actions',
1181
+ sections: 'Sections'
1182
+ };
834
1183
  function selectDomains(root, filter) {
835
- const all = [buildAiInstructionsDomain(root), buildCmsSchemaDomain(root), buildActionsDomain(root), buildScriptsDomain(root)];
836
- if (!filter) return all;
837
- const map = {
838
- ai: 'AI Instructions',
839
- cms: 'CMS Schema',
840
- scripts: 'Build Scripts',
841
- actions: 'Actions'
842
- };
843
- return all.filter(d => d.name === map[filter]);
1184
+ const all = [buildAiInstructionsDomain(root), buildCmsSchemaDomain(root), buildCmsMappingDomain(root), buildActionsDomain(root), buildScriptsDomain(root), buildSectionsDomain(root)];
1185
+ if (!filter) {
1186
+ return all;
1187
+ }
1188
+ const filters = Array.isArray(filter) ? filter : [filter];
1189
+ const names = new Set(filters.map(f => DOMAIN_NAME_MAP[f]));
1190
+ return all.filter(d => names.has(d.name));
844
1191
  }
845
1192
 
846
1193
  // ── Core runner ───────────────────────────────────────────────────────────────
@@ -861,7 +1208,9 @@ function runDomains(domains, verbose, format) {
861
1208
  } else {
862
1209
  domainOk = printDomain(domain, results, verbose);
863
1210
  }
864
- if (!domainOk) hasErrors = true;
1211
+ if (!domainOk) {
1212
+ hasErrors = true;
1213
+ }
865
1214
  }
866
1215
  return {
867
1216
  ok: !hasErrors,
@@ -872,11 +1221,12 @@ function runDomains(domains, verbose, format) {
872
1221
  // ── Programmatic API ─────────────────────────────────────────────────────────
873
1222
 
874
1223
  /**
875
- * Runs all validation domains against the given project root.
1224
+ * Runs validation domains against the given project root.
1225
+ * Pass `filters` to validate only specific domains; omit to validate all.
876
1226
  * Prints results in slim mode and returns true if everything passes.
877
1227
  */
878
- function runValidation(root) {
879
- const domains = selectDomains(root);
1228
+ function runValidation(root, filters) {
1229
+ const domains = selectDomains(root, filters);
880
1230
  const {
881
1231
  ok
882
1232
  } = runDomains(domains, false, 'text');
@@ -886,14 +1236,16 @@ function runValidation(root) {
886
1236
  // ── Watch mode ────────────────────────────────────────────────────────────────
887
1237
 
888
1238
  function startWatch(root, run) {
889
- const watchDirs = [path.join(root, 'src', 'configuration'), path.join(root, 'src', 'actions')].filter(d => (0, _fs.existsSync)(d));
1239
+ const watchDirs = [path.join(root, 'src', 'configuration'), path.join(root, 'src', 'actions'), path.join(root, 'src', 'components', 'sections'), path.join(root, 'src', 'createRegistry.ts')].filter(d => (0, _fs.existsSync)(d));
890
1240
  if (watchDirs.length === 0) {
891
1241
  (0, _print.error)('No directories to watch found.');
892
1242
  return;
893
1243
  }
894
1244
  let debounce = null;
895
1245
  const trigger = () => {
896
- if (debounce) clearTimeout(debounce);
1246
+ if (debounce) {
1247
+ clearTimeout(debounce);
1248
+ }
897
1249
  debounce = setTimeout(() => {
898
1250
  console.clear();
899
1251
  (0, _print.info)(`[${new Date().toLocaleTimeString()}] Re-validating...`);
@@ -913,7 +1265,7 @@ function startWatch(root, run) {
913
1265
 
914
1266
  // ── Command ───────────────────────────────────────────────────────────────────
915
1267
 
916
- const validateCommand = exports.validateCommand = new _commander.Command('validate').description('Validate project config files against their schemas').option('--verbose', 'Show all checks, including passing ones').option('--domain <domain>', 'Only validate one domain: ai, cms, actions, or scripts').option('--format <format>', 'Output format: text (default) or json', 'text').option('--watch', 'Re-validate on file changes (TTY only)').option('--strict', 'Exit with error even on warnings').option('--project <path>', 'Explicit project root (overrides cwd auto-detection)').action(opts => {
1268
+ const validateCommand = exports.validateCommand = new _commander.Command('validate').description('Validate project config files against their schemas').option('--verbose', 'Show all checks, including passing ones').option('--domain <domain>', 'Only validate one domain: ai, cms, actions, scripts, or sections').option('--format <format>', 'Output format: text (default) or json', 'text').option('--watch', 'Re-validate on file changes (TTY only)').option('--strict', 'Exit with error even on warnings').option('--project <path>', 'Explicit project root (overrides cwd auto-detection)').action(opts => {
917
1269
  const verbose = Boolean(opts.verbose);
918
1270
  const format = opts.format ?? 'text';
919
1271
  const domainFilter = opts.domain;