@onexapis/cli 1.1.66 → 1.1.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import chalk4 from 'chalk';
2
2
  import ora from 'ora';
3
- import path10 from 'path';
3
+ import fs3 from 'fs';
4
+ import path12 from 'path';
4
5
  import { glob } from 'glob';
5
6
  import fs from 'fs-extra';
6
7
  import crypto from 'crypto';
8
+ import fs10 from 'fs/promises';
7
9
  import * as esbuild from 'esbuild';
8
- import fs8 from 'fs/promises';
9
10
  import { createRequire } from 'module';
10
- import fs3 from 'fs';
11
11
  import { execSync, spawn } from 'child_process';
12
12
  import inquirer from 'inquirer';
13
13
  import ejs from 'ejs';
@@ -85,6 +85,13 @@ var init_logger = __esm({
85
85
  logger = new Logger();
86
86
  }
87
87
  });
88
+ function isNextjsProject(dir) {
89
+ return fs3.existsSync(path12.join(dir, "next.config.ts")) || fs3.existsSync(path12.join(dir, "next.config.js")) || fs3.existsSync(path12.join(dir, "next.config.mjs"));
90
+ }
91
+ var init_detect_nextjs = __esm({
92
+ "src/utils/detect-nextjs.ts"() {
93
+ }
94
+ });
88
95
  function sortedCopy(value) {
89
96
  if (Array.isArray(value)) {
90
97
  return value.map((v) => sortedCopy(v));
@@ -167,7 +174,7 @@ async function extractSchemas(themePath) {
167
174
  const sections = {};
168
175
  for (const file of schemaFiles) {
169
176
  try {
170
- const mod = await jiti.import(path10.join(themePath, file));
177
+ const mod = await jiti.import(path12.join(themePath, file));
171
178
  const exports$1 = mod;
172
179
  for (const value of Object.values(exports$1)) {
173
180
  if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
@@ -195,7 +202,7 @@ var init_extract_schemas = __esm({
195
202
  }
196
203
  });
197
204
  function mimeFor(filename) {
198
- const ext = path10.extname(filename).toLowerCase();
205
+ const ext = path12.extname(filename).toLowerCase();
199
206
  return MIME_MAP[ext] || "application/octet-stream";
200
207
  }
201
208
  async function sha256Prefix(absPath, len) {
@@ -203,15 +210,15 @@ async function sha256Prefix(absPath, len) {
203
210
  return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
204
211
  }
205
212
  function insertHashIntoName(relPath, hash) {
206
- const dir = path10.posix.dirname(relPath);
207
- const base = path10.posix.basename(relPath);
208
- const ext = path10.posix.extname(base);
213
+ const dir = path12.posix.dirname(relPath);
214
+ const base = path12.posix.basename(relPath);
215
+ const ext = path12.posix.extname(base);
209
216
  const stem = ext ? base.slice(0, -ext.length) : base;
210
217
  const hashed = `${stem}-${hash}${ext}`;
211
218
  return dir === "." ? hashed : `${dir}/${hashed}`;
212
219
  }
213
220
  async function scanThemeAssets(distDir) {
214
- const assetsDir = path10.join(distDir, "theme-assets");
221
+ const assetsDir = path12.join(distDir, "theme-assets");
215
222
  if (!await fs.pathExists(assetsDir)) return [];
216
223
  const files = await glob("**/*", {
217
224
  cwd: assetsDir,
@@ -220,10 +227,10 @@ async function scanThemeAssets(distDir) {
220
227
  });
221
228
  const results = [];
222
229
  for (const rel of files) {
223
- const absPath = path10.join(assetsDir, rel);
230
+ const absPath = path12.join(assetsDir, rel);
224
231
  const stat = await fs.stat(absPath);
225
232
  if (!stat.isFile()) continue;
226
- const originalPath = rel.split(path10.sep).join("/");
233
+ const originalPath = rel.split(path12.sep).join("/");
227
234
  const hash = await sha256Prefix(absPath, HASH_LEN);
228
235
  const hashedPath = insertHashIntoName(originalPath, hash);
229
236
  const contentType = mimeFor(rel);
@@ -266,6 +273,101 @@ var init_scan_theme_assets = __esm({
266
273
  HASH_LEN = 8;
267
274
  }
268
275
  });
276
+ async function scanAppDirectory(themePath) {
277
+ const appDir = path12.join(themePath, "app");
278
+ let pageFiles;
279
+ try {
280
+ pageFiles = await glob("**/page.{tsx,ts,jsx,js}", { cwd: appDir });
281
+ } catch {
282
+ return [];
283
+ }
284
+ if (pageFiles.length === 0) return [];
285
+ const pages = [];
286
+ for (const pageFile of pageFiles) {
287
+ const routePath = deriveRoutePath(pageFile);
288
+ const absPageFile = path12.join(appDir, pageFile);
289
+ let source;
290
+ try {
291
+ source = await fs10.readFile(absPageFile, "utf-8");
292
+ } catch {
293
+ continue;
294
+ }
295
+ const sections = await extractSectionsFromPage(source, themePath);
296
+ pages.push({
297
+ routePath,
298
+ sourceFile: path12.join("app", pageFile),
299
+ sections
300
+ });
301
+ }
302
+ return pages;
303
+ }
304
+ function deriveRoutePath(pageFile) {
305
+ const dir = path12.dirname(pageFile);
306
+ if (dir === ".") return "/";
307
+ return "/" + dir;
308
+ }
309
+ async function extractSectionsFromPage(source, themePath) {
310
+ const importRegex = /import\s+\w+\s+from\s+["'](@\/|\.\.?\/)(components\/[^"']+)["']/g;
311
+ const sections = [];
312
+ const seen = /* @__PURE__ */ new Set();
313
+ for (const match of source.matchAll(importRegex)) {
314
+ const rawImportPath = match[2];
315
+ const componentDir = path12.dirname(rawImportPath);
316
+ const absComponentDir = path12.join(themePath, componentDir);
317
+ if (seen.has(componentDir)) continue;
318
+ seen.add(componentDir);
319
+ const sectionJsonPath = path12.join(absComponentDir, "section.json");
320
+ let sectionJson;
321
+ try {
322
+ const raw = await fs10.readFile(sectionJsonPath, "utf-8");
323
+ sectionJson = JSON.parse(raw);
324
+ } catch {
325
+ continue;
326
+ }
327
+ if (sectionJson.type !== "opaque-react") continue;
328
+ if (!sectionJson.entry) continue;
329
+ sections.push({
330
+ type: "opaque-react",
331
+ name: sectionJson.name ?? path12.basename(componentDir),
332
+ entry: path12.join(componentDir, sectionJson.entry),
333
+ componentDir
334
+ });
335
+ }
336
+ return sections;
337
+ }
338
+ function buildNextjsPagesMap(pages, themeId) {
339
+ const result = {};
340
+ for (const page of pages) {
341
+ const id = page.routePath === "/" ? "home" : page.routePath.replace(/\//g, "-").replace(/^-/, "");
342
+ const makeSectionType = (name) => `${themeId}-${name.toLowerCase().replace(/\s+/g, "-")}`;
343
+ result[id] = {
344
+ id,
345
+ name: id.charAt(0).toUpperCase() + id.slice(1),
346
+ path: page.routePath,
347
+ config: {
348
+ id,
349
+ path: page.routePath,
350
+ sections: page.sections.map((s, i) => ({
351
+ id: `${id}-section-${i}`,
352
+ type: makeSectionType(s.name),
353
+ sectionType: "opaque-react",
354
+ settings: {}
355
+ }))
356
+ },
357
+ sections: page.sections.map((s, i) => ({
358
+ id: `${id}-section-${i}`,
359
+ type: makeSectionType(s.name),
360
+ sectionType: "opaque-react",
361
+ settings: {}
362
+ }))
363
+ };
364
+ }
365
+ return result;
366
+ }
367
+ var init_nextjs_page_scanner = __esm({
368
+ "src/utils/nextjs-page-scanner.ts"() {
369
+ }
370
+ });
269
371
 
270
372
  // src/utils/compile-theme.ts
271
373
  var compile_theme_exports = {};
@@ -281,8 +383,8 @@ async function generateThemeCSS(themePath, outDir) {
281
383
  const tailwindcss = (await import('tailwindcss')).default;
282
384
  const tailwindConfig = {
283
385
  content: [
284
- path10.join(themePath, "sections/**/*.{ts,tsx}"),
285
- path10.join(themePath, "components/**/*.{ts,tsx}")
386
+ path12.join(themePath, "sections/**/*.{ts,tsx}"),
387
+ path12.join(themePath, "components/**/*.{ts,tsx}")
286
388
  ],
287
389
  theme: { extend: {} },
288
390
  plugins: []
@@ -292,7 +394,7 @@ async function generateThemeCSS(themePath, outDir) {
292
394
  inputCSS,
293
395
  { from: void 0 }
294
396
  );
295
- await fs8.writeFile(path10.join(outDir, "bundle.css"), result.css);
397
+ await fs10.writeFile(path12.join(outDir, "bundle.css"), result.css);
296
398
  logger.info("Generated bundle.css");
297
399
  } catch (err) {
298
400
  logger.warning(
@@ -303,12 +405,12 @@ async function generateThemeCSS(themePath, outDir) {
303
405
  async function resolveNodeModulesFile(startDir, relativePath) {
304
406
  let dir = startDir;
305
407
  while (true) {
306
- const candidate = path10.join(dir, "node_modules", relativePath);
408
+ const candidate = path12.join(dir, "node_modules", relativePath);
307
409
  try {
308
- await fs8.access(candidate);
410
+ await fs10.access(candidate);
309
411
  return candidate;
310
412
  } catch {
311
- const parent = path10.dirname(dir);
413
+ const parent = path12.dirname(dir);
312
414
  if (parent === dir) break;
313
415
  dir = parent;
314
416
  }
@@ -332,7 +434,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
332
434
  });
333
435
  for (const file of sourceFiles) {
334
436
  try {
335
- const content = await fs8.readFile(path10.join(sourceDir, file), "utf-8");
437
+ const content = await fs10.readFile(path12.join(sourceDir, file), "utf-8");
336
438
  for (const match of content.matchAll(namespaceImportRegex)) {
337
439
  const subpath = match[1] ? match[1].slice(1) : "";
338
440
  if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
@@ -386,17 +488,17 @@ function createCoreGlobalPlugin(themePath) {
386
488
  const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
387
489
  let distPath = await resolveNodeModulesFile(
388
490
  themePath,
389
- path10.join("@onexapis", "core", "dist", distFileName)
491
+ path12.join("@onexapis", "core", "dist", distFileName)
390
492
  );
391
493
  if (!distPath) {
392
494
  distPath = await resolveNodeModulesFile(
393
495
  __dirname,
394
- path10.join("@onexapis", "core", "dist", distFileName)
496
+ path12.join("@onexapis", "core", "dist", distFileName)
395
497
  );
396
498
  }
397
499
  try {
398
500
  if (!distPath) throw new Error("not found");
399
- const distContent = await fs8.readFile(distPath, "utf-8");
501
+ const distContent = await fs10.readFile(distPath, "utf-8");
400
502
  const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
401
503
  for (const m of exportMatches) {
402
504
  const names = m[1].split(",").map((n) => {
@@ -443,180 +545,6 @@ ${namedExportLines}
443
545
  }
444
546
  };
445
547
  }
446
- function createThemeDepsStubPlugin(themePath) {
447
- return {
448
- name: "theme-deps-stub",
449
- setup(build2) {
450
- const tryResolveOrStub = (filter, namespace) => {
451
- build2.onResolve({ filter }, async (args) => {
452
- if (args.pluginData?.skipStub) return void 0;
453
- try {
454
- const result = await build2.resolve(args.path, {
455
- kind: args.kind,
456
- resolveDir: args.resolveDir || themePath,
457
- importer: args.importer,
458
- namespace: "file",
459
- pluginData: { skipStub: true }
460
- });
461
- if (!result.errors.length) return result;
462
- } catch {
463
- }
464
- try {
465
- const req = createRequire(import.meta.url || __filename);
466
- const resolved = req.resolve(args.path);
467
- if (resolved) return { path: resolved, namespace: "file" };
468
- } catch {
469
- }
470
- return { path: args.path, namespace };
471
- });
472
- };
473
- tryResolveOrStub(/^next\//, "next-stub");
474
- build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
475
- const stubs = {
476
- "next/image": `
477
- import React from 'react';
478
- const Image = React.forwardRef((props, ref) => {
479
- const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
480
- const imgSrc = typeof src === 'object' ? src.src : src;
481
- const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
482
- const mergedStyle = { ...fillStyle, ...style };
483
- return React.createElement('img', {
484
- ref, src: imgSrc, alt,
485
- width: fill ? undefined : width, height: fill ? undefined : height,
486
- loading: priority ? 'eager' : 'lazy',
487
- style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
488
- className, onLoad, onError, ...rest,
489
- });
490
- });
491
- export default Image;
492
- `,
493
- "next/link": `
494
- import React from 'react';
495
- const Link = ({ href, children, ...rest }) => React.createElement('a', { href, ...rest }, children);
496
- export default Link;
497
- `,
498
- "next/navigation": `
499
- export function useRouter() { return { push(u){window.location.href=u}, replace(u){window.location.href=u}, back(){window.history.back()}, forward(){window.history.forward()}, refresh(){window.location.reload()}, prefetch(){} }; }
500
- export function usePathname() { return window.location.pathname; }
501
- export function useSearchParams() { return new URLSearchParams(window.location.search); }
502
- export function useParams() { return {}; }
503
- export function redirect(url) { window.location.href = url; }
504
- export function notFound() { throw new Error('Not Found'); }
505
- `,
506
- "next/headers": `
507
- export function cookies() { return { get(){}, getAll(){ return []; }, set(){}, delete(){}, has(){ return false; } }; }
508
- export function headers() { return new Headers(); }
509
- `
510
- };
511
- return {
512
- contents: stubs[args.path] || "export default {};",
513
- loader: "jsx",
514
- resolveDir: themePath
515
- };
516
- });
517
- const lucideImports = /* @__PURE__ */ new Set();
518
- let lucideThemeScanned = false;
519
- tryResolveOrStub(/^lucide-react/, "lucide-stub");
520
- build2.onLoad({ filter: /.*/, namespace: "lucide-stub" }, async () => {
521
- if (!lucideThemeScanned) {
522
- lucideThemeScanned = true;
523
- try {
524
- const scanned = await scanImportsFromPackage(
525
- themePath,
526
- "lucide-react"
527
- );
528
- for (const names of Object.values(scanned)) {
529
- for (const name of names) lucideImports.add(name);
530
- }
531
- } catch {
532
- }
533
- }
534
- const iconNames = [...lucideImports];
535
- const exports$1 = iconNames.map((n) => `icon as ${n}`).join(", ");
536
- return {
537
- contents: `
538
- const icon = (props) => null;
539
- export { ${exports$1} };
540
- export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true : icon });
541
- `.trim(),
542
- loader: "jsx"
543
- };
544
- });
545
- tryResolveOrStub(/^framer-motion/, "motion-stub");
546
- build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
547
- contents: `
548
- import React from 'react';
549
- const handler = { get: (_, name) => {
550
- if (name === '__esModule') return true;
551
- return React.forwardRef((props, ref) => React.createElement(name, { ...props, ref }));
552
- }};
553
- export const motion = new Proxy({}, handler);
554
- export const AnimatePresence = ({ children }) => children || null;
555
- export function useInView() { return true; }
556
- export default { motion, AnimatePresence, useInView };
557
- `.trim(),
558
- loader: "jsx",
559
- resolveDir: themePath
560
- }));
561
- tryResolveOrStub(/^sonner$/, "sonner-stub");
562
- build2.onLoad({ filter: /.*/, namespace: "sonner-stub" }, () => ({
563
- contents: `
564
- export const toast = new Proxy(() => {}, { get: () => () => {} });
565
- export const Toaster = () => null;
566
- export default { toast, Toaster };
567
- `.trim(),
568
- loader: "jsx"
569
- }));
570
- tryResolveOrStub(/^react-hook-form$/, "rhf-stub");
571
- build2.onLoad({ filter: /.*/, namespace: "rhf-stub" }, () => ({
572
- contents: `
573
- export function useForm() {
574
- return {
575
- register: () => ({}),
576
- handleSubmit: (fn) => (e) => { e?.preventDefault?.(); fn({}); },
577
- formState: { errors: {}, isSubmitting: false, isValid: true },
578
- watch: () => undefined,
579
- setValue: () => {},
580
- reset: () => {},
581
- control: {},
582
- };
583
- }
584
- export function useController() { return { field: {}, fieldState: {} }; }
585
- export function useFormContext() { return useForm(); }
586
- `.trim(),
587
- loader: "js"
588
- }));
589
- tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
590
- build2.onLoad(
591
- { filter: /.*/, namespace: "hookform-resolvers-stub" },
592
- () => ({
593
- contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
594
- loader: "js"
595
- })
596
- );
597
- tryResolveOrStub(/^next-intl$/, "next-intl-stub");
598
- build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
599
- contents: `
600
- export function useTranslations(ns) {
601
- return (key) => ns ? ns + '.' + key : key;
602
- }
603
- export function useLocale() { return 'en'; }
604
- export function useMessages() { return {}; }
605
- `.trim(),
606
- loader: "js"
607
- }));
608
- tryResolveOrStub(/^zod$/, "zod-stub");
609
- build2.onLoad({ filter: /.*/, namespace: "zod-stub" }, () => ({
610
- contents: `
611
- const schema = () => ({ parse: (v) => v, safeParse: (v) => ({ success: true, data: v }), optional: schema, min: schema, max: schema, email: schema, url: schema, regex: schema, refine: schema, transform: schema });
612
- export const z = { string: schema, number: schema, boolean: schema, object: (s) => ({ ...schema(), shape: s }), array: schema, enum: schema, union: schema, literal: schema, infer: undefined };
613
- export default z;
614
- `.trim(),
615
- loader: "js"
616
- }));
617
- }
618
- };
619
- }
620
548
  async function generateThemeData(themePath, outputDir, themeId) {
621
549
  const { createJiti } = await import('jiti');
622
550
  const jiti = createJiti(import.meta.url);
@@ -625,7 +553,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
625
553
  const pages = {};
626
554
  for (const ext of [".ts", ".js"]) {
627
555
  try {
628
- const mod = await jiti.import(path10.join(themePath, `theme.config${ext}`));
556
+ const mod = await jiti.import(path12.join(themePath, `theme.config${ext}`));
629
557
  themeConfig = mod.default || mod;
630
558
  break;
631
559
  } catch {
@@ -633,20 +561,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
633
561
  }
634
562
  for (const ext of [".ts", ".js"]) {
635
563
  try {
636
- const mod = await jiti.import(path10.join(themePath, `theme.layout${ext}`));
564
+ const mod = await jiti.import(path12.join(themePath, `theme.layout${ext}`));
637
565
  layoutConfig = mod.default || mod;
638
566
  break;
639
567
  } catch {
640
568
  }
641
569
  }
642
570
  const schemas = {};
643
- const sectionsDir = path10.join(themePath, "sections");
571
+ const sectionsDir = path12.join(themePath, "sections");
644
572
  try {
645
- const sectionDirs = await fs8.readdir(sectionsDir);
573
+ const sectionDirs = await fs10.readdir(sectionsDir);
646
574
  for (const dir of sectionDirs) {
647
- const schemaFile = path10.join(sectionsDir, dir, `${dir}.schema.ts`);
575
+ const schemaFile = path12.join(sectionsDir, dir, `${dir}.schema.ts`);
648
576
  try {
649
- await fs8.access(schemaFile);
577
+ await fs10.access(schemaFile);
650
578
  const mod = await jiti.import(schemaFile);
651
579
  for (const [key, value] of Object.entries(mod)) {
652
580
  if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
@@ -658,14 +586,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
658
586
  }
659
587
  } catch {
660
588
  }
661
- const pagesDir = path10.join(themePath, "pages");
589
+ const pagesDir = path12.join(themePath, "pages");
662
590
  try {
663
- const files = await fs8.readdir(pagesDir);
591
+ const files = await fs10.readdir(pagesDir);
664
592
  for (const file of files) {
665
593
  if (!file.match(/\.(ts|js)$/)) continue;
666
594
  const name = file.replace(/\.(ts|js)$/, "");
667
595
  try {
668
- const mod = await jiti.import(path10.join(pagesDir, file));
596
+ const mod = await jiti.import(path12.join(pagesDir, file));
669
597
  const config = mod.default || mod;
670
598
  const sections = (config.sections || []).map((section) => {
671
599
  const schema = schemas[section.type];
@@ -693,8 +621,16 @@ async function generateThemeData(themePath, outputDir, themeId) {
693
621
  }
694
622
  } catch {
695
623
  }
696
- await fs8.writeFile(
697
- path10.join(outputDir, "theme-data.json"),
624
+ if (isNextjsProject(themePath)) {
625
+ const nextjsPages = await scanAppDirectory(themePath);
626
+ if (nextjsPages.length > 0) {
627
+ const nextjsPagesMap = buildNextjsPagesMap(nextjsPages, themeId);
628
+ Object.assign(pages, nextjsPagesMap);
629
+ logger.info(`Scanned ${nextjsPages.length} Next.js app/ pages`);
630
+ }
631
+ }
632
+ await fs10.writeFile(
633
+ path12.join(outputDir, "theme-data.json"),
698
634
  JSON.stringify(
699
635
  {
700
636
  themeId,
@@ -717,22 +653,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
717
653
  logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
718
654
  }
719
655
  async function contentHashEntry(outputDir) {
720
- const entryPath = path10.join(outputDir, "bundle-entry.js");
721
- const mapPath = path10.join(outputDir, "bundle-entry.js.map");
656
+ const entryPath = path12.join(outputDir, "bundle-entry.js");
657
+ const mapPath = path12.join(outputDir, "bundle-entry.js.map");
722
658
  let entryContent;
723
659
  try {
724
- entryContent = await fs8.readFile(entryPath, "utf-8");
660
+ entryContent = await fs10.readFile(entryPath, "utf-8");
725
661
  } catch {
726
- const indexPath = path10.join(outputDir, "index.js");
662
+ const indexPath = path12.join(outputDir, "index.js");
727
663
  try {
728
- entryContent = await fs8.readFile(indexPath, "utf-8");
664
+ entryContent = await fs10.readFile(indexPath, "utf-8");
729
665
  } catch {
730
666
  logger.warning("No entry file found in output, skipping content hash");
731
667
  return;
732
668
  }
733
669
  const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
734
670
  const hashedName2 = `bundle-entry-${hash2}.js`;
735
- const indexMapPath = path10.join(outputDir, "index.js.map");
671
+ const indexMapPath = path12.join(outputDir, "index.js.map");
736
672
  const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
737
673
  entryContent = entryContent.replace(
738
674
  /\/\/# sourceMappingURL=index\.js\.map/,
@@ -740,18 +676,18 @@ async function contentHashEntry(outputDir) {
740
676
  );
741
677
  const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
742
678
  for (const f of oldFiles2) {
743
- await fs8.unlink(path10.join(outputDir, f));
679
+ await fs10.unlink(path12.join(outputDir, f));
744
680
  }
745
- await fs8.writeFile(path10.join(outputDir, hashedName2), entryContent);
746
- await fs8.unlink(indexPath);
681
+ await fs10.writeFile(path12.join(outputDir, hashedName2), entryContent);
682
+ await fs10.unlink(indexPath);
747
683
  try {
748
- await fs8.unlink(entryPath);
684
+ await fs10.unlink(entryPath);
749
685
  } catch {
750
686
  }
751
- await fs8.writeFile(entryPath, entryContent);
687
+ await fs10.writeFile(entryPath, entryContent);
752
688
  try {
753
- await fs8.access(indexMapPath);
754
- await fs8.rename(indexMapPath, path10.join(outputDir, hashedMapName2));
689
+ await fs10.access(indexMapPath);
690
+ await fs10.rename(indexMapPath, path12.join(outputDir, hashedMapName2));
755
691
  } catch {
756
692
  }
757
693
  logger.info(`Entry hashed: ${hashedName2}`);
@@ -766,17 +702,17 @@ async function contentHashEntry(outputDir) {
766
702
  );
767
703
  const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
768
704
  for (const f of oldFiles) {
769
- await fs8.unlink(path10.join(outputDir, f));
705
+ await fs10.unlink(path12.join(outputDir, f));
770
706
  }
771
- await fs8.writeFile(path10.join(outputDir, hashedName), entryContent);
707
+ await fs10.writeFile(path12.join(outputDir, hashedName), entryContent);
772
708
  try {
773
- await fs8.unlink(entryPath);
709
+ await fs10.unlink(entryPath);
774
710
  } catch {
775
711
  }
776
- await fs8.writeFile(entryPath, entryContent);
712
+ await fs10.writeFile(entryPath, entryContent);
777
713
  try {
778
- await fs8.access(mapPath);
779
- await fs8.rename(mapPath, path10.join(outputDir, hashedMapName));
714
+ await fs10.access(mapPath);
715
+ await fs10.rename(mapPath, path12.join(outputDir, hashedMapName));
780
716
  } catch {
781
717
  }
782
718
  logger.info(`Entry hashed: ${hashedName}`);
@@ -788,7 +724,7 @@ async function extractDataRequirements(themePath) {
788
724
  const requirements = {};
789
725
  for (const file of schemaFiles) {
790
726
  try {
791
- const mod = await jiti.import(path10.join(themePath, file));
727
+ const mod = await jiti.import(path12.join(themePath, file));
792
728
  const exports$1 = mod;
793
729
  for (const value of Object.values(exports$1)) {
794
730
  if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
@@ -806,8 +742,8 @@ async function extractDataRequirements(themePath) {
806
742
  async function writeGateManifests(themePath, outputDir) {
807
743
  try {
808
744
  const schemas = await extractSchemas(themePath);
809
- await fs8.writeFile(
810
- path10.join(outputDir, "schemas.json"),
745
+ await fs10.writeFile(
746
+ path12.join(outputDir, "schemas.json"),
811
747
  serializeManifest(schemas)
812
748
  );
813
749
  logger.info(
@@ -826,8 +762,8 @@ async function writeGateManifests(themePath, outputDir) {
826
762
  size: e.size,
827
763
  contentType: e.contentType
828
764
  }));
829
- await fs8.writeFile(
830
- path10.join(outputDir, "asset-manifest.json"),
765
+ await fs10.writeFile(
766
+ path12.join(outputDir, "asset-manifest.json"),
831
767
  JSON.stringify({ manifestVersion: 1, assets }, null, 2)
832
768
  );
833
769
  logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
@@ -837,12 +773,71 @@ async function writeGateManifests(themePath, outputDir) {
837
773
  );
838
774
  }
839
775
  }
776
+ async function compileSections(themePath, outputDir) {
777
+ const sectionsDir = path12.join(themePath, "sections");
778
+ let sectionDirs;
779
+ try {
780
+ sectionDirs = await fs10.readdir(sectionsDir);
781
+ } catch {
782
+ return;
783
+ }
784
+ for (const dirName of sectionDirs) {
785
+ const sectionSrc = path12.join(sectionsDir, dirName);
786
+ const sectionOut = path12.join(outputDir, "sections", dirName);
787
+ let section = null;
788
+ try {
789
+ const raw = await fs10.readFile(
790
+ path12.join(sectionSrc, "section.manifest.json"),
791
+ "utf-8"
792
+ );
793
+ section = JSON.parse(raw);
794
+ } catch {
795
+ continue;
796
+ }
797
+ switch (section.type) {
798
+ case "editable":
799
+ case "opaque-react":
800
+ break;
801
+ case "html": {
802
+ await fs10.mkdir(sectionOut, { recursive: true });
803
+ const htmlSrc = path12.join(sectionSrc, section.html);
804
+ let htmlContent = await fs10.readFile(htmlSrc, "utf-8");
805
+ htmlContent = htmlContent.replace(
806
+ /<script[^>]+src=["']https?:\/\/[^"']*["'][^>]*><\/script>/gi,
807
+ ""
808
+ );
809
+ await fs10.writeFile(path12.join(sectionOut, path12.basename(section.html)), htmlContent);
810
+ if (section.css) {
811
+ await fs10.copyFile(
812
+ path12.join(sectionSrc, section.css),
813
+ path12.join(sectionOut, path12.basename(section.css))
814
+ );
815
+ }
816
+ break;
817
+ }
818
+ case "iframe":
819
+ break;
820
+ case "webcomponent": {
821
+ await fs10.mkdir(sectionOut, { recursive: true });
822
+ await fs10.copyFile(
823
+ path12.join(sectionSrc, section.bundle),
824
+ path12.join(sectionOut, path12.basename(section.bundle))
825
+ );
826
+ break;
827
+ }
828
+ default:
829
+ throw new Error(
830
+ `Unknown section type. Valid types: editable, opaque-react, html, iframe, webcomponent`
831
+ );
832
+ }
833
+ }
834
+ }
840
835
  async function generateManifest(themeName, themePath, outputDir) {
841
836
  let version = "1.0.0";
842
837
  let themeId = themeName;
843
838
  try {
844
- const pkgContent = await fs8.readFile(
845
- path10.join(themePath, "package.json"),
839
+ const pkgContent = await fs10.readFile(
840
+ path12.join(themePath, "package.json"),
846
841
  "utf-8"
847
842
  );
848
843
  const pkg = JSON.parse(pkgContent);
@@ -860,7 +855,7 @@ async function generateManifest(themeName, themePath, outputDir) {
860
855
  const dataRequirements = await extractDataRequirements(themePath);
861
856
  let hasThemeConfig = false;
862
857
  try {
863
- await fs8.access(path10.join(themePath, "theme.config.ts"));
858
+ await fs10.access(path12.join(themePath, "theme.config.ts"));
864
859
  hasThemeConfig = true;
865
860
  } catch {
866
861
  }
@@ -901,24 +896,34 @@ async function generateManifest(themeName, themePath, outputDir) {
901
896
  // Section data requirements for server-side prefetching (keyed by section type)
902
897
  dataRequirements
903
898
  };
904
- await fs8.writeFile(
905
- path10.join(outputDir, "manifest.json"),
899
+ await fs10.writeFile(
900
+ path12.join(outputDir, "manifest.json"),
906
901
  JSON.stringify(manifest, null, 2)
907
902
  );
908
903
  }
909
904
  async function compileStandaloneTheme(themePath, themeName) {
910
- const outputDir = path10.join(themePath, "dist");
911
- const bundleEntry = path10.join(themePath, "bundle-entry.ts");
912
- const indexEntry = path10.join(themePath, "index.ts");
905
+ const outputDir = path12.join(themePath, "dist");
906
+ const isNextjs = isNextjsProject(themePath);
907
+ if (isNextjs) {
908
+ logger.info("Detected Next.js project \u2014 using next/* shims");
909
+ }
910
+ const bundleEntry = path12.join(themePath, "bundle-entry.ts");
911
+ const indexEntry = path12.join(themePath, "index.ts");
913
912
  let entryPoint = indexEntry;
914
913
  try {
915
- await fs8.access(bundleEntry);
914
+ await fs10.access(bundleEntry);
916
915
  entryPoint = bundleEntry;
917
916
  } catch {
918
917
  }
919
- const shimPath = path10.join(outputDir, ".process-shim.js");
920
- await fs8.mkdir(outputDir, { recursive: true });
921
- await fs8.writeFile(shimPath, PROCESS_SHIM);
918
+ const shimPath = path12.join(outputDir, ".process-shim.js");
919
+ await fs10.mkdir(outputDir, { recursive: true });
920
+ await fs10.writeFile(shimPath, PROCESS_SHIM);
921
+ const plugins = [
922
+ reactGlobalPlugin,
923
+ reactQueryGlobalPlugin,
924
+ createCoreGlobalPlugin(themePath)
925
+ ];
926
+ if (isNextjs) plugins.unshift(nextShimPlugin);
922
927
  const buildOptions = {
923
928
  entryPoints: [entryPoint],
924
929
  bundle: true,
@@ -930,12 +935,7 @@ async function compileStandaloneTheme(themePath, themeName) {
930
935
  banner: {
931
936
  js: '"use client";'
932
937
  },
933
- plugins: [
934
- reactGlobalPlugin,
935
- reactQueryGlobalPlugin,
936
- createCoreGlobalPlugin(themePath),
937
- createThemeDepsStubPlugin(themePath)
938
- ],
938
+ plugins,
939
939
  external: [],
940
940
  alias: {
941
941
  events: "events/",
@@ -969,15 +969,16 @@ async function compileStandaloneTheme(themePath, themeName) {
969
969
  try {
970
970
  const result = await esbuild.build(buildOptions);
971
971
  try {
972
- await fs8.unlink(shimPath);
972
+ await fs10.unlink(shimPath);
973
973
  } catch {
974
974
  }
975
+ await compileSections(themePath, outputDir);
975
976
  await contentHashEntry(outputDir);
976
- const themeAssetsDir = path10.join(themePath, "assets");
977
- const distThemeAssets = path10.join(outputDir, "theme-assets");
977
+ const themeAssetsDir = path12.join(themePath, "assets");
978
+ const distThemeAssets = path12.join(outputDir, "theme-assets");
978
979
  try {
979
- await fs8.access(themeAssetsDir);
980
- await fs8.cp(themeAssetsDir, distThemeAssets, { recursive: true });
980
+ await fs10.access(themeAssetsDir);
981
+ await fs10.cp(themeAssetsDir, distThemeAssets, { recursive: true });
981
982
  logger.info("Copied static assets to dist/theme-assets/");
982
983
  } catch {
983
984
  }
@@ -997,7 +998,7 @@ async function compileStandaloneTheme(themePath, themeName) {
997
998
  return true;
998
999
  } catch (error) {
999
1000
  try {
1000
- await fs8.unlink(shimPath);
1001
+ await fs10.unlink(shimPath);
1001
1002
  } catch {
1002
1003
  }
1003
1004
  logger.error(`esbuild compilation failed: ${error}`);
@@ -1005,18 +1006,25 @@ async function compileStandaloneTheme(themePath, themeName) {
1005
1006
  }
1006
1007
  }
1007
1008
  async function compileStandaloneThemeDev(themePath, themeName) {
1008
- const outputDir = path10.join(themePath, "dist");
1009
- const bundleEntry = path10.join(themePath, "bundle-entry.ts");
1010
- const indexEntry = path10.join(themePath, "index.ts");
1009
+ const outputDir = path12.join(themePath, "dist");
1010
+ const isNextjs = isNextjsProject(themePath);
1011
+ const bundleEntry = path12.join(themePath, "bundle-entry.ts");
1012
+ const indexEntry = path12.join(themePath, "index.ts");
1011
1013
  let entryPoint = indexEntry;
1012
1014
  try {
1013
- await fs8.access(bundleEntry);
1015
+ await fs10.access(bundleEntry);
1014
1016
  entryPoint = bundleEntry;
1015
1017
  } catch {
1016
1018
  }
1017
- const shimPath = path10.join(outputDir, ".process-shim.js");
1018
- await fs8.mkdir(outputDir, { recursive: true });
1019
- await fs8.writeFile(shimPath, PROCESS_SHIM);
1019
+ const shimPath = path12.join(outputDir, ".process-shim.js");
1020
+ await fs10.mkdir(outputDir, { recursive: true });
1021
+ await fs10.writeFile(shimPath, PROCESS_SHIM);
1022
+ const devPlugins = [
1023
+ reactGlobalPlugin,
1024
+ reactQueryGlobalPlugin,
1025
+ createCoreGlobalPlugin(themePath)
1026
+ ];
1027
+ if (isNextjs) devPlugins.unshift(nextShimPlugin);
1020
1028
  const buildOptions = {
1021
1029
  entryPoints: [entryPoint],
1022
1030
  bundle: true,
@@ -1027,12 +1035,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
1027
1035
  banner: {
1028
1036
  js: '"use client";'
1029
1037
  },
1030
- plugins: [
1031
- reactGlobalPlugin,
1032
- reactQueryGlobalPlugin,
1033
- createCoreGlobalPlugin(themePath),
1034
- createThemeDepsStubPlugin(themePath)
1035
- ],
1038
+ plugins: devPlugins,
1036
1039
  external: [],
1037
1040
  alias: {
1038
1041
  events: "events/",
@@ -1070,18 +1073,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
1070
1073
  return { context: context2, outputDir };
1071
1074
  }
1072
1075
  async function compilePreviewRuntime(themePath) {
1073
- const outputDir = path10.join(themePath, "dist");
1074
- await fs8.mkdir(outputDir, { recursive: true });
1075
- const outputPath = path10.join(outputDir, "preview-runtime.js");
1076
+ const outputDir = path12.join(themePath, "dist");
1077
+ await fs10.mkdir(outputDir, { recursive: true });
1078
+ const outputPath = path12.join(outputDir, "preview-runtime.js");
1076
1079
  const locations = [
1077
- path10.join(__dirname, "..", "preview", "preview-app.tsx"),
1078
- path10.join(__dirname, "preview", "preview-app.tsx"),
1079
- path10.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
1080
+ path12.join(__dirname, "..", "preview", "preview-app.tsx"),
1081
+ path12.join(__dirname, "preview", "preview-app.tsx"),
1082
+ path12.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
1080
1083
  ];
1081
1084
  let previewEntryPath = null;
1082
1085
  for (const loc of locations) {
1083
1086
  try {
1084
- await fs8.access(loc);
1087
+ await fs10.access(loc);
1085
1088
  previewEntryPath = loc;
1086
1089
  break;
1087
1090
  } catch {
@@ -1164,10 +1167,10 @@ ${locations.join("\n")}`
1164
1167
  if (!lucideScanned) {
1165
1168
  lucideScanned = true;
1166
1169
  const coreSrcCandidates = [
1167
- path10.join(themePath, "node_modules", "@onexapis", "core", "src"),
1168
- path10.join(themePath, "..", "..", "packages", "core", "src"),
1170
+ path12.join(themePath, "node_modules", "@onexapis", "core", "src"),
1171
+ path12.join(themePath, "..", "..", "packages", "core", "src"),
1169
1172
  // monorepo sibling
1170
- path10.join(
1173
+ path12.join(
1171
1174
  __dirname,
1172
1175
  "..",
1173
1176
  "..",
@@ -1182,7 +1185,7 @@ ${locations.join("\n")}`
1182
1185
  let coreSourceDir = null;
1183
1186
  for (const candidate of coreSrcCandidates) {
1184
1187
  try {
1185
- await fs8.access(candidate);
1188
+ await fs10.access(candidate);
1186
1189
  coreSourceDir = candidate;
1187
1190
  break;
1188
1191
  } catch {
@@ -1201,21 +1204,21 @@ ${locations.join("\n")}`
1201
1204
  }
1202
1205
  } else {
1203
1206
  const coreDistCandidates = [
1204
- path10.join(themePath, "node_modules", "@onexapis", "core", "dist")
1207
+ path12.join(themePath, "node_modules", "@onexapis", "core", "dist")
1205
1208
  ];
1206
1209
  const resolvedDist = await resolveNodeModulesFile(
1207
1210
  __dirname,
1208
- path10.join("@onexapis", "core", "dist")
1211
+ path12.join("@onexapis", "core", "dist")
1209
1212
  );
1210
1213
  if (resolvedDist) coreDistCandidates.push(resolvedDist);
1211
1214
  for (const candidate of coreDistCandidates) {
1212
1215
  try {
1213
- await fs8.access(candidate);
1216
+ await fs10.access(candidate);
1214
1217
  const mjsFiles = await glob("*.mjs", { cwd: candidate });
1215
1218
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
1216
1219
  for (const file of mjsFiles) {
1217
- const content = await fs8.readFile(
1218
- path10.join(candidate, file),
1220
+ const content = await fs10.readFile(
1221
+ path12.join(candidate, file),
1219
1222
  "utf-8"
1220
1223
  );
1221
1224
  for (const match of content.matchAll(importRegex)) {
@@ -1270,7 +1273,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
1270
1273
  const req = createRequire(import.meta.url || __filename);
1271
1274
  const cjsPath = req.resolve("framer-motion");
1272
1275
  const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
1273
- const esmEntry = path10.join(pkgDir, "dist", "es", "index.mjs");
1276
+ const esmEntry = path12.join(pkgDir, "dist", "es", "index.mjs");
1274
1277
  const { existsSync } = await import('fs');
1275
1278
  if (existsSync(esmEntry)) {
1276
1279
  return { path: esmEntry, namespace: "file" };
@@ -1369,8 +1372,8 @@ export function headers() { return new Headers(); }
1369
1372
  });
1370
1373
  }
1371
1374
  };
1372
- const shimPath = path10.join(outputDir, ".process-shim-preview.js");
1373
- await fs8.writeFile(shimPath, PROCESS_SHIM);
1375
+ const shimPath = path12.join(outputDir, ".process-shim-preview.js");
1376
+ await fs10.writeFile(shimPath, PROCESS_SHIM);
1374
1377
  await esbuild.build({
1375
1378
  entryPoints: [previewEntryPath],
1376
1379
  bundle: true,
@@ -1405,17 +1408,19 @@ export function headers() { return new Headers(); }
1405
1408
  }
1406
1409
  });
1407
1410
  try {
1408
- await fs8.unlink(shimPath);
1411
+ await fs10.unlink(shimPath);
1409
1412
  } catch {
1410
1413
  }
1411
1414
  return outputPath;
1412
1415
  }
1413
- var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
1416
+ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin, nextShimPlugin;
1414
1417
  var init_compile_theme = __esm({
1415
1418
  "src/utils/compile-theme.ts"() {
1416
1419
  init_logger();
1417
1420
  init_extract_schemas();
1418
1421
  init_scan_theme_assets();
1422
+ init_detect_nextjs();
1423
+ init_nextjs_page_scanner();
1419
1424
  PROCESS_SHIM = `
1420
1425
  if (typeof process === "undefined") {
1421
1426
  globalThis.process = {
@@ -1561,6 +1566,145 @@ export const {
1561
1566
  }));
1562
1567
  }
1563
1568
  };
1569
+ nextShimPlugin = {
1570
+ name: "next-shim",
1571
+ setup(build2) {
1572
+ for (const serverModule of ["next/headers", "next/server", "next/cache"]) {
1573
+ build2.onResolve({ filter: new RegExp(`^${serverModule.replace("/", "\\/")}`) }, (args) => ({
1574
+ path: args.path,
1575
+ namespace: "next-server-error"
1576
+ }));
1577
+ }
1578
+ build2.onLoad({ filter: /.*/, namespace: "next-server-error" }, (args) => ({
1579
+ errors: [
1580
+ {
1581
+ text: `"${args.path}" is server-only and cannot be used in a OneX theme bundle. Use client-side equivalents or remove the import.`
1582
+ }
1583
+ ]
1584
+ }));
1585
+ build2.onResolve({ filter: /^next\/navigation$/ }, () => ({
1586
+ path: "next-navigation-shim",
1587
+ namespace: "next-shim"
1588
+ }));
1589
+ build2.onLoad({ filter: /^next-navigation-shim$/, namespace: "next-shim" }, () => ({
1590
+ contents: `
1591
+ export function usePathname() {
1592
+ if (typeof window === 'undefined') return '/';
1593
+ return window.location.pathname;
1594
+ }
1595
+ export function useSearchParams() {
1596
+ if (typeof window === 'undefined') return new URLSearchParams();
1597
+ return new URLSearchParams(window.location.search);
1598
+ }
1599
+ export function useParams() {
1600
+ if (typeof window === 'undefined') return {};
1601
+ return (globalThis.__ONEX_ROUTE_PARAMS__) ?? {};
1602
+ }
1603
+ export function useRouter() {
1604
+ return {
1605
+ push(url) { if (typeof window !== 'undefined') window.location.href = url; },
1606
+ replace(url) { if (typeof window !== 'undefined') window.location.replace(url); },
1607
+ back() { if (typeof window !== 'undefined') window.history.back(); },
1608
+ forward() { if (typeof window !== 'undefined') window.history.forward(); },
1609
+ refresh() { if (typeof window !== 'undefined') window.location.reload(); },
1610
+ prefetch() {},
1611
+ };
1612
+ }
1613
+ export function redirect(url) {
1614
+ if (typeof window !== 'undefined') window.location.href = url;
1615
+ throw new Error('redirect');
1616
+ }
1617
+ export function notFound() { throw new Error('not-found'); }
1618
+ `.trim(),
1619
+ loader: "js"
1620
+ }));
1621
+ build2.onResolve({ filter: /^next\/font\// }, () => ({
1622
+ path: "next-font-shim",
1623
+ namespace: "next-shim"
1624
+ }));
1625
+ build2.onLoad({ filter: /^next-font-shim$/, namespace: "next-shim" }, () => ({
1626
+ contents: `
1627
+ function makeFont(family) {
1628
+ return function(_opts) {
1629
+ return {
1630
+ className: '',
1631
+ style: { fontFamily: family + ', system-ui, sans-serif' },
1632
+ variable: '--font-' + family.toLowerCase().replace(/\\s+/g, '-'),
1633
+ };
1634
+ };
1635
+ }
1636
+ export const Inter = makeFont('Inter');
1637
+ export const Roboto = makeFont('Roboto');
1638
+ export const Open_Sans = makeFont('Open Sans');
1639
+ export const Lato = makeFont('Lato');
1640
+ export const Montserrat = makeFont('Montserrat');
1641
+ export const Poppins = makeFont('Poppins');
1642
+ export const Raleway = makeFont('Raleway');
1643
+ export const Nunito = makeFont('Nunito');
1644
+ export const Geist = makeFont('Geist');
1645
+ export const Geist_Mono = makeFont('Geist Mono');
1646
+ export const DM_Sans = makeFont('DM Sans');
1647
+ export const Plus_Jakarta_Sans = makeFont('Plus Jakarta Sans');
1648
+ export function localFont(_opts) {
1649
+ return { className: '', style: { fontFamily: 'system-ui, sans-serif' }, variable: '--font-local' };
1650
+ }
1651
+ `.trim(),
1652
+ loader: "js"
1653
+ }));
1654
+ build2.onResolve({ filter: /^next\/dynamic$/ }, () => ({
1655
+ path: "next-dynamic-shim",
1656
+ namespace: "next-shim"
1657
+ }));
1658
+ build2.onLoad({ filter: /^next-dynamic-shim$/, namespace: "next-shim" }, () => ({
1659
+ contents: `
1660
+ import { lazy, Suspense, createElement } from 'react';
1661
+ export default function dynamic(loader, opts) {
1662
+ const Lazy = lazy(loader);
1663
+ return function DynamicComponent(props) {
1664
+ return createElement(Suspense, { fallback: opts?.loading ? createElement(opts.loading) : null },
1665
+ createElement(Lazy, props));
1666
+ };
1667
+ }
1668
+ `.trim(),
1669
+ loader: "js"
1670
+ }));
1671
+ build2.onResolve({ filter: /^next\/image$/ }, () => ({
1672
+ path: "next-image-shim",
1673
+ namespace: "next-shim"
1674
+ }));
1675
+ build2.onLoad({ filter: /^next-image-shim$/, namespace: "next-shim" }, () => ({
1676
+ contents: `
1677
+ import { createElement } from 'react';
1678
+ export default function Image({ src, alt, width, height, style, className, ...rest }) {
1679
+ return createElement('img', { src, alt, width, height, style, className, ...rest });
1680
+ }
1681
+ `.trim(),
1682
+ loader: "js"
1683
+ }));
1684
+ build2.onResolve({ filter: /^next\/link$/ }, () => ({
1685
+ path: "next-link-shim",
1686
+ namespace: "next-shim"
1687
+ }));
1688
+ build2.onLoad({ filter: /^next-link-shim$/, namespace: "next-shim" }, () => ({
1689
+ contents: `
1690
+ import { createElement } from 'react';
1691
+ export default function Link({ href, children, className, style, ...rest }) {
1692
+ return createElement('a', { href, className, style, ...rest }, children);
1693
+ }
1694
+ `.trim(),
1695
+ loader: "js"
1696
+ }));
1697
+ build2.onResolve({ filter: /^next\// }, () => ({
1698
+ path: "next-noop-shim",
1699
+ namespace: "next-shim"
1700
+ }));
1701
+ build2.onLoad({ filter: /^next-noop-shim$/, namespace: "next-shim" }, () => ({
1702
+ contents: `export default {};
1703
+ `,
1704
+ loader: "js"
1705
+ }));
1706
+ }
1707
+ };
1564
1708
  }
1565
1709
  });
1566
1710
 
@@ -1585,8 +1729,8 @@ function validateThemeName(name) {
1585
1729
  return /^[a-z][a-z0-9-]*$/.test(name);
1586
1730
  }
1587
1731
  function pathExists(filePath) {
1588
- const fs12 = __require("fs-extra");
1589
- return fs12.existsSync(filePath);
1732
+ const fs14 = __require("fs-extra");
1733
+ return fs14.existsSync(filePath);
1590
1734
  }
1591
1735
  function validateCategory(category) {
1592
1736
  const validCategories = [
@@ -1627,18 +1771,18 @@ async function renderTemplate(templatePath, data) {
1627
1771
  return ejs.render(template, data);
1628
1772
  }
1629
1773
  async function writeFile(filePath, content) {
1630
- await fs.ensureDir(path10.dirname(filePath));
1774
+ await fs.ensureDir(path12.dirname(filePath));
1631
1775
  await fs.writeFile(filePath, content, "utf-8");
1632
1776
  }
1633
1777
  function getTemplatesDir() {
1634
1778
  const locations = [
1635
- path10.join(__dirname, "../../templates"),
1779
+ path12.join(__dirname, "../../templates"),
1636
1780
  // Development
1637
- path10.join(__dirname, "../templates"),
1781
+ path12.join(__dirname, "../templates"),
1638
1782
  // Production (dist/)
1639
- path10.join(process.cwd(), "templates"),
1783
+ path12.join(process.cwd(), "templates"),
1640
1784
  // Fallback
1641
- path10.join(process.cwd(), "packages/cli/templates")
1785
+ path12.join(process.cwd(), "packages/cli/templates")
1642
1786
  // Monorepo
1643
1787
  ];
1644
1788
  for (const location of locations) {
@@ -1650,7 +1794,7 @@ function getTemplatesDir() {
1650
1794
  }
1651
1795
  async function copyTemplate(templateName, targetDir, data) {
1652
1796
  const templatesDir = getTemplatesDir();
1653
- const templateDir = path10.join(templatesDir, templateName);
1797
+ const templateDir = path12.join(templatesDir, templateName);
1654
1798
  if (!fs.existsSync(templateDir)) {
1655
1799
  throw new Error(
1656
1800
  `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
@@ -1659,8 +1803,8 @@ async function copyTemplate(templateName, targetDir, data) {
1659
1803
  await fs.ensureDir(targetDir);
1660
1804
  const files = await fs.readdir(templateDir);
1661
1805
  for (const file of files) {
1662
- const templatePath = path10.join(templateDir, file);
1663
- const targetPath = path10.join(targetDir, file);
1806
+ const templatePath = path12.join(templateDir, file);
1807
+ const targetPath = path12.join(targetDir, file);
1664
1808
  const stat = await fs.stat(templatePath);
1665
1809
  if (stat.isDirectory()) {
1666
1810
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1677,8 +1821,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1677
1821
  await fs.ensureDir(targetDir);
1678
1822
  const files = await fs.readdir(templateDir);
1679
1823
  for (const file of files) {
1680
- const templatePath = path10.join(templateDir, file);
1681
- const targetPath = path10.join(targetDir, file);
1824
+ const templatePath = path12.join(templateDir, file);
1825
+ const targetPath = path12.join(targetDir, file);
1682
1826
  const stat = await fs.stat(templatePath);
1683
1827
  if (stat.isDirectory()) {
1684
1828
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1693,32 +1837,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1693
1837
  }
1694
1838
  function getProjectRoot() {
1695
1839
  let currentDir = process.cwd();
1696
- while (currentDir !== path10.parse(currentDir).root) {
1697
- const packageJsonPath = path10.join(currentDir, "package.json");
1840
+ while (currentDir !== path12.parse(currentDir).root) {
1841
+ const packageJsonPath = path12.join(currentDir, "package.json");
1698
1842
  if (fs.existsSync(packageJsonPath)) {
1699
1843
  const packageJson = fs.readJsonSync(packageJsonPath);
1700
- if (packageJson.workspaces || fs.existsSync(path10.join(currentDir, "src/themes")) || fs.existsSync(path10.join(currentDir, "themes"))) {
1844
+ if (packageJson.workspaces || fs.existsSync(path12.join(currentDir, "src/themes")) || fs.existsSync(path12.join(currentDir, "themes"))) {
1701
1845
  return currentDir;
1702
1846
  }
1703
1847
  }
1704
- currentDir = path10.dirname(currentDir);
1848
+ currentDir = path12.dirname(currentDir);
1705
1849
  }
1706
1850
  return process.cwd();
1707
1851
  }
1708
1852
  function getThemesDir() {
1709
1853
  const root = getProjectRoot();
1710
- if (fs.existsSync(path10.join(root, "themes")))
1711
- return path10.join(root, "themes");
1712
- if (fs.existsSync(path10.join(root, "src/themes")))
1713
- return path10.join(root, "src/themes");
1714
- return path10.dirname(root);
1854
+ if (fs.existsSync(path12.join(root, "themes")))
1855
+ return path12.join(root, "themes");
1856
+ if (fs.existsSync(path12.join(root, "src/themes")))
1857
+ return path12.join(root, "src/themes");
1858
+ return path12.dirname(root);
1715
1859
  }
1716
1860
  function getFeaturesDir() {
1717
- return path10.join(getProjectRoot(), "src/features");
1861
+ return path12.join(getProjectRoot(), "src/features");
1718
1862
  }
1719
1863
  function isOneXProject() {
1720
1864
  const root = getProjectRoot();
1721
- return fs.existsSync(path10.join(root, "themes")) || fs.existsSync(path10.join(root, "src/themes")) || fs.existsSync(path10.join(root, "theme.config.ts")) || fs.existsSync(path10.join(root, "bundle-entry.ts"));
1865
+ return fs.existsSync(path12.join(root, "themes")) || fs.existsSync(path12.join(root, "src/themes")) || fs.existsSync(path12.join(root, "theme.config.ts")) || fs.existsSync(path12.join(root, "bundle-entry.ts"));
1722
1866
  }
1723
1867
  function ensureOneXProject() {
1724
1868
  if (!isOneXProject()) {
@@ -1734,13 +1878,13 @@ function listThemes() {
1734
1878
  return [];
1735
1879
  }
1736
1880
  return fs.readdirSync(themesDir).filter((name) => {
1737
- const themePath = path10.join(themesDir, name);
1738
- return fs.statSync(themePath).isDirectory() && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
1881
+ const themePath = path12.join(themesDir, name);
1882
+ return fs.statSync(themePath).isDirectory() && (fs.existsSync(path12.join(themePath, "theme.config.ts")) || fs.existsSync(path12.join(themePath, "bundle-entry.ts")) || fs.existsSync(path12.join(themePath, "manifest.ts")));
1739
1883
  });
1740
1884
  }
1741
1885
  function themeExists(themeName) {
1742
- const themePath = path10.join(getThemesDir(), themeName);
1743
- return fs.existsSync(themePath) && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
1886
+ const themePath = path12.join(getThemesDir(), themeName);
1887
+ return fs.existsSync(themePath) && (fs.existsSync(path12.join(themePath, "theme.config.ts")) || fs.existsSync(path12.join(themePath, "bundle-entry.ts")) || fs.existsSync(path12.join(themePath, "manifest.ts")));
1744
1888
  }
1745
1889
  function detectPackageManager() {
1746
1890
  const userAgent = process.env.npm_config_user_agent || "";
@@ -1748,9 +1892,9 @@ function detectPackageManager() {
1748
1892
  if (userAgent.includes("yarn")) return "yarn";
1749
1893
  if (userAgent.includes("bun")) return "bun";
1750
1894
  const cwd = process.cwd();
1751
- if (fs.existsSync(path10.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1752
- if (fs.existsSync(path10.join(cwd, "yarn.lock"))) return "yarn";
1753
- if (fs.existsSync(path10.join(cwd, "bun.lockb"))) return "bun";
1895
+ if (fs.existsSync(path12.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1896
+ if (fs.existsSync(path12.join(cwd, "yarn.lock"))) return "yarn";
1897
+ if (fs.existsSync(path12.join(cwd, "bun.lockb"))) return "bun";
1754
1898
  return "npm";
1755
1899
  }
1756
1900
  async function installDependencies(projectPath, packageManager = "npm") {
@@ -1767,16 +1911,16 @@ async function installDependencies(projectPath, packageManager = "npm") {
1767
1911
  }
1768
1912
  });
1769
1913
  }
1770
- var AUTH_DIR = path10.join(os.homedir(), ".onexthm");
1914
+ var AUTH_DIR = path12.join(os.homedir(), ".onexthm");
1771
1915
  var ENV_URLS = {
1772
1916
  dev: "https://platform-dev.onexeos.com",
1773
1917
  staging: "https://platform-staging.onexeos.com",
1774
1918
  prod: "https://platform-apis.onexeos.com"
1775
1919
  };
1776
1920
  function getAuthFile(env = "dev") {
1777
- const newFile = path10.join(AUTH_DIR, `auth-${env}.json`);
1921
+ const newFile = path12.join(AUTH_DIR, `auth-${env}.json`);
1778
1922
  if (env === "dev") {
1779
- const legacyFile = path10.join(AUTH_DIR, "auth.json");
1923
+ const legacyFile = path12.join(AUTH_DIR, "auth.json");
1780
1924
  if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
1781
1925
  try {
1782
1926
  fs.moveSync(legacyFile, newFile);
@@ -1903,7 +2047,7 @@ function decrypt(text, key) {
1903
2047
  }
1904
2048
 
1905
2049
  // src/commands/init.ts
1906
- async function initCommand(projectName, options = {}) {
2050
+ async function initCommand(projectName, options) {
1907
2051
  logger.header("Create New OneX Theme Project");
1908
2052
  let name;
1909
2053
  if (!projectName) {
@@ -1918,7 +2062,7 @@ async function initCommand(projectName, options = {}) {
1918
2062
  if (!validateThemeName(kebabName)) {
1919
2063
  return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
1920
2064
  }
1921
- if (fs3.existsSync(path10.join(process.cwd(), kebabName))) {
2065
+ if (fs3.existsSync(path12.join(process.cwd(), kebabName))) {
1922
2066
  return `Directory "${kebabName}" already exists`;
1923
2067
  }
1924
2068
  return true;
@@ -1929,14 +2073,14 @@ async function initCommand(projectName, options = {}) {
1929
2073
  } else {
1930
2074
  name = toKebabCase(projectName);
1931
2075
  }
1932
- const projectPath = path10.join(process.cwd(), name);
2076
+ const projectPath = path12.join(process.cwd(), name);
1933
2077
  if (fs3.existsSync(projectPath)) {
1934
2078
  logger.error(`Directory "${name}" already exists.`);
1935
2079
  process.exit(1);
1936
2080
  }
1937
2081
  if (!options.yes) {
1938
2082
  try {
1939
- const apiUrl = getApiUrl(options.env ?? "dev");
2083
+ const apiUrl = getApiUrl(options.env);
1940
2084
  const controller = new AbortController();
1941
2085
  const timeout = setTimeout(() => controller.abort(), 3e3);
1942
2086
  const response = await fetch(
@@ -2045,7 +2189,7 @@ async function initCommand(projectName, options = {}) {
2045
2189
  description,
2046
2190
  author
2047
2191
  );
2048
- const mcpJsonPath = path10.join(projectPath, ".mcp.json");
2192
+ const mcpJsonPath = path12.join(projectPath, ".mcp.json");
2049
2193
  if (fs3.existsSync(mcpJsonPath)) {
2050
2194
  let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
2051
2195
  if (figmaApiKey) {
@@ -2125,7 +2269,7 @@ async function initCommand(projectName, options = {}) {
2125
2269
  }
2126
2270
  }
2127
2271
  async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
2128
- const configPath = path10.join(projectPath, "theme.config.ts");
2272
+ const configPath = path12.join(projectPath, "theme.config.ts");
2129
2273
  if (fs3.existsSync(configPath)) {
2130
2274
  let content = fs3.readFileSync(configPath, "utf-8");
2131
2275
  content = content.replace(
@@ -2138,7 +2282,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
2138
2282
  );
2139
2283
  fs3.writeFileSync(configPath, content, "utf-8");
2140
2284
  }
2141
- const pkgPath = path10.join(projectPath, "package.json");
2285
+ const pkgPath = path12.join(projectPath, "package.json");
2142
2286
  if (fs3.existsSync(pkgPath)) {
2143
2287
  let content = fs3.readFileSync(pkgPath, "utf-8");
2144
2288
  content = content.replace(
@@ -2160,10 +2304,10 @@ async function createSectionCommand(name, options) {
2160
2304
  ensureOneXProject();
2161
2305
  if (!options.theme) {
2162
2306
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2163
- (f) => fs.existsSync(path10.join(process.cwd(), f))
2307
+ (f) => fs.existsSync(path12.join(process.cwd(), f))
2164
2308
  );
2165
2309
  if (isStandaloneTheme) {
2166
- options.theme = path10.basename(process.cwd());
2310
+ options.theme = path12.basename(process.cwd());
2167
2311
  }
2168
2312
  }
2169
2313
  const sectionName = toKebabCase(name);
@@ -2226,35 +2370,35 @@ async function createSectionCommand(name, options) {
2226
2370
  };
2227
2371
  logger.startSpinner("Creating section files...");
2228
2372
  try {
2229
- const themePath = path10.join(getThemesDir(), themeName);
2230
- const sectionPath = path10.join(themePath, "sections", sectionName);
2373
+ const themePath = path12.join(getThemesDir(), themeName);
2374
+ const sectionPath = path12.join(themePath, "sections", sectionName);
2231
2375
  const schemaContent = generateSectionSchema(data);
2232
2376
  await writeFile(
2233
- path10.join(sectionPath, `${sectionName}.schema.ts`),
2377
+ path12.join(sectionPath, `${sectionName}.schema.ts`),
2234
2378
  schemaContent
2235
2379
  );
2236
2380
  if (createTemplate) {
2237
2381
  const templateContent = generateSectionTemplate(data);
2238
2382
  await writeFile(
2239
- path10.join(sectionPath, `${sectionName}-default.tsx`),
2383
+ path12.join(sectionPath, `${sectionName}-default.tsx`),
2240
2384
  templateContent
2241
2385
  );
2242
2386
  }
2243
2387
  const indexContent = generateSectionIndex(data, createTemplate);
2244
- await writeFile(path10.join(sectionPath, "index.ts"), indexContent);
2388
+ await writeFile(path12.join(sectionPath, "index.ts"), indexContent);
2245
2389
  logger.stopSpinner(true, "Section files created successfully!");
2246
2390
  logger.newLine();
2247
2391
  logger.section("Next steps:");
2248
2392
  logger.log(
2249
- ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}.schema.ts`))}`
2393
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}.schema.ts`))}`
2250
2394
  );
2251
2395
  if (createTemplate) {
2252
2396
  logger.log(
2253
- ` 2. Edit template: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}-default.tsx`))}`
2397
+ ` 2. Edit template: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}-default.tsx`))}`
2254
2398
  );
2255
2399
  }
2256
2400
  logger.log(
2257
- ` 3. Add to theme manifest: ${path10.relative(process.cwd(), path10.join(themePath, "manifest.ts"))}`
2401
+ ` 3. Add to theme manifest: ${path12.relative(process.cwd(), path12.join(themePath, "manifest.ts"))}`
2258
2402
  );
2259
2403
  logger.newLine();
2260
2404
  logger.success("Section created successfully!");
@@ -2402,10 +2546,10 @@ async function createBlockCommand(name, options) {
2402
2546
  ensureOneXProject();
2403
2547
  if (!options.theme) {
2404
2548
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2405
- (f) => fs.existsSync(path10.join(process.cwd(), f))
2549
+ (f) => fs.existsSync(path12.join(process.cwd(), f))
2406
2550
  );
2407
2551
  if (isStandaloneTheme) {
2408
- options.theme = path10.basename(process.cwd());
2552
+ options.theme = path12.basename(process.cwd());
2409
2553
  }
2410
2554
  }
2411
2555
  const blockName = toKebabCase(name);
@@ -2480,24 +2624,24 @@ async function createBlockCommand(name, options) {
2480
2624
  };
2481
2625
  logger.startSpinner("Creating block files...");
2482
2626
  try {
2483
- const blockPath = scope === "shared" ? path10.join(getFeaturesDir(), "blocks", blockName) : path10.join(getThemesDir(), themeName, "blocks", blockName);
2627
+ const blockPath = scope === "shared" ? path12.join(getFeaturesDir(), "blocks", blockName) : path12.join(getThemesDir(), themeName, "blocks", blockName);
2484
2628
  const schemaContent = generateBlockSchema(data);
2485
2629
  await writeFile(
2486
- path10.join(blockPath, `${blockName}.schema.ts`),
2630
+ path12.join(blockPath, `${blockName}.schema.ts`),
2487
2631
  schemaContent
2488
2632
  );
2489
2633
  const componentContent = generateBlockComponent(data);
2490
- await writeFile(path10.join(blockPath, `${blockName}.tsx`), componentContent);
2634
+ await writeFile(path12.join(blockPath, `${blockName}.tsx`), componentContent);
2491
2635
  const indexContent = generateBlockIndex(data);
2492
- await writeFile(path10.join(blockPath, "index.ts"), indexContent);
2636
+ await writeFile(path12.join(blockPath, "index.ts"), indexContent);
2493
2637
  logger.stopSpinner(true, "Block files created successfully!");
2494
2638
  logger.newLine();
2495
2639
  logger.section("Next steps:");
2496
2640
  logger.log(
2497
- ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.schema.ts`))}`
2641
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.schema.ts`))}`
2498
2642
  );
2499
2643
  logger.log(
2500
- ` 2. Edit component: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.tsx`))}`
2644
+ ` 2. Edit component: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.tsx`))}`
2501
2645
  );
2502
2646
  logger.log(
2503
2647
  ` 3. Register in block registry: src/lib/registry/block-registry.ts`
@@ -2675,31 +2819,31 @@ async function createComponentCommand(name, options) {
2675
2819
  };
2676
2820
  logger.startSpinner("Creating component files...");
2677
2821
  try {
2678
- const componentPath = path10.join(
2822
+ const componentPath = path12.join(
2679
2823
  getFeaturesDir(),
2680
2824
  "components",
2681
2825
  componentName
2682
2826
  );
2683
2827
  const schemaContent = generateComponentSchema(data);
2684
2828
  await writeFile(
2685
- path10.join(componentPath, `${componentName}.schema.ts`),
2829
+ path12.join(componentPath, `${componentName}.schema.ts`),
2686
2830
  schemaContent
2687
2831
  );
2688
2832
  const componentContent = generateComponent(data);
2689
2833
  await writeFile(
2690
- path10.join(componentPath, `${componentName}.tsx`),
2834
+ path12.join(componentPath, `${componentName}.tsx`),
2691
2835
  componentContent
2692
2836
  );
2693
2837
  const indexContent = generateComponentIndex(data);
2694
- await writeFile(path10.join(componentPath, "index.ts"), indexContent);
2838
+ await writeFile(path12.join(componentPath, "index.ts"), indexContent);
2695
2839
  logger.stopSpinner(true, "Component files created successfully!");
2696
2840
  logger.newLine();
2697
2841
  logger.section("Next steps:");
2698
2842
  logger.log(
2699
- ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.schema.ts`))}`
2843
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.schema.ts`))}`
2700
2844
  );
2701
2845
  logger.log(
2702
- ` 2. Edit component: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.tsx`))}`
2846
+ ` 2. Edit component: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.tsx`))}`
2703
2847
  );
2704
2848
  logger.log(
2705
2849
  ` 3. Register in component registry: src/lib/registry/component-registry.ts`
@@ -2856,13 +3000,13 @@ async function listSections(themeFilter) {
2856
3000
  return;
2857
3001
  }
2858
3002
  for (const theme of themes) {
2859
- const sectionsDir = path10.join(getThemesDir(), theme, "sections");
3003
+ const sectionsDir = path12.join(getThemesDir(), theme, "sections");
2860
3004
  if (!fs.existsSync(sectionsDir)) {
2861
3005
  continue;
2862
3006
  }
2863
3007
  const sections = fs.readdirSync(sectionsDir).filter((name) => {
2864
- const sectionPath = path10.join(sectionsDir, name);
2865
- return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path10.join(sectionPath, "index.ts"));
3008
+ const sectionPath = path12.join(sectionsDir, name);
3009
+ return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path12.join(sectionPath, "index.ts"));
2866
3010
  });
2867
3011
  if (sections.length > 0) {
2868
3012
  logger.log(chalk4.cyan(`
@@ -2876,11 +3020,11 @@ async function listSections(themeFilter) {
2876
3020
  }
2877
3021
  async function listBlocks(themeFilter) {
2878
3022
  logger.section("\u{1F9F1} Blocks");
2879
- const sharedBlocksDir = path10.join(getFeaturesDir(), "blocks");
3023
+ const sharedBlocksDir = path12.join(getFeaturesDir(), "blocks");
2880
3024
  if (fs.existsSync(sharedBlocksDir)) {
2881
3025
  const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
2882
- const blockPath = path10.join(sharedBlocksDir, name);
2883
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
3026
+ const blockPath = path12.join(sharedBlocksDir, name);
3027
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
2884
3028
  });
2885
3029
  if (sharedBlocks.length > 0) {
2886
3030
  logger.log(chalk4.cyan("\n Shared:"));
@@ -2891,13 +3035,13 @@ async function listBlocks(themeFilter) {
2891
3035
  }
2892
3036
  const themes = themeFilter ? [themeFilter] : listThemes();
2893
3037
  for (const theme of themes) {
2894
- const blocksDir = path10.join(getThemesDir(), theme, "blocks");
3038
+ const blocksDir = path12.join(getThemesDir(), theme, "blocks");
2895
3039
  if (!fs.existsSync(blocksDir)) {
2896
3040
  continue;
2897
3041
  }
2898
3042
  const blocks = fs.readdirSync(blocksDir).filter((name) => {
2899
- const blockPath = path10.join(blocksDir, name);
2900
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
3043
+ const blockPath = path12.join(blocksDir, name);
3044
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
2901
3045
  });
2902
3046
  if (blocks.length > 0) {
2903
3047
  logger.log(chalk4.cyan(`
@@ -2911,14 +3055,14 @@ async function listBlocks(themeFilter) {
2911
3055
  }
2912
3056
  async function listComponents() {
2913
3057
  logger.section("\u2699\uFE0F Components");
2914
- const componentsDir = path10.join(getFeaturesDir(), "components");
3058
+ const componentsDir = path12.join(getFeaturesDir(), "components");
2915
3059
  if (!fs.existsSync(componentsDir)) {
2916
3060
  logger.warning("No components directory found");
2917
3061
  return;
2918
3062
  }
2919
3063
  const components = fs.readdirSync(componentsDir).filter((name) => {
2920
- const componentPath = path10.join(componentsDir, name);
2921
- return fs.statSync(componentPath).isDirectory() && fs.existsSync(path10.join(componentPath, "index.ts"));
3064
+ const componentPath = path12.join(componentsDir, name);
3065
+ return fs.statSync(componentPath).isDirectory() && fs.existsSync(path12.join(componentPath, "index.ts"));
2922
3066
  });
2923
3067
  if (components.length === 0) {
2924
3068
  logger.warning("No components found");
@@ -2939,11 +3083,11 @@ async function listThemesInfo() {
2939
3083
  }
2940
3084
  logger.log("");
2941
3085
  for (const theme of themes) {
2942
- const themeDir = path10.join(getThemesDir(), theme);
3086
+ const themeDir = path12.join(getThemesDir(), theme);
2943
3087
  const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
2944
3088
  let manifestContent = "";
2945
3089
  for (const candidate of candidates) {
2946
- const candidatePath = path10.join(themeDir, candidate);
3090
+ const candidatePath = path12.join(themeDir, candidate);
2947
3091
  if (fs.existsSync(candidatePath)) {
2948
3092
  manifestContent = fs.readFileSync(candidatePath, "utf-8");
2949
3093
  break;
@@ -2965,6 +3109,7 @@ async function listThemesInfo() {
2965
3109
 
2966
3110
  // src/commands/build.ts
2967
3111
  init_logger();
3112
+ init_detect_nextjs();
2968
3113
  async function buildCommand(options) {
2969
3114
  logger.header("Build Theme");
2970
3115
  let themePath;
@@ -2972,14 +3117,14 @@ async function buildCommand(options) {
2972
3117
  if (options.theme) {
2973
3118
  themeName = options.theme;
2974
3119
  try {
2975
- const workspaceThemePath = path10.join(getThemesDir(), themeName);
3120
+ const workspaceThemePath = path12.join(getThemesDir(), themeName);
2976
3121
  if (fs.existsSync(workspaceThemePath)) {
2977
3122
  themePath = workspaceThemePath;
2978
3123
  } else {
2979
- themePath = path10.join(process.cwd(), themeName);
3124
+ themePath = path12.join(process.cwd(), themeName);
2980
3125
  }
2981
3126
  } catch {
2982
- themePath = path10.join(process.cwd(), themeName);
3127
+ themePath = path12.join(process.cwd(), themeName);
2983
3128
  }
2984
3129
  if (!fs.existsSync(themePath)) {
2985
3130
  logger.error(`Theme "${themeName}" not found.`);
@@ -2989,11 +3134,14 @@ async function buildCommand(options) {
2989
3134
  const isThemeDir = [
2990
3135
  "theme.config.ts",
2991
3136
  "bundle-entry.ts",
2992
- "manifest.ts"
2993
- ].some((f) => fs.existsSync(path10.join(process.cwd(), f)));
3137
+ "manifest.ts",
3138
+ "next.config.ts",
3139
+ "next.config.js",
3140
+ "next.config.mjs"
3141
+ ].some((f) => fs.existsSync(path12.join(process.cwd(), f)));
2994
3142
  if (isThemeDir) {
2995
3143
  themePath = process.cwd();
2996
- themeName = path10.basename(themePath);
3144
+ themeName = path12.basename(themePath);
2997
3145
  logger.info(`Building current theme: ${themeName}`);
2998
3146
  } else {
2999
3147
  logger.error(
@@ -3002,7 +3150,7 @@ async function buildCommand(options) {
3002
3150
  process.exit(1);
3003
3151
  }
3004
3152
  }
3005
- const packageJsonPath = path10.join(themePath, "package.json");
3153
+ const packageJsonPath = path12.join(themePath, "package.json");
3006
3154
  const hasPkgJson = fs.existsSync(packageJsonPath);
3007
3155
  if (!hasPkgJson) {
3008
3156
  logger.warning(
@@ -3018,30 +3166,42 @@ async function buildCommand(options) {
3018
3166
  }
3019
3167
  logger.newLine();
3020
3168
  logger.section("Build Steps");
3021
- logger.startSpinner("Running type check...");
3022
- const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
3023
- if (!typeCheckSuccess) {
3024
- logger.stopSpinner(false, "Type check failed");
3025
- logger.error("Fix type errors before building.");
3026
- process.exit(1);
3027
- }
3028
- logger.stopSpinner(true, "Type check passed");
3029
- logger.startSpinner("Running linter...");
3030
- const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
3031
- if (!lintSuccess) {
3032
- logger.stopSpinner(false, "Lint failed");
3033
- logger.error("Fix lint errors before building.");
3034
- process.exit(1);
3035
- }
3036
- logger.stopSpinner(true, "Lint passed");
3037
3169
  const pkgJson = fs.readJsonSync(packageJsonPath);
3170
+ if (pkgJson.scripts?.["type-check"]) {
3171
+ logger.startSpinner("Running type check...");
3172
+ const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
3173
+ if (!typeCheckSuccess) {
3174
+ logger.stopSpinner(false, "Type check failed");
3175
+ logger.error("Fix type errors before building.");
3176
+ process.exit(1);
3177
+ }
3178
+ logger.stopSpinner(true, "Type check passed");
3179
+ } else {
3180
+ logger.info("Skipping type check (no type-check script in package.json)");
3181
+ }
3182
+ const isNextjsForLint = isNextjsProject(themePath);
3183
+ if (!isNextjsForLint && pkgJson.scripts?.lint) {
3184
+ logger.startSpinner("Running linter...");
3185
+ const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
3186
+ if (!lintSuccess) {
3187
+ logger.stopSpinner(false, "Lint failed");
3188
+ logger.error("Fix lint errors before building.");
3189
+ process.exit(1);
3190
+ }
3191
+ logger.stopSpinner(true, "Lint passed");
3192
+ } else if (isNextjsForLint) {
3193
+ logger.info("Skipping lint (Next.js project compiled via esbuild)");
3194
+ } else {
3195
+ logger.info("Skipping lint (no lint script in package.json)");
3196
+ }
3038
3197
  const buildScript = pkgJson.scripts?.build || "";
3039
3198
  const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex build") || buildScript.includes("onex-cli build");
3199
+ const isNextjs = isNextjsProject(themePath);
3040
3200
  logger.startSpinner(
3041
3201
  options.watch ? "Building (watch mode)..." : "Building..."
3042
3202
  );
3043
3203
  let buildSuccess;
3044
- if (isRecursive) {
3204
+ if (isRecursive || isNextjs) {
3045
3205
  const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
3046
3206
  buildSuccess = await compileStandaloneTheme2(themePath, themeName);
3047
3207
  } else {
@@ -3058,9 +3218,9 @@ async function buildCommand(options) {
3058
3218
  logger.success("\u2713 Theme built successfully!");
3059
3219
  logger.newLine();
3060
3220
  logger.info(`Theme: ${themeName}`);
3061
- const distPath = path10.join(themePath, "dist");
3221
+ const distPath = path12.join(themePath, "dist");
3062
3222
  if (fs.existsSync(distPath)) {
3063
- logger.log(`Output: ${path10.relative(process.cwd(), distPath)}`);
3223
+ logger.log(`Output: ${path12.relative(process.cwd(), distPath)}`);
3064
3224
  const files = fs.readdirSync(distPath);
3065
3225
  logger.log(`Files: ${files.length}`);
3066
3226
  }
@@ -3201,8 +3361,8 @@ async function downloadBundleZip(apiUrl, themeId, version) {
3201
3361
  async function createCompatibilityFiles(outputDir, manifest) {
3202
3362
  const entryFile = manifest.output?.entry || "bundle-entry.js";
3203
3363
  if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
3204
- const hashedPath = path10.join(outputDir, entryFile);
3205
- const stablePath = path10.join(outputDir, "bundle-entry.js");
3364
+ const hashedPath = path12.join(outputDir, entryFile);
3365
+ const stablePath = path12.join(outputDir, "bundle-entry.js");
3206
3366
  if (await fs.pathExists(hashedPath)) {
3207
3367
  await fs.copy(hashedPath, stablePath);
3208
3368
  const mapPath = hashedPath + ".map";
@@ -3211,13 +3371,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
3211
3371
  }
3212
3372
  }
3213
3373
  }
3214
- const sectionsRegistryPath = path10.join(outputDir, "sections-registry.js");
3374
+ const sectionsRegistryPath = path12.join(outputDir, "sections-registry.js");
3215
3375
  const content = `// Re-export all sections from bundle-entry
3216
3376
  // This file exists to maintain compatibility with the import path
3217
3377
  export * from './bundle-entry.js';
3218
3378
  `;
3219
3379
  await fs.writeFile(sectionsRegistryPath, content, "utf-8");
3220
- const pkgJsonPath = path10.join(outputDir, "package.json");
3380
+ const pkgJsonPath = path12.join(outputDir, "package.json");
3221
3381
  await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
3222
3382
  }
3223
3383
  function showDownloadFailureHelp(themeId, apiUrl) {
@@ -3258,7 +3418,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
3258
3418
  }
3259
3419
  async function downloadCommand(options) {
3260
3420
  logger.header("Download Theme");
3261
- const env = options.env ?? "dev";
3421
+ const env = options.env;
3262
3422
  const apiUrl = getApiUrl(env);
3263
3423
  logger.info(`Environment: ${env} (${apiUrl})`);
3264
3424
  const spinner = ora("Initializing download...").start();
@@ -3316,7 +3476,7 @@ async function downloadCommand(options) {
3316
3476
  zip.extractAllTo(outputDir, true);
3317
3477
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
3318
3478
  spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
3319
- const manifestPath = path10.join(outputDir, "manifest.json");
3479
+ const manifestPath = path12.join(outputDir, "manifest.json");
3320
3480
  const manifest = await fs.readJson(manifestPath);
3321
3481
  await createCompatibilityFiles(outputDir, manifest);
3322
3482
  console.log();
@@ -3437,7 +3597,7 @@ async function renameTheme(themeDir, oldName, newName) {
3437
3597
  const oldPrefix = `${oldName}-`;
3438
3598
  const newPrefix = `${newName}-`;
3439
3599
  const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3440
- const pkgPath = path10.join(themeDir, "package.json");
3600
+ const pkgPath = path12.join(themeDir, "package.json");
3441
3601
  if (await fs.pathExists(pkgPath)) {
3442
3602
  const pkg = await fs.readJson(pkgPath);
3443
3603
  pkg.name = `@onex-themes/${newName}`;
@@ -3453,7 +3613,7 @@ async function renameTheme(themeDir, oldName, newName) {
3453
3613
  }
3454
3614
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3455
3615
  }
3456
- const configPath = path10.join(themeDir, "theme.config.ts");
3616
+ const configPath = path12.join(themeDir, "theme.config.ts");
3457
3617
  if (await fs.pathExists(configPath)) {
3458
3618
  let content = await fs.readFile(configPath, "utf-8");
3459
3619
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3463,7 +3623,7 @@ async function renameTheme(themeDir, oldName, newName) {
3463
3623
  );
3464
3624
  await fs.writeFile(configPath, content);
3465
3625
  }
3466
- const layoutPath = path10.join(themeDir, "theme.layout.ts");
3626
+ const layoutPath = path12.join(themeDir, "theme.layout.ts");
3467
3627
  if (await fs.pathExists(layoutPath)) {
3468
3628
  let content = await fs.readFile(layoutPath, "utf-8");
3469
3629
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3476,7 +3636,7 @@ async function renameTheme(themeDir, oldName, newName) {
3476
3636
  const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3477
3637
  const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
3478
3638
  for (const file of tsFiles) {
3479
- const filePath = path10.join(themeDir, file);
3639
+ const filePath = path12.join(themeDir, file);
3480
3640
  let content = await fs.readFile(filePath, "utf-8");
3481
3641
  const original = content;
3482
3642
  content = content.replace(
@@ -3498,7 +3658,7 @@ async function renameTheme(themeDir, oldName, newName) {
3498
3658
  }
3499
3659
  async function cloneCommand(themeName, options) {
3500
3660
  logger.header("Clone Theme Source");
3501
- const env = options.env ?? "dev";
3661
+ const env = options.env;
3502
3662
  const apiUrl = getApiUrl(env);
3503
3663
  logger.info(`Environment: ${env} (${apiUrl})`);
3504
3664
  if (options.bucket) {
@@ -3519,7 +3679,7 @@ async function cloneCommand(themeName, options) {
3519
3679
  }
3520
3680
  const spinner = ora("Initializing clone...").start();
3521
3681
  try {
3522
- const outputDir = options.output || path10.resolve(process.cwd(), newName);
3682
+ const outputDir = options.output || path12.resolve(process.cwd(), newName);
3523
3683
  if (await fs.pathExists(outputDir)) {
3524
3684
  spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
3525
3685
  logger.info(
@@ -3565,7 +3725,7 @@ async function cloneCommand(themeName, options) {
3565
3725
  spinner.succeed(
3566
3726
  `Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
3567
3727
  );
3568
- const envExamplePath = path10.join(outputDir, ".env.example");
3728
+ const envExamplePath = path12.join(outputDir, ".env.example");
3569
3729
  if (!await fs.pathExists(envExamplePath)) {
3570
3730
  await fs.writeFile(
3571
3731
  envExamplePath,
@@ -3578,7 +3738,7 @@ async function cloneCommand(themeName, options) {
3578
3738
  ].join("\n")
3579
3739
  );
3580
3740
  }
3581
- const mcpJsonPath = path10.join(outputDir, ".mcp.json");
3741
+ const mcpJsonPath = path12.join(outputDir, ".mcp.json");
3582
3742
  if (await fs.pathExists(mcpJsonPath)) {
3583
3743
  const { default: inquirerMod } = await import('inquirer');
3584
3744
  const { figmaApiKey } = await inquirerMod.prompt([
@@ -3603,7 +3763,7 @@ async function cloneCommand(themeName, options) {
3603
3763
  }
3604
3764
  if (options.install !== false) {
3605
3765
  const hasPkgJson = await fs.pathExists(
3606
- path10.join(outputDir, "package.json")
3766
+ path12.join(outputDir, "package.json")
3607
3767
  );
3608
3768
  if (hasPkgJson) {
3609
3769
  spinner.start("Installing dependencies...");
@@ -3631,7 +3791,7 @@ async function cloneCommand(themeName, options) {
3631
3791
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
3632
3792
  console.log();
3633
3793
  console.log(chalk4.cyan("Next steps:"));
3634
- console.log(chalk4.gray(` cd ${path10.relative(process.cwd(), outputDir)}`));
3794
+ console.log(chalk4.gray(` cd ${path12.relative(process.cwd(), outputDir)}`));
3635
3795
  console.log(
3636
3796
  chalk4.gray(" cp .env.example .env # then add your Company ID")
3637
3797
  );