@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/README.md +1 -1
- package/dist/cli.js +1688 -801
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1684 -797
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +784 -405
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +779 -400
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +89 -7
- package/package.json +2 -2
- package/templates/default/package.json +5 -0
package/dist/cli.js
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
|
|
4
4
|
var chalk4 = require('chalk');
|
|
5
5
|
var ora = require('ora');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var fs8 = require('fs/promises');
|
|
9
|
-
var crypto = require('crypto');
|
|
6
|
+
var fs3 = require('fs');
|
|
7
|
+
var path13 = require('path');
|
|
10
8
|
var glob = require('glob');
|
|
9
|
+
var fs8 = require('fs-extra');
|
|
10
|
+
var crypto = require('crypto');
|
|
11
|
+
var fs11 = require('fs/promises');
|
|
12
|
+
var esbuild = require('esbuild');
|
|
11
13
|
var module$1 = require('module');
|
|
12
14
|
var http = require('http');
|
|
13
|
-
var fs3 = require('fs');
|
|
14
15
|
var ws = require('ws');
|
|
15
16
|
var os = require('os');
|
|
16
17
|
var dotenv = require('dotenv');
|
|
17
|
-
var fs = require('fs-extra');
|
|
18
18
|
var ejs = require('ejs');
|
|
19
19
|
var child_process = require('child_process');
|
|
20
20
|
var commander = require('commander');
|
|
@@ -49,15 +49,15 @@ function _interopNamespace(e) {
|
|
|
49
49
|
|
|
50
50
|
var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
|
|
51
51
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
52
|
-
var
|
|
53
|
-
var
|
|
52
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
53
|
+
var path13__default = /*#__PURE__*/_interopDefault(path13);
|
|
54
54
|
var fs8__default = /*#__PURE__*/_interopDefault(fs8);
|
|
55
55
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
56
|
+
var fs11__default = /*#__PURE__*/_interopDefault(fs11);
|
|
57
|
+
var esbuild__namespace = /*#__PURE__*/_interopNamespace(esbuild);
|
|
56
58
|
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
57
|
-
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
58
59
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
59
60
|
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
60
|
-
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
61
61
|
var ejs__default = /*#__PURE__*/_interopDefault(ejs);
|
|
62
62
|
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
63
63
|
var archiver__default = /*#__PURE__*/_interopDefault(archiver);
|
|
@@ -132,6 +132,308 @@ var init_logger = __esm({
|
|
|
132
132
|
logger = new Logger();
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
|
+
function isNextjsProject(dir) {
|
|
136
|
+
return fs3__default.default.existsSync(path13__default.default.join(dir, "next.config.ts")) || fs3__default.default.existsSync(path13__default.default.join(dir, "next.config.js")) || fs3__default.default.existsSync(path13__default.default.join(dir, "next.config.mjs"));
|
|
137
|
+
}
|
|
138
|
+
var init_detect_nextjs = __esm({
|
|
139
|
+
"src/utils/detect-nextjs.ts"() {
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
function sortedCopy(value) {
|
|
143
|
+
if (Array.isArray(value)) {
|
|
144
|
+
return value.map((v) => sortedCopy(v));
|
|
145
|
+
}
|
|
146
|
+
if (value && typeof value === "object") {
|
|
147
|
+
const sorted = {};
|
|
148
|
+
for (const key of Object.keys(value).sort()) {
|
|
149
|
+
sorted[key] = sortedCopy(value[key]);
|
|
150
|
+
}
|
|
151
|
+
return sorted;
|
|
152
|
+
}
|
|
153
|
+
return value;
|
|
154
|
+
}
|
|
155
|
+
function normalizeField(raw) {
|
|
156
|
+
const out = {
|
|
157
|
+
id: String(raw.id),
|
|
158
|
+
type: String(raw.type)
|
|
159
|
+
};
|
|
160
|
+
if (raw.required === true) out.required = true;
|
|
161
|
+
if (raw.default !== void 0) out.default = raw.default;
|
|
162
|
+
if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
|
|
163
|
+
out.aliases = [...raw.aliases].map(String).sort();
|
|
164
|
+
}
|
|
165
|
+
if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
|
|
166
|
+
if (typeof raw.min === "number") out.min = raw.min;
|
|
167
|
+
if (typeof raw.max === "number") out.max = raw.max;
|
|
168
|
+
if (typeof raw.step === "number") out.step = raw.step;
|
|
169
|
+
if (Array.isArray(raw.accept)) {
|
|
170
|
+
out.accept = [...raw.accept].map(String).sort();
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(raw.options)) {
|
|
173
|
+
out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
function normalizeBlock(raw) {
|
|
178
|
+
return {
|
|
179
|
+
type: String(raw.type),
|
|
180
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
181
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
182
|
+
...typeof raw.limit === "number" ? { limit: raw.limit } : {},
|
|
183
|
+
...typeof raw.min === "number" ? { min: raw.min } : {},
|
|
184
|
+
...raw.sortable === true ? { sortable: true } : {},
|
|
185
|
+
...raw.baseType ? { baseType: String(raw.baseType) } : {}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function normalizeTemplate(raw) {
|
|
189
|
+
const out = { id: String(raw.id) };
|
|
190
|
+
if (raw.isDefault === true) out.isDefault = true;
|
|
191
|
+
if (Array.isArray(raw.settings)) {
|
|
192
|
+
out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
|
|
193
|
+
}
|
|
194
|
+
if (raw.defaults && typeof raw.defaults === "object") {
|
|
195
|
+
out.defaults = sortedCopy(raw.defaults);
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
function sortFieldsById(a, b) {
|
|
200
|
+
return a.id.localeCompare(b.id);
|
|
201
|
+
}
|
|
202
|
+
function sortByType(a, b) {
|
|
203
|
+
return a.type.localeCompare(b.type);
|
|
204
|
+
}
|
|
205
|
+
function normalizeSection(raw) {
|
|
206
|
+
return {
|
|
207
|
+
type: String(raw.type),
|
|
208
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
209
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
210
|
+
blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
|
|
211
|
+
templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
|
|
212
|
+
dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
|
|
213
|
+
...raw.global === true ? { global: true } : {},
|
|
214
|
+
...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
async function extractSchemas(themePath) {
|
|
218
|
+
const { createJiti } = await import('jiti');
|
|
219
|
+
const jiti = createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
220
|
+
const schemaFiles = await glob.glob("sections/**/*.schema.ts", { cwd: themePath });
|
|
221
|
+
const sections = {};
|
|
222
|
+
for (const file of schemaFiles) {
|
|
223
|
+
try {
|
|
224
|
+
const mod = await jiti.import(path13__default.default.join(themePath, file));
|
|
225
|
+
const exports$1 = mod;
|
|
226
|
+
for (const value of Object.values(exports$1)) {
|
|
227
|
+
if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
|
|
228
|
+
const section = normalizeSection(value);
|
|
229
|
+
sections[section.type] = section;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} catch {
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const manifest = {
|
|
236
|
+
manifestVersion: 1,
|
|
237
|
+
sections: {}
|
|
238
|
+
};
|
|
239
|
+
for (const type of Object.keys(sections).sort()) {
|
|
240
|
+
manifest.sections[type] = sections[type];
|
|
241
|
+
}
|
|
242
|
+
return manifest;
|
|
243
|
+
}
|
|
244
|
+
function serializeManifest(manifest) {
|
|
245
|
+
return JSON.stringify(sortedCopy(manifest), null, 2);
|
|
246
|
+
}
|
|
247
|
+
var init_extract_schemas = __esm({
|
|
248
|
+
"src/utils/extract-schemas.ts"() {
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
function isVideoAsset(filePath) {
|
|
252
|
+
const lower = filePath.toLowerCase();
|
|
253
|
+
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
254
|
+
}
|
|
255
|
+
function mimeFor(filename) {
|
|
256
|
+
const ext = path13__default.default.extname(filename).toLowerCase();
|
|
257
|
+
return MIME_MAP[ext] || "application/octet-stream";
|
|
258
|
+
}
|
|
259
|
+
async function sha256Prefix(absPath, len) {
|
|
260
|
+
const buf = await fs8__default.default.readFile(absPath);
|
|
261
|
+
return crypto__default.default.createHash("sha256").update(buf).digest("hex").slice(0, len);
|
|
262
|
+
}
|
|
263
|
+
function insertHashIntoName(relPath, hash) {
|
|
264
|
+
const dir = path13__default.default.posix.dirname(relPath);
|
|
265
|
+
const base = path13__default.default.posix.basename(relPath);
|
|
266
|
+
const ext = path13__default.default.posix.extname(base);
|
|
267
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
268
|
+
const hashed = `${stem}-${hash}${ext}`;
|
|
269
|
+
return dir === "." ? hashed : `${dir}/${hashed}`;
|
|
270
|
+
}
|
|
271
|
+
async function scanThemeAssets(distDir) {
|
|
272
|
+
const assetsDir = path13__default.default.join(distDir, "theme-assets");
|
|
273
|
+
if (!await fs8__default.default.pathExists(assetsDir)) return [];
|
|
274
|
+
const files = await glob.glob("**/*", {
|
|
275
|
+
cwd: assetsDir,
|
|
276
|
+
nodir: true,
|
|
277
|
+
dot: false
|
|
278
|
+
});
|
|
279
|
+
const results = [];
|
|
280
|
+
for (const rel of files) {
|
|
281
|
+
const absPath = path13__default.default.join(assetsDir, rel);
|
|
282
|
+
const stat = await fs8__default.default.stat(absPath);
|
|
283
|
+
if (!stat.isFile()) continue;
|
|
284
|
+
const originalPath = rel.split(path13__default.default.sep).join("/");
|
|
285
|
+
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
286
|
+
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
287
|
+
const contentType = mimeFor(rel);
|
|
288
|
+
results.push({
|
|
289
|
+
originalPath,
|
|
290
|
+
hashedPath,
|
|
291
|
+
hash,
|
|
292
|
+
size: stat.size,
|
|
293
|
+
contentType,
|
|
294
|
+
absPath
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
|
|
298
|
+
return results;
|
|
299
|
+
}
|
|
300
|
+
function buildAssetMap(entries) {
|
|
301
|
+
const map = {};
|
|
302
|
+
for (const e of entries) {
|
|
303
|
+
map[e.originalPath] = e.hashedPath;
|
|
304
|
+
}
|
|
305
|
+
return map;
|
|
306
|
+
}
|
|
307
|
+
var MIME_MAP, HASH_LEN, VIDEO_EXTENSIONS;
|
|
308
|
+
var init_scan_theme_assets = __esm({
|
|
309
|
+
"src/utils/scan-theme-assets.ts"() {
|
|
310
|
+
MIME_MAP = {
|
|
311
|
+
".png": "image/png",
|
|
312
|
+
".jpg": "image/jpeg",
|
|
313
|
+
".jpeg": "image/jpeg",
|
|
314
|
+
".gif": "image/gif",
|
|
315
|
+
".webp": "image/webp",
|
|
316
|
+
".avif": "image/avif",
|
|
317
|
+
".svg": "image/svg+xml",
|
|
318
|
+
".ico": "image/x-icon",
|
|
319
|
+
".bmp": "image/bmp",
|
|
320
|
+
".woff": "font/woff",
|
|
321
|
+
".woff2": "font/woff2",
|
|
322
|
+
".ttf": "font/ttf",
|
|
323
|
+
".otf": "font/otf",
|
|
324
|
+
".eot": "application/vnd.ms-fontobject",
|
|
325
|
+
".mp4": "video/mp4",
|
|
326
|
+
".webm": "video/webm",
|
|
327
|
+
".mov": "video/quicktime",
|
|
328
|
+
".ogg": "video/ogg",
|
|
329
|
+
".json": "application/json"
|
|
330
|
+
};
|
|
331
|
+
HASH_LEN = 8;
|
|
332
|
+
VIDEO_EXTENSIONS = [
|
|
333
|
+
".mp4",
|
|
334
|
+
".webm",
|
|
335
|
+
".ogg",
|
|
336
|
+
".mov",
|
|
337
|
+
".avi",
|
|
338
|
+
".mkv"
|
|
339
|
+
];
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
async function scanAppDirectory(themePath) {
|
|
343
|
+
const appDir = path13__default.default.join(themePath, "app");
|
|
344
|
+
let pageFiles;
|
|
345
|
+
try {
|
|
346
|
+
pageFiles = await glob.glob("**/page.{tsx,ts,jsx,js}", { cwd: appDir });
|
|
347
|
+
} catch {
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
if (pageFiles.length === 0) return [];
|
|
351
|
+
const pages = [];
|
|
352
|
+
for (const pageFile of pageFiles) {
|
|
353
|
+
const routePath = deriveRoutePath(pageFile);
|
|
354
|
+
const absPageFile = path13__default.default.join(appDir, pageFile);
|
|
355
|
+
let source;
|
|
356
|
+
try {
|
|
357
|
+
source = await fs11__default.default.readFile(absPageFile, "utf-8");
|
|
358
|
+
} catch {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const sections = await extractSectionsFromPage(source, themePath);
|
|
362
|
+
pages.push({
|
|
363
|
+
routePath,
|
|
364
|
+
sourceFile: path13__default.default.join("app", pageFile),
|
|
365
|
+
sections
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
return pages;
|
|
369
|
+
}
|
|
370
|
+
function deriveRoutePath(pageFile) {
|
|
371
|
+
const dir = path13__default.default.dirname(pageFile);
|
|
372
|
+
if (dir === ".") return "/";
|
|
373
|
+
return "/" + dir;
|
|
374
|
+
}
|
|
375
|
+
async function extractSectionsFromPage(source, themePath) {
|
|
376
|
+
const importRegex = /import\s+\w+\s+from\s+["'](@\/|\.\.?\/)(components\/[^"']+)["']/g;
|
|
377
|
+
const sections = [];
|
|
378
|
+
const seen = /* @__PURE__ */ new Set();
|
|
379
|
+
for (const match of source.matchAll(importRegex)) {
|
|
380
|
+
const rawImportPath = match[2];
|
|
381
|
+
const componentDir = path13__default.default.dirname(rawImportPath);
|
|
382
|
+
const absComponentDir = path13__default.default.join(themePath, componentDir);
|
|
383
|
+
if (seen.has(componentDir)) continue;
|
|
384
|
+
seen.add(componentDir);
|
|
385
|
+
const sectionJsonPath = path13__default.default.join(absComponentDir, "section.json");
|
|
386
|
+
let sectionJson;
|
|
387
|
+
try {
|
|
388
|
+
const raw = await fs11__default.default.readFile(sectionJsonPath, "utf-8");
|
|
389
|
+
sectionJson = JSON.parse(raw);
|
|
390
|
+
} catch {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (sectionJson.type !== "opaque-react") continue;
|
|
394
|
+
if (!sectionJson.entry) continue;
|
|
395
|
+
sections.push({
|
|
396
|
+
type: "opaque-react",
|
|
397
|
+
name: sectionJson.name ?? path13__default.default.basename(componentDir),
|
|
398
|
+
entry: path13__default.default.join(componentDir, sectionJson.entry),
|
|
399
|
+
componentDir
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
return sections;
|
|
403
|
+
}
|
|
404
|
+
function buildNextjsPagesMap(pages, themeId) {
|
|
405
|
+
const result = {};
|
|
406
|
+
for (const page of pages) {
|
|
407
|
+
const id = page.routePath === "/" ? "home" : page.routePath.replace(/\//g, "-").replace(/^-/, "");
|
|
408
|
+
const makeSectionType = (name) => `${themeId}-${name.toLowerCase().replace(/\s+/g, "-")}`;
|
|
409
|
+
result[id] = {
|
|
410
|
+
id,
|
|
411
|
+
name: id.charAt(0).toUpperCase() + id.slice(1),
|
|
412
|
+
path: page.routePath,
|
|
413
|
+
config: {
|
|
414
|
+
id,
|
|
415
|
+
path: page.routePath,
|
|
416
|
+
sections: page.sections.map((s, i) => ({
|
|
417
|
+
id: `${id}-section-${i}`,
|
|
418
|
+
type: makeSectionType(s.name),
|
|
419
|
+
sectionType: "opaque-react",
|
|
420
|
+
settings: {}
|
|
421
|
+
}))
|
|
422
|
+
},
|
|
423
|
+
sections: page.sections.map((s, i) => ({
|
|
424
|
+
id: `${id}-section-${i}`,
|
|
425
|
+
type: makeSectionType(s.name),
|
|
426
|
+
sectionType: "opaque-react",
|
|
427
|
+
settings: {}
|
|
428
|
+
}))
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
var init_nextjs_page_scanner = __esm({
|
|
434
|
+
"src/utils/nextjs-page-scanner.ts"() {
|
|
435
|
+
}
|
|
436
|
+
});
|
|
135
437
|
|
|
136
438
|
// src/utils/compile-theme.ts
|
|
137
439
|
var compile_theme_exports = {};
|
|
@@ -147,8 +449,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
147
449
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
148
450
|
const tailwindConfig = {
|
|
149
451
|
content: [
|
|
150
|
-
|
|
151
|
-
|
|
452
|
+
path13__default.default.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
453
|
+
path13__default.default.join(themePath, "components/**/*.{ts,tsx}")
|
|
152
454
|
],
|
|
153
455
|
theme: { extend: {} },
|
|
154
456
|
plugins: []
|
|
@@ -158,7 +460,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
158
460
|
inputCSS,
|
|
159
461
|
{ from: void 0 }
|
|
160
462
|
);
|
|
161
|
-
await
|
|
463
|
+
await fs11__default.default.writeFile(path13__default.default.join(outDir, "bundle.css"), result.css);
|
|
162
464
|
logger.info("Generated bundle.css");
|
|
163
465
|
} catch (err) {
|
|
164
466
|
logger.warning(
|
|
@@ -169,12 +471,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
169
471
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
170
472
|
let dir = startDir;
|
|
171
473
|
while (true) {
|
|
172
|
-
const candidate =
|
|
474
|
+
const candidate = path13__default.default.join(dir, "node_modules", relativePath);
|
|
173
475
|
try {
|
|
174
|
-
await
|
|
476
|
+
await fs11__default.default.access(candidate);
|
|
175
477
|
return candidate;
|
|
176
478
|
} catch {
|
|
177
|
-
const parent =
|
|
479
|
+
const parent = path13__default.default.dirname(dir);
|
|
178
480
|
if (parent === dir) break;
|
|
179
481
|
dir = parent;
|
|
180
482
|
}
|
|
@@ -198,7 +500,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
198
500
|
});
|
|
199
501
|
for (const file of sourceFiles) {
|
|
200
502
|
try {
|
|
201
|
-
const content = await
|
|
503
|
+
const content = await fs11__default.default.readFile(path13__default.default.join(sourceDir, file), "utf-8");
|
|
202
504
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
203
505
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
204
506
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -252,17 +554,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
252
554
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
253
555
|
let distPath = await resolveNodeModulesFile(
|
|
254
556
|
themePath,
|
|
255
|
-
|
|
557
|
+
path13__default.default.join("@onexapis", "core", "dist", distFileName)
|
|
256
558
|
);
|
|
257
559
|
if (!distPath) {
|
|
258
560
|
distPath = await resolveNodeModulesFile(
|
|
259
561
|
__dirname,
|
|
260
|
-
|
|
562
|
+
path13__default.default.join("@onexapis", "core", "dist", distFileName)
|
|
261
563
|
);
|
|
262
564
|
}
|
|
263
565
|
try {
|
|
264
566
|
if (!distPath) throw new Error("not found");
|
|
265
|
-
const distContent = await
|
|
567
|
+
const distContent = await fs11__default.default.readFile(distPath, "utf-8");
|
|
266
568
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
267
569
|
for (const m of exportMatches) {
|
|
268
570
|
const names = m[1].split(",").map((n) => {
|
|
@@ -309,180 +611,6 @@ ${namedExportLines}
|
|
|
309
611
|
}
|
|
310
612
|
};
|
|
311
613
|
}
|
|
312
|
-
function createThemeDepsStubPlugin(themePath) {
|
|
313
|
-
return {
|
|
314
|
-
name: "theme-deps-stub",
|
|
315
|
-
setup(build2) {
|
|
316
|
-
const tryResolveOrStub = (filter, namespace) => {
|
|
317
|
-
build2.onResolve({ filter }, async (args) => {
|
|
318
|
-
if (args.pluginData?.skipStub) return void 0;
|
|
319
|
-
try {
|
|
320
|
-
const result = await build2.resolve(args.path, {
|
|
321
|
-
kind: args.kind,
|
|
322
|
-
resolveDir: args.resolveDir || themePath,
|
|
323
|
-
importer: args.importer,
|
|
324
|
-
namespace: "file",
|
|
325
|
-
pluginData: { skipStub: true }
|
|
326
|
-
});
|
|
327
|
-
if (!result.errors.length) return result;
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
|
|
332
|
-
const resolved = req.resolve(args.path);
|
|
333
|
-
if (resolved) return { path: resolved, namespace: "file" };
|
|
334
|
-
} catch {
|
|
335
|
-
}
|
|
336
|
-
return { path: args.path, namespace };
|
|
337
|
-
});
|
|
338
|
-
};
|
|
339
|
-
tryResolveOrStub(/^next\//, "next-stub");
|
|
340
|
-
build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
|
|
341
|
-
const stubs = {
|
|
342
|
-
"next/image": `
|
|
343
|
-
import React from 'react';
|
|
344
|
-
const Image = React.forwardRef((props, ref) => {
|
|
345
|
-
const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
|
|
346
|
-
const imgSrc = typeof src === 'object' ? src.src : src;
|
|
347
|
-
const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
|
|
348
|
-
const mergedStyle = { ...fillStyle, ...style };
|
|
349
|
-
return React.createElement('img', {
|
|
350
|
-
ref, src: imgSrc, alt,
|
|
351
|
-
width: fill ? undefined : width, height: fill ? undefined : height,
|
|
352
|
-
loading: priority ? 'eager' : 'lazy',
|
|
353
|
-
style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
|
|
354
|
-
className, onLoad, onError, ...rest,
|
|
355
|
-
});
|
|
356
|
-
});
|
|
357
|
-
export default Image;
|
|
358
|
-
`,
|
|
359
|
-
"next/link": `
|
|
360
|
-
import React from 'react';
|
|
361
|
-
const Link = ({ href, children, ...rest }) => React.createElement('a', { href, ...rest }, children);
|
|
362
|
-
export default Link;
|
|
363
|
-
`,
|
|
364
|
-
"next/navigation": `
|
|
365
|
-
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(){} }; }
|
|
366
|
-
export function usePathname() { return window.location.pathname; }
|
|
367
|
-
export function useSearchParams() { return new URLSearchParams(window.location.search); }
|
|
368
|
-
export function useParams() { return {}; }
|
|
369
|
-
export function redirect(url) { window.location.href = url; }
|
|
370
|
-
export function notFound() { throw new Error('Not Found'); }
|
|
371
|
-
`,
|
|
372
|
-
"next/headers": `
|
|
373
|
-
export function cookies() { return { get(){}, getAll(){ return []; }, set(){}, delete(){}, has(){ return false; } }; }
|
|
374
|
-
export function headers() { return new Headers(); }
|
|
375
|
-
`
|
|
376
|
-
};
|
|
377
|
-
return {
|
|
378
|
-
contents: stubs[args.path] || "export default {};",
|
|
379
|
-
loader: "jsx",
|
|
380
|
-
resolveDir: themePath
|
|
381
|
-
};
|
|
382
|
-
});
|
|
383
|
-
const lucideImports = /* @__PURE__ */ new Set();
|
|
384
|
-
let lucideThemeScanned = false;
|
|
385
|
-
tryResolveOrStub(/^lucide-react/, "lucide-stub");
|
|
386
|
-
build2.onLoad({ filter: /.*/, namespace: "lucide-stub" }, async () => {
|
|
387
|
-
if (!lucideThemeScanned) {
|
|
388
|
-
lucideThemeScanned = true;
|
|
389
|
-
try {
|
|
390
|
-
const scanned = await scanImportsFromPackage(
|
|
391
|
-
themePath,
|
|
392
|
-
"lucide-react"
|
|
393
|
-
);
|
|
394
|
-
for (const names of Object.values(scanned)) {
|
|
395
|
-
for (const name of names) lucideImports.add(name);
|
|
396
|
-
}
|
|
397
|
-
} catch {
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
const iconNames = [...lucideImports];
|
|
401
|
-
const exports$1 = iconNames.map((n) => `icon as ${n}`).join(", ");
|
|
402
|
-
return {
|
|
403
|
-
contents: `
|
|
404
|
-
const icon = (props) => null;
|
|
405
|
-
export { ${exports$1} };
|
|
406
|
-
export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true : icon });
|
|
407
|
-
`.trim(),
|
|
408
|
-
loader: "jsx"
|
|
409
|
-
};
|
|
410
|
-
});
|
|
411
|
-
tryResolveOrStub(/^framer-motion/, "motion-stub");
|
|
412
|
-
build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
|
|
413
|
-
contents: `
|
|
414
|
-
import React from 'react';
|
|
415
|
-
const handler = { get: (_, name) => {
|
|
416
|
-
if (name === '__esModule') return true;
|
|
417
|
-
return React.forwardRef((props, ref) => React.createElement(name, { ...props, ref }));
|
|
418
|
-
}};
|
|
419
|
-
export const motion = new Proxy({}, handler);
|
|
420
|
-
export const AnimatePresence = ({ children }) => children || null;
|
|
421
|
-
export function useInView() { return true; }
|
|
422
|
-
export default { motion, AnimatePresence, useInView };
|
|
423
|
-
`.trim(),
|
|
424
|
-
loader: "jsx",
|
|
425
|
-
resolveDir: themePath
|
|
426
|
-
}));
|
|
427
|
-
tryResolveOrStub(/^sonner$/, "sonner-stub");
|
|
428
|
-
build2.onLoad({ filter: /.*/, namespace: "sonner-stub" }, () => ({
|
|
429
|
-
contents: `
|
|
430
|
-
export const toast = new Proxy(() => {}, { get: () => () => {} });
|
|
431
|
-
export const Toaster = () => null;
|
|
432
|
-
export default { toast, Toaster };
|
|
433
|
-
`.trim(),
|
|
434
|
-
loader: "jsx"
|
|
435
|
-
}));
|
|
436
|
-
tryResolveOrStub(/^react-hook-form$/, "rhf-stub");
|
|
437
|
-
build2.onLoad({ filter: /.*/, namespace: "rhf-stub" }, () => ({
|
|
438
|
-
contents: `
|
|
439
|
-
export function useForm() {
|
|
440
|
-
return {
|
|
441
|
-
register: () => ({}),
|
|
442
|
-
handleSubmit: (fn) => (e) => { e?.preventDefault?.(); fn({}); },
|
|
443
|
-
formState: { errors: {}, isSubmitting: false, isValid: true },
|
|
444
|
-
watch: () => undefined,
|
|
445
|
-
setValue: () => {},
|
|
446
|
-
reset: () => {},
|
|
447
|
-
control: {},
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
export function useController() { return { field: {}, fieldState: {} }; }
|
|
451
|
-
export function useFormContext() { return useForm(); }
|
|
452
|
-
`.trim(),
|
|
453
|
-
loader: "js"
|
|
454
|
-
}));
|
|
455
|
-
tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
|
|
456
|
-
build2.onLoad(
|
|
457
|
-
{ filter: /.*/, namespace: "hookform-resolvers-stub" },
|
|
458
|
-
() => ({
|
|
459
|
-
contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
|
|
460
|
-
loader: "js"
|
|
461
|
-
})
|
|
462
|
-
);
|
|
463
|
-
tryResolveOrStub(/^next-intl$/, "next-intl-stub");
|
|
464
|
-
build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
|
|
465
|
-
contents: `
|
|
466
|
-
export function useTranslations(ns) {
|
|
467
|
-
return (key) => ns ? ns + '.' + key : key;
|
|
468
|
-
}
|
|
469
|
-
export function useLocale() { return 'en'; }
|
|
470
|
-
export function useMessages() { return {}; }
|
|
471
|
-
`.trim(),
|
|
472
|
-
loader: "js"
|
|
473
|
-
}));
|
|
474
|
-
tryResolveOrStub(/^zod$/, "zod-stub");
|
|
475
|
-
build2.onLoad({ filter: /.*/, namespace: "zod-stub" }, () => ({
|
|
476
|
-
contents: `
|
|
477
|
-
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 });
|
|
478
|
-
export const z = { string: schema, number: schema, boolean: schema, object: (s) => ({ ...schema(), shape: s }), array: schema, enum: schema, union: schema, literal: schema, infer: undefined };
|
|
479
|
-
export default z;
|
|
480
|
-
`.trim(),
|
|
481
|
-
loader: "js"
|
|
482
|
-
}));
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
614
|
async function generateThemeData(themePath, outputDir, themeId) {
|
|
487
615
|
const { createJiti } = await import('jiti');
|
|
488
616
|
const jiti = createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
@@ -491,7 +619,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
491
619
|
const pages = {};
|
|
492
620
|
for (const ext of [".ts", ".js"]) {
|
|
493
621
|
try {
|
|
494
|
-
const mod = await jiti.import(
|
|
622
|
+
const mod = await jiti.import(path13__default.default.join(themePath, `theme.config${ext}`));
|
|
495
623
|
themeConfig = mod.default || mod;
|
|
496
624
|
break;
|
|
497
625
|
} catch {
|
|
@@ -499,20 +627,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
499
627
|
}
|
|
500
628
|
for (const ext of [".ts", ".js"]) {
|
|
501
629
|
try {
|
|
502
|
-
const mod = await jiti.import(
|
|
630
|
+
const mod = await jiti.import(path13__default.default.join(themePath, `theme.layout${ext}`));
|
|
503
631
|
layoutConfig = mod.default || mod;
|
|
504
632
|
break;
|
|
505
633
|
} catch {
|
|
506
634
|
}
|
|
507
635
|
}
|
|
508
636
|
const schemas = {};
|
|
509
|
-
const sectionsDir =
|
|
637
|
+
const sectionsDir = path13__default.default.join(themePath, "sections");
|
|
510
638
|
try {
|
|
511
|
-
const sectionDirs = await
|
|
639
|
+
const sectionDirs = await fs11__default.default.readdir(sectionsDir);
|
|
512
640
|
for (const dir of sectionDirs) {
|
|
513
|
-
const schemaFile =
|
|
641
|
+
const schemaFile = path13__default.default.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
514
642
|
try {
|
|
515
|
-
await
|
|
643
|
+
await fs11__default.default.access(schemaFile);
|
|
516
644
|
const mod = await jiti.import(schemaFile);
|
|
517
645
|
for (const [key, value] of Object.entries(mod)) {
|
|
518
646
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -524,14 +652,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
524
652
|
}
|
|
525
653
|
} catch {
|
|
526
654
|
}
|
|
527
|
-
const pagesDir =
|
|
655
|
+
const pagesDir = path13__default.default.join(themePath, "pages");
|
|
528
656
|
try {
|
|
529
|
-
const files = await
|
|
657
|
+
const files = await fs11__default.default.readdir(pagesDir);
|
|
530
658
|
for (const file of files) {
|
|
531
659
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
532
660
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
533
661
|
try {
|
|
534
|
-
const mod = await jiti.import(
|
|
662
|
+
const mod = await jiti.import(path13__default.default.join(pagesDir, file));
|
|
535
663
|
const config = mod.default || mod;
|
|
536
664
|
const sections = (config.sections || []).map((section) => {
|
|
537
665
|
const schema = schemas[section.type];
|
|
@@ -559,8 +687,16 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
559
687
|
}
|
|
560
688
|
} catch {
|
|
561
689
|
}
|
|
562
|
-
|
|
563
|
-
|
|
690
|
+
if (isNextjsProject(themePath)) {
|
|
691
|
+
const nextjsPages = await scanAppDirectory(themePath);
|
|
692
|
+
if (nextjsPages.length > 0) {
|
|
693
|
+
const nextjsPagesMap = buildNextjsPagesMap(nextjsPages, themeId);
|
|
694
|
+
Object.assign(pages, nextjsPagesMap);
|
|
695
|
+
logger.info(`Scanned ${nextjsPages.length} Next.js app/ pages`);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
await fs11__default.default.writeFile(
|
|
699
|
+
path13__default.default.join(outputDir, "theme-data.json"),
|
|
564
700
|
JSON.stringify(
|
|
565
701
|
{
|
|
566
702
|
themeId,
|
|
@@ -583,22 +719,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
583
719
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
584
720
|
}
|
|
585
721
|
async function contentHashEntry(outputDir) {
|
|
586
|
-
const entryPath =
|
|
587
|
-
const mapPath =
|
|
722
|
+
const entryPath = path13__default.default.join(outputDir, "bundle-entry.js");
|
|
723
|
+
const mapPath = path13__default.default.join(outputDir, "bundle-entry.js.map");
|
|
588
724
|
let entryContent;
|
|
589
725
|
try {
|
|
590
|
-
entryContent = await
|
|
726
|
+
entryContent = await fs11__default.default.readFile(entryPath, "utf-8");
|
|
591
727
|
} catch {
|
|
592
|
-
const indexPath =
|
|
728
|
+
const indexPath = path13__default.default.join(outputDir, "index.js");
|
|
593
729
|
try {
|
|
594
|
-
entryContent = await
|
|
730
|
+
entryContent = await fs11__default.default.readFile(indexPath, "utf-8");
|
|
595
731
|
} catch {
|
|
596
732
|
logger.warning("No entry file found in output, skipping content hash");
|
|
597
733
|
return;
|
|
598
734
|
}
|
|
599
735
|
const hash2 = crypto__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
600
736
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
601
|
-
const indexMapPath =
|
|
737
|
+
const indexMapPath = path13__default.default.join(outputDir, "index.js.map");
|
|
602
738
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
603
739
|
entryContent = entryContent.replace(
|
|
604
740
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
@@ -606,18 +742,18 @@ async function contentHashEntry(outputDir) {
|
|
|
606
742
|
);
|
|
607
743
|
const oldFiles2 = await glob.glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
608
744
|
for (const f of oldFiles2) {
|
|
609
|
-
await
|
|
745
|
+
await fs11__default.default.unlink(path13__default.default.join(outputDir, f));
|
|
610
746
|
}
|
|
611
|
-
await
|
|
612
|
-
await
|
|
747
|
+
await fs11__default.default.writeFile(path13__default.default.join(outputDir, hashedName2), entryContent);
|
|
748
|
+
await fs11__default.default.unlink(indexPath);
|
|
613
749
|
try {
|
|
614
|
-
await
|
|
750
|
+
await fs11__default.default.unlink(entryPath);
|
|
615
751
|
} catch {
|
|
616
752
|
}
|
|
617
|
-
await
|
|
753
|
+
await fs11__default.default.writeFile(entryPath, entryContent);
|
|
618
754
|
try {
|
|
619
|
-
await
|
|
620
|
-
await
|
|
755
|
+
await fs11__default.default.access(indexMapPath);
|
|
756
|
+
await fs11__default.default.rename(indexMapPath, path13__default.default.join(outputDir, hashedMapName2));
|
|
621
757
|
} catch {
|
|
622
758
|
}
|
|
623
759
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
@@ -632,17 +768,17 @@ async function contentHashEntry(outputDir) {
|
|
|
632
768
|
);
|
|
633
769
|
const oldFiles = await glob.glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
634
770
|
for (const f of oldFiles) {
|
|
635
|
-
await
|
|
771
|
+
await fs11__default.default.unlink(path13__default.default.join(outputDir, f));
|
|
636
772
|
}
|
|
637
|
-
await
|
|
773
|
+
await fs11__default.default.writeFile(path13__default.default.join(outputDir, hashedName), entryContent);
|
|
638
774
|
try {
|
|
639
|
-
await
|
|
775
|
+
await fs11__default.default.unlink(entryPath);
|
|
640
776
|
} catch {
|
|
641
777
|
}
|
|
642
|
-
await
|
|
778
|
+
await fs11__default.default.writeFile(entryPath, entryContent);
|
|
643
779
|
try {
|
|
644
|
-
await
|
|
645
|
-
await
|
|
780
|
+
await fs11__default.default.access(mapPath);
|
|
781
|
+
await fs11__default.default.rename(mapPath, path13__default.default.join(outputDir, hashedMapName));
|
|
646
782
|
} catch {
|
|
647
783
|
}
|
|
648
784
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -654,7 +790,7 @@ async function extractDataRequirements(themePath) {
|
|
|
654
790
|
const requirements = {};
|
|
655
791
|
for (const file of schemaFiles) {
|
|
656
792
|
try {
|
|
657
|
-
const mod = await jiti.import(
|
|
793
|
+
const mod = await jiti.import(path13__default.default.join(themePath, file));
|
|
658
794
|
const exports$1 = mod;
|
|
659
795
|
for (const value of Object.values(exports$1)) {
|
|
660
796
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -669,12 +805,105 @@ async function extractDataRequirements(themePath) {
|
|
|
669
805
|
}
|
|
670
806
|
return requirements;
|
|
671
807
|
}
|
|
808
|
+
async function writeGateManifests(themePath, outputDir) {
|
|
809
|
+
try {
|
|
810
|
+
const schemas = await extractSchemas(themePath);
|
|
811
|
+
await fs11__default.default.writeFile(
|
|
812
|
+
path13__default.default.join(outputDir, "schemas.json"),
|
|
813
|
+
serializeManifest(schemas)
|
|
814
|
+
);
|
|
815
|
+
logger.info(
|
|
816
|
+
`Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
|
|
817
|
+
);
|
|
818
|
+
} catch (err) {
|
|
819
|
+
logger.warning(
|
|
820
|
+
`schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
try {
|
|
824
|
+
const entries = await scanThemeAssets(outputDir);
|
|
825
|
+
const assets = entries.map((e) => ({
|
|
826
|
+
path: e.originalPath,
|
|
827
|
+
hash: e.hash,
|
|
828
|
+
size: e.size,
|
|
829
|
+
contentType: e.contentType
|
|
830
|
+
}));
|
|
831
|
+
await fs11__default.default.writeFile(
|
|
832
|
+
path13__default.default.join(outputDir, "asset-manifest.json"),
|
|
833
|
+
JSON.stringify({ manifestVersion: 1, assets }, null, 2)
|
|
834
|
+
);
|
|
835
|
+
logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
|
|
836
|
+
} catch (err) {
|
|
837
|
+
logger.warning(
|
|
838
|
+
`asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
async function compileSections(themePath, outputDir) {
|
|
843
|
+
const sectionsDir = path13__default.default.join(themePath, "sections");
|
|
844
|
+
let sectionDirs;
|
|
845
|
+
try {
|
|
846
|
+
sectionDirs = await fs11__default.default.readdir(sectionsDir);
|
|
847
|
+
} catch {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
for (const dirName of sectionDirs) {
|
|
851
|
+
const sectionSrc = path13__default.default.join(sectionsDir, dirName);
|
|
852
|
+
const sectionOut = path13__default.default.join(outputDir, "sections", dirName);
|
|
853
|
+
let section = null;
|
|
854
|
+
try {
|
|
855
|
+
const raw = await fs11__default.default.readFile(
|
|
856
|
+
path13__default.default.join(sectionSrc, "section.manifest.json"),
|
|
857
|
+
"utf-8"
|
|
858
|
+
);
|
|
859
|
+
section = JSON.parse(raw);
|
|
860
|
+
} catch {
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
switch (section.type) {
|
|
864
|
+
case "editable":
|
|
865
|
+
case "opaque-react":
|
|
866
|
+
break;
|
|
867
|
+
case "html": {
|
|
868
|
+
await fs11__default.default.mkdir(sectionOut, { recursive: true });
|
|
869
|
+
const htmlSrc = path13__default.default.join(sectionSrc, section.html);
|
|
870
|
+
let htmlContent = await fs11__default.default.readFile(htmlSrc, "utf-8");
|
|
871
|
+
htmlContent = htmlContent.replace(
|
|
872
|
+
/<script[^>]+src=["']https?:\/\/[^"']*["'][^>]*><\/script>/gi,
|
|
873
|
+
""
|
|
874
|
+
);
|
|
875
|
+
await fs11__default.default.writeFile(path13__default.default.join(sectionOut, path13__default.default.basename(section.html)), htmlContent);
|
|
876
|
+
if (section.css) {
|
|
877
|
+
await fs11__default.default.copyFile(
|
|
878
|
+
path13__default.default.join(sectionSrc, section.css),
|
|
879
|
+
path13__default.default.join(sectionOut, path13__default.default.basename(section.css))
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
case "iframe":
|
|
885
|
+
break;
|
|
886
|
+
case "webcomponent": {
|
|
887
|
+
await fs11__default.default.mkdir(sectionOut, { recursive: true });
|
|
888
|
+
await fs11__default.default.copyFile(
|
|
889
|
+
path13__default.default.join(sectionSrc, section.bundle),
|
|
890
|
+
path13__default.default.join(sectionOut, path13__default.default.basename(section.bundle))
|
|
891
|
+
);
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
default:
|
|
895
|
+
throw new Error(
|
|
896
|
+
`Unknown section type. Valid types: editable, opaque-react, html, iframe, webcomponent`
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
672
901
|
async function generateManifest(themeName, themePath, outputDir) {
|
|
673
902
|
let version2 = "1.0.0";
|
|
674
903
|
let themeId = themeName;
|
|
675
904
|
try {
|
|
676
|
-
const pkgContent = await
|
|
677
|
-
|
|
905
|
+
const pkgContent = await fs11__default.default.readFile(
|
|
906
|
+
path13__default.default.join(themePath, "package.json"),
|
|
678
907
|
"utf-8"
|
|
679
908
|
);
|
|
680
909
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -692,7 +921,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
692
921
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
693
922
|
let hasThemeConfig = false;
|
|
694
923
|
try {
|
|
695
|
-
await
|
|
924
|
+
await fs11__default.default.access(path13__default.default.join(themePath, "theme.config.ts"));
|
|
696
925
|
hasThemeConfig = true;
|
|
697
926
|
} catch {
|
|
698
927
|
}
|
|
@@ -733,24 +962,34 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
733
962
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
734
963
|
dataRequirements
|
|
735
964
|
};
|
|
736
|
-
await
|
|
737
|
-
|
|
965
|
+
await fs11__default.default.writeFile(
|
|
966
|
+
path13__default.default.join(outputDir, "manifest.json"),
|
|
738
967
|
JSON.stringify(manifest, null, 2)
|
|
739
968
|
);
|
|
740
969
|
}
|
|
741
970
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
742
|
-
const outputDir =
|
|
743
|
-
const
|
|
744
|
-
|
|
971
|
+
const outputDir = path13__default.default.join(themePath, "dist");
|
|
972
|
+
const isNextjs = isNextjsProject(themePath);
|
|
973
|
+
if (isNextjs) {
|
|
974
|
+
logger.info("Detected Next.js project \u2014 using next/* shims");
|
|
975
|
+
}
|
|
976
|
+
const bundleEntry = path13__default.default.join(themePath, "bundle-entry.ts");
|
|
977
|
+
const indexEntry = path13__default.default.join(themePath, "index.ts");
|
|
745
978
|
let entryPoint = indexEntry;
|
|
746
979
|
try {
|
|
747
|
-
await
|
|
980
|
+
await fs11__default.default.access(bundleEntry);
|
|
748
981
|
entryPoint = bundleEntry;
|
|
749
982
|
} catch {
|
|
750
983
|
}
|
|
751
|
-
const shimPath =
|
|
752
|
-
await
|
|
753
|
-
await
|
|
984
|
+
const shimPath = path13__default.default.join(outputDir, ".process-shim.js");
|
|
985
|
+
await fs11__default.default.mkdir(outputDir, { recursive: true });
|
|
986
|
+
await fs11__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
987
|
+
const plugins = [
|
|
988
|
+
reactGlobalPlugin,
|
|
989
|
+
reactQueryGlobalPlugin,
|
|
990
|
+
createCoreGlobalPlugin(themePath)
|
|
991
|
+
];
|
|
992
|
+
if (isNextjs) plugins.unshift(nextShimPlugin);
|
|
754
993
|
const buildOptions = {
|
|
755
994
|
entryPoints: [entryPoint],
|
|
756
995
|
bundle: true,
|
|
@@ -762,12 +1001,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
762
1001
|
banner: {
|
|
763
1002
|
js: '"use client";'
|
|
764
1003
|
},
|
|
765
|
-
plugins
|
|
766
|
-
reactGlobalPlugin,
|
|
767
|
-
reactQueryGlobalPlugin,
|
|
768
|
-
createCoreGlobalPlugin(themePath),
|
|
769
|
-
createThemeDepsStubPlugin(themePath)
|
|
770
|
-
],
|
|
1004
|
+
plugins,
|
|
771
1005
|
external: [],
|
|
772
1006
|
alias: {
|
|
773
1007
|
events: "events/",
|
|
@@ -801,19 +1035,21 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
801
1035
|
try {
|
|
802
1036
|
const result = await esbuild__namespace.build(buildOptions);
|
|
803
1037
|
try {
|
|
804
|
-
await
|
|
1038
|
+
await fs11__default.default.unlink(shimPath);
|
|
805
1039
|
} catch {
|
|
806
1040
|
}
|
|
1041
|
+
await compileSections(themePath, outputDir);
|
|
807
1042
|
await contentHashEntry(outputDir);
|
|
808
|
-
const themeAssetsDir =
|
|
809
|
-
const distThemeAssets =
|
|
1043
|
+
const themeAssetsDir = path13__default.default.join(themePath, "assets");
|
|
1044
|
+
const distThemeAssets = path13__default.default.join(outputDir, "theme-assets");
|
|
810
1045
|
try {
|
|
811
|
-
await
|
|
812
|
-
await
|
|
1046
|
+
await fs11__default.default.access(themeAssetsDir);
|
|
1047
|
+
await fs11__default.default.cp(themeAssetsDir, distThemeAssets, { recursive: true });
|
|
813
1048
|
logger.info("Copied static assets to dist/theme-assets/");
|
|
814
1049
|
} catch {
|
|
815
1050
|
}
|
|
816
1051
|
await generateManifest(themeName, themePath, outputDir);
|
|
1052
|
+
await writeGateManifests(themePath, outputDir);
|
|
817
1053
|
await generateThemeData(themePath, outputDir, themeName);
|
|
818
1054
|
await generateThemeCSS(themePath, outputDir);
|
|
819
1055
|
if (result.metafile) {
|
|
@@ -828,7 +1064,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
828
1064
|
return true;
|
|
829
1065
|
} catch (error) {
|
|
830
1066
|
try {
|
|
831
|
-
await
|
|
1067
|
+
await fs11__default.default.unlink(shimPath);
|
|
832
1068
|
} catch {
|
|
833
1069
|
}
|
|
834
1070
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -836,18 +1072,25 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
836
1072
|
}
|
|
837
1073
|
}
|
|
838
1074
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
839
|
-
const outputDir =
|
|
840
|
-
const
|
|
841
|
-
const
|
|
1075
|
+
const outputDir = path13__default.default.join(themePath, "dist");
|
|
1076
|
+
const isNextjs = isNextjsProject(themePath);
|
|
1077
|
+
const bundleEntry = path13__default.default.join(themePath, "bundle-entry.ts");
|
|
1078
|
+
const indexEntry = path13__default.default.join(themePath, "index.ts");
|
|
842
1079
|
let entryPoint = indexEntry;
|
|
843
1080
|
try {
|
|
844
|
-
await
|
|
1081
|
+
await fs11__default.default.access(bundleEntry);
|
|
845
1082
|
entryPoint = bundleEntry;
|
|
846
1083
|
} catch {
|
|
847
1084
|
}
|
|
848
|
-
const shimPath =
|
|
849
|
-
await
|
|
850
|
-
await
|
|
1085
|
+
const shimPath = path13__default.default.join(outputDir, ".process-shim.js");
|
|
1086
|
+
await fs11__default.default.mkdir(outputDir, { recursive: true });
|
|
1087
|
+
await fs11__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
1088
|
+
const devPlugins = [
|
|
1089
|
+
reactGlobalPlugin,
|
|
1090
|
+
reactQueryGlobalPlugin,
|
|
1091
|
+
createCoreGlobalPlugin(themePath)
|
|
1092
|
+
];
|
|
1093
|
+
if (isNextjs) devPlugins.unshift(nextShimPlugin);
|
|
851
1094
|
const buildOptions = {
|
|
852
1095
|
entryPoints: [entryPoint],
|
|
853
1096
|
bundle: true,
|
|
@@ -858,12 +1101,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
858
1101
|
banner: {
|
|
859
1102
|
js: '"use client";'
|
|
860
1103
|
},
|
|
861
|
-
plugins:
|
|
862
|
-
reactGlobalPlugin,
|
|
863
|
-
reactQueryGlobalPlugin,
|
|
864
|
-
createCoreGlobalPlugin(themePath),
|
|
865
|
-
createThemeDepsStubPlugin(themePath)
|
|
866
|
-
],
|
|
1104
|
+
plugins: devPlugins,
|
|
867
1105
|
external: [],
|
|
868
1106
|
alias: {
|
|
869
1107
|
events: "events/",
|
|
@@ -901,18 +1139,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
901
1139
|
return { context: context2, outputDir };
|
|
902
1140
|
}
|
|
903
1141
|
async function compilePreviewRuntime(themePath) {
|
|
904
|
-
const outputDir =
|
|
905
|
-
await
|
|
906
|
-
const outputPath =
|
|
1142
|
+
const outputDir = path13__default.default.join(themePath, "dist");
|
|
1143
|
+
await fs11__default.default.mkdir(outputDir, { recursive: true });
|
|
1144
|
+
const outputPath = path13__default.default.join(outputDir, "preview-runtime.js");
|
|
907
1145
|
const locations = [
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1146
|
+
path13__default.default.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
1147
|
+
path13__default.default.join(__dirname, "preview", "preview-app.tsx"),
|
|
1148
|
+
path13__default.default.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
911
1149
|
];
|
|
912
1150
|
let previewEntryPath = null;
|
|
913
1151
|
for (const loc of locations) {
|
|
914
1152
|
try {
|
|
915
|
-
await
|
|
1153
|
+
await fs11__default.default.access(loc);
|
|
916
1154
|
previewEntryPath = loc;
|
|
917
1155
|
break;
|
|
918
1156
|
} catch {
|
|
@@ -995,10 +1233,10 @@ ${locations.join("\n")}`
|
|
|
995
1233
|
if (!lucideScanned) {
|
|
996
1234
|
lucideScanned = true;
|
|
997
1235
|
const coreSrcCandidates = [
|
|
998
|
-
|
|
999
|
-
|
|
1236
|
+
path13__default.default.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
1237
|
+
path13__default.default.join(themePath, "..", "..", "packages", "core", "src"),
|
|
1000
1238
|
// monorepo sibling
|
|
1001
|
-
|
|
1239
|
+
path13__default.default.join(
|
|
1002
1240
|
__dirname,
|
|
1003
1241
|
"..",
|
|
1004
1242
|
"..",
|
|
@@ -1013,7 +1251,7 @@ ${locations.join("\n")}`
|
|
|
1013
1251
|
let coreSourceDir = null;
|
|
1014
1252
|
for (const candidate of coreSrcCandidates) {
|
|
1015
1253
|
try {
|
|
1016
|
-
await
|
|
1254
|
+
await fs11__default.default.access(candidate);
|
|
1017
1255
|
coreSourceDir = candidate;
|
|
1018
1256
|
break;
|
|
1019
1257
|
} catch {
|
|
@@ -1032,21 +1270,21 @@ ${locations.join("\n")}`
|
|
|
1032
1270
|
}
|
|
1033
1271
|
} else {
|
|
1034
1272
|
const coreDistCandidates = [
|
|
1035
|
-
|
|
1273
|
+
path13__default.default.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
1036
1274
|
];
|
|
1037
1275
|
const resolvedDist = await resolveNodeModulesFile(
|
|
1038
1276
|
__dirname,
|
|
1039
|
-
|
|
1277
|
+
path13__default.default.join("@onexapis", "core", "dist")
|
|
1040
1278
|
);
|
|
1041
1279
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
1042
1280
|
for (const candidate of coreDistCandidates) {
|
|
1043
1281
|
try {
|
|
1044
|
-
await
|
|
1282
|
+
await fs11__default.default.access(candidate);
|
|
1045
1283
|
const mjsFiles = await glob.glob("*.mjs", { cwd: candidate });
|
|
1046
1284
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
1047
1285
|
for (const file of mjsFiles) {
|
|
1048
|
-
const content = await
|
|
1049
|
-
|
|
1286
|
+
const content = await fs11__default.default.readFile(
|
|
1287
|
+
path13__default.default.join(candidate, file),
|
|
1050
1288
|
"utf-8"
|
|
1051
1289
|
);
|
|
1052
1290
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1101,7 +1339,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1101
1339
|
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
|
|
1102
1340
|
const cjsPath = req.resolve("framer-motion");
|
|
1103
1341
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1104
|
-
const esmEntry =
|
|
1342
|
+
const esmEntry = path13__default.default.join(pkgDir, "dist", "es", "index.mjs");
|
|
1105
1343
|
const { existsSync } = await import('fs');
|
|
1106
1344
|
if (existsSync(esmEntry)) {
|
|
1107
1345
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1200,8 +1438,8 @@ export function headers() { return new Headers(); }
|
|
|
1200
1438
|
});
|
|
1201
1439
|
}
|
|
1202
1440
|
};
|
|
1203
|
-
const shimPath =
|
|
1204
|
-
await
|
|
1441
|
+
const shimPath = path13__default.default.join(outputDir, ".process-shim-preview.js");
|
|
1442
|
+
await fs11__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
1205
1443
|
await esbuild__namespace.build({
|
|
1206
1444
|
entryPoints: [previewEntryPath],
|
|
1207
1445
|
bundle: true,
|
|
@@ -1236,15 +1474,19 @@ export function headers() { return new Headers(); }
|
|
|
1236
1474
|
}
|
|
1237
1475
|
});
|
|
1238
1476
|
try {
|
|
1239
|
-
await
|
|
1477
|
+
await fs11__default.default.unlink(shimPath);
|
|
1240
1478
|
} catch {
|
|
1241
1479
|
}
|
|
1242
1480
|
return outputPath;
|
|
1243
1481
|
}
|
|
1244
|
-
var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
|
|
1482
|
+
var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin, nextShimPlugin;
|
|
1245
1483
|
var init_compile_theme = __esm({
|
|
1246
1484
|
"src/utils/compile-theme.ts"() {
|
|
1247
1485
|
init_logger();
|
|
1486
|
+
init_extract_schemas();
|
|
1487
|
+
init_scan_theme_assets();
|
|
1488
|
+
init_detect_nextjs();
|
|
1489
|
+
init_nextjs_page_scanner();
|
|
1248
1490
|
PROCESS_SHIM = `
|
|
1249
1491
|
if (typeof process === "undefined") {
|
|
1250
1492
|
globalThis.process = {
|
|
@@ -1390,6 +1632,145 @@ export const {
|
|
|
1390
1632
|
}));
|
|
1391
1633
|
}
|
|
1392
1634
|
};
|
|
1635
|
+
nextShimPlugin = {
|
|
1636
|
+
name: "next-shim",
|
|
1637
|
+
setup(build2) {
|
|
1638
|
+
for (const serverModule of ["next/headers", "next/server", "next/cache"]) {
|
|
1639
|
+
build2.onResolve({ filter: new RegExp(`^${serverModule.replace("/", "\\/")}`) }, (args) => ({
|
|
1640
|
+
path: args.path,
|
|
1641
|
+
namespace: "next-server-error"
|
|
1642
|
+
}));
|
|
1643
|
+
}
|
|
1644
|
+
build2.onLoad({ filter: /.*/, namespace: "next-server-error" }, (args) => ({
|
|
1645
|
+
errors: [
|
|
1646
|
+
{
|
|
1647
|
+
text: `"${args.path}" is server-only and cannot be used in a OneX theme bundle. Use client-side equivalents or remove the import.`
|
|
1648
|
+
}
|
|
1649
|
+
]
|
|
1650
|
+
}));
|
|
1651
|
+
build2.onResolve({ filter: /^next\/navigation$/ }, () => ({
|
|
1652
|
+
path: "next-navigation-shim",
|
|
1653
|
+
namespace: "next-shim"
|
|
1654
|
+
}));
|
|
1655
|
+
build2.onLoad({ filter: /^next-navigation-shim$/, namespace: "next-shim" }, () => ({
|
|
1656
|
+
contents: `
|
|
1657
|
+
export function usePathname() {
|
|
1658
|
+
if (typeof window === 'undefined') return '/';
|
|
1659
|
+
return window.location.pathname;
|
|
1660
|
+
}
|
|
1661
|
+
export function useSearchParams() {
|
|
1662
|
+
if (typeof window === 'undefined') return new URLSearchParams();
|
|
1663
|
+
return new URLSearchParams(window.location.search);
|
|
1664
|
+
}
|
|
1665
|
+
export function useParams() {
|
|
1666
|
+
if (typeof window === 'undefined') return {};
|
|
1667
|
+
return (globalThis.__ONEX_ROUTE_PARAMS__) ?? {};
|
|
1668
|
+
}
|
|
1669
|
+
export function useRouter() {
|
|
1670
|
+
return {
|
|
1671
|
+
push(url) { if (typeof window !== 'undefined') window.location.href = url; },
|
|
1672
|
+
replace(url) { if (typeof window !== 'undefined') window.location.replace(url); },
|
|
1673
|
+
back() { if (typeof window !== 'undefined') window.history.back(); },
|
|
1674
|
+
forward() { if (typeof window !== 'undefined') window.history.forward(); },
|
|
1675
|
+
refresh() { if (typeof window !== 'undefined') window.location.reload(); },
|
|
1676
|
+
prefetch() {},
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
export function redirect(url) {
|
|
1680
|
+
if (typeof window !== 'undefined') window.location.href = url;
|
|
1681
|
+
throw new Error('redirect');
|
|
1682
|
+
}
|
|
1683
|
+
export function notFound() { throw new Error('not-found'); }
|
|
1684
|
+
`.trim(),
|
|
1685
|
+
loader: "js"
|
|
1686
|
+
}));
|
|
1687
|
+
build2.onResolve({ filter: /^next\/font\// }, () => ({
|
|
1688
|
+
path: "next-font-shim",
|
|
1689
|
+
namespace: "next-shim"
|
|
1690
|
+
}));
|
|
1691
|
+
build2.onLoad({ filter: /^next-font-shim$/, namespace: "next-shim" }, () => ({
|
|
1692
|
+
contents: `
|
|
1693
|
+
function makeFont(family) {
|
|
1694
|
+
return function(_opts) {
|
|
1695
|
+
return {
|
|
1696
|
+
className: '',
|
|
1697
|
+
style: { fontFamily: family + ', system-ui, sans-serif' },
|
|
1698
|
+
variable: '--font-' + family.toLowerCase().replace(/\\s+/g, '-'),
|
|
1699
|
+
};
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
export const Inter = makeFont('Inter');
|
|
1703
|
+
export const Roboto = makeFont('Roboto');
|
|
1704
|
+
export const Open_Sans = makeFont('Open Sans');
|
|
1705
|
+
export const Lato = makeFont('Lato');
|
|
1706
|
+
export const Montserrat = makeFont('Montserrat');
|
|
1707
|
+
export const Poppins = makeFont('Poppins');
|
|
1708
|
+
export const Raleway = makeFont('Raleway');
|
|
1709
|
+
export const Nunito = makeFont('Nunito');
|
|
1710
|
+
export const Geist = makeFont('Geist');
|
|
1711
|
+
export const Geist_Mono = makeFont('Geist Mono');
|
|
1712
|
+
export const DM_Sans = makeFont('DM Sans');
|
|
1713
|
+
export const Plus_Jakarta_Sans = makeFont('Plus Jakarta Sans');
|
|
1714
|
+
export function localFont(_opts) {
|
|
1715
|
+
return { className: '', style: { fontFamily: 'system-ui, sans-serif' }, variable: '--font-local' };
|
|
1716
|
+
}
|
|
1717
|
+
`.trim(),
|
|
1718
|
+
loader: "js"
|
|
1719
|
+
}));
|
|
1720
|
+
build2.onResolve({ filter: /^next\/dynamic$/ }, () => ({
|
|
1721
|
+
path: "next-dynamic-shim",
|
|
1722
|
+
namespace: "next-shim"
|
|
1723
|
+
}));
|
|
1724
|
+
build2.onLoad({ filter: /^next-dynamic-shim$/, namespace: "next-shim" }, () => ({
|
|
1725
|
+
contents: `
|
|
1726
|
+
import { lazy, Suspense, createElement } from 'react';
|
|
1727
|
+
export default function dynamic(loader, opts) {
|
|
1728
|
+
const Lazy = lazy(loader);
|
|
1729
|
+
return function DynamicComponent(props) {
|
|
1730
|
+
return createElement(Suspense, { fallback: opts?.loading ? createElement(opts.loading) : null },
|
|
1731
|
+
createElement(Lazy, props));
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
`.trim(),
|
|
1735
|
+
loader: "js"
|
|
1736
|
+
}));
|
|
1737
|
+
build2.onResolve({ filter: /^next\/image$/ }, () => ({
|
|
1738
|
+
path: "next-image-shim",
|
|
1739
|
+
namespace: "next-shim"
|
|
1740
|
+
}));
|
|
1741
|
+
build2.onLoad({ filter: /^next-image-shim$/, namespace: "next-shim" }, () => ({
|
|
1742
|
+
contents: `
|
|
1743
|
+
import { createElement } from 'react';
|
|
1744
|
+
export default function Image({ src, alt, width, height, style, className, ...rest }) {
|
|
1745
|
+
return createElement('img', { src, alt, width, height, style, className, ...rest });
|
|
1746
|
+
}
|
|
1747
|
+
`.trim(),
|
|
1748
|
+
loader: "js"
|
|
1749
|
+
}));
|
|
1750
|
+
build2.onResolve({ filter: /^next\/link$/ }, () => ({
|
|
1751
|
+
path: "next-link-shim",
|
|
1752
|
+
namespace: "next-shim"
|
|
1753
|
+
}));
|
|
1754
|
+
build2.onLoad({ filter: /^next-link-shim$/, namespace: "next-shim" }, () => ({
|
|
1755
|
+
contents: `
|
|
1756
|
+
import { createElement } from 'react';
|
|
1757
|
+
export default function Link({ href, children, className, style, ...rest }) {
|
|
1758
|
+
return createElement('a', { href, className, style, ...rest }, children);
|
|
1759
|
+
}
|
|
1760
|
+
`.trim(),
|
|
1761
|
+
loader: "js"
|
|
1762
|
+
}));
|
|
1763
|
+
build2.onResolve({ filter: /^next\// }, () => ({
|
|
1764
|
+
path: "next-noop-shim",
|
|
1765
|
+
namespace: "next-shim"
|
|
1766
|
+
}));
|
|
1767
|
+
build2.onLoad({ filter: /^next-noop-shim$/, namespace: "next-shim" }, () => ({
|
|
1768
|
+
contents: `export default {};
|
|
1769
|
+
`,
|
|
1770
|
+
loader: "js"
|
|
1771
|
+
}));
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1393
1774
|
}
|
|
1394
1775
|
});
|
|
1395
1776
|
|
|
@@ -1400,7 +1781,7 @@ __export(dev_server_exports, {
|
|
|
1400
1781
|
});
|
|
1401
1782
|
function createDevServer(options) {
|
|
1402
1783
|
const clients = /* @__PURE__ */ new Set();
|
|
1403
|
-
const themeDataPath =
|
|
1784
|
+
const themeDataPath = path13__default.default.join(options.distDir, "theme-data.json");
|
|
1404
1785
|
const server = http__default.default.createServer((req, res) => {
|
|
1405
1786
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1406
1787
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -1426,8 +1807,8 @@ function createDevServer(options) {
|
|
|
1426
1807
|
if (pathname.startsWith("/_assets/")) {
|
|
1427
1808
|
const parts = pathname.replace(/^\/_assets\//, "").split("/");
|
|
1428
1809
|
const assetSubpath = parts.slice(1).join("/");
|
|
1429
|
-
const assetPath =
|
|
1430
|
-
if (!assetPath.startsWith(
|
|
1810
|
+
const assetPath = path13__default.default.join(options.themePath, "assets", assetSubpath);
|
|
1811
|
+
if (!assetPath.startsWith(path13__default.default.join(options.themePath, "assets"))) {
|
|
1431
1812
|
res.writeHead(403);
|
|
1432
1813
|
res.end("Forbidden");
|
|
1433
1814
|
return;
|
|
@@ -1438,8 +1819,8 @@ function createDevServer(options) {
|
|
|
1438
1819
|
if (pathname.startsWith("/themes/")) {
|
|
1439
1820
|
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
1440
1821
|
if (match) {
|
|
1441
|
-
const assetPath =
|
|
1442
|
-
if (!assetPath.startsWith(
|
|
1822
|
+
const assetPath = path13__default.default.join(options.themePath, "assets", match[1]);
|
|
1823
|
+
if (!assetPath.startsWith(path13__default.default.join(options.themePath, "assets"))) {
|
|
1443
1824
|
res.writeHead(403);
|
|
1444
1825
|
res.end("Forbidden");
|
|
1445
1826
|
return;
|
|
@@ -1451,26 +1832,26 @@ function createDevServer(options) {
|
|
|
1451
1832
|
if (pathname.startsWith("/assets/")) {
|
|
1452
1833
|
const subpath = pathname.replace(/^\/assets\//, "");
|
|
1453
1834
|
const segments = subpath.split("/");
|
|
1454
|
-
const assetsBase =
|
|
1835
|
+
const assetsBase = path13__default.default.join(options.themePath, "assets");
|
|
1455
1836
|
let assetPath;
|
|
1456
1837
|
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
1457
|
-
assetPath =
|
|
1838
|
+
assetPath = path13__default.default.join(assetsBase, segments.slice(1).join("/"));
|
|
1458
1839
|
} else {
|
|
1459
|
-
assetPath =
|
|
1840
|
+
assetPath = path13__default.default.join(assetsBase, subpath);
|
|
1460
1841
|
}
|
|
1461
1842
|
if (assetPath.startsWith(assetsBase) && fs3__default.default.existsSync(assetPath)) {
|
|
1462
1843
|
serveFile(res, assetPath);
|
|
1463
1844
|
return;
|
|
1464
1845
|
}
|
|
1465
1846
|
if (segments.length > 1) {
|
|
1466
|
-
const fallbackPath =
|
|
1847
|
+
const fallbackPath = path13__default.default.join(assetsBase, segments.slice(1).join("/"));
|
|
1467
1848
|
if (fallbackPath.startsWith(assetsBase) && fs3__default.default.existsSync(fallbackPath)) {
|
|
1468
1849
|
serveFile(res, fallbackPath);
|
|
1469
1850
|
return;
|
|
1470
1851
|
}
|
|
1471
1852
|
}
|
|
1472
1853
|
}
|
|
1473
|
-
const filePath =
|
|
1854
|
+
const filePath = path13__default.default.join(options.distDir, pathname);
|
|
1474
1855
|
if (!filePath.startsWith(options.distDir)) {
|
|
1475
1856
|
res.writeHead(403);
|
|
1476
1857
|
res.end("Forbidden");
|
|
@@ -1513,7 +1894,7 @@ function serveFile(res, filePath) {
|
|
|
1513
1894
|
res.end("Not Found");
|
|
1514
1895
|
return;
|
|
1515
1896
|
}
|
|
1516
|
-
const ext =
|
|
1897
|
+
const ext = path13__default.default.extname(filePath);
|
|
1517
1898
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1518
1899
|
const content = fs3__default.default.readFileSync(filePath);
|
|
1519
1900
|
res.writeHead(200, { "Content-Type": contentType });
|
|
@@ -1630,26 +2011,26 @@ var init_dev_server = __esm({
|
|
|
1630
2011
|
// src/utils/file-helpers.ts
|
|
1631
2012
|
init_logger();
|
|
1632
2013
|
async function renderTemplate(templatePath, data) {
|
|
1633
|
-
const template = await
|
|
2014
|
+
const template = await fs8__default.default.readFile(templatePath, "utf-8");
|
|
1634
2015
|
return ejs__default.default.render(template, data);
|
|
1635
2016
|
}
|
|
1636
2017
|
async function writeFile(filePath, content) {
|
|
1637
|
-
await
|
|
1638
|
-
await
|
|
2018
|
+
await fs8__default.default.ensureDir(path13__default.default.dirname(filePath));
|
|
2019
|
+
await fs8__default.default.writeFile(filePath, content, "utf-8");
|
|
1639
2020
|
}
|
|
1640
2021
|
function getTemplatesDir() {
|
|
1641
2022
|
const locations = [
|
|
1642
|
-
|
|
2023
|
+
path13__default.default.join(__dirname, "../../templates"),
|
|
1643
2024
|
// Development
|
|
1644
|
-
|
|
2025
|
+
path13__default.default.join(__dirname, "../templates"),
|
|
1645
2026
|
// Production (dist/)
|
|
1646
|
-
|
|
2027
|
+
path13__default.default.join(process.cwd(), "templates"),
|
|
1647
2028
|
// Fallback
|
|
1648
|
-
|
|
2029
|
+
path13__default.default.join(process.cwd(), "packages/cli/templates")
|
|
1649
2030
|
// Monorepo
|
|
1650
2031
|
];
|
|
1651
2032
|
for (const location of locations) {
|
|
1652
|
-
if (
|
|
2033
|
+
if (fs8__default.default.existsSync(location)) {
|
|
1653
2034
|
return location;
|
|
1654
2035
|
}
|
|
1655
2036
|
}
|
|
@@ -1657,18 +2038,18 @@ function getTemplatesDir() {
|
|
|
1657
2038
|
}
|
|
1658
2039
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1659
2040
|
const templatesDir = getTemplatesDir();
|
|
1660
|
-
const templateDir =
|
|
1661
|
-
if (!
|
|
2041
|
+
const templateDir = path13__default.default.join(templatesDir, templateName);
|
|
2042
|
+
if (!fs8__default.default.existsSync(templateDir)) {
|
|
1662
2043
|
throw new Error(
|
|
1663
|
-
`Template "${templateName}" not found at ${templateDir}. Available templates: ${
|
|
2044
|
+
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs8__default.default.readdirSync(templatesDir).join(", ")}`
|
|
1664
2045
|
);
|
|
1665
2046
|
}
|
|
1666
|
-
await
|
|
1667
|
-
const files = await
|
|
2047
|
+
await fs8__default.default.ensureDir(targetDir);
|
|
2048
|
+
const files = await fs8__default.default.readdir(templateDir);
|
|
1668
2049
|
for (const file of files) {
|
|
1669
|
-
const templatePath =
|
|
1670
|
-
const targetPath =
|
|
1671
|
-
const stat = await
|
|
2050
|
+
const templatePath = path13__default.default.join(templateDir, file);
|
|
2051
|
+
const targetPath = path13__default.default.join(targetDir, file);
|
|
2052
|
+
const stat = await fs8__default.default.stat(templatePath);
|
|
1672
2053
|
if (stat.isDirectory()) {
|
|
1673
2054
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
1674
2055
|
} else if (file.endsWith(".ejs")) {
|
|
@@ -1676,17 +2057,17 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1676
2057
|
const outputPath = targetPath.replace(/\.ejs$/, "");
|
|
1677
2058
|
await writeFile(outputPath, content);
|
|
1678
2059
|
} else {
|
|
1679
|
-
await
|
|
2060
|
+
await fs8__default.default.copy(templatePath, targetPath);
|
|
1680
2061
|
}
|
|
1681
2062
|
}
|
|
1682
2063
|
}
|
|
1683
2064
|
async function copyTemplateDir(templateDir, targetDir, data) {
|
|
1684
|
-
await
|
|
1685
|
-
const files = await
|
|
2065
|
+
await fs8__default.default.ensureDir(targetDir);
|
|
2066
|
+
const files = await fs8__default.default.readdir(templateDir);
|
|
1686
2067
|
for (const file of files) {
|
|
1687
|
-
const templatePath =
|
|
1688
|
-
const targetPath =
|
|
1689
|
-
const stat = await
|
|
2068
|
+
const templatePath = path13__default.default.join(templateDir, file);
|
|
2069
|
+
const targetPath = path13__default.default.join(targetDir, file);
|
|
2070
|
+
const stat = await fs8__default.default.stat(templatePath);
|
|
1690
2071
|
if (stat.isDirectory()) {
|
|
1691
2072
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
1692
2073
|
} else if (file.endsWith(".ejs")) {
|
|
@@ -1694,38 +2075,38 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1694
2075
|
const outputPath = targetPath.replace(/\.ejs$/, "");
|
|
1695
2076
|
await writeFile(outputPath, content);
|
|
1696
2077
|
} else {
|
|
1697
|
-
await
|
|
2078
|
+
await fs8__default.default.copy(templatePath, targetPath);
|
|
1698
2079
|
}
|
|
1699
2080
|
}
|
|
1700
2081
|
}
|
|
1701
2082
|
function getProjectRoot() {
|
|
1702
2083
|
let currentDir = process.cwd();
|
|
1703
|
-
while (currentDir !==
|
|
1704
|
-
const packageJsonPath =
|
|
1705
|
-
if (
|
|
1706
|
-
const packageJson =
|
|
1707
|
-
if (packageJson.workspaces ||
|
|
2084
|
+
while (currentDir !== path13__default.default.parse(currentDir).root) {
|
|
2085
|
+
const packageJsonPath = path13__default.default.join(currentDir, "package.json");
|
|
2086
|
+
if (fs8__default.default.existsSync(packageJsonPath)) {
|
|
2087
|
+
const packageJson = fs8__default.default.readJsonSync(packageJsonPath);
|
|
2088
|
+
if (packageJson.workspaces || fs8__default.default.existsSync(path13__default.default.join(currentDir, "src/themes")) || fs8__default.default.existsSync(path13__default.default.join(currentDir, "themes"))) {
|
|
1708
2089
|
return currentDir;
|
|
1709
2090
|
}
|
|
1710
2091
|
}
|
|
1711
|
-
currentDir =
|
|
2092
|
+
currentDir = path13__default.default.dirname(currentDir);
|
|
1712
2093
|
}
|
|
1713
2094
|
return process.cwd();
|
|
1714
2095
|
}
|
|
1715
2096
|
function getThemesDir() {
|
|
1716
2097
|
const root = getProjectRoot();
|
|
1717
|
-
if (
|
|
1718
|
-
return
|
|
1719
|
-
if (
|
|
1720
|
-
return
|
|
1721
|
-
return
|
|
2098
|
+
if (fs8__default.default.existsSync(path13__default.default.join(root, "themes")))
|
|
2099
|
+
return path13__default.default.join(root, "themes");
|
|
2100
|
+
if (fs8__default.default.existsSync(path13__default.default.join(root, "src/themes")))
|
|
2101
|
+
return path13__default.default.join(root, "src/themes");
|
|
2102
|
+
return path13__default.default.dirname(root);
|
|
1722
2103
|
}
|
|
1723
2104
|
function getFeaturesDir() {
|
|
1724
|
-
return
|
|
2105
|
+
return path13__default.default.join(getProjectRoot(), "src/features");
|
|
1725
2106
|
}
|
|
1726
2107
|
function isOneXProject() {
|
|
1727
2108
|
const root = getProjectRoot();
|
|
1728
|
-
return
|
|
2109
|
+
return fs8__default.default.existsSync(path13__default.default.join(root, "themes")) || fs8__default.default.existsSync(path13__default.default.join(root, "src/themes")) || fs8__default.default.existsSync(path13__default.default.join(root, "theme.config.ts")) || fs8__default.default.existsSync(path13__default.default.join(root, "bundle-entry.ts"));
|
|
1729
2110
|
}
|
|
1730
2111
|
function ensureOneXProject() {
|
|
1731
2112
|
if (!isOneXProject()) {
|
|
@@ -1737,17 +2118,17 @@ function ensureOneXProject() {
|
|
|
1737
2118
|
}
|
|
1738
2119
|
function listThemes() {
|
|
1739
2120
|
const themesDir = getThemesDir();
|
|
1740
|
-
if (!
|
|
2121
|
+
if (!fs8__default.default.existsSync(themesDir)) {
|
|
1741
2122
|
return [];
|
|
1742
2123
|
}
|
|
1743
|
-
return
|
|
1744
|
-
const themePath =
|
|
1745
|
-
return
|
|
2124
|
+
return fs8__default.default.readdirSync(themesDir).filter((name) => {
|
|
2125
|
+
const themePath = path13__default.default.join(themesDir, name);
|
|
2126
|
+
return fs8__default.default.statSync(themePath).isDirectory() && (fs8__default.default.existsSync(path13__default.default.join(themePath, "theme.config.ts")) || fs8__default.default.existsSync(path13__default.default.join(themePath, "bundle-entry.ts")) || fs8__default.default.existsSync(path13__default.default.join(themePath, "manifest.ts")));
|
|
1746
2127
|
});
|
|
1747
2128
|
}
|
|
1748
2129
|
function themeExists(themeName) {
|
|
1749
|
-
const themePath =
|
|
1750
|
-
return
|
|
2130
|
+
const themePath = path13__default.default.join(getThemesDir(), themeName);
|
|
2131
|
+
return fs8__default.default.existsSync(themePath) && (fs8__default.default.existsSync(path13__default.default.join(themePath, "theme.config.ts")) || fs8__default.default.existsSync(path13__default.default.join(themePath, "bundle-entry.ts")) || fs8__default.default.existsSync(path13__default.default.join(themePath, "manifest.ts")));
|
|
1751
2132
|
}
|
|
1752
2133
|
function detectPackageManager() {
|
|
1753
2134
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1755,9 +2136,9 @@ function detectPackageManager() {
|
|
|
1755
2136
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1756
2137
|
if (userAgent.includes("bun")) return "bun";
|
|
1757
2138
|
const cwd = process.cwd();
|
|
1758
|
-
if (
|
|
1759
|
-
if (
|
|
1760
|
-
if (
|
|
2139
|
+
if (fs8__default.default.existsSync(path13__default.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
2140
|
+
if (fs8__default.default.existsSync(path13__default.default.join(cwd, "yarn.lock"))) return "yarn";
|
|
2141
|
+
if (fs8__default.default.existsSync(path13__default.default.join(cwd, "bun.lockb"))) return "bun";
|
|
1761
2142
|
return "npm";
|
|
1762
2143
|
}
|
|
1763
2144
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1806,22 +2187,23 @@ function getValidCategories() {
|
|
|
1806
2187
|
"contact"
|
|
1807
2188
|
];
|
|
1808
2189
|
}
|
|
1809
|
-
var AUTH_DIR =
|
|
2190
|
+
var AUTH_DIR = path13__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
1810
2191
|
var ENV_URLS = {
|
|
1811
2192
|
dev: "https://platform-dev.onexeos.com",
|
|
1812
|
-
|
|
2193
|
+
staging: "https://platform-staging.onexeos.com",
|
|
2194
|
+
prod: "https://platform-apis.onexeos.com"
|
|
1813
2195
|
};
|
|
1814
2196
|
function getAuthFile(env = "dev") {
|
|
1815
|
-
const newFile =
|
|
2197
|
+
const newFile = path13__default.default.join(AUTH_DIR, `auth-${env}.json`);
|
|
1816
2198
|
if (env === "dev") {
|
|
1817
|
-
const legacyFile =
|
|
1818
|
-
if (
|
|
2199
|
+
const legacyFile = path13__default.default.join(AUTH_DIR, "auth.json");
|
|
2200
|
+
if (fs8__default.default.existsSync(legacyFile) && !fs8__default.default.existsSync(newFile)) {
|
|
1819
2201
|
try {
|
|
1820
|
-
|
|
2202
|
+
fs8__default.default.moveSync(legacyFile, newFile);
|
|
1821
2203
|
} catch {
|
|
1822
2204
|
try {
|
|
1823
|
-
|
|
1824
|
-
|
|
2205
|
+
fs8__default.default.copySync(legacyFile, newFile);
|
|
2206
|
+
fs8__default.default.removeSync(legacyFile);
|
|
1825
2207
|
} catch {
|
|
1826
2208
|
}
|
|
1827
2209
|
}
|
|
@@ -1833,17 +2215,17 @@ function getApiUrl(env = "dev") {
|
|
|
1833
2215
|
return process.env.ONEXTHM_API_URL || ENV_URLS[env];
|
|
1834
2216
|
}
|
|
1835
2217
|
async function saveAuthTokens(tokens, env = "dev") {
|
|
1836
|
-
await
|
|
2218
|
+
await fs8__default.default.ensureDir(AUTH_DIR);
|
|
1837
2219
|
const key = getMachineKey();
|
|
1838
2220
|
const data = JSON.stringify(tokens);
|
|
1839
2221
|
const encrypted = encrypt(data, key);
|
|
1840
|
-
await
|
|
2222
|
+
await fs8__default.default.writeFile(getAuthFile(env), encrypted, "utf-8");
|
|
1841
2223
|
}
|
|
1842
2224
|
function loadAuthTokens(env = "dev") {
|
|
1843
2225
|
try {
|
|
1844
2226
|
const file = getAuthFile(env);
|
|
1845
|
-
if (!
|
|
1846
|
-
const encrypted =
|
|
2227
|
+
if (!fs8__default.default.existsSync(file)) return null;
|
|
2228
|
+
const encrypted = fs8__default.default.readFileSync(file, "utf-8");
|
|
1847
2229
|
const key = getMachineKey();
|
|
1848
2230
|
const data = decrypt(encrypted, key);
|
|
1849
2231
|
return JSON.parse(data);
|
|
@@ -1853,7 +2235,7 @@ function loadAuthTokens(env = "dev") {
|
|
|
1853
2235
|
}
|
|
1854
2236
|
async function clearAuthTokens(env = "dev") {
|
|
1855
2237
|
try {
|
|
1856
|
-
await
|
|
2238
|
+
await fs8__default.default.remove(getAuthFile(env));
|
|
1857
2239
|
} catch {
|
|
1858
2240
|
}
|
|
1859
2241
|
}
|
|
@@ -1912,7 +2294,7 @@ function getMachineKey() {
|
|
|
1912
2294
|
seed = `onexthm:${os__default.default.hostname()}:${os__default.default.userInfo().username}`;
|
|
1913
2295
|
} else if (process.platform === "linux") {
|
|
1914
2296
|
try {
|
|
1915
|
-
seed = `onexthm:${
|
|
2297
|
+
seed = `onexthm:${fs8__default.default.readFileSync("/etc/machine-id", "utf-8").trim()}`;
|
|
1916
2298
|
} catch {
|
|
1917
2299
|
seed = `onexthm:${os__default.default.hostname()}:${os__default.default.userInfo().username}`;
|
|
1918
2300
|
}
|
|
@@ -1950,7 +2332,7 @@ function parseJwtClaims(idToken) {
|
|
|
1950
2332
|
}
|
|
1951
2333
|
|
|
1952
2334
|
// src/commands/init.ts
|
|
1953
|
-
async function initCommand(projectName, options
|
|
2335
|
+
async function initCommand(projectName, options) {
|
|
1954
2336
|
logger.header("Create New OneX Theme Project");
|
|
1955
2337
|
let name;
|
|
1956
2338
|
if (!projectName) {
|
|
@@ -1965,7 +2347,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1965
2347
|
if (!validateThemeName(kebabName)) {
|
|
1966
2348
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1967
2349
|
}
|
|
1968
|
-
if (fs3__default.default.existsSync(
|
|
2350
|
+
if (fs3__default.default.existsSync(path13__default.default.join(process.cwd(), kebabName))) {
|
|
1969
2351
|
return `Directory "${kebabName}" already exists`;
|
|
1970
2352
|
}
|
|
1971
2353
|
return true;
|
|
@@ -1976,14 +2358,14 @@ async function initCommand(projectName, options = {}) {
|
|
|
1976
2358
|
} else {
|
|
1977
2359
|
name = toKebabCase(projectName);
|
|
1978
2360
|
}
|
|
1979
|
-
const projectPath =
|
|
2361
|
+
const projectPath = path13__default.default.join(process.cwd(), name);
|
|
1980
2362
|
if (fs3__default.default.existsSync(projectPath)) {
|
|
1981
2363
|
logger.error(`Directory "${name}" already exists.`);
|
|
1982
2364
|
process.exit(1);
|
|
1983
2365
|
}
|
|
1984
2366
|
if (!options.yes) {
|
|
1985
2367
|
try {
|
|
1986
|
-
const apiUrl = getApiUrl(options.env
|
|
2368
|
+
const apiUrl = getApiUrl(options.env);
|
|
1987
2369
|
const controller = new AbortController();
|
|
1988
2370
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1989
2371
|
const response = await fetch(
|
|
@@ -2092,7 +2474,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2092
2474
|
description,
|
|
2093
2475
|
author
|
|
2094
2476
|
);
|
|
2095
|
-
const mcpJsonPath =
|
|
2477
|
+
const mcpJsonPath = path13__default.default.join(projectPath, ".mcp.json");
|
|
2096
2478
|
if (fs3__default.default.existsSync(mcpJsonPath)) {
|
|
2097
2479
|
let mcpContent = fs3__default.default.readFileSync(mcpJsonPath, "utf-8");
|
|
2098
2480
|
if (figmaApiKey) {
|
|
@@ -2172,7 +2554,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2172
2554
|
}
|
|
2173
2555
|
}
|
|
2174
2556
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
2175
|
-
const configPath =
|
|
2557
|
+
const configPath = path13__default.default.join(projectPath, "theme.config.ts");
|
|
2176
2558
|
if (fs3__default.default.existsSync(configPath)) {
|
|
2177
2559
|
let content = fs3__default.default.readFileSync(configPath, "utf-8");
|
|
2178
2560
|
content = content.replace(
|
|
@@ -2185,7 +2567,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
2185
2567
|
);
|
|
2186
2568
|
fs3__default.default.writeFileSync(configPath, content, "utf-8");
|
|
2187
2569
|
}
|
|
2188
|
-
const pkgPath =
|
|
2570
|
+
const pkgPath = path13__default.default.join(projectPath, "package.json");
|
|
2189
2571
|
if (fs3__default.default.existsSync(pkgPath)) {
|
|
2190
2572
|
let content = fs3__default.default.readFileSync(pkgPath, "utf-8");
|
|
2191
2573
|
content = content.replace(
|
|
@@ -2207,10 +2589,10 @@ async function createSectionCommand(name, options) {
|
|
|
2207
2589
|
ensureOneXProject();
|
|
2208
2590
|
if (!options.theme) {
|
|
2209
2591
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2210
|
-
(f) =>
|
|
2592
|
+
(f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f))
|
|
2211
2593
|
);
|
|
2212
2594
|
if (isStandaloneTheme) {
|
|
2213
|
-
options.theme =
|
|
2595
|
+
options.theme = path13__default.default.basename(process.cwd());
|
|
2214
2596
|
}
|
|
2215
2597
|
}
|
|
2216
2598
|
const sectionName = toKebabCase(name);
|
|
@@ -2273,35 +2655,35 @@ async function createSectionCommand(name, options) {
|
|
|
2273
2655
|
};
|
|
2274
2656
|
logger.startSpinner("Creating section files...");
|
|
2275
2657
|
try {
|
|
2276
|
-
const themePath =
|
|
2277
|
-
const sectionPath =
|
|
2658
|
+
const themePath = path13__default.default.join(getThemesDir(), themeName);
|
|
2659
|
+
const sectionPath = path13__default.default.join(themePath, "sections", sectionName);
|
|
2278
2660
|
const schemaContent = generateSectionSchema(data);
|
|
2279
2661
|
await writeFile(
|
|
2280
|
-
|
|
2662
|
+
path13__default.default.join(sectionPath, `${sectionName}.schema.ts`),
|
|
2281
2663
|
schemaContent
|
|
2282
2664
|
);
|
|
2283
2665
|
if (createTemplate) {
|
|
2284
2666
|
const templateContent = generateSectionTemplate(data);
|
|
2285
2667
|
await writeFile(
|
|
2286
|
-
|
|
2668
|
+
path13__default.default.join(sectionPath, `${sectionName}-default.tsx`),
|
|
2287
2669
|
templateContent
|
|
2288
2670
|
);
|
|
2289
2671
|
}
|
|
2290
2672
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
2291
|
-
await writeFile(
|
|
2673
|
+
await writeFile(path13__default.default.join(sectionPath, "index.ts"), indexContent);
|
|
2292
2674
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
2293
2675
|
logger.newLine();
|
|
2294
2676
|
logger.section("Next steps:");
|
|
2295
2677
|
logger.log(
|
|
2296
|
-
` 1. Edit schema: ${
|
|
2678
|
+
` 1. Edit schema: ${path13__default.default.relative(process.cwd(), path13__default.default.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
2297
2679
|
);
|
|
2298
2680
|
if (createTemplate) {
|
|
2299
2681
|
logger.log(
|
|
2300
|
-
` 2. Edit template: ${
|
|
2682
|
+
` 2. Edit template: ${path13__default.default.relative(process.cwd(), path13__default.default.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
2301
2683
|
);
|
|
2302
2684
|
}
|
|
2303
2685
|
logger.log(
|
|
2304
|
-
` 3. Add to theme manifest: ${
|
|
2686
|
+
` 3. Add to theme manifest: ${path13__default.default.relative(process.cwd(), path13__default.default.join(themePath, "manifest.ts"))}`
|
|
2305
2687
|
);
|
|
2306
2688
|
logger.newLine();
|
|
2307
2689
|
logger.success("Section created successfully!");
|
|
@@ -2449,10 +2831,10 @@ async function createBlockCommand(name, options) {
|
|
|
2449
2831
|
ensureOneXProject();
|
|
2450
2832
|
if (!options.theme) {
|
|
2451
2833
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2452
|
-
(f) =>
|
|
2834
|
+
(f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f))
|
|
2453
2835
|
);
|
|
2454
2836
|
if (isStandaloneTheme) {
|
|
2455
|
-
options.theme =
|
|
2837
|
+
options.theme = path13__default.default.basename(process.cwd());
|
|
2456
2838
|
}
|
|
2457
2839
|
}
|
|
2458
2840
|
const blockName = toKebabCase(name);
|
|
@@ -2527,24 +2909,24 @@ async function createBlockCommand(name, options) {
|
|
|
2527
2909
|
};
|
|
2528
2910
|
logger.startSpinner("Creating block files...");
|
|
2529
2911
|
try {
|
|
2530
|
-
const blockPath = scope === "shared" ?
|
|
2912
|
+
const blockPath = scope === "shared" ? path13__default.default.join(getFeaturesDir(), "blocks", blockName) : path13__default.default.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2531
2913
|
const schemaContent = generateBlockSchema(data);
|
|
2532
2914
|
await writeFile(
|
|
2533
|
-
|
|
2915
|
+
path13__default.default.join(blockPath, `${blockName}.schema.ts`),
|
|
2534
2916
|
schemaContent
|
|
2535
2917
|
);
|
|
2536
2918
|
const componentContent = generateBlockComponent(data);
|
|
2537
|
-
await writeFile(
|
|
2919
|
+
await writeFile(path13__default.default.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2538
2920
|
const indexContent = generateBlockIndex(data);
|
|
2539
|
-
await writeFile(
|
|
2921
|
+
await writeFile(path13__default.default.join(blockPath, "index.ts"), indexContent);
|
|
2540
2922
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2541
2923
|
logger.newLine();
|
|
2542
2924
|
logger.section("Next steps:");
|
|
2543
2925
|
logger.log(
|
|
2544
|
-
` 1. Edit schema: ${
|
|
2926
|
+
` 1. Edit schema: ${path13__default.default.relative(process.cwd(), path13__default.default.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2545
2927
|
);
|
|
2546
2928
|
logger.log(
|
|
2547
|
-
` 2. Edit component: ${
|
|
2929
|
+
` 2. Edit component: ${path13__default.default.relative(process.cwd(), path13__default.default.join(blockPath, `${blockName}.tsx`))}`
|
|
2548
2930
|
);
|
|
2549
2931
|
logger.log(
|
|
2550
2932
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2722,31 +3104,31 @@ async function createComponentCommand(name, options) {
|
|
|
2722
3104
|
};
|
|
2723
3105
|
logger.startSpinner("Creating component files...");
|
|
2724
3106
|
try {
|
|
2725
|
-
const componentPath =
|
|
3107
|
+
const componentPath = path13__default.default.join(
|
|
2726
3108
|
getFeaturesDir(),
|
|
2727
3109
|
"components",
|
|
2728
3110
|
componentName
|
|
2729
3111
|
);
|
|
2730
3112
|
const schemaContent = generateComponentSchema(data);
|
|
2731
3113
|
await writeFile(
|
|
2732
|
-
|
|
3114
|
+
path13__default.default.join(componentPath, `${componentName}.schema.ts`),
|
|
2733
3115
|
schemaContent
|
|
2734
3116
|
);
|
|
2735
3117
|
const componentContent = generateComponent(data);
|
|
2736
3118
|
await writeFile(
|
|
2737
|
-
|
|
3119
|
+
path13__default.default.join(componentPath, `${componentName}.tsx`),
|
|
2738
3120
|
componentContent
|
|
2739
3121
|
);
|
|
2740
3122
|
const indexContent = generateComponentIndex(data);
|
|
2741
|
-
await writeFile(
|
|
3123
|
+
await writeFile(path13__default.default.join(componentPath, "index.ts"), indexContent);
|
|
2742
3124
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2743
3125
|
logger.newLine();
|
|
2744
3126
|
logger.section("Next steps:");
|
|
2745
3127
|
logger.log(
|
|
2746
|
-
` 1. Edit schema: ${
|
|
3128
|
+
` 1. Edit schema: ${path13__default.default.relative(process.cwd(), path13__default.default.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2747
3129
|
);
|
|
2748
3130
|
logger.log(
|
|
2749
|
-
` 2. Edit component: ${
|
|
3131
|
+
` 2. Edit component: ${path13__default.default.relative(process.cwd(), path13__default.default.join(componentPath, `${componentName}.tsx`))}`
|
|
2750
3132
|
);
|
|
2751
3133
|
logger.log(
|
|
2752
3134
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2903,13 +3285,13 @@ async function listSections(themeFilter) {
|
|
|
2903
3285
|
return;
|
|
2904
3286
|
}
|
|
2905
3287
|
for (const theme of themes) {
|
|
2906
|
-
const sectionsDir =
|
|
2907
|
-
if (!
|
|
3288
|
+
const sectionsDir = path13__default.default.join(getThemesDir(), theme, "sections");
|
|
3289
|
+
if (!fs8__default.default.existsSync(sectionsDir)) {
|
|
2908
3290
|
continue;
|
|
2909
3291
|
}
|
|
2910
|
-
const sections =
|
|
2911
|
-
const sectionPath =
|
|
2912
|
-
return
|
|
3292
|
+
const sections = fs8__default.default.readdirSync(sectionsDir).filter((name) => {
|
|
3293
|
+
const sectionPath = path13__default.default.join(sectionsDir, name);
|
|
3294
|
+
return fs8__default.default.statSync(sectionPath).isDirectory() && fs8__default.default.existsSync(path13__default.default.join(sectionPath, "index.ts"));
|
|
2913
3295
|
});
|
|
2914
3296
|
if (sections.length > 0) {
|
|
2915
3297
|
logger.log(chalk4__default.default.cyan(`
|
|
@@ -2923,11 +3305,11 @@ async function listSections(themeFilter) {
|
|
|
2923
3305
|
}
|
|
2924
3306
|
async function listBlocks(themeFilter) {
|
|
2925
3307
|
logger.section("\u{1F9F1} Blocks");
|
|
2926
|
-
const sharedBlocksDir =
|
|
2927
|
-
if (
|
|
2928
|
-
const sharedBlocks =
|
|
2929
|
-
const blockPath =
|
|
2930
|
-
return
|
|
3308
|
+
const sharedBlocksDir = path13__default.default.join(getFeaturesDir(), "blocks");
|
|
3309
|
+
if (fs8__default.default.existsSync(sharedBlocksDir)) {
|
|
3310
|
+
const sharedBlocks = fs8__default.default.readdirSync(sharedBlocksDir).filter((name) => {
|
|
3311
|
+
const blockPath = path13__default.default.join(sharedBlocksDir, name);
|
|
3312
|
+
return fs8__default.default.statSync(blockPath).isDirectory() && fs8__default.default.existsSync(path13__default.default.join(blockPath, "index.ts"));
|
|
2931
3313
|
});
|
|
2932
3314
|
if (sharedBlocks.length > 0) {
|
|
2933
3315
|
logger.log(chalk4__default.default.cyan("\n Shared:"));
|
|
@@ -2938,13 +3320,13 @@ async function listBlocks(themeFilter) {
|
|
|
2938
3320
|
}
|
|
2939
3321
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2940
3322
|
for (const theme of themes) {
|
|
2941
|
-
const blocksDir =
|
|
2942
|
-
if (!
|
|
3323
|
+
const blocksDir = path13__default.default.join(getThemesDir(), theme, "blocks");
|
|
3324
|
+
if (!fs8__default.default.existsSync(blocksDir)) {
|
|
2943
3325
|
continue;
|
|
2944
3326
|
}
|
|
2945
|
-
const blocks =
|
|
2946
|
-
const blockPath =
|
|
2947
|
-
return
|
|
3327
|
+
const blocks = fs8__default.default.readdirSync(blocksDir).filter((name) => {
|
|
3328
|
+
const blockPath = path13__default.default.join(blocksDir, name);
|
|
3329
|
+
return fs8__default.default.statSync(blockPath).isDirectory() && fs8__default.default.existsSync(path13__default.default.join(blockPath, "index.ts"));
|
|
2948
3330
|
});
|
|
2949
3331
|
if (blocks.length > 0) {
|
|
2950
3332
|
logger.log(chalk4__default.default.cyan(`
|
|
@@ -2958,14 +3340,14 @@ async function listBlocks(themeFilter) {
|
|
|
2958
3340
|
}
|
|
2959
3341
|
async function listComponents() {
|
|
2960
3342
|
logger.section("\u2699\uFE0F Components");
|
|
2961
|
-
const componentsDir =
|
|
2962
|
-
if (!
|
|
3343
|
+
const componentsDir = path13__default.default.join(getFeaturesDir(), "components");
|
|
3344
|
+
if (!fs8__default.default.existsSync(componentsDir)) {
|
|
2963
3345
|
logger.warning("No components directory found");
|
|
2964
3346
|
return;
|
|
2965
3347
|
}
|
|
2966
|
-
const components =
|
|
2967
|
-
const componentPath =
|
|
2968
|
-
return
|
|
3348
|
+
const components = fs8__default.default.readdirSync(componentsDir).filter((name) => {
|
|
3349
|
+
const componentPath = path13__default.default.join(componentsDir, name);
|
|
3350
|
+
return fs8__default.default.statSync(componentPath).isDirectory() && fs8__default.default.existsSync(path13__default.default.join(componentPath, "index.ts"));
|
|
2969
3351
|
});
|
|
2970
3352
|
if (components.length === 0) {
|
|
2971
3353
|
logger.warning("No components found");
|
|
@@ -2986,13 +3368,13 @@ async function listThemesInfo() {
|
|
|
2986
3368
|
}
|
|
2987
3369
|
logger.log("");
|
|
2988
3370
|
for (const theme of themes) {
|
|
2989
|
-
const themeDir =
|
|
3371
|
+
const themeDir = path13__default.default.join(getThemesDir(), theme);
|
|
2990
3372
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2991
3373
|
let manifestContent = "";
|
|
2992
3374
|
for (const candidate of candidates) {
|
|
2993
|
-
const candidatePath =
|
|
2994
|
-
if (
|
|
2995
|
-
manifestContent =
|
|
3375
|
+
const candidatePath = path13__default.default.join(themeDir, candidate);
|
|
3376
|
+
if (fs8__default.default.existsSync(candidatePath)) {
|
|
3377
|
+
manifestContent = fs8__default.default.readFileSync(candidatePath, "utf-8");
|
|
2996
3378
|
break;
|
|
2997
3379
|
}
|
|
2998
3380
|
}
|
|
@@ -3012,6 +3394,7 @@ async function listThemesInfo() {
|
|
|
3012
3394
|
|
|
3013
3395
|
// src/commands/validate.ts
|
|
3014
3396
|
init_logger();
|
|
3397
|
+
init_detect_nextjs();
|
|
3015
3398
|
async function validateCommand(options) {
|
|
3016
3399
|
logger.header("Validate Theme");
|
|
3017
3400
|
ensureOneXProject();
|
|
@@ -3027,10 +3410,13 @@ async function validateCommand(options) {
|
|
|
3027
3410
|
const isThemeDir2 = [
|
|
3028
3411
|
"theme.config.ts",
|
|
3029
3412
|
"bundle-entry.ts",
|
|
3030
|
-
"manifest.ts"
|
|
3031
|
-
|
|
3413
|
+
"manifest.ts",
|
|
3414
|
+
"next.config.ts",
|
|
3415
|
+
"next.config.js",
|
|
3416
|
+
"next.config.mjs"
|
|
3417
|
+
].some((f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f)));
|
|
3032
3418
|
if (isThemeDir2) {
|
|
3033
|
-
themeToValidate =
|
|
3419
|
+
themeToValidate = path13__default.default.basename(process.cwd());
|
|
3034
3420
|
logger.info(`Validating current theme: ${themeToValidate}`);
|
|
3035
3421
|
} else {
|
|
3036
3422
|
logger.error(
|
|
@@ -3039,11 +3425,11 @@ async function validateCommand(options) {
|
|
|
3039
3425
|
process.exit(1);
|
|
3040
3426
|
}
|
|
3041
3427
|
}
|
|
3042
|
-
const themePath =
|
|
3428
|
+
const themePath = path13__default.default.join(getThemesDir(), themeToValidate);
|
|
3043
3429
|
logger.startSpinner("Running validation checks...");
|
|
3044
3430
|
const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
|
|
3045
3431
|
const foundEntry = entryFiles.find(
|
|
3046
|
-
(f) =>
|
|
3432
|
+
(f) => fs8__default.default.existsSync(path13__default.default.join(themePath, f))
|
|
3047
3433
|
);
|
|
3048
3434
|
if (!foundEntry) {
|
|
3049
3435
|
issues.push({
|
|
@@ -3052,8 +3438,8 @@ async function validateCommand(options) {
|
|
|
3052
3438
|
message: "No theme entry file found (need at least one of: manifest.ts, theme.config.ts, bundle-entry.ts)"
|
|
3053
3439
|
});
|
|
3054
3440
|
} else if (foundEntry === "manifest.ts") {
|
|
3055
|
-
const manifestContent =
|
|
3056
|
-
|
|
3441
|
+
const manifestContent = fs8__default.default.readFileSync(
|
|
3442
|
+
path13__default.default.join(themePath, foundEntry),
|
|
3057
3443
|
"utf-8"
|
|
3058
3444
|
);
|
|
3059
3445
|
if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
|
|
@@ -3064,56 +3450,56 @@ async function validateCommand(options) {
|
|
|
3064
3450
|
});
|
|
3065
3451
|
}
|
|
3066
3452
|
}
|
|
3067
|
-
const configPath =
|
|
3068
|
-
if (!
|
|
3453
|
+
const configPath = path13__default.default.join(themePath, "theme.config.ts");
|
|
3454
|
+
if (!fs8__default.default.existsSync(configPath)) {
|
|
3069
3455
|
issues.push({
|
|
3070
3456
|
type: "warning",
|
|
3071
3457
|
file: "theme.config.ts",
|
|
3072
3458
|
message: "Theme config file not found (recommended)"
|
|
3073
3459
|
});
|
|
3074
3460
|
}
|
|
3075
|
-
const indexPath =
|
|
3076
|
-
if (!
|
|
3461
|
+
const indexPath = path13__default.default.join(themePath, "index.ts");
|
|
3462
|
+
if (!fs8__default.default.existsSync(indexPath)) {
|
|
3077
3463
|
issues.push({
|
|
3078
3464
|
type: "warning",
|
|
3079
3465
|
file: "index.ts",
|
|
3080
3466
|
message: "Index file not found (recommended)"
|
|
3081
3467
|
});
|
|
3082
3468
|
}
|
|
3083
|
-
const sectionsDir =
|
|
3084
|
-
if (!
|
|
3469
|
+
const sectionsDir = path13__default.default.join(themePath, "sections");
|
|
3470
|
+
if (!fs8__default.default.existsSync(sectionsDir)) {
|
|
3085
3471
|
issues.push({
|
|
3086
3472
|
type: "warning",
|
|
3087
3473
|
file: "sections/",
|
|
3088
3474
|
message: "Sections directory not found"
|
|
3089
3475
|
});
|
|
3090
3476
|
} else {
|
|
3091
|
-
const sections =
|
|
3092
|
-
(name) =>
|
|
3477
|
+
const sections = fs8__default.default.readdirSync(sectionsDir).filter(
|
|
3478
|
+
(name) => fs8__default.default.statSync(path13__default.default.join(sectionsDir, name)).isDirectory()
|
|
3093
3479
|
);
|
|
3094
3480
|
for (const sectionName of sections) {
|
|
3095
|
-
const sectionPath =
|
|
3096
|
-
const schemaFile =
|
|
3097
|
-
const defaultTemplate =
|
|
3481
|
+
const sectionPath = path13__default.default.join(sectionsDir, sectionName);
|
|
3482
|
+
const schemaFile = path13__default.default.join(sectionPath, `${sectionName}.schema.ts`);
|
|
3483
|
+
const defaultTemplate = path13__default.default.join(
|
|
3098
3484
|
sectionPath,
|
|
3099
3485
|
`${sectionName}-default.tsx`
|
|
3100
3486
|
);
|
|
3101
|
-
const indexFile =
|
|
3102
|
-
if (!
|
|
3487
|
+
const indexFile = path13__default.default.join(sectionPath, "index.ts");
|
|
3488
|
+
if (!fs8__default.default.existsSync(schemaFile)) {
|
|
3103
3489
|
issues.push({
|
|
3104
3490
|
type: "error",
|
|
3105
3491
|
file: `sections/${sectionName}/${sectionName}.schema.ts`,
|
|
3106
3492
|
message: "Section schema file missing"
|
|
3107
3493
|
});
|
|
3108
3494
|
}
|
|
3109
|
-
if (!
|
|
3495
|
+
if (!fs8__default.default.existsSync(indexFile)) {
|
|
3110
3496
|
issues.push({
|
|
3111
3497
|
type: "error",
|
|
3112
3498
|
file: `sections/${sectionName}/index.ts`,
|
|
3113
3499
|
message: "Section index file missing"
|
|
3114
3500
|
});
|
|
3115
3501
|
}
|
|
3116
|
-
if (!
|
|
3502
|
+
if (!fs8__default.default.existsSync(defaultTemplate)) {
|
|
3117
3503
|
issues.push({
|
|
3118
3504
|
type: "warning",
|
|
3119
3505
|
file: `sections/${sectionName}/${sectionName}-default.tsx`,
|
|
@@ -3122,29 +3508,29 @@ async function validateCommand(options) {
|
|
|
3122
3508
|
}
|
|
3123
3509
|
}
|
|
3124
3510
|
}
|
|
3125
|
-
const blocksDir =
|
|
3126
|
-
if (
|
|
3127
|
-
const blocks =
|
|
3511
|
+
const blocksDir = path13__default.default.join(themePath, "blocks");
|
|
3512
|
+
if (fs8__default.default.existsSync(blocksDir)) {
|
|
3513
|
+
const blocks = fs8__default.default.readdirSync(blocksDir).filter((name) => fs8__default.default.statSync(path13__default.default.join(blocksDir, name)).isDirectory());
|
|
3128
3514
|
for (const blockName of blocks) {
|
|
3129
|
-
const blockPath =
|
|
3130
|
-
const schemaFile =
|
|
3131
|
-
const componentFile =
|
|
3132
|
-
const indexFile =
|
|
3133
|
-
if (!
|
|
3515
|
+
const blockPath = path13__default.default.join(blocksDir, blockName);
|
|
3516
|
+
const schemaFile = path13__default.default.join(blockPath, `${blockName}.schema.ts`);
|
|
3517
|
+
const componentFile = path13__default.default.join(blockPath, `${blockName}.tsx`);
|
|
3518
|
+
const indexFile = path13__default.default.join(blockPath, "index.ts");
|
|
3519
|
+
if (!fs8__default.default.existsSync(schemaFile)) {
|
|
3134
3520
|
issues.push({
|
|
3135
3521
|
type: "error",
|
|
3136
3522
|
file: `blocks/${blockName}/${blockName}.schema.ts`,
|
|
3137
3523
|
message: "Block schema file missing"
|
|
3138
3524
|
});
|
|
3139
3525
|
}
|
|
3140
|
-
if (!
|
|
3526
|
+
if (!fs8__default.default.existsSync(componentFile)) {
|
|
3141
3527
|
issues.push({
|
|
3142
3528
|
type: "error",
|
|
3143
3529
|
file: `blocks/${blockName}/${blockName}.tsx`,
|
|
3144
3530
|
message: "Block component file missing"
|
|
3145
3531
|
});
|
|
3146
3532
|
}
|
|
3147
|
-
if (!
|
|
3533
|
+
if (!fs8__default.default.existsSync(indexFile)) {
|
|
3148
3534
|
issues.push({
|
|
3149
3535
|
type: "error",
|
|
3150
3536
|
file: `blocks/${blockName}/index.ts`,
|
|
@@ -3153,16 +3539,16 @@ async function validateCommand(options) {
|
|
|
3153
3539
|
}
|
|
3154
3540
|
}
|
|
3155
3541
|
}
|
|
3156
|
-
if (
|
|
3157
|
-
const sections =
|
|
3158
|
-
(name) =>
|
|
3542
|
+
if (fs8__default.default.existsSync(sectionsDir)) {
|
|
3543
|
+
const sections = fs8__default.default.readdirSync(sectionsDir).filter(
|
|
3544
|
+
(name) => fs8__default.default.statSync(path13__default.default.join(sectionsDir, name)).isDirectory()
|
|
3159
3545
|
);
|
|
3160
3546
|
for (const sectionName of sections) {
|
|
3161
|
-
const sectionPath =
|
|
3162
|
-
const tsxFiles =
|
|
3547
|
+
const sectionPath = path13__default.default.join(sectionsDir, sectionName);
|
|
3548
|
+
const tsxFiles = fs8__default.default.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
|
|
3163
3549
|
for (const tsxFile of tsxFiles) {
|
|
3164
|
-
const filePath =
|
|
3165
|
-
const content =
|
|
3550
|
+
const filePath = path13__default.default.join(sectionPath, tsxFile);
|
|
3551
|
+
const content = fs8__default.default.readFileSync(filePath, "utf-8");
|
|
3166
3552
|
const relPath = `sections/${sectionName}/${tsxFile}`;
|
|
3167
3553
|
if (!content.includes('"use client"') && !content.includes("'use client'")) {
|
|
3168
3554
|
issues.push({
|
|
@@ -3209,12 +3595,12 @@ async function validateCommand(options) {
|
|
|
3209
3595
|
}
|
|
3210
3596
|
}
|
|
3211
3597
|
}
|
|
3212
|
-
const registryPath =
|
|
3213
|
-
const bundleEntryPath =
|
|
3214
|
-
const registryContent =
|
|
3215
|
-
if (
|
|
3216
|
-
const sections =
|
|
3217
|
-
(name) =>
|
|
3598
|
+
const registryPath = path13__default.default.join(themePath, "sections-registry.ts");
|
|
3599
|
+
const bundleEntryPath = path13__default.default.join(themePath, "bundle-entry.ts");
|
|
3600
|
+
const registryContent = fs8__default.default.existsSync(registryPath) ? fs8__default.default.readFileSync(registryPath, "utf-8") : fs8__default.default.existsSync(bundleEntryPath) ? fs8__default.default.readFileSync(bundleEntryPath, "utf-8") : "";
|
|
3601
|
+
if (fs8__default.default.existsSync(sectionsDir) && registryContent) {
|
|
3602
|
+
const sections = fs8__default.default.readdirSync(sectionsDir).filter(
|
|
3603
|
+
(name) => fs8__default.default.statSync(path13__default.default.join(sectionsDir, name)).isDirectory()
|
|
3218
3604
|
);
|
|
3219
3605
|
for (const sectionName of sections) {
|
|
3220
3606
|
if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
|
|
@@ -3226,7 +3612,7 @@ async function validateCommand(options) {
|
|
|
3226
3612
|
}
|
|
3227
3613
|
}
|
|
3228
3614
|
}
|
|
3229
|
-
if (
|
|
3615
|
+
if (fs8__default.default.existsSync(sectionsDir)) {
|
|
3230
3616
|
const schemaTypes = await loadSchemaTypes(themePath, sectionsDir);
|
|
3231
3617
|
for (const { folderName, schemaType } of schemaTypes) {
|
|
3232
3618
|
if (schemaType && schemaType !== folderName) {
|
|
@@ -3237,8 +3623,8 @@ async function validateCommand(options) {
|
|
|
3237
3623
|
});
|
|
3238
3624
|
}
|
|
3239
3625
|
}
|
|
3240
|
-
const pagesDir =
|
|
3241
|
-
if (
|
|
3626
|
+
const pagesDir = path13__default.default.join(themePath, "pages");
|
|
3627
|
+
if (fs8__default.default.existsSync(pagesDir)) {
|
|
3242
3628
|
const allSchemaTypeSet = new Set(
|
|
3243
3629
|
schemaTypes.map((s) => s.schemaType || s.folderName)
|
|
3244
3630
|
);
|
|
@@ -3249,6 +3635,10 @@ async function validateCommand(options) {
|
|
|
3249
3635
|
issues.push(...pageIssues);
|
|
3250
3636
|
}
|
|
3251
3637
|
}
|
|
3638
|
+
if (isNextjsProject(themePath)) {
|
|
3639
|
+
const nextjsIssues = await validateNextjsComponents(themePath);
|
|
3640
|
+
issues.push(...nextjsIssues);
|
|
3641
|
+
}
|
|
3252
3642
|
logger.stopSpinner(true, "Validation complete");
|
|
3253
3643
|
const errors = issues.filter((i) => i.type === "error");
|
|
3254
3644
|
const warnings = issues.filter((i) => i.type === "warning");
|
|
@@ -3289,18 +3679,18 @@ async function validateCommand(options) {
|
|
|
3289
3679
|
}
|
|
3290
3680
|
async function loadSchemaTypes(themePath, sectionsDir) {
|
|
3291
3681
|
const results = [];
|
|
3292
|
-
const sections =
|
|
3682
|
+
const sections = fs8__default.default.readdirSync(sectionsDir).filter((name) => fs8__default.default.statSync(path13__default.default.join(sectionsDir, name)).isDirectory());
|
|
3293
3683
|
for (const sectionName of sections) {
|
|
3294
|
-
const schemaFile =
|
|
3684
|
+
const schemaFile = path13__default.default.join(
|
|
3295
3685
|
sectionsDir,
|
|
3296
3686
|
sectionName,
|
|
3297
3687
|
`${sectionName}.schema.ts`
|
|
3298
3688
|
);
|
|
3299
|
-
if (!
|
|
3689
|
+
if (!fs8__default.default.existsSync(schemaFile)) {
|
|
3300
3690
|
results.push({ folderName: sectionName, schemaType: null });
|
|
3301
3691
|
continue;
|
|
3302
3692
|
}
|
|
3303
|
-
const content =
|
|
3693
|
+
const content = fs8__default.default.readFileSync(schemaFile, "utf-8");
|
|
3304
3694
|
let schemaType = null;
|
|
3305
3695
|
const schemaExportMatch = content.match(
|
|
3306
3696
|
/:\s*SectionSchema\s*=\s*\{[\s\S]*?\btype:\s*["']([^"']+)["']/
|
|
@@ -3327,9 +3717,9 @@ async function loadSchemaTypes(themePath, sectionsDir) {
|
|
|
3327
3717
|
}
|
|
3328
3718
|
async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
3329
3719
|
const issues = [];
|
|
3330
|
-
const files =
|
|
3720
|
+
const files = fs8__default.default.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
|
|
3331
3721
|
for (const file of files) {
|
|
3332
|
-
const content =
|
|
3722
|
+
const content = fs8__default.default.readFileSync(path13__default.default.join(pagesDir, file), "utf-8");
|
|
3333
3723
|
const pageName = file.replace(/\.(ts|js)$/, "");
|
|
3334
3724
|
const sectionsMatch = content.match(/\bsections:\s*\[/);
|
|
3335
3725
|
if (!sectionsMatch || sectionsMatch.index === void 0) continue;
|
|
@@ -3342,9 +3732,13 @@ async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
|
3342
3732
|
endIdx = i;
|
|
3343
3733
|
}
|
|
3344
3734
|
const sectionsBlock = content.slice(startIdx, endIdx);
|
|
3345
|
-
const
|
|
3346
|
-
|
|
3735
|
+
const sectionTypeMatches = sectionsBlock.matchAll(
|
|
3736
|
+
/\bid:\s*["'][^"']*["'],\s*\n?\s*type:\s*["']([^"']+)["']/g
|
|
3737
|
+
);
|
|
3738
|
+
for (const match of sectionTypeMatches) {
|
|
3347
3739
|
const sectionType = match[1];
|
|
3740
|
+
if (COMPONENT_TYPES.has(sectionType)) continue;
|
|
3741
|
+
if (BLOCK_TYPES.has(sectionType)) continue;
|
|
3348
3742
|
if (!validTypes.has(sectionType)) {
|
|
3349
3743
|
issues.push({
|
|
3350
3744
|
type: "error",
|
|
@@ -3397,9 +3791,128 @@ var FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
3397
3791
|
"inline_richtext",
|
|
3398
3792
|
"repeater"
|
|
3399
3793
|
]);
|
|
3794
|
+
var COMPONENT_TYPES = /* @__PURE__ */ new Set([
|
|
3795
|
+
"heading",
|
|
3796
|
+
"paragraph",
|
|
3797
|
+
"button",
|
|
3798
|
+
"image",
|
|
3799
|
+
"link",
|
|
3800
|
+
"icon",
|
|
3801
|
+
"badge",
|
|
3802
|
+
"divider",
|
|
3803
|
+
"spacer",
|
|
3804
|
+
"container",
|
|
3805
|
+
"grid",
|
|
3806
|
+
"columns",
|
|
3807
|
+
"card",
|
|
3808
|
+
"quote",
|
|
3809
|
+
"input",
|
|
3810
|
+
"textarea",
|
|
3811
|
+
"checkbox",
|
|
3812
|
+
"select",
|
|
3813
|
+
"video",
|
|
3814
|
+
"gallery",
|
|
3815
|
+
"alert",
|
|
3816
|
+
"progress",
|
|
3817
|
+
"rating",
|
|
3818
|
+
"timer",
|
|
3819
|
+
"list",
|
|
3820
|
+
"table",
|
|
3821
|
+
"accordion",
|
|
3822
|
+
"tabs",
|
|
3823
|
+
"code",
|
|
3824
|
+
"map",
|
|
3825
|
+
"product-card",
|
|
3826
|
+
"blog-card",
|
|
3827
|
+
"social-links",
|
|
3828
|
+
"hotline-contacts",
|
|
3829
|
+
"company-info",
|
|
3830
|
+
"torn-separator"
|
|
3831
|
+
]);
|
|
3832
|
+
var BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
3833
|
+
"brand-feature",
|
|
3834
|
+
"collection-item",
|
|
3835
|
+
"crafting-step",
|
|
3836
|
+
"testimonial-item",
|
|
3837
|
+
"stat-item",
|
|
3838
|
+
"footer-link",
|
|
3839
|
+
"navigation-links-block",
|
|
3840
|
+
"policy-section",
|
|
3841
|
+
"core-value-card",
|
|
3842
|
+
"faq-item",
|
|
3843
|
+
"feature-item",
|
|
3844
|
+
"gallery-item",
|
|
3845
|
+
"logo-item",
|
|
3846
|
+
"pricing-tier",
|
|
3847
|
+
"service-item",
|
|
3848
|
+
"stat-card",
|
|
3849
|
+
"team-member",
|
|
3850
|
+
"hero-content"
|
|
3851
|
+
]);
|
|
3852
|
+
var SERVER_ONLY_APIS = [
|
|
3853
|
+
"next/headers",
|
|
3854
|
+
"next/server",
|
|
3855
|
+
"next/cache",
|
|
3856
|
+
"cookies()",
|
|
3857
|
+
"headers()",
|
|
3858
|
+
"draftMode()"
|
|
3859
|
+
];
|
|
3860
|
+
async function validateNextjsComponents(themePath) {
|
|
3861
|
+
const issues = [];
|
|
3862
|
+
const { glob: glob6 } = await import('glob');
|
|
3863
|
+
const componentFiles = await glob6("components/**/*.{tsx,ts}", {
|
|
3864
|
+
cwd: themePath,
|
|
3865
|
+
ignore: ["**/node_modules/**"]
|
|
3866
|
+
});
|
|
3867
|
+
for (const relFile of componentFiles) {
|
|
3868
|
+
const absFile = path13__default.default.join(themePath, relFile);
|
|
3869
|
+
const content = fs8__default.default.readFileSync(absFile, "utf-8");
|
|
3870
|
+
const dir = path13__default.default.dirname(absFile);
|
|
3871
|
+
const hasSectionJson = fs8__default.default.existsSync(path13__default.default.join(dir, "section.json"));
|
|
3872
|
+
if (!hasSectionJson) continue;
|
|
3873
|
+
for (const api of SERVER_ONLY_APIS) {
|
|
3874
|
+
if (content.includes(`"${api}"`) || content.includes(`'${api}'`)) {
|
|
3875
|
+
issues.push({
|
|
3876
|
+
type: "error",
|
|
3877
|
+
file: relFile,
|
|
3878
|
+
message: `"${api}" is server-only and cannot be used in a OneX theme bundle. Remove this import or move data fetching to a client-side useEffect/useQuery.`
|
|
3879
|
+
});
|
|
3880
|
+
}
|
|
3881
|
+
if (content.includes(api.replace("()", "") + "(")) {
|
|
3882
|
+
issues.push({
|
|
3883
|
+
type: "error",
|
|
3884
|
+
file: relFile,
|
|
3885
|
+
message: `${api} is server-only and cannot be called in a browser bundle. Use useQuery or fetch() inside useEffect instead.`
|
|
3886
|
+
});
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
const isAsyncComponent = /export\s+default\s+async\s+function/.test(content) || /export\s+default\s+async\s+\(/.test(content);
|
|
3890
|
+
if (isAsyncComponent) {
|
|
3891
|
+
const hasUseClient2 = content.includes('"use client"') || content.includes("'use client'");
|
|
3892
|
+
if (!hasUseClient2) {
|
|
3893
|
+
issues.push({
|
|
3894
|
+
type: "error",
|
|
3895
|
+
file: relFile,
|
|
3896
|
+
message: 'Async Server Components cannot be compiled to a browser bundle. Add "use client" at the top and convert data fetching to useQuery or useEffect.'
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
const usesHooks = /\buse[A-Z]\w+\s*\(/.test(content);
|
|
3901
|
+
const hasUseClient = content.includes('"use client"') || content.includes("'use client'");
|
|
3902
|
+
if (usesHooks && !hasUseClient) {
|
|
3903
|
+
issues.push({
|
|
3904
|
+
type: "warning",
|
|
3905
|
+
file: relFile,
|
|
3906
|
+
message: 'Component uses React hooks but is missing "use client" directive. Add "use client" at the top of the file.'
|
|
3907
|
+
});
|
|
3908
|
+
}
|
|
3909
|
+
}
|
|
3910
|
+
return issues;
|
|
3911
|
+
}
|
|
3400
3912
|
|
|
3401
3913
|
// src/commands/build.ts
|
|
3402
3914
|
init_logger();
|
|
3915
|
+
init_detect_nextjs();
|
|
3403
3916
|
async function buildCommand(options) {
|
|
3404
3917
|
logger.header("Build Theme");
|
|
3405
3918
|
let themePath;
|
|
@@ -3407,16 +3920,16 @@ async function buildCommand(options) {
|
|
|
3407
3920
|
if (options.theme) {
|
|
3408
3921
|
themeName = options.theme;
|
|
3409
3922
|
try {
|
|
3410
|
-
const workspaceThemePath =
|
|
3411
|
-
if (
|
|
3923
|
+
const workspaceThemePath = path13__default.default.join(getThemesDir(), themeName);
|
|
3924
|
+
if (fs8__default.default.existsSync(workspaceThemePath)) {
|
|
3412
3925
|
themePath = workspaceThemePath;
|
|
3413
3926
|
} else {
|
|
3414
|
-
themePath =
|
|
3927
|
+
themePath = path13__default.default.join(process.cwd(), themeName);
|
|
3415
3928
|
}
|
|
3416
3929
|
} catch {
|
|
3417
|
-
themePath =
|
|
3930
|
+
themePath = path13__default.default.join(process.cwd(), themeName);
|
|
3418
3931
|
}
|
|
3419
|
-
if (!
|
|
3932
|
+
if (!fs8__default.default.existsSync(themePath)) {
|
|
3420
3933
|
logger.error(`Theme "${themeName}" not found.`);
|
|
3421
3934
|
process.exit(1);
|
|
3422
3935
|
}
|
|
@@ -3424,11 +3937,14 @@ async function buildCommand(options) {
|
|
|
3424
3937
|
const isThemeDir2 = [
|
|
3425
3938
|
"theme.config.ts",
|
|
3426
3939
|
"bundle-entry.ts",
|
|
3427
|
-
"manifest.ts"
|
|
3428
|
-
|
|
3940
|
+
"manifest.ts",
|
|
3941
|
+
"next.config.ts",
|
|
3942
|
+
"next.config.js",
|
|
3943
|
+
"next.config.mjs"
|
|
3944
|
+
].some((f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f)));
|
|
3429
3945
|
if (isThemeDir2) {
|
|
3430
3946
|
themePath = process.cwd();
|
|
3431
|
-
themeName =
|
|
3947
|
+
themeName = path13__default.default.basename(themePath);
|
|
3432
3948
|
logger.info(`Building current theme: ${themeName}`);
|
|
3433
3949
|
} else {
|
|
3434
3950
|
logger.error(
|
|
@@ -3437,8 +3953,8 @@ async function buildCommand(options) {
|
|
|
3437
3953
|
process.exit(1);
|
|
3438
3954
|
}
|
|
3439
3955
|
}
|
|
3440
|
-
const packageJsonPath =
|
|
3441
|
-
const hasPkgJson =
|
|
3956
|
+
const packageJsonPath = path13__default.default.join(themePath, "package.json");
|
|
3957
|
+
const hasPkgJson = fs8__default.default.existsSync(packageJsonPath);
|
|
3442
3958
|
if (!hasPkgJson) {
|
|
3443
3959
|
logger.warning(
|
|
3444
3960
|
"No package.json found in theme. Skipping build (themes in monorepo are built via turbo)."
|
|
@@ -3453,30 +3969,42 @@ async function buildCommand(options) {
|
|
|
3453
3969
|
}
|
|
3454
3970
|
logger.newLine();
|
|
3455
3971
|
logger.section("Build Steps");
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
logger.
|
|
3468
|
-
|
|
3469
|
-
|
|
3972
|
+
const pkgJson = fs8__default.default.readJsonSync(packageJsonPath);
|
|
3973
|
+
if (pkgJson.scripts?.["type-check"]) {
|
|
3974
|
+
logger.startSpinner("Running type check...");
|
|
3975
|
+
const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
|
|
3976
|
+
if (!typeCheckSuccess) {
|
|
3977
|
+
logger.stopSpinner(false, "Type check failed");
|
|
3978
|
+
logger.error("Fix type errors before building.");
|
|
3979
|
+
process.exit(1);
|
|
3980
|
+
}
|
|
3981
|
+
logger.stopSpinner(true, "Type check passed");
|
|
3982
|
+
} else {
|
|
3983
|
+
logger.info("Skipping type check (no type-check script in package.json)");
|
|
3984
|
+
}
|
|
3985
|
+
const isNextjsForLint = isNextjsProject(themePath);
|
|
3986
|
+
if (!isNextjsForLint && pkgJson.scripts?.lint) {
|
|
3987
|
+
logger.startSpinner("Running linter...");
|
|
3988
|
+
const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
|
|
3989
|
+
if (!lintSuccess) {
|
|
3990
|
+
logger.stopSpinner(false, "Lint failed");
|
|
3991
|
+
logger.error("Fix lint errors before building.");
|
|
3992
|
+
process.exit(1);
|
|
3993
|
+
}
|
|
3994
|
+
logger.stopSpinner(true, "Lint passed");
|
|
3995
|
+
} else if (isNextjsForLint) {
|
|
3996
|
+
logger.info("Skipping lint (Next.js project compiled via esbuild)");
|
|
3997
|
+
} else {
|
|
3998
|
+
logger.info("Skipping lint (no lint script in package.json)");
|
|
3470
3999
|
}
|
|
3471
|
-
logger.stopSpinner(true, "Lint passed");
|
|
3472
|
-
const pkgJson = fs__default.default.readJsonSync(packageJsonPath);
|
|
3473
4000
|
const buildScript = pkgJson.scripts?.build || "";
|
|
3474
4001
|
const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex build") || buildScript.includes("onex-cli build");
|
|
4002
|
+
const isNextjs = isNextjsProject(themePath);
|
|
3475
4003
|
logger.startSpinner(
|
|
3476
4004
|
options.watch ? "Building (watch mode)..." : "Building..."
|
|
3477
4005
|
);
|
|
3478
4006
|
let buildSuccess;
|
|
3479
|
-
if (isRecursive) {
|
|
4007
|
+
if (isRecursive || isNextjs) {
|
|
3480
4008
|
const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
3481
4009
|
buildSuccess = await compileStandaloneTheme2(themePath, themeName);
|
|
3482
4010
|
} else {
|
|
@@ -3493,10 +4021,10 @@ async function buildCommand(options) {
|
|
|
3493
4021
|
logger.success("\u2713 Theme built successfully!");
|
|
3494
4022
|
logger.newLine();
|
|
3495
4023
|
logger.info(`Theme: ${themeName}`);
|
|
3496
|
-
const distPath =
|
|
3497
|
-
if (
|
|
3498
|
-
logger.log(`Output: ${
|
|
3499
|
-
const files =
|
|
4024
|
+
const distPath = path13__default.default.join(themePath, "dist");
|
|
4025
|
+
if (fs8__default.default.existsSync(distPath)) {
|
|
4026
|
+
logger.log(`Output: ${path13__default.default.relative(process.cwd(), distPath)}`);
|
|
4027
|
+
const files = fs8__default.default.readdirSync(distPath);
|
|
3500
4028
|
logger.log(`Files: ${files.length}`);
|
|
3501
4029
|
}
|
|
3502
4030
|
}
|
|
@@ -3551,8 +4079,8 @@ async function packageCommand(options) {
|
|
|
3551
4079
|
let themeName;
|
|
3552
4080
|
if (options.theme) {
|
|
3553
4081
|
themeName = options.theme;
|
|
3554
|
-
themePath =
|
|
3555
|
-
if (!
|
|
4082
|
+
themePath = path13__default.default.join(getThemesDir(), themeName);
|
|
4083
|
+
if (!fs8__default.default.existsSync(themePath)) {
|
|
3556
4084
|
logger.error(`Theme "${themeName}" not found.`);
|
|
3557
4085
|
process.exit(1);
|
|
3558
4086
|
}
|
|
@@ -3560,11 +4088,14 @@ async function packageCommand(options) {
|
|
|
3560
4088
|
const isThemeDir2 = [
|
|
3561
4089
|
"theme.config.ts",
|
|
3562
4090
|
"bundle-entry.ts",
|
|
3563
|
-
"manifest.ts"
|
|
3564
|
-
|
|
4091
|
+
"manifest.ts",
|
|
4092
|
+
"next.config.ts",
|
|
4093
|
+
"next.config.js",
|
|
4094
|
+
"next.config.mjs"
|
|
4095
|
+
].some((f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f)));
|
|
3565
4096
|
if (isThemeDir2) {
|
|
3566
4097
|
themePath = process.cwd();
|
|
3567
|
-
themeName =
|
|
4098
|
+
themeName = path13__default.default.basename(themePath);
|
|
3568
4099
|
logger.info(`Packaging current theme: ${themeName}`);
|
|
3569
4100
|
} else {
|
|
3570
4101
|
logger.error(
|
|
@@ -3573,22 +4104,19 @@ async function packageCommand(options) {
|
|
|
3573
4104
|
process.exit(1);
|
|
3574
4105
|
}
|
|
3575
4106
|
}
|
|
3576
|
-
const packageJsonPath =
|
|
4107
|
+
const packageJsonPath = path13__default.default.join(themePath, "package.json");
|
|
3577
4108
|
let version2 = "1.0.0";
|
|
3578
|
-
if (
|
|
3579
|
-
const packageJson = await
|
|
4109
|
+
if (fs8__default.default.existsSync(packageJsonPath)) {
|
|
4110
|
+
const packageJson = await fs8__default.default.readJson(packageJsonPath);
|
|
3580
4111
|
version2 = packageJson.version || "1.0.0";
|
|
3581
4112
|
}
|
|
3582
4113
|
logger.newLine();
|
|
3583
4114
|
logger.info(`Theme: ${themeName}`);
|
|
3584
4115
|
logger.info(`Version: ${version2}`);
|
|
3585
4116
|
logger.newLine();
|
|
3586
|
-
const
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
themeName,
|
|
3590
|
-
"dist"
|
|
3591
|
-
);
|
|
4117
|
+
const standaloneDistPath = path13__default.default.join(themePath, "dist");
|
|
4118
|
+
const monorepoDistPath = path13__default.default.join(process.cwd(), "themes", themeName, "dist");
|
|
4119
|
+
const compiledThemePath = fs8__default.default.existsSync(standaloneDistPath) ? standaloneDistPath : monorepoDistPath;
|
|
3592
4120
|
if (!options.skipBuild) {
|
|
3593
4121
|
logger.section("Step 1: Compile Theme");
|
|
3594
4122
|
logger.startSpinner("Compiling theme with esbuild...");
|
|
@@ -3609,7 +4137,7 @@ async function packageCommand(options) {
|
|
|
3609
4137
|
} else {
|
|
3610
4138
|
logger.info("Skipping build (--skip-build flag)");
|
|
3611
4139
|
}
|
|
3612
|
-
if (!
|
|
4140
|
+
if (!fs8__default.default.existsSync(compiledThemePath)) {
|
|
3613
4141
|
logger.error(`Compiled theme not found at: ${compiledThemePath}`);
|
|
3614
4142
|
logger.info("Run without --skip-build to compile first.");
|
|
3615
4143
|
process.exit(1);
|
|
@@ -3617,25 +4145,25 @@ async function packageCommand(options) {
|
|
|
3617
4145
|
logger.newLine();
|
|
3618
4146
|
logger.section("Step 2: Create Package");
|
|
3619
4147
|
const packageName = options.name || `${themeName}-${version2}`;
|
|
3620
|
-
const outputDir = options.output ||
|
|
3621
|
-
const outputPath =
|
|
3622
|
-
await
|
|
4148
|
+
const outputDir = options.output || path13__default.default.join(process.cwd(), "dist");
|
|
4149
|
+
const outputPath = path13__default.default.join(outputDir, `${packageName}.zip`);
|
|
4150
|
+
await fs8__default.default.ensureDir(outputDir);
|
|
3623
4151
|
logger.startSpinner("Creating zip archive...");
|
|
3624
4152
|
try {
|
|
3625
4153
|
await createZipArchive(compiledThemePath, outputPath);
|
|
3626
4154
|
logger.stopSpinner(true, "Package created");
|
|
3627
|
-
const stats = await
|
|
4155
|
+
const stats = await fs8__default.default.stat(outputPath);
|
|
3628
4156
|
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
3629
4157
|
logger.newLine();
|
|
3630
4158
|
logger.success("\u2713 Theme packaged successfully!");
|
|
3631
4159
|
logger.newLine();
|
|
3632
4160
|
logger.info(`Package: ${packageName}.zip`);
|
|
3633
4161
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3634
|
-
logger.log(`Location: ${
|
|
4162
|
+
logger.log(`Location: ${path13__default.default.relative(process.cwd(), outputPath)}`);
|
|
3635
4163
|
logger.newLine();
|
|
3636
4164
|
logger.section("Next steps:");
|
|
3637
4165
|
logger.log(
|
|
3638
|
-
` onexthm deploy --package ${
|
|
4166
|
+
` onexthm deploy --package ${path13__default.default.relative(process.cwd(), outputPath)}`
|
|
3639
4167
|
);
|
|
3640
4168
|
} catch (error) {
|
|
3641
4169
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3669,7 +4197,7 @@ function runCommand2(command, args) {
|
|
|
3669
4197
|
}
|
|
3670
4198
|
async function createZipArchive(compiledThemePath, outputPath) {
|
|
3671
4199
|
return new Promise((resolve, reject) => {
|
|
3672
|
-
const output =
|
|
4200
|
+
const output = fs8__default.default.createWriteStream(outputPath);
|
|
3673
4201
|
const archive = archiver__default.default("zip", {
|
|
3674
4202
|
zlib: { level: 9 }
|
|
3675
4203
|
// Maximum compression
|
|
@@ -3693,14 +4221,14 @@ async function deployCommand(options) {
|
|
|
3693
4221
|
ensureOneXProject();
|
|
3694
4222
|
let packagePath;
|
|
3695
4223
|
if (options.package) {
|
|
3696
|
-
packagePath =
|
|
4224
|
+
packagePath = path13__default.default.resolve(options.package);
|
|
3697
4225
|
} else if (options.theme) {
|
|
3698
|
-
const distDir =
|
|
3699
|
-
if (!
|
|
4226
|
+
const distDir = path13__default.default.join(process.cwd(), "dist");
|
|
4227
|
+
if (!fs8__default.default.existsSync(distDir)) {
|
|
3700
4228
|
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3701
4229
|
process.exit(1);
|
|
3702
4230
|
}
|
|
3703
|
-
const files =
|
|
4231
|
+
const files = fs8__default.default.readdirSync(distDir);
|
|
3704
4232
|
const packageFiles = files.filter(
|
|
3705
4233
|
(f) => f.startsWith(options.theme) && f.endsWith(".zip")
|
|
3706
4234
|
);
|
|
@@ -3710,7 +4238,7 @@ async function deployCommand(options) {
|
|
|
3710
4238
|
process.exit(1);
|
|
3711
4239
|
}
|
|
3712
4240
|
packageFiles.sort().reverse();
|
|
3713
|
-
packagePath =
|
|
4241
|
+
packagePath = path13__default.default.join(distDir, packageFiles[0]);
|
|
3714
4242
|
} else {
|
|
3715
4243
|
logger.error("Either --package or --theme must be specified.");
|
|
3716
4244
|
logger.info("Examples:");
|
|
@@ -3718,17 +4246,17 @@ async function deployCommand(options) {
|
|
|
3718
4246
|
logger.log(" onexthm deploy --theme tinan");
|
|
3719
4247
|
process.exit(1);
|
|
3720
4248
|
}
|
|
3721
|
-
if (!
|
|
4249
|
+
if (!fs8__default.default.existsSync(packagePath)) {
|
|
3722
4250
|
logger.error(`Package not found: ${packagePath}`);
|
|
3723
4251
|
process.exit(1);
|
|
3724
4252
|
}
|
|
3725
|
-
const stats = await
|
|
4253
|
+
const stats = await fs8__default.default.stat(packagePath);
|
|
3726
4254
|
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
3727
|
-
const fileName =
|
|
4255
|
+
const fileName = path13__default.default.basename(packagePath);
|
|
3728
4256
|
logger.newLine();
|
|
3729
4257
|
logger.info(`Package: ${fileName}`);
|
|
3730
4258
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3731
|
-
logger.log(`Path: ${
|
|
4259
|
+
logger.log(`Path: ${path13__default.default.relative(process.cwd(), packagePath)}`);
|
|
3732
4260
|
logger.newLine();
|
|
3733
4261
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3734
4262
|
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
@@ -3738,7 +4266,7 @@ async function deployCommand(options) {
|
|
|
3738
4266
|
logger.startSpinner("Uploading theme package...");
|
|
3739
4267
|
try {
|
|
3740
4268
|
const formData = new FormData__default.default();
|
|
3741
|
-
formData.append("theme",
|
|
4269
|
+
formData.append("theme", fs8__default.default.createReadStream(packagePath), {
|
|
3742
4270
|
filename: fileName,
|
|
3743
4271
|
contentType: "application/zip"
|
|
3744
4272
|
});
|
|
@@ -3885,24 +4413,24 @@ async function downloadBundleZip(apiUrl, themeId, version2) {
|
|
|
3885
4413
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
3886
4414
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
3887
4415
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
3888
|
-
const hashedPath =
|
|
3889
|
-
const stablePath =
|
|
3890
|
-
if (await
|
|
3891
|
-
await
|
|
4416
|
+
const hashedPath = path13__default.default.join(outputDir, entryFile);
|
|
4417
|
+
const stablePath = path13__default.default.join(outputDir, "bundle-entry.js");
|
|
4418
|
+
if (await fs8__default.default.pathExists(hashedPath)) {
|
|
4419
|
+
await fs8__default.default.copy(hashedPath, stablePath);
|
|
3892
4420
|
const mapPath = hashedPath + ".map";
|
|
3893
|
-
if (await
|
|
3894
|
-
await
|
|
4421
|
+
if (await fs8__default.default.pathExists(mapPath)) {
|
|
4422
|
+
await fs8__default.default.copy(mapPath, stablePath + ".map");
|
|
3895
4423
|
}
|
|
3896
4424
|
}
|
|
3897
4425
|
}
|
|
3898
|
-
const sectionsRegistryPath =
|
|
4426
|
+
const sectionsRegistryPath = path13__default.default.join(outputDir, "sections-registry.js");
|
|
3899
4427
|
const content = `// Re-export all sections from bundle-entry
|
|
3900
4428
|
// This file exists to maintain compatibility with the import path
|
|
3901
4429
|
export * from './bundle-entry.js';
|
|
3902
4430
|
`;
|
|
3903
|
-
await
|
|
3904
|
-
const pkgJsonPath =
|
|
3905
|
-
await
|
|
4431
|
+
await fs8__default.default.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
4432
|
+
const pkgJsonPath = path13__default.default.join(outputDir, "package.json");
|
|
4433
|
+
await fs8__default.default.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
3906
4434
|
}
|
|
3907
4435
|
function showDownloadFailureHelp(themeId, apiUrl) {
|
|
3908
4436
|
console.log();
|
|
@@ -3942,7 +4470,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3942
4470
|
}
|
|
3943
4471
|
async function downloadCommand(options) {
|
|
3944
4472
|
logger.header("Download Theme");
|
|
3945
|
-
const env = options.env
|
|
4473
|
+
const env = options.env;
|
|
3946
4474
|
const apiUrl = getApiUrl(env);
|
|
3947
4475
|
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3948
4476
|
const spinner = ora__default.default("Initializing download...").start();
|
|
@@ -3994,14 +4522,14 @@ async function downloadCommand(options) {
|
|
|
3994
4522
|
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
3995
4523
|
spinner.succeed(`Downloaded bundle.zip (${sizeMB} MB)`);
|
|
3996
4524
|
spinner.start("Extracting bundle...");
|
|
3997
|
-
await
|
|
3998
|
-
await
|
|
4525
|
+
await fs8__default.default.remove(outputDir);
|
|
4526
|
+
await fs8__default.default.ensureDir(outputDir);
|
|
3999
4527
|
const zip = new AdmZip__default.default(zipBuffer);
|
|
4000
4528
|
zip.extractAllTo(outputDir, true);
|
|
4001
4529
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
4002
4530
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
4003
|
-
const manifestPath =
|
|
4004
|
-
const manifest = await
|
|
4531
|
+
const manifestPath = path13__default.default.join(outputDir, "manifest.json");
|
|
4532
|
+
const manifest = await fs8__default.default.readJson(manifestPath);
|
|
4005
4533
|
await createCompatibilityFiles(outputDir, manifest);
|
|
4006
4534
|
console.log();
|
|
4007
4535
|
logger.success(chalk4__default.default.green.bold("Theme downloaded successfully!"));
|
|
@@ -4121,9 +4649,9 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4121
4649
|
const oldPrefix = `${oldName}-`;
|
|
4122
4650
|
const newPrefix = `${newName}-`;
|
|
4123
4651
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4124
|
-
const pkgPath =
|
|
4125
|
-
if (await
|
|
4126
|
-
const pkg = await
|
|
4652
|
+
const pkgPath = path13__default.default.join(themeDir, "package.json");
|
|
4653
|
+
if (await fs8__default.default.pathExists(pkgPath)) {
|
|
4654
|
+
const pkg = await fs8__default.default.readJson(pkgPath);
|
|
4127
4655
|
pkg.name = `@onex-themes/${newName}`;
|
|
4128
4656
|
if (pkg.description) {
|
|
4129
4657
|
pkg.description = pkg.description.replace(
|
|
@@ -4135,33 +4663,33 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4135
4663
|
if (pkg.devDependencies?.["@onexapis/cli"]) {
|
|
4136
4664
|
delete pkg.devDependencies["@onexapis/cli"];
|
|
4137
4665
|
}
|
|
4138
|
-
await
|
|
4666
|
+
await fs8__default.default.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
4139
4667
|
}
|
|
4140
|
-
const configPath =
|
|
4141
|
-
if (await
|
|
4142
|
-
let content = await
|
|
4668
|
+
const configPath = path13__default.default.join(themeDir, "theme.config.ts");
|
|
4669
|
+
if (await fs8__default.default.pathExists(configPath)) {
|
|
4670
|
+
let content = await fs8__default.default.readFile(configPath, "utf-8");
|
|
4143
4671
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
4144
4672
|
content = content.replace(
|
|
4145
4673
|
/name:\s*"[^"]*Theme"/,
|
|
4146
4674
|
`name: "${newDisplayName} Theme"`
|
|
4147
4675
|
);
|
|
4148
|
-
await
|
|
4676
|
+
await fs8__default.default.writeFile(configPath, content);
|
|
4149
4677
|
}
|
|
4150
|
-
const layoutPath =
|
|
4151
|
-
if (await
|
|
4152
|
-
let content = await
|
|
4678
|
+
const layoutPath = path13__default.default.join(themeDir, "theme.layout.ts");
|
|
4679
|
+
if (await fs8__default.default.pathExists(layoutPath)) {
|
|
4680
|
+
let content = await fs8__default.default.readFile(layoutPath, "utf-8");
|
|
4153
4681
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
4154
4682
|
content = content.replace(
|
|
4155
4683
|
/name:\s*"[^"]*Theme"/,
|
|
4156
4684
|
`name: "${newDisplayName} Theme"`
|
|
4157
4685
|
);
|
|
4158
|
-
await
|
|
4686
|
+
await fs8__default.default.writeFile(layoutPath, content);
|
|
4159
4687
|
}
|
|
4160
4688
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4161
4689
|
const tsFiles = await glob.glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
4162
4690
|
for (const file of tsFiles) {
|
|
4163
|
-
const filePath =
|
|
4164
|
-
let content = await
|
|
4691
|
+
const filePath = path13__default.default.join(themeDir, file);
|
|
4692
|
+
let content = await fs8__default.default.readFile(filePath, "utf-8");
|
|
4165
4693
|
const original = content;
|
|
4166
4694
|
content = content.replace(
|
|
4167
4695
|
new RegExp(`"${oldPrefix}`, "g"),
|
|
@@ -4176,13 +4704,13 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4176
4704
|
`${newDisplayName} Theme`
|
|
4177
4705
|
);
|
|
4178
4706
|
if (content !== original) {
|
|
4179
|
-
await
|
|
4707
|
+
await fs8__default.default.writeFile(filePath, content);
|
|
4180
4708
|
}
|
|
4181
4709
|
}
|
|
4182
4710
|
}
|
|
4183
4711
|
async function cloneCommand(themeName, options) {
|
|
4184
4712
|
logger.header("Clone Theme Source");
|
|
4185
|
-
const env = options.env
|
|
4713
|
+
const env = options.env;
|
|
4186
4714
|
const apiUrl = getApiUrl(env);
|
|
4187
4715
|
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
4188
4716
|
if (options.bucket) {
|
|
@@ -4203,8 +4731,8 @@ async function cloneCommand(themeName, options) {
|
|
|
4203
4731
|
}
|
|
4204
4732
|
const spinner = ora__default.default("Initializing clone...").start();
|
|
4205
4733
|
try {
|
|
4206
|
-
const outputDir = options.output ||
|
|
4207
|
-
if (await
|
|
4734
|
+
const outputDir = options.output || path13__default.default.resolve(process.cwd(), newName);
|
|
4735
|
+
if (await fs8__default.default.pathExists(outputDir)) {
|
|
4208
4736
|
spinner.fail(chalk4__default.default.red(`Directory already exists: ${outputDir}`));
|
|
4209
4737
|
logger.info(
|
|
4210
4738
|
chalk4__default.default.gray(
|
|
@@ -4237,7 +4765,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4237
4765
|
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
4238
4766
|
spinner.succeed(`Downloaded source.zip (${sizeMB} MB)`);
|
|
4239
4767
|
spinner.start(`Extracting to ${outputDir}...`);
|
|
4240
|
-
await
|
|
4768
|
+
await fs8__default.default.ensureDir(outputDir);
|
|
4241
4769
|
const zip = new AdmZip__default.default(zipBuffer);
|
|
4242
4770
|
zip.extractAllTo(outputDir, true);
|
|
4243
4771
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
@@ -4249,9 +4777,9 @@ async function cloneCommand(themeName, options) {
|
|
|
4249
4777
|
spinner.succeed(
|
|
4250
4778
|
`Renamed theme: ${chalk4__default.default.gray(themeName)} \u2192 ${chalk4__default.default.cyan(newName)}`
|
|
4251
4779
|
);
|
|
4252
|
-
const envExamplePath =
|
|
4253
|
-
if (!await
|
|
4254
|
-
await
|
|
4780
|
+
const envExamplePath = path13__default.default.join(outputDir, ".env.example");
|
|
4781
|
+
if (!await fs8__default.default.pathExists(envExamplePath)) {
|
|
4782
|
+
await fs8__default.default.writeFile(
|
|
4255
4783
|
envExamplePath,
|
|
4256
4784
|
[
|
|
4257
4785
|
"# API Configuration (enables real data in preview)",
|
|
@@ -4262,8 +4790,8 @@ async function cloneCommand(themeName, options) {
|
|
|
4262
4790
|
].join("\n")
|
|
4263
4791
|
);
|
|
4264
4792
|
}
|
|
4265
|
-
const mcpJsonPath =
|
|
4266
|
-
if (await
|
|
4793
|
+
const mcpJsonPath = path13__default.default.join(outputDir, ".mcp.json");
|
|
4794
|
+
if (await fs8__default.default.pathExists(mcpJsonPath)) {
|
|
4267
4795
|
const { default: inquirerMod } = await import('inquirer');
|
|
4268
4796
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
4269
4797
|
{
|
|
@@ -4272,7 +4800,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4272
4800
|
message: "Figma API Key (optional, for Figma-to-code MCP \u2014 press Enter to skip):"
|
|
4273
4801
|
}
|
|
4274
4802
|
]);
|
|
4275
|
-
let mcpContent = await
|
|
4803
|
+
let mcpContent = await fs8__default.default.readFile(mcpJsonPath, "utf-8");
|
|
4276
4804
|
if (figmaApiKey) {
|
|
4277
4805
|
mcpContent = mcpContent.replace("__FIGMA_API_KEY__", figmaApiKey);
|
|
4278
4806
|
} else {
|
|
@@ -4283,11 +4811,11 @@ async function cloneCommand(themeName, options) {
|
|
|
4283
4811
|
} catch {
|
|
4284
4812
|
}
|
|
4285
4813
|
}
|
|
4286
|
-
await
|
|
4814
|
+
await fs8__default.default.writeFile(mcpJsonPath, mcpContent, "utf-8");
|
|
4287
4815
|
}
|
|
4288
4816
|
if (options.install !== false) {
|
|
4289
|
-
const hasPkgJson = await
|
|
4290
|
-
|
|
4817
|
+
const hasPkgJson = await fs8__default.default.pathExists(
|
|
4818
|
+
path13__default.default.join(outputDir, "package.json")
|
|
4291
4819
|
);
|
|
4292
4820
|
if (hasPkgJson) {
|
|
4293
4821
|
spinner.start("Installing dependencies...");
|
|
@@ -4315,7 +4843,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4315
4843
|
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
4316
4844
|
console.log();
|
|
4317
4845
|
console.log(chalk4__default.default.cyan("Next steps:"));
|
|
4318
|
-
console.log(chalk4__default.default.gray(` cd ${
|
|
4846
|
+
console.log(chalk4__default.default.gray(` cd ${path13__default.default.relative(process.cwd(), outputDir)}`));
|
|
4319
4847
|
console.log(
|
|
4320
4848
|
chalk4__default.default.gray(" cp .env.example .env # then add your Company ID")
|
|
4321
4849
|
);
|
|
@@ -4342,16 +4870,16 @@ async function devCommand(options) {
|
|
|
4342
4870
|
if (options.theme) {
|
|
4343
4871
|
themeName = options.theme;
|
|
4344
4872
|
try {
|
|
4345
|
-
const workspaceThemePath =
|
|
4346
|
-
if (
|
|
4873
|
+
const workspaceThemePath = path13__default.default.join(getThemesDir(), themeName);
|
|
4874
|
+
if (fs8__default.default.existsSync(workspaceThemePath)) {
|
|
4347
4875
|
themePath = workspaceThemePath;
|
|
4348
4876
|
} else {
|
|
4349
|
-
themePath =
|
|
4877
|
+
themePath = path13__default.default.join(process.cwd(), themeName);
|
|
4350
4878
|
}
|
|
4351
4879
|
} catch {
|
|
4352
|
-
themePath =
|
|
4880
|
+
themePath = path13__default.default.join(process.cwd(), themeName);
|
|
4353
4881
|
}
|
|
4354
|
-
if (!
|
|
4882
|
+
if (!fs8__default.default.existsSync(themePath)) {
|
|
4355
4883
|
logger.error(`Theme "${themeName}" not found.`);
|
|
4356
4884
|
process.exit(1);
|
|
4357
4885
|
}
|
|
@@ -4359,11 +4887,14 @@ async function devCommand(options) {
|
|
|
4359
4887
|
const isThemeDir2 = [
|
|
4360
4888
|
"theme.config.ts",
|
|
4361
4889
|
"bundle-entry.ts",
|
|
4362
|
-
"manifest.ts"
|
|
4363
|
-
|
|
4890
|
+
"manifest.ts",
|
|
4891
|
+
"next.config.ts",
|
|
4892
|
+
"next.config.js",
|
|
4893
|
+
"next.config.mjs"
|
|
4894
|
+
].some((f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f)));
|
|
4364
4895
|
if (isThemeDir2) {
|
|
4365
4896
|
themePath = process.cwd();
|
|
4366
|
-
themeName =
|
|
4897
|
+
themeName = path13__default.default.basename(themePath);
|
|
4367
4898
|
} else {
|
|
4368
4899
|
logger.error(
|
|
4369
4900
|
"Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
|
|
@@ -4432,9 +4963,9 @@ async function devCommand(options) {
|
|
|
4432
4963
|
watcher.close();
|
|
4433
4964
|
await context2.dispose();
|
|
4434
4965
|
server.close();
|
|
4435
|
-
const shimPath =
|
|
4966
|
+
const shimPath = path13__default.default.join(outputDir, ".process-shim.js");
|
|
4436
4967
|
try {
|
|
4437
|
-
await
|
|
4968
|
+
await fs11__default.default.unlink(shimPath);
|
|
4438
4969
|
} catch {
|
|
4439
4970
|
}
|
|
4440
4971
|
process.exit(0);
|
|
@@ -4443,8 +4974,8 @@ async function devCommand(options) {
|
|
|
4443
4974
|
|
|
4444
4975
|
// src/commands/config.ts
|
|
4445
4976
|
init_logger();
|
|
4446
|
-
var CONFIG_DIR =
|
|
4447
|
-
var CONFIG_FILE =
|
|
4977
|
+
var CONFIG_DIR = path13__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
4978
|
+
var CONFIG_FILE = path13__default.default.join(CONFIG_DIR, ".env");
|
|
4448
4979
|
var CONFIG_ENTRIES = [
|
|
4449
4980
|
{
|
|
4450
4981
|
key: "AWS_ACCESS_KEY_ID",
|
|
@@ -4530,7 +5061,7 @@ async function configCommand() {
|
|
|
4530
5061
|
logger.header("OneX CLI Configuration");
|
|
4531
5062
|
let existing = {};
|
|
4532
5063
|
try {
|
|
4533
|
-
const content = await
|
|
5064
|
+
const content = await fs8__default.default.readFile(CONFIG_FILE, "utf-8");
|
|
4534
5065
|
existing = parseEnvFile(content);
|
|
4535
5066
|
logger.info(`Existing config found at: ${CONFIG_FILE}`);
|
|
4536
5067
|
logger.newLine();
|
|
@@ -4566,8 +5097,8 @@ async function configCommand() {
|
|
|
4566
5097
|
for (const key of Object.keys(merged)) {
|
|
4567
5098
|
if (!merged[key]) delete merged[key];
|
|
4568
5099
|
}
|
|
4569
|
-
await
|
|
4570
|
-
await
|
|
5100
|
+
await fs8__default.default.ensureDir(CONFIG_DIR);
|
|
5101
|
+
await fs8__default.default.writeFile(CONFIG_FILE, serializeEnv(merged));
|
|
4571
5102
|
logger.newLine();
|
|
4572
5103
|
logger.success(`Config saved to: ${CONFIG_FILE}`);
|
|
4573
5104
|
logger.newLine();
|
|
@@ -4586,8 +5117,8 @@ async function configCommand() {
|
|
|
4586
5117
|
|
|
4587
5118
|
// src/commands/login.ts
|
|
4588
5119
|
init_logger();
|
|
4589
|
-
async function loginCommand(options
|
|
4590
|
-
const env = options.env
|
|
5120
|
+
async function loginCommand(options) {
|
|
5121
|
+
const env = options.env;
|
|
4591
5122
|
const apiUrl = getApiUrl(env);
|
|
4592
5123
|
logger.header("OneX Theme Developer Login");
|
|
4593
5124
|
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
@@ -4676,8 +5207,8 @@ async function loginCommand(options = {}) {
|
|
|
4676
5207
|
|
|
4677
5208
|
// src/commands/logout.ts
|
|
4678
5209
|
init_logger();
|
|
4679
|
-
async function logoutCommand(options
|
|
4680
|
-
const env = options.env
|
|
5210
|
+
async function logoutCommand(options) {
|
|
5211
|
+
const env = options.env;
|
|
4681
5212
|
const tokens = loadAuthTokens(env);
|
|
4682
5213
|
if (!tokens) {
|
|
4683
5214
|
logger.info(`Not logged in to ${env} environment.`);
|
|
@@ -4689,8 +5220,8 @@ async function logoutCommand(options = {}) {
|
|
|
4689
5220
|
|
|
4690
5221
|
// src/commands/whoami.ts
|
|
4691
5222
|
init_logger();
|
|
4692
|
-
async function whoamiCommand(options
|
|
4693
|
-
const env = options.env
|
|
5223
|
+
async function whoamiCommand(options) {
|
|
5224
|
+
const env = options.env;
|
|
4694
5225
|
const tokens = loadAuthTokens(env);
|
|
4695
5226
|
if (!tokens) {
|
|
4696
5227
|
logger.error(
|
|
@@ -4712,96 +5243,362 @@ async function whoamiCommand(options = {}) {
|
|
|
4712
5243
|
|
|
4713
5244
|
// src/commands/publish.ts
|
|
4714
5245
|
init_logger();
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
5246
|
+
init_scan_theme_assets();
|
|
5247
|
+
|
|
5248
|
+
// src/utils/fetch-prior-schemas.ts
|
|
5249
|
+
async function fetchPriorGateManifests(themeId, env) {
|
|
5250
|
+
const apiUrl = getApiUrl(env);
|
|
5251
|
+
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/gate-manifests/latest`;
|
|
5252
|
+
let res;
|
|
5253
|
+
try {
|
|
5254
|
+
res = await authenticatedFetch(url, { method: "GET" }, env);
|
|
5255
|
+
} catch (err) {
|
|
5256
|
+
return {
|
|
5257
|
+
result: null,
|
|
5258
|
+
reason: `network error: ${err instanceof Error ? err.message : "unknown"}`
|
|
5259
|
+
};
|
|
5260
|
+
}
|
|
5261
|
+
if (res.status === 404) {
|
|
5262
|
+
return { result: null, reason: "no-prior" };
|
|
5263
|
+
}
|
|
5264
|
+
if (!res.ok) {
|
|
5265
|
+
return {
|
|
5266
|
+
result: null,
|
|
5267
|
+
reason: `server returned ${res.status} ${res.statusText}`
|
|
5268
|
+
};
|
|
5269
|
+
}
|
|
5270
|
+
let data;
|
|
5271
|
+
try {
|
|
5272
|
+
data = await res.json();
|
|
5273
|
+
} catch {
|
|
5274
|
+
return { result: null, reason: "non-JSON response from server" };
|
|
5275
|
+
}
|
|
5276
|
+
const body = data.statusCode ? data.body : data;
|
|
5277
|
+
if (!body || typeof body.version !== "string" || !body.schemas || !body.assets) {
|
|
5278
|
+
return { result: null, reason: "malformed response (missing fields)" };
|
|
5279
|
+
}
|
|
5280
|
+
return {
|
|
5281
|
+
result: {
|
|
5282
|
+
version: body.version,
|
|
5283
|
+
schemas: body.schemas,
|
|
5284
|
+
assets: body.assets
|
|
5285
|
+
},
|
|
5286
|
+
reason: null
|
|
5287
|
+
};
|
|
4748
5288
|
}
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
5289
|
+
|
|
5290
|
+
// src/utils/schema-diff.ts
|
|
5291
|
+
var SEVERITY = {
|
|
5292
|
+
safe: 0,
|
|
5293
|
+
"safe-rename": 1,
|
|
5294
|
+
"defaults-only": 2,
|
|
5295
|
+
additive: 3,
|
|
5296
|
+
breaking: 4,
|
|
5297
|
+
"breaking-asset": 5,
|
|
5298
|
+
"breaking-severe": 6
|
|
5299
|
+
};
|
|
5300
|
+
var BUMP_FOR = {
|
|
5301
|
+
safe: "patch",
|
|
5302
|
+
"safe-rename": "patch",
|
|
5303
|
+
"defaults-only": "patch",
|
|
5304
|
+
additive: "minor",
|
|
5305
|
+
breaking: "major",
|
|
5306
|
+
"breaking-asset": "major",
|
|
5307
|
+
"breaking-severe": "major"
|
|
5308
|
+
};
|
|
5309
|
+
function bumpFor(kind) {
|
|
5310
|
+
return BUMP_FOR[kind];
|
|
5311
|
+
}
|
|
5312
|
+
function maxSeverity(a, b) {
|
|
5313
|
+
return SEVERITY[a] >= SEVERITY[b] ? a : b;
|
|
5314
|
+
}
|
|
5315
|
+
function classify(changes) {
|
|
5316
|
+
let highest = "safe";
|
|
5317
|
+
for (const c of changes) {
|
|
5318
|
+
highest = maxSeverity(highest, c.kind);
|
|
5319
|
+
}
|
|
5320
|
+
return { bump: bumpFor(highest), highest, changes };
|
|
5321
|
+
}
|
|
5322
|
+
function diffManifests(prior, current) {
|
|
5323
|
+
const changes = [];
|
|
5324
|
+
const priorSections = prior.schemas.sections;
|
|
5325
|
+
const currentSections = current.schemas.sections;
|
|
5326
|
+
const sectionTypes = /* @__PURE__ */ new Set([
|
|
5327
|
+
...Object.keys(priorSections),
|
|
5328
|
+
...Object.keys(currentSections)
|
|
5329
|
+
]);
|
|
5330
|
+
for (const type of [...sectionTypes].sort()) {
|
|
5331
|
+
const p = priorSections[type];
|
|
5332
|
+
const c = currentSections[type];
|
|
5333
|
+
if (p && !c) {
|
|
5334
|
+
changes.push({
|
|
5335
|
+
kind: "breaking-severe",
|
|
5336
|
+
path: `sections.${type}`,
|
|
5337
|
+
detail: `Section type "${type}" removed. Pages using this section will render empty.`
|
|
5338
|
+
});
|
|
5339
|
+
continue;
|
|
5340
|
+
}
|
|
5341
|
+
if (!p && c) {
|
|
5342
|
+
changes.push({
|
|
5343
|
+
kind: "additive",
|
|
5344
|
+
path: `sections.${type}`,
|
|
5345
|
+
detail: `Section type "${type}" added.`
|
|
5346
|
+
});
|
|
5347
|
+
continue;
|
|
5348
|
+
}
|
|
5349
|
+
if (p && c) diffSection(p, c, changes);
|
|
5350
|
+
}
|
|
5351
|
+
diffAssets(prior.assets, current.assets, changes);
|
|
5352
|
+
return changes;
|
|
4752
5353
|
}
|
|
4753
|
-
|
|
4754
|
-
const
|
|
4755
|
-
|
|
5354
|
+
function diffSection(prior, current, out) {
|
|
5355
|
+
const type = current.type;
|
|
5356
|
+
if (JSON.stringify(prior.dataRequirements) !== JSON.stringify(current.dataRequirements)) {
|
|
5357
|
+
out.push({
|
|
5358
|
+
kind: "breaking",
|
|
5359
|
+
path: `sections.${type}.dataRequirements`,
|
|
5360
|
+
detail: "dataRequirements changed."
|
|
5361
|
+
});
|
|
5362
|
+
}
|
|
5363
|
+
diffFieldList(
|
|
5364
|
+
prior.settings,
|
|
5365
|
+
current.settings,
|
|
5366
|
+
`sections.${type}.settings`,
|
|
5367
|
+
out
|
|
5368
|
+
);
|
|
5369
|
+
diffDefaults(
|
|
5370
|
+
prior.defaults,
|
|
5371
|
+
current.defaults,
|
|
5372
|
+
`sections.${type}.defaults`,
|
|
5373
|
+
out
|
|
5374
|
+
);
|
|
5375
|
+
diffBlocks(prior.blocks, current.blocks, `sections.${type}.blocks`, out);
|
|
5376
|
+
}
|
|
5377
|
+
function diffBlocks(prior, current, pathPrefix, out) {
|
|
5378
|
+
const priorByType = new Map(prior.map((b) => [b.type, b]));
|
|
5379
|
+
const currentByType = new Map(current.map((b) => [b.type, b]));
|
|
5380
|
+
for (const type of /* @__PURE__ */ new Set([
|
|
5381
|
+
...priorByType.keys(),
|
|
5382
|
+
...currentByType.keys()
|
|
5383
|
+
])) {
|
|
5384
|
+
const p = priorByType.get(type);
|
|
5385
|
+
const c = currentByType.get(type);
|
|
5386
|
+
if (p && !c) {
|
|
5387
|
+
out.push({
|
|
5388
|
+
kind: "breaking",
|
|
5389
|
+
path: `${pathPrefix}.${type}`,
|
|
5390
|
+
detail: `Block type "${type}" removed.`
|
|
5391
|
+
});
|
|
5392
|
+
continue;
|
|
5393
|
+
}
|
|
5394
|
+
if (!p && c) {
|
|
5395
|
+
out.push({
|
|
5396
|
+
kind: "additive",
|
|
5397
|
+
path: `${pathPrefix}.${type}`,
|
|
5398
|
+
detail: `Block type "${type}" added.`
|
|
5399
|
+
});
|
|
5400
|
+
continue;
|
|
5401
|
+
}
|
|
5402
|
+
if (p && c) {
|
|
5403
|
+
diffFieldList(
|
|
5404
|
+
p.settings,
|
|
5405
|
+
c.settings,
|
|
5406
|
+
`${pathPrefix}.${type}.settings`,
|
|
5407
|
+
out
|
|
5408
|
+
);
|
|
5409
|
+
diffDefaults(
|
|
5410
|
+
p.defaults,
|
|
5411
|
+
c.defaults,
|
|
5412
|
+
`${pathPrefix}.${type}.defaults`,
|
|
5413
|
+
out
|
|
5414
|
+
);
|
|
5415
|
+
}
|
|
5416
|
+
}
|
|
4756
5417
|
}
|
|
4757
|
-
function
|
|
4758
|
-
const
|
|
4759
|
-
const
|
|
4760
|
-
const
|
|
4761
|
-
const
|
|
4762
|
-
|
|
4763
|
-
|
|
5418
|
+
function diffFieldList(prior, current, pathPrefix, out) {
|
|
5419
|
+
const priorById = new Map(prior.map((f) => [f.id, f]));
|
|
5420
|
+
const currentById = new Map(current.map((f) => [f.id, f]));
|
|
5421
|
+
const aliasToCurrent = /* @__PURE__ */ new Map();
|
|
5422
|
+
for (const f of current) {
|
|
5423
|
+
if (f.aliases) {
|
|
5424
|
+
for (const alias of f.aliases) {
|
|
5425
|
+
aliasToCurrent.set(alias, f);
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
for (const [id, p] of priorById) {
|
|
5430
|
+
const c = currentById.get(id);
|
|
5431
|
+
if (c) {
|
|
5432
|
+
diffFieldPair(p, c, `${pathPrefix}.${id}`, out);
|
|
5433
|
+
continue;
|
|
5434
|
+
}
|
|
5435
|
+
const renamed = aliasToCurrent.get(id);
|
|
5436
|
+
if (renamed) {
|
|
5437
|
+
if (renamed.type === p.type) {
|
|
5438
|
+
out.push({
|
|
5439
|
+
kind: "safe-rename",
|
|
5440
|
+
path: `${pathPrefix}.${id}`,
|
|
5441
|
+
detail: `Field "${id}" renamed to "${renamed.id}" (alias preserved).`
|
|
5442
|
+
});
|
|
5443
|
+
} else {
|
|
5444
|
+
out.push({
|
|
5445
|
+
kind: "breaking",
|
|
5446
|
+
path: `${pathPrefix}.${id}`,
|
|
5447
|
+
detail: `Field "${id}" renamed to "${renamed.id}" but type changed (${p.type} \u2192 ${renamed.type}).`
|
|
5448
|
+
});
|
|
5449
|
+
}
|
|
5450
|
+
} else {
|
|
5451
|
+
out.push({
|
|
5452
|
+
kind: "breaking",
|
|
5453
|
+
path: `${pathPrefix}.${id}`,
|
|
5454
|
+
detail: `Field "${id}" removed. Consider adding aliases: ["${id}"] to the replacement field if this was a rename.`
|
|
5455
|
+
});
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
for (const [id, c] of currentById) {
|
|
5459
|
+
if (priorById.has(id)) continue;
|
|
5460
|
+
const coveredByAlias = c.aliases?.some((a) => priorById.has(a)) ?? false;
|
|
5461
|
+
if (coveredByAlias) continue;
|
|
5462
|
+
if (c.required && c.default === void 0) {
|
|
5463
|
+
out.push({
|
|
5464
|
+
kind: "breaking",
|
|
5465
|
+
path: `${pathPrefix}.${id}`,
|
|
5466
|
+
detail: `Required field "${id}" added with no default. Existing instances cannot satisfy it.`
|
|
5467
|
+
});
|
|
5468
|
+
} else {
|
|
5469
|
+
out.push({
|
|
5470
|
+
kind: "additive",
|
|
5471
|
+
path: `${pathPrefix}.${id}`,
|
|
5472
|
+
detail: `Field "${id}" added.`
|
|
5473
|
+
});
|
|
5474
|
+
}
|
|
5475
|
+
}
|
|
4764
5476
|
}
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
5477
|
+
function diffFieldPair(p, c, path25, out) {
|
|
5478
|
+
if (p.type !== c.type) {
|
|
5479
|
+
out.push({
|
|
5480
|
+
kind: "breaking",
|
|
5481
|
+
path: path25,
|
|
5482
|
+
detail: `Type changed (${p.type} \u2192 ${c.type}). Saved values may misrender.`
|
|
5483
|
+
});
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
if (p.required !== true && c.required === true) {
|
|
5487
|
+
out.push({
|
|
5488
|
+
kind: "breaking",
|
|
5489
|
+
path: path25,
|
|
5490
|
+
detail: "Field became required. Existing empty instances now invalid."
|
|
5491
|
+
});
|
|
5492
|
+
}
|
|
5493
|
+
if (typeof p.maxLength === "number" || typeof c.maxLength === "number") {
|
|
5494
|
+
if ((c.maxLength ?? Infinity) < (p.maxLength ?? Infinity)) {
|
|
5495
|
+
out.push({
|
|
5496
|
+
kind: "breaking",
|
|
5497
|
+
path: path25,
|
|
5498
|
+
detail: `maxLength tightened (${p.maxLength ?? "\u221E"} \u2192 ${c.maxLength}).`
|
|
5499
|
+
});
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
if (typeof p.min === "number" || typeof c.min === "number") {
|
|
5503
|
+
if ((c.min ?? -Infinity) > (p.min ?? -Infinity)) {
|
|
5504
|
+
out.push({
|
|
5505
|
+
kind: "breaking",
|
|
5506
|
+
path: path25,
|
|
5507
|
+
detail: `min raised (${p.min ?? "-\u221E"} \u2192 ${c.min}).`
|
|
5508
|
+
});
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
if (typeof p.max === "number" || typeof c.max === "number") {
|
|
5512
|
+
if ((c.max ?? Infinity) < (p.max ?? Infinity)) {
|
|
5513
|
+
out.push({
|
|
5514
|
+
kind: "breaking",
|
|
5515
|
+
path: path25,
|
|
5516
|
+
detail: `max lowered (${p.max ?? "\u221E"} \u2192 ${c.max}).`
|
|
5517
|
+
});
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
if (p.options || c.options) {
|
|
5521
|
+
const priorOpts = new Set(p.options ?? []);
|
|
5522
|
+
const currentOpts = new Set(c.options ?? []);
|
|
5523
|
+
const removed = [...priorOpts].filter((o) => !currentOpts.has(o));
|
|
5524
|
+
const added = [...currentOpts].filter((o) => !priorOpts.has(o));
|
|
5525
|
+
if (removed.length > 0) {
|
|
5526
|
+
out.push({
|
|
5527
|
+
kind: "breaking",
|
|
5528
|
+
path: path25,
|
|
5529
|
+
detail: `Option(s) removed: ${removed.join(", ")}. Existing saved values may be orphaned.`
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
if (added.length > 0) {
|
|
5533
|
+
out.push({
|
|
5534
|
+
kind: "additive",
|
|
5535
|
+
path: path25,
|
|
5536
|
+
detail: `Option(s) added: ${added.join(", ")}.`
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
if (!deepEqual(p.default, c.default)) {
|
|
5541
|
+
out.push({
|
|
5542
|
+
kind: "defaults-only",
|
|
5543
|
+
path: path25,
|
|
5544
|
+
detail: `Default changed: ${JSON.stringify(p.default)} \u2192 ${JSON.stringify(c.default)}.`
|
|
4789
5545
|
});
|
|
4790
5546
|
}
|
|
4791
|
-
results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
|
|
4792
|
-
return results;
|
|
4793
5547
|
}
|
|
4794
|
-
function
|
|
4795
|
-
const
|
|
4796
|
-
for (const
|
|
4797
|
-
|
|
5548
|
+
function diffDefaults(prior, current, pathPrefix, out) {
|
|
5549
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(prior), ...Object.keys(current)]);
|
|
5550
|
+
for (const key of [...keys].sort()) {
|
|
5551
|
+
if (!(key in prior) || !(key in current)) continue;
|
|
5552
|
+
if (!deepEqual(prior[key], current[key])) {
|
|
5553
|
+
out.push({
|
|
5554
|
+
kind: "defaults-only",
|
|
5555
|
+
path: `${pathPrefix}.${key}`,
|
|
5556
|
+
detail: `Default value changed.`
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
4798
5559
|
}
|
|
4799
|
-
|
|
5560
|
+
}
|
|
5561
|
+
function diffAssets(prior, current, out) {
|
|
5562
|
+
const currentPaths = new Set(current.assets.map((a) => a.path));
|
|
5563
|
+
for (const a of prior.assets) {
|
|
5564
|
+
if (!currentPaths.has(a.path)) {
|
|
5565
|
+
out.push({
|
|
5566
|
+
kind: "breaking-asset",
|
|
5567
|
+
path: `theme-assets/${a.path}`,
|
|
5568
|
+
detail: `Asset "${a.path}" was present in the prior version and is now missing. Code that references it hardcoded will break.`
|
|
5569
|
+
});
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
function deepEqual(a, b) {
|
|
5574
|
+
if (a === b) return true;
|
|
5575
|
+
if (a === null || b === null) return false;
|
|
5576
|
+
if (typeof a !== typeof b) return false;
|
|
5577
|
+
if (typeof a !== "object") return false;
|
|
5578
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
5579
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
5580
|
+
if (a.length !== b.length) return false;
|
|
5581
|
+
for (let i = 0; i < a.length; i++) {
|
|
5582
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
5583
|
+
}
|
|
5584
|
+
return true;
|
|
5585
|
+
}
|
|
5586
|
+
const ak = Object.keys(a);
|
|
5587
|
+
const bk = Object.keys(b);
|
|
5588
|
+
if (ak.length !== bk.length) return false;
|
|
5589
|
+
for (const k of ak) {
|
|
5590
|
+
if (!deepEqual(
|
|
5591
|
+
a[k],
|
|
5592
|
+
b[k]
|
|
5593
|
+
))
|
|
5594
|
+
return false;
|
|
5595
|
+
}
|
|
5596
|
+
return true;
|
|
4800
5597
|
}
|
|
4801
5598
|
|
|
4802
5599
|
// src/commands/publish.ts
|
|
4803
5600
|
async function publishCommand(options) {
|
|
4804
|
-
const env = options.env
|
|
5601
|
+
const env = options.env;
|
|
4805
5602
|
logger.header("OneX Theme Publish");
|
|
4806
5603
|
logger.info(`Environment: ${env} (${getApiUrl(env)})`);
|
|
4807
5604
|
logger.newLine();
|
|
@@ -4815,13 +5612,13 @@ async function publishCommand(options) {
|
|
|
4815
5612
|
logger.info(`Logged in as: ${tokens.user.email}`);
|
|
4816
5613
|
let themePath;
|
|
4817
5614
|
if (options.theme) {
|
|
4818
|
-
themePath =
|
|
5615
|
+
themePath = path13__default.default.resolve(options.theme);
|
|
4819
5616
|
} else {
|
|
4820
5617
|
const isThemeDir2 = [
|
|
4821
5618
|
"theme.config.ts",
|
|
4822
5619
|
"bundle-entry.ts",
|
|
4823
5620
|
"manifest.ts"
|
|
4824
|
-
].some((f) =>
|
|
5621
|
+
].some((f) => fs8__default.default.existsSync(path13__default.default.join(process.cwd(), f)));
|
|
4825
5622
|
if (isThemeDir2) {
|
|
4826
5623
|
themePath = process.cwd();
|
|
4827
5624
|
} else {
|
|
@@ -4831,13 +5628,13 @@ async function publishCommand(options) {
|
|
|
4831
5628
|
process.exit(1);
|
|
4832
5629
|
}
|
|
4833
5630
|
}
|
|
4834
|
-
const pkgPath =
|
|
4835
|
-
if (!
|
|
5631
|
+
const pkgPath = path13__default.default.join(themePath, "package.json");
|
|
5632
|
+
if (!fs8__default.default.existsSync(pkgPath)) {
|
|
4836
5633
|
logger.error("No package.json found in theme directory");
|
|
4837
5634
|
process.exit(1);
|
|
4838
5635
|
}
|
|
4839
|
-
const pkg =
|
|
4840
|
-
const themeId = pkg.name?.replace("@onex-themes/", "") ||
|
|
5636
|
+
const pkg = fs8__default.default.readJsonSync(pkgPath);
|
|
5637
|
+
const themeId = pkg.name?.replace("@onex-themes/", "") || path13__default.default.basename(themePath);
|
|
4841
5638
|
if (options.bump) {
|
|
4842
5639
|
const currentVersion = pkg.version || "1.0.0";
|
|
4843
5640
|
const newVersion = semver__default.default.inc(currentVersion, options.bump);
|
|
@@ -4846,7 +5643,7 @@ async function publishCommand(options) {
|
|
|
4846
5643
|
process.exit(1);
|
|
4847
5644
|
}
|
|
4848
5645
|
pkg.version = newVersion;
|
|
4849
|
-
|
|
5646
|
+
fs8__default.default.writeJsonSync(pkgPath, pkg, { spaces: 2 });
|
|
4850
5647
|
logger.info(`Bumped version: ${currentVersion} -> ${newVersion}`);
|
|
4851
5648
|
}
|
|
4852
5649
|
const version2 = pkg.version || "1.0.0";
|
|
@@ -4861,57 +5658,62 @@ async function publishCommand(options) {
|
|
|
4861
5658
|
logger.info(`Version: ${version2}`);
|
|
4862
5659
|
logger.newLine();
|
|
4863
5660
|
const apiUrl = getApiUrl(env);
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
5661
|
+
if (!options.dryRun) {
|
|
5662
|
+
logger.startSpinner("Registering theme...");
|
|
5663
|
+
try {
|
|
5664
|
+
const regResponse = await authenticatedFetch(
|
|
5665
|
+
`${apiUrl}/website-api/themes/register`,
|
|
5666
|
+
{
|
|
5667
|
+
method: "POST",
|
|
5668
|
+
body: JSON.stringify({
|
|
5669
|
+
themeId,
|
|
5670
|
+
name: pkg.displayName || themeId,
|
|
5671
|
+
description: pkg.description || "",
|
|
5672
|
+
email: tokens.user.email,
|
|
5673
|
+
author: typeof pkg.author === "string" ? pkg.author : pkg.author?.name || tokens.user.name || "",
|
|
5674
|
+
category: pkg.onex?.category || "MINIMAL",
|
|
5675
|
+
tags: pkg.keywords || [],
|
|
5676
|
+
thumbnail_url: pkg.onex?.thumbnail || ""
|
|
5677
|
+
})
|
|
5678
|
+
},
|
|
5679
|
+
env
|
|
5680
|
+
);
|
|
5681
|
+
const regData = await regResponse.json();
|
|
5682
|
+
const regBody = regData.statusCode ? regData.body : regData;
|
|
5683
|
+
if (!regResponse.ok) {
|
|
5684
|
+
const errMsg = regBody.error || regBody.message || "Registration failed";
|
|
5685
|
+
if (!errMsg.includes("already registered")) {
|
|
5686
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5687
|
+
logger.error(errMsg);
|
|
5688
|
+
process.exit(1);
|
|
5689
|
+
}
|
|
4891
5690
|
}
|
|
5691
|
+
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
5692
|
+
} catch (error) {
|
|
5693
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5694
|
+
logger.error(
|
|
5695
|
+
error instanceof Error ? error.message : "Connection failed"
|
|
5696
|
+
);
|
|
5697
|
+
process.exit(1);
|
|
4892
5698
|
}
|
|
4893
|
-
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
4894
|
-
} catch (error) {
|
|
4895
|
-
logger.stopSpinner(false, "Registration failed");
|
|
4896
|
-
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4897
|
-
process.exit(1);
|
|
4898
5699
|
}
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
5700
|
+
if (!options.dryRun) {
|
|
5701
|
+
logger.startSpinner("Checking version availability...");
|
|
5702
|
+
try {
|
|
5703
|
+
const checkResponse = await authenticatedFetch(
|
|
5704
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/exists`,
|
|
5705
|
+
{ method: "GET" },
|
|
5706
|
+
env
|
|
5707
|
+
);
|
|
5708
|
+
const checkData = await checkResponse.json();
|
|
5709
|
+
const checkBody = checkData.statusCode ? checkData.body : checkData;
|
|
5710
|
+
if (checkBody.exists) {
|
|
5711
|
+
logger.stopSpinner(false, "Version already published");
|
|
5712
|
+
const patchVer = semver__default.default.inc(version2, "patch") || "?";
|
|
5713
|
+
const minorVer = semver__default.default.inc(version2, "minor") || "?";
|
|
5714
|
+
const majorVer = semver__default.default.inc(version2, "major") || "?";
|
|
5715
|
+
logger.error(
|
|
5716
|
+
`
|
|
4915
5717
|
Version ${version2} of "${themeId}" is already published and cannot be overwritten.
|
|
4916
5718
|
|
|
4917
5719
|
To publish a new version:
|
|
@@ -4922,12 +5724,16 @@ Or use the --bump flag:
|
|
|
4922
5724
|
onexthm publish --bump patch (${version2} -> ${patchVer})
|
|
4923
5725
|
onexthm publish --bump minor (${version2} -> ${minorVer})
|
|
4924
5726
|
onexthm publish --bump major (${version2} -> ${majorVer})`
|
|
5727
|
+
);
|
|
5728
|
+
process.exit(1);
|
|
5729
|
+
}
|
|
5730
|
+
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
5731
|
+
} catch (error) {
|
|
5732
|
+
logger.stopSpinner(
|
|
5733
|
+
true,
|
|
5734
|
+
"Version check skipped (endpoint not available)"
|
|
4925
5735
|
);
|
|
4926
|
-
process.exit(1);
|
|
4927
5736
|
}
|
|
4928
|
-
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
4929
|
-
} catch (error) {
|
|
4930
|
-
logger.stopSpinner(true, "Version check skipped (endpoint not available)");
|
|
4931
5737
|
}
|
|
4932
5738
|
logger.startSpinner("Building theme...");
|
|
4933
5739
|
try {
|
|
@@ -4944,7 +5750,19 @@ Or use the --bump flag:
|
|
|
4944
5750
|
logger.error(error instanceof Error ? error.message : "Build error");
|
|
4945
5751
|
process.exit(1);
|
|
4946
5752
|
}
|
|
4947
|
-
const distDir =
|
|
5753
|
+
const distDir = path13__default.default.join(themePath, "dist");
|
|
5754
|
+
const classification = await runSchemaDiffGate(
|
|
5755
|
+
themeId,
|
|
5756
|
+
distDir,
|
|
5757
|
+
env,
|
|
5758
|
+
options
|
|
5759
|
+
);
|
|
5760
|
+
if (options.dryRun) {
|
|
5761
|
+
const exitCode = classification?.highest === "breaking" || classification?.highest === "breaking-severe" || classification?.highest === "breaking-asset" ? 2 : 0;
|
|
5762
|
+
logger.newLine();
|
|
5763
|
+
logger.info(`Dry run complete (exit ${exitCode}). No files uploaded.`);
|
|
5764
|
+
process.exit(exitCode);
|
|
5765
|
+
}
|
|
4948
5766
|
let assetEntries = [];
|
|
4949
5767
|
try {
|
|
4950
5768
|
assetEntries = await scanThemeAssets(distDir);
|
|
@@ -4981,8 +5799,8 @@ Or use the --bump flag:
|
|
|
4981
5799
|
for (const [originalPath, url] of Object.entries(videoUrls)) {
|
|
4982
5800
|
assetMap[originalPath] = url;
|
|
4983
5801
|
}
|
|
4984
|
-
const assetMapPath =
|
|
4985
|
-
await
|
|
5802
|
+
const assetMapPath = path13__default.default.join(distDir, "asset-map.json");
|
|
5803
|
+
await fs8__default.default.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
|
|
4986
5804
|
} catch (error) {
|
|
4987
5805
|
logger.error(
|
|
4988
5806
|
`Failed to write asset-map.json: ${error instanceof Error ? error.message : "unknown"}`
|
|
@@ -5057,7 +5875,7 @@ Or use the --bump flag:
|
|
|
5057
5875
|
continue;
|
|
5058
5876
|
}
|
|
5059
5877
|
try {
|
|
5060
|
-
const buf = await
|
|
5878
|
+
const buf = await fs8__default.default.promises.readFile(entry.absPath);
|
|
5061
5879
|
const res = await fetch(item.upload_url, {
|
|
5062
5880
|
method: "PUT",
|
|
5063
5881
|
headers: {
|
|
@@ -5099,12 +5917,12 @@ Or use the --bump flag:
|
|
|
5099
5917
|
}
|
|
5100
5918
|
logger.startSpinner("Uploading bundle...");
|
|
5101
5919
|
try {
|
|
5102
|
-
if (!
|
|
5920
|
+
if (!fs8__default.default.existsSync(distDir)) {
|
|
5103
5921
|
logger.stopSpinner(false, "No dist/ directory");
|
|
5104
5922
|
logger.error("Build the theme first: onexthm build");
|
|
5105
5923
|
process.exit(1);
|
|
5106
5924
|
}
|
|
5107
|
-
const bundleZipPath =
|
|
5925
|
+
const bundleZipPath = path13__default.default.join(themePath, "dist", "bundle.zip");
|
|
5108
5926
|
await createZip(distDir, bundleZipPath, [
|
|
5109
5927
|
"bundle.zip",
|
|
5110
5928
|
"source.zip",
|
|
@@ -5113,7 +5931,7 @@ Or use the --bump flag:
|
|
|
5113
5931
|
"theme-assets",
|
|
5114
5932
|
"theme-assets/**"
|
|
5115
5933
|
]);
|
|
5116
|
-
const bundleBuffer =
|
|
5934
|
+
const bundleBuffer = fs8__default.default.readFileSync(bundleZipPath);
|
|
5117
5935
|
const bundleRes = await fetch(bundleUploadUrl, {
|
|
5118
5936
|
method: "PUT",
|
|
5119
5937
|
headers: { "Content-Type": "application/zip" },
|
|
@@ -5131,7 +5949,7 @@ Or use the --bump flag:
|
|
|
5131
5949
|
}
|
|
5132
5950
|
logger.startSpinner("Uploading source...");
|
|
5133
5951
|
try {
|
|
5134
|
-
const sourceZipPath =
|
|
5952
|
+
const sourceZipPath = path13__default.default.join(themePath, "dist", "source.zip");
|
|
5135
5953
|
await createZip(themePath, sourceZipPath, [
|
|
5136
5954
|
"node_modules",
|
|
5137
5955
|
"dist",
|
|
@@ -5139,7 +5957,7 @@ Or use the --bump flag:
|
|
|
5139
5957
|
".env",
|
|
5140
5958
|
".env.local"
|
|
5141
5959
|
]);
|
|
5142
|
-
const sourceBuffer =
|
|
5960
|
+
const sourceBuffer = fs8__default.default.readFileSync(sourceZipPath);
|
|
5143
5961
|
const sourceRes = await fetch(sourceUploadUrl, {
|
|
5144
5962
|
method: "PUT",
|
|
5145
5963
|
headers: { "Content-Type": "application/zip" },
|
|
@@ -5217,9 +6035,9 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir, env = "dev")
|
|
|
5217
6035
|
let imageBase64 = null;
|
|
5218
6036
|
let mimeType = "image/png";
|
|
5219
6037
|
for (const { file, mime } of THUMBNAIL_CANDIDATES) {
|
|
5220
|
-
const candidate =
|
|
5221
|
-
if (
|
|
5222
|
-
const buf =
|
|
6038
|
+
const candidate = path13__default.default.join(themePath, file);
|
|
6039
|
+
if (fs8__default.default.existsSync(candidate)) {
|
|
6040
|
+
const buf = fs8__default.default.readFileSync(candidate);
|
|
5223
6041
|
imageBase64 = `data:${mime};base64,${buf.toString("base64")}`;
|
|
5224
6042
|
mimeType = mime;
|
|
5225
6043
|
logger.info(`Using local thumbnail: ${file}`);
|
|
@@ -5319,7 +6137,7 @@ async function screenshotHomePage(themePath, distDir) {
|
|
|
5319
6137
|
const { compilePreviewRuntime: compilePreviewRuntime2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
5320
6138
|
const { createDevServer: createDevServer2 } = await Promise.resolve().then(() => (init_dev_server(), dev_server_exports));
|
|
5321
6139
|
const previewRuntimePath = await compilePreviewRuntime2(themePath);
|
|
5322
|
-
const themeName =
|
|
6140
|
+
const themeName = path13__default.default.basename(themePath);
|
|
5323
6141
|
const port = await findFreePort(4500);
|
|
5324
6142
|
const server = createDevServer2({
|
|
5325
6143
|
port,
|
|
@@ -5376,7 +6194,7 @@ async function findFreePort(start) {
|
|
|
5376
6194
|
});
|
|
5377
6195
|
}
|
|
5378
6196
|
async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
|
|
5379
|
-
const fileName =
|
|
6197
|
+
const fileName = path13__default.default.basename(video.originalPath);
|
|
5380
6198
|
const videoInitUrl = `${apiUrl}/media/videos/multipart/init`;
|
|
5381
6199
|
const videoInitBody = {
|
|
5382
6200
|
file_name: fileName,
|
|
@@ -5412,7 +6230,7 @@ async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
|
|
|
5412
6230
|
);
|
|
5413
6231
|
}
|
|
5414
6232
|
const { upload_id, file_key, chunk_size, chunk_urls } = initBody;
|
|
5415
|
-
const fileBuffer = await
|
|
6233
|
+
const fileBuffer = await fs8__default.default.promises.readFile(video.absPath);
|
|
5416
6234
|
const CHUNK_CONCURRENCY = 4;
|
|
5417
6235
|
const queue = [...chunk_urls];
|
|
5418
6236
|
const parts = [];
|
|
@@ -5505,6 +6323,91 @@ async function createZip(sourceDir, outputPath, exclude) {
|
|
|
5505
6323
|
archive.finalize();
|
|
5506
6324
|
});
|
|
5507
6325
|
}
|
|
6326
|
+
async function runSchemaDiffGate(themeId, distDir, env, options) {
|
|
6327
|
+
logger.startSpinner("Fetching prior version for diff...");
|
|
6328
|
+
const { result: prior, reason } = await fetchPriorGateManifests(themeId, env);
|
|
6329
|
+
if (!prior) {
|
|
6330
|
+
if (reason === "no-prior") {
|
|
6331
|
+
logger.stopSpinner(true, "First publish \u2014 no prior version to diff");
|
|
6332
|
+
} else {
|
|
6333
|
+
logger.stopSpinner(true, `Gate skipped (${reason})`);
|
|
6334
|
+
}
|
|
6335
|
+
return null;
|
|
6336
|
+
}
|
|
6337
|
+
logger.stopSpinner(true, `Fetched prior version ${prior.version}`);
|
|
6338
|
+
let currentSchemas;
|
|
6339
|
+
let currentAssets;
|
|
6340
|
+
try {
|
|
6341
|
+
currentSchemas = JSON.parse(
|
|
6342
|
+
await fs8__default.default.readFile(path13__default.default.join(distDir, "schemas.json"), "utf-8")
|
|
6343
|
+
);
|
|
6344
|
+
} catch (err) {
|
|
6345
|
+
logger.warning(
|
|
6346
|
+
`Gate skipped: dist/schemas.json missing or unreadable (${err instanceof Error ? err.message : "unknown"})`
|
|
6347
|
+
);
|
|
6348
|
+
return null;
|
|
6349
|
+
}
|
|
6350
|
+
try {
|
|
6351
|
+
currentAssets = JSON.parse(
|
|
6352
|
+
await fs8__default.default.readFile(path13__default.default.join(distDir, "asset-manifest.json"), "utf-8")
|
|
6353
|
+
);
|
|
6354
|
+
} catch {
|
|
6355
|
+
currentAssets = { manifestVersion: 1, assets: [] };
|
|
6356
|
+
}
|
|
6357
|
+
const changes = diffManifests(
|
|
6358
|
+
{ schemas: prior.schemas, assets: prior.assets },
|
|
6359
|
+
{ schemas: currentSchemas, assets: currentAssets }
|
|
6360
|
+
);
|
|
6361
|
+
const classification = classify(changes);
|
|
6362
|
+
printGateReport(prior.version, classification);
|
|
6363
|
+
if (options.dryRun) return classification;
|
|
6364
|
+
const isBreaking = classification.highest === "breaking" || classification.highest === "breaking-severe" || classification.highest === "breaking-asset";
|
|
6365
|
+
if (isBreaking && !options.force) {
|
|
6366
|
+
logger.error(
|
|
6367
|
+
"\nPublish blocked: breaking changes detected.\n \u2022 Bump major version and ship migration notes, OR\n \u2022 Re-run with --force to override (logged in the audit trail)."
|
|
6368
|
+
);
|
|
6369
|
+
process.exit(1);
|
|
6370
|
+
}
|
|
6371
|
+
if (classification.highest === "defaults-only" && !options.confirmDefaults) {
|
|
6372
|
+
logger.error(
|
|
6373
|
+
"\nPublish blocked: default values changed.\nThese defaults will propagate to every customer site that hasn't overridden\nthe field. Re-run with --confirm-defaults to acknowledge the change, or\nrevert the default if it wasn't intentional."
|
|
6374
|
+
);
|
|
6375
|
+
process.exit(1);
|
|
6376
|
+
}
|
|
6377
|
+
return classification;
|
|
6378
|
+
}
|
|
6379
|
+
function printGateReport(priorVersion, classification) {
|
|
6380
|
+
logger.newLine();
|
|
6381
|
+
logger.info(`Schema diff vs. v${priorVersion}:`);
|
|
6382
|
+
if (classification.changes.length === 0) {
|
|
6383
|
+
logger.log(" \u2713 Safe \u2014 no schema changes detected");
|
|
6384
|
+
return;
|
|
6385
|
+
}
|
|
6386
|
+
for (const change of classification.changes) {
|
|
6387
|
+
const icon = iconFor(change.kind);
|
|
6388
|
+
logger.log(` ${icon} [${change.kind}] ${change.path} \u2014 ${change.detail}`);
|
|
6389
|
+
}
|
|
6390
|
+
logger.log(
|
|
6391
|
+
`
|
|
6392
|
+
\u2192 Classification: ${classification.highest}. Suggested bump: ${classification.bump}.`
|
|
6393
|
+
);
|
|
6394
|
+
}
|
|
6395
|
+
function iconFor(kind) {
|
|
6396
|
+
switch (kind) {
|
|
6397
|
+
case "safe":
|
|
6398
|
+
case "safe-rename":
|
|
6399
|
+
return "\u2713";
|
|
6400
|
+
case "additive":
|
|
6401
|
+
return "+";
|
|
6402
|
+
case "defaults-only":
|
|
6403
|
+
return "\u26A0";
|
|
6404
|
+
case "breaking":
|
|
6405
|
+
case "breaking-asset":
|
|
6406
|
+
return "\u2717";
|
|
6407
|
+
case "breaking-severe":
|
|
6408
|
+
return "\u2717\u2717";
|
|
6409
|
+
}
|
|
6410
|
+
}
|
|
5508
6411
|
|
|
5509
6412
|
// src/commands/mcp.ts
|
|
5510
6413
|
init_logger();
|
|
@@ -5516,24 +6419,24 @@ var AI_CONTEXT_FILES = [
|
|
|
5516
6419
|
".mcp.json"
|
|
5517
6420
|
];
|
|
5518
6421
|
function resolveTargetDir(opts) {
|
|
5519
|
-
return
|
|
6422
|
+
return path13__default.default.resolve(opts.cwd ?? process.cwd());
|
|
5520
6423
|
}
|
|
5521
6424
|
function resolveDefaultTemplateDir() {
|
|
5522
|
-
return
|
|
6425
|
+
return path13__default.default.join(getTemplatesDir(), "default");
|
|
5523
6426
|
}
|
|
5524
6427
|
function isThemeDir(dir) {
|
|
5525
|
-
return
|
|
6428
|
+
return fs8__default.default.existsSync(path13__default.default.join(dir, "theme.config.ts")) || fs8__default.default.existsSync(path13__default.default.join(dir, "theme.config.js"));
|
|
5526
6429
|
}
|
|
5527
6430
|
function inspectFiles(templateDir, targetDir) {
|
|
5528
6431
|
return AI_CONTEXT_FILES.map((name) => {
|
|
5529
|
-
const templatePath =
|
|
5530
|
-
const targetPath =
|
|
5531
|
-
const exists =
|
|
6432
|
+
const templatePath = path13__default.default.join(templateDir, name);
|
|
6433
|
+
const targetPath = path13__default.default.join(targetDir, name);
|
|
6434
|
+
const exists = fs8__default.default.existsSync(targetPath);
|
|
5532
6435
|
let identical = false;
|
|
5533
|
-
if (exists &&
|
|
6436
|
+
if (exists && fs8__default.default.existsSync(templatePath)) {
|
|
5534
6437
|
try {
|
|
5535
|
-
const a =
|
|
5536
|
-
const b =
|
|
6438
|
+
const a = fs8__default.default.readFileSync(templatePath, "utf-8");
|
|
6439
|
+
const b = fs8__default.default.readFileSync(targetPath, "utf-8");
|
|
5537
6440
|
identical = a.replace(/\r\n/g, "\n") === b.replace(/\r\n/g, "\n");
|
|
5538
6441
|
} catch {
|
|
5539
6442
|
identical = false;
|
|
@@ -5583,11 +6486,11 @@ async function mcpSetupCommand(options = {}) {
|
|
|
5583
6486
|
}
|
|
5584
6487
|
}
|
|
5585
6488
|
for (const s of missing) {
|
|
5586
|
-
if (!
|
|
6489
|
+
if (!fs8__default.default.existsSync(s.templatePath)) {
|
|
5587
6490
|
logger.warning(` ! ${s.name} not in template \u2014 skipped`);
|
|
5588
6491
|
continue;
|
|
5589
6492
|
}
|
|
5590
|
-
await
|
|
6493
|
+
await fs8__default.default.copy(s.templatePath, s.targetPath);
|
|
5591
6494
|
logger.success(` \u2713 ${s.name}`);
|
|
5592
6495
|
}
|
|
5593
6496
|
logger.log("");
|
|
@@ -5648,11 +6551,11 @@ async function mcpUpgradeCommand(options = {}) {
|
|
|
5648
6551
|
}
|
|
5649
6552
|
}
|
|
5650
6553
|
for (const s of toUpgrade) {
|
|
5651
|
-
if (!
|
|
6554
|
+
if (!fs8__default.default.existsSync(s.templatePath)) {
|
|
5652
6555
|
logger.warning(` ! ${s.name} not in template \u2014 skipped`);
|
|
5653
6556
|
continue;
|
|
5654
6557
|
}
|
|
5655
|
-
await
|
|
6558
|
+
await fs8__default.default.copy(s.templatePath, s.targetPath, { overwrite: true });
|
|
5656
6559
|
logger.success(` \u2713 ${s.name}`);
|
|
5657
6560
|
}
|
|
5658
6561
|
logger.log("");
|
|
@@ -5670,12 +6573,12 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5670
6573
|
return;
|
|
5671
6574
|
}
|
|
5672
6575
|
logger.success("theme.config.ts present");
|
|
5673
|
-
const mcpJsonPath =
|
|
5674
|
-
if (!
|
|
6576
|
+
const mcpJsonPath = path13__default.default.join(targetDir, ".mcp.json");
|
|
6577
|
+
if (!fs8__default.default.existsSync(mcpJsonPath)) {
|
|
5675
6578
|
logger.error(".mcp.json missing \u2014 run `onexthm mcp setup`");
|
|
5676
6579
|
} else {
|
|
5677
6580
|
try {
|
|
5678
|
-
const mcpJson = JSON.parse(
|
|
6581
|
+
const mcpJson = JSON.parse(fs8__default.default.readFileSync(mcpJsonPath, "utf-8"));
|
|
5679
6582
|
const servers = mcpJson?.mcpServers ?? {};
|
|
5680
6583
|
if (servers.onexthm) {
|
|
5681
6584
|
logger.success(".mcp.json registers `onexthm`");
|
|
@@ -5708,8 +6611,8 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5708
6611
|
logger.success(`${s.name} up to date`);
|
|
5709
6612
|
}
|
|
5710
6613
|
}
|
|
5711
|
-
const registryPath =
|
|
5712
|
-
if (
|
|
6614
|
+
const registryPath = path13__default.default.join(targetDir, "sections-registry.ts");
|
|
6615
|
+
if (fs8__default.default.existsSync(registryPath)) {
|
|
5713
6616
|
logger.success("sections-registry.ts present");
|
|
5714
6617
|
} else {
|
|
5715
6618
|
logger.warning(
|
|
@@ -5720,24 +6623,27 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5720
6623
|
|
|
5721
6624
|
// src/cli.ts
|
|
5722
6625
|
dotenv__default.default.config({
|
|
5723
|
-
path:
|
|
6626
|
+
path: path13__default.default.join(process.cwd(), ".env.local"),
|
|
5724
6627
|
override: true
|
|
5725
6628
|
});
|
|
5726
|
-
dotenv__default.default.config({ path:
|
|
6629
|
+
dotenv__default.default.config({ path: path13__default.default.join(process.cwd(), ".env") });
|
|
5727
6630
|
try {
|
|
5728
6631
|
const projectRoot = getProjectRoot();
|
|
5729
|
-
if (
|
|
6632
|
+
if (path13__default.default.resolve(projectRoot) !== path13__default.default.resolve(process.cwd())) {
|
|
5730
6633
|
dotenv__default.default.config({
|
|
5731
|
-
path:
|
|
6634
|
+
path: path13__default.default.join(projectRoot, ".env.local")
|
|
5732
6635
|
});
|
|
5733
|
-
dotenv__default.default.config({ path:
|
|
6636
|
+
dotenv__default.default.config({ path: path13__default.default.join(projectRoot, ".env") });
|
|
5734
6637
|
}
|
|
5735
6638
|
} catch {
|
|
5736
6639
|
}
|
|
5737
6640
|
dotenv__default.default.config({
|
|
5738
|
-
path:
|
|
6641
|
+
path: path13__default.default.join(os__default.default.homedir(), ".onexthm", ".env"),
|
|
5739
6642
|
quiet: true
|
|
5740
6643
|
});
|
|
6644
|
+
function envOpt() {
|
|
6645
|
+
return new commander.Option("--env <env>", "Target environment: dev, staging, or prod").choices(["dev", "staging", "prod"]).makeOptionMandatory();
|
|
6646
|
+
}
|
|
5741
6647
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
5742
6648
|
var { version } = require2("../package.json");
|
|
5743
6649
|
var program = new commander.Command();
|
|
@@ -5746,11 +6652,7 @@ program.command("init").description("Create a new OneX theme project").argument(
|
|
|
5746
6652
|
"-t, --template <template>",
|
|
5747
6653
|
"Template to use (default, minimal)",
|
|
5748
6654
|
"default"
|
|
5749
|
-
).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").
|
|
5750
|
-
"--env <env>",
|
|
5751
|
-
"Target environment: dev or prod (default: dev)",
|
|
5752
|
-
"dev"
|
|
5753
|
-
).action(initCommand);
|
|
6655
|
+
).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").addOption(envOpt()).action(initCommand);
|
|
5754
6656
|
program.command("create:section").alias("cs").description("Create a new section").argument("<name>", "Name of the section (e.g., hero, features)").option("-t, --theme <theme>", "Theme to create section in").option(
|
|
5755
6657
|
"-c, --category <category>",
|
|
5756
6658
|
"Section category (headers, content, footers)"
|
|
@@ -5777,36 +6679,16 @@ program.command("download").description("Download a published theme via the webs
|
|
|
5777
6679
|
"-v, --version <version>",
|
|
5778
6680
|
"Theme version (default: latest)",
|
|
5779
6681
|
"latest"
|
|
5780
|
-
).option(
|
|
5781
|
-
"--env <env>",
|
|
5782
|
-
"Target environment: dev or prod (default: dev)",
|
|
5783
|
-
"dev"
|
|
5784
|
-
).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
|
|
6682
|
+
).addOption(envOpt()).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
|
|
5785
6683
|
program.command("clone").description("Clone theme source code via the website-api").argument("<theme-name>", "Theme to clone").option(
|
|
5786
6684
|
"-v, --version <version>",
|
|
5787
6685
|
"Theme version (default: latest)",
|
|
5788
6686
|
"latest"
|
|
5789
|
-
).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").option(
|
|
5790
|
-
"--env <env>",
|
|
5791
|
-
"Target environment: dev or prod (default: dev)",
|
|
5792
|
-
"dev"
|
|
5793
|
-
).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
6687
|
+
).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").addOption(envOpt()).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
5794
6688
|
program.command("config").description("Configure OneX CLI credentials (AWS, API keys)").action(configCommand);
|
|
5795
|
-
program.command("login").description("Login to OneX platform").
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
"dev"
|
|
5799
|
-
).action(loginCommand);
|
|
5800
|
-
program.command("logout").description("Logout from OneX platform").option(
|
|
5801
|
-
"--env <env>",
|
|
5802
|
-
"Target environment: dev or prod (default: dev)",
|
|
5803
|
-
"dev"
|
|
5804
|
-
).action(logoutCommand);
|
|
5805
|
-
program.command("whoami").description("Show current logged-in developer").option(
|
|
5806
|
-
"--env <env>",
|
|
5807
|
-
"Target environment: dev or prod (default: dev)",
|
|
5808
|
-
"dev"
|
|
5809
|
-
).action(whoamiCommand);
|
|
6689
|
+
program.command("login").description("Login to OneX platform").addOption(envOpt()).action(loginCommand);
|
|
6690
|
+
program.command("logout").description("Logout from OneX platform").addOption(envOpt()).action(logoutCommand);
|
|
6691
|
+
program.command("whoami").description("Show current logged-in developer").addOption(envOpt()).action(whoamiCommand);
|
|
5810
6692
|
var mcpCmd = program.command("mcp").description("Manage MCP server registration and AI-context files");
|
|
5811
6693
|
mcpCmd.command("setup").description(
|
|
5812
6694
|
"Install .mcp.json + CLAUDE.md + AGENTS.md + .cursorrules into the current theme"
|
|
@@ -5818,10 +6700,15 @@ mcpCmd.command("doctor").description("Diagnose MCP setup in the current theme di
|
|
|
5818
6700
|
program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").option(
|
|
5819
6701
|
"--bump <type>",
|
|
5820
6702
|
"Auto-bump version before publish (patch|minor|major)"
|
|
6703
|
+
).addOption(envOpt()).option(
|
|
6704
|
+
"--dry-run",
|
|
6705
|
+
"Build locally and print the schema-diff classification without publishing"
|
|
6706
|
+
).option(
|
|
6707
|
+
"--confirm-defaults",
|
|
6708
|
+
"Confirm that changed section/block defaults should propagate to live sites"
|
|
5821
6709
|
).option(
|
|
5822
|
-
"--
|
|
5823
|
-
"
|
|
5824
|
-
"dev"
|
|
6710
|
+
"--force",
|
|
6711
|
+
"Publish even when the diff gate detects a breaking change"
|
|
5825
6712
|
).action(publishCommand);
|
|
5826
6713
|
program.configureOutput({
|
|
5827
6714
|
writeErr: (str) => process.stderr.write(chalk4__default.default.red(str))
|