@onexapis/cli 1.1.65 → 1.1.66
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 +1098 -417
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1093 -412
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +413 -194
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +409 -190
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +89 -7
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import chalk4 from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
-
import
|
|
5
|
-
import path9 from 'path';
|
|
6
|
-
import fs8 from 'fs/promises';
|
|
7
|
-
import crypto from 'crypto';
|
|
4
|
+
import path11 from 'path';
|
|
8
5
|
import { glob } from 'glob';
|
|
6
|
+
import fs from 'fs-extra';
|
|
7
|
+
import crypto from 'crypto';
|
|
8
|
+
import * as esbuild from 'esbuild';
|
|
9
|
+
import fs9 from 'fs/promises';
|
|
9
10
|
import { createRequire } from 'module';
|
|
10
11
|
import http from 'http';
|
|
11
12
|
import fs3 from 'fs';
|
|
12
13
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
13
14
|
import os from 'os';
|
|
14
15
|
import dotenv from 'dotenv';
|
|
15
|
-
import fs from 'fs-extra';
|
|
16
16
|
import ejs from 'ejs';
|
|
17
17
|
import { execSync, spawn } from 'child_process';
|
|
18
18
|
import { Command } from 'commander';
|
|
@@ -89,6 +89,206 @@ var init_logger = __esm({
|
|
|
89
89
|
logger = new Logger();
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
|
+
function sortedCopy(value) {
|
|
93
|
+
if (Array.isArray(value)) {
|
|
94
|
+
return value.map((v) => sortedCopy(v));
|
|
95
|
+
}
|
|
96
|
+
if (value && typeof value === "object") {
|
|
97
|
+
const sorted = {};
|
|
98
|
+
for (const key of Object.keys(value).sort()) {
|
|
99
|
+
sorted[key] = sortedCopy(value[key]);
|
|
100
|
+
}
|
|
101
|
+
return sorted;
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
function normalizeField(raw) {
|
|
106
|
+
const out = {
|
|
107
|
+
id: String(raw.id),
|
|
108
|
+
type: String(raw.type)
|
|
109
|
+
};
|
|
110
|
+
if (raw.required === true) out.required = true;
|
|
111
|
+
if (raw.default !== void 0) out.default = raw.default;
|
|
112
|
+
if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
|
|
113
|
+
out.aliases = [...raw.aliases].map(String).sort();
|
|
114
|
+
}
|
|
115
|
+
if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
|
|
116
|
+
if (typeof raw.min === "number") out.min = raw.min;
|
|
117
|
+
if (typeof raw.max === "number") out.max = raw.max;
|
|
118
|
+
if (typeof raw.step === "number") out.step = raw.step;
|
|
119
|
+
if (Array.isArray(raw.accept)) {
|
|
120
|
+
out.accept = [...raw.accept].map(String).sort();
|
|
121
|
+
}
|
|
122
|
+
if (Array.isArray(raw.options)) {
|
|
123
|
+
out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function normalizeBlock(raw) {
|
|
128
|
+
return {
|
|
129
|
+
type: String(raw.type),
|
|
130
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
131
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
132
|
+
...typeof raw.limit === "number" ? { limit: raw.limit } : {},
|
|
133
|
+
...typeof raw.min === "number" ? { min: raw.min } : {},
|
|
134
|
+
...raw.sortable === true ? { sortable: true } : {},
|
|
135
|
+
...raw.baseType ? { baseType: String(raw.baseType) } : {}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function normalizeTemplate(raw) {
|
|
139
|
+
const out = { id: String(raw.id) };
|
|
140
|
+
if (raw.isDefault === true) out.isDefault = true;
|
|
141
|
+
if (Array.isArray(raw.settings)) {
|
|
142
|
+
out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
|
|
143
|
+
}
|
|
144
|
+
if (raw.defaults && typeof raw.defaults === "object") {
|
|
145
|
+
out.defaults = sortedCopy(raw.defaults);
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
function sortFieldsById(a, b) {
|
|
150
|
+
return a.id.localeCompare(b.id);
|
|
151
|
+
}
|
|
152
|
+
function sortByType(a, b) {
|
|
153
|
+
return a.type.localeCompare(b.type);
|
|
154
|
+
}
|
|
155
|
+
function normalizeSection(raw) {
|
|
156
|
+
return {
|
|
157
|
+
type: String(raw.type),
|
|
158
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
159
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
160
|
+
blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
|
|
161
|
+
templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
|
|
162
|
+
dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
|
|
163
|
+
...raw.global === true ? { global: true } : {},
|
|
164
|
+
...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function extractSchemas(themePath) {
|
|
168
|
+
const { createJiti } = await import('jiti');
|
|
169
|
+
const jiti = createJiti(import.meta.url);
|
|
170
|
+
const schemaFiles = await glob("sections/**/*.schema.ts", { cwd: themePath });
|
|
171
|
+
const sections = {};
|
|
172
|
+
for (const file of schemaFiles) {
|
|
173
|
+
try {
|
|
174
|
+
const mod = await jiti.import(path11.join(themePath, file));
|
|
175
|
+
const exports$1 = mod;
|
|
176
|
+
for (const value of Object.values(exports$1)) {
|
|
177
|
+
if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
|
|
178
|
+
const section = normalizeSection(value);
|
|
179
|
+
sections[section.type] = section;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const manifest = {
|
|
186
|
+
manifestVersion: 1,
|
|
187
|
+
sections: {}
|
|
188
|
+
};
|
|
189
|
+
for (const type of Object.keys(sections).sort()) {
|
|
190
|
+
manifest.sections[type] = sections[type];
|
|
191
|
+
}
|
|
192
|
+
return manifest;
|
|
193
|
+
}
|
|
194
|
+
function serializeManifest(manifest) {
|
|
195
|
+
return JSON.stringify(sortedCopy(manifest), null, 2);
|
|
196
|
+
}
|
|
197
|
+
var init_extract_schemas = __esm({
|
|
198
|
+
"src/utils/extract-schemas.ts"() {
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
function isVideoAsset(filePath) {
|
|
202
|
+
const lower = filePath.toLowerCase();
|
|
203
|
+
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
204
|
+
}
|
|
205
|
+
function mimeFor(filename) {
|
|
206
|
+
const ext = path11.extname(filename).toLowerCase();
|
|
207
|
+
return MIME_MAP[ext] || "application/octet-stream";
|
|
208
|
+
}
|
|
209
|
+
async function sha256Prefix(absPath, len) {
|
|
210
|
+
const buf = await fs.readFile(absPath);
|
|
211
|
+
return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
|
|
212
|
+
}
|
|
213
|
+
function insertHashIntoName(relPath, hash) {
|
|
214
|
+
const dir = path11.posix.dirname(relPath);
|
|
215
|
+
const base = path11.posix.basename(relPath);
|
|
216
|
+
const ext = path11.posix.extname(base);
|
|
217
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
218
|
+
const hashed = `${stem}-${hash}${ext}`;
|
|
219
|
+
return dir === "." ? hashed : `${dir}/${hashed}`;
|
|
220
|
+
}
|
|
221
|
+
async function scanThemeAssets(distDir) {
|
|
222
|
+
const assetsDir = path11.join(distDir, "theme-assets");
|
|
223
|
+
if (!await fs.pathExists(assetsDir)) return [];
|
|
224
|
+
const files = await glob("**/*", {
|
|
225
|
+
cwd: assetsDir,
|
|
226
|
+
nodir: true,
|
|
227
|
+
dot: false
|
|
228
|
+
});
|
|
229
|
+
const results = [];
|
|
230
|
+
for (const rel of files) {
|
|
231
|
+
const absPath = path11.join(assetsDir, rel);
|
|
232
|
+
const stat = await fs.stat(absPath);
|
|
233
|
+
if (!stat.isFile()) continue;
|
|
234
|
+
const originalPath = rel.split(path11.sep).join("/");
|
|
235
|
+
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
236
|
+
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
237
|
+
const contentType = mimeFor(rel);
|
|
238
|
+
results.push({
|
|
239
|
+
originalPath,
|
|
240
|
+
hashedPath,
|
|
241
|
+
hash,
|
|
242
|
+
size: stat.size,
|
|
243
|
+
contentType,
|
|
244
|
+
absPath
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
|
|
248
|
+
return results;
|
|
249
|
+
}
|
|
250
|
+
function buildAssetMap(entries) {
|
|
251
|
+
const map = {};
|
|
252
|
+
for (const e of entries) {
|
|
253
|
+
map[e.originalPath] = e.hashedPath;
|
|
254
|
+
}
|
|
255
|
+
return map;
|
|
256
|
+
}
|
|
257
|
+
var MIME_MAP, HASH_LEN, VIDEO_EXTENSIONS;
|
|
258
|
+
var init_scan_theme_assets = __esm({
|
|
259
|
+
"src/utils/scan-theme-assets.ts"() {
|
|
260
|
+
MIME_MAP = {
|
|
261
|
+
".png": "image/png",
|
|
262
|
+
".jpg": "image/jpeg",
|
|
263
|
+
".jpeg": "image/jpeg",
|
|
264
|
+
".gif": "image/gif",
|
|
265
|
+
".webp": "image/webp",
|
|
266
|
+
".avif": "image/avif",
|
|
267
|
+
".svg": "image/svg+xml",
|
|
268
|
+
".ico": "image/x-icon",
|
|
269
|
+
".bmp": "image/bmp",
|
|
270
|
+
".woff": "font/woff",
|
|
271
|
+
".woff2": "font/woff2",
|
|
272
|
+
".ttf": "font/ttf",
|
|
273
|
+
".otf": "font/otf",
|
|
274
|
+
".eot": "application/vnd.ms-fontobject",
|
|
275
|
+
".mp4": "video/mp4",
|
|
276
|
+
".webm": "video/webm",
|
|
277
|
+
".mov": "video/quicktime",
|
|
278
|
+
".ogg": "video/ogg",
|
|
279
|
+
".json": "application/json"
|
|
280
|
+
};
|
|
281
|
+
HASH_LEN = 8;
|
|
282
|
+
VIDEO_EXTENSIONS = [
|
|
283
|
+
".mp4",
|
|
284
|
+
".webm",
|
|
285
|
+
".ogg",
|
|
286
|
+
".mov",
|
|
287
|
+
".avi",
|
|
288
|
+
".mkv"
|
|
289
|
+
];
|
|
290
|
+
}
|
|
291
|
+
});
|
|
92
292
|
|
|
93
293
|
// src/utils/compile-theme.ts
|
|
94
294
|
var compile_theme_exports = {};
|
|
@@ -104,8 +304,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
104
304
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
105
305
|
const tailwindConfig = {
|
|
106
306
|
content: [
|
|
107
|
-
|
|
108
|
-
|
|
307
|
+
path11.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
308
|
+
path11.join(themePath, "components/**/*.{ts,tsx}")
|
|
109
309
|
],
|
|
110
310
|
theme: { extend: {} },
|
|
111
311
|
plugins: []
|
|
@@ -115,7 +315,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
115
315
|
inputCSS,
|
|
116
316
|
{ from: void 0 }
|
|
117
317
|
);
|
|
118
|
-
await
|
|
318
|
+
await fs9.writeFile(path11.join(outDir, "bundle.css"), result.css);
|
|
119
319
|
logger.info("Generated bundle.css");
|
|
120
320
|
} catch (err) {
|
|
121
321
|
logger.warning(
|
|
@@ -126,12 +326,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
126
326
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
127
327
|
let dir = startDir;
|
|
128
328
|
while (true) {
|
|
129
|
-
const candidate =
|
|
329
|
+
const candidate = path11.join(dir, "node_modules", relativePath);
|
|
130
330
|
try {
|
|
131
|
-
await
|
|
331
|
+
await fs9.access(candidate);
|
|
132
332
|
return candidate;
|
|
133
333
|
} catch {
|
|
134
|
-
const parent =
|
|
334
|
+
const parent = path11.dirname(dir);
|
|
135
335
|
if (parent === dir) break;
|
|
136
336
|
dir = parent;
|
|
137
337
|
}
|
|
@@ -155,7 +355,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
155
355
|
});
|
|
156
356
|
for (const file of sourceFiles) {
|
|
157
357
|
try {
|
|
158
|
-
const content = await
|
|
358
|
+
const content = await fs9.readFile(path11.join(sourceDir, file), "utf-8");
|
|
159
359
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
160
360
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
161
361
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -209,17 +409,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
209
409
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
210
410
|
let distPath = await resolveNodeModulesFile(
|
|
211
411
|
themePath,
|
|
212
|
-
|
|
412
|
+
path11.join("@onexapis", "core", "dist", distFileName)
|
|
213
413
|
);
|
|
214
414
|
if (!distPath) {
|
|
215
415
|
distPath = await resolveNodeModulesFile(
|
|
216
416
|
__dirname,
|
|
217
|
-
|
|
417
|
+
path11.join("@onexapis", "core", "dist", distFileName)
|
|
218
418
|
);
|
|
219
419
|
}
|
|
220
420
|
try {
|
|
221
421
|
if (!distPath) throw new Error("not found");
|
|
222
|
-
const distContent = await
|
|
422
|
+
const distContent = await fs9.readFile(distPath, "utf-8");
|
|
223
423
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
224
424
|
for (const m of exportMatches) {
|
|
225
425
|
const names = m[1].split(",").map((n) => {
|
|
@@ -448,7 +648,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
448
648
|
const pages = {};
|
|
449
649
|
for (const ext of [".ts", ".js"]) {
|
|
450
650
|
try {
|
|
451
|
-
const mod = await jiti.import(
|
|
651
|
+
const mod = await jiti.import(path11.join(themePath, `theme.config${ext}`));
|
|
452
652
|
themeConfig = mod.default || mod;
|
|
453
653
|
break;
|
|
454
654
|
} catch {
|
|
@@ -456,20 +656,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
456
656
|
}
|
|
457
657
|
for (const ext of [".ts", ".js"]) {
|
|
458
658
|
try {
|
|
459
|
-
const mod = await jiti.import(
|
|
659
|
+
const mod = await jiti.import(path11.join(themePath, `theme.layout${ext}`));
|
|
460
660
|
layoutConfig = mod.default || mod;
|
|
461
661
|
break;
|
|
462
662
|
} catch {
|
|
463
663
|
}
|
|
464
664
|
}
|
|
465
665
|
const schemas = {};
|
|
466
|
-
const sectionsDir =
|
|
666
|
+
const sectionsDir = path11.join(themePath, "sections");
|
|
467
667
|
try {
|
|
468
|
-
const sectionDirs = await
|
|
668
|
+
const sectionDirs = await fs9.readdir(sectionsDir);
|
|
469
669
|
for (const dir of sectionDirs) {
|
|
470
|
-
const schemaFile =
|
|
670
|
+
const schemaFile = path11.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
471
671
|
try {
|
|
472
|
-
await
|
|
672
|
+
await fs9.access(schemaFile);
|
|
473
673
|
const mod = await jiti.import(schemaFile);
|
|
474
674
|
for (const [key, value] of Object.entries(mod)) {
|
|
475
675
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -481,14 +681,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
481
681
|
}
|
|
482
682
|
} catch {
|
|
483
683
|
}
|
|
484
|
-
const pagesDir =
|
|
684
|
+
const pagesDir = path11.join(themePath, "pages");
|
|
485
685
|
try {
|
|
486
|
-
const files = await
|
|
686
|
+
const files = await fs9.readdir(pagesDir);
|
|
487
687
|
for (const file of files) {
|
|
488
688
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
489
689
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
490
690
|
try {
|
|
491
|
-
const mod = await jiti.import(
|
|
691
|
+
const mod = await jiti.import(path11.join(pagesDir, file));
|
|
492
692
|
const config = mod.default || mod;
|
|
493
693
|
const sections = (config.sections || []).map((section) => {
|
|
494
694
|
const schema = schemas[section.type];
|
|
@@ -516,8 +716,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
516
716
|
}
|
|
517
717
|
} catch {
|
|
518
718
|
}
|
|
519
|
-
await
|
|
520
|
-
|
|
719
|
+
await fs9.writeFile(
|
|
720
|
+
path11.join(outputDir, "theme-data.json"),
|
|
521
721
|
JSON.stringify(
|
|
522
722
|
{
|
|
523
723
|
themeId,
|
|
@@ -540,22 +740,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
540
740
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
541
741
|
}
|
|
542
742
|
async function contentHashEntry(outputDir) {
|
|
543
|
-
const entryPath =
|
|
544
|
-
const mapPath =
|
|
743
|
+
const entryPath = path11.join(outputDir, "bundle-entry.js");
|
|
744
|
+
const mapPath = path11.join(outputDir, "bundle-entry.js.map");
|
|
545
745
|
let entryContent;
|
|
546
746
|
try {
|
|
547
|
-
entryContent = await
|
|
747
|
+
entryContent = await fs9.readFile(entryPath, "utf-8");
|
|
548
748
|
} catch {
|
|
549
|
-
const indexPath =
|
|
749
|
+
const indexPath = path11.join(outputDir, "index.js");
|
|
550
750
|
try {
|
|
551
|
-
entryContent = await
|
|
751
|
+
entryContent = await fs9.readFile(indexPath, "utf-8");
|
|
552
752
|
} catch {
|
|
553
753
|
logger.warning("No entry file found in output, skipping content hash");
|
|
554
754
|
return;
|
|
555
755
|
}
|
|
556
756
|
const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
557
757
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
558
|
-
const indexMapPath =
|
|
758
|
+
const indexMapPath = path11.join(outputDir, "index.js.map");
|
|
559
759
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
560
760
|
entryContent = entryContent.replace(
|
|
561
761
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
@@ -563,18 +763,18 @@ async function contentHashEntry(outputDir) {
|
|
|
563
763
|
);
|
|
564
764
|
const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
565
765
|
for (const f of oldFiles2) {
|
|
566
|
-
await
|
|
766
|
+
await fs9.unlink(path11.join(outputDir, f));
|
|
567
767
|
}
|
|
568
|
-
await
|
|
569
|
-
await
|
|
768
|
+
await fs9.writeFile(path11.join(outputDir, hashedName2), entryContent);
|
|
769
|
+
await fs9.unlink(indexPath);
|
|
570
770
|
try {
|
|
571
|
-
await
|
|
771
|
+
await fs9.unlink(entryPath);
|
|
572
772
|
} catch {
|
|
573
773
|
}
|
|
574
|
-
await
|
|
774
|
+
await fs9.writeFile(entryPath, entryContent);
|
|
575
775
|
try {
|
|
576
|
-
await
|
|
577
|
-
await
|
|
776
|
+
await fs9.access(indexMapPath);
|
|
777
|
+
await fs9.rename(indexMapPath, path11.join(outputDir, hashedMapName2));
|
|
578
778
|
} catch {
|
|
579
779
|
}
|
|
580
780
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
@@ -589,17 +789,17 @@ async function contentHashEntry(outputDir) {
|
|
|
589
789
|
);
|
|
590
790
|
const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
591
791
|
for (const f of oldFiles) {
|
|
592
|
-
await
|
|
792
|
+
await fs9.unlink(path11.join(outputDir, f));
|
|
593
793
|
}
|
|
594
|
-
await
|
|
794
|
+
await fs9.writeFile(path11.join(outputDir, hashedName), entryContent);
|
|
595
795
|
try {
|
|
596
|
-
await
|
|
796
|
+
await fs9.unlink(entryPath);
|
|
597
797
|
} catch {
|
|
598
798
|
}
|
|
599
|
-
await
|
|
799
|
+
await fs9.writeFile(entryPath, entryContent);
|
|
600
800
|
try {
|
|
601
|
-
await
|
|
602
|
-
await
|
|
801
|
+
await fs9.access(mapPath);
|
|
802
|
+
await fs9.rename(mapPath, path11.join(outputDir, hashedMapName));
|
|
603
803
|
} catch {
|
|
604
804
|
}
|
|
605
805
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -611,7 +811,7 @@ async function extractDataRequirements(themePath) {
|
|
|
611
811
|
const requirements = {};
|
|
612
812
|
for (const file of schemaFiles) {
|
|
613
813
|
try {
|
|
614
|
-
const mod = await jiti.import(
|
|
814
|
+
const mod = await jiti.import(path11.join(themePath, file));
|
|
615
815
|
const exports$1 = mod;
|
|
616
816
|
for (const value of Object.values(exports$1)) {
|
|
617
817
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -626,12 +826,46 @@ async function extractDataRequirements(themePath) {
|
|
|
626
826
|
}
|
|
627
827
|
return requirements;
|
|
628
828
|
}
|
|
829
|
+
async function writeGateManifests(themePath, outputDir) {
|
|
830
|
+
try {
|
|
831
|
+
const schemas = await extractSchemas(themePath);
|
|
832
|
+
await fs9.writeFile(
|
|
833
|
+
path11.join(outputDir, "schemas.json"),
|
|
834
|
+
serializeManifest(schemas)
|
|
835
|
+
);
|
|
836
|
+
logger.info(
|
|
837
|
+
`Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
|
|
838
|
+
);
|
|
839
|
+
} catch (err) {
|
|
840
|
+
logger.warning(
|
|
841
|
+
`schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
845
|
+
const entries = await scanThemeAssets(outputDir);
|
|
846
|
+
const assets = entries.map((e) => ({
|
|
847
|
+
path: e.originalPath,
|
|
848
|
+
hash: e.hash,
|
|
849
|
+
size: e.size,
|
|
850
|
+
contentType: e.contentType
|
|
851
|
+
}));
|
|
852
|
+
await fs9.writeFile(
|
|
853
|
+
path11.join(outputDir, "asset-manifest.json"),
|
|
854
|
+
JSON.stringify({ manifestVersion: 1, assets }, null, 2)
|
|
855
|
+
);
|
|
856
|
+
logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
|
|
857
|
+
} catch (err) {
|
|
858
|
+
logger.warning(
|
|
859
|
+
`asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
629
863
|
async function generateManifest(themeName, themePath, outputDir) {
|
|
630
864
|
let version2 = "1.0.0";
|
|
631
865
|
let themeId = themeName;
|
|
632
866
|
try {
|
|
633
|
-
const pkgContent = await
|
|
634
|
-
|
|
867
|
+
const pkgContent = await fs9.readFile(
|
|
868
|
+
path11.join(themePath, "package.json"),
|
|
635
869
|
"utf-8"
|
|
636
870
|
);
|
|
637
871
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -649,7 +883,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
649
883
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
650
884
|
let hasThemeConfig = false;
|
|
651
885
|
try {
|
|
652
|
-
await
|
|
886
|
+
await fs9.access(path11.join(themePath, "theme.config.ts"));
|
|
653
887
|
hasThemeConfig = true;
|
|
654
888
|
} catch {
|
|
655
889
|
}
|
|
@@ -690,24 +924,24 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
690
924
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
691
925
|
dataRequirements
|
|
692
926
|
};
|
|
693
|
-
await
|
|
694
|
-
|
|
927
|
+
await fs9.writeFile(
|
|
928
|
+
path11.join(outputDir, "manifest.json"),
|
|
695
929
|
JSON.stringify(manifest, null, 2)
|
|
696
930
|
);
|
|
697
931
|
}
|
|
698
932
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
699
|
-
const outputDir =
|
|
700
|
-
const bundleEntry =
|
|
701
|
-
const indexEntry =
|
|
933
|
+
const outputDir = path11.join(themePath, "dist");
|
|
934
|
+
const bundleEntry = path11.join(themePath, "bundle-entry.ts");
|
|
935
|
+
const indexEntry = path11.join(themePath, "index.ts");
|
|
702
936
|
let entryPoint = indexEntry;
|
|
703
937
|
try {
|
|
704
|
-
await
|
|
938
|
+
await fs9.access(bundleEntry);
|
|
705
939
|
entryPoint = bundleEntry;
|
|
706
940
|
} catch {
|
|
707
941
|
}
|
|
708
|
-
const shimPath =
|
|
709
|
-
await
|
|
710
|
-
await
|
|
942
|
+
const shimPath = path11.join(outputDir, ".process-shim.js");
|
|
943
|
+
await fs9.mkdir(outputDir, { recursive: true });
|
|
944
|
+
await fs9.writeFile(shimPath, PROCESS_SHIM);
|
|
711
945
|
const buildOptions = {
|
|
712
946
|
entryPoints: [entryPoint],
|
|
713
947
|
bundle: true,
|
|
@@ -758,19 +992,20 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
758
992
|
try {
|
|
759
993
|
const result = await esbuild.build(buildOptions);
|
|
760
994
|
try {
|
|
761
|
-
await
|
|
995
|
+
await fs9.unlink(shimPath);
|
|
762
996
|
} catch {
|
|
763
997
|
}
|
|
764
998
|
await contentHashEntry(outputDir);
|
|
765
|
-
const themeAssetsDir =
|
|
766
|
-
const distThemeAssets =
|
|
999
|
+
const themeAssetsDir = path11.join(themePath, "assets");
|
|
1000
|
+
const distThemeAssets = path11.join(outputDir, "theme-assets");
|
|
767
1001
|
try {
|
|
768
|
-
await
|
|
769
|
-
await
|
|
1002
|
+
await fs9.access(themeAssetsDir);
|
|
1003
|
+
await fs9.cp(themeAssetsDir, distThemeAssets, { recursive: true });
|
|
770
1004
|
logger.info("Copied static assets to dist/theme-assets/");
|
|
771
1005
|
} catch {
|
|
772
1006
|
}
|
|
773
1007
|
await generateManifest(themeName, themePath, outputDir);
|
|
1008
|
+
await writeGateManifests(themePath, outputDir);
|
|
774
1009
|
await generateThemeData(themePath, outputDir, themeName);
|
|
775
1010
|
await generateThemeCSS(themePath, outputDir);
|
|
776
1011
|
if (result.metafile) {
|
|
@@ -785,7 +1020,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
785
1020
|
return true;
|
|
786
1021
|
} catch (error) {
|
|
787
1022
|
try {
|
|
788
|
-
await
|
|
1023
|
+
await fs9.unlink(shimPath);
|
|
789
1024
|
} catch {
|
|
790
1025
|
}
|
|
791
1026
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -793,18 +1028,18 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
793
1028
|
}
|
|
794
1029
|
}
|
|
795
1030
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
796
|
-
const outputDir =
|
|
797
|
-
const bundleEntry =
|
|
798
|
-
const indexEntry =
|
|
1031
|
+
const outputDir = path11.join(themePath, "dist");
|
|
1032
|
+
const bundleEntry = path11.join(themePath, "bundle-entry.ts");
|
|
1033
|
+
const indexEntry = path11.join(themePath, "index.ts");
|
|
799
1034
|
let entryPoint = indexEntry;
|
|
800
1035
|
try {
|
|
801
|
-
await
|
|
1036
|
+
await fs9.access(bundleEntry);
|
|
802
1037
|
entryPoint = bundleEntry;
|
|
803
1038
|
} catch {
|
|
804
1039
|
}
|
|
805
|
-
const shimPath =
|
|
806
|
-
await
|
|
807
|
-
await
|
|
1040
|
+
const shimPath = path11.join(outputDir, ".process-shim.js");
|
|
1041
|
+
await fs9.mkdir(outputDir, { recursive: true });
|
|
1042
|
+
await fs9.writeFile(shimPath, PROCESS_SHIM);
|
|
808
1043
|
const buildOptions = {
|
|
809
1044
|
entryPoints: [entryPoint],
|
|
810
1045
|
bundle: true,
|
|
@@ -858,18 +1093,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
858
1093
|
return { context: context2, outputDir };
|
|
859
1094
|
}
|
|
860
1095
|
async function compilePreviewRuntime(themePath) {
|
|
861
|
-
const outputDir =
|
|
862
|
-
await
|
|
863
|
-
const outputPath =
|
|
1096
|
+
const outputDir = path11.join(themePath, "dist");
|
|
1097
|
+
await fs9.mkdir(outputDir, { recursive: true });
|
|
1098
|
+
const outputPath = path11.join(outputDir, "preview-runtime.js");
|
|
864
1099
|
const locations = [
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1100
|
+
path11.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
1101
|
+
path11.join(__dirname, "preview", "preview-app.tsx"),
|
|
1102
|
+
path11.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
868
1103
|
];
|
|
869
1104
|
let previewEntryPath = null;
|
|
870
1105
|
for (const loc of locations) {
|
|
871
1106
|
try {
|
|
872
|
-
await
|
|
1107
|
+
await fs9.access(loc);
|
|
873
1108
|
previewEntryPath = loc;
|
|
874
1109
|
break;
|
|
875
1110
|
} catch {
|
|
@@ -952,10 +1187,10 @@ ${locations.join("\n")}`
|
|
|
952
1187
|
if (!lucideScanned) {
|
|
953
1188
|
lucideScanned = true;
|
|
954
1189
|
const coreSrcCandidates = [
|
|
955
|
-
|
|
956
|
-
|
|
1190
|
+
path11.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
1191
|
+
path11.join(themePath, "..", "..", "packages", "core", "src"),
|
|
957
1192
|
// monorepo sibling
|
|
958
|
-
|
|
1193
|
+
path11.join(
|
|
959
1194
|
__dirname,
|
|
960
1195
|
"..",
|
|
961
1196
|
"..",
|
|
@@ -970,7 +1205,7 @@ ${locations.join("\n")}`
|
|
|
970
1205
|
let coreSourceDir = null;
|
|
971
1206
|
for (const candidate of coreSrcCandidates) {
|
|
972
1207
|
try {
|
|
973
|
-
await
|
|
1208
|
+
await fs9.access(candidate);
|
|
974
1209
|
coreSourceDir = candidate;
|
|
975
1210
|
break;
|
|
976
1211
|
} catch {
|
|
@@ -989,21 +1224,21 @@ ${locations.join("\n")}`
|
|
|
989
1224
|
}
|
|
990
1225
|
} else {
|
|
991
1226
|
const coreDistCandidates = [
|
|
992
|
-
|
|
1227
|
+
path11.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
993
1228
|
];
|
|
994
1229
|
const resolvedDist = await resolveNodeModulesFile(
|
|
995
1230
|
__dirname,
|
|
996
|
-
|
|
1231
|
+
path11.join("@onexapis", "core", "dist")
|
|
997
1232
|
);
|
|
998
1233
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
999
1234
|
for (const candidate of coreDistCandidates) {
|
|
1000
1235
|
try {
|
|
1001
|
-
await
|
|
1236
|
+
await fs9.access(candidate);
|
|
1002
1237
|
const mjsFiles = await glob("*.mjs", { cwd: candidate });
|
|
1003
1238
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
1004
1239
|
for (const file of mjsFiles) {
|
|
1005
|
-
const content = await
|
|
1006
|
-
|
|
1240
|
+
const content = await fs9.readFile(
|
|
1241
|
+
path11.join(candidate, file),
|
|
1007
1242
|
"utf-8"
|
|
1008
1243
|
);
|
|
1009
1244
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1058,7 +1293,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1058
1293
|
const req = createRequire(import.meta.url || __filename);
|
|
1059
1294
|
const cjsPath = req.resolve("framer-motion");
|
|
1060
1295
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1061
|
-
const esmEntry =
|
|
1296
|
+
const esmEntry = path11.join(pkgDir, "dist", "es", "index.mjs");
|
|
1062
1297
|
const { existsSync } = await import('fs');
|
|
1063
1298
|
if (existsSync(esmEntry)) {
|
|
1064
1299
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1157,8 +1392,8 @@ export function headers() { return new Headers(); }
|
|
|
1157
1392
|
});
|
|
1158
1393
|
}
|
|
1159
1394
|
};
|
|
1160
|
-
const shimPath =
|
|
1161
|
-
await
|
|
1395
|
+
const shimPath = path11.join(outputDir, ".process-shim-preview.js");
|
|
1396
|
+
await fs9.writeFile(shimPath, PROCESS_SHIM);
|
|
1162
1397
|
await esbuild.build({
|
|
1163
1398
|
entryPoints: [previewEntryPath],
|
|
1164
1399
|
bundle: true,
|
|
@@ -1193,7 +1428,7 @@ export function headers() { return new Headers(); }
|
|
|
1193
1428
|
}
|
|
1194
1429
|
});
|
|
1195
1430
|
try {
|
|
1196
|
-
await
|
|
1431
|
+
await fs9.unlink(shimPath);
|
|
1197
1432
|
} catch {
|
|
1198
1433
|
}
|
|
1199
1434
|
return outputPath;
|
|
@@ -1202,6 +1437,8 @@ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
|
|
|
1202
1437
|
var init_compile_theme = __esm({
|
|
1203
1438
|
"src/utils/compile-theme.ts"() {
|
|
1204
1439
|
init_logger();
|
|
1440
|
+
init_extract_schemas();
|
|
1441
|
+
init_scan_theme_assets();
|
|
1205
1442
|
PROCESS_SHIM = `
|
|
1206
1443
|
if (typeof process === "undefined") {
|
|
1207
1444
|
globalThis.process = {
|
|
@@ -1357,7 +1594,7 @@ __export(dev_server_exports, {
|
|
|
1357
1594
|
});
|
|
1358
1595
|
function createDevServer(options) {
|
|
1359
1596
|
const clients = /* @__PURE__ */ new Set();
|
|
1360
|
-
const themeDataPath =
|
|
1597
|
+
const themeDataPath = path11.join(options.distDir, "theme-data.json");
|
|
1361
1598
|
const server = http.createServer((req, res) => {
|
|
1362
1599
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1363
1600
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -1383,8 +1620,8 @@ function createDevServer(options) {
|
|
|
1383
1620
|
if (pathname.startsWith("/_assets/")) {
|
|
1384
1621
|
const parts = pathname.replace(/^\/_assets\//, "").split("/");
|
|
1385
1622
|
const assetSubpath = parts.slice(1).join("/");
|
|
1386
|
-
const assetPath =
|
|
1387
|
-
if (!assetPath.startsWith(
|
|
1623
|
+
const assetPath = path11.join(options.themePath, "assets", assetSubpath);
|
|
1624
|
+
if (!assetPath.startsWith(path11.join(options.themePath, "assets"))) {
|
|
1388
1625
|
res.writeHead(403);
|
|
1389
1626
|
res.end("Forbidden");
|
|
1390
1627
|
return;
|
|
@@ -1395,8 +1632,8 @@ function createDevServer(options) {
|
|
|
1395
1632
|
if (pathname.startsWith("/themes/")) {
|
|
1396
1633
|
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
1397
1634
|
if (match) {
|
|
1398
|
-
const assetPath =
|
|
1399
|
-
if (!assetPath.startsWith(
|
|
1635
|
+
const assetPath = path11.join(options.themePath, "assets", match[1]);
|
|
1636
|
+
if (!assetPath.startsWith(path11.join(options.themePath, "assets"))) {
|
|
1400
1637
|
res.writeHead(403);
|
|
1401
1638
|
res.end("Forbidden");
|
|
1402
1639
|
return;
|
|
@@ -1408,26 +1645,26 @@ function createDevServer(options) {
|
|
|
1408
1645
|
if (pathname.startsWith("/assets/")) {
|
|
1409
1646
|
const subpath = pathname.replace(/^\/assets\//, "");
|
|
1410
1647
|
const segments = subpath.split("/");
|
|
1411
|
-
const assetsBase =
|
|
1648
|
+
const assetsBase = path11.join(options.themePath, "assets");
|
|
1412
1649
|
let assetPath;
|
|
1413
1650
|
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
1414
|
-
assetPath =
|
|
1651
|
+
assetPath = path11.join(assetsBase, segments.slice(1).join("/"));
|
|
1415
1652
|
} else {
|
|
1416
|
-
assetPath =
|
|
1653
|
+
assetPath = path11.join(assetsBase, subpath);
|
|
1417
1654
|
}
|
|
1418
1655
|
if (assetPath.startsWith(assetsBase) && fs3.existsSync(assetPath)) {
|
|
1419
1656
|
serveFile(res, assetPath);
|
|
1420
1657
|
return;
|
|
1421
1658
|
}
|
|
1422
1659
|
if (segments.length > 1) {
|
|
1423
|
-
const fallbackPath =
|
|
1660
|
+
const fallbackPath = path11.join(assetsBase, segments.slice(1).join("/"));
|
|
1424
1661
|
if (fallbackPath.startsWith(assetsBase) && fs3.existsSync(fallbackPath)) {
|
|
1425
1662
|
serveFile(res, fallbackPath);
|
|
1426
1663
|
return;
|
|
1427
1664
|
}
|
|
1428
1665
|
}
|
|
1429
1666
|
}
|
|
1430
|
-
const filePath =
|
|
1667
|
+
const filePath = path11.join(options.distDir, pathname);
|
|
1431
1668
|
if (!filePath.startsWith(options.distDir)) {
|
|
1432
1669
|
res.writeHead(403);
|
|
1433
1670
|
res.end("Forbidden");
|
|
@@ -1470,7 +1707,7 @@ function serveFile(res, filePath) {
|
|
|
1470
1707
|
res.end("Not Found");
|
|
1471
1708
|
return;
|
|
1472
1709
|
}
|
|
1473
|
-
const ext =
|
|
1710
|
+
const ext = path11.extname(filePath);
|
|
1474
1711
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1475
1712
|
const content = fs3.readFileSync(filePath);
|
|
1476
1713
|
res.writeHead(200, { "Content-Type": contentType });
|
|
@@ -1591,18 +1828,18 @@ async function renderTemplate(templatePath, data) {
|
|
|
1591
1828
|
return ejs.render(template, data);
|
|
1592
1829
|
}
|
|
1593
1830
|
async function writeFile(filePath, content) {
|
|
1594
|
-
await fs.ensureDir(
|
|
1831
|
+
await fs.ensureDir(path11.dirname(filePath));
|
|
1595
1832
|
await fs.writeFile(filePath, content, "utf-8");
|
|
1596
1833
|
}
|
|
1597
1834
|
function getTemplatesDir() {
|
|
1598
1835
|
const locations = [
|
|
1599
|
-
|
|
1836
|
+
path11.join(__dirname, "../../templates"),
|
|
1600
1837
|
// Development
|
|
1601
|
-
|
|
1838
|
+
path11.join(__dirname, "../templates"),
|
|
1602
1839
|
// Production (dist/)
|
|
1603
|
-
|
|
1840
|
+
path11.join(process.cwd(), "templates"),
|
|
1604
1841
|
// Fallback
|
|
1605
|
-
|
|
1842
|
+
path11.join(process.cwd(), "packages/cli/templates")
|
|
1606
1843
|
// Monorepo
|
|
1607
1844
|
];
|
|
1608
1845
|
for (const location of locations) {
|
|
@@ -1614,7 +1851,7 @@ function getTemplatesDir() {
|
|
|
1614
1851
|
}
|
|
1615
1852
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1616
1853
|
const templatesDir = getTemplatesDir();
|
|
1617
|
-
const templateDir =
|
|
1854
|
+
const templateDir = path11.join(templatesDir, templateName);
|
|
1618
1855
|
if (!fs.existsSync(templateDir)) {
|
|
1619
1856
|
throw new Error(
|
|
1620
1857
|
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
|
|
@@ -1623,8 +1860,8 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1623
1860
|
await fs.ensureDir(targetDir);
|
|
1624
1861
|
const files = await fs.readdir(templateDir);
|
|
1625
1862
|
for (const file of files) {
|
|
1626
|
-
const templatePath =
|
|
1627
|
-
const targetPath =
|
|
1863
|
+
const templatePath = path11.join(templateDir, file);
|
|
1864
|
+
const targetPath = path11.join(targetDir, file);
|
|
1628
1865
|
const stat = await fs.stat(templatePath);
|
|
1629
1866
|
if (stat.isDirectory()) {
|
|
1630
1867
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1641,8 +1878,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1641
1878
|
await fs.ensureDir(targetDir);
|
|
1642
1879
|
const files = await fs.readdir(templateDir);
|
|
1643
1880
|
for (const file of files) {
|
|
1644
|
-
const templatePath =
|
|
1645
|
-
const targetPath =
|
|
1881
|
+
const templatePath = path11.join(templateDir, file);
|
|
1882
|
+
const targetPath = path11.join(targetDir, file);
|
|
1646
1883
|
const stat = await fs.stat(templatePath);
|
|
1647
1884
|
if (stat.isDirectory()) {
|
|
1648
1885
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1657,32 +1894,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1657
1894
|
}
|
|
1658
1895
|
function getProjectRoot() {
|
|
1659
1896
|
let currentDir = process.cwd();
|
|
1660
|
-
while (currentDir !==
|
|
1661
|
-
const packageJsonPath =
|
|
1897
|
+
while (currentDir !== path11.parse(currentDir).root) {
|
|
1898
|
+
const packageJsonPath = path11.join(currentDir, "package.json");
|
|
1662
1899
|
if (fs.existsSync(packageJsonPath)) {
|
|
1663
1900
|
const packageJson = fs.readJsonSync(packageJsonPath);
|
|
1664
|
-
if (packageJson.workspaces || fs.existsSync(
|
|
1901
|
+
if (packageJson.workspaces || fs.existsSync(path11.join(currentDir, "src/themes")) || fs.existsSync(path11.join(currentDir, "themes"))) {
|
|
1665
1902
|
return currentDir;
|
|
1666
1903
|
}
|
|
1667
1904
|
}
|
|
1668
|
-
currentDir =
|
|
1905
|
+
currentDir = path11.dirname(currentDir);
|
|
1669
1906
|
}
|
|
1670
1907
|
return process.cwd();
|
|
1671
1908
|
}
|
|
1672
1909
|
function getThemesDir() {
|
|
1673
1910
|
const root = getProjectRoot();
|
|
1674
|
-
if (fs.existsSync(
|
|
1675
|
-
return
|
|
1676
|
-
if (fs.existsSync(
|
|
1677
|
-
return
|
|
1678
|
-
return
|
|
1911
|
+
if (fs.existsSync(path11.join(root, "themes")))
|
|
1912
|
+
return path11.join(root, "themes");
|
|
1913
|
+
if (fs.existsSync(path11.join(root, "src/themes")))
|
|
1914
|
+
return path11.join(root, "src/themes");
|
|
1915
|
+
return path11.dirname(root);
|
|
1679
1916
|
}
|
|
1680
1917
|
function getFeaturesDir() {
|
|
1681
|
-
return
|
|
1918
|
+
return path11.join(getProjectRoot(), "src/features");
|
|
1682
1919
|
}
|
|
1683
1920
|
function isOneXProject() {
|
|
1684
1921
|
const root = getProjectRoot();
|
|
1685
|
-
return fs.existsSync(
|
|
1922
|
+
return fs.existsSync(path11.join(root, "themes")) || fs.existsSync(path11.join(root, "src/themes")) || fs.existsSync(path11.join(root, "theme.config.ts")) || fs.existsSync(path11.join(root, "bundle-entry.ts"));
|
|
1686
1923
|
}
|
|
1687
1924
|
function ensureOneXProject() {
|
|
1688
1925
|
if (!isOneXProject()) {
|
|
@@ -1698,13 +1935,13 @@ function listThemes() {
|
|
|
1698
1935
|
return [];
|
|
1699
1936
|
}
|
|
1700
1937
|
return fs.readdirSync(themesDir).filter((name) => {
|
|
1701
|
-
const themePath =
|
|
1702
|
-
return fs.statSync(themePath).isDirectory() && (fs.existsSync(
|
|
1938
|
+
const themePath = path11.join(themesDir, name);
|
|
1939
|
+
return fs.statSync(themePath).isDirectory() && (fs.existsSync(path11.join(themePath, "theme.config.ts")) || fs.existsSync(path11.join(themePath, "bundle-entry.ts")) || fs.existsSync(path11.join(themePath, "manifest.ts")));
|
|
1703
1940
|
});
|
|
1704
1941
|
}
|
|
1705
1942
|
function themeExists(themeName) {
|
|
1706
|
-
const themePath =
|
|
1707
|
-
return fs.existsSync(themePath) && (fs.existsSync(
|
|
1943
|
+
const themePath = path11.join(getThemesDir(), themeName);
|
|
1944
|
+
return fs.existsSync(themePath) && (fs.existsSync(path11.join(themePath, "theme.config.ts")) || fs.existsSync(path11.join(themePath, "bundle-entry.ts")) || fs.existsSync(path11.join(themePath, "manifest.ts")));
|
|
1708
1945
|
}
|
|
1709
1946
|
function detectPackageManager() {
|
|
1710
1947
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1712,9 +1949,9 @@ function detectPackageManager() {
|
|
|
1712
1949
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1713
1950
|
if (userAgent.includes("bun")) return "bun";
|
|
1714
1951
|
const cwd = process.cwd();
|
|
1715
|
-
if (fs.existsSync(
|
|
1716
|
-
if (fs.existsSync(
|
|
1717
|
-
if (fs.existsSync(
|
|
1952
|
+
if (fs.existsSync(path11.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1953
|
+
if (fs.existsSync(path11.join(cwd, "yarn.lock"))) return "yarn";
|
|
1954
|
+
if (fs.existsSync(path11.join(cwd, "bun.lockb"))) return "bun";
|
|
1718
1955
|
return "npm";
|
|
1719
1956
|
}
|
|
1720
1957
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1763,15 +2000,16 @@ function getValidCategories() {
|
|
|
1763
2000
|
"contact"
|
|
1764
2001
|
];
|
|
1765
2002
|
}
|
|
1766
|
-
var AUTH_DIR =
|
|
2003
|
+
var AUTH_DIR = path11.join(os.homedir(), ".onexthm");
|
|
1767
2004
|
var ENV_URLS = {
|
|
1768
2005
|
dev: "https://platform-dev.onexeos.com",
|
|
1769
|
-
|
|
2006
|
+
staging: "https://platform-staging.onexeos.com",
|
|
2007
|
+
prod: "https://platform-apis.onexeos.com"
|
|
1770
2008
|
};
|
|
1771
2009
|
function getAuthFile(env = "dev") {
|
|
1772
|
-
const newFile =
|
|
2010
|
+
const newFile = path11.join(AUTH_DIR, `auth-${env}.json`);
|
|
1773
2011
|
if (env === "dev") {
|
|
1774
|
-
const legacyFile =
|
|
2012
|
+
const legacyFile = path11.join(AUTH_DIR, "auth.json");
|
|
1775
2013
|
if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
|
|
1776
2014
|
try {
|
|
1777
2015
|
fs.moveSync(legacyFile, newFile);
|
|
@@ -1922,7 +2160,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1922
2160
|
if (!validateThemeName(kebabName)) {
|
|
1923
2161
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1924
2162
|
}
|
|
1925
|
-
if (fs3.existsSync(
|
|
2163
|
+
if (fs3.existsSync(path11.join(process.cwd(), kebabName))) {
|
|
1926
2164
|
return `Directory "${kebabName}" already exists`;
|
|
1927
2165
|
}
|
|
1928
2166
|
return true;
|
|
@@ -1933,7 +2171,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1933
2171
|
} else {
|
|
1934
2172
|
name = toKebabCase(projectName);
|
|
1935
2173
|
}
|
|
1936
|
-
const projectPath =
|
|
2174
|
+
const projectPath = path11.join(process.cwd(), name);
|
|
1937
2175
|
if (fs3.existsSync(projectPath)) {
|
|
1938
2176
|
logger.error(`Directory "${name}" already exists.`);
|
|
1939
2177
|
process.exit(1);
|
|
@@ -2049,7 +2287,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2049
2287
|
description,
|
|
2050
2288
|
author
|
|
2051
2289
|
);
|
|
2052
|
-
const mcpJsonPath =
|
|
2290
|
+
const mcpJsonPath = path11.join(projectPath, ".mcp.json");
|
|
2053
2291
|
if (fs3.existsSync(mcpJsonPath)) {
|
|
2054
2292
|
let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
|
|
2055
2293
|
if (figmaApiKey) {
|
|
@@ -2129,7 +2367,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2129
2367
|
}
|
|
2130
2368
|
}
|
|
2131
2369
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
2132
|
-
const configPath =
|
|
2370
|
+
const configPath = path11.join(projectPath, "theme.config.ts");
|
|
2133
2371
|
if (fs3.existsSync(configPath)) {
|
|
2134
2372
|
let content = fs3.readFileSync(configPath, "utf-8");
|
|
2135
2373
|
content = content.replace(
|
|
@@ -2142,7 +2380,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
2142
2380
|
);
|
|
2143
2381
|
fs3.writeFileSync(configPath, content, "utf-8");
|
|
2144
2382
|
}
|
|
2145
|
-
const pkgPath =
|
|
2383
|
+
const pkgPath = path11.join(projectPath, "package.json");
|
|
2146
2384
|
if (fs3.existsSync(pkgPath)) {
|
|
2147
2385
|
let content = fs3.readFileSync(pkgPath, "utf-8");
|
|
2148
2386
|
content = content.replace(
|
|
@@ -2164,10 +2402,10 @@ async function createSectionCommand(name, options) {
|
|
|
2164
2402
|
ensureOneXProject();
|
|
2165
2403
|
if (!options.theme) {
|
|
2166
2404
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2167
|
-
(f) => fs.existsSync(
|
|
2405
|
+
(f) => fs.existsSync(path11.join(process.cwd(), f))
|
|
2168
2406
|
);
|
|
2169
2407
|
if (isStandaloneTheme) {
|
|
2170
|
-
options.theme =
|
|
2408
|
+
options.theme = path11.basename(process.cwd());
|
|
2171
2409
|
}
|
|
2172
2410
|
}
|
|
2173
2411
|
const sectionName = toKebabCase(name);
|
|
@@ -2230,35 +2468,35 @@ async function createSectionCommand(name, options) {
|
|
|
2230
2468
|
};
|
|
2231
2469
|
logger.startSpinner("Creating section files...");
|
|
2232
2470
|
try {
|
|
2233
|
-
const themePath =
|
|
2234
|
-
const sectionPath =
|
|
2471
|
+
const themePath = path11.join(getThemesDir(), themeName);
|
|
2472
|
+
const sectionPath = path11.join(themePath, "sections", sectionName);
|
|
2235
2473
|
const schemaContent = generateSectionSchema(data);
|
|
2236
2474
|
await writeFile(
|
|
2237
|
-
|
|
2475
|
+
path11.join(sectionPath, `${sectionName}.schema.ts`),
|
|
2238
2476
|
schemaContent
|
|
2239
2477
|
);
|
|
2240
2478
|
if (createTemplate) {
|
|
2241
2479
|
const templateContent = generateSectionTemplate(data);
|
|
2242
2480
|
await writeFile(
|
|
2243
|
-
|
|
2481
|
+
path11.join(sectionPath, `${sectionName}-default.tsx`),
|
|
2244
2482
|
templateContent
|
|
2245
2483
|
);
|
|
2246
2484
|
}
|
|
2247
2485
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
2248
|
-
await writeFile(
|
|
2486
|
+
await writeFile(path11.join(sectionPath, "index.ts"), indexContent);
|
|
2249
2487
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
2250
2488
|
logger.newLine();
|
|
2251
2489
|
logger.section("Next steps:");
|
|
2252
2490
|
logger.log(
|
|
2253
|
-
` 1. Edit schema: ${
|
|
2491
|
+
` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
2254
2492
|
);
|
|
2255
2493
|
if (createTemplate) {
|
|
2256
2494
|
logger.log(
|
|
2257
|
-
` 2. Edit template: ${
|
|
2495
|
+
` 2. Edit template: ${path11.relative(process.cwd(), path11.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
2258
2496
|
);
|
|
2259
2497
|
}
|
|
2260
2498
|
logger.log(
|
|
2261
|
-
` 3. Add to theme manifest: ${
|
|
2499
|
+
` 3. Add to theme manifest: ${path11.relative(process.cwd(), path11.join(themePath, "manifest.ts"))}`
|
|
2262
2500
|
);
|
|
2263
2501
|
logger.newLine();
|
|
2264
2502
|
logger.success("Section created successfully!");
|
|
@@ -2406,10 +2644,10 @@ async function createBlockCommand(name, options) {
|
|
|
2406
2644
|
ensureOneXProject();
|
|
2407
2645
|
if (!options.theme) {
|
|
2408
2646
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2409
|
-
(f) => fs.existsSync(
|
|
2647
|
+
(f) => fs.existsSync(path11.join(process.cwd(), f))
|
|
2410
2648
|
);
|
|
2411
2649
|
if (isStandaloneTheme) {
|
|
2412
|
-
options.theme =
|
|
2650
|
+
options.theme = path11.basename(process.cwd());
|
|
2413
2651
|
}
|
|
2414
2652
|
}
|
|
2415
2653
|
const blockName = toKebabCase(name);
|
|
@@ -2484,24 +2722,24 @@ async function createBlockCommand(name, options) {
|
|
|
2484
2722
|
};
|
|
2485
2723
|
logger.startSpinner("Creating block files...");
|
|
2486
2724
|
try {
|
|
2487
|
-
const blockPath = scope === "shared" ?
|
|
2725
|
+
const blockPath = scope === "shared" ? path11.join(getFeaturesDir(), "blocks", blockName) : path11.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2488
2726
|
const schemaContent = generateBlockSchema(data);
|
|
2489
2727
|
await writeFile(
|
|
2490
|
-
|
|
2728
|
+
path11.join(blockPath, `${blockName}.schema.ts`),
|
|
2491
2729
|
schemaContent
|
|
2492
2730
|
);
|
|
2493
2731
|
const componentContent = generateBlockComponent(data);
|
|
2494
|
-
await writeFile(
|
|
2732
|
+
await writeFile(path11.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2495
2733
|
const indexContent = generateBlockIndex(data);
|
|
2496
|
-
await writeFile(
|
|
2734
|
+
await writeFile(path11.join(blockPath, "index.ts"), indexContent);
|
|
2497
2735
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2498
2736
|
logger.newLine();
|
|
2499
2737
|
logger.section("Next steps:");
|
|
2500
2738
|
logger.log(
|
|
2501
|
-
` 1. Edit schema: ${
|
|
2739
|
+
` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2502
2740
|
);
|
|
2503
2741
|
logger.log(
|
|
2504
|
-
` 2. Edit component: ${
|
|
2742
|
+
` 2. Edit component: ${path11.relative(process.cwd(), path11.join(blockPath, `${blockName}.tsx`))}`
|
|
2505
2743
|
);
|
|
2506
2744
|
logger.log(
|
|
2507
2745
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2679,31 +2917,31 @@ async function createComponentCommand(name, options) {
|
|
|
2679
2917
|
};
|
|
2680
2918
|
logger.startSpinner("Creating component files...");
|
|
2681
2919
|
try {
|
|
2682
|
-
const componentPath =
|
|
2920
|
+
const componentPath = path11.join(
|
|
2683
2921
|
getFeaturesDir(),
|
|
2684
2922
|
"components",
|
|
2685
2923
|
componentName
|
|
2686
2924
|
);
|
|
2687
2925
|
const schemaContent = generateComponentSchema(data);
|
|
2688
2926
|
await writeFile(
|
|
2689
|
-
|
|
2927
|
+
path11.join(componentPath, `${componentName}.schema.ts`),
|
|
2690
2928
|
schemaContent
|
|
2691
2929
|
);
|
|
2692
2930
|
const componentContent = generateComponent(data);
|
|
2693
2931
|
await writeFile(
|
|
2694
|
-
|
|
2932
|
+
path11.join(componentPath, `${componentName}.tsx`),
|
|
2695
2933
|
componentContent
|
|
2696
2934
|
);
|
|
2697
2935
|
const indexContent = generateComponentIndex(data);
|
|
2698
|
-
await writeFile(
|
|
2936
|
+
await writeFile(path11.join(componentPath, "index.ts"), indexContent);
|
|
2699
2937
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2700
2938
|
logger.newLine();
|
|
2701
2939
|
logger.section("Next steps:");
|
|
2702
2940
|
logger.log(
|
|
2703
|
-
` 1. Edit schema: ${
|
|
2941
|
+
` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2704
2942
|
);
|
|
2705
2943
|
logger.log(
|
|
2706
|
-
` 2. Edit component: ${
|
|
2944
|
+
` 2. Edit component: ${path11.relative(process.cwd(), path11.join(componentPath, `${componentName}.tsx`))}`
|
|
2707
2945
|
);
|
|
2708
2946
|
logger.log(
|
|
2709
2947
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2860,13 +3098,13 @@ async function listSections(themeFilter) {
|
|
|
2860
3098
|
return;
|
|
2861
3099
|
}
|
|
2862
3100
|
for (const theme of themes) {
|
|
2863
|
-
const sectionsDir =
|
|
3101
|
+
const sectionsDir = path11.join(getThemesDir(), theme, "sections");
|
|
2864
3102
|
if (!fs.existsSync(sectionsDir)) {
|
|
2865
3103
|
continue;
|
|
2866
3104
|
}
|
|
2867
3105
|
const sections = fs.readdirSync(sectionsDir).filter((name) => {
|
|
2868
|
-
const sectionPath =
|
|
2869
|
-
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(
|
|
3106
|
+
const sectionPath = path11.join(sectionsDir, name);
|
|
3107
|
+
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path11.join(sectionPath, "index.ts"));
|
|
2870
3108
|
});
|
|
2871
3109
|
if (sections.length > 0) {
|
|
2872
3110
|
logger.log(chalk4.cyan(`
|
|
@@ -2880,11 +3118,11 @@ async function listSections(themeFilter) {
|
|
|
2880
3118
|
}
|
|
2881
3119
|
async function listBlocks(themeFilter) {
|
|
2882
3120
|
logger.section("\u{1F9F1} Blocks");
|
|
2883
|
-
const sharedBlocksDir =
|
|
3121
|
+
const sharedBlocksDir = path11.join(getFeaturesDir(), "blocks");
|
|
2884
3122
|
if (fs.existsSync(sharedBlocksDir)) {
|
|
2885
3123
|
const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
|
|
2886
|
-
const blockPath =
|
|
2887
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
3124
|
+
const blockPath = path11.join(sharedBlocksDir, name);
|
|
3125
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path11.join(blockPath, "index.ts"));
|
|
2888
3126
|
});
|
|
2889
3127
|
if (sharedBlocks.length > 0) {
|
|
2890
3128
|
logger.log(chalk4.cyan("\n Shared:"));
|
|
@@ -2895,13 +3133,13 @@ async function listBlocks(themeFilter) {
|
|
|
2895
3133
|
}
|
|
2896
3134
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2897
3135
|
for (const theme of themes) {
|
|
2898
|
-
const blocksDir =
|
|
3136
|
+
const blocksDir = path11.join(getThemesDir(), theme, "blocks");
|
|
2899
3137
|
if (!fs.existsSync(blocksDir)) {
|
|
2900
3138
|
continue;
|
|
2901
3139
|
}
|
|
2902
3140
|
const blocks = fs.readdirSync(blocksDir).filter((name) => {
|
|
2903
|
-
const blockPath =
|
|
2904
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
3141
|
+
const blockPath = path11.join(blocksDir, name);
|
|
3142
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path11.join(blockPath, "index.ts"));
|
|
2905
3143
|
});
|
|
2906
3144
|
if (blocks.length > 0) {
|
|
2907
3145
|
logger.log(chalk4.cyan(`
|
|
@@ -2915,14 +3153,14 @@ async function listBlocks(themeFilter) {
|
|
|
2915
3153
|
}
|
|
2916
3154
|
async function listComponents() {
|
|
2917
3155
|
logger.section("\u2699\uFE0F Components");
|
|
2918
|
-
const componentsDir =
|
|
3156
|
+
const componentsDir = path11.join(getFeaturesDir(), "components");
|
|
2919
3157
|
if (!fs.existsSync(componentsDir)) {
|
|
2920
3158
|
logger.warning("No components directory found");
|
|
2921
3159
|
return;
|
|
2922
3160
|
}
|
|
2923
3161
|
const components = fs.readdirSync(componentsDir).filter((name) => {
|
|
2924
|
-
const componentPath =
|
|
2925
|
-
return fs.statSync(componentPath).isDirectory() && fs.existsSync(
|
|
3162
|
+
const componentPath = path11.join(componentsDir, name);
|
|
3163
|
+
return fs.statSync(componentPath).isDirectory() && fs.existsSync(path11.join(componentPath, "index.ts"));
|
|
2926
3164
|
});
|
|
2927
3165
|
if (components.length === 0) {
|
|
2928
3166
|
logger.warning("No components found");
|
|
@@ -2943,11 +3181,11 @@ async function listThemesInfo() {
|
|
|
2943
3181
|
}
|
|
2944
3182
|
logger.log("");
|
|
2945
3183
|
for (const theme of themes) {
|
|
2946
|
-
const themeDir =
|
|
3184
|
+
const themeDir = path11.join(getThemesDir(), theme);
|
|
2947
3185
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2948
3186
|
let manifestContent = "";
|
|
2949
3187
|
for (const candidate of candidates) {
|
|
2950
|
-
const candidatePath =
|
|
3188
|
+
const candidatePath = path11.join(themeDir, candidate);
|
|
2951
3189
|
if (fs.existsSync(candidatePath)) {
|
|
2952
3190
|
manifestContent = fs.readFileSync(candidatePath, "utf-8");
|
|
2953
3191
|
break;
|
|
@@ -2985,9 +3223,9 @@ async function validateCommand(options) {
|
|
|
2985
3223
|
"theme.config.ts",
|
|
2986
3224
|
"bundle-entry.ts",
|
|
2987
3225
|
"manifest.ts"
|
|
2988
|
-
].some((f) => fs.existsSync(
|
|
3226
|
+
].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
|
|
2989
3227
|
if (isThemeDir2) {
|
|
2990
|
-
themeToValidate =
|
|
3228
|
+
themeToValidate = path11.basename(process.cwd());
|
|
2991
3229
|
logger.info(`Validating current theme: ${themeToValidate}`);
|
|
2992
3230
|
} else {
|
|
2993
3231
|
logger.error(
|
|
@@ -2996,11 +3234,11 @@ async function validateCommand(options) {
|
|
|
2996
3234
|
process.exit(1);
|
|
2997
3235
|
}
|
|
2998
3236
|
}
|
|
2999
|
-
const themePath =
|
|
3237
|
+
const themePath = path11.join(getThemesDir(), themeToValidate);
|
|
3000
3238
|
logger.startSpinner("Running validation checks...");
|
|
3001
3239
|
const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
|
|
3002
3240
|
const foundEntry = entryFiles.find(
|
|
3003
|
-
(f) => fs.existsSync(
|
|
3241
|
+
(f) => fs.existsSync(path11.join(themePath, f))
|
|
3004
3242
|
);
|
|
3005
3243
|
if (!foundEntry) {
|
|
3006
3244
|
issues.push({
|
|
@@ -3010,7 +3248,7 @@ async function validateCommand(options) {
|
|
|
3010
3248
|
});
|
|
3011
3249
|
} else if (foundEntry === "manifest.ts") {
|
|
3012
3250
|
const manifestContent = fs.readFileSync(
|
|
3013
|
-
|
|
3251
|
+
path11.join(themePath, foundEntry),
|
|
3014
3252
|
"utf-8"
|
|
3015
3253
|
);
|
|
3016
3254
|
if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
|
|
@@ -3021,7 +3259,7 @@ async function validateCommand(options) {
|
|
|
3021
3259
|
});
|
|
3022
3260
|
}
|
|
3023
3261
|
}
|
|
3024
|
-
const configPath =
|
|
3262
|
+
const configPath = path11.join(themePath, "theme.config.ts");
|
|
3025
3263
|
if (!fs.existsSync(configPath)) {
|
|
3026
3264
|
issues.push({
|
|
3027
3265
|
type: "warning",
|
|
@@ -3029,7 +3267,7 @@ async function validateCommand(options) {
|
|
|
3029
3267
|
message: "Theme config file not found (recommended)"
|
|
3030
3268
|
});
|
|
3031
3269
|
}
|
|
3032
|
-
const indexPath =
|
|
3270
|
+
const indexPath = path11.join(themePath, "index.ts");
|
|
3033
3271
|
if (!fs.existsSync(indexPath)) {
|
|
3034
3272
|
issues.push({
|
|
3035
3273
|
type: "warning",
|
|
@@ -3037,7 +3275,7 @@ async function validateCommand(options) {
|
|
|
3037
3275
|
message: "Index file not found (recommended)"
|
|
3038
3276
|
});
|
|
3039
3277
|
}
|
|
3040
|
-
const sectionsDir =
|
|
3278
|
+
const sectionsDir = path11.join(themePath, "sections");
|
|
3041
3279
|
if (!fs.existsSync(sectionsDir)) {
|
|
3042
3280
|
issues.push({
|
|
3043
3281
|
type: "warning",
|
|
@@ -3046,16 +3284,16 @@ async function validateCommand(options) {
|
|
|
3046
3284
|
});
|
|
3047
3285
|
} else {
|
|
3048
3286
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
3049
|
-
(name) => fs.statSync(
|
|
3287
|
+
(name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
|
|
3050
3288
|
);
|
|
3051
3289
|
for (const sectionName of sections) {
|
|
3052
|
-
const sectionPath =
|
|
3053
|
-
const schemaFile =
|
|
3054
|
-
const defaultTemplate =
|
|
3290
|
+
const sectionPath = path11.join(sectionsDir, sectionName);
|
|
3291
|
+
const schemaFile = path11.join(sectionPath, `${sectionName}.schema.ts`);
|
|
3292
|
+
const defaultTemplate = path11.join(
|
|
3055
3293
|
sectionPath,
|
|
3056
3294
|
`${sectionName}-default.tsx`
|
|
3057
3295
|
);
|
|
3058
|
-
const indexFile =
|
|
3296
|
+
const indexFile = path11.join(sectionPath, "index.ts");
|
|
3059
3297
|
if (!fs.existsSync(schemaFile)) {
|
|
3060
3298
|
issues.push({
|
|
3061
3299
|
type: "error",
|
|
@@ -3079,14 +3317,14 @@ async function validateCommand(options) {
|
|
|
3079
3317
|
}
|
|
3080
3318
|
}
|
|
3081
3319
|
}
|
|
3082
|
-
const blocksDir =
|
|
3320
|
+
const blocksDir = path11.join(themePath, "blocks");
|
|
3083
3321
|
if (fs.existsSync(blocksDir)) {
|
|
3084
|
-
const blocks = fs.readdirSync(blocksDir).filter((name) => fs.statSync(
|
|
3322
|
+
const blocks = fs.readdirSync(blocksDir).filter((name) => fs.statSync(path11.join(blocksDir, name)).isDirectory());
|
|
3085
3323
|
for (const blockName of blocks) {
|
|
3086
|
-
const blockPath =
|
|
3087
|
-
const schemaFile =
|
|
3088
|
-
const componentFile =
|
|
3089
|
-
const indexFile =
|
|
3324
|
+
const blockPath = path11.join(blocksDir, blockName);
|
|
3325
|
+
const schemaFile = path11.join(blockPath, `${blockName}.schema.ts`);
|
|
3326
|
+
const componentFile = path11.join(blockPath, `${blockName}.tsx`);
|
|
3327
|
+
const indexFile = path11.join(blockPath, "index.ts");
|
|
3090
3328
|
if (!fs.existsSync(schemaFile)) {
|
|
3091
3329
|
issues.push({
|
|
3092
3330
|
type: "error",
|
|
@@ -3112,13 +3350,13 @@ async function validateCommand(options) {
|
|
|
3112
3350
|
}
|
|
3113
3351
|
if (fs.existsSync(sectionsDir)) {
|
|
3114
3352
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
3115
|
-
(name) => fs.statSync(
|
|
3353
|
+
(name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
|
|
3116
3354
|
);
|
|
3117
3355
|
for (const sectionName of sections) {
|
|
3118
|
-
const sectionPath =
|
|
3356
|
+
const sectionPath = path11.join(sectionsDir, sectionName);
|
|
3119
3357
|
const tsxFiles = fs.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
|
|
3120
3358
|
for (const tsxFile of tsxFiles) {
|
|
3121
|
-
const filePath =
|
|
3359
|
+
const filePath = path11.join(sectionPath, tsxFile);
|
|
3122
3360
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
3123
3361
|
const relPath = `sections/${sectionName}/${tsxFile}`;
|
|
3124
3362
|
if (!content.includes('"use client"') && !content.includes("'use client'")) {
|
|
@@ -3166,12 +3404,12 @@ async function validateCommand(options) {
|
|
|
3166
3404
|
}
|
|
3167
3405
|
}
|
|
3168
3406
|
}
|
|
3169
|
-
const registryPath =
|
|
3170
|
-
const bundleEntryPath =
|
|
3407
|
+
const registryPath = path11.join(themePath, "sections-registry.ts");
|
|
3408
|
+
const bundleEntryPath = path11.join(themePath, "bundle-entry.ts");
|
|
3171
3409
|
const registryContent = fs.existsSync(registryPath) ? fs.readFileSync(registryPath, "utf-8") : fs.existsSync(bundleEntryPath) ? fs.readFileSync(bundleEntryPath, "utf-8") : "";
|
|
3172
3410
|
if (fs.existsSync(sectionsDir) && registryContent) {
|
|
3173
3411
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
3174
|
-
(name) => fs.statSync(
|
|
3412
|
+
(name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
|
|
3175
3413
|
);
|
|
3176
3414
|
for (const sectionName of sections) {
|
|
3177
3415
|
if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
|
|
@@ -3194,7 +3432,7 @@ async function validateCommand(options) {
|
|
|
3194
3432
|
});
|
|
3195
3433
|
}
|
|
3196
3434
|
}
|
|
3197
|
-
const pagesDir =
|
|
3435
|
+
const pagesDir = path11.join(themePath, "pages");
|
|
3198
3436
|
if (fs.existsSync(pagesDir)) {
|
|
3199
3437
|
const allSchemaTypeSet = new Set(
|
|
3200
3438
|
schemaTypes.map((s) => s.schemaType || s.folderName)
|
|
@@ -3246,9 +3484,9 @@ async function validateCommand(options) {
|
|
|
3246
3484
|
}
|
|
3247
3485
|
async function loadSchemaTypes(themePath, sectionsDir) {
|
|
3248
3486
|
const results = [];
|
|
3249
|
-
const sections = fs.readdirSync(sectionsDir).filter((name) => fs.statSync(
|
|
3487
|
+
const sections = fs.readdirSync(sectionsDir).filter((name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory());
|
|
3250
3488
|
for (const sectionName of sections) {
|
|
3251
|
-
const schemaFile =
|
|
3489
|
+
const schemaFile = path11.join(
|
|
3252
3490
|
sectionsDir,
|
|
3253
3491
|
sectionName,
|
|
3254
3492
|
`${sectionName}.schema.ts`
|
|
@@ -3286,7 +3524,7 @@ async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
|
3286
3524
|
const issues = [];
|
|
3287
3525
|
const files = fs.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
|
|
3288
3526
|
for (const file of files) {
|
|
3289
|
-
const content = fs.readFileSync(
|
|
3527
|
+
const content = fs.readFileSync(path11.join(pagesDir, file), "utf-8");
|
|
3290
3528
|
const pageName = file.replace(/\.(ts|js)$/, "");
|
|
3291
3529
|
const sectionsMatch = content.match(/\bsections:\s*\[/);
|
|
3292
3530
|
if (!sectionsMatch || sectionsMatch.index === void 0) continue;
|
|
@@ -3299,9 +3537,13 @@ async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
|
3299
3537
|
endIdx = i;
|
|
3300
3538
|
}
|
|
3301
3539
|
const sectionsBlock = content.slice(startIdx, endIdx);
|
|
3302
|
-
const
|
|
3303
|
-
|
|
3540
|
+
const sectionTypeMatches = sectionsBlock.matchAll(
|
|
3541
|
+
/\bid:\s*["'][^"']*["'],\s*\n?\s*type:\s*["']([^"']+)["']/g
|
|
3542
|
+
);
|
|
3543
|
+
for (const match of sectionTypeMatches) {
|
|
3304
3544
|
const sectionType = match[1];
|
|
3545
|
+
if (COMPONENT_TYPES.has(sectionType)) continue;
|
|
3546
|
+
if (BLOCK_TYPES.has(sectionType)) continue;
|
|
3305
3547
|
if (!validTypes.has(sectionType)) {
|
|
3306
3548
|
issues.push({
|
|
3307
3549
|
type: "error",
|
|
@@ -3354,6 +3596,64 @@ var FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
3354
3596
|
"inline_richtext",
|
|
3355
3597
|
"repeater"
|
|
3356
3598
|
]);
|
|
3599
|
+
var COMPONENT_TYPES = /* @__PURE__ */ new Set([
|
|
3600
|
+
"heading",
|
|
3601
|
+
"paragraph",
|
|
3602
|
+
"button",
|
|
3603
|
+
"image",
|
|
3604
|
+
"link",
|
|
3605
|
+
"icon",
|
|
3606
|
+
"badge",
|
|
3607
|
+
"divider",
|
|
3608
|
+
"spacer",
|
|
3609
|
+
"container",
|
|
3610
|
+
"grid",
|
|
3611
|
+
"columns",
|
|
3612
|
+
"card",
|
|
3613
|
+
"quote",
|
|
3614
|
+
"input",
|
|
3615
|
+
"textarea",
|
|
3616
|
+
"checkbox",
|
|
3617
|
+
"select",
|
|
3618
|
+
"video",
|
|
3619
|
+
"gallery",
|
|
3620
|
+
"alert",
|
|
3621
|
+
"progress",
|
|
3622
|
+
"rating",
|
|
3623
|
+
"timer",
|
|
3624
|
+
"list",
|
|
3625
|
+
"table",
|
|
3626
|
+
"accordion",
|
|
3627
|
+
"tabs",
|
|
3628
|
+
"code",
|
|
3629
|
+
"map",
|
|
3630
|
+
"product-card",
|
|
3631
|
+
"blog-card",
|
|
3632
|
+
"social-links",
|
|
3633
|
+
"hotline-contacts",
|
|
3634
|
+
"company-info",
|
|
3635
|
+
"torn-separator"
|
|
3636
|
+
]);
|
|
3637
|
+
var BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
3638
|
+
"brand-feature",
|
|
3639
|
+
"collection-item",
|
|
3640
|
+
"crafting-step",
|
|
3641
|
+
"testimonial-item",
|
|
3642
|
+
"stat-item",
|
|
3643
|
+
"footer-link",
|
|
3644
|
+
"navigation-links-block",
|
|
3645
|
+
"policy-section",
|
|
3646
|
+
"core-value-card",
|
|
3647
|
+
"faq-item",
|
|
3648
|
+
"feature-item",
|
|
3649
|
+
"gallery-item",
|
|
3650
|
+
"logo-item",
|
|
3651
|
+
"pricing-tier",
|
|
3652
|
+
"service-item",
|
|
3653
|
+
"stat-card",
|
|
3654
|
+
"team-member",
|
|
3655
|
+
"hero-content"
|
|
3656
|
+
]);
|
|
3357
3657
|
|
|
3358
3658
|
// src/commands/build.ts
|
|
3359
3659
|
init_logger();
|
|
@@ -3364,14 +3664,14 @@ async function buildCommand(options) {
|
|
|
3364
3664
|
if (options.theme) {
|
|
3365
3665
|
themeName = options.theme;
|
|
3366
3666
|
try {
|
|
3367
|
-
const workspaceThemePath =
|
|
3667
|
+
const workspaceThemePath = path11.join(getThemesDir(), themeName);
|
|
3368
3668
|
if (fs.existsSync(workspaceThemePath)) {
|
|
3369
3669
|
themePath = workspaceThemePath;
|
|
3370
3670
|
} else {
|
|
3371
|
-
themePath =
|
|
3671
|
+
themePath = path11.join(process.cwd(), themeName);
|
|
3372
3672
|
}
|
|
3373
3673
|
} catch {
|
|
3374
|
-
themePath =
|
|
3674
|
+
themePath = path11.join(process.cwd(), themeName);
|
|
3375
3675
|
}
|
|
3376
3676
|
if (!fs.existsSync(themePath)) {
|
|
3377
3677
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -3382,10 +3682,10 @@ async function buildCommand(options) {
|
|
|
3382
3682
|
"theme.config.ts",
|
|
3383
3683
|
"bundle-entry.ts",
|
|
3384
3684
|
"manifest.ts"
|
|
3385
|
-
].some((f) => fs.existsSync(
|
|
3685
|
+
].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
|
|
3386
3686
|
if (isThemeDir2) {
|
|
3387
3687
|
themePath = process.cwd();
|
|
3388
|
-
themeName =
|
|
3688
|
+
themeName = path11.basename(themePath);
|
|
3389
3689
|
logger.info(`Building current theme: ${themeName}`);
|
|
3390
3690
|
} else {
|
|
3391
3691
|
logger.error(
|
|
@@ -3394,7 +3694,7 @@ async function buildCommand(options) {
|
|
|
3394
3694
|
process.exit(1);
|
|
3395
3695
|
}
|
|
3396
3696
|
}
|
|
3397
|
-
const packageJsonPath =
|
|
3697
|
+
const packageJsonPath = path11.join(themePath, "package.json");
|
|
3398
3698
|
const hasPkgJson = fs.existsSync(packageJsonPath);
|
|
3399
3699
|
if (!hasPkgJson) {
|
|
3400
3700
|
logger.warning(
|
|
@@ -3450,9 +3750,9 @@ async function buildCommand(options) {
|
|
|
3450
3750
|
logger.success("\u2713 Theme built successfully!");
|
|
3451
3751
|
logger.newLine();
|
|
3452
3752
|
logger.info(`Theme: ${themeName}`);
|
|
3453
|
-
const distPath =
|
|
3753
|
+
const distPath = path11.join(themePath, "dist");
|
|
3454
3754
|
if (fs.existsSync(distPath)) {
|
|
3455
|
-
logger.log(`Output: ${
|
|
3755
|
+
logger.log(`Output: ${path11.relative(process.cwd(), distPath)}`);
|
|
3456
3756
|
const files = fs.readdirSync(distPath);
|
|
3457
3757
|
logger.log(`Files: ${files.length}`);
|
|
3458
3758
|
}
|
|
@@ -3508,7 +3808,7 @@ async function packageCommand(options) {
|
|
|
3508
3808
|
let themeName;
|
|
3509
3809
|
if (options.theme) {
|
|
3510
3810
|
themeName = options.theme;
|
|
3511
|
-
themePath =
|
|
3811
|
+
themePath = path11.join(getThemesDir(), themeName);
|
|
3512
3812
|
if (!fs.existsSync(themePath)) {
|
|
3513
3813
|
logger.error(`Theme "${themeName}" not found.`);
|
|
3514
3814
|
process.exit(1);
|
|
@@ -3518,10 +3818,10 @@ async function packageCommand(options) {
|
|
|
3518
3818
|
"theme.config.ts",
|
|
3519
3819
|
"bundle-entry.ts",
|
|
3520
3820
|
"manifest.ts"
|
|
3521
|
-
].some((f) => fs.existsSync(
|
|
3821
|
+
].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
|
|
3522
3822
|
if (isThemeDir2) {
|
|
3523
3823
|
themePath = process.cwd();
|
|
3524
|
-
themeName =
|
|
3824
|
+
themeName = path11.basename(themePath);
|
|
3525
3825
|
logger.info(`Packaging current theme: ${themeName}`);
|
|
3526
3826
|
} else {
|
|
3527
3827
|
logger.error(
|
|
@@ -3530,7 +3830,7 @@ async function packageCommand(options) {
|
|
|
3530
3830
|
process.exit(1);
|
|
3531
3831
|
}
|
|
3532
3832
|
}
|
|
3533
|
-
const packageJsonPath =
|
|
3833
|
+
const packageJsonPath = path11.join(themePath, "package.json");
|
|
3534
3834
|
let version2 = "1.0.0";
|
|
3535
3835
|
if (fs.existsSync(packageJsonPath)) {
|
|
3536
3836
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
@@ -3540,7 +3840,7 @@ async function packageCommand(options) {
|
|
|
3540
3840
|
logger.info(`Theme: ${themeName}`);
|
|
3541
3841
|
logger.info(`Version: ${version2}`);
|
|
3542
3842
|
logger.newLine();
|
|
3543
|
-
const compiledThemePath =
|
|
3843
|
+
const compiledThemePath = path11.join(
|
|
3544
3844
|
process.cwd(),
|
|
3545
3845
|
"themes",
|
|
3546
3846
|
themeName,
|
|
@@ -3574,8 +3874,8 @@ async function packageCommand(options) {
|
|
|
3574
3874
|
logger.newLine();
|
|
3575
3875
|
logger.section("Step 2: Create Package");
|
|
3576
3876
|
const packageName = options.name || `${themeName}-${version2}`;
|
|
3577
|
-
const outputDir = options.output ||
|
|
3578
|
-
const outputPath =
|
|
3877
|
+
const outputDir = options.output || path11.join(process.cwd(), "dist");
|
|
3878
|
+
const outputPath = path11.join(outputDir, `${packageName}.zip`);
|
|
3579
3879
|
await fs.ensureDir(outputDir);
|
|
3580
3880
|
logger.startSpinner("Creating zip archive...");
|
|
3581
3881
|
try {
|
|
@@ -3588,11 +3888,11 @@ async function packageCommand(options) {
|
|
|
3588
3888
|
logger.newLine();
|
|
3589
3889
|
logger.info(`Package: ${packageName}.zip`);
|
|
3590
3890
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3591
|
-
logger.log(`Location: ${
|
|
3891
|
+
logger.log(`Location: ${path11.relative(process.cwd(), outputPath)}`);
|
|
3592
3892
|
logger.newLine();
|
|
3593
3893
|
logger.section("Next steps:");
|
|
3594
3894
|
logger.log(
|
|
3595
|
-
` onexthm deploy --package ${
|
|
3895
|
+
` onexthm deploy --package ${path11.relative(process.cwd(), outputPath)}`
|
|
3596
3896
|
);
|
|
3597
3897
|
} catch (error) {
|
|
3598
3898
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3650,9 +3950,9 @@ async function deployCommand(options) {
|
|
|
3650
3950
|
ensureOneXProject();
|
|
3651
3951
|
let packagePath;
|
|
3652
3952
|
if (options.package) {
|
|
3653
|
-
packagePath =
|
|
3953
|
+
packagePath = path11.resolve(options.package);
|
|
3654
3954
|
} else if (options.theme) {
|
|
3655
|
-
const distDir =
|
|
3955
|
+
const distDir = path11.join(process.cwd(), "dist");
|
|
3656
3956
|
if (!fs.existsSync(distDir)) {
|
|
3657
3957
|
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3658
3958
|
process.exit(1);
|
|
@@ -3667,7 +3967,7 @@ async function deployCommand(options) {
|
|
|
3667
3967
|
process.exit(1);
|
|
3668
3968
|
}
|
|
3669
3969
|
packageFiles.sort().reverse();
|
|
3670
|
-
packagePath =
|
|
3970
|
+
packagePath = path11.join(distDir, packageFiles[0]);
|
|
3671
3971
|
} else {
|
|
3672
3972
|
logger.error("Either --package or --theme must be specified.");
|
|
3673
3973
|
logger.info("Examples:");
|
|
@@ -3681,11 +3981,11 @@ async function deployCommand(options) {
|
|
|
3681
3981
|
}
|
|
3682
3982
|
const stats = await fs.stat(packagePath);
|
|
3683
3983
|
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
3684
|
-
const fileName =
|
|
3984
|
+
const fileName = path11.basename(packagePath);
|
|
3685
3985
|
logger.newLine();
|
|
3686
3986
|
logger.info(`Package: ${fileName}`);
|
|
3687
3987
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3688
|
-
logger.log(`Path: ${
|
|
3988
|
+
logger.log(`Path: ${path11.relative(process.cwd(), packagePath)}`);
|
|
3689
3989
|
logger.newLine();
|
|
3690
3990
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3691
3991
|
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
@@ -3842,8 +4142,8 @@ async function downloadBundleZip(apiUrl, themeId, version2) {
|
|
|
3842
4142
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
3843
4143
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
3844
4144
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
3845
|
-
const hashedPath =
|
|
3846
|
-
const stablePath =
|
|
4145
|
+
const hashedPath = path11.join(outputDir, entryFile);
|
|
4146
|
+
const stablePath = path11.join(outputDir, "bundle-entry.js");
|
|
3847
4147
|
if (await fs.pathExists(hashedPath)) {
|
|
3848
4148
|
await fs.copy(hashedPath, stablePath);
|
|
3849
4149
|
const mapPath = hashedPath + ".map";
|
|
@@ -3852,13 +4152,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
|
|
|
3852
4152
|
}
|
|
3853
4153
|
}
|
|
3854
4154
|
}
|
|
3855
|
-
const sectionsRegistryPath =
|
|
4155
|
+
const sectionsRegistryPath = path11.join(outputDir, "sections-registry.js");
|
|
3856
4156
|
const content = `// Re-export all sections from bundle-entry
|
|
3857
4157
|
// This file exists to maintain compatibility with the import path
|
|
3858
4158
|
export * from './bundle-entry.js';
|
|
3859
4159
|
`;
|
|
3860
4160
|
await fs.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
3861
|
-
const pkgJsonPath =
|
|
4161
|
+
const pkgJsonPath = path11.join(outputDir, "package.json");
|
|
3862
4162
|
await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
3863
4163
|
}
|
|
3864
4164
|
function showDownloadFailureHelp(themeId, apiUrl) {
|
|
@@ -3957,7 +4257,7 @@ async function downloadCommand(options) {
|
|
|
3957
4257
|
zip.extractAllTo(outputDir, true);
|
|
3958
4258
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
3959
4259
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
3960
|
-
const manifestPath =
|
|
4260
|
+
const manifestPath = path11.join(outputDir, "manifest.json");
|
|
3961
4261
|
const manifest = await fs.readJson(manifestPath);
|
|
3962
4262
|
await createCompatibilityFiles(outputDir, manifest);
|
|
3963
4263
|
console.log();
|
|
@@ -4078,7 +4378,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4078
4378
|
const oldPrefix = `${oldName}-`;
|
|
4079
4379
|
const newPrefix = `${newName}-`;
|
|
4080
4380
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4081
|
-
const pkgPath =
|
|
4381
|
+
const pkgPath = path11.join(themeDir, "package.json");
|
|
4082
4382
|
if (await fs.pathExists(pkgPath)) {
|
|
4083
4383
|
const pkg = await fs.readJson(pkgPath);
|
|
4084
4384
|
pkg.name = `@onex-themes/${newName}`;
|
|
@@ -4094,7 +4394,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4094
4394
|
}
|
|
4095
4395
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
4096
4396
|
}
|
|
4097
|
-
const configPath =
|
|
4397
|
+
const configPath = path11.join(themeDir, "theme.config.ts");
|
|
4098
4398
|
if (await fs.pathExists(configPath)) {
|
|
4099
4399
|
let content = await fs.readFile(configPath, "utf-8");
|
|
4100
4400
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -4104,7 +4404,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4104
4404
|
);
|
|
4105
4405
|
await fs.writeFile(configPath, content);
|
|
4106
4406
|
}
|
|
4107
|
-
const layoutPath =
|
|
4407
|
+
const layoutPath = path11.join(themeDir, "theme.layout.ts");
|
|
4108
4408
|
if (await fs.pathExists(layoutPath)) {
|
|
4109
4409
|
let content = await fs.readFile(layoutPath, "utf-8");
|
|
4110
4410
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -4117,7 +4417,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4117
4417
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4118
4418
|
const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
4119
4419
|
for (const file of tsFiles) {
|
|
4120
|
-
const filePath =
|
|
4420
|
+
const filePath = path11.join(themeDir, file);
|
|
4121
4421
|
let content = await fs.readFile(filePath, "utf-8");
|
|
4122
4422
|
const original = content;
|
|
4123
4423
|
content = content.replace(
|
|
@@ -4160,7 +4460,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4160
4460
|
}
|
|
4161
4461
|
const spinner = ora("Initializing clone...").start();
|
|
4162
4462
|
try {
|
|
4163
|
-
const outputDir = options.output ||
|
|
4463
|
+
const outputDir = options.output || path11.resolve(process.cwd(), newName);
|
|
4164
4464
|
if (await fs.pathExists(outputDir)) {
|
|
4165
4465
|
spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
|
|
4166
4466
|
logger.info(
|
|
@@ -4206,7 +4506,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4206
4506
|
spinner.succeed(
|
|
4207
4507
|
`Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
|
|
4208
4508
|
);
|
|
4209
|
-
const envExamplePath =
|
|
4509
|
+
const envExamplePath = path11.join(outputDir, ".env.example");
|
|
4210
4510
|
if (!await fs.pathExists(envExamplePath)) {
|
|
4211
4511
|
await fs.writeFile(
|
|
4212
4512
|
envExamplePath,
|
|
@@ -4219,7 +4519,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4219
4519
|
].join("\n")
|
|
4220
4520
|
);
|
|
4221
4521
|
}
|
|
4222
|
-
const mcpJsonPath =
|
|
4522
|
+
const mcpJsonPath = path11.join(outputDir, ".mcp.json");
|
|
4223
4523
|
if (await fs.pathExists(mcpJsonPath)) {
|
|
4224
4524
|
const { default: inquirerMod } = await import('inquirer');
|
|
4225
4525
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
@@ -4244,7 +4544,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4244
4544
|
}
|
|
4245
4545
|
if (options.install !== false) {
|
|
4246
4546
|
const hasPkgJson = await fs.pathExists(
|
|
4247
|
-
|
|
4547
|
+
path11.join(outputDir, "package.json")
|
|
4248
4548
|
);
|
|
4249
4549
|
if (hasPkgJson) {
|
|
4250
4550
|
spinner.start("Installing dependencies...");
|
|
@@ -4272,7 +4572,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4272
4572
|
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
4273
4573
|
console.log();
|
|
4274
4574
|
console.log(chalk4.cyan("Next steps:"));
|
|
4275
|
-
console.log(chalk4.gray(` cd ${
|
|
4575
|
+
console.log(chalk4.gray(` cd ${path11.relative(process.cwd(), outputDir)}`));
|
|
4276
4576
|
console.log(
|
|
4277
4577
|
chalk4.gray(" cp .env.example .env # then add your Company ID")
|
|
4278
4578
|
);
|
|
@@ -4299,14 +4599,14 @@ async function devCommand(options) {
|
|
|
4299
4599
|
if (options.theme) {
|
|
4300
4600
|
themeName = options.theme;
|
|
4301
4601
|
try {
|
|
4302
|
-
const workspaceThemePath =
|
|
4602
|
+
const workspaceThemePath = path11.join(getThemesDir(), themeName);
|
|
4303
4603
|
if (fs.existsSync(workspaceThemePath)) {
|
|
4304
4604
|
themePath = workspaceThemePath;
|
|
4305
4605
|
} else {
|
|
4306
|
-
themePath =
|
|
4606
|
+
themePath = path11.join(process.cwd(), themeName);
|
|
4307
4607
|
}
|
|
4308
4608
|
} catch {
|
|
4309
|
-
themePath =
|
|
4609
|
+
themePath = path11.join(process.cwd(), themeName);
|
|
4310
4610
|
}
|
|
4311
4611
|
if (!fs.existsSync(themePath)) {
|
|
4312
4612
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -4317,10 +4617,10 @@ async function devCommand(options) {
|
|
|
4317
4617
|
"theme.config.ts",
|
|
4318
4618
|
"bundle-entry.ts",
|
|
4319
4619
|
"manifest.ts"
|
|
4320
|
-
].some((f) => fs.existsSync(
|
|
4620
|
+
].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
|
|
4321
4621
|
if (isThemeDir2) {
|
|
4322
4622
|
themePath = process.cwd();
|
|
4323
|
-
themeName =
|
|
4623
|
+
themeName = path11.basename(themePath);
|
|
4324
4624
|
} else {
|
|
4325
4625
|
logger.error(
|
|
4326
4626
|
"Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
|
|
@@ -4389,9 +4689,9 @@ async function devCommand(options) {
|
|
|
4389
4689
|
watcher.close();
|
|
4390
4690
|
await context2.dispose();
|
|
4391
4691
|
server.close();
|
|
4392
|
-
const shimPath =
|
|
4692
|
+
const shimPath = path11.join(outputDir, ".process-shim.js");
|
|
4393
4693
|
try {
|
|
4394
|
-
await
|
|
4694
|
+
await fs9.unlink(shimPath);
|
|
4395
4695
|
} catch {
|
|
4396
4696
|
}
|
|
4397
4697
|
process.exit(0);
|
|
@@ -4400,8 +4700,8 @@ async function devCommand(options) {
|
|
|
4400
4700
|
|
|
4401
4701
|
// src/commands/config.ts
|
|
4402
4702
|
init_logger();
|
|
4403
|
-
var CONFIG_DIR =
|
|
4404
|
-
var CONFIG_FILE =
|
|
4703
|
+
var CONFIG_DIR = path11.join(os.homedir(), ".onexthm");
|
|
4704
|
+
var CONFIG_FILE = path11.join(CONFIG_DIR, ".env");
|
|
4405
4705
|
var CONFIG_ENTRIES = [
|
|
4406
4706
|
{
|
|
4407
4707
|
key: "AWS_ACCESS_KEY_ID",
|
|
@@ -4669,91 +4969,357 @@ async function whoamiCommand(options = {}) {
|
|
|
4669
4969
|
|
|
4670
4970
|
// src/commands/publish.ts
|
|
4671
4971
|
init_logger();
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4972
|
+
init_scan_theme_assets();
|
|
4973
|
+
|
|
4974
|
+
// src/utils/fetch-prior-schemas.ts
|
|
4975
|
+
async function fetchPriorGateManifests(themeId, env) {
|
|
4976
|
+
const apiUrl = getApiUrl(env);
|
|
4977
|
+
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/gate-manifests/latest`;
|
|
4978
|
+
let res;
|
|
4979
|
+
try {
|
|
4980
|
+
res = await authenticatedFetch(url, { method: "GET" }, env);
|
|
4981
|
+
} catch (err) {
|
|
4982
|
+
return {
|
|
4983
|
+
result: null,
|
|
4984
|
+
reason: `network error: ${err instanceof Error ? err.message : "unknown"}`
|
|
4985
|
+
};
|
|
4986
|
+
}
|
|
4987
|
+
if (res.status === 404) {
|
|
4988
|
+
return { result: null, reason: "no-prior" };
|
|
4989
|
+
}
|
|
4990
|
+
if (!res.ok) {
|
|
4991
|
+
return {
|
|
4992
|
+
result: null,
|
|
4993
|
+
reason: `server returned ${res.status} ${res.statusText}`
|
|
4994
|
+
};
|
|
4995
|
+
}
|
|
4996
|
+
let data;
|
|
4997
|
+
try {
|
|
4998
|
+
data = await res.json();
|
|
4999
|
+
} catch {
|
|
5000
|
+
return { result: null, reason: "non-JSON response from server" };
|
|
5001
|
+
}
|
|
5002
|
+
const body = data.statusCode ? data.body : data;
|
|
5003
|
+
if (!body || typeof body.version !== "string" || !body.schemas || !body.assets) {
|
|
5004
|
+
return { result: null, reason: "malformed response (missing fields)" };
|
|
5005
|
+
}
|
|
5006
|
+
return {
|
|
5007
|
+
result: {
|
|
5008
|
+
version: body.version,
|
|
5009
|
+
schemas: body.schemas,
|
|
5010
|
+
assets: body.assets
|
|
5011
|
+
},
|
|
5012
|
+
reason: null
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
|
|
5016
|
+
// src/utils/schema-diff.ts
|
|
5017
|
+
var SEVERITY = {
|
|
5018
|
+
safe: 0,
|
|
5019
|
+
"safe-rename": 1,
|
|
5020
|
+
"defaults-only": 2,
|
|
5021
|
+
additive: 3,
|
|
5022
|
+
breaking: 4,
|
|
5023
|
+
"breaking-asset": 5,
|
|
5024
|
+
"breaking-severe": 6
|
|
4692
5025
|
};
|
|
4693
|
-
var
|
|
4694
|
-
|
|
4695
|
-
"
|
|
4696
|
-
"
|
|
4697
|
-
"
|
|
4698
|
-
"
|
|
4699
|
-
"
|
|
4700
|
-
"
|
|
4701
|
-
|
|
4702
|
-
function
|
|
4703
|
-
|
|
4704
|
-
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
5026
|
+
var BUMP_FOR = {
|
|
5027
|
+
safe: "patch",
|
|
5028
|
+
"safe-rename": "patch",
|
|
5029
|
+
"defaults-only": "patch",
|
|
5030
|
+
additive: "minor",
|
|
5031
|
+
breaking: "major",
|
|
5032
|
+
"breaking-asset": "major",
|
|
5033
|
+
"breaking-severe": "major"
|
|
5034
|
+
};
|
|
5035
|
+
function bumpFor(kind) {
|
|
5036
|
+
return BUMP_FOR[kind];
|
|
4705
5037
|
}
|
|
4706
|
-
function
|
|
4707
|
-
|
|
4708
|
-
return MIME_MAP[ext] || "application/octet-stream";
|
|
5038
|
+
function maxSeverity(a, b) {
|
|
5039
|
+
return SEVERITY[a] >= SEVERITY[b] ? a : b;
|
|
4709
5040
|
}
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
5041
|
+
function classify(changes) {
|
|
5042
|
+
let highest = "safe";
|
|
5043
|
+
for (const c of changes) {
|
|
5044
|
+
highest = maxSeverity(highest, c.kind);
|
|
5045
|
+
}
|
|
5046
|
+
return { bump: bumpFor(highest), highest, changes };
|
|
4713
5047
|
}
|
|
4714
|
-
function
|
|
4715
|
-
const
|
|
4716
|
-
const
|
|
4717
|
-
const
|
|
4718
|
-
const
|
|
4719
|
-
|
|
4720
|
-
|
|
5048
|
+
function diffManifests(prior, current) {
|
|
5049
|
+
const changes = [];
|
|
5050
|
+
const priorSections = prior.schemas.sections;
|
|
5051
|
+
const currentSections = current.schemas.sections;
|
|
5052
|
+
const sectionTypes = /* @__PURE__ */ new Set([
|
|
5053
|
+
...Object.keys(priorSections),
|
|
5054
|
+
...Object.keys(currentSections)
|
|
5055
|
+
]);
|
|
5056
|
+
for (const type of [...sectionTypes].sort()) {
|
|
5057
|
+
const p = priorSections[type];
|
|
5058
|
+
const c = currentSections[type];
|
|
5059
|
+
if (p && !c) {
|
|
5060
|
+
changes.push({
|
|
5061
|
+
kind: "breaking-severe",
|
|
5062
|
+
path: `sections.${type}`,
|
|
5063
|
+
detail: `Section type "${type}" removed. Pages using this section will render empty.`
|
|
5064
|
+
});
|
|
5065
|
+
continue;
|
|
5066
|
+
}
|
|
5067
|
+
if (!p && c) {
|
|
5068
|
+
changes.push({
|
|
5069
|
+
kind: "additive",
|
|
5070
|
+
path: `sections.${type}`,
|
|
5071
|
+
detail: `Section type "${type}" added.`
|
|
5072
|
+
});
|
|
5073
|
+
continue;
|
|
5074
|
+
}
|
|
5075
|
+
if (p && c) diffSection(p, c, changes);
|
|
5076
|
+
}
|
|
5077
|
+
diffAssets(prior.assets, current.assets, changes);
|
|
5078
|
+
return changes;
|
|
4721
5079
|
}
|
|
4722
|
-
|
|
4723
|
-
const
|
|
4724
|
-
if (
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
});
|
|
4730
|
-
const results = [];
|
|
4731
|
-
for (const rel of files) {
|
|
4732
|
-
const absPath = path9.join(assetsDir, rel);
|
|
4733
|
-
const stat = await fs.stat(absPath);
|
|
4734
|
-
if (!stat.isFile()) continue;
|
|
4735
|
-
const originalPath = rel.split(path9.sep).join("/");
|
|
4736
|
-
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
4737
|
-
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
4738
|
-
const contentType = mimeFor(rel);
|
|
4739
|
-
results.push({
|
|
4740
|
-
originalPath,
|
|
4741
|
-
hashedPath,
|
|
4742
|
-
hash,
|
|
4743
|
-
size: stat.size,
|
|
4744
|
-
contentType,
|
|
4745
|
-
absPath
|
|
5080
|
+
function diffSection(prior, current, out) {
|
|
5081
|
+
const type = current.type;
|
|
5082
|
+
if (JSON.stringify(prior.dataRequirements) !== JSON.stringify(current.dataRequirements)) {
|
|
5083
|
+
out.push({
|
|
5084
|
+
kind: "breaking",
|
|
5085
|
+
path: `sections.${type}.dataRequirements`,
|
|
5086
|
+
detail: "dataRequirements changed."
|
|
4746
5087
|
});
|
|
4747
5088
|
}
|
|
4748
|
-
|
|
4749
|
-
|
|
5089
|
+
diffFieldList(
|
|
5090
|
+
prior.settings,
|
|
5091
|
+
current.settings,
|
|
5092
|
+
`sections.${type}.settings`,
|
|
5093
|
+
out
|
|
5094
|
+
);
|
|
5095
|
+
diffDefaults(
|
|
5096
|
+
prior.defaults,
|
|
5097
|
+
current.defaults,
|
|
5098
|
+
`sections.${type}.defaults`,
|
|
5099
|
+
out
|
|
5100
|
+
);
|
|
5101
|
+
diffBlocks(prior.blocks, current.blocks, `sections.${type}.blocks`, out);
|
|
4750
5102
|
}
|
|
4751
|
-
function
|
|
4752
|
-
const
|
|
4753
|
-
|
|
4754
|
-
|
|
5103
|
+
function diffBlocks(prior, current, pathPrefix, out) {
|
|
5104
|
+
const priorByType = new Map(prior.map((b) => [b.type, b]));
|
|
5105
|
+
const currentByType = new Map(current.map((b) => [b.type, b]));
|
|
5106
|
+
for (const type of /* @__PURE__ */ new Set([
|
|
5107
|
+
...priorByType.keys(),
|
|
5108
|
+
...currentByType.keys()
|
|
5109
|
+
])) {
|
|
5110
|
+
const p = priorByType.get(type);
|
|
5111
|
+
const c = currentByType.get(type);
|
|
5112
|
+
if (p && !c) {
|
|
5113
|
+
out.push({
|
|
5114
|
+
kind: "breaking",
|
|
5115
|
+
path: `${pathPrefix}.${type}`,
|
|
5116
|
+
detail: `Block type "${type}" removed.`
|
|
5117
|
+
});
|
|
5118
|
+
continue;
|
|
5119
|
+
}
|
|
5120
|
+
if (!p && c) {
|
|
5121
|
+
out.push({
|
|
5122
|
+
kind: "additive",
|
|
5123
|
+
path: `${pathPrefix}.${type}`,
|
|
5124
|
+
detail: `Block type "${type}" added.`
|
|
5125
|
+
});
|
|
5126
|
+
continue;
|
|
5127
|
+
}
|
|
5128
|
+
if (p && c) {
|
|
5129
|
+
diffFieldList(
|
|
5130
|
+
p.settings,
|
|
5131
|
+
c.settings,
|
|
5132
|
+
`${pathPrefix}.${type}.settings`,
|
|
5133
|
+
out
|
|
5134
|
+
);
|
|
5135
|
+
diffDefaults(
|
|
5136
|
+
p.defaults,
|
|
5137
|
+
c.defaults,
|
|
5138
|
+
`${pathPrefix}.${type}.defaults`,
|
|
5139
|
+
out
|
|
5140
|
+
);
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
function diffFieldList(prior, current, pathPrefix, out) {
|
|
5145
|
+
const priorById = new Map(prior.map((f) => [f.id, f]));
|
|
5146
|
+
const currentById = new Map(current.map((f) => [f.id, f]));
|
|
5147
|
+
const aliasToCurrent = /* @__PURE__ */ new Map();
|
|
5148
|
+
for (const f of current) {
|
|
5149
|
+
if (f.aliases) {
|
|
5150
|
+
for (const alias of f.aliases) {
|
|
5151
|
+
aliasToCurrent.set(alias, f);
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
for (const [id, p] of priorById) {
|
|
5156
|
+
const c = currentById.get(id);
|
|
5157
|
+
if (c) {
|
|
5158
|
+
diffFieldPair(p, c, `${pathPrefix}.${id}`, out);
|
|
5159
|
+
continue;
|
|
5160
|
+
}
|
|
5161
|
+
const renamed = aliasToCurrent.get(id);
|
|
5162
|
+
if (renamed) {
|
|
5163
|
+
if (renamed.type === p.type) {
|
|
5164
|
+
out.push({
|
|
5165
|
+
kind: "safe-rename",
|
|
5166
|
+
path: `${pathPrefix}.${id}`,
|
|
5167
|
+
detail: `Field "${id}" renamed to "${renamed.id}" (alias preserved).`
|
|
5168
|
+
});
|
|
5169
|
+
} else {
|
|
5170
|
+
out.push({
|
|
5171
|
+
kind: "breaking",
|
|
5172
|
+
path: `${pathPrefix}.${id}`,
|
|
5173
|
+
detail: `Field "${id}" renamed to "${renamed.id}" but type changed (${p.type} \u2192 ${renamed.type}).`
|
|
5174
|
+
});
|
|
5175
|
+
}
|
|
5176
|
+
} else {
|
|
5177
|
+
out.push({
|
|
5178
|
+
kind: "breaking",
|
|
5179
|
+
path: `${pathPrefix}.${id}`,
|
|
5180
|
+
detail: `Field "${id}" removed. Consider adding aliases: ["${id}"] to the replacement field if this was a rename.`
|
|
5181
|
+
});
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5184
|
+
for (const [id, c] of currentById) {
|
|
5185
|
+
if (priorById.has(id)) continue;
|
|
5186
|
+
const coveredByAlias = c.aliases?.some((a) => priorById.has(a)) ?? false;
|
|
5187
|
+
if (coveredByAlias) continue;
|
|
5188
|
+
if (c.required && c.default === void 0) {
|
|
5189
|
+
out.push({
|
|
5190
|
+
kind: "breaking",
|
|
5191
|
+
path: `${pathPrefix}.${id}`,
|
|
5192
|
+
detail: `Required field "${id}" added with no default. Existing instances cannot satisfy it.`
|
|
5193
|
+
});
|
|
5194
|
+
} else {
|
|
5195
|
+
out.push({
|
|
5196
|
+
kind: "additive",
|
|
5197
|
+
path: `${pathPrefix}.${id}`,
|
|
5198
|
+
detail: `Field "${id}" added.`
|
|
5199
|
+
});
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
}
|
|
5203
|
+
function diffFieldPair(p, c, path23, out) {
|
|
5204
|
+
if (p.type !== c.type) {
|
|
5205
|
+
out.push({
|
|
5206
|
+
kind: "breaking",
|
|
5207
|
+
path: path23,
|
|
5208
|
+
detail: `Type changed (${p.type} \u2192 ${c.type}). Saved values may misrender.`
|
|
5209
|
+
});
|
|
5210
|
+
return;
|
|
5211
|
+
}
|
|
5212
|
+
if (p.required !== true && c.required === true) {
|
|
5213
|
+
out.push({
|
|
5214
|
+
kind: "breaking",
|
|
5215
|
+
path: path23,
|
|
5216
|
+
detail: "Field became required. Existing empty instances now invalid."
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5219
|
+
if (typeof p.maxLength === "number" || typeof c.maxLength === "number") {
|
|
5220
|
+
if ((c.maxLength ?? Infinity) < (p.maxLength ?? Infinity)) {
|
|
5221
|
+
out.push({
|
|
5222
|
+
kind: "breaking",
|
|
5223
|
+
path: path23,
|
|
5224
|
+
detail: `maxLength tightened (${p.maxLength ?? "\u221E"} \u2192 ${c.maxLength}).`
|
|
5225
|
+
});
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
if (typeof p.min === "number" || typeof c.min === "number") {
|
|
5229
|
+
if ((c.min ?? -Infinity) > (p.min ?? -Infinity)) {
|
|
5230
|
+
out.push({
|
|
5231
|
+
kind: "breaking",
|
|
5232
|
+
path: path23,
|
|
5233
|
+
detail: `min raised (${p.min ?? "-\u221E"} \u2192 ${c.min}).`
|
|
5234
|
+
});
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
if (typeof p.max === "number" || typeof c.max === "number") {
|
|
5238
|
+
if ((c.max ?? Infinity) < (p.max ?? Infinity)) {
|
|
5239
|
+
out.push({
|
|
5240
|
+
kind: "breaking",
|
|
5241
|
+
path: path23,
|
|
5242
|
+
detail: `max lowered (${p.max ?? "\u221E"} \u2192 ${c.max}).`
|
|
5243
|
+
});
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
if (p.options || c.options) {
|
|
5247
|
+
const priorOpts = new Set(p.options ?? []);
|
|
5248
|
+
const currentOpts = new Set(c.options ?? []);
|
|
5249
|
+
const removed = [...priorOpts].filter((o) => !currentOpts.has(o));
|
|
5250
|
+
const added = [...currentOpts].filter((o) => !priorOpts.has(o));
|
|
5251
|
+
if (removed.length > 0) {
|
|
5252
|
+
out.push({
|
|
5253
|
+
kind: "breaking",
|
|
5254
|
+
path: path23,
|
|
5255
|
+
detail: `Option(s) removed: ${removed.join(", ")}. Existing saved values may be orphaned.`
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5258
|
+
if (added.length > 0) {
|
|
5259
|
+
out.push({
|
|
5260
|
+
kind: "additive",
|
|
5261
|
+
path: path23,
|
|
5262
|
+
detail: `Option(s) added: ${added.join(", ")}.`
|
|
5263
|
+
});
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
if (!deepEqual(p.default, c.default)) {
|
|
5267
|
+
out.push({
|
|
5268
|
+
kind: "defaults-only",
|
|
5269
|
+
path: path23,
|
|
5270
|
+
detail: `Default changed: ${JSON.stringify(p.default)} \u2192 ${JSON.stringify(c.default)}.`
|
|
5271
|
+
});
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
function diffDefaults(prior, current, pathPrefix, out) {
|
|
5275
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(prior), ...Object.keys(current)]);
|
|
5276
|
+
for (const key of [...keys].sort()) {
|
|
5277
|
+
if (!(key in prior) || !(key in current)) continue;
|
|
5278
|
+
if (!deepEqual(prior[key], current[key])) {
|
|
5279
|
+
out.push({
|
|
5280
|
+
kind: "defaults-only",
|
|
5281
|
+
path: `${pathPrefix}.${key}`,
|
|
5282
|
+
detail: `Default value changed.`
|
|
5283
|
+
});
|
|
5284
|
+
}
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
function diffAssets(prior, current, out) {
|
|
5288
|
+
const currentPaths = new Set(current.assets.map((a) => a.path));
|
|
5289
|
+
for (const a of prior.assets) {
|
|
5290
|
+
if (!currentPaths.has(a.path)) {
|
|
5291
|
+
out.push({
|
|
5292
|
+
kind: "breaking-asset",
|
|
5293
|
+
path: `theme-assets/${a.path}`,
|
|
5294
|
+
detail: `Asset "${a.path}" was present in the prior version and is now missing. Code that references it hardcoded will break.`
|
|
5295
|
+
});
|
|
5296
|
+
}
|
|
4755
5297
|
}
|
|
4756
|
-
|
|
5298
|
+
}
|
|
5299
|
+
function deepEqual(a, b) {
|
|
5300
|
+
if (a === b) return true;
|
|
5301
|
+
if (a === null || b === null) return false;
|
|
5302
|
+
if (typeof a !== typeof b) return false;
|
|
5303
|
+
if (typeof a !== "object") return false;
|
|
5304
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
5305
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
5306
|
+
if (a.length !== b.length) return false;
|
|
5307
|
+
for (let i = 0; i < a.length; i++) {
|
|
5308
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
5309
|
+
}
|
|
5310
|
+
return true;
|
|
5311
|
+
}
|
|
5312
|
+
const ak = Object.keys(a);
|
|
5313
|
+
const bk = Object.keys(b);
|
|
5314
|
+
if (ak.length !== bk.length) return false;
|
|
5315
|
+
for (const k of ak) {
|
|
5316
|
+
if (!deepEqual(
|
|
5317
|
+
a[k],
|
|
5318
|
+
b[k]
|
|
5319
|
+
))
|
|
5320
|
+
return false;
|
|
5321
|
+
}
|
|
5322
|
+
return true;
|
|
4757
5323
|
}
|
|
4758
5324
|
|
|
4759
5325
|
// src/commands/publish.ts
|
|
@@ -4772,13 +5338,13 @@ async function publishCommand(options) {
|
|
|
4772
5338
|
logger.info(`Logged in as: ${tokens.user.email}`);
|
|
4773
5339
|
let themePath;
|
|
4774
5340
|
if (options.theme) {
|
|
4775
|
-
themePath =
|
|
5341
|
+
themePath = path11.resolve(options.theme);
|
|
4776
5342
|
} else {
|
|
4777
5343
|
const isThemeDir2 = [
|
|
4778
5344
|
"theme.config.ts",
|
|
4779
5345
|
"bundle-entry.ts",
|
|
4780
5346
|
"manifest.ts"
|
|
4781
|
-
].some((f) => fs.existsSync(
|
|
5347
|
+
].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
|
|
4782
5348
|
if (isThemeDir2) {
|
|
4783
5349
|
themePath = process.cwd();
|
|
4784
5350
|
} else {
|
|
@@ -4788,13 +5354,13 @@ async function publishCommand(options) {
|
|
|
4788
5354
|
process.exit(1);
|
|
4789
5355
|
}
|
|
4790
5356
|
}
|
|
4791
|
-
const pkgPath =
|
|
5357
|
+
const pkgPath = path11.join(themePath, "package.json");
|
|
4792
5358
|
if (!fs.existsSync(pkgPath)) {
|
|
4793
5359
|
logger.error("No package.json found in theme directory");
|
|
4794
5360
|
process.exit(1);
|
|
4795
5361
|
}
|
|
4796
5362
|
const pkg = fs.readJsonSync(pkgPath);
|
|
4797
|
-
const themeId = pkg.name?.replace("@onex-themes/", "") ||
|
|
5363
|
+
const themeId = pkg.name?.replace("@onex-themes/", "") || path11.basename(themePath);
|
|
4798
5364
|
if (options.bump) {
|
|
4799
5365
|
const currentVersion = pkg.version || "1.0.0";
|
|
4800
5366
|
const newVersion = semver.inc(currentVersion, options.bump);
|
|
@@ -4818,57 +5384,62 @@ async function publishCommand(options) {
|
|
|
4818
5384
|
logger.info(`Version: ${version2}`);
|
|
4819
5385
|
logger.newLine();
|
|
4820
5386
|
const apiUrl = getApiUrl(env);
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
5387
|
+
if (!options.dryRun) {
|
|
5388
|
+
logger.startSpinner("Registering theme...");
|
|
5389
|
+
try {
|
|
5390
|
+
const regResponse = await authenticatedFetch(
|
|
5391
|
+
`${apiUrl}/website-api/themes/register`,
|
|
5392
|
+
{
|
|
5393
|
+
method: "POST",
|
|
5394
|
+
body: JSON.stringify({
|
|
5395
|
+
themeId,
|
|
5396
|
+
name: pkg.displayName || themeId,
|
|
5397
|
+
description: pkg.description || "",
|
|
5398
|
+
email: tokens.user.email,
|
|
5399
|
+
author: typeof pkg.author === "string" ? pkg.author : pkg.author?.name || tokens.user.name || "",
|
|
5400
|
+
category: pkg.onex?.category || "MINIMAL",
|
|
5401
|
+
tags: pkg.keywords || [],
|
|
5402
|
+
thumbnail_url: pkg.onex?.thumbnail || ""
|
|
5403
|
+
})
|
|
5404
|
+
},
|
|
5405
|
+
env
|
|
5406
|
+
);
|
|
5407
|
+
const regData = await regResponse.json();
|
|
5408
|
+
const regBody = regData.statusCode ? regData.body : regData;
|
|
5409
|
+
if (!regResponse.ok) {
|
|
5410
|
+
const errMsg = regBody.error || regBody.message || "Registration failed";
|
|
5411
|
+
if (!errMsg.includes("already registered")) {
|
|
5412
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5413
|
+
logger.error(errMsg);
|
|
5414
|
+
process.exit(1);
|
|
5415
|
+
}
|
|
4848
5416
|
}
|
|
5417
|
+
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
5418
|
+
} catch (error) {
|
|
5419
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5420
|
+
logger.error(
|
|
5421
|
+
error instanceof Error ? error.message : "Connection failed"
|
|
5422
|
+
);
|
|
5423
|
+
process.exit(1);
|
|
4849
5424
|
}
|
|
4850
|
-
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
4851
|
-
} catch (error) {
|
|
4852
|
-
logger.stopSpinner(false, "Registration failed");
|
|
4853
|
-
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4854
|
-
process.exit(1);
|
|
4855
5425
|
}
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
5426
|
+
if (!options.dryRun) {
|
|
5427
|
+
logger.startSpinner("Checking version availability...");
|
|
5428
|
+
try {
|
|
5429
|
+
const checkResponse = await authenticatedFetch(
|
|
5430
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/exists`,
|
|
5431
|
+
{ method: "GET" },
|
|
5432
|
+
env
|
|
5433
|
+
);
|
|
5434
|
+
const checkData = await checkResponse.json();
|
|
5435
|
+
const checkBody = checkData.statusCode ? checkData.body : checkData;
|
|
5436
|
+
if (checkBody.exists) {
|
|
5437
|
+
logger.stopSpinner(false, "Version already published");
|
|
5438
|
+
const patchVer = semver.inc(version2, "patch") || "?";
|
|
5439
|
+
const minorVer = semver.inc(version2, "minor") || "?";
|
|
5440
|
+
const majorVer = semver.inc(version2, "major") || "?";
|
|
5441
|
+
logger.error(
|
|
5442
|
+
`
|
|
4872
5443
|
Version ${version2} of "${themeId}" is already published and cannot be overwritten.
|
|
4873
5444
|
|
|
4874
5445
|
To publish a new version:
|
|
@@ -4879,12 +5450,16 @@ Or use the --bump flag:
|
|
|
4879
5450
|
onexthm publish --bump patch (${version2} -> ${patchVer})
|
|
4880
5451
|
onexthm publish --bump minor (${version2} -> ${minorVer})
|
|
4881
5452
|
onexthm publish --bump major (${version2} -> ${majorVer})`
|
|
5453
|
+
);
|
|
5454
|
+
process.exit(1);
|
|
5455
|
+
}
|
|
5456
|
+
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
5457
|
+
} catch (error) {
|
|
5458
|
+
logger.stopSpinner(
|
|
5459
|
+
true,
|
|
5460
|
+
"Version check skipped (endpoint not available)"
|
|
4882
5461
|
);
|
|
4883
|
-
process.exit(1);
|
|
4884
5462
|
}
|
|
4885
|
-
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
4886
|
-
} catch (error) {
|
|
4887
|
-
logger.stopSpinner(true, "Version check skipped (endpoint not available)");
|
|
4888
5463
|
}
|
|
4889
5464
|
logger.startSpinner("Building theme...");
|
|
4890
5465
|
try {
|
|
@@ -4901,7 +5476,19 @@ Or use the --bump flag:
|
|
|
4901
5476
|
logger.error(error instanceof Error ? error.message : "Build error");
|
|
4902
5477
|
process.exit(1);
|
|
4903
5478
|
}
|
|
4904
|
-
const distDir =
|
|
5479
|
+
const distDir = path11.join(themePath, "dist");
|
|
5480
|
+
const classification = await runSchemaDiffGate(
|
|
5481
|
+
themeId,
|
|
5482
|
+
distDir,
|
|
5483
|
+
env,
|
|
5484
|
+
options
|
|
5485
|
+
);
|
|
5486
|
+
if (options.dryRun) {
|
|
5487
|
+
const exitCode = classification?.highest === "breaking" || classification?.highest === "breaking-severe" || classification?.highest === "breaking-asset" ? 2 : 0;
|
|
5488
|
+
logger.newLine();
|
|
5489
|
+
logger.info(`Dry run complete (exit ${exitCode}). No files uploaded.`);
|
|
5490
|
+
process.exit(exitCode);
|
|
5491
|
+
}
|
|
4905
5492
|
let assetEntries = [];
|
|
4906
5493
|
try {
|
|
4907
5494
|
assetEntries = await scanThemeAssets(distDir);
|
|
@@ -4938,7 +5525,7 @@ Or use the --bump flag:
|
|
|
4938
5525
|
for (const [originalPath, url] of Object.entries(videoUrls)) {
|
|
4939
5526
|
assetMap[originalPath] = url;
|
|
4940
5527
|
}
|
|
4941
|
-
const assetMapPath =
|
|
5528
|
+
const assetMapPath = path11.join(distDir, "asset-map.json");
|
|
4942
5529
|
await fs.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
|
|
4943
5530
|
} catch (error) {
|
|
4944
5531
|
logger.error(
|
|
@@ -5061,7 +5648,7 @@ Or use the --bump flag:
|
|
|
5061
5648
|
logger.error("Build the theme first: onexthm build");
|
|
5062
5649
|
process.exit(1);
|
|
5063
5650
|
}
|
|
5064
|
-
const bundleZipPath =
|
|
5651
|
+
const bundleZipPath = path11.join(themePath, "dist", "bundle.zip");
|
|
5065
5652
|
await createZip(distDir, bundleZipPath, [
|
|
5066
5653
|
"bundle.zip",
|
|
5067
5654
|
"source.zip",
|
|
@@ -5088,7 +5675,7 @@ Or use the --bump flag:
|
|
|
5088
5675
|
}
|
|
5089
5676
|
logger.startSpinner("Uploading source...");
|
|
5090
5677
|
try {
|
|
5091
|
-
const sourceZipPath =
|
|
5678
|
+
const sourceZipPath = path11.join(themePath, "dist", "source.zip");
|
|
5092
5679
|
await createZip(themePath, sourceZipPath, [
|
|
5093
5680
|
"node_modules",
|
|
5094
5681
|
"dist",
|
|
@@ -5174,7 +5761,7 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir, env = "dev")
|
|
|
5174
5761
|
let imageBase64 = null;
|
|
5175
5762
|
let mimeType = "image/png";
|
|
5176
5763
|
for (const { file, mime } of THUMBNAIL_CANDIDATES) {
|
|
5177
|
-
const candidate =
|
|
5764
|
+
const candidate = path11.join(themePath, file);
|
|
5178
5765
|
if (fs.existsSync(candidate)) {
|
|
5179
5766
|
const buf = fs.readFileSync(candidate);
|
|
5180
5767
|
imageBase64 = `data:${mime};base64,${buf.toString("base64")}`;
|
|
@@ -5276,7 +5863,7 @@ async function screenshotHomePage(themePath, distDir) {
|
|
|
5276
5863
|
const { compilePreviewRuntime: compilePreviewRuntime2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
5277
5864
|
const { createDevServer: createDevServer2 } = await Promise.resolve().then(() => (init_dev_server(), dev_server_exports));
|
|
5278
5865
|
const previewRuntimePath = await compilePreviewRuntime2(themePath);
|
|
5279
|
-
const themeName =
|
|
5866
|
+
const themeName = path11.basename(themePath);
|
|
5280
5867
|
const port = await findFreePort(4500);
|
|
5281
5868
|
const server = createDevServer2({
|
|
5282
5869
|
port,
|
|
@@ -5333,7 +5920,7 @@ async function findFreePort(start) {
|
|
|
5333
5920
|
});
|
|
5334
5921
|
}
|
|
5335
5922
|
async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
|
|
5336
|
-
const fileName =
|
|
5923
|
+
const fileName = path11.basename(video.originalPath);
|
|
5337
5924
|
const videoInitUrl = `${apiUrl}/media/videos/multipart/init`;
|
|
5338
5925
|
const videoInitBody = {
|
|
5339
5926
|
file_name: fileName,
|
|
@@ -5462,6 +6049,91 @@ async function createZip(sourceDir, outputPath, exclude) {
|
|
|
5462
6049
|
archive.finalize();
|
|
5463
6050
|
});
|
|
5464
6051
|
}
|
|
6052
|
+
async function runSchemaDiffGate(themeId, distDir, env, options) {
|
|
6053
|
+
logger.startSpinner("Fetching prior version for diff...");
|
|
6054
|
+
const { result: prior, reason } = await fetchPriorGateManifests(themeId, env);
|
|
6055
|
+
if (!prior) {
|
|
6056
|
+
if (reason === "no-prior") {
|
|
6057
|
+
logger.stopSpinner(true, "First publish \u2014 no prior version to diff");
|
|
6058
|
+
} else {
|
|
6059
|
+
logger.stopSpinner(true, `Gate skipped (${reason})`);
|
|
6060
|
+
}
|
|
6061
|
+
return null;
|
|
6062
|
+
}
|
|
6063
|
+
logger.stopSpinner(true, `Fetched prior version ${prior.version}`);
|
|
6064
|
+
let currentSchemas;
|
|
6065
|
+
let currentAssets;
|
|
6066
|
+
try {
|
|
6067
|
+
currentSchemas = JSON.parse(
|
|
6068
|
+
await fs.readFile(path11.join(distDir, "schemas.json"), "utf-8")
|
|
6069
|
+
);
|
|
6070
|
+
} catch (err) {
|
|
6071
|
+
logger.warning(
|
|
6072
|
+
`Gate skipped: dist/schemas.json missing or unreadable (${err instanceof Error ? err.message : "unknown"})`
|
|
6073
|
+
);
|
|
6074
|
+
return null;
|
|
6075
|
+
}
|
|
6076
|
+
try {
|
|
6077
|
+
currentAssets = JSON.parse(
|
|
6078
|
+
await fs.readFile(path11.join(distDir, "asset-manifest.json"), "utf-8")
|
|
6079
|
+
);
|
|
6080
|
+
} catch {
|
|
6081
|
+
currentAssets = { manifestVersion: 1, assets: [] };
|
|
6082
|
+
}
|
|
6083
|
+
const changes = diffManifests(
|
|
6084
|
+
{ schemas: prior.schemas, assets: prior.assets },
|
|
6085
|
+
{ schemas: currentSchemas, assets: currentAssets }
|
|
6086
|
+
);
|
|
6087
|
+
const classification = classify(changes);
|
|
6088
|
+
printGateReport(prior.version, classification);
|
|
6089
|
+
if (options.dryRun) return classification;
|
|
6090
|
+
const isBreaking = classification.highest === "breaking" || classification.highest === "breaking-severe" || classification.highest === "breaking-asset";
|
|
6091
|
+
if (isBreaking && !options.force) {
|
|
6092
|
+
logger.error(
|
|
6093
|
+
"\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)."
|
|
6094
|
+
);
|
|
6095
|
+
process.exit(1);
|
|
6096
|
+
}
|
|
6097
|
+
if (classification.highest === "defaults-only" && !options.confirmDefaults) {
|
|
6098
|
+
logger.error(
|
|
6099
|
+
"\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."
|
|
6100
|
+
);
|
|
6101
|
+
process.exit(1);
|
|
6102
|
+
}
|
|
6103
|
+
return classification;
|
|
6104
|
+
}
|
|
6105
|
+
function printGateReport(priorVersion, classification) {
|
|
6106
|
+
logger.newLine();
|
|
6107
|
+
logger.info(`Schema diff vs. v${priorVersion}:`);
|
|
6108
|
+
if (classification.changes.length === 0) {
|
|
6109
|
+
logger.log(" \u2713 Safe \u2014 no schema changes detected");
|
|
6110
|
+
return;
|
|
6111
|
+
}
|
|
6112
|
+
for (const change of classification.changes) {
|
|
6113
|
+
const icon = iconFor(change.kind);
|
|
6114
|
+
logger.log(` ${icon} [${change.kind}] ${change.path} \u2014 ${change.detail}`);
|
|
6115
|
+
}
|
|
6116
|
+
logger.log(
|
|
6117
|
+
`
|
|
6118
|
+
\u2192 Classification: ${classification.highest}. Suggested bump: ${classification.bump}.`
|
|
6119
|
+
);
|
|
6120
|
+
}
|
|
6121
|
+
function iconFor(kind) {
|
|
6122
|
+
switch (kind) {
|
|
6123
|
+
case "safe":
|
|
6124
|
+
case "safe-rename":
|
|
6125
|
+
return "\u2713";
|
|
6126
|
+
case "additive":
|
|
6127
|
+
return "+";
|
|
6128
|
+
case "defaults-only":
|
|
6129
|
+
return "\u26A0";
|
|
6130
|
+
case "breaking":
|
|
6131
|
+
case "breaking-asset":
|
|
6132
|
+
return "\u2717";
|
|
6133
|
+
case "breaking-severe":
|
|
6134
|
+
return "\u2717\u2717";
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
5465
6137
|
|
|
5466
6138
|
// src/commands/mcp.ts
|
|
5467
6139
|
init_logger();
|
|
@@ -5473,18 +6145,18 @@ var AI_CONTEXT_FILES = [
|
|
|
5473
6145
|
".mcp.json"
|
|
5474
6146
|
];
|
|
5475
6147
|
function resolveTargetDir(opts) {
|
|
5476
|
-
return
|
|
6148
|
+
return path11.resolve(opts.cwd ?? process.cwd());
|
|
5477
6149
|
}
|
|
5478
6150
|
function resolveDefaultTemplateDir() {
|
|
5479
|
-
return
|
|
6151
|
+
return path11.join(getTemplatesDir(), "default");
|
|
5480
6152
|
}
|
|
5481
6153
|
function isThemeDir(dir) {
|
|
5482
|
-
return fs.existsSync(
|
|
6154
|
+
return fs.existsSync(path11.join(dir, "theme.config.ts")) || fs.existsSync(path11.join(dir, "theme.config.js"));
|
|
5483
6155
|
}
|
|
5484
6156
|
function inspectFiles(templateDir, targetDir) {
|
|
5485
6157
|
return AI_CONTEXT_FILES.map((name) => {
|
|
5486
|
-
const templatePath =
|
|
5487
|
-
const targetPath =
|
|
6158
|
+
const templatePath = path11.join(templateDir, name);
|
|
6159
|
+
const targetPath = path11.join(targetDir, name);
|
|
5488
6160
|
const exists = fs.existsSync(targetPath);
|
|
5489
6161
|
let identical = false;
|
|
5490
6162
|
if (exists && fs.existsSync(templatePath)) {
|
|
@@ -5627,7 +6299,7 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5627
6299
|
return;
|
|
5628
6300
|
}
|
|
5629
6301
|
logger.success("theme.config.ts present");
|
|
5630
|
-
const mcpJsonPath =
|
|
6302
|
+
const mcpJsonPath = path11.join(targetDir, ".mcp.json");
|
|
5631
6303
|
if (!fs.existsSync(mcpJsonPath)) {
|
|
5632
6304
|
logger.error(".mcp.json missing \u2014 run `onexthm mcp setup`");
|
|
5633
6305
|
} else {
|
|
@@ -5665,7 +6337,7 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5665
6337
|
logger.success(`${s.name} up to date`);
|
|
5666
6338
|
}
|
|
5667
6339
|
}
|
|
5668
|
-
const registryPath =
|
|
6340
|
+
const registryPath = path11.join(targetDir, "sections-registry.ts");
|
|
5669
6341
|
if (fs.existsSync(registryPath)) {
|
|
5670
6342
|
logger.success("sections-registry.ts present");
|
|
5671
6343
|
} else {
|
|
@@ -5677,22 +6349,22 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5677
6349
|
|
|
5678
6350
|
// src/cli.ts
|
|
5679
6351
|
dotenv.config({
|
|
5680
|
-
path:
|
|
6352
|
+
path: path11.join(process.cwd(), ".env.local"),
|
|
5681
6353
|
override: true
|
|
5682
6354
|
});
|
|
5683
|
-
dotenv.config({ path:
|
|
6355
|
+
dotenv.config({ path: path11.join(process.cwd(), ".env") });
|
|
5684
6356
|
try {
|
|
5685
6357
|
const projectRoot = getProjectRoot();
|
|
5686
|
-
if (
|
|
6358
|
+
if (path11.resolve(projectRoot) !== path11.resolve(process.cwd())) {
|
|
5687
6359
|
dotenv.config({
|
|
5688
|
-
path:
|
|
6360
|
+
path: path11.join(projectRoot, ".env.local")
|
|
5689
6361
|
});
|
|
5690
|
-
dotenv.config({ path:
|
|
6362
|
+
dotenv.config({ path: path11.join(projectRoot, ".env") });
|
|
5691
6363
|
}
|
|
5692
6364
|
} catch {
|
|
5693
6365
|
}
|
|
5694
6366
|
dotenv.config({
|
|
5695
|
-
path:
|
|
6367
|
+
path: path11.join(os.homedir(), ".onexthm", ".env"),
|
|
5696
6368
|
quiet: true
|
|
5697
6369
|
});
|
|
5698
6370
|
var require2 = createRequire(import.meta.url);
|
|
@@ -5705,7 +6377,7 @@ program.command("init").description("Create a new OneX theme project").argument(
|
|
|
5705
6377
|
"default"
|
|
5706
6378
|
).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").option(
|
|
5707
6379
|
"--env <env>",
|
|
5708
|
-
"Target environment: dev or prod (default: dev)",
|
|
6380
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5709
6381
|
"dev"
|
|
5710
6382
|
).action(initCommand);
|
|
5711
6383
|
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(
|
|
@@ -5736,7 +6408,7 @@ program.command("download").description("Download a published theme via the webs
|
|
|
5736
6408
|
"latest"
|
|
5737
6409
|
).option(
|
|
5738
6410
|
"--env <env>",
|
|
5739
|
-
"Target environment: dev or prod (default: dev)",
|
|
6411
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5740
6412
|
"dev"
|
|
5741
6413
|
).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
|
|
5742
6414
|
program.command("clone").description("Clone theme source code via the website-api").argument("<theme-name>", "Theme to clone").option(
|
|
@@ -5745,23 +6417,23 @@ program.command("clone").description("Clone theme source code via the website-ap
|
|
|
5745
6417
|
"latest"
|
|
5746
6418
|
).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").option(
|
|
5747
6419
|
"--env <env>",
|
|
5748
|
-
"Target environment: dev or prod (default: dev)",
|
|
6420
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5749
6421
|
"dev"
|
|
5750
6422
|
).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
5751
6423
|
program.command("config").description("Configure OneX CLI credentials (AWS, API keys)").action(configCommand);
|
|
5752
6424
|
program.command("login").description("Login to OneX platform").option(
|
|
5753
6425
|
"--env <env>",
|
|
5754
|
-
"Target environment: dev or prod (default: dev)",
|
|
6426
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5755
6427
|
"dev"
|
|
5756
6428
|
).action(loginCommand);
|
|
5757
6429
|
program.command("logout").description("Logout from OneX platform").option(
|
|
5758
6430
|
"--env <env>",
|
|
5759
|
-
"Target environment: dev or prod (default: dev)",
|
|
6431
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5760
6432
|
"dev"
|
|
5761
6433
|
).action(logoutCommand);
|
|
5762
6434
|
program.command("whoami").description("Show current logged-in developer").option(
|
|
5763
6435
|
"--env <env>",
|
|
5764
|
-
"Target environment: dev or prod (default: dev)",
|
|
6436
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5765
6437
|
"dev"
|
|
5766
6438
|
).action(whoamiCommand);
|
|
5767
6439
|
var mcpCmd = program.command("mcp").description("Manage MCP server registration and AI-context files");
|
|
@@ -5777,8 +6449,17 @@ program.command("publish").description("Build, scan, and publish theme to market
|
|
|
5777
6449
|
"Auto-bump version before publish (patch|minor|major)"
|
|
5778
6450
|
).option(
|
|
5779
6451
|
"--env <env>",
|
|
5780
|
-
"Target environment: dev or prod (default: dev)",
|
|
6452
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
5781
6453
|
"dev"
|
|
6454
|
+
).option(
|
|
6455
|
+
"--dry-run",
|
|
6456
|
+
"Build locally and print the schema-diff classification without publishing"
|
|
6457
|
+
).option(
|
|
6458
|
+
"--confirm-defaults",
|
|
6459
|
+
"Confirm that changed section/block defaults should propagate to live sites"
|
|
6460
|
+
).option(
|
|
6461
|
+
"--force",
|
|
6462
|
+
"Publish even when the diff gate detects a breaking change"
|
|
5782
6463
|
).action(publishCommand);
|
|
5783
6464
|
program.configureOutput({
|
|
5784
6465
|
writeErr: (str) => process.stderr.write(chalk4.red(str))
|