@onexapis/cli 1.1.65 → 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,15 +1,15 @@
1
1
  import chalk4 from 'chalk';
2
2
  import ora from 'ora';
3
- import * as esbuild from 'esbuild';
4
- import path8 from 'path';
5
- import fs7 from 'fs/promises';
6
- import crypto from 'crypto';
3
+ import fs3 from 'fs';
4
+ import path12 from 'path';
7
5
  import { glob } from 'glob';
6
+ import fs from 'fs-extra';
7
+ import crypto from 'crypto';
8
+ import fs10 from 'fs/promises';
9
+ import * as esbuild from 'esbuild';
8
10
  import { createRequire } from 'module';
9
- import fs3 from 'fs';
10
11
  import { execSync, spawn } from 'child_process';
11
12
  import inquirer from 'inquirer';
12
- import fs from 'fs-extra';
13
13
  import ejs from 'ejs';
14
14
  import os from 'os';
15
15
  import AdmZip from 'adm-zip';
@@ -85,6 +85,289 @@ 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
+ });
95
+ function sortedCopy(value) {
96
+ if (Array.isArray(value)) {
97
+ return value.map((v) => sortedCopy(v));
98
+ }
99
+ if (value && typeof value === "object") {
100
+ const sorted = {};
101
+ for (const key of Object.keys(value).sort()) {
102
+ sorted[key] = sortedCopy(value[key]);
103
+ }
104
+ return sorted;
105
+ }
106
+ return value;
107
+ }
108
+ function normalizeField(raw) {
109
+ const out = {
110
+ id: String(raw.id),
111
+ type: String(raw.type)
112
+ };
113
+ if (raw.required === true) out.required = true;
114
+ if (raw.default !== void 0) out.default = raw.default;
115
+ if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
116
+ out.aliases = [...raw.aliases].map(String).sort();
117
+ }
118
+ if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
119
+ if (typeof raw.min === "number") out.min = raw.min;
120
+ if (typeof raw.max === "number") out.max = raw.max;
121
+ if (typeof raw.step === "number") out.step = raw.step;
122
+ if (Array.isArray(raw.accept)) {
123
+ out.accept = [...raw.accept].map(String).sort();
124
+ }
125
+ if (Array.isArray(raw.options)) {
126
+ out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
127
+ }
128
+ return out;
129
+ }
130
+ function normalizeBlock(raw) {
131
+ return {
132
+ type: String(raw.type),
133
+ settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
134
+ defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
135
+ ...typeof raw.limit === "number" ? { limit: raw.limit } : {},
136
+ ...typeof raw.min === "number" ? { min: raw.min } : {},
137
+ ...raw.sortable === true ? { sortable: true } : {},
138
+ ...raw.baseType ? { baseType: String(raw.baseType) } : {}
139
+ };
140
+ }
141
+ function normalizeTemplate(raw) {
142
+ const out = { id: String(raw.id) };
143
+ if (raw.isDefault === true) out.isDefault = true;
144
+ if (Array.isArray(raw.settings)) {
145
+ out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
146
+ }
147
+ if (raw.defaults && typeof raw.defaults === "object") {
148
+ out.defaults = sortedCopy(raw.defaults);
149
+ }
150
+ return out;
151
+ }
152
+ function sortFieldsById(a, b) {
153
+ return a.id.localeCompare(b.id);
154
+ }
155
+ function sortByType(a, b) {
156
+ return a.type.localeCompare(b.type);
157
+ }
158
+ function normalizeSection(raw) {
159
+ return {
160
+ type: String(raw.type),
161
+ settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
162
+ defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
163
+ blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
164
+ templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
165
+ dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
166
+ ...raw.global === true ? { global: true } : {},
167
+ ...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
168
+ };
169
+ }
170
+ async function extractSchemas(themePath) {
171
+ const { createJiti } = await import('jiti');
172
+ const jiti = createJiti(import.meta.url);
173
+ const schemaFiles = await glob("sections/**/*.schema.ts", { cwd: themePath });
174
+ const sections = {};
175
+ for (const file of schemaFiles) {
176
+ try {
177
+ const mod = await jiti.import(path12.join(themePath, file));
178
+ const exports$1 = mod;
179
+ for (const value of Object.values(exports$1)) {
180
+ if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
181
+ const section = normalizeSection(value);
182
+ sections[section.type] = section;
183
+ }
184
+ }
185
+ } catch {
186
+ }
187
+ }
188
+ const manifest = {
189
+ manifestVersion: 1,
190
+ sections: {}
191
+ };
192
+ for (const type of Object.keys(sections).sort()) {
193
+ manifest.sections[type] = sections[type];
194
+ }
195
+ return manifest;
196
+ }
197
+ function serializeManifest(manifest) {
198
+ return JSON.stringify(sortedCopy(manifest), null, 2);
199
+ }
200
+ var init_extract_schemas = __esm({
201
+ "src/utils/extract-schemas.ts"() {
202
+ }
203
+ });
204
+ function mimeFor(filename) {
205
+ const ext = path12.extname(filename).toLowerCase();
206
+ return MIME_MAP[ext] || "application/octet-stream";
207
+ }
208
+ async function sha256Prefix(absPath, len) {
209
+ const buf = await fs.readFile(absPath);
210
+ return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
211
+ }
212
+ function insertHashIntoName(relPath, hash) {
213
+ const dir = path12.posix.dirname(relPath);
214
+ const base = path12.posix.basename(relPath);
215
+ const ext = path12.posix.extname(base);
216
+ const stem = ext ? base.slice(0, -ext.length) : base;
217
+ const hashed = `${stem}-${hash}${ext}`;
218
+ return dir === "." ? hashed : `${dir}/${hashed}`;
219
+ }
220
+ async function scanThemeAssets(distDir) {
221
+ const assetsDir = path12.join(distDir, "theme-assets");
222
+ if (!await fs.pathExists(assetsDir)) return [];
223
+ const files = await glob("**/*", {
224
+ cwd: assetsDir,
225
+ nodir: true,
226
+ dot: false
227
+ });
228
+ const results = [];
229
+ for (const rel of files) {
230
+ const absPath = path12.join(assetsDir, rel);
231
+ const stat = await fs.stat(absPath);
232
+ if (!stat.isFile()) continue;
233
+ const originalPath = rel.split(path12.sep).join("/");
234
+ const hash = await sha256Prefix(absPath, HASH_LEN);
235
+ const hashedPath = insertHashIntoName(originalPath, hash);
236
+ const contentType = mimeFor(rel);
237
+ results.push({
238
+ originalPath,
239
+ hashedPath,
240
+ hash,
241
+ size: stat.size,
242
+ contentType,
243
+ absPath
244
+ });
245
+ }
246
+ results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
247
+ return results;
248
+ }
249
+ var MIME_MAP, HASH_LEN;
250
+ var init_scan_theme_assets = __esm({
251
+ "src/utils/scan-theme-assets.ts"() {
252
+ MIME_MAP = {
253
+ ".png": "image/png",
254
+ ".jpg": "image/jpeg",
255
+ ".jpeg": "image/jpeg",
256
+ ".gif": "image/gif",
257
+ ".webp": "image/webp",
258
+ ".avif": "image/avif",
259
+ ".svg": "image/svg+xml",
260
+ ".ico": "image/x-icon",
261
+ ".bmp": "image/bmp",
262
+ ".woff": "font/woff",
263
+ ".woff2": "font/woff2",
264
+ ".ttf": "font/ttf",
265
+ ".otf": "font/otf",
266
+ ".eot": "application/vnd.ms-fontobject",
267
+ ".mp4": "video/mp4",
268
+ ".webm": "video/webm",
269
+ ".mov": "video/quicktime",
270
+ ".ogg": "video/ogg",
271
+ ".json": "application/json"
272
+ };
273
+ HASH_LEN = 8;
274
+ }
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
+ });
88
371
 
89
372
  // src/utils/compile-theme.ts
90
373
  var compile_theme_exports = {};
@@ -100,8 +383,8 @@ async function generateThemeCSS(themePath, outDir) {
100
383
  const tailwindcss = (await import('tailwindcss')).default;
101
384
  const tailwindConfig = {
102
385
  content: [
103
- path8.join(themePath, "sections/**/*.{ts,tsx}"),
104
- path8.join(themePath, "components/**/*.{ts,tsx}")
386
+ path12.join(themePath, "sections/**/*.{ts,tsx}"),
387
+ path12.join(themePath, "components/**/*.{ts,tsx}")
105
388
  ],
106
389
  theme: { extend: {} },
107
390
  plugins: []
@@ -111,7 +394,7 @@ async function generateThemeCSS(themePath, outDir) {
111
394
  inputCSS,
112
395
  { from: void 0 }
113
396
  );
114
- await fs7.writeFile(path8.join(outDir, "bundle.css"), result.css);
397
+ await fs10.writeFile(path12.join(outDir, "bundle.css"), result.css);
115
398
  logger.info("Generated bundle.css");
116
399
  } catch (err) {
117
400
  logger.warning(
@@ -122,12 +405,12 @@ async function generateThemeCSS(themePath, outDir) {
122
405
  async function resolveNodeModulesFile(startDir, relativePath) {
123
406
  let dir = startDir;
124
407
  while (true) {
125
- const candidate = path8.join(dir, "node_modules", relativePath);
408
+ const candidate = path12.join(dir, "node_modules", relativePath);
126
409
  try {
127
- await fs7.access(candidate);
410
+ await fs10.access(candidate);
128
411
  return candidate;
129
412
  } catch {
130
- const parent = path8.dirname(dir);
413
+ const parent = path12.dirname(dir);
131
414
  if (parent === dir) break;
132
415
  dir = parent;
133
416
  }
@@ -151,7 +434,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
151
434
  });
152
435
  for (const file of sourceFiles) {
153
436
  try {
154
- const content = await fs7.readFile(path8.join(sourceDir, file), "utf-8");
437
+ const content = await fs10.readFile(path12.join(sourceDir, file), "utf-8");
155
438
  for (const match of content.matchAll(namespaceImportRegex)) {
156
439
  const subpath = match[1] ? match[1].slice(1) : "";
157
440
  if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
@@ -205,17 +488,17 @@ function createCoreGlobalPlugin(themePath) {
205
488
  const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
206
489
  let distPath = await resolveNodeModulesFile(
207
490
  themePath,
208
- path8.join("@onexapis", "core", "dist", distFileName)
491
+ path12.join("@onexapis", "core", "dist", distFileName)
209
492
  );
210
493
  if (!distPath) {
211
494
  distPath = await resolveNodeModulesFile(
212
495
  __dirname,
213
- path8.join("@onexapis", "core", "dist", distFileName)
496
+ path12.join("@onexapis", "core", "dist", distFileName)
214
497
  );
215
498
  }
216
499
  try {
217
500
  if (!distPath) throw new Error("not found");
218
- const distContent = await fs7.readFile(distPath, "utf-8");
501
+ const distContent = await fs10.readFile(distPath, "utf-8");
219
502
  const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
220
503
  for (const m of exportMatches) {
221
504
  const names = m[1].split(",").map((n) => {
@@ -262,180 +545,6 @@ ${namedExportLines}
262
545
  }
263
546
  };
264
547
  }
265
- function createThemeDepsStubPlugin(themePath) {
266
- return {
267
- name: "theme-deps-stub",
268
- setup(build2) {
269
- const tryResolveOrStub = (filter, namespace) => {
270
- build2.onResolve({ filter }, async (args) => {
271
- if (args.pluginData?.skipStub) return void 0;
272
- try {
273
- const result = await build2.resolve(args.path, {
274
- kind: args.kind,
275
- resolveDir: args.resolveDir || themePath,
276
- importer: args.importer,
277
- namespace: "file",
278
- pluginData: { skipStub: true }
279
- });
280
- if (!result.errors.length) return result;
281
- } catch {
282
- }
283
- try {
284
- const req = createRequire(import.meta.url || __filename);
285
- const resolved = req.resolve(args.path);
286
- if (resolved) return { path: resolved, namespace: "file" };
287
- } catch {
288
- }
289
- return { path: args.path, namespace };
290
- });
291
- };
292
- tryResolveOrStub(/^next\//, "next-stub");
293
- build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
294
- const stubs = {
295
- "next/image": `
296
- import React from 'react';
297
- const Image = React.forwardRef((props, ref) => {
298
- const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
299
- const imgSrc = typeof src === 'object' ? src.src : src;
300
- const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
301
- const mergedStyle = { ...fillStyle, ...style };
302
- return React.createElement('img', {
303
- ref, src: imgSrc, alt,
304
- width: fill ? undefined : width, height: fill ? undefined : height,
305
- loading: priority ? 'eager' : 'lazy',
306
- style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
307
- className, onLoad, onError, ...rest,
308
- });
309
- });
310
- export default Image;
311
- `,
312
- "next/link": `
313
- import React from 'react';
314
- const Link = ({ href, children, ...rest }) => React.createElement('a', { href, ...rest }, children);
315
- export default Link;
316
- `,
317
- "next/navigation": `
318
- 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(){} }; }
319
- export function usePathname() { return window.location.pathname; }
320
- export function useSearchParams() { return new URLSearchParams(window.location.search); }
321
- export function useParams() { return {}; }
322
- export function redirect(url) { window.location.href = url; }
323
- export function notFound() { throw new Error('Not Found'); }
324
- `,
325
- "next/headers": `
326
- export function cookies() { return { get(){}, getAll(){ return []; }, set(){}, delete(){}, has(){ return false; } }; }
327
- export function headers() { return new Headers(); }
328
- `
329
- };
330
- return {
331
- contents: stubs[args.path] || "export default {};",
332
- loader: "jsx",
333
- resolveDir: themePath
334
- };
335
- });
336
- const lucideImports = /* @__PURE__ */ new Set();
337
- let lucideThemeScanned = false;
338
- tryResolveOrStub(/^lucide-react/, "lucide-stub");
339
- build2.onLoad({ filter: /.*/, namespace: "lucide-stub" }, async () => {
340
- if (!lucideThemeScanned) {
341
- lucideThemeScanned = true;
342
- try {
343
- const scanned = await scanImportsFromPackage(
344
- themePath,
345
- "lucide-react"
346
- );
347
- for (const names of Object.values(scanned)) {
348
- for (const name of names) lucideImports.add(name);
349
- }
350
- } catch {
351
- }
352
- }
353
- const iconNames = [...lucideImports];
354
- const exports$1 = iconNames.map((n) => `icon as ${n}`).join(", ");
355
- return {
356
- contents: `
357
- const icon = (props) => null;
358
- export { ${exports$1} };
359
- export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true : icon });
360
- `.trim(),
361
- loader: "jsx"
362
- };
363
- });
364
- tryResolveOrStub(/^framer-motion/, "motion-stub");
365
- build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
366
- contents: `
367
- import React from 'react';
368
- const handler = { get: (_, name) => {
369
- if (name === '__esModule') return true;
370
- return React.forwardRef((props, ref) => React.createElement(name, { ...props, ref }));
371
- }};
372
- export const motion = new Proxy({}, handler);
373
- export const AnimatePresence = ({ children }) => children || null;
374
- export function useInView() { return true; }
375
- export default { motion, AnimatePresence, useInView };
376
- `.trim(),
377
- loader: "jsx",
378
- resolveDir: themePath
379
- }));
380
- tryResolveOrStub(/^sonner$/, "sonner-stub");
381
- build2.onLoad({ filter: /.*/, namespace: "sonner-stub" }, () => ({
382
- contents: `
383
- export const toast = new Proxy(() => {}, { get: () => () => {} });
384
- export const Toaster = () => null;
385
- export default { toast, Toaster };
386
- `.trim(),
387
- loader: "jsx"
388
- }));
389
- tryResolveOrStub(/^react-hook-form$/, "rhf-stub");
390
- build2.onLoad({ filter: /.*/, namespace: "rhf-stub" }, () => ({
391
- contents: `
392
- export function useForm() {
393
- return {
394
- register: () => ({}),
395
- handleSubmit: (fn) => (e) => { e?.preventDefault?.(); fn({}); },
396
- formState: { errors: {}, isSubmitting: false, isValid: true },
397
- watch: () => undefined,
398
- setValue: () => {},
399
- reset: () => {},
400
- control: {},
401
- };
402
- }
403
- export function useController() { return { field: {}, fieldState: {} }; }
404
- export function useFormContext() { return useForm(); }
405
- `.trim(),
406
- loader: "js"
407
- }));
408
- tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
409
- build2.onLoad(
410
- { filter: /.*/, namespace: "hookform-resolvers-stub" },
411
- () => ({
412
- contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
413
- loader: "js"
414
- })
415
- );
416
- tryResolveOrStub(/^next-intl$/, "next-intl-stub");
417
- build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
418
- contents: `
419
- export function useTranslations(ns) {
420
- return (key) => ns ? ns + '.' + key : key;
421
- }
422
- export function useLocale() { return 'en'; }
423
- export function useMessages() { return {}; }
424
- `.trim(),
425
- loader: "js"
426
- }));
427
- tryResolveOrStub(/^zod$/, "zod-stub");
428
- build2.onLoad({ filter: /.*/, namespace: "zod-stub" }, () => ({
429
- contents: `
430
- 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 });
431
- export const z = { string: schema, number: schema, boolean: schema, object: (s) => ({ ...schema(), shape: s }), array: schema, enum: schema, union: schema, literal: schema, infer: undefined };
432
- export default z;
433
- `.trim(),
434
- loader: "js"
435
- }));
436
- }
437
- };
438
- }
439
548
  async function generateThemeData(themePath, outputDir, themeId) {
440
549
  const { createJiti } = await import('jiti');
441
550
  const jiti = createJiti(import.meta.url);
@@ -444,7 +553,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
444
553
  const pages = {};
445
554
  for (const ext of [".ts", ".js"]) {
446
555
  try {
447
- const mod = await jiti.import(path8.join(themePath, `theme.config${ext}`));
556
+ const mod = await jiti.import(path12.join(themePath, `theme.config${ext}`));
448
557
  themeConfig = mod.default || mod;
449
558
  break;
450
559
  } catch {
@@ -452,20 +561,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
452
561
  }
453
562
  for (const ext of [".ts", ".js"]) {
454
563
  try {
455
- const mod = await jiti.import(path8.join(themePath, `theme.layout${ext}`));
564
+ const mod = await jiti.import(path12.join(themePath, `theme.layout${ext}`));
456
565
  layoutConfig = mod.default || mod;
457
566
  break;
458
567
  } catch {
459
568
  }
460
569
  }
461
570
  const schemas = {};
462
- const sectionsDir = path8.join(themePath, "sections");
571
+ const sectionsDir = path12.join(themePath, "sections");
463
572
  try {
464
- const sectionDirs = await fs7.readdir(sectionsDir);
573
+ const sectionDirs = await fs10.readdir(sectionsDir);
465
574
  for (const dir of sectionDirs) {
466
- const schemaFile = path8.join(sectionsDir, dir, `${dir}.schema.ts`);
575
+ const schemaFile = path12.join(sectionsDir, dir, `${dir}.schema.ts`);
467
576
  try {
468
- await fs7.access(schemaFile);
577
+ await fs10.access(schemaFile);
469
578
  const mod = await jiti.import(schemaFile);
470
579
  for (const [key, value] of Object.entries(mod)) {
471
580
  if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
@@ -477,14 +586,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
477
586
  }
478
587
  } catch {
479
588
  }
480
- const pagesDir = path8.join(themePath, "pages");
589
+ const pagesDir = path12.join(themePath, "pages");
481
590
  try {
482
- const files = await fs7.readdir(pagesDir);
591
+ const files = await fs10.readdir(pagesDir);
483
592
  for (const file of files) {
484
593
  if (!file.match(/\.(ts|js)$/)) continue;
485
594
  const name = file.replace(/\.(ts|js)$/, "");
486
595
  try {
487
- const mod = await jiti.import(path8.join(pagesDir, file));
596
+ const mod = await jiti.import(path12.join(pagesDir, file));
488
597
  const config = mod.default || mod;
489
598
  const sections = (config.sections || []).map((section) => {
490
599
  const schema = schemas[section.type];
@@ -512,8 +621,16 @@ async function generateThemeData(themePath, outputDir, themeId) {
512
621
  }
513
622
  } catch {
514
623
  }
515
- await fs7.writeFile(
516
- path8.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"),
517
634
  JSON.stringify(
518
635
  {
519
636
  themeId,
@@ -536,22 +653,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
536
653
  logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
537
654
  }
538
655
  async function contentHashEntry(outputDir) {
539
- const entryPath = path8.join(outputDir, "bundle-entry.js");
540
- const mapPath = path8.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");
541
658
  let entryContent;
542
659
  try {
543
- entryContent = await fs7.readFile(entryPath, "utf-8");
660
+ entryContent = await fs10.readFile(entryPath, "utf-8");
544
661
  } catch {
545
- const indexPath = path8.join(outputDir, "index.js");
662
+ const indexPath = path12.join(outputDir, "index.js");
546
663
  try {
547
- entryContent = await fs7.readFile(indexPath, "utf-8");
664
+ entryContent = await fs10.readFile(indexPath, "utf-8");
548
665
  } catch {
549
666
  logger.warning("No entry file found in output, skipping content hash");
550
667
  return;
551
668
  }
552
669
  const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
553
670
  const hashedName2 = `bundle-entry-${hash2}.js`;
554
- const indexMapPath = path8.join(outputDir, "index.js.map");
671
+ const indexMapPath = path12.join(outputDir, "index.js.map");
555
672
  const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
556
673
  entryContent = entryContent.replace(
557
674
  /\/\/# sourceMappingURL=index\.js\.map/,
@@ -559,18 +676,18 @@ async function contentHashEntry(outputDir) {
559
676
  );
560
677
  const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
561
678
  for (const f of oldFiles2) {
562
- await fs7.unlink(path8.join(outputDir, f));
679
+ await fs10.unlink(path12.join(outputDir, f));
563
680
  }
564
- await fs7.writeFile(path8.join(outputDir, hashedName2), entryContent);
565
- await fs7.unlink(indexPath);
681
+ await fs10.writeFile(path12.join(outputDir, hashedName2), entryContent);
682
+ await fs10.unlink(indexPath);
566
683
  try {
567
- await fs7.unlink(entryPath);
684
+ await fs10.unlink(entryPath);
568
685
  } catch {
569
686
  }
570
- await fs7.writeFile(entryPath, entryContent);
687
+ await fs10.writeFile(entryPath, entryContent);
571
688
  try {
572
- await fs7.access(indexMapPath);
573
- await fs7.rename(indexMapPath, path8.join(outputDir, hashedMapName2));
689
+ await fs10.access(indexMapPath);
690
+ await fs10.rename(indexMapPath, path12.join(outputDir, hashedMapName2));
574
691
  } catch {
575
692
  }
576
693
  logger.info(`Entry hashed: ${hashedName2}`);
@@ -585,17 +702,17 @@ async function contentHashEntry(outputDir) {
585
702
  );
586
703
  const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
587
704
  for (const f of oldFiles) {
588
- await fs7.unlink(path8.join(outputDir, f));
705
+ await fs10.unlink(path12.join(outputDir, f));
589
706
  }
590
- await fs7.writeFile(path8.join(outputDir, hashedName), entryContent);
707
+ await fs10.writeFile(path12.join(outputDir, hashedName), entryContent);
591
708
  try {
592
- await fs7.unlink(entryPath);
709
+ await fs10.unlink(entryPath);
593
710
  } catch {
594
711
  }
595
- await fs7.writeFile(entryPath, entryContent);
712
+ await fs10.writeFile(entryPath, entryContent);
596
713
  try {
597
- await fs7.access(mapPath);
598
- await fs7.rename(mapPath, path8.join(outputDir, hashedMapName));
714
+ await fs10.access(mapPath);
715
+ await fs10.rename(mapPath, path12.join(outputDir, hashedMapName));
599
716
  } catch {
600
717
  }
601
718
  logger.info(`Entry hashed: ${hashedName}`);
@@ -607,7 +724,7 @@ async function extractDataRequirements(themePath) {
607
724
  const requirements = {};
608
725
  for (const file of schemaFiles) {
609
726
  try {
610
- const mod = await jiti.import(path8.join(themePath, file));
727
+ const mod = await jiti.import(path12.join(themePath, file));
611
728
  const exports$1 = mod;
612
729
  for (const value of Object.values(exports$1)) {
613
730
  if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
@@ -622,12 +739,105 @@ async function extractDataRequirements(themePath) {
622
739
  }
623
740
  return requirements;
624
741
  }
742
+ async function writeGateManifests(themePath, outputDir) {
743
+ try {
744
+ const schemas = await extractSchemas(themePath);
745
+ await fs10.writeFile(
746
+ path12.join(outputDir, "schemas.json"),
747
+ serializeManifest(schemas)
748
+ );
749
+ logger.info(
750
+ `Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
751
+ );
752
+ } catch (err) {
753
+ logger.warning(
754
+ `schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
755
+ );
756
+ }
757
+ try {
758
+ const entries = await scanThemeAssets(outputDir);
759
+ const assets = entries.map((e) => ({
760
+ path: e.originalPath,
761
+ hash: e.hash,
762
+ size: e.size,
763
+ contentType: e.contentType
764
+ }));
765
+ await fs10.writeFile(
766
+ path12.join(outputDir, "asset-manifest.json"),
767
+ JSON.stringify({ manifestVersion: 1, assets }, null, 2)
768
+ );
769
+ logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
770
+ } catch (err) {
771
+ logger.warning(
772
+ `asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
773
+ );
774
+ }
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
+ }
625
835
  async function generateManifest(themeName, themePath, outputDir) {
626
836
  let version = "1.0.0";
627
837
  let themeId = themeName;
628
838
  try {
629
- const pkgContent = await fs7.readFile(
630
- path8.join(themePath, "package.json"),
839
+ const pkgContent = await fs10.readFile(
840
+ path12.join(themePath, "package.json"),
631
841
  "utf-8"
632
842
  );
633
843
  const pkg = JSON.parse(pkgContent);
@@ -645,7 +855,7 @@ async function generateManifest(themeName, themePath, outputDir) {
645
855
  const dataRequirements = await extractDataRequirements(themePath);
646
856
  let hasThemeConfig = false;
647
857
  try {
648
- await fs7.access(path8.join(themePath, "theme.config.ts"));
858
+ await fs10.access(path12.join(themePath, "theme.config.ts"));
649
859
  hasThemeConfig = true;
650
860
  } catch {
651
861
  }
@@ -686,24 +896,34 @@ async function generateManifest(themeName, themePath, outputDir) {
686
896
  // Section data requirements for server-side prefetching (keyed by section type)
687
897
  dataRequirements
688
898
  };
689
- await fs7.writeFile(
690
- path8.join(outputDir, "manifest.json"),
899
+ await fs10.writeFile(
900
+ path12.join(outputDir, "manifest.json"),
691
901
  JSON.stringify(manifest, null, 2)
692
902
  );
693
903
  }
694
904
  async function compileStandaloneTheme(themePath, themeName) {
695
- const outputDir = path8.join(themePath, "dist");
696
- const bundleEntry = path8.join(themePath, "bundle-entry.ts");
697
- const indexEntry = path8.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");
698
912
  let entryPoint = indexEntry;
699
913
  try {
700
- await fs7.access(bundleEntry);
914
+ await fs10.access(bundleEntry);
701
915
  entryPoint = bundleEntry;
702
916
  } catch {
703
917
  }
704
- const shimPath = path8.join(outputDir, ".process-shim.js");
705
- await fs7.mkdir(outputDir, { recursive: true });
706
- await fs7.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);
707
927
  const buildOptions = {
708
928
  entryPoints: [entryPoint],
709
929
  bundle: true,
@@ -715,12 +935,7 @@ async function compileStandaloneTheme(themePath, themeName) {
715
935
  banner: {
716
936
  js: '"use client";'
717
937
  },
718
- plugins: [
719
- reactGlobalPlugin,
720
- reactQueryGlobalPlugin,
721
- createCoreGlobalPlugin(themePath),
722
- createThemeDepsStubPlugin(themePath)
723
- ],
938
+ plugins,
724
939
  external: [],
725
940
  alias: {
726
941
  events: "events/",
@@ -754,19 +969,21 @@ async function compileStandaloneTheme(themePath, themeName) {
754
969
  try {
755
970
  const result = await esbuild.build(buildOptions);
756
971
  try {
757
- await fs7.unlink(shimPath);
972
+ await fs10.unlink(shimPath);
758
973
  } catch {
759
974
  }
975
+ await compileSections(themePath, outputDir);
760
976
  await contentHashEntry(outputDir);
761
- const themeAssetsDir = path8.join(themePath, "assets");
762
- const distThemeAssets = path8.join(outputDir, "theme-assets");
977
+ const themeAssetsDir = path12.join(themePath, "assets");
978
+ const distThemeAssets = path12.join(outputDir, "theme-assets");
763
979
  try {
764
- await fs7.access(themeAssetsDir);
765
- await fs7.cp(themeAssetsDir, distThemeAssets, { recursive: true });
980
+ await fs10.access(themeAssetsDir);
981
+ await fs10.cp(themeAssetsDir, distThemeAssets, { recursive: true });
766
982
  logger.info("Copied static assets to dist/theme-assets/");
767
983
  } catch {
768
984
  }
769
985
  await generateManifest(themeName, themePath, outputDir);
986
+ await writeGateManifests(themePath, outputDir);
770
987
  await generateThemeData(themePath, outputDir, themeName);
771
988
  await generateThemeCSS(themePath, outputDir);
772
989
  if (result.metafile) {
@@ -781,7 +998,7 @@ async function compileStandaloneTheme(themePath, themeName) {
781
998
  return true;
782
999
  } catch (error) {
783
1000
  try {
784
- await fs7.unlink(shimPath);
1001
+ await fs10.unlink(shimPath);
785
1002
  } catch {
786
1003
  }
787
1004
  logger.error(`esbuild compilation failed: ${error}`);
@@ -789,18 +1006,25 @@ async function compileStandaloneTheme(themePath, themeName) {
789
1006
  }
790
1007
  }
791
1008
  async function compileStandaloneThemeDev(themePath, themeName) {
792
- const outputDir = path8.join(themePath, "dist");
793
- const bundleEntry = path8.join(themePath, "bundle-entry.ts");
794
- const indexEntry = path8.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");
795
1013
  let entryPoint = indexEntry;
796
1014
  try {
797
- await fs7.access(bundleEntry);
1015
+ await fs10.access(bundleEntry);
798
1016
  entryPoint = bundleEntry;
799
1017
  } catch {
800
1018
  }
801
- const shimPath = path8.join(outputDir, ".process-shim.js");
802
- await fs7.mkdir(outputDir, { recursive: true });
803
- await fs7.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);
804
1028
  const buildOptions = {
805
1029
  entryPoints: [entryPoint],
806
1030
  bundle: true,
@@ -811,12 +1035,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
811
1035
  banner: {
812
1036
  js: '"use client";'
813
1037
  },
814
- plugins: [
815
- reactGlobalPlugin,
816
- reactQueryGlobalPlugin,
817
- createCoreGlobalPlugin(themePath),
818
- createThemeDepsStubPlugin(themePath)
819
- ],
1038
+ plugins: devPlugins,
820
1039
  external: [],
821
1040
  alias: {
822
1041
  events: "events/",
@@ -854,18 +1073,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
854
1073
  return { context: context2, outputDir };
855
1074
  }
856
1075
  async function compilePreviewRuntime(themePath) {
857
- const outputDir = path8.join(themePath, "dist");
858
- await fs7.mkdir(outputDir, { recursive: true });
859
- const outputPath = path8.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");
860
1079
  const locations = [
861
- path8.join(__dirname, "..", "preview", "preview-app.tsx"),
862
- path8.join(__dirname, "preview", "preview-app.tsx"),
863
- path8.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")
864
1083
  ];
865
1084
  let previewEntryPath = null;
866
1085
  for (const loc of locations) {
867
1086
  try {
868
- await fs7.access(loc);
1087
+ await fs10.access(loc);
869
1088
  previewEntryPath = loc;
870
1089
  break;
871
1090
  } catch {
@@ -948,10 +1167,10 @@ ${locations.join("\n")}`
948
1167
  if (!lucideScanned) {
949
1168
  lucideScanned = true;
950
1169
  const coreSrcCandidates = [
951
- path8.join(themePath, "node_modules", "@onexapis", "core", "src"),
952
- path8.join(themePath, "..", "..", "packages", "core", "src"),
1170
+ path12.join(themePath, "node_modules", "@onexapis", "core", "src"),
1171
+ path12.join(themePath, "..", "..", "packages", "core", "src"),
953
1172
  // monorepo sibling
954
- path8.join(
1173
+ path12.join(
955
1174
  __dirname,
956
1175
  "..",
957
1176
  "..",
@@ -966,7 +1185,7 @@ ${locations.join("\n")}`
966
1185
  let coreSourceDir = null;
967
1186
  for (const candidate of coreSrcCandidates) {
968
1187
  try {
969
- await fs7.access(candidate);
1188
+ await fs10.access(candidate);
970
1189
  coreSourceDir = candidate;
971
1190
  break;
972
1191
  } catch {
@@ -985,21 +1204,21 @@ ${locations.join("\n")}`
985
1204
  }
986
1205
  } else {
987
1206
  const coreDistCandidates = [
988
- path8.join(themePath, "node_modules", "@onexapis", "core", "dist")
1207
+ path12.join(themePath, "node_modules", "@onexapis", "core", "dist")
989
1208
  ];
990
1209
  const resolvedDist = await resolveNodeModulesFile(
991
1210
  __dirname,
992
- path8.join("@onexapis", "core", "dist")
1211
+ path12.join("@onexapis", "core", "dist")
993
1212
  );
994
1213
  if (resolvedDist) coreDistCandidates.push(resolvedDist);
995
1214
  for (const candidate of coreDistCandidates) {
996
1215
  try {
997
- await fs7.access(candidate);
1216
+ await fs10.access(candidate);
998
1217
  const mjsFiles = await glob("*.mjs", { cwd: candidate });
999
1218
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
1000
1219
  for (const file of mjsFiles) {
1001
- const content = await fs7.readFile(
1002
- path8.join(candidate, file),
1220
+ const content = await fs10.readFile(
1221
+ path12.join(candidate, file),
1003
1222
  "utf-8"
1004
1223
  );
1005
1224
  for (const match of content.matchAll(importRegex)) {
@@ -1054,7 +1273,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
1054
1273
  const req = createRequire(import.meta.url || __filename);
1055
1274
  const cjsPath = req.resolve("framer-motion");
1056
1275
  const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
1057
- const esmEntry = path8.join(pkgDir, "dist", "es", "index.mjs");
1276
+ const esmEntry = path12.join(pkgDir, "dist", "es", "index.mjs");
1058
1277
  const { existsSync } = await import('fs');
1059
1278
  if (existsSync(esmEntry)) {
1060
1279
  return { path: esmEntry, namespace: "file" };
@@ -1153,8 +1372,8 @@ export function headers() { return new Headers(); }
1153
1372
  });
1154
1373
  }
1155
1374
  };
1156
- const shimPath = path8.join(outputDir, ".process-shim-preview.js");
1157
- await fs7.writeFile(shimPath, PROCESS_SHIM);
1375
+ const shimPath = path12.join(outputDir, ".process-shim-preview.js");
1376
+ await fs10.writeFile(shimPath, PROCESS_SHIM);
1158
1377
  await esbuild.build({
1159
1378
  entryPoints: [previewEntryPath],
1160
1379
  bundle: true,
@@ -1189,15 +1408,19 @@ export function headers() { return new Headers(); }
1189
1408
  }
1190
1409
  });
1191
1410
  try {
1192
- await fs7.unlink(shimPath);
1411
+ await fs10.unlink(shimPath);
1193
1412
  } catch {
1194
1413
  }
1195
1414
  return outputPath;
1196
1415
  }
1197
- var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
1416
+ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin, nextShimPlugin;
1198
1417
  var init_compile_theme = __esm({
1199
1418
  "src/utils/compile-theme.ts"() {
1200
1419
  init_logger();
1420
+ init_extract_schemas();
1421
+ init_scan_theme_assets();
1422
+ init_detect_nextjs();
1423
+ init_nextjs_page_scanner();
1201
1424
  PROCESS_SHIM = `
1202
1425
  if (typeof process === "undefined") {
1203
1426
  globalThis.process = {
@@ -1343,6 +1566,145 @@ export const {
1343
1566
  }));
1344
1567
  }
1345
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
+ };
1346
1708
  }
1347
1709
  });
1348
1710
 
@@ -1367,8 +1729,8 @@ function validateThemeName(name) {
1367
1729
  return /^[a-z][a-z0-9-]*$/.test(name);
1368
1730
  }
1369
1731
  function pathExists(filePath) {
1370
- const fs11 = __require("fs-extra");
1371
- return fs11.existsSync(filePath);
1732
+ const fs14 = __require("fs-extra");
1733
+ return fs14.existsSync(filePath);
1372
1734
  }
1373
1735
  function validateCategory(category) {
1374
1736
  const validCategories = [
@@ -1409,18 +1771,18 @@ async function renderTemplate(templatePath, data) {
1409
1771
  return ejs.render(template, data);
1410
1772
  }
1411
1773
  async function writeFile(filePath, content) {
1412
- await fs.ensureDir(path8.dirname(filePath));
1774
+ await fs.ensureDir(path12.dirname(filePath));
1413
1775
  await fs.writeFile(filePath, content, "utf-8");
1414
1776
  }
1415
1777
  function getTemplatesDir() {
1416
1778
  const locations = [
1417
- path8.join(__dirname, "../../templates"),
1779
+ path12.join(__dirname, "../../templates"),
1418
1780
  // Development
1419
- path8.join(__dirname, "../templates"),
1781
+ path12.join(__dirname, "../templates"),
1420
1782
  // Production (dist/)
1421
- path8.join(process.cwd(), "templates"),
1783
+ path12.join(process.cwd(), "templates"),
1422
1784
  // Fallback
1423
- path8.join(process.cwd(), "packages/cli/templates")
1785
+ path12.join(process.cwd(), "packages/cli/templates")
1424
1786
  // Monorepo
1425
1787
  ];
1426
1788
  for (const location of locations) {
@@ -1432,7 +1794,7 @@ function getTemplatesDir() {
1432
1794
  }
1433
1795
  async function copyTemplate(templateName, targetDir, data) {
1434
1796
  const templatesDir = getTemplatesDir();
1435
- const templateDir = path8.join(templatesDir, templateName);
1797
+ const templateDir = path12.join(templatesDir, templateName);
1436
1798
  if (!fs.existsSync(templateDir)) {
1437
1799
  throw new Error(
1438
1800
  `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
@@ -1441,8 +1803,8 @@ async function copyTemplate(templateName, targetDir, data) {
1441
1803
  await fs.ensureDir(targetDir);
1442
1804
  const files = await fs.readdir(templateDir);
1443
1805
  for (const file of files) {
1444
- const templatePath = path8.join(templateDir, file);
1445
- const targetPath = path8.join(targetDir, file);
1806
+ const templatePath = path12.join(templateDir, file);
1807
+ const targetPath = path12.join(targetDir, file);
1446
1808
  const stat = await fs.stat(templatePath);
1447
1809
  if (stat.isDirectory()) {
1448
1810
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1459,8 +1821,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1459
1821
  await fs.ensureDir(targetDir);
1460
1822
  const files = await fs.readdir(templateDir);
1461
1823
  for (const file of files) {
1462
- const templatePath = path8.join(templateDir, file);
1463
- const targetPath = path8.join(targetDir, file);
1824
+ const templatePath = path12.join(templateDir, file);
1825
+ const targetPath = path12.join(targetDir, file);
1464
1826
  const stat = await fs.stat(templatePath);
1465
1827
  if (stat.isDirectory()) {
1466
1828
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1475,32 +1837,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1475
1837
  }
1476
1838
  function getProjectRoot() {
1477
1839
  let currentDir = process.cwd();
1478
- while (currentDir !== path8.parse(currentDir).root) {
1479
- const packageJsonPath = path8.join(currentDir, "package.json");
1840
+ while (currentDir !== path12.parse(currentDir).root) {
1841
+ const packageJsonPath = path12.join(currentDir, "package.json");
1480
1842
  if (fs.existsSync(packageJsonPath)) {
1481
1843
  const packageJson = fs.readJsonSync(packageJsonPath);
1482
- if (packageJson.workspaces || fs.existsSync(path8.join(currentDir, "src/themes")) || fs.existsSync(path8.join(currentDir, "themes"))) {
1844
+ if (packageJson.workspaces || fs.existsSync(path12.join(currentDir, "src/themes")) || fs.existsSync(path12.join(currentDir, "themes"))) {
1483
1845
  return currentDir;
1484
1846
  }
1485
1847
  }
1486
- currentDir = path8.dirname(currentDir);
1848
+ currentDir = path12.dirname(currentDir);
1487
1849
  }
1488
1850
  return process.cwd();
1489
1851
  }
1490
1852
  function getThemesDir() {
1491
1853
  const root = getProjectRoot();
1492
- if (fs.existsSync(path8.join(root, "themes")))
1493
- return path8.join(root, "themes");
1494
- if (fs.existsSync(path8.join(root, "src/themes")))
1495
- return path8.join(root, "src/themes");
1496
- return path8.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);
1497
1859
  }
1498
1860
  function getFeaturesDir() {
1499
- return path8.join(getProjectRoot(), "src/features");
1861
+ return path12.join(getProjectRoot(), "src/features");
1500
1862
  }
1501
1863
  function isOneXProject() {
1502
1864
  const root = getProjectRoot();
1503
- return fs.existsSync(path8.join(root, "themes")) || fs.existsSync(path8.join(root, "src/themes")) || fs.existsSync(path8.join(root, "theme.config.ts")) || fs.existsSync(path8.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"));
1504
1866
  }
1505
1867
  function ensureOneXProject() {
1506
1868
  if (!isOneXProject()) {
@@ -1516,13 +1878,13 @@ function listThemes() {
1516
1878
  return [];
1517
1879
  }
1518
1880
  return fs.readdirSync(themesDir).filter((name) => {
1519
- const themePath = path8.join(themesDir, name);
1520
- return fs.statSync(themePath).isDirectory() && (fs.existsSync(path8.join(themePath, "theme.config.ts")) || fs.existsSync(path8.join(themePath, "bundle-entry.ts")) || fs.existsSync(path8.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")));
1521
1883
  });
1522
1884
  }
1523
1885
  function themeExists(themeName) {
1524
- const themePath = path8.join(getThemesDir(), themeName);
1525
- return fs.existsSync(themePath) && (fs.existsSync(path8.join(themePath, "theme.config.ts")) || fs.existsSync(path8.join(themePath, "bundle-entry.ts")) || fs.existsSync(path8.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")));
1526
1888
  }
1527
1889
  function detectPackageManager() {
1528
1890
  const userAgent = process.env.npm_config_user_agent || "";
@@ -1530,9 +1892,9 @@ function detectPackageManager() {
1530
1892
  if (userAgent.includes("yarn")) return "yarn";
1531
1893
  if (userAgent.includes("bun")) return "bun";
1532
1894
  const cwd = process.cwd();
1533
- if (fs.existsSync(path8.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1534
- if (fs.existsSync(path8.join(cwd, "yarn.lock"))) return "yarn";
1535
- if (fs.existsSync(path8.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";
1536
1898
  return "npm";
1537
1899
  }
1538
1900
  async function installDependencies(projectPath, packageManager = "npm") {
@@ -1549,15 +1911,16 @@ async function installDependencies(projectPath, packageManager = "npm") {
1549
1911
  }
1550
1912
  });
1551
1913
  }
1552
- var AUTH_DIR = path8.join(os.homedir(), ".onexthm");
1914
+ var AUTH_DIR = path12.join(os.homedir(), ".onexthm");
1553
1915
  var ENV_URLS = {
1554
1916
  dev: "https://platform-dev.onexeos.com",
1555
- prod: "https://platform-staging.onexeos.com"
1917
+ staging: "https://platform-staging.onexeos.com",
1918
+ prod: "https://platform-apis.onexeos.com"
1556
1919
  };
1557
1920
  function getAuthFile(env = "dev") {
1558
- const newFile = path8.join(AUTH_DIR, `auth-${env}.json`);
1921
+ const newFile = path12.join(AUTH_DIR, `auth-${env}.json`);
1559
1922
  if (env === "dev") {
1560
- const legacyFile = path8.join(AUTH_DIR, "auth.json");
1923
+ const legacyFile = path12.join(AUTH_DIR, "auth.json");
1561
1924
  if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
1562
1925
  try {
1563
1926
  fs.moveSync(legacyFile, newFile);
@@ -1684,7 +2047,7 @@ function decrypt(text, key) {
1684
2047
  }
1685
2048
 
1686
2049
  // src/commands/init.ts
1687
- async function initCommand(projectName, options = {}) {
2050
+ async function initCommand(projectName, options) {
1688
2051
  logger.header("Create New OneX Theme Project");
1689
2052
  let name;
1690
2053
  if (!projectName) {
@@ -1699,7 +2062,7 @@ async function initCommand(projectName, options = {}) {
1699
2062
  if (!validateThemeName(kebabName)) {
1700
2063
  return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
1701
2064
  }
1702
- if (fs3.existsSync(path8.join(process.cwd(), kebabName))) {
2065
+ if (fs3.existsSync(path12.join(process.cwd(), kebabName))) {
1703
2066
  return `Directory "${kebabName}" already exists`;
1704
2067
  }
1705
2068
  return true;
@@ -1710,14 +2073,14 @@ async function initCommand(projectName, options = {}) {
1710
2073
  } else {
1711
2074
  name = toKebabCase(projectName);
1712
2075
  }
1713
- const projectPath = path8.join(process.cwd(), name);
2076
+ const projectPath = path12.join(process.cwd(), name);
1714
2077
  if (fs3.existsSync(projectPath)) {
1715
2078
  logger.error(`Directory "${name}" already exists.`);
1716
2079
  process.exit(1);
1717
2080
  }
1718
2081
  if (!options.yes) {
1719
2082
  try {
1720
- const apiUrl = getApiUrl(options.env ?? "dev");
2083
+ const apiUrl = getApiUrl(options.env);
1721
2084
  const controller = new AbortController();
1722
2085
  const timeout = setTimeout(() => controller.abort(), 3e3);
1723
2086
  const response = await fetch(
@@ -1826,7 +2189,7 @@ async function initCommand(projectName, options = {}) {
1826
2189
  description,
1827
2190
  author
1828
2191
  );
1829
- const mcpJsonPath = path8.join(projectPath, ".mcp.json");
2192
+ const mcpJsonPath = path12.join(projectPath, ".mcp.json");
1830
2193
  if (fs3.existsSync(mcpJsonPath)) {
1831
2194
  let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
1832
2195
  if (figmaApiKey) {
@@ -1906,7 +2269,7 @@ async function initCommand(projectName, options = {}) {
1906
2269
  }
1907
2270
  }
1908
2271
  async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
1909
- const configPath = path8.join(projectPath, "theme.config.ts");
2272
+ const configPath = path12.join(projectPath, "theme.config.ts");
1910
2273
  if (fs3.existsSync(configPath)) {
1911
2274
  let content = fs3.readFileSync(configPath, "utf-8");
1912
2275
  content = content.replace(
@@ -1919,7 +2282,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
1919
2282
  );
1920
2283
  fs3.writeFileSync(configPath, content, "utf-8");
1921
2284
  }
1922
- const pkgPath = path8.join(projectPath, "package.json");
2285
+ const pkgPath = path12.join(projectPath, "package.json");
1923
2286
  if (fs3.existsSync(pkgPath)) {
1924
2287
  let content = fs3.readFileSync(pkgPath, "utf-8");
1925
2288
  content = content.replace(
@@ -1941,10 +2304,10 @@ async function createSectionCommand(name, options) {
1941
2304
  ensureOneXProject();
1942
2305
  if (!options.theme) {
1943
2306
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
1944
- (f) => fs.existsSync(path8.join(process.cwd(), f))
2307
+ (f) => fs.existsSync(path12.join(process.cwd(), f))
1945
2308
  );
1946
2309
  if (isStandaloneTheme) {
1947
- options.theme = path8.basename(process.cwd());
2310
+ options.theme = path12.basename(process.cwd());
1948
2311
  }
1949
2312
  }
1950
2313
  const sectionName = toKebabCase(name);
@@ -2007,35 +2370,35 @@ async function createSectionCommand(name, options) {
2007
2370
  };
2008
2371
  logger.startSpinner("Creating section files...");
2009
2372
  try {
2010
- const themePath = path8.join(getThemesDir(), themeName);
2011
- const sectionPath = path8.join(themePath, "sections", sectionName);
2373
+ const themePath = path12.join(getThemesDir(), themeName);
2374
+ const sectionPath = path12.join(themePath, "sections", sectionName);
2012
2375
  const schemaContent = generateSectionSchema(data);
2013
2376
  await writeFile(
2014
- path8.join(sectionPath, `${sectionName}.schema.ts`),
2377
+ path12.join(sectionPath, `${sectionName}.schema.ts`),
2015
2378
  schemaContent
2016
2379
  );
2017
2380
  if (createTemplate) {
2018
2381
  const templateContent = generateSectionTemplate(data);
2019
2382
  await writeFile(
2020
- path8.join(sectionPath, `${sectionName}-default.tsx`),
2383
+ path12.join(sectionPath, `${sectionName}-default.tsx`),
2021
2384
  templateContent
2022
2385
  );
2023
2386
  }
2024
2387
  const indexContent = generateSectionIndex(data, createTemplate);
2025
- await writeFile(path8.join(sectionPath, "index.ts"), indexContent);
2388
+ await writeFile(path12.join(sectionPath, "index.ts"), indexContent);
2026
2389
  logger.stopSpinner(true, "Section files created successfully!");
2027
2390
  logger.newLine();
2028
2391
  logger.section("Next steps:");
2029
2392
  logger.log(
2030
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(sectionPath, `${sectionName}.schema.ts`))}`
2393
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}.schema.ts`))}`
2031
2394
  );
2032
2395
  if (createTemplate) {
2033
2396
  logger.log(
2034
- ` 2. Edit template: ${path8.relative(process.cwd(), path8.join(sectionPath, `${sectionName}-default.tsx`))}`
2397
+ ` 2. Edit template: ${path12.relative(process.cwd(), path12.join(sectionPath, `${sectionName}-default.tsx`))}`
2035
2398
  );
2036
2399
  }
2037
2400
  logger.log(
2038
- ` 3. Add to theme manifest: ${path8.relative(process.cwd(), path8.join(themePath, "manifest.ts"))}`
2401
+ ` 3. Add to theme manifest: ${path12.relative(process.cwd(), path12.join(themePath, "manifest.ts"))}`
2039
2402
  );
2040
2403
  logger.newLine();
2041
2404
  logger.success("Section created successfully!");
@@ -2183,10 +2546,10 @@ async function createBlockCommand(name, options) {
2183
2546
  ensureOneXProject();
2184
2547
  if (!options.theme) {
2185
2548
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2186
- (f) => fs.existsSync(path8.join(process.cwd(), f))
2549
+ (f) => fs.existsSync(path12.join(process.cwd(), f))
2187
2550
  );
2188
2551
  if (isStandaloneTheme) {
2189
- options.theme = path8.basename(process.cwd());
2552
+ options.theme = path12.basename(process.cwd());
2190
2553
  }
2191
2554
  }
2192
2555
  const blockName = toKebabCase(name);
@@ -2261,24 +2624,24 @@ async function createBlockCommand(name, options) {
2261
2624
  };
2262
2625
  logger.startSpinner("Creating block files...");
2263
2626
  try {
2264
- const blockPath = scope === "shared" ? path8.join(getFeaturesDir(), "blocks", blockName) : path8.join(getThemesDir(), themeName, "blocks", blockName);
2627
+ const blockPath = scope === "shared" ? path12.join(getFeaturesDir(), "blocks", blockName) : path12.join(getThemesDir(), themeName, "blocks", blockName);
2265
2628
  const schemaContent = generateBlockSchema(data);
2266
2629
  await writeFile(
2267
- path8.join(blockPath, `${blockName}.schema.ts`),
2630
+ path12.join(blockPath, `${blockName}.schema.ts`),
2268
2631
  schemaContent
2269
2632
  );
2270
2633
  const componentContent = generateBlockComponent(data);
2271
- await writeFile(path8.join(blockPath, `${blockName}.tsx`), componentContent);
2634
+ await writeFile(path12.join(blockPath, `${blockName}.tsx`), componentContent);
2272
2635
  const indexContent = generateBlockIndex(data);
2273
- await writeFile(path8.join(blockPath, "index.ts"), indexContent);
2636
+ await writeFile(path12.join(blockPath, "index.ts"), indexContent);
2274
2637
  logger.stopSpinner(true, "Block files created successfully!");
2275
2638
  logger.newLine();
2276
2639
  logger.section("Next steps:");
2277
2640
  logger.log(
2278
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(blockPath, `${blockName}.schema.ts`))}`
2641
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.schema.ts`))}`
2279
2642
  );
2280
2643
  logger.log(
2281
- ` 2. Edit component: ${path8.relative(process.cwd(), path8.join(blockPath, `${blockName}.tsx`))}`
2644
+ ` 2. Edit component: ${path12.relative(process.cwd(), path12.join(blockPath, `${blockName}.tsx`))}`
2282
2645
  );
2283
2646
  logger.log(
2284
2647
  ` 3. Register in block registry: src/lib/registry/block-registry.ts`
@@ -2456,31 +2819,31 @@ async function createComponentCommand(name, options) {
2456
2819
  };
2457
2820
  logger.startSpinner("Creating component files...");
2458
2821
  try {
2459
- const componentPath = path8.join(
2822
+ const componentPath = path12.join(
2460
2823
  getFeaturesDir(),
2461
2824
  "components",
2462
2825
  componentName
2463
2826
  );
2464
2827
  const schemaContent = generateComponentSchema(data);
2465
2828
  await writeFile(
2466
- path8.join(componentPath, `${componentName}.schema.ts`),
2829
+ path12.join(componentPath, `${componentName}.schema.ts`),
2467
2830
  schemaContent
2468
2831
  );
2469
2832
  const componentContent = generateComponent(data);
2470
2833
  await writeFile(
2471
- path8.join(componentPath, `${componentName}.tsx`),
2834
+ path12.join(componentPath, `${componentName}.tsx`),
2472
2835
  componentContent
2473
2836
  );
2474
2837
  const indexContent = generateComponentIndex(data);
2475
- await writeFile(path8.join(componentPath, "index.ts"), indexContent);
2838
+ await writeFile(path12.join(componentPath, "index.ts"), indexContent);
2476
2839
  logger.stopSpinner(true, "Component files created successfully!");
2477
2840
  logger.newLine();
2478
2841
  logger.section("Next steps:");
2479
2842
  logger.log(
2480
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(componentPath, `${componentName}.schema.ts`))}`
2843
+ ` 1. Edit schema: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.schema.ts`))}`
2481
2844
  );
2482
2845
  logger.log(
2483
- ` 2. Edit component: ${path8.relative(process.cwd(), path8.join(componentPath, `${componentName}.tsx`))}`
2846
+ ` 2. Edit component: ${path12.relative(process.cwd(), path12.join(componentPath, `${componentName}.tsx`))}`
2484
2847
  );
2485
2848
  logger.log(
2486
2849
  ` 3. Register in component registry: src/lib/registry/component-registry.ts`
@@ -2637,13 +3000,13 @@ async function listSections(themeFilter) {
2637
3000
  return;
2638
3001
  }
2639
3002
  for (const theme of themes) {
2640
- const sectionsDir = path8.join(getThemesDir(), theme, "sections");
3003
+ const sectionsDir = path12.join(getThemesDir(), theme, "sections");
2641
3004
  if (!fs.existsSync(sectionsDir)) {
2642
3005
  continue;
2643
3006
  }
2644
3007
  const sections = fs.readdirSync(sectionsDir).filter((name) => {
2645
- const sectionPath = path8.join(sectionsDir, name);
2646
- return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path8.join(sectionPath, "index.ts"));
3008
+ const sectionPath = path12.join(sectionsDir, name);
3009
+ return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path12.join(sectionPath, "index.ts"));
2647
3010
  });
2648
3011
  if (sections.length > 0) {
2649
3012
  logger.log(chalk4.cyan(`
@@ -2657,11 +3020,11 @@ async function listSections(themeFilter) {
2657
3020
  }
2658
3021
  async function listBlocks(themeFilter) {
2659
3022
  logger.section("\u{1F9F1} Blocks");
2660
- const sharedBlocksDir = path8.join(getFeaturesDir(), "blocks");
3023
+ const sharedBlocksDir = path12.join(getFeaturesDir(), "blocks");
2661
3024
  if (fs.existsSync(sharedBlocksDir)) {
2662
3025
  const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
2663
- const blockPath = path8.join(sharedBlocksDir, name);
2664
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path8.join(blockPath, "index.ts"));
3026
+ const blockPath = path12.join(sharedBlocksDir, name);
3027
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
2665
3028
  });
2666
3029
  if (sharedBlocks.length > 0) {
2667
3030
  logger.log(chalk4.cyan("\n Shared:"));
@@ -2672,13 +3035,13 @@ async function listBlocks(themeFilter) {
2672
3035
  }
2673
3036
  const themes = themeFilter ? [themeFilter] : listThemes();
2674
3037
  for (const theme of themes) {
2675
- const blocksDir = path8.join(getThemesDir(), theme, "blocks");
3038
+ const blocksDir = path12.join(getThemesDir(), theme, "blocks");
2676
3039
  if (!fs.existsSync(blocksDir)) {
2677
3040
  continue;
2678
3041
  }
2679
3042
  const blocks = fs.readdirSync(blocksDir).filter((name) => {
2680
- const blockPath = path8.join(blocksDir, name);
2681
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path8.join(blockPath, "index.ts"));
3043
+ const blockPath = path12.join(blocksDir, name);
3044
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path12.join(blockPath, "index.ts"));
2682
3045
  });
2683
3046
  if (blocks.length > 0) {
2684
3047
  logger.log(chalk4.cyan(`
@@ -2692,14 +3055,14 @@ async function listBlocks(themeFilter) {
2692
3055
  }
2693
3056
  async function listComponents() {
2694
3057
  logger.section("\u2699\uFE0F Components");
2695
- const componentsDir = path8.join(getFeaturesDir(), "components");
3058
+ const componentsDir = path12.join(getFeaturesDir(), "components");
2696
3059
  if (!fs.existsSync(componentsDir)) {
2697
3060
  logger.warning("No components directory found");
2698
3061
  return;
2699
3062
  }
2700
3063
  const components = fs.readdirSync(componentsDir).filter((name) => {
2701
- const componentPath = path8.join(componentsDir, name);
2702
- return fs.statSync(componentPath).isDirectory() && fs.existsSync(path8.join(componentPath, "index.ts"));
3064
+ const componentPath = path12.join(componentsDir, name);
3065
+ return fs.statSync(componentPath).isDirectory() && fs.existsSync(path12.join(componentPath, "index.ts"));
2703
3066
  });
2704
3067
  if (components.length === 0) {
2705
3068
  logger.warning("No components found");
@@ -2720,11 +3083,11 @@ async function listThemesInfo() {
2720
3083
  }
2721
3084
  logger.log("");
2722
3085
  for (const theme of themes) {
2723
- const themeDir = path8.join(getThemesDir(), theme);
3086
+ const themeDir = path12.join(getThemesDir(), theme);
2724
3087
  const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
2725
3088
  let manifestContent = "";
2726
3089
  for (const candidate of candidates) {
2727
- const candidatePath = path8.join(themeDir, candidate);
3090
+ const candidatePath = path12.join(themeDir, candidate);
2728
3091
  if (fs.existsSync(candidatePath)) {
2729
3092
  manifestContent = fs.readFileSync(candidatePath, "utf-8");
2730
3093
  break;
@@ -2746,6 +3109,7 @@ async function listThemesInfo() {
2746
3109
 
2747
3110
  // src/commands/build.ts
2748
3111
  init_logger();
3112
+ init_detect_nextjs();
2749
3113
  async function buildCommand(options) {
2750
3114
  logger.header("Build Theme");
2751
3115
  let themePath;
@@ -2753,14 +3117,14 @@ async function buildCommand(options) {
2753
3117
  if (options.theme) {
2754
3118
  themeName = options.theme;
2755
3119
  try {
2756
- const workspaceThemePath = path8.join(getThemesDir(), themeName);
3120
+ const workspaceThemePath = path12.join(getThemesDir(), themeName);
2757
3121
  if (fs.existsSync(workspaceThemePath)) {
2758
3122
  themePath = workspaceThemePath;
2759
3123
  } else {
2760
- themePath = path8.join(process.cwd(), themeName);
3124
+ themePath = path12.join(process.cwd(), themeName);
2761
3125
  }
2762
3126
  } catch {
2763
- themePath = path8.join(process.cwd(), themeName);
3127
+ themePath = path12.join(process.cwd(), themeName);
2764
3128
  }
2765
3129
  if (!fs.existsSync(themePath)) {
2766
3130
  logger.error(`Theme "${themeName}" not found.`);
@@ -2770,11 +3134,14 @@ async function buildCommand(options) {
2770
3134
  const isThemeDir = [
2771
3135
  "theme.config.ts",
2772
3136
  "bundle-entry.ts",
2773
- "manifest.ts"
2774
- ].some((f) => fs.existsSync(path8.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)));
2775
3142
  if (isThemeDir) {
2776
3143
  themePath = process.cwd();
2777
- themeName = path8.basename(themePath);
3144
+ themeName = path12.basename(themePath);
2778
3145
  logger.info(`Building current theme: ${themeName}`);
2779
3146
  } else {
2780
3147
  logger.error(
@@ -2783,7 +3150,7 @@ async function buildCommand(options) {
2783
3150
  process.exit(1);
2784
3151
  }
2785
3152
  }
2786
- const packageJsonPath = path8.join(themePath, "package.json");
3153
+ const packageJsonPath = path12.join(themePath, "package.json");
2787
3154
  const hasPkgJson = fs.existsSync(packageJsonPath);
2788
3155
  if (!hasPkgJson) {
2789
3156
  logger.warning(
@@ -2799,30 +3166,42 @@ async function buildCommand(options) {
2799
3166
  }
2800
3167
  logger.newLine();
2801
3168
  logger.section("Build Steps");
2802
- logger.startSpinner("Running type check...");
2803
- const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
2804
- if (!typeCheckSuccess) {
2805
- logger.stopSpinner(false, "Type check failed");
2806
- logger.error("Fix type errors before building.");
2807
- process.exit(1);
2808
- }
2809
- logger.stopSpinner(true, "Type check passed");
2810
- logger.startSpinner("Running linter...");
2811
- const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
2812
- if (!lintSuccess) {
2813
- logger.stopSpinner(false, "Lint failed");
2814
- logger.error("Fix lint errors before building.");
2815
- process.exit(1);
2816
- }
2817
- logger.stopSpinner(true, "Lint passed");
2818
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
+ }
2819
3197
  const buildScript = pkgJson.scripts?.build || "";
2820
3198
  const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex build") || buildScript.includes("onex-cli build");
3199
+ const isNextjs = isNextjsProject(themePath);
2821
3200
  logger.startSpinner(
2822
3201
  options.watch ? "Building (watch mode)..." : "Building..."
2823
3202
  );
2824
3203
  let buildSuccess;
2825
- if (isRecursive) {
3204
+ if (isRecursive || isNextjs) {
2826
3205
  const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
2827
3206
  buildSuccess = await compileStandaloneTheme2(themePath, themeName);
2828
3207
  } else {
@@ -2839,9 +3218,9 @@ async function buildCommand(options) {
2839
3218
  logger.success("\u2713 Theme built successfully!");
2840
3219
  logger.newLine();
2841
3220
  logger.info(`Theme: ${themeName}`);
2842
- const distPath = path8.join(themePath, "dist");
3221
+ const distPath = path12.join(themePath, "dist");
2843
3222
  if (fs.existsSync(distPath)) {
2844
- logger.log(`Output: ${path8.relative(process.cwd(), distPath)}`);
3223
+ logger.log(`Output: ${path12.relative(process.cwd(), distPath)}`);
2845
3224
  const files = fs.readdirSync(distPath);
2846
3225
  logger.log(`Files: ${files.length}`);
2847
3226
  }
@@ -2982,8 +3361,8 @@ async function downloadBundleZip(apiUrl, themeId, version) {
2982
3361
  async function createCompatibilityFiles(outputDir, manifest) {
2983
3362
  const entryFile = manifest.output?.entry || "bundle-entry.js";
2984
3363
  if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
2985
- const hashedPath = path8.join(outputDir, entryFile);
2986
- const stablePath = path8.join(outputDir, "bundle-entry.js");
3364
+ const hashedPath = path12.join(outputDir, entryFile);
3365
+ const stablePath = path12.join(outputDir, "bundle-entry.js");
2987
3366
  if (await fs.pathExists(hashedPath)) {
2988
3367
  await fs.copy(hashedPath, stablePath);
2989
3368
  const mapPath = hashedPath + ".map";
@@ -2992,13 +3371,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
2992
3371
  }
2993
3372
  }
2994
3373
  }
2995
- const sectionsRegistryPath = path8.join(outputDir, "sections-registry.js");
3374
+ const sectionsRegistryPath = path12.join(outputDir, "sections-registry.js");
2996
3375
  const content = `// Re-export all sections from bundle-entry
2997
3376
  // This file exists to maintain compatibility with the import path
2998
3377
  export * from './bundle-entry.js';
2999
3378
  `;
3000
3379
  await fs.writeFile(sectionsRegistryPath, content, "utf-8");
3001
- const pkgJsonPath = path8.join(outputDir, "package.json");
3380
+ const pkgJsonPath = path12.join(outputDir, "package.json");
3002
3381
  await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
3003
3382
  }
3004
3383
  function showDownloadFailureHelp(themeId, apiUrl) {
@@ -3039,7 +3418,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
3039
3418
  }
3040
3419
  async function downloadCommand(options) {
3041
3420
  logger.header("Download Theme");
3042
- const env = options.env ?? "dev";
3421
+ const env = options.env;
3043
3422
  const apiUrl = getApiUrl(env);
3044
3423
  logger.info(`Environment: ${env} (${apiUrl})`);
3045
3424
  const spinner = ora("Initializing download...").start();
@@ -3097,7 +3476,7 @@ async function downloadCommand(options) {
3097
3476
  zip.extractAllTo(outputDir, true);
3098
3477
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
3099
3478
  spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
3100
- const manifestPath = path8.join(outputDir, "manifest.json");
3479
+ const manifestPath = path12.join(outputDir, "manifest.json");
3101
3480
  const manifest = await fs.readJson(manifestPath);
3102
3481
  await createCompatibilityFiles(outputDir, manifest);
3103
3482
  console.log();
@@ -3218,7 +3597,7 @@ async function renameTheme(themeDir, oldName, newName) {
3218
3597
  const oldPrefix = `${oldName}-`;
3219
3598
  const newPrefix = `${newName}-`;
3220
3599
  const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3221
- const pkgPath = path8.join(themeDir, "package.json");
3600
+ const pkgPath = path12.join(themeDir, "package.json");
3222
3601
  if (await fs.pathExists(pkgPath)) {
3223
3602
  const pkg = await fs.readJson(pkgPath);
3224
3603
  pkg.name = `@onex-themes/${newName}`;
@@ -3234,7 +3613,7 @@ async function renameTheme(themeDir, oldName, newName) {
3234
3613
  }
3235
3614
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3236
3615
  }
3237
- const configPath = path8.join(themeDir, "theme.config.ts");
3616
+ const configPath = path12.join(themeDir, "theme.config.ts");
3238
3617
  if (await fs.pathExists(configPath)) {
3239
3618
  let content = await fs.readFile(configPath, "utf-8");
3240
3619
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3244,7 +3623,7 @@ async function renameTheme(themeDir, oldName, newName) {
3244
3623
  );
3245
3624
  await fs.writeFile(configPath, content);
3246
3625
  }
3247
- const layoutPath = path8.join(themeDir, "theme.layout.ts");
3626
+ const layoutPath = path12.join(themeDir, "theme.layout.ts");
3248
3627
  if (await fs.pathExists(layoutPath)) {
3249
3628
  let content = await fs.readFile(layoutPath, "utf-8");
3250
3629
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3257,7 +3636,7 @@ async function renameTheme(themeDir, oldName, newName) {
3257
3636
  const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3258
3637
  const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
3259
3638
  for (const file of tsFiles) {
3260
- const filePath = path8.join(themeDir, file);
3639
+ const filePath = path12.join(themeDir, file);
3261
3640
  let content = await fs.readFile(filePath, "utf-8");
3262
3641
  const original = content;
3263
3642
  content = content.replace(
@@ -3279,7 +3658,7 @@ async function renameTheme(themeDir, oldName, newName) {
3279
3658
  }
3280
3659
  async function cloneCommand(themeName, options) {
3281
3660
  logger.header("Clone Theme Source");
3282
- const env = options.env ?? "dev";
3661
+ const env = options.env;
3283
3662
  const apiUrl = getApiUrl(env);
3284
3663
  logger.info(`Environment: ${env} (${apiUrl})`);
3285
3664
  if (options.bucket) {
@@ -3300,7 +3679,7 @@ async function cloneCommand(themeName, options) {
3300
3679
  }
3301
3680
  const spinner = ora("Initializing clone...").start();
3302
3681
  try {
3303
- const outputDir = options.output || path8.resolve(process.cwd(), newName);
3682
+ const outputDir = options.output || path12.resolve(process.cwd(), newName);
3304
3683
  if (await fs.pathExists(outputDir)) {
3305
3684
  spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
3306
3685
  logger.info(
@@ -3346,7 +3725,7 @@ async function cloneCommand(themeName, options) {
3346
3725
  spinner.succeed(
3347
3726
  `Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
3348
3727
  );
3349
- const envExamplePath = path8.join(outputDir, ".env.example");
3728
+ const envExamplePath = path12.join(outputDir, ".env.example");
3350
3729
  if (!await fs.pathExists(envExamplePath)) {
3351
3730
  await fs.writeFile(
3352
3731
  envExamplePath,
@@ -3359,7 +3738,7 @@ async function cloneCommand(themeName, options) {
3359
3738
  ].join("\n")
3360
3739
  );
3361
3740
  }
3362
- const mcpJsonPath = path8.join(outputDir, ".mcp.json");
3741
+ const mcpJsonPath = path12.join(outputDir, ".mcp.json");
3363
3742
  if (await fs.pathExists(mcpJsonPath)) {
3364
3743
  const { default: inquirerMod } = await import('inquirer');
3365
3744
  const { figmaApiKey } = await inquirerMod.prompt([
@@ -3384,7 +3763,7 @@ async function cloneCommand(themeName, options) {
3384
3763
  }
3385
3764
  if (options.install !== false) {
3386
3765
  const hasPkgJson = await fs.pathExists(
3387
- path8.join(outputDir, "package.json")
3766
+ path12.join(outputDir, "package.json")
3388
3767
  );
3389
3768
  if (hasPkgJson) {
3390
3769
  spinner.start("Installing dependencies...");
@@ -3412,7 +3791,7 @@ async function cloneCommand(themeName, options) {
3412
3791
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
3413
3792
  console.log();
3414
3793
  console.log(chalk4.cyan("Next steps:"));
3415
- console.log(chalk4.gray(` cd ${path8.relative(process.cwd(), outputDir)}`));
3794
+ console.log(chalk4.gray(` cd ${path12.relative(process.cwd(), outputDir)}`));
3416
3795
  console.log(
3417
3796
  chalk4.gray(" cp .env.example .env # then add your Company ID")
3418
3797
  );