@onexapis/cli 1.1.64 → 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 +1350 -507
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1346 -503
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +10 -17
- package/dist/index.d.ts +10 -17
- package/dist/index.js +477 -230
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +473 -226
- package/dist/index.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +89 -7
- package/package.json +2 -2
- package/templates/default/.env.example +1 -1
package/dist/cli.js
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
|
|
4
4
|
var chalk4 = require('chalk');
|
|
5
5
|
var ora = require('ora');
|
|
6
|
-
var
|
|
7
|
-
var path9 = require('path');
|
|
8
|
-
var fs8 = require('fs/promises');
|
|
9
|
-
var crypto = require('crypto');
|
|
6
|
+
var path11 = require('path');
|
|
10
7
|
var glob = require('glob');
|
|
8
|
+
var fs = require('fs-extra');
|
|
9
|
+
var crypto = require('crypto');
|
|
10
|
+
var esbuild = require('esbuild');
|
|
11
|
+
var fs9 = require('fs/promises');
|
|
11
12
|
var module$1 = require('module');
|
|
12
13
|
var http = require('http');
|
|
13
14
|
var fs3 = require('fs');
|
|
14
15
|
var ws = require('ws');
|
|
15
16
|
var os = require('os');
|
|
16
17
|
var dotenv = require('dotenv');
|
|
17
|
-
var fs = require('fs-extra');
|
|
18
18
|
var ejs = require('ejs');
|
|
19
19
|
var child_process = require('child_process');
|
|
20
20
|
var commander = require('commander');
|
|
@@ -49,15 +49,15 @@ function _interopNamespace(e) {
|
|
|
49
49
|
|
|
50
50
|
var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
|
|
51
51
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
52
|
-
var
|
|
53
|
-
var
|
|
54
|
-
var fs8__default = /*#__PURE__*/_interopDefault(fs8);
|
|
52
|
+
var path11__default = /*#__PURE__*/_interopDefault(path11);
|
|
53
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
55
54
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
55
|
+
var esbuild__namespace = /*#__PURE__*/_interopNamespace(esbuild);
|
|
56
|
+
var fs9__default = /*#__PURE__*/_interopDefault(fs9);
|
|
56
57
|
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
57
58
|
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
58
59
|
var os__default = /*#__PURE__*/_interopDefault(os);
|
|
59
60
|
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
60
|
-
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
61
61
|
var ejs__default = /*#__PURE__*/_interopDefault(ejs);
|
|
62
62
|
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
63
63
|
var archiver__default = /*#__PURE__*/_interopDefault(archiver);
|
|
@@ -132,6 +132,206 @@ var init_logger = __esm({
|
|
|
132
132
|
logger = new Logger();
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
|
+
function sortedCopy(value) {
|
|
136
|
+
if (Array.isArray(value)) {
|
|
137
|
+
return value.map((v) => sortedCopy(v));
|
|
138
|
+
}
|
|
139
|
+
if (value && typeof value === "object") {
|
|
140
|
+
const sorted = {};
|
|
141
|
+
for (const key of Object.keys(value).sort()) {
|
|
142
|
+
sorted[key] = sortedCopy(value[key]);
|
|
143
|
+
}
|
|
144
|
+
return sorted;
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
function normalizeField(raw) {
|
|
149
|
+
const out = {
|
|
150
|
+
id: String(raw.id),
|
|
151
|
+
type: String(raw.type)
|
|
152
|
+
};
|
|
153
|
+
if (raw.required === true) out.required = true;
|
|
154
|
+
if (raw.default !== void 0) out.default = raw.default;
|
|
155
|
+
if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
|
|
156
|
+
out.aliases = [...raw.aliases].map(String).sort();
|
|
157
|
+
}
|
|
158
|
+
if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
|
|
159
|
+
if (typeof raw.min === "number") out.min = raw.min;
|
|
160
|
+
if (typeof raw.max === "number") out.max = raw.max;
|
|
161
|
+
if (typeof raw.step === "number") out.step = raw.step;
|
|
162
|
+
if (Array.isArray(raw.accept)) {
|
|
163
|
+
out.accept = [...raw.accept].map(String).sort();
|
|
164
|
+
}
|
|
165
|
+
if (Array.isArray(raw.options)) {
|
|
166
|
+
out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
function normalizeBlock(raw) {
|
|
171
|
+
return {
|
|
172
|
+
type: String(raw.type),
|
|
173
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
174
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
175
|
+
...typeof raw.limit === "number" ? { limit: raw.limit } : {},
|
|
176
|
+
...typeof raw.min === "number" ? { min: raw.min } : {},
|
|
177
|
+
...raw.sortable === true ? { sortable: true } : {},
|
|
178
|
+
...raw.baseType ? { baseType: String(raw.baseType) } : {}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function normalizeTemplate(raw) {
|
|
182
|
+
const out = { id: String(raw.id) };
|
|
183
|
+
if (raw.isDefault === true) out.isDefault = true;
|
|
184
|
+
if (Array.isArray(raw.settings)) {
|
|
185
|
+
out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
|
|
186
|
+
}
|
|
187
|
+
if (raw.defaults && typeof raw.defaults === "object") {
|
|
188
|
+
out.defaults = sortedCopy(raw.defaults);
|
|
189
|
+
}
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
function sortFieldsById(a, b) {
|
|
193
|
+
return a.id.localeCompare(b.id);
|
|
194
|
+
}
|
|
195
|
+
function sortByType(a, b) {
|
|
196
|
+
return a.type.localeCompare(b.type);
|
|
197
|
+
}
|
|
198
|
+
function normalizeSection(raw) {
|
|
199
|
+
return {
|
|
200
|
+
type: String(raw.type),
|
|
201
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
202
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
203
|
+
blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
|
|
204
|
+
templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
|
|
205
|
+
dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
|
|
206
|
+
...raw.global === true ? { global: true } : {},
|
|
207
|
+
...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async function extractSchemas(themePath) {
|
|
211
|
+
const { createJiti } = await import('jiti');
|
|
212
|
+
const jiti = createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
213
|
+
const schemaFiles = await glob.glob("sections/**/*.schema.ts", { cwd: themePath });
|
|
214
|
+
const sections = {};
|
|
215
|
+
for (const file of schemaFiles) {
|
|
216
|
+
try {
|
|
217
|
+
const mod = await jiti.import(path11__default.default.join(themePath, file));
|
|
218
|
+
const exports$1 = mod;
|
|
219
|
+
for (const value of Object.values(exports$1)) {
|
|
220
|
+
if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
|
|
221
|
+
const section = normalizeSection(value);
|
|
222
|
+
sections[section.type] = section;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const manifest = {
|
|
229
|
+
manifestVersion: 1,
|
|
230
|
+
sections: {}
|
|
231
|
+
};
|
|
232
|
+
for (const type of Object.keys(sections).sort()) {
|
|
233
|
+
manifest.sections[type] = sections[type];
|
|
234
|
+
}
|
|
235
|
+
return manifest;
|
|
236
|
+
}
|
|
237
|
+
function serializeManifest(manifest) {
|
|
238
|
+
return JSON.stringify(sortedCopy(manifest), null, 2);
|
|
239
|
+
}
|
|
240
|
+
var init_extract_schemas = __esm({
|
|
241
|
+
"src/utils/extract-schemas.ts"() {
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
function isVideoAsset(filePath) {
|
|
245
|
+
const lower = filePath.toLowerCase();
|
|
246
|
+
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
247
|
+
}
|
|
248
|
+
function mimeFor(filename) {
|
|
249
|
+
const ext = path11__default.default.extname(filename).toLowerCase();
|
|
250
|
+
return MIME_MAP[ext] || "application/octet-stream";
|
|
251
|
+
}
|
|
252
|
+
async function sha256Prefix(absPath, len) {
|
|
253
|
+
const buf = await fs__default.default.readFile(absPath);
|
|
254
|
+
return crypto__default.default.createHash("sha256").update(buf).digest("hex").slice(0, len);
|
|
255
|
+
}
|
|
256
|
+
function insertHashIntoName(relPath, hash) {
|
|
257
|
+
const dir = path11__default.default.posix.dirname(relPath);
|
|
258
|
+
const base = path11__default.default.posix.basename(relPath);
|
|
259
|
+
const ext = path11__default.default.posix.extname(base);
|
|
260
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
261
|
+
const hashed = `${stem}-${hash}${ext}`;
|
|
262
|
+
return dir === "." ? hashed : `${dir}/${hashed}`;
|
|
263
|
+
}
|
|
264
|
+
async function scanThemeAssets(distDir) {
|
|
265
|
+
const assetsDir = path11__default.default.join(distDir, "theme-assets");
|
|
266
|
+
if (!await fs__default.default.pathExists(assetsDir)) return [];
|
|
267
|
+
const files = await glob.glob("**/*", {
|
|
268
|
+
cwd: assetsDir,
|
|
269
|
+
nodir: true,
|
|
270
|
+
dot: false
|
|
271
|
+
});
|
|
272
|
+
const results = [];
|
|
273
|
+
for (const rel of files) {
|
|
274
|
+
const absPath = path11__default.default.join(assetsDir, rel);
|
|
275
|
+
const stat = await fs__default.default.stat(absPath);
|
|
276
|
+
if (!stat.isFile()) continue;
|
|
277
|
+
const originalPath = rel.split(path11__default.default.sep).join("/");
|
|
278
|
+
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
279
|
+
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
280
|
+
const contentType = mimeFor(rel);
|
|
281
|
+
results.push({
|
|
282
|
+
originalPath,
|
|
283
|
+
hashedPath,
|
|
284
|
+
hash,
|
|
285
|
+
size: stat.size,
|
|
286
|
+
contentType,
|
|
287
|
+
absPath
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
|
|
291
|
+
return results;
|
|
292
|
+
}
|
|
293
|
+
function buildAssetMap(entries) {
|
|
294
|
+
const map = {};
|
|
295
|
+
for (const e of entries) {
|
|
296
|
+
map[e.originalPath] = e.hashedPath;
|
|
297
|
+
}
|
|
298
|
+
return map;
|
|
299
|
+
}
|
|
300
|
+
var MIME_MAP, HASH_LEN, VIDEO_EXTENSIONS;
|
|
301
|
+
var init_scan_theme_assets = __esm({
|
|
302
|
+
"src/utils/scan-theme-assets.ts"() {
|
|
303
|
+
MIME_MAP = {
|
|
304
|
+
".png": "image/png",
|
|
305
|
+
".jpg": "image/jpeg",
|
|
306
|
+
".jpeg": "image/jpeg",
|
|
307
|
+
".gif": "image/gif",
|
|
308
|
+
".webp": "image/webp",
|
|
309
|
+
".avif": "image/avif",
|
|
310
|
+
".svg": "image/svg+xml",
|
|
311
|
+
".ico": "image/x-icon",
|
|
312
|
+
".bmp": "image/bmp",
|
|
313
|
+
".woff": "font/woff",
|
|
314
|
+
".woff2": "font/woff2",
|
|
315
|
+
".ttf": "font/ttf",
|
|
316
|
+
".otf": "font/otf",
|
|
317
|
+
".eot": "application/vnd.ms-fontobject",
|
|
318
|
+
".mp4": "video/mp4",
|
|
319
|
+
".webm": "video/webm",
|
|
320
|
+
".mov": "video/quicktime",
|
|
321
|
+
".ogg": "video/ogg",
|
|
322
|
+
".json": "application/json"
|
|
323
|
+
};
|
|
324
|
+
HASH_LEN = 8;
|
|
325
|
+
VIDEO_EXTENSIONS = [
|
|
326
|
+
".mp4",
|
|
327
|
+
".webm",
|
|
328
|
+
".ogg",
|
|
329
|
+
".mov",
|
|
330
|
+
".avi",
|
|
331
|
+
".mkv"
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
});
|
|
135
335
|
|
|
136
336
|
// src/utils/compile-theme.ts
|
|
137
337
|
var compile_theme_exports = {};
|
|
@@ -147,8 +347,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
147
347
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
148
348
|
const tailwindConfig = {
|
|
149
349
|
content: [
|
|
150
|
-
|
|
151
|
-
|
|
350
|
+
path11__default.default.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
351
|
+
path11__default.default.join(themePath, "components/**/*.{ts,tsx}")
|
|
152
352
|
],
|
|
153
353
|
theme: { extend: {} },
|
|
154
354
|
plugins: []
|
|
@@ -158,7 +358,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
158
358
|
inputCSS,
|
|
159
359
|
{ from: void 0 }
|
|
160
360
|
);
|
|
161
|
-
await
|
|
361
|
+
await fs9__default.default.writeFile(path11__default.default.join(outDir, "bundle.css"), result.css);
|
|
162
362
|
logger.info("Generated bundle.css");
|
|
163
363
|
} catch (err) {
|
|
164
364
|
logger.warning(
|
|
@@ -169,12 +369,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
169
369
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
170
370
|
let dir = startDir;
|
|
171
371
|
while (true) {
|
|
172
|
-
const candidate =
|
|
372
|
+
const candidate = path11__default.default.join(dir, "node_modules", relativePath);
|
|
173
373
|
try {
|
|
174
|
-
await
|
|
374
|
+
await fs9__default.default.access(candidate);
|
|
175
375
|
return candidate;
|
|
176
376
|
} catch {
|
|
177
|
-
const parent =
|
|
377
|
+
const parent = path11__default.default.dirname(dir);
|
|
178
378
|
if (parent === dir) break;
|
|
179
379
|
dir = parent;
|
|
180
380
|
}
|
|
@@ -198,7 +398,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
198
398
|
});
|
|
199
399
|
for (const file of sourceFiles) {
|
|
200
400
|
try {
|
|
201
|
-
const content = await
|
|
401
|
+
const content = await fs9__default.default.readFile(path11__default.default.join(sourceDir, file), "utf-8");
|
|
202
402
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
203
403
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
204
404
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -252,17 +452,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
252
452
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
253
453
|
let distPath = await resolveNodeModulesFile(
|
|
254
454
|
themePath,
|
|
255
|
-
|
|
455
|
+
path11__default.default.join("@onexapis", "core", "dist", distFileName)
|
|
256
456
|
);
|
|
257
457
|
if (!distPath) {
|
|
258
458
|
distPath = await resolveNodeModulesFile(
|
|
259
459
|
__dirname,
|
|
260
|
-
|
|
460
|
+
path11__default.default.join("@onexapis", "core", "dist", distFileName)
|
|
261
461
|
);
|
|
262
462
|
}
|
|
263
463
|
try {
|
|
264
464
|
if (!distPath) throw new Error("not found");
|
|
265
|
-
const distContent = await
|
|
465
|
+
const distContent = await fs9__default.default.readFile(distPath, "utf-8");
|
|
266
466
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
267
467
|
for (const m of exportMatches) {
|
|
268
468
|
const names = m[1].split(",").map((n) => {
|
|
@@ -491,7 +691,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
491
691
|
const pages = {};
|
|
492
692
|
for (const ext of [".ts", ".js"]) {
|
|
493
693
|
try {
|
|
494
|
-
const mod = await jiti.import(
|
|
694
|
+
const mod = await jiti.import(path11__default.default.join(themePath, `theme.config${ext}`));
|
|
495
695
|
themeConfig = mod.default || mod;
|
|
496
696
|
break;
|
|
497
697
|
} catch {
|
|
@@ -499,20 +699,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
499
699
|
}
|
|
500
700
|
for (const ext of [".ts", ".js"]) {
|
|
501
701
|
try {
|
|
502
|
-
const mod = await jiti.import(
|
|
702
|
+
const mod = await jiti.import(path11__default.default.join(themePath, `theme.layout${ext}`));
|
|
503
703
|
layoutConfig = mod.default || mod;
|
|
504
704
|
break;
|
|
505
705
|
} catch {
|
|
506
706
|
}
|
|
507
707
|
}
|
|
508
708
|
const schemas = {};
|
|
509
|
-
const sectionsDir =
|
|
709
|
+
const sectionsDir = path11__default.default.join(themePath, "sections");
|
|
510
710
|
try {
|
|
511
|
-
const sectionDirs = await
|
|
711
|
+
const sectionDirs = await fs9__default.default.readdir(sectionsDir);
|
|
512
712
|
for (const dir of sectionDirs) {
|
|
513
|
-
const schemaFile =
|
|
713
|
+
const schemaFile = path11__default.default.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
514
714
|
try {
|
|
515
|
-
await
|
|
715
|
+
await fs9__default.default.access(schemaFile);
|
|
516
716
|
const mod = await jiti.import(schemaFile);
|
|
517
717
|
for (const [key, value] of Object.entries(mod)) {
|
|
518
718
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -524,14 +724,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
524
724
|
}
|
|
525
725
|
} catch {
|
|
526
726
|
}
|
|
527
|
-
const pagesDir =
|
|
727
|
+
const pagesDir = path11__default.default.join(themePath, "pages");
|
|
528
728
|
try {
|
|
529
|
-
const files = await
|
|
729
|
+
const files = await fs9__default.default.readdir(pagesDir);
|
|
530
730
|
for (const file of files) {
|
|
531
731
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
532
732
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
533
733
|
try {
|
|
534
|
-
const mod = await jiti.import(
|
|
734
|
+
const mod = await jiti.import(path11__default.default.join(pagesDir, file));
|
|
535
735
|
const config = mod.default || mod;
|
|
536
736
|
const sections = (config.sections || []).map((section) => {
|
|
537
737
|
const schema = schemas[section.type];
|
|
@@ -559,8 +759,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
559
759
|
}
|
|
560
760
|
} catch {
|
|
561
761
|
}
|
|
562
|
-
await
|
|
563
|
-
|
|
762
|
+
await fs9__default.default.writeFile(
|
|
763
|
+
path11__default.default.join(outputDir, "theme-data.json"),
|
|
564
764
|
JSON.stringify(
|
|
565
765
|
{
|
|
566
766
|
themeId,
|
|
@@ -583,22 +783,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
583
783
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
584
784
|
}
|
|
585
785
|
async function contentHashEntry(outputDir) {
|
|
586
|
-
const entryPath =
|
|
587
|
-
const mapPath =
|
|
786
|
+
const entryPath = path11__default.default.join(outputDir, "bundle-entry.js");
|
|
787
|
+
const mapPath = path11__default.default.join(outputDir, "bundle-entry.js.map");
|
|
588
788
|
let entryContent;
|
|
589
789
|
try {
|
|
590
|
-
entryContent = await
|
|
790
|
+
entryContent = await fs9__default.default.readFile(entryPath, "utf-8");
|
|
591
791
|
} catch {
|
|
592
|
-
const indexPath =
|
|
792
|
+
const indexPath = path11__default.default.join(outputDir, "index.js");
|
|
593
793
|
try {
|
|
594
|
-
entryContent = await
|
|
794
|
+
entryContent = await fs9__default.default.readFile(indexPath, "utf-8");
|
|
595
795
|
} catch {
|
|
596
796
|
logger.warning("No entry file found in output, skipping content hash");
|
|
597
797
|
return;
|
|
598
798
|
}
|
|
599
799
|
const hash2 = crypto__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
600
800
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
601
|
-
const indexMapPath =
|
|
801
|
+
const indexMapPath = path11__default.default.join(outputDir, "index.js.map");
|
|
602
802
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
603
803
|
entryContent = entryContent.replace(
|
|
604
804
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
@@ -606,18 +806,18 @@ async function contentHashEntry(outputDir) {
|
|
|
606
806
|
);
|
|
607
807
|
const oldFiles2 = await glob.glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
608
808
|
for (const f of oldFiles2) {
|
|
609
|
-
await
|
|
809
|
+
await fs9__default.default.unlink(path11__default.default.join(outputDir, f));
|
|
610
810
|
}
|
|
611
|
-
await
|
|
612
|
-
await
|
|
811
|
+
await fs9__default.default.writeFile(path11__default.default.join(outputDir, hashedName2), entryContent);
|
|
812
|
+
await fs9__default.default.unlink(indexPath);
|
|
613
813
|
try {
|
|
614
|
-
await
|
|
814
|
+
await fs9__default.default.unlink(entryPath);
|
|
615
815
|
} catch {
|
|
616
816
|
}
|
|
617
|
-
await
|
|
817
|
+
await fs9__default.default.writeFile(entryPath, entryContent);
|
|
618
818
|
try {
|
|
619
|
-
await
|
|
620
|
-
await
|
|
819
|
+
await fs9__default.default.access(indexMapPath);
|
|
820
|
+
await fs9__default.default.rename(indexMapPath, path11__default.default.join(outputDir, hashedMapName2));
|
|
621
821
|
} catch {
|
|
622
822
|
}
|
|
623
823
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
@@ -632,17 +832,17 @@ async function contentHashEntry(outputDir) {
|
|
|
632
832
|
);
|
|
633
833
|
const oldFiles = await glob.glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
634
834
|
for (const f of oldFiles) {
|
|
635
|
-
await
|
|
835
|
+
await fs9__default.default.unlink(path11__default.default.join(outputDir, f));
|
|
636
836
|
}
|
|
637
|
-
await
|
|
837
|
+
await fs9__default.default.writeFile(path11__default.default.join(outputDir, hashedName), entryContent);
|
|
638
838
|
try {
|
|
639
|
-
await
|
|
839
|
+
await fs9__default.default.unlink(entryPath);
|
|
640
840
|
} catch {
|
|
641
841
|
}
|
|
642
|
-
await
|
|
842
|
+
await fs9__default.default.writeFile(entryPath, entryContent);
|
|
643
843
|
try {
|
|
644
|
-
await
|
|
645
|
-
await
|
|
844
|
+
await fs9__default.default.access(mapPath);
|
|
845
|
+
await fs9__default.default.rename(mapPath, path11__default.default.join(outputDir, hashedMapName));
|
|
646
846
|
} catch {
|
|
647
847
|
}
|
|
648
848
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -654,7 +854,7 @@ async function extractDataRequirements(themePath) {
|
|
|
654
854
|
const requirements = {};
|
|
655
855
|
for (const file of schemaFiles) {
|
|
656
856
|
try {
|
|
657
|
-
const mod = await jiti.import(
|
|
857
|
+
const mod = await jiti.import(path11__default.default.join(themePath, file));
|
|
658
858
|
const exports$1 = mod;
|
|
659
859
|
for (const value of Object.values(exports$1)) {
|
|
660
860
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -669,12 +869,46 @@ async function extractDataRequirements(themePath) {
|
|
|
669
869
|
}
|
|
670
870
|
return requirements;
|
|
671
871
|
}
|
|
872
|
+
async function writeGateManifests(themePath, outputDir) {
|
|
873
|
+
try {
|
|
874
|
+
const schemas = await extractSchemas(themePath);
|
|
875
|
+
await fs9__default.default.writeFile(
|
|
876
|
+
path11__default.default.join(outputDir, "schemas.json"),
|
|
877
|
+
serializeManifest(schemas)
|
|
878
|
+
);
|
|
879
|
+
logger.info(
|
|
880
|
+
`Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
|
|
881
|
+
);
|
|
882
|
+
} catch (err) {
|
|
883
|
+
logger.warning(
|
|
884
|
+
`schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
const entries = await scanThemeAssets(outputDir);
|
|
889
|
+
const assets = entries.map((e) => ({
|
|
890
|
+
path: e.originalPath,
|
|
891
|
+
hash: e.hash,
|
|
892
|
+
size: e.size,
|
|
893
|
+
contentType: e.contentType
|
|
894
|
+
}));
|
|
895
|
+
await fs9__default.default.writeFile(
|
|
896
|
+
path11__default.default.join(outputDir, "asset-manifest.json"),
|
|
897
|
+
JSON.stringify({ manifestVersion: 1, assets }, null, 2)
|
|
898
|
+
);
|
|
899
|
+
logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
|
|
900
|
+
} catch (err) {
|
|
901
|
+
logger.warning(
|
|
902
|
+
`asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
672
906
|
async function generateManifest(themeName, themePath, outputDir) {
|
|
673
907
|
let version2 = "1.0.0";
|
|
674
908
|
let themeId = themeName;
|
|
675
909
|
try {
|
|
676
|
-
const pkgContent = await
|
|
677
|
-
|
|
910
|
+
const pkgContent = await fs9__default.default.readFile(
|
|
911
|
+
path11__default.default.join(themePath, "package.json"),
|
|
678
912
|
"utf-8"
|
|
679
913
|
);
|
|
680
914
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -692,7 +926,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
692
926
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
693
927
|
let hasThemeConfig = false;
|
|
694
928
|
try {
|
|
695
|
-
await
|
|
929
|
+
await fs9__default.default.access(path11__default.default.join(themePath, "theme.config.ts"));
|
|
696
930
|
hasThemeConfig = true;
|
|
697
931
|
} catch {
|
|
698
932
|
}
|
|
@@ -733,24 +967,24 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
733
967
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
734
968
|
dataRequirements
|
|
735
969
|
};
|
|
736
|
-
await
|
|
737
|
-
|
|
970
|
+
await fs9__default.default.writeFile(
|
|
971
|
+
path11__default.default.join(outputDir, "manifest.json"),
|
|
738
972
|
JSON.stringify(manifest, null, 2)
|
|
739
973
|
);
|
|
740
974
|
}
|
|
741
975
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
742
|
-
const outputDir =
|
|
743
|
-
const bundleEntry =
|
|
744
|
-
const indexEntry =
|
|
976
|
+
const outputDir = path11__default.default.join(themePath, "dist");
|
|
977
|
+
const bundleEntry = path11__default.default.join(themePath, "bundle-entry.ts");
|
|
978
|
+
const indexEntry = path11__default.default.join(themePath, "index.ts");
|
|
745
979
|
let entryPoint = indexEntry;
|
|
746
980
|
try {
|
|
747
|
-
await
|
|
981
|
+
await fs9__default.default.access(bundleEntry);
|
|
748
982
|
entryPoint = bundleEntry;
|
|
749
983
|
} catch {
|
|
750
984
|
}
|
|
751
|
-
const shimPath =
|
|
752
|
-
await
|
|
753
|
-
await
|
|
985
|
+
const shimPath = path11__default.default.join(outputDir, ".process-shim.js");
|
|
986
|
+
await fs9__default.default.mkdir(outputDir, { recursive: true });
|
|
987
|
+
await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
754
988
|
const buildOptions = {
|
|
755
989
|
entryPoints: [entryPoint],
|
|
756
990
|
bundle: true,
|
|
@@ -801,19 +1035,20 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
801
1035
|
try {
|
|
802
1036
|
const result = await esbuild__namespace.build(buildOptions);
|
|
803
1037
|
try {
|
|
804
|
-
await
|
|
1038
|
+
await fs9__default.default.unlink(shimPath);
|
|
805
1039
|
} catch {
|
|
806
1040
|
}
|
|
807
1041
|
await contentHashEntry(outputDir);
|
|
808
|
-
const themeAssetsDir =
|
|
809
|
-
const distThemeAssets =
|
|
1042
|
+
const themeAssetsDir = path11__default.default.join(themePath, "assets");
|
|
1043
|
+
const distThemeAssets = path11__default.default.join(outputDir, "theme-assets");
|
|
810
1044
|
try {
|
|
811
|
-
await
|
|
812
|
-
await
|
|
1045
|
+
await fs9__default.default.access(themeAssetsDir);
|
|
1046
|
+
await fs9__default.default.cp(themeAssetsDir, distThemeAssets, { recursive: true });
|
|
813
1047
|
logger.info("Copied static assets to dist/theme-assets/");
|
|
814
1048
|
} catch {
|
|
815
1049
|
}
|
|
816
1050
|
await generateManifest(themeName, themePath, outputDir);
|
|
1051
|
+
await writeGateManifests(themePath, outputDir);
|
|
817
1052
|
await generateThemeData(themePath, outputDir, themeName);
|
|
818
1053
|
await generateThemeCSS(themePath, outputDir);
|
|
819
1054
|
if (result.metafile) {
|
|
@@ -828,7 +1063,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
828
1063
|
return true;
|
|
829
1064
|
} catch (error) {
|
|
830
1065
|
try {
|
|
831
|
-
await
|
|
1066
|
+
await fs9__default.default.unlink(shimPath);
|
|
832
1067
|
} catch {
|
|
833
1068
|
}
|
|
834
1069
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -836,18 +1071,18 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
836
1071
|
}
|
|
837
1072
|
}
|
|
838
1073
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
839
|
-
const outputDir =
|
|
840
|
-
const bundleEntry =
|
|
841
|
-
const indexEntry =
|
|
1074
|
+
const outputDir = path11__default.default.join(themePath, "dist");
|
|
1075
|
+
const bundleEntry = path11__default.default.join(themePath, "bundle-entry.ts");
|
|
1076
|
+
const indexEntry = path11__default.default.join(themePath, "index.ts");
|
|
842
1077
|
let entryPoint = indexEntry;
|
|
843
1078
|
try {
|
|
844
|
-
await
|
|
1079
|
+
await fs9__default.default.access(bundleEntry);
|
|
845
1080
|
entryPoint = bundleEntry;
|
|
846
1081
|
} catch {
|
|
847
1082
|
}
|
|
848
|
-
const shimPath =
|
|
849
|
-
await
|
|
850
|
-
await
|
|
1083
|
+
const shimPath = path11__default.default.join(outputDir, ".process-shim.js");
|
|
1084
|
+
await fs9__default.default.mkdir(outputDir, { recursive: true });
|
|
1085
|
+
await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
851
1086
|
const buildOptions = {
|
|
852
1087
|
entryPoints: [entryPoint],
|
|
853
1088
|
bundle: true,
|
|
@@ -901,18 +1136,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
901
1136
|
return { context: context2, outputDir };
|
|
902
1137
|
}
|
|
903
1138
|
async function compilePreviewRuntime(themePath) {
|
|
904
|
-
const outputDir =
|
|
905
|
-
await
|
|
906
|
-
const outputPath =
|
|
1139
|
+
const outputDir = path11__default.default.join(themePath, "dist");
|
|
1140
|
+
await fs9__default.default.mkdir(outputDir, { recursive: true });
|
|
1141
|
+
const outputPath = path11__default.default.join(outputDir, "preview-runtime.js");
|
|
907
1142
|
const locations = [
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1143
|
+
path11__default.default.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
1144
|
+
path11__default.default.join(__dirname, "preview", "preview-app.tsx"),
|
|
1145
|
+
path11__default.default.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
911
1146
|
];
|
|
912
1147
|
let previewEntryPath = null;
|
|
913
1148
|
for (const loc of locations) {
|
|
914
1149
|
try {
|
|
915
|
-
await
|
|
1150
|
+
await fs9__default.default.access(loc);
|
|
916
1151
|
previewEntryPath = loc;
|
|
917
1152
|
break;
|
|
918
1153
|
} catch {
|
|
@@ -995,10 +1230,10 @@ ${locations.join("\n")}`
|
|
|
995
1230
|
if (!lucideScanned) {
|
|
996
1231
|
lucideScanned = true;
|
|
997
1232
|
const coreSrcCandidates = [
|
|
998
|
-
|
|
999
|
-
|
|
1233
|
+
path11__default.default.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
1234
|
+
path11__default.default.join(themePath, "..", "..", "packages", "core", "src"),
|
|
1000
1235
|
// monorepo sibling
|
|
1001
|
-
|
|
1236
|
+
path11__default.default.join(
|
|
1002
1237
|
__dirname,
|
|
1003
1238
|
"..",
|
|
1004
1239
|
"..",
|
|
@@ -1013,7 +1248,7 @@ ${locations.join("\n")}`
|
|
|
1013
1248
|
let coreSourceDir = null;
|
|
1014
1249
|
for (const candidate of coreSrcCandidates) {
|
|
1015
1250
|
try {
|
|
1016
|
-
await
|
|
1251
|
+
await fs9__default.default.access(candidate);
|
|
1017
1252
|
coreSourceDir = candidate;
|
|
1018
1253
|
break;
|
|
1019
1254
|
} catch {
|
|
@@ -1032,21 +1267,21 @@ ${locations.join("\n")}`
|
|
|
1032
1267
|
}
|
|
1033
1268
|
} else {
|
|
1034
1269
|
const coreDistCandidates = [
|
|
1035
|
-
|
|
1270
|
+
path11__default.default.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
1036
1271
|
];
|
|
1037
1272
|
const resolvedDist = await resolveNodeModulesFile(
|
|
1038
1273
|
__dirname,
|
|
1039
|
-
|
|
1274
|
+
path11__default.default.join("@onexapis", "core", "dist")
|
|
1040
1275
|
);
|
|
1041
1276
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
1042
1277
|
for (const candidate of coreDistCandidates) {
|
|
1043
1278
|
try {
|
|
1044
|
-
await
|
|
1279
|
+
await fs9__default.default.access(candidate);
|
|
1045
1280
|
const mjsFiles = await glob.glob("*.mjs", { cwd: candidate });
|
|
1046
1281
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
1047
1282
|
for (const file of mjsFiles) {
|
|
1048
|
-
const content = await
|
|
1049
|
-
|
|
1283
|
+
const content = await fs9__default.default.readFile(
|
|
1284
|
+
path11__default.default.join(candidate, file),
|
|
1050
1285
|
"utf-8"
|
|
1051
1286
|
);
|
|
1052
1287
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1101,7 +1336,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1101
1336
|
const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
|
|
1102
1337
|
const cjsPath = req.resolve("framer-motion");
|
|
1103
1338
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1104
|
-
const esmEntry =
|
|
1339
|
+
const esmEntry = path11__default.default.join(pkgDir, "dist", "es", "index.mjs");
|
|
1105
1340
|
const { existsSync } = await import('fs');
|
|
1106
1341
|
if (existsSync(esmEntry)) {
|
|
1107
1342
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1200,8 +1435,8 @@ export function headers() { return new Headers(); }
|
|
|
1200
1435
|
});
|
|
1201
1436
|
}
|
|
1202
1437
|
};
|
|
1203
|
-
const shimPath =
|
|
1204
|
-
await
|
|
1438
|
+
const shimPath = path11__default.default.join(outputDir, ".process-shim-preview.js");
|
|
1439
|
+
await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
|
|
1205
1440
|
await esbuild__namespace.build({
|
|
1206
1441
|
entryPoints: [previewEntryPath],
|
|
1207
1442
|
bundle: true,
|
|
@@ -1236,7 +1471,7 @@ export function headers() { return new Headers(); }
|
|
|
1236
1471
|
}
|
|
1237
1472
|
});
|
|
1238
1473
|
try {
|
|
1239
|
-
await
|
|
1474
|
+
await fs9__default.default.unlink(shimPath);
|
|
1240
1475
|
} catch {
|
|
1241
1476
|
}
|
|
1242
1477
|
return outputPath;
|
|
@@ -1245,6 +1480,8 @@ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
|
|
|
1245
1480
|
var init_compile_theme = __esm({
|
|
1246
1481
|
"src/utils/compile-theme.ts"() {
|
|
1247
1482
|
init_logger();
|
|
1483
|
+
init_extract_schemas();
|
|
1484
|
+
init_scan_theme_assets();
|
|
1248
1485
|
PROCESS_SHIM = `
|
|
1249
1486
|
if (typeof process === "undefined") {
|
|
1250
1487
|
globalThis.process = {
|
|
@@ -1400,7 +1637,7 @@ __export(dev_server_exports, {
|
|
|
1400
1637
|
});
|
|
1401
1638
|
function createDevServer(options) {
|
|
1402
1639
|
const clients = /* @__PURE__ */ new Set();
|
|
1403
|
-
const themeDataPath =
|
|
1640
|
+
const themeDataPath = path11__default.default.join(options.distDir, "theme-data.json");
|
|
1404
1641
|
const server = http__default.default.createServer((req, res) => {
|
|
1405
1642
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1406
1643
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -1426,8 +1663,8 @@ function createDevServer(options) {
|
|
|
1426
1663
|
if (pathname.startsWith("/_assets/")) {
|
|
1427
1664
|
const parts = pathname.replace(/^\/_assets\//, "").split("/");
|
|
1428
1665
|
const assetSubpath = parts.slice(1).join("/");
|
|
1429
|
-
const assetPath =
|
|
1430
|
-
if (!assetPath.startsWith(
|
|
1666
|
+
const assetPath = path11__default.default.join(options.themePath, "assets", assetSubpath);
|
|
1667
|
+
if (!assetPath.startsWith(path11__default.default.join(options.themePath, "assets"))) {
|
|
1431
1668
|
res.writeHead(403);
|
|
1432
1669
|
res.end("Forbidden");
|
|
1433
1670
|
return;
|
|
@@ -1438,8 +1675,8 @@ function createDevServer(options) {
|
|
|
1438
1675
|
if (pathname.startsWith("/themes/")) {
|
|
1439
1676
|
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
1440
1677
|
if (match) {
|
|
1441
|
-
const assetPath =
|
|
1442
|
-
if (!assetPath.startsWith(
|
|
1678
|
+
const assetPath = path11__default.default.join(options.themePath, "assets", match[1]);
|
|
1679
|
+
if (!assetPath.startsWith(path11__default.default.join(options.themePath, "assets"))) {
|
|
1443
1680
|
res.writeHead(403);
|
|
1444
1681
|
res.end("Forbidden");
|
|
1445
1682
|
return;
|
|
@@ -1451,26 +1688,26 @@ function createDevServer(options) {
|
|
|
1451
1688
|
if (pathname.startsWith("/assets/")) {
|
|
1452
1689
|
const subpath = pathname.replace(/^\/assets\//, "");
|
|
1453
1690
|
const segments = subpath.split("/");
|
|
1454
|
-
const assetsBase =
|
|
1691
|
+
const assetsBase = path11__default.default.join(options.themePath, "assets");
|
|
1455
1692
|
let assetPath;
|
|
1456
1693
|
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
1457
|
-
assetPath =
|
|
1694
|
+
assetPath = path11__default.default.join(assetsBase, segments.slice(1).join("/"));
|
|
1458
1695
|
} else {
|
|
1459
|
-
assetPath =
|
|
1696
|
+
assetPath = path11__default.default.join(assetsBase, subpath);
|
|
1460
1697
|
}
|
|
1461
1698
|
if (assetPath.startsWith(assetsBase) && fs3__default.default.existsSync(assetPath)) {
|
|
1462
1699
|
serveFile(res, assetPath);
|
|
1463
1700
|
return;
|
|
1464
1701
|
}
|
|
1465
1702
|
if (segments.length > 1) {
|
|
1466
|
-
const fallbackPath =
|
|
1703
|
+
const fallbackPath = path11__default.default.join(assetsBase, segments.slice(1).join("/"));
|
|
1467
1704
|
if (fallbackPath.startsWith(assetsBase) && fs3__default.default.existsSync(fallbackPath)) {
|
|
1468
1705
|
serveFile(res, fallbackPath);
|
|
1469
1706
|
return;
|
|
1470
1707
|
}
|
|
1471
1708
|
}
|
|
1472
1709
|
}
|
|
1473
|
-
const filePath =
|
|
1710
|
+
const filePath = path11__default.default.join(options.distDir, pathname);
|
|
1474
1711
|
if (!filePath.startsWith(options.distDir)) {
|
|
1475
1712
|
res.writeHead(403);
|
|
1476
1713
|
res.end("Forbidden");
|
|
@@ -1513,7 +1750,7 @@ function serveFile(res, filePath) {
|
|
|
1513
1750
|
res.end("Not Found");
|
|
1514
1751
|
return;
|
|
1515
1752
|
}
|
|
1516
|
-
const ext =
|
|
1753
|
+
const ext = path11__default.default.extname(filePath);
|
|
1517
1754
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
1518
1755
|
const content = fs3__default.default.readFileSync(filePath);
|
|
1519
1756
|
res.writeHead(200, { "Content-Type": contentType });
|
|
@@ -1634,18 +1871,18 @@ async function renderTemplate(templatePath, data) {
|
|
|
1634
1871
|
return ejs__default.default.render(template, data);
|
|
1635
1872
|
}
|
|
1636
1873
|
async function writeFile(filePath, content) {
|
|
1637
|
-
await fs__default.default.ensureDir(
|
|
1874
|
+
await fs__default.default.ensureDir(path11__default.default.dirname(filePath));
|
|
1638
1875
|
await fs__default.default.writeFile(filePath, content, "utf-8");
|
|
1639
1876
|
}
|
|
1640
1877
|
function getTemplatesDir() {
|
|
1641
1878
|
const locations = [
|
|
1642
|
-
|
|
1879
|
+
path11__default.default.join(__dirname, "../../templates"),
|
|
1643
1880
|
// Development
|
|
1644
|
-
|
|
1881
|
+
path11__default.default.join(__dirname, "../templates"),
|
|
1645
1882
|
// Production (dist/)
|
|
1646
|
-
|
|
1883
|
+
path11__default.default.join(process.cwd(), "templates"),
|
|
1647
1884
|
// Fallback
|
|
1648
|
-
|
|
1885
|
+
path11__default.default.join(process.cwd(), "packages/cli/templates")
|
|
1649
1886
|
// Monorepo
|
|
1650
1887
|
];
|
|
1651
1888
|
for (const location of locations) {
|
|
@@ -1657,7 +1894,7 @@ function getTemplatesDir() {
|
|
|
1657
1894
|
}
|
|
1658
1895
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1659
1896
|
const templatesDir = getTemplatesDir();
|
|
1660
|
-
const templateDir =
|
|
1897
|
+
const templateDir = path11__default.default.join(templatesDir, templateName);
|
|
1661
1898
|
if (!fs__default.default.existsSync(templateDir)) {
|
|
1662
1899
|
throw new Error(
|
|
1663
1900
|
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs__default.default.readdirSync(templatesDir).join(", ")}`
|
|
@@ -1666,8 +1903,8 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1666
1903
|
await fs__default.default.ensureDir(targetDir);
|
|
1667
1904
|
const files = await fs__default.default.readdir(templateDir);
|
|
1668
1905
|
for (const file of files) {
|
|
1669
|
-
const templatePath =
|
|
1670
|
-
const targetPath =
|
|
1906
|
+
const templatePath = path11__default.default.join(templateDir, file);
|
|
1907
|
+
const targetPath = path11__default.default.join(targetDir, file);
|
|
1671
1908
|
const stat = await fs__default.default.stat(templatePath);
|
|
1672
1909
|
if (stat.isDirectory()) {
|
|
1673
1910
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1684,8 +1921,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1684
1921
|
await fs__default.default.ensureDir(targetDir);
|
|
1685
1922
|
const files = await fs__default.default.readdir(templateDir);
|
|
1686
1923
|
for (const file of files) {
|
|
1687
|
-
const templatePath =
|
|
1688
|
-
const targetPath =
|
|
1924
|
+
const templatePath = path11__default.default.join(templateDir, file);
|
|
1925
|
+
const targetPath = path11__default.default.join(targetDir, file);
|
|
1689
1926
|
const stat = await fs__default.default.stat(templatePath);
|
|
1690
1927
|
if (stat.isDirectory()) {
|
|
1691
1928
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1700,32 +1937,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1700
1937
|
}
|
|
1701
1938
|
function getProjectRoot() {
|
|
1702
1939
|
let currentDir = process.cwd();
|
|
1703
|
-
while (currentDir !==
|
|
1704
|
-
const packageJsonPath =
|
|
1940
|
+
while (currentDir !== path11__default.default.parse(currentDir).root) {
|
|
1941
|
+
const packageJsonPath = path11__default.default.join(currentDir, "package.json");
|
|
1705
1942
|
if (fs__default.default.existsSync(packageJsonPath)) {
|
|
1706
1943
|
const packageJson = fs__default.default.readJsonSync(packageJsonPath);
|
|
1707
|
-
if (packageJson.workspaces || fs__default.default.existsSync(
|
|
1944
|
+
if (packageJson.workspaces || fs__default.default.existsSync(path11__default.default.join(currentDir, "src/themes")) || fs__default.default.existsSync(path11__default.default.join(currentDir, "themes"))) {
|
|
1708
1945
|
return currentDir;
|
|
1709
1946
|
}
|
|
1710
1947
|
}
|
|
1711
|
-
currentDir =
|
|
1948
|
+
currentDir = path11__default.default.dirname(currentDir);
|
|
1712
1949
|
}
|
|
1713
1950
|
return process.cwd();
|
|
1714
1951
|
}
|
|
1715
1952
|
function getThemesDir() {
|
|
1716
1953
|
const root = getProjectRoot();
|
|
1717
|
-
if (fs__default.default.existsSync(
|
|
1718
|
-
return
|
|
1719
|
-
if (fs__default.default.existsSync(
|
|
1720
|
-
return
|
|
1721
|
-
return
|
|
1954
|
+
if (fs__default.default.existsSync(path11__default.default.join(root, "themes")))
|
|
1955
|
+
return path11__default.default.join(root, "themes");
|
|
1956
|
+
if (fs__default.default.existsSync(path11__default.default.join(root, "src/themes")))
|
|
1957
|
+
return path11__default.default.join(root, "src/themes");
|
|
1958
|
+
return path11__default.default.dirname(root);
|
|
1722
1959
|
}
|
|
1723
1960
|
function getFeaturesDir() {
|
|
1724
|
-
return
|
|
1961
|
+
return path11__default.default.join(getProjectRoot(), "src/features");
|
|
1725
1962
|
}
|
|
1726
1963
|
function isOneXProject() {
|
|
1727
1964
|
const root = getProjectRoot();
|
|
1728
|
-
return fs__default.default.existsSync(
|
|
1965
|
+
return fs__default.default.existsSync(path11__default.default.join(root, "themes")) || fs__default.default.existsSync(path11__default.default.join(root, "src/themes")) || fs__default.default.existsSync(path11__default.default.join(root, "theme.config.ts")) || fs__default.default.existsSync(path11__default.default.join(root, "bundle-entry.ts"));
|
|
1729
1966
|
}
|
|
1730
1967
|
function ensureOneXProject() {
|
|
1731
1968
|
if (!isOneXProject()) {
|
|
@@ -1741,13 +1978,13 @@ function listThemes() {
|
|
|
1741
1978
|
return [];
|
|
1742
1979
|
}
|
|
1743
1980
|
return fs__default.default.readdirSync(themesDir).filter((name) => {
|
|
1744
|
-
const themePath =
|
|
1745
|
-
return fs__default.default.statSync(themePath).isDirectory() && (fs__default.default.existsSync(
|
|
1981
|
+
const themePath = path11__default.default.join(themesDir, name);
|
|
1982
|
+
return fs__default.default.statSync(themePath).isDirectory() && (fs__default.default.existsSync(path11__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path11__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path11__default.default.join(themePath, "manifest.ts")));
|
|
1746
1983
|
});
|
|
1747
1984
|
}
|
|
1748
1985
|
function themeExists(themeName) {
|
|
1749
|
-
const themePath =
|
|
1750
|
-
return fs__default.default.existsSync(themePath) && (fs__default.default.existsSync(
|
|
1986
|
+
const themePath = path11__default.default.join(getThemesDir(), themeName);
|
|
1987
|
+
return fs__default.default.existsSync(themePath) && (fs__default.default.existsSync(path11__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path11__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path11__default.default.join(themePath, "manifest.ts")));
|
|
1751
1988
|
}
|
|
1752
1989
|
function detectPackageManager() {
|
|
1753
1990
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1755,9 +1992,9 @@ function detectPackageManager() {
|
|
|
1755
1992
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1756
1993
|
if (userAgent.includes("bun")) return "bun";
|
|
1757
1994
|
const cwd = process.cwd();
|
|
1758
|
-
if (fs__default.default.existsSync(
|
|
1759
|
-
if (fs__default.default.existsSync(
|
|
1760
|
-
if (fs__default.default.existsSync(
|
|
1995
|
+
if (fs__default.default.existsSync(path11__default.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1996
|
+
if (fs__default.default.existsSync(path11__default.default.join(cwd, "yarn.lock"))) return "yarn";
|
|
1997
|
+
if (fs__default.default.existsSync(path11__default.default.join(cwd, "bun.lockb"))) return "bun";
|
|
1761
1998
|
return "npm";
|
|
1762
1999
|
}
|
|
1763
2000
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1806,22 +2043,45 @@ function getValidCategories() {
|
|
|
1806
2043
|
"contact"
|
|
1807
2044
|
];
|
|
1808
2045
|
}
|
|
1809
|
-
var AUTH_DIR =
|
|
1810
|
-
var
|
|
1811
|
-
|
|
1812
|
-
|
|
2046
|
+
var AUTH_DIR = path11__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
2047
|
+
var ENV_URLS = {
|
|
2048
|
+
dev: "https://platform-dev.onexeos.com",
|
|
2049
|
+
staging: "https://platform-staging.onexeos.com",
|
|
2050
|
+
prod: "https://platform-apis.onexeos.com"
|
|
2051
|
+
};
|
|
2052
|
+
function getAuthFile(env = "dev") {
|
|
2053
|
+
const newFile = path11__default.default.join(AUTH_DIR, `auth-${env}.json`);
|
|
2054
|
+
if (env === "dev") {
|
|
2055
|
+
const legacyFile = path11__default.default.join(AUTH_DIR, "auth.json");
|
|
2056
|
+
if (fs__default.default.existsSync(legacyFile) && !fs__default.default.existsSync(newFile)) {
|
|
2057
|
+
try {
|
|
2058
|
+
fs__default.default.moveSync(legacyFile, newFile);
|
|
2059
|
+
} catch {
|
|
2060
|
+
try {
|
|
2061
|
+
fs__default.default.copySync(legacyFile, newFile);
|
|
2062
|
+
fs__default.default.removeSync(legacyFile);
|
|
2063
|
+
} catch {
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
return newFile;
|
|
2069
|
+
}
|
|
2070
|
+
function getApiUrl(env = "dev") {
|
|
2071
|
+
return process.env.ONEXTHM_API_URL || ENV_URLS[env];
|
|
1813
2072
|
}
|
|
1814
|
-
async function saveAuthTokens(tokens) {
|
|
2073
|
+
async function saveAuthTokens(tokens, env = "dev") {
|
|
1815
2074
|
await fs__default.default.ensureDir(AUTH_DIR);
|
|
1816
2075
|
const key = getMachineKey();
|
|
1817
2076
|
const data = JSON.stringify(tokens);
|
|
1818
2077
|
const encrypted = encrypt(data, key);
|
|
1819
|
-
await fs__default.default.writeFile(
|
|
2078
|
+
await fs__default.default.writeFile(getAuthFile(env), encrypted, "utf-8");
|
|
1820
2079
|
}
|
|
1821
|
-
function loadAuthTokens() {
|
|
2080
|
+
function loadAuthTokens(env = "dev") {
|
|
1822
2081
|
try {
|
|
1823
|
-
|
|
1824
|
-
|
|
2082
|
+
const file = getAuthFile(env);
|
|
2083
|
+
if (!fs__default.default.existsSync(file)) return null;
|
|
2084
|
+
const encrypted = fs__default.default.readFileSync(file, "utf-8");
|
|
1825
2085
|
const key = getMachineKey();
|
|
1826
2086
|
const data = decrypt(encrypted, key);
|
|
1827
2087
|
return JSON.parse(data);
|
|
@@ -1829,34 +2089,34 @@ function loadAuthTokens() {
|
|
|
1829
2089
|
return null;
|
|
1830
2090
|
}
|
|
1831
2091
|
}
|
|
1832
|
-
async function clearAuthTokens() {
|
|
2092
|
+
async function clearAuthTokens(env = "dev") {
|
|
1833
2093
|
try {
|
|
1834
|
-
await fs__default.default.remove(
|
|
2094
|
+
await fs__default.default.remove(getAuthFile(env));
|
|
1835
2095
|
} catch {
|
|
1836
2096
|
}
|
|
1837
2097
|
}
|
|
1838
2098
|
function isTokenExpired(tokens) {
|
|
1839
2099
|
return Date.now() / 1e3 > tokens.expiresAt - 300;
|
|
1840
2100
|
}
|
|
1841
|
-
async function getValidTokens() {
|
|
1842
|
-
const tokens = loadAuthTokens();
|
|
2101
|
+
async function getValidTokens(env = "dev") {
|
|
2102
|
+
const tokens = loadAuthTokens(env);
|
|
1843
2103
|
if (!tokens) return null;
|
|
1844
2104
|
if (!isTokenExpired(tokens)) return tokens;
|
|
1845
2105
|
try {
|
|
1846
|
-
const apiUrl = getApiUrl();
|
|
2106
|
+
const apiUrl = getApiUrl(env);
|
|
1847
2107
|
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
1848
2108
|
method: "POST",
|
|
1849
2109
|
headers: { "Content-Type": "application/json" },
|
|
1850
2110
|
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
1851
2111
|
});
|
|
1852
2112
|
if (!response.ok) {
|
|
1853
|
-
await clearAuthTokens();
|
|
2113
|
+
await clearAuthTokens(env);
|
|
1854
2114
|
return null;
|
|
1855
2115
|
}
|
|
1856
2116
|
const data = await response.json();
|
|
1857
2117
|
const body = data.statusCode ? data.body : data;
|
|
1858
2118
|
if (!body.IdToken) {
|
|
1859
|
-
await clearAuthTokens();
|
|
2119
|
+
await clearAuthTokens(env);
|
|
1860
2120
|
return null;
|
|
1861
2121
|
}
|
|
1862
2122
|
const refreshed = {
|
|
@@ -1865,17 +2125,19 @@ async function getValidTokens() {
|
|
|
1865
2125
|
idToken: body.IdToken,
|
|
1866
2126
|
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
1867
2127
|
};
|
|
1868
|
-
await saveAuthTokens(refreshed);
|
|
2128
|
+
await saveAuthTokens(refreshed, env);
|
|
1869
2129
|
return refreshed;
|
|
1870
2130
|
} catch {
|
|
1871
|
-
await clearAuthTokens();
|
|
2131
|
+
await clearAuthTokens(env);
|
|
1872
2132
|
return null;
|
|
1873
2133
|
}
|
|
1874
2134
|
}
|
|
1875
|
-
async function authenticatedFetch(url, init) {
|
|
1876
|
-
const tokens = await getValidTokens();
|
|
2135
|
+
async function authenticatedFetch(url, init, env = "dev") {
|
|
2136
|
+
const tokens = await getValidTokens(env);
|
|
1877
2137
|
if (!tokens) {
|
|
1878
|
-
throw new Error(
|
|
2138
|
+
throw new Error(
|
|
2139
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
2140
|
+
);
|
|
1879
2141
|
}
|
|
1880
2142
|
const headers = new Headers(init?.headers);
|
|
1881
2143
|
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
@@ -1941,7 +2203,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1941
2203
|
if (!validateThemeName(kebabName)) {
|
|
1942
2204
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1943
2205
|
}
|
|
1944
|
-
if (fs3__default.default.existsSync(
|
|
2206
|
+
if (fs3__default.default.existsSync(path11__default.default.join(process.cwd(), kebabName))) {
|
|
1945
2207
|
return `Directory "${kebabName}" already exists`;
|
|
1946
2208
|
}
|
|
1947
2209
|
return true;
|
|
@@ -1952,14 +2214,14 @@ async function initCommand(projectName, options = {}) {
|
|
|
1952
2214
|
} else {
|
|
1953
2215
|
name = toKebabCase(projectName);
|
|
1954
2216
|
}
|
|
1955
|
-
const projectPath =
|
|
2217
|
+
const projectPath = path11__default.default.join(process.cwd(), name);
|
|
1956
2218
|
if (fs3__default.default.existsSync(projectPath)) {
|
|
1957
2219
|
logger.error(`Directory "${name}" already exists.`);
|
|
1958
2220
|
process.exit(1);
|
|
1959
2221
|
}
|
|
1960
2222
|
if (!options.yes) {
|
|
1961
2223
|
try {
|
|
1962
|
-
const apiUrl = getApiUrl();
|
|
2224
|
+
const apiUrl = getApiUrl(options.env ?? "dev");
|
|
1963
2225
|
const controller = new AbortController();
|
|
1964
2226
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1965
2227
|
const response = await fetch(
|
|
@@ -2068,7 +2330,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2068
2330
|
description,
|
|
2069
2331
|
author
|
|
2070
2332
|
);
|
|
2071
|
-
const mcpJsonPath =
|
|
2333
|
+
const mcpJsonPath = path11__default.default.join(projectPath, ".mcp.json");
|
|
2072
2334
|
if (fs3__default.default.existsSync(mcpJsonPath)) {
|
|
2073
2335
|
let mcpContent = fs3__default.default.readFileSync(mcpJsonPath, "utf-8");
|
|
2074
2336
|
if (figmaApiKey) {
|
|
@@ -2148,7 +2410,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
2148
2410
|
}
|
|
2149
2411
|
}
|
|
2150
2412
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
2151
|
-
const configPath =
|
|
2413
|
+
const configPath = path11__default.default.join(projectPath, "theme.config.ts");
|
|
2152
2414
|
if (fs3__default.default.existsSync(configPath)) {
|
|
2153
2415
|
let content = fs3__default.default.readFileSync(configPath, "utf-8");
|
|
2154
2416
|
content = content.replace(
|
|
@@ -2161,7 +2423,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
2161
2423
|
);
|
|
2162
2424
|
fs3__default.default.writeFileSync(configPath, content, "utf-8");
|
|
2163
2425
|
}
|
|
2164
|
-
const pkgPath =
|
|
2426
|
+
const pkgPath = path11__default.default.join(projectPath, "package.json");
|
|
2165
2427
|
if (fs3__default.default.existsSync(pkgPath)) {
|
|
2166
2428
|
let content = fs3__default.default.readFileSync(pkgPath, "utf-8");
|
|
2167
2429
|
content = content.replace(
|
|
@@ -2183,10 +2445,10 @@ async function createSectionCommand(name, options) {
|
|
|
2183
2445
|
ensureOneXProject();
|
|
2184
2446
|
if (!options.theme) {
|
|
2185
2447
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2186
|
-
(f) => fs__default.default.existsSync(
|
|
2448
|
+
(f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f))
|
|
2187
2449
|
);
|
|
2188
2450
|
if (isStandaloneTheme) {
|
|
2189
|
-
options.theme =
|
|
2451
|
+
options.theme = path11__default.default.basename(process.cwd());
|
|
2190
2452
|
}
|
|
2191
2453
|
}
|
|
2192
2454
|
const sectionName = toKebabCase(name);
|
|
@@ -2249,35 +2511,35 @@ async function createSectionCommand(name, options) {
|
|
|
2249
2511
|
};
|
|
2250
2512
|
logger.startSpinner("Creating section files...");
|
|
2251
2513
|
try {
|
|
2252
|
-
const themePath =
|
|
2253
|
-
const sectionPath =
|
|
2514
|
+
const themePath = path11__default.default.join(getThemesDir(), themeName);
|
|
2515
|
+
const sectionPath = path11__default.default.join(themePath, "sections", sectionName);
|
|
2254
2516
|
const schemaContent = generateSectionSchema(data);
|
|
2255
2517
|
await writeFile(
|
|
2256
|
-
|
|
2518
|
+
path11__default.default.join(sectionPath, `${sectionName}.schema.ts`),
|
|
2257
2519
|
schemaContent
|
|
2258
2520
|
);
|
|
2259
2521
|
if (createTemplate) {
|
|
2260
2522
|
const templateContent = generateSectionTemplate(data);
|
|
2261
2523
|
await writeFile(
|
|
2262
|
-
|
|
2524
|
+
path11__default.default.join(sectionPath, `${sectionName}-default.tsx`),
|
|
2263
2525
|
templateContent
|
|
2264
2526
|
);
|
|
2265
2527
|
}
|
|
2266
2528
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
2267
|
-
await writeFile(
|
|
2529
|
+
await writeFile(path11__default.default.join(sectionPath, "index.ts"), indexContent);
|
|
2268
2530
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
2269
2531
|
logger.newLine();
|
|
2270
2532
|
logger.section("Next steps:");
|
|
2271
2533
|
logger.log(
|
|
2272
|
-
` 1. Edit schema: ${
|
|
2534
|
+
` 1. Edit schema: ${path11__default.default.relative(process.cwd(), path11__default.default.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
2273
2535
|
);
|
|
2274
2536
|
if (createTemplate) {
|
|
2275
2537
|
logger.log(
|
|
2276
|
-
` 2. Edit template: ${
|
|
2538
|
+
` 2. Edit template: ${path11__default.default.relative(process.cwd(), path11__default.default.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
2277
2539
|
);
|
|
2278
2540
|
}
|
|
2279
2541
|
logger.log(
|
|
2280
|
-
` 3. Add to theme manifest: ${
|
|
2542
|
+
` 3. Add to theme manifest: ${path11__default.default.relative(process.cwd(), path11__default.default.join(themePath, "manifest.ts"))}`
|
|
2281
2543
|
);
|
|
2282
2544
|
logger.newLine();
|
|
2283
2545
|
logger.success("Section created successfully!");
|
|
@@ -2425,10 +2687,10 @@ async function createBlockCommand(name, options) {
|
|
|
2425
2687
|
ensureOneXProject();
|
|
2426
2688
|
if (!options.theme) {
|
|
2427
2689
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2428
|
-
(f) => fs__default.default.existsSync(
|
|
2690
|
+
(f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f))
|
|
2429
2691
|
);
|
|
2430
2692
|
if (isStandaloneTheme) {
|
|
2431
|
-
options.theme =
|
|
2693
|
+
options.theme = path11__default.default.basename(process.cwd());
|
|
2432
2694
|
}
|
|
2433
2695
|
}
|
|
2434
2696
|
const blockName = toKebabCase(name);
|
|
@@ -2503,24 +2765,24 @@ async function createBlockCommand(name, options) {
|
|
|
2503
2765
|
};
|
|
2504
2766
|
logger.startSpinner("Creating block files...");
|
|
2505
2767
|
try {
|
|
2506
|
-
const blockPath = scope === "shared" ?
|
|
2768
|
+
const blockPath = scope === "shared" ? path11__default.default.join(getFeaturesDir(), "blocks", blockName) : path11__default.default.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2507
2769
|
const schemaContent = generateBlockSchema(data);
|
|
2508
2770
|
await writeFile(
|
|
2509
|
-
|
|
2771
|
+
path11__default.default.join(blockPath, `${blockName}.schema.ts`),
|
|
2510
2772
|
schemaContent
|
|
2511
2773
|
);
|
|
2512
2774
|
const componentContent = generateBlockComponent(data);
|
|
2513
|
-
await writeFile(
|
|
2775
|
+
await writeFile(path11__default.default.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2514
2776
|
const indexContent = generateBlockIndex(data);
|
|
2515
|
-
await writeFile(
|
|
2777
|
+
await writeFile(path11__default.default.join(blockPath, "index.ts"), indexContent);
|
|
2516
2778
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2517
2779
|
logger.newLine();
|
|
2518
2780
|
logger.section("Next steps:");
|
|
2519
2781
|
logger.log(
|
|
2520
|
-
` 1. Edit schema: ${
|
|
2782
|
+
` 1. Edit schema: ${path11__default.default.relative(process.cwd(), path11__default.default.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2521
2783
|
);
|
|
2522
2784
|
logger.log(
|
|
2523
|
-
` 2. Edit component: ${
|
|
2785
|
+
` 2. Edit component: ${path11__default.default.relative(process.cwd(), path11__default.default.join(blockPath, `${blockName}.tsx`))}`
|
|
2524
2786
|
);
|
|
2525
2787
|
logger.log(
|
|
2526
2788
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2698,31 +2960,31 @@ async function createComponentCommand(name, options) {
|
|
|
2698
2960
|
};
|
|
2699
2961
|
logger.startSpinner("Creating component files...");
|
|
2700
2962
|
try {
|
|
2701
|
-
const componentPath =
|
|
2963
|
+
const componentPath = path11__default.default.join(
|
|
2702
2964
|
getFeaturesDir(),
|
|
2703
2965
|
"components",
|
|
2704
2966
|
componentName
|
|
2705
2967
|
);
|
|
2706
2968
|
const schemaContent = generateComponentSchema(data);
|
|
2707
2969
|
await writeFile(
|
|
2708
|
-
|
|
2970
|
+
path11__default.default.join(componentPath, `${componentName}.schema.ts`),
|
|
2709
2971
|
schemaContent
|
|
2710
2972
|
);
|
|
2711
2973
|
const componentContent = generateComponent(data);
|
|
2712
2974
|
await writeFile(
|
|
2713
|
-
|
|
2975
|
+
path11__default.default.join(componentPath, `${componentName}.tsx`),
|
|
2714
2976
|
componentContent
|
|
2715
2977
|
);
|
|
2716
2978
|
const indexContent = generateComponentIndex(data);
|
|
2717
|
-
await writeFile(
|
|
2979
|
+
await writeFile(path11__default.default.join(componentPath, "index.ts"), indexContent);
|
|
2718
2980
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2719
2981
|
logger.newLine();
|
|
2720
2982
|
logger.section("Next steps:");
|
|
2721
2983
|
logger.log(
|
|
2722
|
-
` 1. Edit schema: ${
|
|
2984
|
+
` 1. Edit schema: ${path11__default.default.relative(process.cwd(), path11__default.default.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2723
2985
|
);
|
|
2724
2986
|
logger.log(
|
|
2725
|
-
` 2. Edit component: ${
|
|
2987
|
+
` 2. Edit component: ${path11__default.default.relative(process.cwd(), path11__default.default.join(componentPath, `${componentName}.tsx`))}`
|
|
2726
2988
|
);
|
|
2727
2989
|
logger.log(
|
|
2728
2990
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2879,13 +3141,13 @@ async function listSections(themeFilter) {
|
|
|
2879
3141
|
return;
|
|
2880
3142
|
}
|
|
2881
3143
|
for (const theme of themes) {
|
|
2882
|
-
const sectionsDir =
|
|
3144
|
+
const sectionsDir = path11__default.default.join(getThemesDir(), theme, "sections");
|
|
2883
3145
|
if (!fs__default.default.existsSync(sectionsDir)) {
|
|
2884
3146
|
continue;
|
|
2885
3147
|
}
|
|
2886
3148
|
const sections = fs__default.default.readdirSync(sectionsDir).filter((name) => {
|
|
2887
|
-
const sectionPath =
|
|
2888
|
-
return fs__default.default.statSync(sectionPath).isDirectory() && fs__default.default.existsSync(
|
|
3149
|
+
const sectionPath = path11__default.default.join(sectionsDir, name);
|
|
3150
|
+
return fs__default.default.statSync(sectionPath).isDirectory() && fs__default.default.existsSync(path11__default.default.join(sectionPath, "index.ts"));
|
|
2889
3151
|
});
|
|
2890
3152
|
if (sections.length > 0) {
|
|
2891
3153
|
logger.log(chalk4__default.default.cyan(`
|
|
@@ -2899,11 +3161,11 @@ async function listSections(themeFilter) {
|
|
|
2899
3161
|
}
|
|
2900
3162
|
async function listBlocks(themeFilter) {
|
|
2901
3163
|
logger.section("\u{1F9F1} Blocks");
|
|
2902
|
-
const sharedBlocksDir =
|
|
3164
|
+
const sharedBlocksDir = path11__default.default.join(getFeaturesDir(), "blocks");
|
|
2903
3165
|
if (fs__default.default.existsSync(sharedBlocksDir)) {
|
|
2904
3166
|
const sharedBlocks = fs__default.default.readdirSync(sharedBlocksDir).filter((name) => {
|
|
2905
|
-
const blockPath =
|
|
2906
|
-
return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(
|
|
3167
|
+
const blockPath = path11__default.default.join(sharedBlocksDir, name);
|
|
3168
|
+
return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path11__default.default.join(blockPath, "index.ts"));
|
|
2907
3169
|
});
|
|
2908
3170
|
if (sharedBlocks.length > 0) {
|
|
2909
3171
|
logger.log(chalk4__default.default.cyan("\n Shared:"));
|
|
@@ -2914,13 +3176,13 @@ async function listBlocks(themeFilter) {
|
|
|
2914
3176
|
}
|
|
2915
3177
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2916
3178
|
for (const theme of themes) {
|
|
2917
|
-
const blocksDir =
|
|
3179
|
+
const blocksDir = path11__default.default.join(getThemesDir(), theme, "blocks");
|
|
2918
3180
|
if (!fs__default.default.existsSync(blocksDir)) {
|
|
2919
3181
|
continue;
|
|
2920
3182
|
}
|
|
2921
3183
|
const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => {
|
|
2922
|
-
const blockPath =
|
|
2923
|
-
return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(
|
|
3184
|
+
const blockPath = path11__default.default.join(blocksDir, name);
|
|
3185
|
+
return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path11__default.default.join(blockPath, "index.ts"));
|
|
2924
3186
|
});
|
|
2925
3187
|
if (blocks.length > 0) {
|
|
2926
3188
|
logger.log(chalk4__default.default.cyan(`
|
|
@@ -2934,14 +3196,14 @@ async function listBlocks(themeFilter) {
|
|
|
2934
3196
|
}
|
|
2935
3197
|
async function listComponents() {
|
|
2936
3198
|
logger.section("\u2699\uFE0F Components");
|
|
2937
|
-
const componentsDir =
|
|
3199
|
+
const componentsDir = path11__default.default.join(getFeaturesDir(), "components");
|
|
2938
3200
|
if (!fs__default.default.existsSync(componentsDir)) {
|
|
2939
3201
|
logger.warning("No components directory found");
|
|
2940
3202
|
return;
|
|
2941
3203
|
}
|
|
2942
3204
|
const components = fs__default.default.readdirSync(componentsDir).filter((name) => {
|
|
2943
|
-
const componentPath =
|
|
2944
|
-
return fs__default.default.statSync(componentPath).isDirectory() && fs__default.default.existsSync(
|
|
3205
|
+
const componentPath = path11__default.default.join(componentsDir, name);
|
|
3206
|
+
return fs__default.default.statSync(componentPath).isDirectory() && fs__default.default.existsSync(path11__default.default.join(componentPath, "index.ts"));
|
|
2945
3207
|
});
|
|
2946
3208
|
if (components.length === 0) {
|
|
2947
3209
|
logger.warning("No components found");
|
|
@@ -2962,11 +3224,11 @@ async function listThemesInfo() {
|
|
|
2962
3224
|
}
|
|
2963
3225
|
logger.log("");
|
|
2964
3226
|
for (const theme of themes) {
|
|
2965
|
-
const themeDir =
|
|
3227
|
+
const themeDir = path11__default.default.join(getThemesDir(), theme);
|
|
2966
3228
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2967
3229
|
let manifestContent = "";
|
|
2968
3230
|
for (const candidate of candidates) {
|
|
2969
|
-
const candidatePath =
|
|
3231
|
+
const candidatePath = path11__default.default.join(themeDir, candidate);
|
|
2970
3232
|
if (fs__default.default.existsSync(candidatePath)) {
|
|
2971
3233
|
manifestContent = fs__default.default.readFileSync(candidatePath, "utf-8");
|
|
2972
3234
|
break;
|
|
@@ -3004,9 +3266,9 @@ async function validateCommand(options) {
|
|
|
3004
3266
|
"theme.config.ts",
|
|
3005
3267
|
"bundle-entry.ts",
|
|
3006
3268
|
"manifest.ts"
|
|
3007
|
-
].some((f) => fs__default.default.existsSync(
|
|
3269
|
+
].some((f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f)));
|
|
3008
3270
|
if (isThemeDir2) {
|
|
3009
|
-
themeToValidate =
|
|
3271
|
+
themeToValidate = path11__default.default.basename(process.cwd());
|
|
3010
3272
|
logger.info(`Validating current theme: ${themeToValidate}`);
|
|
3011
3273
|
} else {
|
|
3012
3274
|
logger.error(
|
|
@@ -3015,11 +3277,11 @@ async function validateCommand(options) {
|
|
|
3015
3277
|
process.exit(1);
|
|
3016
3278
|
}
|
|
3017
3279
|
}
|
|
3018
|
-
const themePath =
|
|
3280
|
+
const themePath = path11__default.default.join(getThemesDir(), themeToValidate);
|
|
3019
3281
|
logger.startSpinner("Running validation checks...");
|
|
3020
3282
|
const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
|
|
3021
3283
|
const foundEntry = entryFiles.find(
|
|
3022
|
-
(f) => fs__default.default.existsSync(
|
|
3284
|
+
(f) => fs__default.default.existsSync(path11__default.default.join(themePath, f))
|
|
3023
3285
|
);
|
|
3024
3286
|
if (!foundEntry) {
|
|
3025
3287
|
issues.push({
|
|
@@ -3029,7 +3291,7 @@ async function validateCommand(options) {
|
|
|
3029
3291
|
});
|
|
3030
3292
|
} else if (foundEntry === "manifest.ts") {
|
|
3031
3293
|
const manifestContent = fs__default.default.readFileSync(
|
|
3032
|
-
|
|
3294
|
+
path11__default.default.join(themePath, foundEntry),
|
|
3033
3295
|
"utf-8"
|
|
3034
3296
|
);
|
|
3035
3297
|
if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
|
|
@@ -3040,7 +3302,7 @@ async function validateCommand(options) {
|
|
|
3040
3302
|
});
|
|
3041
3303
|
}
|
|
3042
3304
|
}
|
|
3043
|
-
const configPath =
|
|
3305
|
+
const configPath = path11__default.default.join(themePath, "theme.config.ts");
|
|
3044
3306
|
if (!fs__default.default.existsSync(configPath)) {
|
|
3045
3307
|
issues.push({
|
|
3046
3308
|
type: "warning",
|
|
@@ -3048,7 +3310,7 @@ async function validateCommand(options) {
|
|
|
3048
3310
|
message: "Theme config file not found (recommended)"
|
|
3049
3311
|
});
|
|
3050
3312
|
}
|
|
3051
|
-
const indexPath =
|
|
3313
|
+
const indexPath = path11__default.default.join(themePath, "index.ts");
|
|
3052
3314
|
if (!fs__default.default.existsSync(indexPath)) {
|
|
3053
3315
|
issues.push({
|
|
3054
3316
|
type: "warning",
|
|
@@ -3056,7 +3318,7 @@ async function validateCommand(options) {
|
|
|
3056
3318
|
message: "Index file not found (recommended)"
|
|
3057
3319
|
});
|
|
3058
3320
|
}
|
|
3059
|
-
const sectionsDir =
|
|
3321
|
+
const sectionsDir = path11__default.default.join(themePath, "sections");
|
|
3060
3322
|
if (!fs__default.default.existsSync(sectionsDir)) {
|
|
3061
3323
|
issues.push({
|
|
3062
3324
|
type: "warning",
|
|
@@ -3065,16 +3327,16 @@ async function validateCommand(options) {
|
|
|
3065
3327
|
});
|
|
3066
3328
|
} else {
|
|
3067
3329
|
const sections = fs__default.default.readdirSync(sectionsDir).filter(
|
|
3068
|
-
(name) => fs__default.default.statSync(
|
|
3330
|
+
(name) => fs__default.default.statSync(path11__default.default.join(sectionsDir, name)).isDirectory()
|
|
3069
3331
|
);
|
|
3070
3332
|
for (const sectionName of sections) {
|
|
3071
|
-
const sectionPath =
|
|
3072
|
-
const schemaFile =
|
|
3073
|
-
const defaultTemplate =
|
|
3333
|
+
const sectionPath = path11__default.default.join(sectionsDir, sectionName);
|
|
3334
|
+
const schemaFile = path11__default.default.join(sectionPath, `${sectionName}.schema.ts`);
|
|
3335
|
+
const defaultTemplate = path11__default.default.join(
|
|
3074
3336
|
sectionPath,
|
|
3075
3337
|
`${sectionName}-default.tsx`
|
|
3076
3338
|
);
|
|
3077
|
-
const indexFile =
|
|
3339
|
+
const indexFile = path11__default.default.join(sectionPath, "index.ts");
|
|
3078
3340
|
if (!fs__default.default.existsSync(schemaFile)) {
|
|
3079
3341
|
issues.push({
|
|
3080
3342
|
type: "error",
|
|
@@ -3098,14 +3360,14 @@ async function validateCommand(options) {
|
|
|
3098
3360
|
}
|
|
3099
3361
|
}
|
|
3100
3362
|
}
|
|
3101
|
-
const blocksDir =
|
|
3363
|
+
const blocksDir = path11__default.default.join(themePath, "blocks");
|
|
3102
3364
|
if (fs__default.default.existsSync(blocksDir)) {
|
|
3103
|
-
const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => fs__default.default.statSync(
|
|
3365
|
+
const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => fs__default.default.statSync(path11__default.default.join(blocksDir, name)).isDirectory());
|
|
3104
3366
|
for (const blockName of blocks) {
|
|
3105
|
-
const blockPath =
|
|
3106
|
-
const schemaFile =
|
|
3107
|
-
const componentFile =
|
|
3108
|
-
const indexFile =
|
|
3367
|
+
const blockPath = path11__default.default.join(blocksDir, blockName);
|
|
3368
|
+
const schemaFile = path11__default.default.join(blockPath, `${blockName}.schema.ts`);
|
|
3369
|
+
const componentFile = path11__default.default.join(blockPath, `${blockName}.tsx`);
|
|
3370
|
+
const indexFile = path11__default.default.join(blockPath, "index.ts");
|
|
3109
3371
|
if (!fs__default.default.existsSync(schemaFile)) {
|
|
3110
3372
|
issues.push({
|
|
3111
3373
|
type: "error",
|
|
@@ -3131,13 +3393,13 @@ async function validateCommand(options) {
|
|
|
3131
3393
|
}
|
|
3132
3394
|
if (fs__default.default.existsSync(sectionsDir)) {
|
|
3133
3395
|
const sections = fs__default.default.readdirSync(sectionsDir).filter(
|
|
3134
|
-
(name) => fs__default.default.statSync(
|
|
3396
|
+
(name) => fs__default.default.statSync(path11__default.default.join(sectionsDir, name)).isDirectory()
|
|
3135
3397
|
);
|
|
3136
3398
|
for (const sectionName of sections) {
|
|
3137
|
-
const sectionPath =
|
|
3399
|
+
const sectionPath = path11__default.default.join(sectionsDir, sectionName);
|
|
3138
3400
|
const tsxFiles = fs__default.default.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
|
|
3139
3401
|
for (const tsxFile of tsxFiles) {
|
|
3140
|
-
const filePath =
|
|
3402
|
+
const filePath = path11__default.default.join(sectionPath, tsxFile);
|
|
3141
3403
|
const content = fs__default.default.readFileSync(filePath, "utf-8");
|
|
3142
3404
|
const relPath = `sections/${sectionName}/${tsxFile}`;
|
|
3143
3405
|
if (!content.includes('"use client"') && !content.includes("'use client'")) {
|
|
@@ -3185,12 +3447,12 @@ async function validateCommand(options) {
|
|
|
3185
3447
|
}
|
|
3186
3448
|
}
|
|
3187
3449
|
}
|
|
3188
|
-
const registryPath =
|
|
3189
|
-
const bundleEntryPath =
|
|
3450
|
+
const registryPath = path11__default.default.join(themePath, "sections-registry.ts");
|
|
3451
|
+
const bundleEntryPath = path11__default.default.join(themePath, "bundle-entry.ts");
|
|
3190
3452
|
const registryContent = fs__default.default.existsSync(registryPath) ? fs__default.default.readFileSync(registryPath, "utf-8") : fs__default.default.existsSync(bundleEntryPath) ? fs__default.default.readFileSync(bundleEntryPath, "utf-8") : "";
|
|
3191
3453
|
if (fs__default.default.existsSync(sectionsDir) && registryContent) {
|
|
3192
3454
|
const sections = fs__default.default.readdirSync(sectionsDir).filter(
|
|
3193
|
-
(name) => fs__default.default.statSync(
|
|
3455
|
+
(name) => fs__default.default.statSync(path11__default.default.join(sectionsDir, name)).isDirectory()
|
|
3194
3456
|
);
|
|
3195
3457
|
for (const sectionName of sections) {
|
|
3196
3458
|
if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
|
|
@@ -3213,7 +3475,7 @@ async function validateCommand(options) {
|
|
|
3213
3475
|
});
|
|
3214
3476
|
}
|
|
3215
3477
|
}
|
|
3216
|
-
const pagesDir =
|
|
3478
|
+
const pagesDir = path11__default.default.join(themePath, "pages");
|
|
3217
3479
|
if (fs__default.default.existsSync(pagesDir)) {
|
|
3218
3480
|
const allSchemaTypeSet = new Set(
|
|
3219
3481
|
schemaTypes.map((s) => s.schemaType || s.folderName)
|
|
@@ -3265,9 +3527,9 @@ async function validateCommand(options) {
|
|
|
3265
3527
|
}
|
|
3266
3528
|
async function loadSchemaTypes(themePath, sectionsDir) {
|
|
3267
3529
|
const results = [];
|
|
3268
|
-
const sections = fs__default.default.readdirSync(sectionsDir).filter((name) => fs__default.default.statSync(
|
|
3530
|
+
const sections = fs__default.default.readdirSync(sectionsDir).filter((name) => fs__default.default.statSync(path11__default.default.join(sectionsDir, name)).isDirectory());
|
|
3269
3531
|
for (const sectionName of sections) {
|
|
3270
|
-
const schemaFile =
|
|
3532
|
+
const schemaFile = path11__default.default.join(
|
|
3271
3533
|
sectionsDir,
|
|
3272
3534
|
sectionName,
|
|
3273
3535
|
`${sectionName}.schema.ts`
|
|
@@ -3305,7 +3567,7 @@ async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
|
3305
3567
|
const issues = [];
|
|
3306
3568
|
const files = fs__default.default.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
|
|
3307
3569
|
for (const file of files) {
|
|
3308
|
-
const content = fs__default.default.readFileSync(
|
|
3570
|
+
const content = fs__default.default.readFileSync(path11__default.default.join(pagesDir, file), "utf-8");
|
|
3309
3571
|
const pageName = file.replace(/\.(ts|js)$/, "");
|
|
3310
3572
|
const sectionsMatch = content.match(/\bsections:\s*\[/);
|
|
3311
3573
|
if (!sectionsMatch || sectionsMatch.index === void 0) continue;
|
|
@@ -3318,9 +3580,13 @@ async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
|
3318
3580
|
endIdx = i;
|
|
3319
3581
|
}
|
|
3320
3582
|
const sectionsBlock = content.slice(startIdx, endIdx);
|
|
3321
|
-
const
|
|
3322
|
-
|
|
3583
|
+
const sectionTypeMatches = sectionsBlock.matchAll(
|
|
3584
|
+
/\bid:\s*["'][^"']*["'],\s*\n?\s*type:\s*["']([^"']+)["']/g
|
|
3585
|
+
);
|
|
3586
|
+
for (const match of sectionTypeMatches) {
|
|
3323
3587
|
const sectionType = match[1];
|
|
3588
|
+
if (COMPONENT_TYPES.has(sectionType)) continue;
|
|
3589
|
+
if (BLOCK_TYPES.has(sectionType)) continue;
|
|
3324
3590
|
if (!validTypes.has(sectionType)) {
|
|
3325
3591
|
issues.push({
|
|
3326
3592
|
type: "error",
|
|
@@ -3373,6 +3639,64 @@ var FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
|
3373
3639
|
"inline_richtext",
|
|
3374
3640
|
"repeater"
|
|
3375
3641
|
]);
|
|
3642
|
+
var COMPONENT_TYPES = /* @__PURE__ */ new Set([
|
|
3643
|
+
"heading",
|
|
3644
|
+
"paragraph",
|
|
3645
|
+
"button",
|
|
3646
|
+
"image",
|
|
3647
|
+
"link",
|
|
3648
|
+
"icon",
|
|
3649
|
+
"badge",
|
|
3650
|
+
"divider",
|
|
3651
|
+
"spacer",
|
|
3652
|
+
"container",
|
|
3653
|
+
"grid",
|
|
3654
|
+
"columns",
|
|
3655
|
+
"card",
|
|
3656
|
+
"quote",
|
|
3657
|
+
"input",
|
|
3658
|
+
"textarea",
|
|
3659
|
+
"checkbox",
|
|
3660
|
+
"select",
|
|
3661
|
+
"video",
|
|
3662
|
+
"gallery",
|
|
3663
|
+
"alert",
|
|
3664
|
+
"progress",
|
|
3665
|
+
"rating",
|
|
3666
|
+
"timer",
|
|
3667
|
+
"list",
|
|
3668
|
+
"table",
|
|
3669
|
+
"accordion",
|
|
3670
|
+
"tabs",
|
|
3671
|
+
"code",
|
|
3672
|
+
"map",
|
|
3673
|
+
"product-card",
|
|
3674
|
+
"blog-card",
|
|
3675
|
+
"social-links",
|
|
3676
|
+
"hotline-contacts",
|
|
3677
|
+
"company-info",
|
|
3678
|
+
"torn-separator"
|
|
3679
|
+
]);
|
|
3680
|
+
var BLOCK_TYPES = /* @__PURE__ */ new Set([
|
|
3681
|
+
"brand-feature",
|
|
3682
|
+
"collection-item",
|
|
3683
|
+
"crafting-step",
|
|
3684
|
+
"testimonial-item",
|
|
3685
|
+
"stat-item",
|
|
3686
|
+
"footer-link",
|
|
3687
|
+
"navigation-links-block",
|
|
3688
|
+
"policy-section",
|
|
3689
|
+
"core-value-card",
|
|
3690
|
+
"faq-item",
|
|
3691
|
+
"feature-item",
|
|
3692
|
+
"gallery-item",
|
|
3693
|
+
"logo-item",
|
|
3694
|
+
"pricing-tier",
|
|
3695
|
+
"service-item",
|
|
3696
|
+
"stat-card",
|
|
3697
|
+
"team-member",
|
|
3698
|
+
"hero-content"
|
|
3699
|
+
]);
|
|
3376
3700
|
|
|
3377
3701
|
// src/commands/build.ts
|
|
3378
3702
|
init_logger();
|
|
@@ -3383,14 +3707,14 @@ async function buildCommand(options) {
|
|
|
3383
3707
|
if (options.theme) {
|
|
3384
3708
|
themeName = options.theme;
|
|
3385
3709
|
try {
|
|
3386
|
-
const workspaceThemePath =
|
|
3710
|
+
const workspaceThemePath = path11__default.default.join(getThemesDir(), themeName);
|
|
3387
3711
|
if (fs__default.default.existsSync(workspaceThemePath)) {
|
|
3388
3712
|
themePath = workspaceThemePath;
|
|
3389
3713
|
} else {
|
|
3390
|
-
themePath =
|
|
3714
|
+
themePath = path11__default.default.join(process.cwd(), themeName);
|
|
3391
3715
|
}
|
|
3392
3716
|
} catch {
|
|
3393
|
-
themePath =
|
|
3717
|
+
themePath = path11__default.default.join(process.cwd(), themeName);
|
|
3394
3718
|
}
|
|
3395
3719
|
if (!fs__default.default.existsSync(themePath)) {
|
|
3396
3720
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -3401,10 +3725,10 @@ async function buildCommand(options) {
|
|
|
3401
3725
|
"theme.config.ts",
|
|
3402
3726
|
"bundle-entry.ts",
|
|
3403
3727
|
"manifest.ts"
|
|
3404
|
-
].some((f) => fs__default.default.existsSync(
|
|
3728
|
+
].some((f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f)));
|
|
3405
3729
|
if (isThemeDir2) {
|
|
3406
3730
|
themePath = process.cwd();
|
|
3407
|
-
themeName =
|
|
3731
|
+
themeName = path11__default.default.basename(themePath);
|
|
3408
3732
|
logger.info(`Building current theme: ${themeName}`);
|
|
3409
3733
|
} else {
|
|
3410
3734
|
logger.error(
|
|
@@ -3413,7 +3737,7 @@ async function buildCommand(options) {
|
|
|
3413
3737
|
process.exit(1);
|
|
3414
3738
|
}
|
|
3415
3739
|
}
|
|
3416
|
-
const packageJsonPath =
|
|
3740
|
+
const packageJsonPath = path11__default.default.join(themePath, "package.json");
|
|
3417
3741
|
const hasPkgJson = fs__default.default.existsSync(packageJsonPath);
|
|
3418
3742
|
if (!hasPkgJson) {
|
|
3419
3743
|
logger.warning(
|
|
@@ -3469,9 +3793,9 @@ async function buildCommand(options) {
|
|
|
3469
3793
|
logger.success("\u2713 Theme built successfully!");
|
|
3470
3794
|
logger.newLine();
|
|
3471
3795
|
logger.info(`Theme: ${themeName}`);
|
|
3472
|
-
const distPath =
|
|
3796
|
+
const distPath = path11__default.default.join(themePath, "dist");
|
|
3473
3797
|
if (fs__default.default.existsSync(distPath)) {
|
|
3474
|
-
logger.log(`Output: ${
|
|
3798
|
+
logger.log(`Output: ${path11__default.default.relative(process.cwd(), distPath)}`);
|
|
3475
3799
|
const files = fs__default.default.readdirSync(distPath);
|
|
3476
3800
|
logger.log(`Files: ${files.length}`);
|
|
3477
3801
|
}
|
|
@@ -3527,7 +3851,7 @@ async function packageCommand(options) {
|
|
|
3527
3851
|
let themeName;
|
|
3528
3852
|
if (options.theme) {
|
|
3529
3853
|
themeName = options.theme;
|
|
3530
|
-
themePath =
|
|
3854
|
+
themePath = path11__default.default.join(getThemesDir(), themeName);
|
|
3531
3855
|
if (!fs__default.default.existsSync(themePath)) {
|
|
3532
3856
|
logger.error(`Theme "${themeName}" not found.`);
|
|
3533
3857
|
process.exit(1);
|
|
@@ -3537,10 +3861,10 @@ async function packageCommand(options) {
|
|
|
3537
3861
|
"theme.config.ts",
|
|
3538
3862
|
"bundle-entry.ts",
|
|
3539
3863
|
"manifest.ts"
|
|
3540
|
-
].some((f) => fs__default.default.existsSync(
|
|
3864
|
+
].some((f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f)));
|
|
3541
3865
|
if (isThemeDir2) {
|
|
3542
3866
|
themePath = process.cwd();
|
|
3543
|
-
themeName =
|
|
3867
|
+
themeName = path11__default.default.basename(themePath);
|
|
3544
3868
|
logger.info(`Packaging current theme: ${themeName}`);
|
|
3545
3869
|
} else {
|
|
3546
3870
|
logger.error(
|
|
@@ -3549,7 +3873,7 @@ async function packageCommand(options) {
|
|
|
3549
3873
|
process.exit(1);
|
|
3550
3874
|
}
|
|
3551
3875
|
}
|
|
3552
|
-
const packageJsonPath =
|
|
3876
|
+
const packageJsonPath = path11__default.default.join(themePath, "package.json");
|
|
3553
3877
|
let version2 = "1.0.0";
|
|
3554
3878
|
if (fs__default.default.existsSync(packageJsonPath)) {
|
|
3555
3879
|
const packageJson = await fs__default.default.readJson(packageJsonPath);
|
|
@@ -3559,7 +3883,7 @@ async function packageCommand(options) {
|
|
|
3559
3883
|
logger.info(`Theme: ${themeName}`);
|
|
3560
3884
|
logger.info(`Version: ${version2}`);
|
|
3561
3885
|
logger.newLine();
|
|
3562
|
-
const compiledThemePath =
|
|
3886
|
+
const compiledThemePath = path11__default.default.join(
|
|
3563
3887
|
process.cwd(),
|
|
3564
3888
|
"themes",
|
|
3565
3889
|
themeName,
|
|
@@ -3593,8 +3917,8 @@ async function packageCommand(options) {
|
|
|
3593
3917
|
logger.newLine();
|
|
3594
3918
|
logger.section("Step 2: Create Package");
|
|
3595
3919
|
const packageName = options.name || `${themeName}-${version2}`;
|
|
3596
|
-
const outputDir = options.output ||
|
|
3597
|
-
const outputPath =
|
|
3920
|
+
const outputDir = options.output || path11__default.default.join(process.cwd(), "dist");
|
|
3921
|
+
const outputPath = path11__default.default.join(outputDir, `${packageName}.zip`);
|
|
3598
3922
|
await fs__default.default.ensureDir(outputDir);
|
|
3599
3923
|
logger.startSpinner("Creating zip archive...");
|
|
3600
3924
|
try {
|
|
@@ -3607,11 +3931,11 @@ async function packageCommand(options) {
|
|
|
3607
3931
|
logger.newLine();
|
|
3608
3932
|
logger.info(`Package: ${packageName}.zip`);
|
|
3609
3933
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3610
|
-
logger.log(`Location: ${
|
|
3934
|
+
logger.log(`Location: ${path11__default.default.relative(process.cwd(), outputPath)}`);
|
|
3611
3935
|
logger.newLine();
|
|
3612
3936
|
logger.section("Next steps:");
|
|
3613
3937
|
logger.log(
|
|
3614
|
-
` onexthm deploy --package ${
|
|
3938
|
+
` onexthm deploy --package ${path11__default.default.relative(process.cwd(), outputPath)}`
|
|
3615
3939
|
);
|
|
3616
3940
|
} catch (error) {
|
|
3617
3941
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3669,9 +3993,9 @@ async function deployCommand(options) {
|
|
|
3669
3993
|
ensureOneXProject();
|
|
3670
3994
|
let packagePath;
|
|
3671
3995
|
if (options.package) {
|
|
3672
|
-
packagePath =
|
|
3996
|
+
packagePath = path11__default.default.resolve(options.package);
|
|
3673
3997
|
} else if (options.theme) {
|
|
3674
|
-
const distDir =
|
|
3998
|
+
const distDir = path11__default.default.join(process.cwd(), "dist");
|
|
3675
3999
|
if (!fs__default.default.existsSync(distDir)) {
|
|
3676
4000
|
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3677
4001
|
process.exit(1);
|
|
@@ -3686,7 +4010,7 @@ async function deployCommand(options) {
|
|
|
3686
4010
|
process.exit(1);
|
|
3687
4011
|
}
|
|
3688
4012
|
packageFiles.sort().reverse();
|
|
3689
|
-
packagePath =
|
|
4013
|
+
packagePath = path11__default.default.join(distDir, packageFiles[0]);
|
|
3690
4014
|
} else {
|
|
3691
4015
|
logger.error("Either --package or --theme must be specified.");
|
|
3692
4016
|
logger.info("Examples:");
|
|
@@ -3700,11 +4024,11 @@ async function deployCommand(options) {
|
|
|
3700
4024
|
}
|
|
3701
4025
|
const stats = await fs__default.default.stat(packagePath);
|
|
3702
4026
|
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
3703
|
-
const fileName =
|
|
4027
|
+
const fileName = path11__default.default.basename(packagePath);
|
|
3704
4028
|
logger.newLine();
|
|
3705
4029
|
logger.info(`Package: ${fileName}`);
|
|
3706
4030
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3707
|
-
logger.log(`Path: ${
|
|
4031
|
+
logger.log(`Path: ${path11__default.default.relative(process.cwd(), packagePath)}`);
|
|
3708
4032
|
logger.newLine();
|
|
3709
4033
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3710
4034
|
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
@@ -3861,8 +4185,8 @@ async function downloadBundleZip(apiUrl, themeId, version2) {
|
|
|
3861
4185
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
3862
4186
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
3863
4187
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
3864
|
-
const hashedPath =
|
|
3865
|
-
const stablePath =
|
|
4188
|
+
const hashedPath = path11__default.default.join(outputDir, entryFile);
|
|
4189
|
+
const stablePath = path11__default.default.join(outputDir, "bundle-entry.js");
|
|
3866
4190
|
if (await fs__default.default.pathExists(hashedPath)) {
|
|
3867
4191
|
await fs__default.default.copy(hashedPath, stablePath);
|
|
3868
4192
|
const mapPath = hashedPath + ".map";
|
|
@@ -3871,13 +4195,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
|
|
|
3871
4195
|
}
|
|
3872
4196
|
}
|
|
3873
4197
|
}
|
|
3874
|
-
const sectionsRegistryPath =
|
|
4198
|
+
const sectionsRegistryPath = path11__default.default.join(outputDir, "sections-registry.js");
|
|
3875
4199
|
const content = `// Re-export all sections from bundle-entry
|
|
3876
4200
|
// This file exists to maintain compatibility with the import path
|
|
3877
4201
|
export * from './bundle-entry.js';
|
|
3878
4202
|
`;
|
|
3879
4203
|
await fs__default.default.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
3880
|
-
const pkgJsonPath =
|
|
4204
|
+
const pkgJsonPath = path11__default.default.join(outputDir, "package.json");
|
|
3881
4205
|
await fs__default.default.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
3882
4206
|
}
|
|
3883
4207
|
function showDownloadFailureHelp(themeId, apiUrl) {
|
|
@@ -3908,9 +4232,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3908
4232
|
console.log();
|
|
3909
4233
|
console.log(chalk4__default.default.white("2. Check API URL configuration:"));
|
|
3910
4234
|
console.log(chalk4__default.default.gray(` Current API URL: ${apiUrl}`));
|
|
3911
|
-
console.log(
|
|
3912
|
-
chalk4__default.default.gray(" Override with NEXT_PUBLIC_API_URL or ONEXTHM_API_URL")
|
|
3913
|
-
);
|
|
4235
|
+
console.log(chalk4__default.default.gray(" Override with ONEXTHM_API_URL env var if needed"));
|
|
3914
4236
|
console.log();
|
|
3915
4237
|
console.log(chalk4__default.default.white("3. Pin a specific version (CI/production):"));
|
|
3916
4238
|
console.log(
|
|
@@ -3920,15 +4242,17 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3920
4242
|
}
|
|
3921
4243
|
async function downloadCommand(options) {
|
|
3922
4244
|
logger.header("Download Theme");
|
|
4245
|
+
const env = options.env ?? "dev";
|
|
4246
|
+
const apiUrl = getApiUrl(env);
|
|
4247
|
+
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3923
4248
|
const spinner = ora__default.default("Initializing download...").start();
|
|
3924
|
-
if (options.bucket
|
|
4249
|
+
if (options.bucket) {
|
|
3925
4250
|
spinner.stop();
|
|
3926
4251
|
logger.warning(
|
|
3927
|
-
"--bucket
|
|
4252
|
+
"--bucket is deprecated and ignored. Themes are now served via HTTP from the website-api Lambda."
|
|
3928
4253
|
);
|
|
3929
4254
|
spinner.start();
|
|
3930
4255
|
}
|
|
3931
|
-
const apiUrl = getApiUrl();
|
|
3932
4256
|
try {
|
|
3933
4257
|
const themeId = options.themeId || process.env.NEXT_PUBLIC_THEME_ID || process.env.THEME_ID;
|
|
3934
4258
|
const requestedVersion = options.version || process.env.THEME_VERSION || "latest";
|
|
@@ -3976,7 +4300,7 @@ async function downloadCommand(options) {
|
|
|
3976
4300
|
zip.extractAllTo(outputDir, true);
|
|
3977
4301
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
3978
4302
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
3979
|
-
const manifestPath =
|
|
4303
|
+
const manifestPath = path11__default.default.join(outputDir, "manifest.json");
|
|
3980
4304
|
const manifest = await fs__default.default.readJson(manifestPath);
|
|
3981
4305
|
await createCompatibilityFiles(outputDir, manifest);
|
|
3982
4306
|
console.log();
|
|
@@ -3985,6 +4309,7 @@ async function downloadCommand(options) {
|
|
|
3985
4309
|
console.log(
|
|
3986
4310
|
chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(`${themeId}@${resolvedVersion}`)
|
|
3987
4311
|
);
|
|
4312
|
+
console.log(chalk4__default.default.cyan(" Env: ") + chalk4__default.default.white(env));
|
|
3988
4313
|
console.log(chalk4__default.default.cyan(" Source: ") + chalk4__default.default.white(apiUrl));
|
|
3989
4314
|
console.log(chalk4__default.default.cyan(" Output: ") + chalk4__default.default.white(outputDir));
|
|
3990
4315
|
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
@@ -4027,11 +4352,9 @@ async function resolveLatestVersion2(apiUrl, themeId) {
|
|
|
4027
4352
|
}
|
|
4028
4353
|
return latest;
|
|
4029
4354
|
}
|
|
4030
|
-
async function fetchSourceZip(apiUrl, themeId, version2) {
|
|
4355
|
+
async function fetchSourceZip(apiUrl, themeId, version2, env) {
|
|
4031
4356
|
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/source?version=${encodeURIComponent(version2)}`;
|
|
4032
|
-
const response = await authenticatedFetch(url, {
|
|
4033
|
-
method: "GET"
|
|
4034
|
-
});
|
|
4357
|
+
const response = await authenticatedFetch(url, { method: "GET" }, env);
|
|
4035
4358
|
if (!response.ok) {
|
|
4036
4359
|
if (response.status === 404) {
|
|
4037
4360
|
throw new Error(
|
|
@@ -4040,7 +4363,7 @@ async function fetchSourceZip(apiUrl, themeId, version2) {
|
|
|
4040
4363
|
}
|
|
4041
4364
|
if (response.status === 401 || response.status === 403) {
|
|
4042
4365
|
throw new Error(
|
|
4043
|
-
`Not authorized to download source for "${themeId}". Run \`onexthm login\` first.`
|
|
4366
|
+
`Not authorized to download source for "${themeId}". Run \`onexthm login --env ${env}\` first.`
|
|
4044
4367
|
);
|
|
4045
4368
|
}
|
|
4046
4369
|
throw new Error(
|
|
@@ -4098,7 +4421,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4098
4421
|
const oldPrefix = `${oldName}-`;
|
|
4099
4422
|
const newPrefix = `${newName}-`;
|
|
4100
4423
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4101
|
-
const pkgPath =
|
|
4424
|
+
const pkgPath = path11__default.default.join(themeDir, "package.json");
|
|
4102
4425
|
if (await fs__default.default.pathExists(pkgPath)) {
|
|
4103
4426
|
const pkg = await fs__default.default.readJson(pkgPath);
|
|
4104
4427
|
pkg.name = `@onex-themes/${newName}`;
|
|
@@ -4114,7 +4437,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4114
4437
|
}
|
|
4115
4438
|
await fs__default.default.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
4116
4439
|
}
|
|
4117
|
-
const configPath =
|
|
4440
|
+
const configPath = path11__default.default.join(themeDir, "theme.config.ts");
|
|
4118
4441
|
if (await fs__default.default.pathExists(configPath)) {
|
|
4119
4442
|
let content = await fs__default.default.readFile(configPath, "utf-8");
|
|
4120
4443
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -4124,7 +4447,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4124
4447
|
);
|
|
4125
4448
|
await fs__default.default.writeFile(configPath, content);
|
|
4126
4449
|
}
|
|
4127
|
-
const layoutPath =
|
|
4450
|
+
const layoutPath = path11__default.default.join(themeDir, "theme.layout.ts");
|
|
4128
4451
|
if (await fs__default.default.pathExists(layoutPath)) {
|
|
4129
4452
|
let content = await fs__default.default.readFile(layoutPath, "utf-8");
|
|
4130
4453
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -4137,7 +4460,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4137
4460
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
4138
4461
|
const tsFiles = await glob.glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
4139
4462
|
for (const file of tsFiles) {
|
|
4140
|
-
const filePath =
|
|
4463
|
+
const filePath = path11__default.default.join(themeDir, file);
|
|
4141
4464
|
let content = await fs__default.default.readFile(filePath, "utf-8");
|
|
4142
4465
|
const original = content;
|
|
4143
4466
|
content = content.replace(
|
|
@@ -4159,14 +4482,19 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
4159
4482
|
}
|
|
4160
4483
|
async function cloneCommand(themeName, options) {
|
|
4161
4484
|
logger.header("Clone Theme Source");
|
|
4162
|
-
|
|
4485
|
+
const env = options.env ?? "dev";
|
|
4486
|
+
const apiUrl = getApiUrl(env);
|
|
4487
|
+
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
4488
|
+
if (options.bucket) {
|
|
4163
4489
|
logger.warning(
|
|
4164
|
-
"--bucket
|
|
4490
|
+
"--bucket is deprecated and ignored. Source is now fetched via HTTP from the website-api Lambda."
|
|
4165
4491
|
);
|
|
4166
4492
|
}
|
|
4167
|
-
const tokens = await getValidTokens();
|
|
4493
|
+
const tokens = await getValidTokens(env);
|
|
4168
4494
|
if (!tokens) {
|
|
4169
|
-
logger.error(
|
|
4495
|
+
logger.error(
|
|
4496
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
4497
|
+
);
|
|
4170
4498
|
process.exit(1);
|
|
4171
4499
|
}
|
|
4172
4500
|
let newName = options.name;
|
|
@@ -4175,8 +4503,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4175
4503
|
}
|
|
4176
4504
|
const spinner = ora__default.default("Initializing clone...").start();
|
|
4177
4505
|
try {
|
|
4178
|
-
const
|
|
4179
|
-
const outputDir = options.output || path9__default.default.resolve(process.cwd(), newName);
|
|
4506
|
+
const outputDir = options.output || path11__default.default.resolve(process.cwd(), newName);
|
|
4180
4507
|
if (await fs__default.default.pathExists(outputDir)) {
|
|
4181
4508
|
spinner.fail(chalk4__default.default.red(`Directory already exists: ${outputDir}`));
|
|
4182
4509
|
logger.info(
|
|
@@ -4195,7 +4522,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4195
4522
|
spinner.start(`Downloading source.zip for ${themeName}@${version2}...`);
|
|
4196
4523
|
let zipBuffer;
|
|
4197
4524
|
try {
|
|
4198
|
-
zipBuffer = await fetchSourceZip(apiUrl, themeName, version2);
|
|
4525
|
+
zipBuffer = await fetchSourceZip(apiUrl, themeName, version2, env);
|
|
4199
4526
|
} catch (error) {
|
|
4200
4527
|
spinner.fail(chalk4__default.default.red(error.message));
|
|
4201
4528
|
console.log();
|
|
@@ -4222,20 +4549,20 @@ async function cloneCommand(themeName, options) {
|
|
|
4222
4549
|
spinner.succeed(
|
|
4223
4550
|
`Renamed theme: ${chalk4__default.default.gray(themeName)} \u2192 ${chalk4__default.default.cyan(newName)}`
|
|
4224
4551
|
);
|
|
4225
|
-
const envExamplePath =
|
|
4552
|
+
const envExamplePath = path11__default.default.join(outputDir, ".env.example");
|
|
4226
4553
|
if (!await fs__default.default.pathExists(envExamplePath)) {
|
|
4227
4554
|
await fs__default.default.writeFile(
|
|
4228
4555
|
envExamplePath,
|
|
4229
4556
|
[
|
|
4230
4557
|
"# API Configuration (enables real data in preview)",
|
|
4231
4558
|
"# Get your Company ID from the OneX dashboard",
|
|
4232
|
-
|
|
4559
|
+
`NEXT_PUBLIC_API_URL=${apiUrl}`,
|
|
4233
4560
|
"NEXT_PUBLIC_COMPANY_ID=",
|
|
4234
4561
|
""
|
|
4235
4562
|
].join("\n")
|
|
4236
4563
|
);
|
|
4237
4564
|
}
|
|
4238
|
-
const mcpJsonPath =
|
|
4565
|
+
const mcpJsonPath = path11__default.default.join(outputDir, ".mcp.json");
|
|
4239
4566
|
if (await fs__default.default.pathExists(mcpJsonPath)) {
|
|
4240
4567
|
const { default: inquirerMod } = await import('inquirer');
|
|
4241
4568
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
@@ -4260,7 +4587,7 @@ async function cloneCommand(themeName, options) {
|
|
|
4260
4587
|
}
|
|
4261
4588
|
if (options.install !== false) {
|
|
4262
4589
|
const hasPkgJson = await fs__default.default.pathExists(
|
|
4263
|
-
|
|
4590
|
+
path11__default.default.join(outputDir, "package.json")
|
|
4264
4591
|
);
|
|
4265
4592
|
if (hasPkgJson) {
|
|
4266
4593
|
spinner.start("Installing dependencies...");
|
|
@@ -4282,12 +4609,13 @@ async function cloneCommand(themeName, options) {
|
|
|
4282
4609
|
console.log(
|
|
4283
4610
|
chalk4__default.default.cyan(" Source: ") + chalk4__default.default.gray(`${themeName}@${version2}`)
|
|
4284
4611
|
);
|
|
4612
|
+
console.log(chalk4__default.default.cyan(" Env: ") + chalk4__default.default.white(env));
|
|
4285
4613
|
console.log(chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(newName));
|
|
4286
4614
|
console.log(chalk4__default.default.cyan(" Location: ") + chalk4__default.default.white(outputDir));
|
|
4287
4615
|
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
4288
4616
|
console.log();
|
|
4289
4617
|
console.log(chalk4__default.default.cyan("Next steps:"));
|
|
4290
|
-
console.log(chalk4__default.default.gray(` cd ${
|
|
4618
|
+
console.log(chalk4__default.default.gray(` cd ${path11__default.default.relative(process.cwd(), outputDir)}`));
|
|
4291
4619
|
console.log(
|
|
4292
4620
|
chalk4__default.default.gray(" cp .env.example .env # then add your Company ID")
|
|
4293
4621
|
);
|
|
@@ -4314,14 +4642,14 @@ async function devCommand(options) {
|
|
|
4314
4642
|
if (options.theme) {
|
|
4315
4643
|
themeName = options.theme;
|
|
4316
4644
|
try {
|
|
4317
|
-
const workspaceThemePath =
|
|
4645
|
+
const workspaceThemePath = path11__default.default.join(getThemesDir(), themeName);
|
|
4318
4646
|
if (fs__default.default.existsSync(workspaceThemePath)) {
|
|
4319
4647
|
themePath = workspaceThemePath;
|
|
4320
4648
|
} else {
|
|
4321
|
-
themePath =
|
|
4649
|
+
themePath = path11__default.default.join(process.cwd(), themeName);
|
|
4322
4650
|
}
|
|
4323
4651
|
} catch {
|
|
4324
|
-
themePath =
|
|
4652
|
+
themePath = path11__default.default.join(process.cwd(), themeName);
|
|
4325
4653
|
}
|
|
4326
4654
|
if (!fs__default.default.existsSync(themePath)) {
|
|
4327
4655
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -4332,10 +4660,10 @@ async function devCommand(options) {
|
|
|
4332
4660
|
"theme.config.ts",
|
|
4333
4661
|
"bundle-entry.ts",
|
|
4334
4662
|
"manifest.ts"
|
|
4335
|
-
].some((f) => fs__default.default.existsSync(
|
|
4663
|
+
].some((f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f)));
|
|
4336
4664
|
if (isThemeDir2) {
|
|
4337
4665
|
themePath = process.cwd();
|
|
4338
|
-
themeName =
|
|
4666
|
+
themeName = path11__default.default.basename(themePath);
|
|
4339
4667
|
} else {
|
|
4340
4668
|
logger.error(
|
|
4341
4669
|
"Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
|
|
@@ -4404,9 +4732,9 @@ async function devCommand(options) {
|
|
|
4404
4732
|
watcher.close();
|
|
4405
4733
|
await context2.dispose();
|
|
4406
4734
|
server.close();
|
|
4407
|
-
const shimPath =
|
|
4735
|
+
const shimPath = path11__default.default.join(outputDir, ".process-shim.js");
|
|
4408
4736
|
try {
|
|
4409
|
-
await
|
|
4737
|
+
await fs9__default.default.unlink(shimPath);
|
|
4410
4738
|
} catch {
|
|
4411
4739
|
}
|
|
4412
4740
|
process.exit(0);
|
|
@@ -4415,8 +4743,8 @@ async function devCommand(options) {
|
|
|
4415
4743
|
|
|
4416
4744
|
// src/commands/config.ts
|
|
4417
4745
|
init_logger();
|
|
4418
|
-
var CONFIG_DIR =
|
|
4419
|
-
var CONFIG_FILE =
|
|
4746
|
+
var CONFIG_DIR = path11__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
4747
|
+
var CONFIG_FILE = path11__default.default.join(CONFIG_DIR, ".env");
|
|
4420
4748
|
var CONFIG_ENTRIES = [
|
|
4421
4749
|
{
|
|
4422
4750
|
key: "AWS_ACCESS_KEY_ID",
|
|
@@ -4558,9 +4886,13 @@ async function configCommand() {
|
|
|
4558
4886
|
|
|
4559
4887
|
// src/commands/login.ts
|
|
4560
4888
|
init_logger();
|
|
4561
|
-
async function loginCommand() {
|
|
4889
|
+
async function loginCommand(options = {}) {
|
|
4890
|
+
const env = options.env ?? "dev";
|
|
4891
|
+
const apiUrl = getApiUrl(env);
|
|
4562
4892
|
logger.header("OneX Theme Developer Login");
|
|
4563
|
-
|
|
4893
|
+
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
4894
|
+
logger.newLine();
|
|
4895
|
+
const existing = loadAuthTokens(env);
|
|
4564
4896
|
if (existing) {
|
|
4565
4897
|
logger.info(`Already logged in as: ${existing.user.email}`);
|
|
4566
4898
|
const { relogin } = await inquirer__default.default.prompt([
|
|
@@ -4589,7 +4921,6 @@ async function loginCommand() {
|
|
|
4589
4921
|
]);
|
|
4590
4922
|
logger.startSpinner("Logging in...");
|
|
4591
4923
|
try {
|
|
4592
|
-
const apiUrl = getApiUrl();
|
|
4593
4924
|
const response = await fetch(`${apiUrl}/auth/login`, {
|
|
4594
4925
|
method: "POST",
|
|
4595
4926
|
headers: { "Content-Type": "application/json" },
|
|
@@ -4624,15 +4955,18 @@ async function loginCommand() {
|
|
|
4624
4955
|
userId: claims.sub
|
|
4625
4956
|
}
|
|
4626
4957
|
};
|
|
4627
|
-
await saveAuthTokens(tokens);
|
|
4958
|
+
await saveAuthTokens(tokens, env);
|
|
4628
4959
|
logger.stopSpinner(true, "Logged in!");
|
|
4629
4960
|
logger.newLine();
|
|
4630
|
-
logger.info(`
|
|
4631
|
-
|
|
4961
|
+
logger.info(` Environment: ${env}`);
|
|
4962
|
+
logger.info(` Email: ${tokens.user.email}`);
|
|
4963
|
+
if (tokens.user.name) logger.info(` Name: ${tokens.user.name}`);
|
|
4632
4964
|
if (tokens.user.companyId)
|
|
4633
|
-
logger.info(` Company:
|
|
4965
|
+
logger.info(` Company: ${tokens.user.companyId}`);
|
|
4634
4966
|
logger.newLine();
|
|
4635
|
-
logger.success(
|
|
4967
|
+
logger.success(
|
|
4968
|
+
`Token stored securely in ~/.onexthm/auth-${env}.json (encrypted)`
|
|
4969
|
+
);
|
|
4636
4970
|
} catch (error) {
|
|
4637
4971
|
logger.stopSpinner(false, "Login failed");
|
|
4638
4972
|
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
@@ -4642,142 +4976,418 @@ async function loginCommand() {
|
|
|
4642
4976
|
|
|
4643
4977
|
// src/commands/logout.ts
|
|
4644
4978
|
init_logger();
|
|
4645
|
-
async function logoutCommand() {
|
|
4646
|
-
const
|
|
4979
|
+
async function logoutCommand(options = {}) {
|
|
4980
|
+
const env = options.env ?? "dev";
|
|
4981
|
+
const tokens = loadAuthTokens(env);
|
|
4647
4982
|
if (!tokens) {
|
|
4648
|
-
logger.info(
|
|
4983
|
+
logger.info(`Not logged in to ${env} environment.`);
|
|
4649
4984
|
return;
|
|
4650
4985
|
}
|
|
4651
|
-
await clearAuthTokens();
|
|
4652
|
-
logger.success(`Logged out (was: ${tokens.user.email})`);
|
|
4986
|
+
await clearAuthTokens(env);
|
|
4987
|
+
logger.success(`Logged out of ${env} (was: ${tokens.user.email})`);
|
|
4653
4988
|
}
|
|
4654
4989
|
|
|
4655
4990
|
// src/commands/whoami.ts
|
|
4656
4991
|
init_logger();
|
|
4657
|
-
async function whoamiCommand() {
|
|
4658
|
-
const
|
|
4992
|
+
async function whoamiCommand(options = {}) {
|
|
4993
|
+
const env = options.env ?? "dev";
|
|
4994
|
+
const tokens = loadAuthTokens(env);
|
|
4659
4995
|
if (!tokens) {
|
|
4660
|
-
logger.error(
|
|
4996
|
+
logger.error(
|
|
4997
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
4998
|
+
);
|
|
4661
4999
|
process.exit(1);
|
|
4662
5000
|
}
|
|
4663
5001
|
const expired = isTokenExpired(tokens);
|
|
4664
5002
|
logger.header("OneX Theme Developer");
|
|
4665
|
-
logger.info(`
|
|
4666
|
-
|
|
5003
|
+
logger.info(` Environment: ${env} (${getApiUrl(env)})`);
|
|
5004
|
+
logger.info(` Email: ${tokens.user.email}`);
|
|
5005
|
+
if (tokens.user.name) logger.info(` Name: ${tokens.user.name}`);
|
|
4667
5006
|
if (tokens.user.companyId)
|
|
4668
|
-
logger.info(` Company:
|
|
5007
|
+
logger.info(` Company: ${tokens.user.companyId}`);
|
|
4669
5008
|
logger.info(
|
|
4670
|
-
` Status:
|
|
5009
|
+
` Status: ${expired ? "\u26A0 Token expired (will auto-refresh)" : "\u2713 Active"}`
|
|
4671
5010
|
);
|
|
4672
5011
|
}
|
|
4673
5012
|
|
|
4674
5013
|
// src/commands/publish.ts
|
|
4675
5014
|
init_logger();
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
5015
|
+
init_scan_theme_assets();
|
|
5016
|
+
|
|
5017
|
+
// src/utils/fetch-prior-schemas.ts
|
|
5018
|
+
async function fetchPriorGateManifests(themeId, env) {
|
|
5019
|
+
const apiUrl = getApiUrl(env);
|
|
5020
|
+
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/gate-manifests/latest`;
|
|
5021
|
+
let res;
|
|
5022
|
+
try {
|
|
5023
|
+
res = await authenticatedFetch(url, { method: "GET" }, env);
|
|
5024
|
+
} catch (err) {
|
|
5025
|
+
return {
|
|
5026
|
+
result: null,
|
|
5027
|
+
reason: `network error: ${err instanceof Error ? err.message : "unknown"}`
|
|
5028
|
+
};
|
|
5029
|
+
}
|
|
5030
|
+
if (res.status === 404) {
|
|
5031
|
+
return { result: null, reason: "no-prior" };
|
|
5032
|
+
}
|
|
5033
|
+
if (!res.ok) {
|
|
5034
|
+
return {
|
|
5035
|
+
result: null,
|
|
5036
|
+
reason: `server returned ${res.status} ${res.statusText}`
|
|
5037
|
+
};
|
|
5038
|
+
}
|
|
5039
|
+
let data;
|
|
5040
|
+
try {
|
|
5041
|
+
data = await res.json();
|
|
5042
|
+
} catch {
|
|
5043
|
+
return { result: null, reason: "non-JSON response from server" };
|
|
5044
|
+
}
|
|
5045
|
+
const body = data.statusCode ? data.body : data;
|
|
5046
|
+
if (!body || typeof body.version !== "string" || !body.schemas || !body.assets) {
|
|
5047
|
+
return { result: null, reason: "malformed response (missing fields)" };
|
|
5048
|
+
}
|
|
5049
|
+
return {
|
|
5050
|
+
result: {
|
|
5051
|
+
version: body.version,
|
|
5052
|
+
schemas: body.schemas,
|
|
5053
|
+
assets: body.assets
|
|
5054
|
+
},
|
|
5055
|
+
reason: null
|
|
5056
|
+
};
|
|
5057
|
+
}
|
|
5058
|
+
|
|
5059
|
+
// src/utils/schema-diff.ts
|
|
5060
|
+
var SEVERITY = {
|
|
5061
|
+
safe: 0,
|
|
5062
|
+
"safe-rename": 1,
|
|
5063
|
+
"defaults-only": 2,
|
|
5064
|
+
additive: 3,
|
|
5065
|
+
breaking: 4,
|
|
5066
|
+
"breaking-asset": 5,
|
|
5067
|
+
"breaking-severe": 6
|
|
4696
5068
|
};
|
|
4697
|
-
var
|
|
4698
|
-
|
|
4699
|
-
"
|
|
4700
|
-
"
|
|
4701
|
-
"
|
|
4702
|
-
"
|
|
4703
|
-
"
|
|
4704
|
-
"
|
|
4705
|
-
|
|
4706
|
-
function
|
|
4707
|
-
|
|
4708
|
-
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
5069
|
+
var BUMP_FOR = {
|
|
5070
|
+
safe: "patch",
|
|
5071
|
+
"safe-rename": "patch",
|
|
5072
|
+
"defaults-only": "patch",
|
|
5073
|
+
additive: "minor",
|
|
5074
|
+
breaking: "major",
|
|
5075
|
+
"breaking-asset": "major",
|
|
5076
|
+
"breaking-severe": "major"
|
|
5077
|
+
};
|
|
5078
|
+
function bumpFor(kind) {
|
|
5079
|
+
return BUMP_FOR[kind];
|
|
4709
5080
|
}
|
|
4710
|
-
function
|
|
4711
|
-
|
|
4712
|
-
return MIME_MAP[ext] || "application/octet-stream";
|
|
5081
|
+
function maxSeverity(a, b) {
|
|
5082
|
+
return SEVERITY[a] >= SEVERITY[b] ? a : b;
|
|
4713
5083
|
}
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
5084
|
+
function classify(changes) {
|
|
5085
|
+
let highest = "safe";
|
|
5086
|
+
for (const c of changes) {
|
|
5087
|
+
highest = maxSeverity(highest, c.kind);
|
|
5088
|
+
}
|
|
5089
|
+
return { bump: bumpFor(highest), highest, changes };
|
|
4717
5090
|
}
|
|
4718
|
-
function
|
|
4719
|
-
const
|
|
4720
|
-
const
|
|
4721
|
-
const
|
|
4722
|
-
const
|
|
4723
|
-
|
|
4724
|
-
|
|
5091
|
+
function diffManifests(prior, current) {
|
|
5092
|
+
const changes = [];
|
|
5093
|
+
const priorSections = prior.schemas.sections;
|
|
5094
|
+
const currentSections = current.schemas.sections;
|
|
5095
|
+
const sectionTypes = /* @__PURE__ */ new Set([
|
|
5096
|
+
...Object.keys(priorSections),
|
|
5097
|
+
...Object.keys(currentSections)
|
|
5098
|
+
]);
|
|
5099
|
+
for (const type of [...sectionTypes].sort()) {
|
|
5100
|
+
const p = priorSections[type];
|
|
5101
|
+
const c = currentSections[type];
|
|
5102
|
+
if (p && !c) {
|
|
5103
|
+
changes.push({
|
|
5104
|
+
kind: "breaking-severe",
|
|
5105
|
+
path: `sections.${type}`,
|
|
5106
|
+
detail: `Section type "${type}" removed. Pages using this section will render empty.`
|
|
5107
|
+
});
|
|
5108
|
+
continue;
|
|
5109
|
+
}
|
|
5110
|
+
if (!p && c) {
|
|
5111
|
+
changes.push({
|
|
5112
|
+
kind: "additive",
|
|
5113
|
+
path: `sections.${type}`,
|
|
5114
|
+
detail: `Section type "${type}" added.`
|
|
5115
|
+
});
|
|
5116
|
+
continue;
|
|
5117
|
+
}
|
|
5118
|
+
if (p && c) diffSection(p, c, changes);
|
|
5119
|
+
}
|
|
5120
|
+
diffAssets(prior.assets, current.assets, changes);
|
|
5121
|
+
return changes;
|
|
4725
5122
|
}
|
|
4726
|
-
|
|
4727
|
-
const
|
|
4728
|
-
if (
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
});
|
|
4734
|
-
const results = [];
|
|
4735
|
-
for (const rel of files) {
|
|
4736
|
-
const absPath = path9__default.default.join(assetsDir, rel);
|
|
4737
|
-
const stat = await fs__default.default.stat(absPath);
|
|
4738
|
-
if (!stat.isFile()) continue;
|
|
4739
|
-
const originalPath = rel.split(path9__default.default.sep).join("/");
|
|
4740
|
-
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
4741
|
-
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
4742
|
-
const contentType = mimeFor(rel);
|
|
4743
|
-
results.push({
|
|
4744
|
-
originalPath,
|
|
4745
|
-
hashedPath,
|
|
4746
|
-
hash,
|
|
4747
|
-
size: stat.size,
|
|
4748
|
-
contentType,
|
|
4749
|
-
absPath
|
|
5123
|
+
function diffSection(prior, current, out) {
|
|
5124
|
+
const type = current.type;
|
|
5125
|
+
if (JSON.stringify(prior.dataRequirements) !== JSON.stringify(current.dataRequirements)) {
|
|
5126
|
+
out.push({
|
|
5127
|
+
kind: "breaking",
|
|
5128
|
+
path: `sections.${type}.dataRequirements`,
|
|
5129
|
+
detail: "dataRequirements changed."
|
|
4750
5130
|
});
|
|
4751
5131
|
}
|
|
4752
|
-
|
|
4753
|
-
|
|
5132
|
+
diffFieldList(
|
|
5133
|
+
prior.settings,
|
|
5134
|
+
current.settings,
|
|
5135
|
+
`sections.${type}.settings`,
|
|
5136
|
+
out
|
|
5137
|
+
);
|
|
5138
|
+
diffDefaults(
|
|
5139
|
+
prior.defaults,
|
|
5140
|
+
current.defaults,
|
|
5141
|
+
`sections.${type}.defaults`,
|
|
5142
|
+
out
|
|
5143
|
+
);
|
|
5144
|
+
diffBlocks(prior.blocks, current.blocks, `sections.${type}.blocks`, out);
|
|
4754
5145
|
}
|
|
4755
|
-
function
|
|
4756
|
-
const
|
|
4757
|
-
|
|
4758
|
-
|
|
5146
|
+
function diffBlocks(prior, current, pathPrefix, out) {
|
|
5147
|
+
const priorByType = new Map(prior.map((b) => [b.type, b]));
|
|
5148
|
+
const currentByType = new Map(current.map((b) => [b.type, b]));
|
|
5149
|
+
for (const type of /* @__PURE__ */ new Set([
|
|
5150
|
+
...priorByType.keys(),
|
|
5151
|
+
...currentByType.keys()
|
|
5152
|
+
])) {
|
|
5153
|
+
const p = priorByType.get(type);
|
|
5154
|
+
const c = currentByType.get(type);
|
|
5155
|
+
if (p && !c) {
|
|
5156
|
+
out.push({
|
|
5157
|
+
kind: "breaking",
|
|
5158
|
+
path: `${pathPrefix}.${type}`,
|
|
5159
|
+
detail: `Block type "${type}" removed.`
|
|
5160
|
+
});
|
|
5161
|
+
continue;
|
|
5162
|
+
}
|
|
5163
|
+
if (!p && c) {
|
|
5164
|
+
out.push({
|
|
5165
|
+
kind: "additive",
|
|
5166
|
+
path: `${pathPrefix}.${type}`,
|
|
5167
|
+
detail: `Block type "${type}" added.`
|
|
5168
|
+
});
|
|
5169
|
+
continue;
|
|
5170
|
+
}
|
|
5171
|
+
if (p && c) {
|
|
5172
|
+
diffFieldList(
|
|
5173
|
+
p.settings,
|
|
5174
|
+
c.settings,
|
|
5175
|
+
`${pathPrefix}.${type}.settings`,
|
|
5176
|
+
out
|
|
5177
|
+
);
|
|
5178
|
+
diffDefaults(
|
|
5179
|
+
p.defaults,
|
|
5180
|
+
c.defaults,
|
|
5181
|
+
`${pathPrefix}.${type}.defaults`,
|
|
5182
|
+
out
|
|
5183
|
+
);
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
function diffFieldList(prior, current, pathPrefix, out) {
|
|
5188
|
+
const priorById = new Map(prior.map((f) => [f.id, f]));
|
|
5189
|
+
const currentById = new Map(current.map((f) => [f.id, f]));
|
|
5190
|
+
const aliasToCurrent = /* @__PURE__ */ new Map();
|
|
5191
|
+
for (const f of current) {
|
|
5192
|
+
if (f.aliases) {
|
|
5193
|
+
for (const alias of f.aliases) {
|
|
5194
|
+
aliasToCurrent.set(alias, f);
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
for (const [id, p] of priorById) {
|
|
5199
|
+
const c = currentById.get(id);
|
|
5200
|
+
if (c) {
|
|
5201
|
+
diffFieldPair(p, c, `${pathPrefix}.${id}`, out);
|
|
5202
|
+
continue;
|
|
5203
|
+
}
|
|
5204
|
+
const renamed = aliasToCurrent.get(id);
|
|
5205
|
+
if (renamed) {
|
|
5206
|
+
if (renamed.type === p.type) {
|
|
5207
|
+
out.push({
|
|
5208
|
+
kind: "safe-rename",
|
|
5209
|
+
path: `${pathPrefix}.${id}`,
|
|
5210
|
+
detail: `Field "${id}" renamed to "${renamed.id}" (alias preserved).`
|
|
5211
|
+
});
|
|
5212
|
+
} else {
|
|
5213
|
+
out.push({
|
|
5214
|
+
kind: "breaking",
|
|
5215
|
+
path: `${pathPrefix}.${id}`,
|
|
5216
|
+
detail: `Field "${id}" renamed to "${renamed.id}" but type changed (${p.type} \u2192 ${renamed.type}).`
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5219
|
+
} else {
|
|
5220
|
+
out.push({
|
|
5221
|
+
kind: "breaking",
|
|
5222
|
+
path: `${pathPrefix}.${id}`,
|
|
5223
|
+
detail: `Field "${id}" removed. Consider adding aliases: ["${id}"] to the replacement field if this was a rename.`
|
|
5224
|
+
});
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
for (const [id, c] of currentById) {
|
|
5228
|
+
if (priorById.has(id)) continue;
|
|
5229
|
+
const coveredByAlias = c.aliases?.some((a) => priorById.has(a)) ?? false;
|
|
5230
|
+
if (coveredByAlias) continue;
|
|
5231
|
+
if (c.required && c.default === void 0) {
|
|
5232
|
+
out.push({
|
|
5233
|
+
kind: "breaking",
|
|
5234
|
+
path: `${pathPrefix}.${id}`,
|
|
5235
|
+
detail: `Required field "${id}" added with no default. Existing instances cannot satisfy it.`
|
|
5236
|
+
});
|
|
5237
|
+
} else {
|
|
5238
|
+
out.push({
|
|
5239
|
+
kind: "additive",
|
|
5240
|
+
path: `${pathPrefix}.${id}`,
|
|
5241
|
+
detail: `Field "${id}" added.`
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
4759
5244
|
}
|
|
4760
|
-
|
|
5245
|
+
}
|
|
5246
|
+
function diffFieldPair(p, c, path23, out) {
|
|
5247
|
+
if (p.type !== c.type) {
|
|
5248
|
+
out.push({
|
|
5249
|
+
kind: "breaking",
|
|
5250
|
+
path: path23,
|
|
5251
|
+
detail: `Type changed (${p.type} \u2192 ${c.type}). Saved values may misrender.`
|
|
5252
|
+
});
|
|
5253
|
+
return;
|
|
5254
|
+
}
|
|
5255
|
+
if (p.required !== true && c.required === true) {
|
|
5256
|
+
out.push({
|
|
5257
|
+
kind: "breaking",
|
|
5258
|
+
path: path23,
|
|
5259
|
+
detail: "Field became required. Existing empty instances now invalid."
|
|
5260
|
+
});
|
|
5261
|
+
}
|
|
5262
|
+
if (typeof p.maxLength === "number" || typeof c.maxLength === "number") {
|
|
5263
|
+
if ((c.maxLength ?? Infinity) < (p.maxLength ?? Infinity)) {
|
|
5264
|
+
out.push({
|
|
5265
|
+
kind: "breaking",
|
|
5266
|
+
path: path23,
|
|
5267
|
+
detail: `maxLength tightened (${p.maxLength ?? "\u221E"} \u2192 ${c.maxLength}).`
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
if (typeof p.min === "number" || typeof c.min === "number") {
|
|
5272
|
+
if ((c.min ?? -Infinity) > (p.min ?? -Infinity)) {
|
|
5273
|
+
out.push({
|
|
5274
|
+
kind: "breaking",
|
|
5275
|
+
path: path23,
|
|
5276
|
+
detail: `min raised (${p.min ?? "-\u221E"} \u2192 ${c.min}).`
|
|
5277
|
+
});
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
if (typeof p.max === "number" || typeof c.max === "number") {
|
|
5281
|
+
if ((c.max ?? Infinity) < (p.max ?? Infinity)) {
|
|
5282
|
+
out.push({
|
|
5283
|
+
kind: "breaking",
|
|
5284
|
+
path: path23,
|
|
5285
|
+
detail: `max lowered (${p.max ?? "\u221E"} \u2192 ${c.max}).`
|
|
5286
|
+
});
|
|
5287
|
+
}
|
|
5288
|
+
}
|
|
5289
|
+
if (p.options || c.options) {
|
|
5290
|
+
const priorOpts = new Set(p.options ?? []);
|
|
5291
|
+
const currentOpts = new Set(c.options ?? []);
|
|
5292
|
+
const removed = [...priorOpts].filter((o) => !currentOpts.has(o));
|
|
5293
|
+
const added = [...currentOpts].filter((o) => !priorOpts.has(o));
|
|
5294
|
+
if (removed.length > 0) {
|
|
5295
|
+
out.push({
|
|
5296
|
+
kind: "breaking",
|
|
5297
|
+
path: path23,
|
|
5298
|
+
detail: `Option(s) removed: ${removed.join(", ")}. Existing saved values may be orphaned.`
|
|
5299
|
+
});
|
|
5300
|
+
}
|
|
5301
|
+
if (added.length > 0) {
|
|
5302
|
+
out.push({
|
|
5303
|
+
kind: "additive",
|
|
5304
|
+
path: path23,
|
|
5305
|
+
detail: `Option(s) added: ${added.join(", ")}.`
|
|
5306
|
+
});
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
if (!deepEqual(p.default, c.default)) {
|
|
5310
|
+
out.push({
|
|
5311
|
+
kind: "defaults-only",
|
|
5312
|
+
path: path23,
|
|
5313
|
+
detail: `Default changed: ${JSON.stringify(p.default)} \u2192 ${JSON.stringify(c.default)}.`
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
function diffDefaults(prior, current, pathPrefix, out) {
|
|
5318
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(prior), ...Object.keys(current)]);
|
|
5319
|
+
for (const key of [...keys].sort()) {
|
|
5320
|
+
if (!(key in prior) || !(key in current)) continue;
|
|
5321
|
+
if (!deepEqual(prior[key], current[key])) {
|
|
5322
|
+
out.push({
|
|
5323
|
+
kind: "defaults-only",
|
|
5324
|
+
path: `${pathPrefix}.${key}`,
|
|
5325
|
+
detail: `Default value changed.`
|
|
5326
|
+
});
|
|
5327
|
+
}
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
function diffAssets(prior, current, out) {
|
|
5331
|
+
const currentPaths = new Set(current.assets.map((a) => a.path));
|
|
5332
|
+
for (const a of prior.assets) {
|
|
5333
|
+
if (!currentPaths.has(a.path)) {
|
|
5334
|
+
out.push({
|
|
5335
|
+
kind: "breaking-asset",
|
|
5336
|
+
path: `theme-assets/${a.path}`,
|
|
5337
|
+
detail: `Asset "${a.path}" was present in the prior version and is now missing. Code that references it hardcoded will break.`
|
|
5338
|
+
});
|
|
5339
|
+
}
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
5342
|
+
function deepEqual(a, b) {
|
|
5343
|
+
if (a === b) return true;
|
|
5344
|
+
if (a === null || b === null) return false;
|
|
5345
|
+
if (typeof a !== typeof b) return false;
|
|
5346
|
+
if (typeof a !== "object") return false;
|
|
5347
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
5348
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
5349
|
+
if (a.length !== b.length) return false;
|
|
5350
|
+
for (let i = 0; i < a.length; i++) {
|
|
5351
|
+
if (!deepEqual(a[i], b[i])) return false;
|
|
5352
|
+
}
|
|
5353
|
+
return true;
|
|
5354
|
+
}
|
|
5355
|
+
const ak = Object.keys(a);
|
|
5356
|
+
const bk = Object.keys(b);
|
|
5357
|
+
if (ak.length !== bk.length) return false;
|
|
5358
|
+
for (const k of ak) {
|
|
5359
|
+
if (!deepEqual(
|
|
5360
|
+
a[k],
|
|
5361
|
+
b[k]
|
|
5362
|
+
))
|
|
5363
|
+
return false;
|
|
5364
|
+
}
|
|
5365
|
+
return true;
|
|
4761
5366
|
}
|
|
4762
5367
|
|
|
4763
5368
|
// src/commands/publish.ts
|
|
4764
5369
|
async function publishCommand(options) {
|
|
5370
|
+
const env = options.env ?? "dev";
|
|
4765
5371
|
logger.header("OneX Theme Publish");
|
|
4766
|
-
|
|
5372
|
+
logger.info(`Environment: ${env} (${getApiUrl(env)})`);
|
|
5373
|
+
logger.newLine();
|
|
5374
|
+
const tokens = await getValidTokens(env);
|
|
4767
5375
|
if (!tokens) {
|
|
4768
|
-
logger.error(
|
|
5376
|
+
logger.error(
|
|
5377
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
5378
|
+
);
|
|
4769
5379
|
process.exit(1);
|
|
4770
5380
|
}
|
|
4771
5381
|
logger.info(`Logged in as: ${tokens.user.email}`);
|
|
4772
5382
|
let themePath;
|
|
4773
5383
|
if (options.theme) {
|
|
4774
|
-
themePath =
|
|
5384
|
+
themePath = path11__default.default.resolve(options.theme);
|
|
4775
5385
|
} else {
|
|
4776
5386
|
const isThemeDir2 = [
|
|
4777
5387
|
"theme.config.ts",
|
|
4778
5388
|
"bundle-entry.ts",
|
|
4779
5389
|
"manifest.ts"
|
|
4780
|
-
].some((f) => fs__default.default.existsSync(
|
|
5390
|
+
].some((f) => fs__default.default.existsSync(path11__default.default.join(process.cwd(), f)));
|
|
4781
5391
|
if (isThemeDir2) {
|
|
4782
5392
|
themePath = process.cwd();
|
|
4783
5393
|
} else {
|
|
@@ -4787,13 +5397,13 @@ async function publishCommand(options) {
|
|
|
4787
5397
|
process.exit(1);
|
|
4788
5398
|
}
|
|
4789
5399
|
}
|
|
4790
|
-
const pkgPath =
|
|
5400
|
+
const pkgPath = path11__default.default.join(themePath, "package.json");
|
|
4791
5401
|
if (!fs__default.default.existsSync(pkgPath)) {
|
|
4792
5402
|
logger.error("No package.json found in theme directory");
|
|
4793
5403
|
process.exit(1);
|
|
4794
5404
|
}
|
|
4795
5405
|
const pkg = fs__default.default.readJsonSync(pkgPath);
|
|
4796
|
-
const themeId = pkg.name?.replace("@onex-themes/", "") ||
|
|
5406
|
+
const themeId = pkg.name?.replace("@onex-themes/", "") || path11__default.default.basename(themePath);
|
|
4797
5407
|
if (options.bump) {
|
|
4798
5408
|
const currentVersion = pkg.version || "1.0.0";
|
|
4799
5409
|
const newVersion = semver__default.default.inc(currentVersion, options.bump);
|
|
@@ -4816,56 +5426,63 @@ async function publishCommand(options) {
|
|
|
4816
5426
|
logger.info(`Theme: ${themeId}`);
|
|
4817
5427
|
logger.info(`Version: ${version2}`);
|
|
4818
5428
|
logger.newLine();
|
|
4819
|
-
const apiUrl = getApiUrl();
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
const
|
|
4842
|
-
if (!
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
5429
|
+
const apiUrl = getApiUrl(env);
|
|
5430
|
+
if (!options.dryRun) {
|
|
5431
|
+
logger.startSpinner("Registering theme...");
|
|
5432
|
+
try {
|
|
5433
|
+
const regResponse = await authenticatedFetch(
|
|
5434
|
+
`${apiUrl}/website-api/themes/register`,
|
|
5435
|
+
{
|
|
5436
|
+
method: "POST",
|
|
5437
|
+
body: JSON.stringify({
|
|
5438
|
+
themeId,
|
|
5439
|
+
name: pkg.displayName || themeId,
|
|
5440
|
+
description: pkg.description || "",
|
|
5441
|
+
email: tokens.user.email,
|
|
5442
|
+
author: typeof pkg.author === "string" ? pkg.author : pkg.author?.name || tokens.user.name || "",
|
|
5443
|
+
category: pkg.onex?.category || "MINIMAL",
|
|
5444
|
+
tags: pkg.keywords || [],
|
|
5445
|
+
thumbnail_url: pkg.onex?.thumbnail || ""
|
|
5446
|
+
})
|
|
5447
|
+
},
|
|
5448
|
+
env
|
|
5449
|
+
);
|
|
5450
|
+
const regData = await regResponse.json();
|
|
5451
|
+
const regBody = regData.statusCode ? regData.body : regData;
|
|
5452
|
+
if (!regResponse.ok) {
|
|
5453
|
+
const errMsg = regBody.error || regBody.message || "Registration failed";
|
|
5454
|
+
if (!errMsg.includes("already registered")) {
|
|
5455
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5456
|
+
logger.error(errMsg);
|
|
5457
|
+
process.exit(1);
|
|
5458
|
+
}
|
|
4846
5459
|
}
|
|
5460
|
+
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
5461
|
+
} catch (error) {
|
|
5462
|
+
logger.stopSpinner(false, "Registration failed");
|
|
5463
|
+
logger.error(
|
|
5464
|
+
error instanceof Error ? error.message : "Connection failed"
|
|
5465
|
+
);
|
|
5466
|
+
process.exit(1);
|
|
4847
5467
|
}
|
|
4848
|
-
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
4849
|
-
} catch (error) {
|
|
4850
|
-
logger.stopSpinner(false, "Registration failed");
|
|
4851
|
-
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4852
|
-
process.exit(1);
|
|
4853
5468
|
}
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
5469
|
+
if (!options.dryRun) {
|
|
5470
|
+
logger.startSpinner("Checking version availability...");
|
|
5471
|
+
try {
|
|
5472
|
+
const checkResponse = await authenticatedFetch(
|
|
5473
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/exists`,
|
|
5474
|
+
{ method: "GET" },
|
|
5475
|
+
env
|
|
5476
|
+
);
|
|
5477
|
+
const checkData = await checkResponse.json();
|
|
5478
|
+
const checkBody = checkData.statusCode ? checkData.body : checkData;
|
|
5479
|
+
if (checkBody.exists) {
|
|
5480
|
+
logger.stopSpinner(false, "Version already published");
|
|
5481
|
+
const patchVer = semver__default.default.inc(version2, "patch") || "?";
|
|
5482
|
+
const minorVer = semver__default.default.inc(version2, "minor") || "?";
|
|
5483
|
+
const majorVer = semver__default.default.inc(version2, "major") || "?";
|
|
5484
|
+
logger.error(
|
|
5485
|
+
`
|
|
4869
5486
|
Version ${version2} of "${themeId}" is already published and cannot be overwritten.
|
|
4870
5487
|
|
|
4871
5488
|
To publish a new version:
|
|
@@ -4876,12 +5493,16 @@ Or use the --bump flag:
|
|
|
4876
5493
|
onexthm publish --bump patch (${version2} -> ${patchVer})
|
|
4877
5494
|
onexthm publish --bump minor (${version2} -> ${minorVer})
|
|
4878
5495
|
onexthm publish --bump major (${version2} -> ${majorVer})`
|
|
5496
|
+
);
|
|
5497
|
+
process.exit(1);
|
|
5498
|
+
}
|
|
5499
|
+
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
5500
|
+
} catch (error) {
|
|
5501
|
+
logger.stopSpinner(
|
|
5502
|
+
true,
|
|
5503
|
+
"Version check skipped (endpoint not available)"
|
|
4879
5504
|
);
|
|
4880
|
-
process.exit(1);
|
|
4881
5505
|
}
|
|
4882
|
-
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
4883
|
-
} catch (error) {
|
|
4884
|
-
logger.stopSpinner(true, "Version check skipped (endpoint not available)");
|
|
4885
5506
|
}
|
|
4886
5507
|
logger.startSpinner("Building theme...");
|
|
4887
5508
|
try {
|
|
@@ -4898,7 +5519,19 @@ Or use the --bump flag:
|
|
|
4898
5519
|
logger.error(error instanceof Error ? error.message : "Build error");
|
|
4899
5520
|
process.exit(1);
|
|
4900
5521
|
}
|
|
4901
|
-
const distDir =
|
|
5522
|
+
const distDir = path11__default.default.join(themePath, "dist");
|
|
5523
|
+
const classification = await runSchemaDiffGate(
|
|
5524
|
+
themeId,
|
|
5525
|
+
distDir,
|
|
5526
|
+
env,
|
|
5527
|
+
options
|
|
5528
|
+
);
|
|
5529
|
+
if (options.dryRun) {
|
|
5530
|
+
const exitCode = classification?.highest === "breaking" || classification?.highest === "breaking-severe" || classification?.highest === "breaking-asset" ? 2 : 0;
|
|
5531
|
+
logger.newLine();
|
|
5532
|
+
logger.info(`Dry run complete (exit ${exitCode}). No files uploaded.`);
|
|
5533
|
+
process.exit(exitCode);
|
|
5534
|
+
}
|
|
4902
5535
|
let assetEntries = [];
|
|
4903
5536
|
try {
|
|
4904
5537
|
assetEntries = await scanThemeAssets(distDir);
|
|
@@ -4920,7 +5553,7 @@ Or use the --bump flag:
|
|
|
4920
5553
|
logger.startSpinner(`Uploading ${videoAssets.length} video(s)...`);
|
|
4921
5554
|
try {
|
|
4922
5555
|
for (const video of videoAssets) {
|
|
4923
|
-
const url = await uploadVideoMultipart(apiUrl, themeId, video);
|
|
5556
|
+
const url = await uploadVideoMultipart(apiUrl, themeId, video, env);
|
|
4924
5557
|
videoUrls[video.originalPath] = url;
|
|
4925
5558
|
}
|
|
4926
5559
|
logger.stopSpinner(true, `Uploaded ${videoAssets.length} video(s)`);
|
|
@@ -4935,7 +5568,7 @@ Or use the --bump flag:
|
|
|
4935
5568
|
for (const [originalPath, url] of Object.entries(videoUrls)) {
|
|
4936
5569
|
assetMap[originalPath] = url;
|
|
4937
5570
|
}
|
|
4938
|
-
const assetMapPath =
|
|
5571
|
+
const assetMapPath = path11__default.default.join(distDir, "asset-map.json");
|
|
4939
5572
|
await fs__default.default.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
|
|
4940
5573
|
} catch (error) {
|
|
4941
5574
|
logger.error(
|
|
@@ -4962,7 +5595,8 @@ Or use the --bump flag:
|
|
|
4962
5595
|
content_type: a.contentType
|
|
4963
5596
|
}))
|
|
4964
5597
|
})
|
|
4965
|
-
}
|
|
5598
|
+
},
|
|
5599
|
+
env
|
|
4966
5600
|
);
|
|
4967
5601
|
const pubData = await pubResponse.json();
|
|
4968
5602
|
const pubBody = pubData.statusCode ? pubData.body : pubData;
|
|
@@ -4988,6 +5622,12 @@ Or use the --bump flag:
|
|
|
4988
5622
|
}
|
|
4989
5623
|
if (assetUploads.length > 0) {
|
|
4990
5624
|
logger.startSpinner(`Uploading ${assetUploads.length} asset(s) to S3...`);
|
|
5625
|
+
if (assetUploads[0]) {
|
|
5626
|
+
logger.log(
|
|
5627
|
+
` [debug] sample presigned PUT URL: ${assetUploads[0].upload_url}`
|
|
5628
|
+
);
|
|
5629
|
+
logger.log(` [debug] sample s3_key: ${assetUploads[0].s3_key}`);
|
|
5630
|
+
}
|
|
4991
5631
|
const CONCURRENCY = 8;
|
|
4992
5632
|
const byHashedPath = new Map(regularAssets.map((a) => [a.hashedPath, a]));
|
|
4993
5633
|
const queue = [...assetUploads];
|
|
@@ -5014,6 +5654,13 @@ Or use the --bump flag:
|
|
|
5014
5654
|
body: buf
|
|
5015
5655
|
});
|
|
5016
5656
|
if (!res.ok) {
|
|
5657
|
+
if (failed === 0) {
|
|
5658
|
+
const errBody = await res.text().catch(() => "(unreadable)");
|
|
5659
|
+
logger.log(` [debug] PUT ${item.upload_url}`);
|
|
5660
|
+
logger.log(
|
|
5661
|
+
` [debug] response ${res.status} ${res.statusText}: ${errBody.slice(0, 500)}`
|
|
5662
|
+
);
|
|
5663
|
+
}
|
|
5017
5664
|
throw new Error(`HTTP ${res.status}`);
|
|
5018
5665
|
}
|
|
5019
5666
|
uploaded++;
|
|
@@ -5044,7 +5691,7 @@ Or use the --bump flag:
|
|
|
5044
5691
|
logger.error("Build the theme first: onexthm build");
|
|
5045
5692
|
process.exit(1);
|
|
5046
5693
|
}
|
|
5047
|
-
const bundleZipPath =
|
|
5694
|
+
const bundleZipPath = path11__default.default.join(themePath, "dist", "bundle.zip");
|
|
5048
5695
|
await createZip(distDir, bundleZipPath, [
|
|
5049
5696
|
"bundle.zip",
|
|
5050
5697
|
"source.zip",
|
|
@@ -5071,7 +5718,7 @@ Or use the --bump flag:
|
|
|
5071
5718
|
}
|
|
5072
5719
|
logger.startSpinner("Uploading source...");
|
|
5073
5720
|
try {
|
|
5074
|
-
const sourceZipPath =
|
|
5721
|
+
const sourceZipPath = path11__default.default.join(themePath, "dist", "source.zip");
|
|
5075
5722
|
await createZip(themePath, sourceZipPath, [
|
|
5076
5723
|
"node_modules",
|
|
5077
5724
|
"dist",
|
|
@@ -5098,7 +5745,8 @@ Or use the --bump flag:
|
|
|
5098
5745
|
try {
|
|
5099
5746
|
const confirmResponse = await authenticatedFetch(
|
|
5100
5747
|
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/confirm`,
|
|
5101
|
-
{ method: "POST" }
|
|
5748
|
+
{ method: "POST" },
|
|
5749
|
+
env
|
|
5102
5750
|
);
|
|
5103
5751
|
const confirmData = await confirmResponse.json();
|
|
5104
5752
|
const confirmBody = confirmData.statusCode ? confirmData.body : confirmData;
|
|
@@ -5144,9 +5792,9 @@ Or use the --bump flag:
|
|
|
5144
5792
|
}
|
|
5145
5793
|
logger.newLine();
|
|
5146
5794
|
logger.success(`\u2713 Theme "${themeId}" v${version2} published!`);
|
|
5147
|
-
await uploadThumbnail(apiUrl, themeId, themePath, distDir);
|
|
5795
|
+
await uploadThumbnail(apiUrl, themeId, themePath, distDir, env);
|
|
5148
5796
|
}
|
|
5149
|
-
async function uploadThumbnail(apiUrl, themeId, themePath, distDir) {
|
|
5797
|
+
async function uploadThumbnail(apiUrl, themeId, themePath, distDir, env = "dev") {
|
|
5150
5798
|
const THUMBNAIL_CANDIDATES = [
|
|
5151
5799
|
{ file: "thumbnail.png", mime: "image/png" },
|
|
5152
5800
|
{ file: "thumbnail.jpg", mime: "image/jpeg" },
|
|
@@ -5156,7 +5804,7 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir) {
|
|
|
5156
5804
|
let imageBase64 = null;
|
|
5157
5805
|
let mimeType = "image/png";
|
|
5158
5806
|
for (const { file, mime } of THUMBNAIL_CANDIDATES) {
|
|
5159
|
-
const candidate =
|
|
5807
|
+
const candidate = path11__default.default.join(themePath, file);
|
|
5160
5808
|
if (fs__default.default.existsSync(candidate)) {
|
|
5161
5809
|
const buf = fs__default.default.readFileSync(candidate);
|
|
5162
5810
|
imageBase64 = `data:${mime};base64,${buf.toString("base64")}`;
|
|
@@ -5181,9 +5829,19 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir) {
|
|
|
5181
5829
|
}
|
|
5182
5830
|
}
|
|
5183
5831
|
logger.startSpinner("Uploading thumbnail...");
|
|
5832
|
+
const imageUploadUrl = `${apiUrl}/media/images/upload`;
|
|
5833
|
+
const imageRequestBody = {
|
|
5834
|
+
prefix: `themes/${themeId}`,
|
|
5835
|
+
image: imageBase64 ? `${imageBase64.slice(0, 60)}... [${Math.round(imageBase64.length * 3 / 4 / 1024)} KB]` : null,
|
|
5836
|
+
name: "thumbnail.png"
|
|
5837
|
+
};
|
|
5838
|
+
logger.log(` \u2192 POST ${imageUploadUrl}`);
|
|
5839
|
+
logger.log(
|
|
5840
|
+
` \u2192 body: ${JSON.stringify({ ...imageRequestBody, image: imageBase64 ? `<base64 ${mimeType} truncated>` : null })}`
|
|
5841
|
+
);
|
|
5184
5842
|
try {
|
|
5185
5843
|
const uploadRes = await authenticatedFetch(
|
|
5186
|
-
|
|
5844
|
+
imageUploadUrl,
|
|
5187
5845
|
{
|
|
5188
5846
|
method: "POST",
|
|
5189
5847
|
body: JSON.stringify({
|
|
@@ -5191,30 +5849,56 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir) {
|
|
|
5191
5849
|
image: imageBase64,
|
|
5192
5850
|
name: "thumbnail.png"
|
|
5193
5851
|
})
|
|
5194
|
-
}
|
|
5852
|
+
},
|
|
5853
|
+
env
|
|
5195
5854
|
);
|
|
5196
|
-
|
|
5855
|
+
logger.log(` \u2190 HTTP ${uploadRes.status} ${uploadRes.statusText}`);
|
|
5856
|
+
const uploadRawText = await uploadRes.text();
|
|
5857
|
+
logger.log(` \u2190 raw response: ${uploadRawText.slice(0, 500)}`);
|
|
5858
|
+
let uploadData;
|
|
5859
|
+
try {
|
|
5860
|
+
uploadData = JSON.parse(uploadRawText);
|
|
5861
|
+
} catch {
|
|
5862
|
+
throw new Error(
|
|
5863
|
+
`Image upload returned non-JSON (HTTP ${uploadRes.status}): ${uploadRawText.slice(0, 200)}`
|
|
5864
|
+
);
|
|
5865
|
+
}
|
|
5197
5866
|
const uploadBody = uploadData.statusCode ? uploadData.body : uploadData;
|
|
5198
5867
|
if (!uploadRes.ok || !uploadBody.url) {
|
|
5199
|
-
throw new Error(
|
|
5868
|
+
throw new Error(
|
|
5869
|
+
`Image upload failed \u2014 HTTP ${uploadRes.status}: ${uploadBody.error || uploadBody.message || JSON.stringify(uploadBody).slice(0, 300)}`
|
|
5870
|
+
);
|
|
5200
5871
|
}
|
|
5872
|
+
const patchUrl = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}`;
|
|
5873
|
+
logger.log(` \u2192 PATCH ${patchUrl}`);
|
|
5201
5874
|
const patchRes = await authenticatedFetch(
|
|
5202
|
-
|
|
5875
|
+
patchUrl,
|
|
5203
5876
|
{
|
|
5204
5877
|
method: "PATCH",
|
|
5205
5878
|
body: JSON.stringify({ thumbnail_url: uploadBody.url })
|
|
5206
|
-
}
|
|
5879
|
+
},
|
|
5880
|
+
env
|
|
5207
5881
|
);
|
|
5882
|
+
logger.log(` \u2190 HTTP ${patchRes.status} ${patchRes.statusText}`);
|
|
5208
5883
|
if (!patchRes.ok) {
|
|
5209
|
-
const
|
|
5210
|
-
|
|
5211
|
-
|
|
5884
|
+
const patchRawText = await patchRes.text();
|
|
5885
|
+
logger.log(` \u2190 raw response: ${patchRawText.slice(0, 500)}`);
|
|
5886
|
+
let patchBody = {};
|
|
5887
|
+
try {
|
|
5888
|
+
patchBody = JSON.parse(patchRawText);
|
|
5889
|
+
} catch {
|
|
5890
|
+
}
|
|
5891
|
+
patchBody = patchBody.statusCode ? patchBody.body : patchBody;
|
|
5892
|
+
throw new Error(
|
|
5893
|
+
`Thumbnail patch failed \u2014 HTTP ${patchRes.status}: ${patchBody.error || patchBody.message || patchRawText.slice(0, 200)}`
|
|
5894
|
+
);
|
|
5212
5895
|
}
|
|
5213
5896
|
logger.stopSpinner(true, "Thumbnail set");
|
|
5214
5897
|
} catch (err) {
|
|
5215
|
-
logger.stopSpinner(false, "Thumbnail upload
|
|
5898
|
+
logger.stopSpinner(false, "Thumbnail upload failed");
|
|
5899
|
+
logger.error(err instanceof Error ? err.message : String(err));
|
|
5216
5900
|
logger.info(
|
|
5217
|
-
|
|
5901
|
+
"Theme published successfully. Thumbnail can be updated later."
|
|
5218
5902
|
);
|
|
5219
5903
|
}
|
|
5220
5904
|
}
|
|
@@ -5222,7 +5906,7 @@ async function screenshotHomePage(themePath, distDir) {
|
|
|
5222
5906
|
const { compilePreviewRuntime: compilePreviewRuntime2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
5223
5907
|
const { createDevServer: createDevServer2 } = await Promise.resolve().then(() => (init_dev_server(), dev_server_exports));
|
|
5224
5908
|
const previewRuntimePath = await compilePreviewRuntime2(themePath);
|
|
5225
|
-
const themeName =
|
|
5909
|
+
const themeName = path11__default.default.basename(themePath);
|
|
5226
5910
|
const port = await findFreePort(4500);
|
|
5227
5911
|
const server = createDevServer2({
|
|
5228
5912
|
port,
|
|
@@ -5278,25 +5962,40 @@ async function findFreePort(start) {
|
|
|
5278
5962
|
srv.on("error", () => resolve(findFreePort(start + 1)));
|
|
5279
5963
|
});
|
|
5280
5964
|
}
|
|
5281
|
-
async function uploadVideoMultipart(apiUrl, themeId, video) {
|
|
5282
|
-
const fileName =
|
|
5965
|
+
async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
|
|
5966
|
+
const fileName = path11__default.default.basename(video.originalPath);
|
|
5967
|
+
const videoInitUrl = `${apiUrl}/media/videos/multipart/init`;
|
|
5968
|
+
const videoInitBody = {
|
|
5969
|
+
file_name: fileName,
|
|
5970
|
+
content_type: video.contentType,
|
|
5971
|
+
file_size: video.size,
|
|
5972
|
+
prefix: `themes/${themeId}/assets`
|
|
5973
|
+
};
|
|
5974
|
+
logger.log(` \u2192 POST ${videoInitUrl}`);
|
|
5975
|
+
logger.log(` \u2192 body: ${JSON.stringify(videoInitBody)}`);
|
|
5283
5976
|
const initRes = await authenticatedFetch(
|
|
5284
|
-
|
|
5977
|
+
videoInitUrl,
|
|
5285
5978
|
{
|
|
5286
5979
|
method: "POST",
|
|
5287
|
-
body: JSON.stringify(
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
file_size: video.size,
|
|
5291
|
-
prefix: `themes/${themeId}/assets`
|
|
5292
|
-
})
|
|
5293
|
-
}
|
|
5980
|
+
body: JSON.stringify(videoInitBody)
|
|
5981
|
+
},
|
|
5982
|
+
env
|
|
5294
5983
|
);
|
|
5295
|
-
|
|
5984
|
+
logger.log(` \u2190 HTTP ${initRes.status} ${initRes.statusText}`);
|
|
5985
|
+
const initRawText = await initRes.text();
|
|
5986
|
+
logger.log(` \u2190 raw response: ${initRawText.slice(0, 500)}`);
|
|
5987
|
+
let initData;
|
|
5988
|
+
try {
|
|
5989
|
+
initData = JSON.parse(initRawText);
|
|
5990
|
+
} catch {
|
|
5991
|
+
throw new Error(
|
|
5992
|
+
`Video init returned non-JSON (HTTP ${initRes.status}): ${initRawText.slice(0, 200)}`
|
|
5993
|
+
);
|
|
5994
|
+
}
|
|
5296
5995
|
const initBody = initData.statusCode ? initData.body : initData;
|
|
5297
5996
|
if (!initRes.ok || !initBody.upload_id) {
|
|
5298
5997
|
throw new Error(
|
|
5299
|
-
`Init multipart failed for ${fileName}: ${initBody.error ||
|
|
5998
|
+
`Init multipart failed for ${fileName} \u2014 HTTP ${initRes.status}: ${initBody.error || initBody.message || JSON.stringify(initBody).slice(0, 300)}`
|
|
5300
5999
|
);
|
|
5301
6000
|
}
|
|
5302
6001
|
const { upload_id, file_key, chunk_size, chunk_urls } = initBody;
|
|
@@ -5331,25 +6030,47 @@ async function uploadVideoMultipart(apiUrl, themeId, video) {
|
|
|
5331
6030
|
)
|
|
5332
6031
|
);
|
|
5333
6032
|
parts.sort((a, b) => a.part_number - b.part_number);
|
|
6033
|
+
const videoCompleteUrl = `${apiUrl}/media/videos/multipart/complete`;
|
|
6034
|
+
logger.log(` \u2192 POST ${videoCompleteUrl}`);
|
|
6035
|
+
logger.log(
|
|
6036
|
+
` \u2192 body: ${JSON.stringify({ upload_id, file_key, parts: `[${parts.length} parts]` })}`
|
|
6037
|
+
);
|
|
5334
6038
|
const completeRes = await authenticatedFetch(
|
|
5335
|
-
|
|
6039
|
+
videoCompleteUrl,
|
|
5336
6040
|
{
|
|
5337
6041
|
method: "POST",
|
|
5338
6042
|
body: JSON.stringify({ upload_id, file_key, parts })
|
|
5339
|
-
}
|
|
6043
|
+
},
|
|
6044
|
+
env
|
|
5340
6045
|
);
|
|
5341
|
-
|
|
6046
|
+
logger.log(` \u2190 HTTP ${completeRes.status} ${completeRes.statusText}`);
|
|
6047
|
+
const completeRawText = await completeRes.text();
|
|
6048
|
+
logger.log(` \u2190 raw response: ${completeRawText.slice(0, 500)}`);
|
|
6049
|
+
let completeData;
|
|
6050
|
+
try {
|
|
6051
|
+
completeData = JSON.parse(completeRawText);
|
|
6052
|
+
} catch {
|
|
6053
|
+
throw new Error(
|
|
6054
|
+
`Video complete returned non-JSON (HTTP ${completeRes.status}): ${completeRawText.slice(0, 200)}`
|
|
6055
|
+
);
|
|
6056
|
+
}
|
|
5342
6057
|
const completeBody = completeData.statusCode ? completeData.body : completeData;
|
|
5343
6058
|
if (!completeRes.ok || !completeBody.url) {
|
|
5344
6059
|
try {
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
6060
|
+
const abortUrl = `${apiUrl}/media/videos/multipart/abort`;
|
|
6061
|
+
logger.log(` \u2192 POST ${abortUrl} (cleanup)`);
|
|
6062
|
+
await authenticatedFetch(
|
|
6063
|
+
abortUrl,
|
|
6064
|
+
{
|
|
6065
|
+
method: "POST",
|
|
6066
|
+
body: JSON.stringify({ upload_id, file_key })
|
|
6067
|
+
},
|
|
6068
|
+
env
|
|
6069
|
+
);
|
|
5349
6070
|
} catch {
|
|
5350
6071
|
}
|
|
5351
6072
|
throw new Error(
|
|
5352
|
-
`Complete multipart failed for ${fileName}: ${completeBody.error ||
|
|
6073
|
+
`Complete multipart failed for ${fileName} \u2014 HTTP ${completeRes.status}: ${completeBody.error || completeBody.message || JSON.stringify(completeBody).slice(0, 300)}`
|
|
5353
6074
|
);
|
|
5354
6075
|
}
|
|
5355
6076
|
return completeBody.url;
|
|
@@ -5371,6 +6092,91 @@ async function createZip(sourceDir, outputPath, exclude) {
|
|
|
5371
6092
|
archive.finalize();
|
|
5372
6093
|
});
|
|
5373
6094
|
}
|
|
6095
|
+
async function runSchemaDiffGate(themeId, distDir, env, options) {
|
|
6096
|
+
logger.startSpinner("Fetching prior version for diff...");
|
|
6097
|
+
const { result: prior, reason } = await fetchPriorGateManifests(themeId, env);
|
|
6098
|
+
if (!prior) {
|
|
6099
|
+
if (reason === "no-prior") {
|
|
6100
|
+
logger.stopSpinner(true, "First publish \u2014 no prior version to diff");
|
|
6101
|
+
} else {
|
|
6102
|
+
logger.stopSpinner(true, `Gate skipped (${reason})`);
|
|
6103
|
+
}
|
|
6104
|
+
return null;
|
|
6105
|
+
}
|
|
6106
|
+
logger.stopSpinner(true, `Fetched prior version ${prior.version}`);
|
|
6107
|
+
let currentSchemas;
|
|
6108
|
+
let currentAssets;
|
|
6109
|
+
try {
|
|
6110
|
+
currentSchemas = JSON.parse(
|
|
6111
|
+
await fs__default.default.readFile(path11__default.default.join(distDir, "schemas.json"), "utf-8")
|
|
6112
|
+
);
|
|
6113
|
+
} catch (err) {
|
|
6114
|
+
logger.warning(
|
|
6115
|
+
`Gate skipped: dist/schemas.json missing or unreadable (${err instanceof Error ? err.message : "unknown"})`
|
|
6116
|
+
);
|
|
6117
|
+
return null;
|
|
6118
|
+
}
|
|
6119
|
+
try {
|
|
6120
|
+
currentAssets = JSON.parse(
|
|
6121
|
+
await fs__default.default.readFile(path11__default.default.join(distDir, "asset-manifest.json"), "utf-8")
|
|
6122
|
+
);
|
|
6123
|
+
} catch {
|
|
6124
|
+
currentAssets = { manifestVersion: 1, assets: [] };
|
|
6125
|
+
}
|
|
6126
|
+
const changes = diffManifests(
|
|
6127
|
+
{ schemas: prior.schemas, assets: prior.assets },
|
|
6128
|
+
{ schemas: currentSchemas, assets: currentAssets }
|
|
6129
|
+
);
|
|
6130
|
+
const classification = classify(changes);
|
|
6131
|
+
printGateReport(prior.version, classification);
|
|
6132
|
+
if (options.dryRun) return classification;
|
|
6133
|
+
const isBreaking = classification.highest === "breaking" || classification.highest === "breaking-severe" || classification.highest === "breaking-asset";
|
|
6134
|
+
if (isBreaking && !options.force) {
|
|
6135
|
+
logger.error(
|
|
6136
|
+
"\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)."
|
|
6137
|
+
);
|
|
6138
|
+
process.exit(1);
|
|
6139
|
+
}
|
|
6140
|
+
if (classification.highest === "defaults-only" && !options.confirmDefaults) {
|
|
6141
|
+
logger.error(
|
|
6142
|
+
"\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."
|
|
6143
|
+
);
|
|
6144
|
+
process.exit(1);
|
|
6145
|
+
}
|
|
6146
|
+
return classification;
|
|
6147
|
+
}
|
|
6148
|
+
function printGateReport(priorVersion, classification) {
|
|
6149
|
+
logger.newLine();
|
|
6150
|
+
logger.info(`Schema diff vs. v${priorVersion}:`);
|
|
6151
|
+
if (classification.changes.length === 0) {
|
|
6152
|
+
logger.log(" \u2713 Safe \u2014 no schema changes detected");
|
|
6153
|
+
return;
|
|
6154
|
+
}
|
|
6155
|
+
for (const change of classification.changes) {
|
|
6156
|
+
const icon = iconFor(change.kind);
|
|
6157
|
+
logger.log(` ${icon} [${change.kind}] ${change.path} \u2014 ${change.detail}`);
|
|
6158
|
+
}
|
|
6159
|
+
logger.log(
|
|
6160
|
+
`
|
|
6161
|
+
\u2192 Classification: ${classification.highest}. Suggested bump: ${classification.bump}.`
|
|
6162
|
+
);
|
|
6163
|
+
}
|
|
6164
|
+
function iconFor(kind) {
|
|
6165
|
+
switch (kind) {
|
|
6166
|
+
case "safe":
|
|
6167
|
+
case "safe-rename":
|
|
6168
|
+
return "\u2713";
|
|
6169
|
+
case "additive":
|
|
6170
|
+
return "+";
|
|
6171
|
+
case "defaults-only":
|
|
6172
|
+
return "\u26A0";
|
|
6173
|
+
case "breaking":
|
|
6174
|
+
case "breaking-asset":
|
|
6175
|
+
return "\u2717";
|
|
6176
|
+
case "breaking-severe":
|
|
6177
|
+
return "\u2717\u2717";
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
5374
6180
|
|
|
5375
6181
|
// src/commands/mcp.ts
|
|
5376
6182
|
init_logger();
|
|
@@ -5382,18 +6188,18 @@ var AI_CONTEXT_FILES = [
|
|
|
5382
6188
|
".mcp.json"
|
|
5383
6189
|
];
|
|
5384
6190
|
function resolveTargetDir(opts) {
|
|
5385
|
-
return
|
|
6191
|
+
return path11__default.default.resolve(opts.cwd ?? process.cwd());
|
|
5386
6192
|
}
|
|
5387
6193
|
function resolveDefaultTemplateDir() {
|
|
5388
|
-
return
|
|
6194
|
+
return path11__default.default.join(getTemplatesDir(), "default");
|
|
5389
6195
|
}
|
|
5390
6196
|
function isThemeDir(dir) {
|
|
5391
|
-
return fs__default.default.existsSync(
|
|
6197
|
+
return fs__default.default.existsSync(path11__default.default.join(dir, "theme.config.ts")) || fs__default.default.existsSync(path11__default.default.join(dir, "theme.config.js"));
|
|
5392
6198
|
}
|
|
5393
6199
|
function inspectFiles(templateDir, targetDir) {
|
|
5394
6200
|
return AI_CONTEXT_FILES.map((name) => {
|
|
5395
|
-
const templatePath =
|
|
5396
|
-
const targetPath =
|
|
6201
|
+
const templatePath = path11__default.default.join(templateDir, name);
|
|
6202
|
+
const targetPath = path11__default.default.join(targetDir, name);
|
|
5397
6203
|
const exists = fs__default.default.existsSync(targetPath);
|
|
5398
6204
|
let identical = false;
|
|
5399
6205
|
if (exists && fs__default.default.existsSync(templatePath)) {
|
|
@@ -5536,7 +6342,7 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5536
6342
|
return;
|
|
5537
6343
|
}
|
|
5538
6344
|
logger.success("theme.config.ts present");
|
|
5539
|
-
const mcpJsonPath =
|
|
6345
|
+
const mcpJsonPath = path11__default.default.join(targetDir, ".mcp.json");
|
|
5540
6346
|
if (!fs__default.default.existsSync(mcpJsonPath)) {
|
|
5541
6347
|
logger.error(".mcp.json missing \u2014 run `onexthm mcp setup`");
|
|
5542
6348
|
} else {
|
|
@@ -5574,7 +6380,7 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5574
6380
|
logger.success(`${s.name} up to date`);
|
|
5575
6381
|
}
|
|
5576
6382
|
}
|
|
5577
|
-
const registryPath =
|
|
6383
|
+
const registryPath = path11__default.default.join(targetDir, "sections-registry.ts");
|
|
5578
6384
|
if (fs__default.default.existsSync(registryPath)) {
|
|
5579
6385
|
logger.success("sections-registry.ts present");
|
|
5580
6386
|
} else {
|
|
@@ -5586,22 +6392,22 @@ async function mcpDoctorCommand(options = {}) {
|
|
|
5586
6392
|
|
|
5587
6393
|
// src/cli.ts
|
|
5588
6394
|
dotenv__default.default.config({
|
|
5589
|
-
path:
|
|
6395
|
+
path: path11__default.default.join(process.cwd(), ".env.local"),
|
|
5590
6396
|
override: true
|
|
5591
6397
|
});
|
|
5592
|
-
dotenv__default.default.config({ path:
|
|
6398
|
+
dotenv__default.default.config({ path: path11__default.default.join(process.cwd(), ".env") });
|
|
5593
6399
|
try {
|
|
5594
6400
|
const projectRoot = getProjectRoot();
|
|
5595
|
-
if (
|
|
6401
|
+
if (path11__default.default.resolve(projectRoot) !== path11__default.default.resolve(process.cwd())) {
|
|
5596
6402
|
dotenv__default.default.config({
|
|
5597
|
-
path:
|
|
6403
|
+
path: path11__default.default.join(projectRoot, ".env.local")
|
|
5598
6404
|
});
|
|
5599
|
-
dotenv__default.default.config({ path:
|
|
6405
|
+
dotenv__default.default.config({ path: path11__default.default.join(projectRoot, ".env") });
|
|
5600
6406
|
}
|
|
5601
6407
|
} catch {
|
|
5602
6408
|
}
|
|
5603
6409
|
dotenv__default.default.config({
|
|
5604
|
-
path:
|
|
6410
|
+
path: path11__default.default.join(os__default.default.homedir(), ".onexthm", ".env"),
|
|
5605
6411
|
quiet: true
|
|
5606
6412
|
});
|
|
5607
6413
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
@@ -5612,7 +6418,11 @@ program.command("init").description("Create a new OneX theme project").argument(
|
|
|
5612
6418
|
"-t, --template <template>",
|
|
5613
6419
|
"Template to use (default, minimal)",
|
|
5614
6420
|
"default"
|
|
5615
|
-
).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").
|
|
6421
|
+
).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").option(
|
|
6422
|
+
"--env <env>",
|
|
6423
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6424
|
+
"dev"
|
|
6425
|
+
).action(initCommand);
|
|
5616
6426
|
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(
|
|
5617
6427
|
"-c, --category <category>",
|
|
5618
6428
|
"Section category (headers, content, footers)"
|
|
@@ -5639,16 +6449,36 @@ program.command("download").description("Download a published theme via the webs
|
|
|
5639
6449
|
"-v, --version <version>",
|
|
5640
6450
|
"Theme version (default: latest)",
|
|
5641
6451
|
"latest"
|
|
5642
|
-
).option(
|
|
6452
|
+
).option(
|
|
6453
|
+
"--env <env>",
|
|
6454
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6455
|
+
"dev"
|
|
6456
|
+
).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
|
|
5643
6457
|
program.command("clone").description("Clone theme source code via the website-api").argument("<theme-name>", "Theme to clone").option(
|
|
5644
6458
|
"-v, --version <version>",
|
|
5645
6459
|
"Theme version (default: latest)",
|
|
5646
6460
|
"latest"
|
|
5647
|
-
).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").option(
|
|
6461
|
+
).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").option(
|
|
6462
|
+
"--env <env>",
|
|
6463
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6464
|
+
"dev"
|
|
6465
|
+
).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
5648
6466
|
program.command("config").description("Configure OneX CLI credentials (AWS, API keys)").action(configCommand);
|
|
5649
|
-
program.command("login").description("Login to OneX platform").
|
|
5650
|
-
|
|
5651
|
-
|
|
6467
|
+
program.command("login").description("Login to OneX platform").option(
|
|
6468
|
+
"--env <env>",
|
|
6469
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6470
|
+
"dev"
|
|
6471
|
+
).action(loginCommand);
|
|
6472
|
+
program.command("logout").description("Logout from OneX platform").option(
|
|
6473
|
+
"--env <env>",
|
|
6474
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6475
|
+
"dev"
|
|
6476
|
+
).action(logoutCommand);
|
|
6477
|
+
program.command("whoami").description("Show current logged-in developer").option(
|
|
6478
|
+
"--env <env>",
|
|
6479
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6480
|
+
"dev"
|
|
6481
|
+
).action(whoamiCommand);
|
|
5652
6482
|
var mcpCmd = program.command("mcp").description("Manage MCP server registration and AI-context files");
|
|
5653
6483
|
mcpCmd.command("setup").description(
|
|
5654
6484
|
"Install .mcp.json + CLAUDE.md + AGENTS.md + .cursorrules into the current theme"
|
|
@@ -5660,6 +6490,19 @@ mcpCmd.command("doctor").description("Diagnose MCP setup in the current theme di
|
|
|
5660
6490
|
program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").option(
|
|
5661
6491
|
"--bump <type>",
|
|
5662
6492
|
"Auto-bump version before publish (patch|minor|major)"
|
|
6493
|
+
).option(
|
|
6494
|
+
"--env <env>",
|
|
6495
|
+
"Target environment: dev, staging, or prod (default: dev)",
|
|
6496
|
+
"dev"
|
|
6497
|
+
).option(
|
|
6498
|
+
"--dry-run",
|
|
6499
|
+
"Build locally and print the schema-diff classification without publishing"
|
|
6500
|
+
).option(
|
|
6501
|
+
"--confirm-defaults",
|
|
6502
|
+
"Confirm that changed section/block defaults should propagate to live sites"
|
|
6503
|
+
).option(
|
|
6504
|
+
"--force",
|
|
6505
|
+
"Publish even when the diff gate detects a breaking change"
|
|
5663
6506
|
).action(publishCommand);
|
|
5664
6507
|
program.configureOutput({
|
|
5665
6508
|
writeErr: (str) => process.stderr.write(chalk4__default.default.red(str))
|