@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/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import chalk4 from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import
|
|
4
|
-
import path8 from 'path';
|
|
5
|
-
import fs7 from 'fs/promises';
|
|
6
|
-
import crypto from 'crypto';
|
|
3
|
+
import path10 from 'path';
|
|
7
4
|
import { glob } from 'glob';
|
|
5
|
+
import fs from 'fs-extra';
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import * as esbuild from 'esbuild';
|
|
8
|
+
import fs8 from 'fs/promises';
|
|
8
9
|
import { createRequire } from 'module';
|
|
9
10
|
import fs3 from 'fs';
|
|
10
11
|
import { execSync, spawn } from 'child_process';
|
|
11
12
|
import inquirer from 'inquirer';
|
|
12
|
-
import fs from 'fs-extra';
|
|
13
13
|
import ejs from 'ejs';
|
|
14
14
|
import os from 'os';
|
|
15
15
|
import AdmZip from 'adm-zip';
|
|
@@ -85,6 +85,187 @@ var init_logger = __esm({
|
|
|
85
85
|
logger = new Logger();
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
+
function sortedCopy(value) {
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
return value.map((v) => sortedCopy(v));
|
|
91
|
+
}
|
|
92
|
+
if (value && typeof value === "object") {
|
|
93
|
+
const sorted = {};
|
|
94
|
+
for (const key of Object.keys(value).sort()) {
|
|
95
|
+
sorted[key] = sortedCopy(value[key]);
|
|
96
|
+
}
|
|
97
|
+
return sorted;
|
|
98
|
+
}
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
function normalizeField(raw) {
|
|
102
|
+
const out = {
|
|
103
|
+
id: String(raw.id),
|
|
104
|
+
type: String(raw.type)
|
|
105
|
+
};
|
|
106
|
+
if (raw.required === true) out.required = true;
|
|
107
|
+
if (raw.default !== void 0) out.default = raw.default;
|
|
108
|
+
if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
|
|
109
|
+
out.aliases = [...raw.aliases].map(String).sort();
|
|
110
|
+
}
|
|
111
|
+
if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
|
|
112
|
+
if (typeof raw.min === "number") out.min = raw.min;
|
|
113
|
+
if (typeof raw.max === "number") out.max = raw.max;
|
|
114
|
+
if (typeof raw.step === "number") out.step = raw.step;
|
|
115
|
+
if (Array.isArray(raw.accept)) {
|
|
116
|
+
out.accept = [...raw.accept].map(String).sort();
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(raw.options)) {
|
|
119
|
+
out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
function normalizeBlock(raw) {
|
|
124
|
+
return {
|
|
125
|
+
type: String(raw.type),
|
|
126
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
127
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
128
|
+
...typeof raw.limit === "number" ? { limit: raw.limit } : {},
|
|
129
|
+
...typeof raw.min === "number" ? { min: raw.min } : {},
|
|
130
|
+
...raw.sortable === true ? { sortable: true } : {},
|
|
131
|
+
...raw.baseType ? { baseType: String(raw.baseType) } : {}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function normalizeTemplate(raw) {
|
|
135
|
+
const out = { id: String(raw.id) };
|
|
136
|
+
if (raw.isDefault === true) out.isDefault = true;
|
|
137
|
+
if (Array.isArray(raw.settings)) {
|
|
138
|
+
out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
|
|
139
|
+
}
|
|
140
|
+
if (raw.defaults && typeof raw.defaults === "object") {
|
|
141
|
+
out.defaults = sortedCopy(raw.defaults);
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
function sortFieldsById(a, b) {
|
|
146
|
+
return a.id.localeCompare(b.id);
|
|
147
|
+
}
|
|
148
|
+
function sortByType(a, b) {
|
|
149
|
+
return a.type.localeCompare(b.type);
|
|
150
|
+
}
|
|
151
|
+
function normalizeSection(raw) {
|
|
152
|
+
return {
|
|
153
|
+
type: String(raw.type),
|
|
154
|
+
settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
|
|
155
|
+
defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
|
|
156
|
+
blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
|
|
157
|
+
templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
|
|
158
|
+
dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
|
|
159
|
+
...raw.global === true ? { global: true } : {},
|
|
160
|
+
...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
async function extractSchemas(themePath) {
|
|
164
|
+
const { createJiti } = await import('jiti');
|
|
165
|
+
const jiti = createJiti(import.meta.url);
|
|
166
|
+
const schemaFiles = await glob("sections/**/*.schema.ts", { cwd: themePath });
|
|
167
|
+
const sections = {};
|
|
168
|
+
for (const file of schemaFiles) {
|
|
169
|
+
try {
|
|
170
|
+
const mod = await jiti.import(path10.join(themePath, file));
|
|
171
|
+
const exports$1 = mod;
|
|
172
|
+
for (const value of Object.values(exports$1)) {
|
|
173
|
+
if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
|
|
174
|
+
const section = normalizeSection(value);
|
|
175
|
+
sections[section.type] = section;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const manifest = {
|
|
182
|
+
manifestVersion: 1,
|
|
183
|
+
sections: {}
|
|
184
|
+
};
|
|
185
|
+
for (const type of Object.keys(sections).sort()) {
|
|
186
|
+
manifest.sections[type] = sections[type];
|
|
187
|
+
}
|
|
188
|
+
return manifest;
|
|
189
|
+
}
|
|
190
|
+
function serializeManifest(manifest) {
|
|
191
|
+
return JSON.stringify(sortedCopy(manifest), null, 2);
|
|
192
|
+
}
|
|
193
|
+
var init_extract_schemas = __esm({
|
|
194
|
+
"src/utils/extract-schemas.ts"() {
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
function mimeFor(filename) {
|
|
198
|
+
const ext = path10.extname(filename).toLowerCase();
|
|
199
|
+
return MIME_MAP[ext] || "application/octet-stream";
|
|
200
|
+
}
|
|
201
|
+
async function sha256Prefix(absPath, len) {
|
|
202
|
+
const buf = await fs.readFile(absPath);
|
|
203
|
+
return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
|
|
204
|
+
}
|
|
205
|
+
function insertHashIntoName(relPath, hash) {
|
|
206
|
+
const dir = path10.posix.dirname(relPath);
|
|
207
|
+
const base = path10.posix.basename(relPath);
|
|
208
|
+
const ext = path10.posix.extname(base);
|
|
209
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
210
|
+
const hashed = `${stem}-${hash}${ext}`;
|
|
211
|
+
return dir === "." ? hashed : `${dir}/${hashed}`;
|
|
212
|
+
}
|
|
213
|
+
async function scanThemeAssets(distDir) {
|
|
214
|
+
const assetsDir = path10.join(distDir, "theme-assets");
|
|
215
|
+
if (!await fs.pathExists(assetsDir)) return [];
|
|
216
|
+
const files = await glob("**/*", {
|
|
217
|
+
cwd: assetsDir,
|
|
218
|
+
nodir: true,
|
|
219
|
+
dot: false
|
|
220
|
+
});
|
|
221
|
+
const results = [];
|
|
222
|
+
for (const rel of files) {
|
|
223
|
+
const absPath = path10.join(assetsDir, rel);
|
|
224
|
+
const stat = await fs.stat(absPath);
|
|
225
|
+
if (!stat.isFile()) continue;
|
|
226
|
+
const originalPath = rel.split(path10.sep).join("/");
|
|
227
|
+
const hash = await sha256Prefix(absPath, HASH_LEN);
|
|
228
|
+
const hashedPath = insertHashIntoName(originalPath, hash);
|
|
229
|
+
const contentType = mimeFor(rel);
|
|
230
|
+
results.push({
|
|
231
|
+
originalPath,
|
|
232
|
+
hashedPath,
|
|
233
|
+
hash,
|
|
234
|
+
size: stat.size,
|
|
235
|
+
contentType,
|
|
236
|
+
absPath
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
|
|
240
|
+
return results;
|
|
241
|
+
}
|
|
242
|
+
var MIME_MAP, HASH_LEN;
|
|
243
|
+
var init_scan_theme_assets = __esm({
|
|
244
|
+
"src/utils/scan-theme-assets.ts"() {
|
|
245
|
+
MIME_MAP = {
|
|
246
|
+
".png": "image/png",
|
|
247
|
+
".jpg": "image/jpeg",
|
|
248
|
+
".jpeg": "image/jpeg",
|
|
249
|
+
".gif": "image/gif",
|
|
250
|
+
".webp": "image/webp",
|
|
251
|
+
".avif": "image/avif",
|
|
252
|
+
".svg": "image/svg+xml",
|
|
253
|
+
".ico": "image/x-icon",
|
|
254
|
+
".bmp": "image/bmp",
|
|
255
|
+
".woff": "font/woff",
|
|
256
|
+
".woff2": "font/woff2",
|
|
257
|
+
".ttf": "font/ttf",
|
|
258
|
+
".otf": "font/otf",
|
|
259
|
+
".eot": "application/vnd.ms-fontobject",
|
|
260
|
+
".mp4": "video/mp4",
|
|
261
|
+
".webm": "video/webm",
|
|
262
|
+
".mov": "video/quicktime",
|
|
263
|
+
".ogg": "video/ogg",
|
|
264
|
+
".json": "application/json"
|
|
265
|
+
};
|
|
266
|
+
HASH_LEN = 8;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
88
269
|
|
|
89
270
|
// src/utils/compile-theme.ts
|
|
90
271
|
var compile_theme_exports = {};
|
|
@@ -100,8 +281,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
100
281
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
101
282
|
const tailwindConfig = {
|
|
102
283
|
content: [
|
|
103
|
-
|
|
104
|
-
|
|
284
|
+
path10.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
285
|
+
path10.join(themePath, "components/**/*.{ts,tsx}")
|
|
105
286
|
],
|
|
106
287
|
theme: { extend: {} },
|
|
107
288
|
plugins: []
|
|
@@ -111,7 +292,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
111
292
|
inputCSS,
|
|
112
293
|
{ from: void 0 }
|
|
113
294
|
);
|
|
114
|
-
await
|
|
295
|
+
await fs8.writeFile(path10.join(outDir, "bundle.css"), result.css);
|
|
115
296
|
logger.info("Generated bundle.css");
|
|
116
297
|
} catch (err) {
|
|
117
298
|
logger.warning(
|
|
@@ -122,12 +303,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
122
303
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
123
304
|
let dir = startDir;
|
|
124
305
|
while (true) {
|
|
125
|
-
const candidate =
|
|
306
|
+
const candidate = path10.join(dir, "node_modules", relativePath);
|
|
126
307
|
try {
|
|
127
|
-
await
|
|
308
|
+
await fs8.access(candidate);
|
|
128
309
|
return candidate;
|
|
129
310
|
} catch {
|
|
130
|
-
const parent =
|
|
311
|
+
const parent = path10.dirname(dir);
|
|
131
312
|
if (parent === dir) break;
|
|
132
313
|
dir = parent;
|
|
133
314
|
}
|
|
@@ -151,7 +332,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
151
332
|
});
|
|
152
333
|
for (const file of sourceFiles) {
|
|
153
334
|
try {
|
|
154
|
-
const content = await
|
|
335
|
+
const content = await fs8.readFile(path10.join(sourceDir, file), "utf-8");
|
|
155
336
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
156
337
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
157
338
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -205,17 +386,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
205
386
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
206
387
|
let distPath = await resolveNodeModulesFile(
|
|
207
388
|
themePath,
|
|
208
|
-
|
|
389
|
+
path10.join("@onexapis", "core", "dist", distFileName)
|
|
209
390
|
);
|
|
210
391
|
if (!distPath) {
|
|
211
392
|
distPath = await resolveNodeModulesFile(
|
|
212
393
|
__dirname,
|
|
213
|
-
|
|
394
|
+
path10.join("@onexapis", "core", "dist", distFileName)
|
|
214
395
|
);
|
|
215
396
|
}
|
|
216
397
|
try {
|
|
217
398
|
if (!distPath) throw new Error("not found");
|
|
218
|
-
const distContent = await
|
|
399
|
+
const distContent = await fs8.readFile(distPath, "utf-8");
|
|
219
400
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
220
401
|
for (const m of exportMatches) {
|
|
221
402
|
const names = m[1].split(",").map((n) => {
|
|
@@ -444,7 +625,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
444
625
|
const pages = {};
|
|
445
626
|
for (const ext of [".ts", ".js"]) {
|
|
446
627
|
try {
|
|
447
|
-
const mod = await jiti.import(
|
|
628
|
+
const mod = await jiti.import(path10.join(themePath, `theme.config${ext}`));
|
|
448
629
|
themeConfig = mod.default || mod;
|
|
449
630
|
break;
|
|
450
631
|
} catch {
|
|
@@ -452,20 +633,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
452
633
|
}
|
|
453
634
|
for (const ext of [".ts", ".js"]) {
|
|
454
635
|
try {
|
|
455
|
-
const mod = await jiti.import(
|
|
636
|
+
const mod = await jiti.import(path10.join(themePath, `theme.layout${ext}`));
|
|
456
637
|
layoutConfig = mod.default || mod;
|
|
457
638
|
break;
|
|
458
639
|
} catch {
|
|
459
640
|
}
|
|
460
641
|
}
|
|
461
642
|
const schemas = {};
|
|
462
|
-
const sectionsDir =
|
|
643
|
+
const sectionsDir = path10.join(themePath, "sections");
|
|
463
644
|
try {
|
|
464
|
-
const sectionDirs = await
|
|
645
|
+
const sectionDirs = await fs8.readdir(sectionsDir);
|
|
465
646
|
for (const dir of sectionDirs) {
|
|
466
|
-
const schemaFile =
|
|
647
|
+
const schemaFile = path10.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
467
648
|
try {
|
|
468
|
-
await
|
|
649
|
+
await fs8.access(schemaFile);
|
|
469
650
|
const mod = await jiti.import(schemaFile);
|
|
470
651
|
for (const [key, value] of Object.entries(mod)) {
|
|
471
652
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -477,14 +658,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
477
658
|
}
|
|
478
659
|
} catch {
|
|
479
660
|
}
|
|
480
|
-
const pagesDir =
|
|
661
|
+
const pagesDir = path10.join(themePath, "pages");
|
|
481
662
|
try {
|
|
482
|
-
const files = await
|
|
663
|
+
const files = await fs8.readdir(pagesDir);
|
|
483
664
|
for (const file of files) {
|
|
484
665
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
485
666
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
486
667
|
try {
|
|
487
|
-
const mod = await jiti.import(
|
|
668
|
+
const mod = await jiti.import(path10.join(pagesDir, file));
|
|
488
669
|
const config = mod.default || mod;
|
|
489
670
|
const sections = (config.sections || []).map((section) => {
|
|
490
671
|
const schema = schemas[section.type];
|
|
@@ -512,8 +693,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
512
693
|
}
|
|
513
694
|
} catch {
|
|
514
695
|
}
|
|
515
|
-
await
|
|
516
|
-
|
|
696
|
+
await fs8.writeFile(
|
|
697
|
+
path10.join(outputDir, "theme-data.json"),
|
|
517
698
|
JSON.stringify(
|
|
518
699
|
{
|
|
519
700
|
themeId,
|
|
@@ -536,22 +717,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
536
717
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
537
718
|
}
|
|
538
719
|
async function contentHashEntry(outputDir) {
|
|
539
|
-
const entryPath =
|
|
540
|
-
const mapPath =
|
|
720
|
+
const entryPath = path10.join(outputDir, "bundle-entry.js");
|
|
721
|
+
const mapPath = path10.join(outputDir, "bundle-entry.js.map");
|
|
541
722
|
let entryContent;
|
|
542
723
|
try {
|
|
543
|
-
entryContent = await
|
|
724
|
+
entryContent = await fs8.readFile(entryPath, "utf-8");
|
|
544
725
|
} catch {
|
|
545
|
-
const indexPath =
|
|
726
|
+
const indexPath = path10.join(outputDir, "index.js");
|
|
546
727
|
try {
|
|
547
|
-
entryContent = await
|
|
728
|
+
entryContent = await fs8.readFile(indexPath, "utf-8");
|
|
548
729
|
} catch {
|
|
549
730
|
logger.warning("No entry file found in output, skipping content hash");
|
|
550
731
|
return;
|
|
551
732
|
}
|
|
552
733
|
const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
553
734
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
554
|
-
const indexMapPath =
|
|
735
|
+
const indexMapPath = path10.join(outputDir, "index.js.map");
|
|
555
736
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
556
737
|
entryContent = entryContent.replace(
|
|
557
738
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
@@ -559,18 +740,18 @@ async function contentHashEntry(outputDir) {
|
|
|
559
740
|
);
|
|
560
741
|
const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
561
742
|
for (const f of oldFiles2) {
|
|
562
|
-
await
|
|
743
|
+
await fs8.unlink(path10.join(outputDir, f));
|
|
563
744
|
}
|
|
564
|
-
await
|
|
565
|
-
await
|
|
745
|
+
await fs8.writeFile(path10.join(outputDir, hashedName2), entryContent);
|
|
746
|
+
await fs8.unlink(indexPath);
|
|
566
747
|
try {
|
|
567
|
-
await
|
|
748
|
+
await fs8.unlink(entryPath);
|
|
568
749
|
} catch {
|
|
569
750
|
}
|
|
570
|
-
await
|
|
751
|
+
await fs8.writeFile(entryPath, entryContent);
|
|
571
752
|
try {
|
|
572
|
-
await
|
|
573
|
-
await
|
|
753
|
+
await fs8.access(indexMapPath);
|
|
754
|
+
await fs8.rename(indexMapPath, path10.join(outputDir, hashedMapName2));
|
|
574
755
|
} catch {
|
|
575
756
|
}
|
|
576
757
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
@@ -585,17 +766,17 @@ async function contentHashEntry(outputDir) {
|
|
|
585
766
|
);
|
|
586
767
|
const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
587
768
|
for (const f of oldFiles) {
|
|
588
|
-
await
|
|
769
|
+
await fs8.unlink(path10.join(outputDir, f));
|
|
589
770
|
}
|
|
590
|
-
await
|
|
771
|
+
await fs8.writeFile(path10.join(outputDir, hashedName), entryContent);
|
|
591
772
|
try {
|
|
592
|
-
await
|
|
773
|
+
await fs8.unlink(entryPath);
|
|
593
774
|
} catch {
|
|
594
775
|
}
|
|
595
|
-
await
|
|
776
|
+
await fs8.writeFile(entryPath, entryContent);
|
|
596
777
|
try {
|
|
597
|
-
await
|
|
598
|
-
await
|
|
778
|
+
await fs8.access(mapPath);
|
|
779
|
+
await fs8.rename(mapPath, path10.join(outputDir, hashedMapName));
|
|
599
780
|
} catch {
|
|
600
781
|
}
|
|
601
782
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -607,7 +788,7 @@ async function extractDataRequirements(themePath) {
|
|
|
607
788
|
const requirements = {};
|
|
608
789
|
for (const file of schemaFiles) {
|
|
609
790
|
try {
|
|
610
|
-
const mod = await jiti.import(
|
|
791
|
+
const mod = await jiti.import(path10.join(themePath, file));
|
|
611
792
|
const exports$1 = mod;
|
|
612
793
|
for (const value of Object.values(exports$1)) {
|
|
613
794
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -622,12 +803,46 @@ async function extractDataRequirements(themePath) {
|
|
|
622
803
|
}
|
|
623
804
|
return requirements;
|
|
624
805
|
}
|
|
806
|
+
async function writeGateManifests(themePath, outputDir) {
|
|
807
|
+
try {
|
|
808
|
+
const schemas = await extractSchemas(themePath);
|
|
809
|
+
await fs8.writeFile(
|
|
810
|
+
path10.join(outputDir, "schemas.json"),
|
|
811
|
+
serializeManifest(schemas)
|
|
812
|
+
);
|
|
813
|
+
logger.info(
|
|
814
|
+
`Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
|
|
815
|
+
);
|
|
816
|
+
} catch (err) {
|
|
817
|
+
logger.warning(
|
|
818
|
+
`schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
try {
|
|
822
|
+
const entries = await scanThemeAssets(outputDir);
|
|
823
|
+
const assets = entries.map((e) => ({
|
|
824
|
+
path: e.originalPath,
|
|
825
|
+
hash: e.hash,
|
|
826
|
+
size: e.size,
|
|
827
|
+
contentType: e.contentType
|
|
828
|
+
}));
|
|
829
|
+
await fs8.writeFile(
|
|
830
|
+
path10.join(outputDir, "asset-manifest.json"),
|
|
831
|
+
JSON.stringify({ manifestVersion: 1, assets }, null, 2)
|
|
832
|
+
);
|
|
833
|
+
logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
|
|
834
|
+
} catch (err) {
|
|
835
|
+
logger.warning(
|
|
836
|
+
`asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
625
840
|
async function generateManifest(themeName, themePath, outputDir) {
|
|
626
841
|
let version = "1.0.0";
|
|
627
842
|
let themeId = themeName;
|
|
628
843
|
try {
|
|
629
|
-
const pkgContent = await
|
|
630
|
-
|
|
844
|
+
const pkgContent = await fs8.readFile(
|
|
845
|
+
path10.join(themePath, "package.json"),
|
|
631
846
|
"utf-8"
|
|
632
847
|
);
|
|
633
848
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -645,7 +860,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
645
860
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
646
861
|
let hasThemeConfig = false;
|
|
647
862
|
try {
|
|
648
|
-
await
|
|
863
|
+
await fs8.access(path10.join(themePath, "theme.config.ts"));
|
|
649
864
|
hasThemeConfig = true;
|
|
650
865
|
} catch {
|
|
651
866
|
}
|
|
@@ -686,24 +901,24 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
686
901
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
687
902
|
dataRequirements
|
|
688
903
|
};
|
|
689
|
-
await
|
|
690
|
-
|
|
904
|
+
await fs8.writeFile(
|
|
905
|
+
path10.join(outputDir, "manifest.json"),
|
|
691
906
|
JSON.stringify(manifest, null, 2)
|
|
692
907
|
);
|
|
693
908
|
}
|
|
694
909
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
695
|
-
const outputDir =
|
|
696
|
-
const bundleEntry =
|
|
697
|
-
const indexEntry =
|
|
910
|
+
const outputDir = path10.join(themePath, "dist");
|
|
911
|
+
const bundleEntry = path10.join(themePath, "bundle-entry.ts");
|
|
912
|
+
const indexEntry = path10.join(themePath, "index.ts");
|
|
698
913
|
let entryPoint = indexEntry;
|
|
699
914
|
try {
|
|
700
|
-
await
|
|
915
|
+
await fs8.access(bundleEntry);
|
|
701
916
|
entryPoint = bundleEntry;
|
|
702
917
|
} catch {
|
|
703
918
|
}
|
|
704
|
-
const shimPath =
|
|
705
|
-
await
|
|
706
|
-
await
|
|
919
|
+
const shimPath = path10.join(outputDir, ".process-shim.js");
|
|
920
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
921
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
707
922
|
const buildOptions = {
|
|
708
923
|
entryPoints: [entryPoint],
|
|
709
924
|
bundle: true,
|
|
@@ -754,19 +969,20 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
754
969
|
try {
|
|
755
970
|
const result = await esbuild.build(buildOptions);
|
|
756
971
|
try {
|
|
757
|
-
await
|
|
972
|
+
await fs8.unlink(shimPath);
|
|
758
973
|
} catch {
|
|
759
974
|
}
|
|
760
975
|
await contentHashEntry(outputDir);
|
|
761
|
-
const themeAssetsDir =
|
|
762
|
-
const distThemeAssets =
|
|
976
|
+
const themeAssetsDir = path10.join(themePath, "assets");
|
|
977
|
+
const distThemeAssets = path10.join(outputDir, "theme-assets");
|
|
763
978
|
try {
|
|
764
|
-
await
|
|
765
|
-
await
|
|
979
|
+
await fs8.access(themeAssetsDir);
|
|
980
|
+
await fs8.cp(themeAssetsDir, distThemeAssets, { recursive: true });
|
|
766
981
|
logger.info("Copied static assets to dist/theme-assets/");
|
|
767
982
|
} catch {
|
|
768
983
|
}
|
|
769
984
|
await generateManifest(themeName, themePath, outputDir);
|
|
985
|
+
await writeGateManifests(themePath, outputDir);
|
|
770
986
|
await generateThemeData(themePath, outputDir, themeName);
|
|
771
987
|
await generateThemeCSS(themePath, outputDir);
|
|
772
988
|
if (result.metafile) {
|
|
@@ -781,7 +997,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
781
997
|
return true;
|
|
782
998
|
} catch (error) {
|
|
783
999
|
try {
|
|
784
|
-
await
|
|
1000
|
+
await fs8.unlink(shimPath);
|
|
785
1001
|
} catch {
|
|
786
1002
|
}
|
|
787
1003
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -789,18 +1005,18 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
789
1005
|
}
|
|
790
1006
|
}
|
|
791
1007
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
792
|
-
const outputDir =
|
|
793
|
-
const bundleEntry =
|
|
794
|
-
const indexEntry =
|
|
1008
|
+
const outputDir = path10.join(themePath, "dist");
|
|
1009
|
+
const bundleEntry = path10.join(themePath, "bundle-entry.ts");
|
|
1010
|
+
const indexEntry = path10.join(themePath, "index.ts");
|
|
795
1011
|
let entryPoint = indexEntry;
|
|
796
1012
|
try {
|
|
797
|
-
await
|
|
1013
|
+
await fs8.access(bundleEntry);
|
|
798
1014
|
entryPoint = bundleEntry;
|
|
799
1015
|
} catch {
|
|
800
1016
|
}
|
|
801
|
-
const shimPath =
|
|
802
|
-
await
|
|
803
|
-
await
|
|
1017
|
+
const shimPath = path10.join(outputDir, ".process-shim.js");
|
|
1018
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
1019
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
804
1020
|
const buildOptions = {
|
|
805
1021
|
entryPoints: [entryPoint],
|
|
806
1022
|
bundle: true,
|
|
@@ -854,18 +1070,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
854
1070
|
return { context: context2, outputDir };
|
|
855
1071
|
}
|
|
856
1072
|
async function compilePreviewRuntime(themePath) {
|
|
857
|
-
const outputDir =
|
|
858
|
-
await
|
|
859
|
-
const outputPath =
|
|
1073
|
+
const outputDir = path10.join(themePath, "dist");
|
|
1074
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
1075
|
+
const outputPath = path10.join(outputDir, "preview-runtime.js");
|
|
860
1076
|
const locations = [
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1077
|
+
path10.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
1078
|
+
path10.join(__dirname, "preview", "preview-app.tsx"),
|
|
1079
|
+
path10.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
864
1080
|
];
|
|
865
1081
|
let previewEntryPath = null;
|
|
866
1082
|
for (const loc of locations) {
|
|
867
1083
|
try {
|
|
868
|
-
await
|
|
1084
|
+
await fs8.access(loc);
|
|
869
1085
|
previewEntryPath = loc;
|
|
870
1086
|
break;
|
|
871
1087
|
} catch {
|
|
@@ -948,10 +1164,10 @@ ${locations.join("\n")}`
|
|
|
948
1164
|
if (!lucideScanned) {
|
|
949
1165
|
lucideScanned = true;
|
|
950
1166
|
const coreSrcCandidates = [
|
|
951
|
-
|
|
952
|
-
|
|
1167
|
+
path10.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
1168
|
+
path10.join(themePath, "..", "..", "packages", "core", "src"),
|
|
953
1169
|
// monorepo sibling
|
|
954
|
-
|
|
1170
|
+
path10.join(
|
|
955
1171
|
__dirname,
|
|
956
1172
|
"..",
|
|
957
1173
|
"..",
|
|
@@ -966,7 +1182,7 @@ ${locations.join("\n")}`
|
|
|
966
1182
|
let coreSourceDir = null;
|
|
967
1183
|
for (const candidate of coreSrcCandidates) {
|
|
968
1184
|
try {
|
|
969
|
-
await
|
|
1185
|
+
await fs8.access(candidate);
|
|
970
1186
|
coreSourceDir = candidate;
|
|
971
1187
|
break;
|
|
972
1188
|
} catch {
|
|
@@ -985,21 +1201,21 @@ ${locations.join("\n")}`
|
|
|
985
1201
|
}
|
|
986
1202
|
} else {
|
|
987
1203
|
const coreDistCandidates = [
|
|
988
|
-
|
|
1204
|
+
path10.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
989
1205
|
];
|
|
990
1206
|
const resolvedDist = await resolveNodeModulesFile(
|
|
991
1207
|
__dirname,
|
|
992
|
-
|
|
1208
|
+
path10.join("@onexapis", "core", "dist")
|
|
993
1209
|
);
|
|
994
1210
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
995
1211
|
for (const candidate of coreDistCandidates) {
|
|
996
1212
|
try {
|
|
997
|
-
await
|
|
1213
|
+
await fs8.access(candidate);
|
|
998
1214
|
const mjsFiles = await glob("*.mjs", { cwd: candidate });
|
|
999
1215
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
1000
1216
|
for (const file of mjsFiles) {
|
|
1001
|
-
const content = await
|
|
1002
|
-
|
|
1217
|
+
const content = await fs8.readFile(
|
|
1218
|
+
path10.join(candidate, file),
|
|
1003
1219
|
"utf-8"
|
|
1004
1220
|
);
|
|
1005
1221
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1054,7 +1270,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1054
1270
|
const req = createRequire(import.meta.url || __filename);
|
|
1055
1271
|
const cjsPath = req.resolve("framer-motion");
|
|
1056
1272
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1057
|
-
const esmEntry =
|
|
1273
|
+
const esmEntry = path10.join(pkgDir, "dist", "es", "index.mjs");
|
|
1058
1274
|
const { existsSync } = await import('fs');
|
|
1059
1275
|
if (existsSync(esmEntry)) {
|
|
1060
1276
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1153,8 +1369,8 @@ export function headers() { return new Headers(); }
|
|
|
1153
1369
|
});
|
|
1154
1370
|
}
|
|
1155
1371
|
};
|
|
1156
|
-
const shimPath =
|
|
1157
|
-
await
|
|
1372
|
+
const shimPath = path10.join(outputDir, ".process-shim-preview.js");
|
|
1373
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
1158
1374
|
await esbuild.build({
|
|
1159
1375
|
entryPoints: [previewEntryPath],
|
|
1160
1376
|
bundle: true,
|
|
@@ -1189,7 +1405,7 @@ export function headers() { return new Headers(); }
|
|
|
1189
1405
|
}
|
|
1190
1406
|
});
|
|
1191
1407
|
try {
|
|
1192
|
-
await
|
|
1408
|
+
await fs8.unlink(shimPath);
|
|
1193
1409
|
} catch {
|
|
1194
1410
|
}
|
|
1195
1411
|
return outputPath;
|
|
@@ -1198,6 +1414,8 @@ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
|
|
|
1198
1414
|
var init_compile_theme = __esm({
|
|
1199
1415
|
"src/utils/compile-theme.ts"() {
|
|
1200
1416
|
init_logger();
|
|
1417
|
+
init_extract_schemas();
|
|
1418
|
+
init_scan_theme_assets();
|
|
1201
1419
|
PROCESS_SHIM = `
|
|
1202
1420
|
if (typeof process === "undefined") {
|
|
1203
1421
|
globalThis.process = {
|
|
@@ -1367,8 +1585,8 @@ function validateThemeName(name) {
|
|
|
1367
1585
|
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
1368
1586
|
}
|
|
1369
1587
|
function pathExists(filePath) {
|
|
1370
|
-
const
|
|
1371
|
-
return
|
|
1588
|
+
const fs12 = __require("fs-extra");
|
|
1589
|
+
return fs12.existsSync(filePath);
|
|
1372
1590
|
}
|
|
1373
1591
|
function validateCategory(category) {
|
|
1374
1592
|
const validCategories = [
|
|
@@ -1409,18 +1627,18 @@ async function renderTemplate(templatePath, data) {
|
|
|
1409
1627
|
return ejs.render(template, data);
|
|
1410
1628
|
}
|
|
1411
1629
|
async function writeFile(filePath, content) {
|
|
1412
|
-
await fs.ensureDir(
|
|
1630
|
+
await fs.ensureDir(path10.dirname(filePath));
|
|
1413
1631
|
await fs.writeFile(filePath, content, "utf-8");
|
|
1414
1632
|
}
|
|
1415
1633
|
function getTemplatesDir() {
|
|
1416
1634
|
const locations = [
|
|
1417
|
-
|
|
1635
|
+
path10.join(__dirname, "../../templates"),
|
|
1418
1636
|
// Development
|
|
1419
|
-
|
|
1637
|
+
path10.join(__dirname, "../templates"),
|
|
1420
1638
|
// Production (dist/)
|
|
1421
|
-
|
|
1639
|
+
path10.join(process.cwd(), "templates"),
|
|
1422
1640
|
// Fallback
|
|
1423
|
-
|
|
1641
|
+
path10.join(process.cwd(), "packages/cli/templates")
|
|
1424
1642
|
// Monorepo
|
|
1425
1643
|
];
|
|
1426
1644
|
for (const location of locations) {
|
|
@@ -1432,7 +1650,7 @@ function getTemplatesDir() {
|
|
|
1432
1650
|
}
|
|
1433
1651
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1434
1652
|
const templatesDir = getTemplatesDir();
|
|
1435
|
-
const templateDir =
|
|
1653
|
+
const templateDir = path10.join(templatesDir, templateName);
|
|
1436
1654
|
if (!fs.existsSync(templateDir)) {
|
|
1437
1655
|
throw new Error(
|
|
1438
1656
|
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
|
|
@@ -1441,8 +1659,8 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1441
1659
|
await fs.ensureDir(targetDir);
|
|
1442
1660
|
const files = await fs.readdir(templateDir);
|
|
1443
1661
|
for (const file of files) {
|
|
1444
|
-
const templatePath =
|
|
1445
|
-
const targetPath =
|
|
1662
|
+
const templatePath = path10.join(templateDir, file);
|
|
1663
|
+
const targetPath = path10.join(targetDir, file);
|
|
1446
1664
|
const stat = await fs.stat(templatePath);
|
|
1447
1665
|
if (stat.isDirectory()) {
|
|
1448
1666
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1459,8 +1677,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1459
1677
|
await fs.ensureDir(targetDir);
|
|
1460
1678
|
const files = await fs.readdir(templateDir);
|
|
1461
1679
|
for (const file of files) {
|
|
1462
|
-
const templatePath =
|
|
1463
|
-
const targetPath =
|
|
1680
|
+
const templatePath = path10.join(templateDir, file);
|
|
1681
|
+
const targetPath = path10.join(targetDir, file);
|
|
1464
1682
|
const stat = await fs.stat(templatePath);
|
|
1465
1683
|
if (stat.isDirectory()) {
|
|
1466
1684
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1475,32 +1693,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1475
1693
|
}
|
|
1476
1694
|
function getProjectRoot() {
|
|
1477
1695
|
let currentDir = process.cwd();
|
|
1478
|
-
while (currentDir !==
|
|
1479
|
-
const packageJsonPath =
|
|
1696
|
+
while (currentDir !== path10.parse(currentDir).root) {
|
|
1697
|
+
const packageJsonPath = path10.join(currentDir, "package.json");
|
|
1480
1698
|
if (fs.existsSync(packageJsonPath)) {
|
|
1481
1699
|
const packageJson = fs.readJsonSync(packageJsonPath);
|
|
1482
|
-
if (packageJson.workspaces || fs.existsSync(
|
|
1700
|
+
if (packageJson.workspaces || fs.existsSync(path10.join(currentDir, "src/themes")) || fs.existsSync(path10.join(currentDir, "themes"))) {
|
|
1483
1701
|
return currentDir;
|
|
1484
1702
|
}
|
|
1485
1703
|
}
|
|
1486
|
-
currentDir =
|
|
1704
|
+
currentDir = path10.dirname(currentDir);
|
|
1487
1705
|
}
|
|
1488
1706
|
return process.cwd();
|
|
1489
1707
|
}
|
|
1490
1708
|
function getThemesDir() {
|
|
1491
1709
|
const root = getProjectRoot();
|
|
1492
|
-
if (fs.existsSync(
|
|
1493
|
-
return
|
|
1494
|
-
if (fs.existsSync(
|
|
1495
|
-
return
|
|
1496
|
-
return
|
|
1710
|
+
if (fs.existsSync(path10.join(root, "themes")))
|
|
1711
|
+
return path10.join(root, "themes");
|
|
1712
|
+
if (fs.existsSync(path10.join(root, "src/themes")))
|
|
1713
|
+
return path10.join(root, "src/themes");
|
|
1714
|
+
return path10.dirname(root);
|
|
1497
1715
|
}
|
|
1498
1716
|
function getFeaturesDir() {
|
|
1499
|
-
return
|
|
1717
|
+
return path10.join(getProjectRoot(), "src/features");
|
|
1500
1718
|
}
|
|
1501
1719
|
function isOneXProject() {
|
|
1502
1720
|
const root = getProjectRoot();
|
|
1503
|
-
return fs.existsSync(
|
|
1721
|
+
return fs.existsSync(path10.join(root, "themes")) || fs.existsSync(path10.join(root, "src/themes")) || fs.existsSync(path10.join(root, "theme.config.ts")) || fs.existsSync(path10.join(root, "bundle-entry.ts"));
|
|
1504
1722
|
}
|
|
1505
1723
|
function ensureOneXProject() {
|
|
1506
1724
|
if (!isOneXProject()) {
|
|
@@ -1516,13 +1734,13 @@ function listThemes() {
|
|
|
1516
1734
|
return [];
|
|
1517
1735
|
}
|
|
1518
1736
|
return fs.readdirSync(themesDir).filter((name) => {
|
|
1519
|
-
const themePath =
|
|
1520
|
-
return fs.statSync(themePath).isDirectory() && (fs.existsSync(
|
|
1737
|
+
const themePath = path10.join(themesDir, name);
|
|
1738
|
+
return fs.statSync(themePath).isDirectory() && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
|
|
1521
1739
|
});
|
|
1522
1740
|
}
|
|
1523
1741
|
function themeExists(themeName) {
|
|
1524
|
-
const themePath =
|
|
1525
|
-
return fs.existsSync(themePath) && (fs.existsSync(
|
|
1742
|
+
const themePath = path10.join(getThemesDir(), themeName);
|
|
1743
|
+
return fs.existsSync(themePath) && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
|
|
1526
1744
|
}
|
|
1527
1745
|
function detectPackageManager() {
|
|
1528
1746
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1530,9 +1748,9 @@ function detectPackageManager() {
|
|
|
1530
1748
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1531
1749
|
if (userAgent.includes("bun")) return "bun";
|
|
1532
1750
|
const cwd = process.cwd();
|
|
1533
|
-
if (fs.existsSync(
|
|
1534
|
-
if (fs.existsSync(
|
|
1535
|
-
if (fs.existsSync(
|
|
1751
|
+
if (fs.existsSync(path10.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1752
|
+
if (fs.existsSync(path10.join(cwd, "yarn.lock"))) return "yarn";
|
|
1753
|
+
if (fs.existsSync(path10.join(cwd, "bun.lockb"))) return "bun";
|
|
1536
1754
|
return "npm";
|
|
1537
1755
|
}
|
|
1538
1756
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1549,22 +1767,45 @@ async function installDependencies(projectPath, packageManager = "npm") {
|
|
|
1549
1767
|
}
|
|
1550
1768
|
});
|
|
1551
1769
|
}
|
|
1552
|
-
var AUTH_DIR =
|
|
1553
|
-
var
|
|
1554
|
-
|
|
1555
|
-
|
|
1770
|
+
var AUTH_DIR = path10.join(os.homedir(), ".onexthm");
|
|
1771
|
+
var ENV_URLS = {
|
|
1772
|
+
dev: "https://platform-dev.onexeos.com",
|
|
1773
|
+
staging: "https://platform-staging.onexeos.com",
|
|
1774
|
+
prod: "https://platform-apis.onexeos.com"
|
|
1775
|
+
};
|
|
1776
|
+
function getAuthFile(env = "dev") {
|
|
1777
|
+
const newFile = path10.join(AUTH_DIR, `auth-${env}.json`);
|
|
1778
|
+
if (env === "dev") {
|
|
1779
|
+
const legacyFile = path10.join(AUTH_DIR, "auth.json");
|
|
1780
|
+
if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
|
|
1781
|
+
try {
|
|
1782
|
+
fs.moveSync(legacyFile, newFile);
|
|
1783
|
+
} catch {
|
|
1784
|
+
try {
|
|
1785
|
+
fs.copySync(legacyFile, newFile);
|
|
1786
|
+
fs.removeSync(legacyFile);
|
|
1787
|
+
} catch {
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return newFile;
|
|
1793
|
+
}
|
|
1794
|
+
function getApiUrl(env = "dev") {
|
|
1795
|
+
return process.env.ONEXTHM_API_URL || ENV_URLS[env];
|
|
1556
1796
|
}
|
|
1557
|
-
async function saveAuthTokens(tokens) {
|
|
1797
|
+
async function saveAuthTokens(tokens, env = "dev") {
|
|
1558
1798
|
await fs.ensureDir(AUTH_DIR);
|
|
1559
1799
|
const key = getMachineKey();
|
|
1560
1800
|
const data = JSON.stringify(tokens);
|
|
1561
1801
|
const encrypted = encrypt(data, key);
|
|
1562
|
-
await fs.writeFile(
|
|
1802
|
+
await fs.writeFile(getAuthFile(env), encrypted, "utf-8");
|
|
1563
1803
|
}
|
|
1564
|
-
function loadAuthTokens() {
|
|
1804
|
+
function loadAuthTokens(env = "dev") {
|
|
1565
1805
|
try {
|
|
1566
|
-
|
|
1567
|
-
|
|
1806
|
+
const file = getAuthFile(env);
|
|
1807
|
+
if (!fs.existsSync(file)) return null;
|
|
1808
|
+
const encrypted = fs.readFileSync(file, "utf-8");
|
|
1568
1809
|
const key = getMachineKey();
|
|
1569
1810
|
const data = decrypt(encrypted, key);
|
|
1570
1811
|
return JSON.parse(data);
|
|
@@ -1572,34 +1813,34 @@ function loadAuthTokens() {
|
|
|
1572
1813
|
return null;
|
|
1573
1814
|
}
|
|
1574
1815
|
}
|
|
1575
|
-
async function clearAuthTokens() {
|
|
1816
|
+
async function clearAuthTokens(env = "dev") {
|
|
1576
1817
|
try {
|
|
1577
|
-
await fs.remove(
|
|
1818
|
+
await fs.remove(getAuthFile(env));
|
|
1578
1819
|
} catch {
|
|
1579
1820
|
}
|
|
1580
1821
|
}
|
|
1581
1822
|
function isTokenExpired(tokens) {
|
|
1582
1823
|
return Date.now() / 1e3 > tokens.expiresAt - 300;
|
|
1583
1824
|
}
|
|
1584
|
-
async function getValidTokens() {
|
|
1585
|
-
const tokens = loadAuthTokens();
|
|
1825
|
+
async function getValidTokens(env = "dev") {
|
|
1826
|
+
const tokens = loadAuthTokens(env);
|
|
1586
1827
|
if (!tokens) return null;
|
|
1587
1828
|
if (!isTokenExpired(tokens)) return tokens;
|
|
1588
1829
|
try {
|
|
1589
|
-
const apiUrl = getApiUrl();
|
|
1830
|
+
const apiUrl = getApiUrl(env);
|
|
1590
1831
|
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
1591
1832
|
method: "POST",
|
|
1592
1833
|
headers: { "Content-Type": "application/json" },
|
|
1593
1834
|
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
1594
1835
|
});
|
|
1595
1836
|
if (!response.ok) {
|
|
1596
|
-
await clearAuthTokens();
|
|
1837
|
+
await clearAuthTokens(env);
|
|
1597
1838
|
return null;
|
|
1598
1839
|
}
|
|
1599
1840
|
const data = await response.json();
|
|
1600
1841
|
const body = data.statusCode ? data.body : data;
|
|
1601
1842
|
if (!body.IdToken) {
|
|
1602
|
-
await clearAuthTokens();
|
|
1843
|
+
await clearAuthTokens(env);
|
|
1603
1844
|
return null;
|
|
1604
1845
|
}
|
|
1605
1846
|
const refreshed = {
|
|
@@ -1608,17 +1849,19 @@ async function getValidTokens() {
|
|
|
1608
1849
|
idToken: body.IdToken,
|
|
1609
1850
|
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
1610
1851
|
};
|
|
1611
|
-
await saveAuthTokens(refreshed);
|
|
1852
|
+
await saveAuthTokens(refreshed, env);
|
|
1612
1853
|
return refreshed;
|
|
1613
1854
|
} catch {
|
|
1614
|
-
await clearAuthTokens();
|
|
1855
|
+
await clearAuthTokens(env);
|
|
1615
1856
|
return null;
|
|
1616
1857
|
}
|
|
1617
1858
|
}
|
|
1618
|
-
async function authenticatedFetch(url, init) {
|
|
1619
|
-
const tokens = await getValidTokens();
|
|
1859
|
+
async function authenticatedFetch(url, init, env = "dev") {
|
|
1860
|
+
const tokens = await getValidTokens(env);
|
|
1620
1861
|
if (!tokens) {
|
|
1621
|
-
throw new Error(
|
|
1862
|
+
throw new Error(
|
|
1863
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
1864
|
+
);
|
|
1622
1865
|
}
|
|
1623
1866
|
const headers = new Headers(init?.headers);
|
|
1624
1867
|
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
@@ -1675,7 +1918,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1675
1918
|
if (!validateThemeName(kebabName)) {
|
|
1676
1919
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1677
1920
|
}
|
|
1678
|
-
if (fs3.existsSync(
|
|
1921
|
+
if (fs3.existsSync(path10.join(process.cwd(), kebabName))) {
|
|
1679
1922
|
return `Directory "${kebabName}" already exists`;
|
|
1680
1923
|
}
|
|
1681
1924
|
return true;
|
|
@@ -1686,14 +1929,14 @@ async function initCommand(projectName, options = {}) {
|
|
|
1686
1929
|
} else {
|
|
1687
1930
|
name = toKebabCase(projectName);
|
|
1688
1931
|
}
|
|
1689
|
-
const projectPath =
|
|
1932
|
+
const projectPath = path10.join(process.cwd(), name);
|
|
1690
1933
|
if (fs3.existsSync(projectPath)) {
|
|
1691
1934
|
logger.error(`Directory "${name}" already exists.`);
|
|
1692
1935
|
process.exit(1);
|
|
1693
1936
|
}
|
|
1694
1937
|
if (!options.yes) {
|
|
1695
1938
|
try {
|
|
1696
|
-
const apiUrl = getApiUrl();
|
|
1939
|
+
const apiUrl = getApiUrl(options.env ?? "dev");
|
|
1697
1940
|
const controller = new AbortController();
|
|
1698
1941
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1699
1942
|
const response = await fetch(
|
|
@@ -1802,7 +2045,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1802
2045
|
description,
|
|
1803
2046
|
author
|
|
1804
2047
|
);
|
|
1805
|
-
const mcpJsonPath =
|
|
2048
|
+
const mcpJsonPath = path10.join(projectPath, ".mcp.json");
|
|
1806
2049
|
if (fs3.existsSync(mcpJsonPath)) {
|
|
1807
2050
|
let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
|
|
1808
2051
|
if (figmaApiKey) {
|
|
@@ -1882,7 +2125,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1882
2125
|
}
|
|
1883
2126
|
}
|
|
1884
2127
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
1885
|
-
const configPath =
|
|
2128
|
+
const configPath = path10.join(projectPath, "theme.config.ts");
|
|
1886
2129
|
if (fs3.existsSync(configPath)) {
|
|
1887
2130
|
let content = fs3.readFileSync(configPath, "utf-8");
|
|
1888
2131
|
content = content.replace(
|
|
@@ -1895,7 +2138,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
1895
2138
|
);
|
|
1896
2139
|
fs3.writeFileSync(configPath, content, "utf-8");
|
|
1897
2140
|
}
|
|
1898
|
-
const pkgPath =
|
|
2141
|
+
const pkgPath = path10.join(projectPath, "package.json");
|
|
1899
2142
|
if (fs3.existsSync(pkgPath)) {
|
|
1900
2143
|
let content = fs3.readFileSync(pkgPath, "utf-8");
|
|
1901
2144
|
content = content.replace(
|
|
@@ -1917,10 +2160,10 @@ async function createSectionCommand(name, options) {
|
|
|
1917
2160
|
ensureOneXProject();
|
|
1918
2161
|
if (!options.theme) {
|
|
1919
2162
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
1920
|
-
(f) => fs.existsSync(
|
|
2163
|
+
(f) => fs.existsSync(path10.join(process.cwd(), f))
|
|
1921
2164
|
);
|
|
1922
2165
|
if (isStandaloneTheme) {
|
|
1923
|
-
options.theme =
|
|
2166
|
+
options.theme = path10.basename(process.cwd());
|
|
1924
2167
|
}
|
|
1925
2168
|
}
|
|
1926
2169
|
const sectionName = toKebabCase(name);
|
|
@@ -1983,35 +2226,35 @@ async function createSectionCommand(name, options) {
|
|
|
1983
2226
|
};
|
|
1984
2227
|
logger.startSpinner("Creating section files...");
|
|
1985
2228
|
try {
|
|
1986
|
-
const themePath =
|
|
1987
|
-
const sectionPath =
|
|
2229
|
+
const themePath = path10.join(getThemesDir(), themeName);
|
|
2230
|
+
const sectionPath = path10.join(themePath, "sections", sectionName);
|
|
1988
2231
|
const schemaContent = generateSectionSchema(data);
|
|
1989
2232
|
await writeFile(
|
|
1990
|
-
|
|
2233
|
+
path10.join(sectionPath, `${sectionName}.schema.ts`),
|
|
1991
2234
|
schemaContent
|
|
1992
2235
|
);
|
|
1993
2236
|
if (createTemplate) {
|
|
1994
2237
|
const templateContent = generateSectionTemplate(data);
|
|
1995
2238
|
await writeFile(
|
|
1996
|
-
|
|
2239
|
+
path10.join(sectionPath, `${sectionName}-default.tsx`),
|
|
1997
2240
|
templateContent
|
|
1998
2241
|
);
|
|
1999
2242
|
}
|
|
2000
2243
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
2001
|
-
await writeFile(
|
|
2244
|
+
await writeFile(path10.join(sectionPath, "index.ts"), indexContent);
|
|
2002
2245
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
2003
2246
|
logger.newLine();
|
|
2004
2247
|
logger.section("Next steps:");
|
|
2005
2248
|
logger.log(
|
|
2006
|
-
` 1. Edit schema: ${
|
|
2249
|
+
` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
2007
2250
|
);
|
|
2008
2251
|
if (createTemplate) {
|
|
2009
2252
|
logger.log(
|
|
2010
|
-
` 2. Edit template: ${
|
|
2253
|
+
` 2. Edit template: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
2011
2254
|
);
|
|
2012
2255
|
}
|
|
2013
2256
|
logger.log(
|
|
2014
|
-
` 3. Add to theme manifest: ${
|
|
2257
|
+
` 3. Add to theme manifest: ${path10.relative(process.cwd(), path10.join(themePath, "manifest.ts"))}`
|
|
2015
2258
|
);
|
|
2016
2259
|
logger.newLine();
|
|
2017
2260
|
logger.success("Section created successfully!");
|
|
@@ -2159,10 +2402,10 @@ async function createBlockCommand(name, options) {
|
|
|
2159
2402
|
ensureOneXProject();
|
|
2160
2403
|
if (!options.theme) {
|
|
2161
2404
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
2162
|
-
(f) => fs.existsSync(
|
|
2405
|
+
(f) => fs.existsSync(path10.join(process.cwd(), f))
|
|
2163
2406
|
);
|
|
2164
2407
|
if (isStandaloneTheme) {
|
|
2165
|
-
options.theme =
|
|
2408
|
+
options.theme = path10.basename(process.cwd());
|
|
2166
2409
|
}
|
|
2167
2410
|
}
|
|
2168
2411
|
const blockName = toKebabCase(name);
|
|
@@ -2237,24 +2480,24 @@ async function createBlockCommand(name, options) {
|
|
|
2237
2480
|
};
|
|
2238
2481
|
logger.startSpinner("Creating block files...");
|
|
2239
2482
|
try {
|
|
2240
|
-
const blockPath = scope === "shared" ?
|
|
2483
|
+
const blockPath = scope === "shared" ? path10.join(getFeaturesDir(), "blocks", blockName) : path10.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2241
2484
|
const schemaContent = generateBlockSchema(data);
|
|
2242
2485
|
await writeFile(
|
|
2243
|
-
|
|
2486
|
+
path10.join(blockPath, `${blockName}.schema.ts`),
|
|
2244
2487
|
schemaContent
|
|
2245
2488
|
);
|
|
2246
2489
|
const componentContent = generateBlockComponent(data);
|
|
2247
|
-
await writeFile(
|
|
2490
|
+
await writeFile(path10.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2248
2491
|
const indexContent = generateBlockIndex(data);
|
|
2249
|
-
await writeFile(
|
|
2492
|
+
await writeFile(path10.join(blockPath, "index.ts"), indexContent);
|
|
2250
2493
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2251
2494
|
logger.newLine();
|
|
2252
2495
|
logger.section("Next steps:");
|
|
2253
2496
|
logger.log(
|
|
2254
|
-
` 1. Edit schema: ${
|
|
2497
|
+
` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2255
2498
|
);
|
|
2256
2499
|
logger.log(
|
|
2257
|
-
` 2. Edit component: ${
|
|
2500
|
+
` 2. Edit component: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.tsx`))}`
|
|
2258
2501
|
);
|
|
2259
2502
|
logger.log(
|
|
2260
2503
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2432,31 +2675,31 @@ async function createComponentCommand(name, options) {
|
|
|
2432
2675
|
};
|
|
2433
2676
|
logger.startSpinner("Creating component files...");
|
|
2434
2677
|
try {
|
|
2435
|
-
const componentPath =
|
|
2678
|
+
const componentPath = path10.join(
|
|
2436
2679
|
getFeaturesDir(),
|
|
2437
2680
|
"components",
|
|
2438
2681
|
componentName
|
|
2439
2682
|
);
|
|
2440
2683
|
const schemaContent = generateComponentSchema(data);
|
|
2441
2684
|
await writeFile(
|
|
2442
|
-
|
|
2685
|
+
path10.join(componentPath, `${componentName}.schema.ts`),
|
|
2443
2686
|
schemaContent
|
|
2444
2687
|
);
|
|
2445
2688
|
const componentContent = generateComponent(data);
|
|
2446
2689
|
await writeFile(
|
|
2447
|
-
|
|
2690
|
+
path10.join(componentPath, `${componentName}.tsx`),
|
|
2448
2691
|
componentContent
|
|
2449
2692
|
);
|
|
2450
2693
|
const indexContent = generateComponentIndex(data);
|
|
2451
|
-
await writeFile(
|
|
2694
|
+
await writeFile(path10.join(componentPath, "index.ts"), indexContent);
|
|
2452
2695
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2453
2696
|
logger.newLine();
|
|
2454
2697
|
logger.section("Next steps:");
|
|
2455
2698
|
logger.log(
|
|
2456
|
-
` 1. Edit schema: ${
|
|
2699
|
+
` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2457
2700
|
);
|
|
2458
2701
|
logger.log(
|
|
2459
|
-
` 2. Edit component: ${
|
|
2702
|
+
` 2. Edit component: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.tsx`))}`
|
|
2460
2703
|
);
|
|
2461
2704
|
logger.log(
|
|
2462
2705
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2613,13 +2856,13 @@ async function listSections(themeFilter) {
|
|
|
2613
2856
|
return;
|
|
2614
2857
|
}
|
|
2615
2858
|
for (const theme of themes) {
|
|
2616
|
-
const sectionsDir =
|
|
2859
|
+
const sectionsDir = path10.join(getThemesDir(), theme, "sections");
|
|
2617
2860
|
if (!fs.existsSync(sectionsDir)) {
|
|
2618
2861
|
continue;
|
|
2619
2862
|
}
|
|
2620
2863
|
const sections = fs.readdirSync(sectionsDir).filter((name) => {
|
|
2621
|
-
const sectionPath =
|
|
2622
|
-
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(
|
|
2864
|
+
const sectionPath = path10.join(sectionsDir, name);
|
|
2865
|
+
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path10.join(sectionPath, "index.ts"));
|
|
2623
2866
|
});
|
|
2624
2867
|
if (sections.length > 0) {
|
|
2625
2868
|
logger.log(chalk4.cyan(`
|
|
@@ -2633,11 +2876,11 @@ async function listSections(themeFilter) {
|
|
|
2633
2876
|
}
|
|
2634
2877
|
async function listBlocks(themeFilter) {
|
|
2635
2878
|
logger.section("\u{1F9F1} Blocks");
|
|
2636
|
-
const sharedBlocksDir =
|
|
2879
|
+
const sharedBlocksDir = path10.join(getFeaturesDir(), "blocks");
|
|
2637
2880
|
if (fs.existsSync(sharedBlocksDir)) {
|
|
2638
2881
|
const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
|
|
2639
|
-
const blockPath =
|
|
2640
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
2882
|
+
const blockPath = path10.join(sharedBlocksDir, name);
|
|
2883
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
|
|
2641
2884
|
});
|
|
2642
2885
|
if (sharedBlocks.length > 0) {
|
|
2643
2886
|
logger.log(chalk4.cyan("\n Shared:"));
|
|
@@ -2648,13 +2891,13 @@ async function listBlocks(themeFilter) {
|
|
|
2648
2891
|
}
|
|
2649
2892
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2650
2893
|
for (const theme of themes) {
|
|
2651
|
-
const blocksDir =
|
|
2894
|
+
const blocksDir = path10.join(getThemesDir(), theme, "blocks");
|
|
2652
2895
|
if (!fs.existsSync(blocksDir)) {
|
|
2653
2896
|
continue;
|
|
2654
2897
|
}
|
|
2655
2898
|
const blocks = fs.readdirSync(blocksDir).filter((name) => {
|
|
2656
|
-
const blockPath =
|
|
2657
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
2899
|
+
const blockPath = path10.join(blocksDir, name);
|
|
2900
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
|
|
2658
2901
|
});
|
|
2659
2902
|
if (blocks.length > 0) {
|
|
2660
2903
|
logger.log(chalk4.cyan(`
|
|
@@ -2668,14 +2911,14 @@ async function listBlocks(themeFilter) {
|
|
|
2668
2911
|
}
|
|
2669
2912
|
async function listComponents() {
|
|
2670
2913
|
logger.section("\u2699\uFE0F Components");
|
|
2671
|
-
const componentsDir =
|
|
2914
|
+
const componentsDir = path10.join(getFeaturesDir(), "components");
|
|
2672
2915
|
if (!fs.existsSync(componentsDir)) {
|
|
2673
2916
|
logger.warning("No components directory found");
|
|
2674
2917
|
return;
|
|
2675
2918
|
}
|
|
2676
2919
|
const components = fs.readdirSync(componentsDir).filter((name) => {
|
|
2677
|
-
const componentPath =
|
|
2678
|
-
return fs.statSync(componentPath).isDirectory() && fs.existsSync(
|
|
2920
|
+
const componentPath = path10.join(componentsDir, name);
|
|
2921
|
+
return fs.statSync(componentPath).isDirectory() && fs.existsSync(path10.join(componentPath, "index.ts"));
|
|
2679
2922
|
});
|
|
2680
2923
|
if (components.length === 0) {
|
|
2681
2924
|
logger.warning("No components found");
|
|
@@ -2696,11 +2939,11 @@ async function listThemesInfo() {
|
|
|
2696
2939
|
}
|
|
2697
2940
|
logger.log("");
|
|
2698
2941
|
for (const theme of themes) {
|
|
2699
|
-
const themeDir =
|
|
2942
|
+
const themeDir = path10.join(getThemesDir(), theme);
|
|
2700
2943
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2701
2944
|
let manifestContent = "";
|
|
2702
2945
|
for (const candidate of candidates) {
|
|
2703
|
-
const candidatePath =
|
|
2946
|
+
const candidatePath = path10.join(themeDir, candidate);
|
|
2704
2947
|
if (fs.existsSync(candidatePath)) {
|
|
2705
2948
|
manifestContent = fs.readFileSync(candidatePath, "utf-8");
|
|
2706
2949
|
break;
|
|
@@ -2729,14 +2972,14 @@ async function buildCommand(options) {
|
|
|
2729
2972
|
if (options.theme) {
|
|
2730
2973
|
themeName = options.theme;
|
|
2731
2974
|
try {
|
|
2732
|
-
const workspaceThemePath =
|
|
2975
|
+
const workspaceThemePath = path10.join(getThemesDir(), themeName);
|
|
2733
2976
|
if (fs.existsSync(workspaceThemePath)) {
|
|
2734
2977
|
themePath = workspaceThemePath;
|
|
2735
2978
|
} else {
|
|
2736
|
-
themePath =
|
|
2979
|
+
themePath = path10.join(process.cwd(), themeName);
|
|
2737
2980
|
}
|
|
2738
2981
|
} catch {
|
|
2739
|
-
themePath =
|
|
2982
|
+
themePath = path10.join(process.cwd(), themeName);
|
|
2740
2983
|
}
|
|
2741
2984
|
if (!fs.existsSync(themePath)) {
|
|
2742
2985
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -2747,10 +2990,10 @@ async function buildCommand(options) {
|
|
|
2747
2990
|
"theme.config.ts",
|
|
2748
2991
|
"bundle-entry.ts",
|
|
2749
2992
|
"manifest.ts"
|
|
2750
|
-
].some((f) => fs.existsSync(
|
|
2993
|
+
].some((f) => fs.existsSync(path10.join(process.cwd(), f)));
|
|
2751
2994
|
if (isThemeDir) {
|
|
2752
2995
|
themePath = process.cwd();
|
|
2753
|
-
themeName =
|
|
2996
|
+
themeName = path10.basename(themePath);
|
|
2754
2997
|
logger.info(`Building current theme: ${themeName}`);
|
|
2755
2998
|
} else {
|
|
2756
2999
|
logger.error(
|
|
@@ -2759,7 +3002,7 @@ async function buildCommand(options) {
|
|
|
2759
3002
|
process.exit(1);
|
|
2760
3003
|
}
|
|
2761
3004
|
}
|
|
2762
|
-
const packageJsonPath =
|
|
3005
|
+
const packageJsonPath = path10.join(themePath, "package.json");
|
|
2763
3006
|
const hasPkgJson = fs.existsSync(packageJsonPath);
|
|
2764
3007
|
if (!hasPkgJson) {
|
|
2765
3008
|
logger.warning(
|
|
@@ -2815,9 +3058,9 @@ async function buildCommand(options) {
|
|
|
2815
3058
|
logger.success("\u2713 Theme built successfully!");
|
|
2816
3059
|
logger.newLine();
|
|
2817
3060
|
logger.info(`Theme: ${themeName}`);
|
|
2818
|
-
const distPath =
|
|
3061
|
+
const distPath = path10.join(themePath, "dist");
|
|
2819
3062
|
if (fs.existsSync(distPath)) {
|
|
2820
|
-
logger.log(`Output: ${
|
|
3063
|
+
logger.log(`Output: ${path10.relative(process.cwd(), distPath)}`);
|
|
2821
3064
|
const files = fs.readdirSync(distPath);
|
|
2822
3065
|
logger.log(`Files: ${files.length}`);
|
|
2823
3066
|
}
|
|
@@ -2958,8 +3201,8 @@ async function downloadBundleZip(apiUrl, themeId, version) {
|
|
|
2958
3201
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
2959
3202
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
2960
3203
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
2961
|
-
const hashedPath =
|
|
2962
|
-
const stablePath =
|
|
3204
|
+
const hashedPath = path10.join(outputDir, entryFile);
|
|
3205
|
+
const stablePath = path10.join(outputDir, "bundle-entry.js");
|
|
2963
3206
|
if (await fs.pathExists(hashedPath)) {
|
|
2964
3207
|
await fs.copy(hashedPath, stablePath);
|
|
2965
3208
|
const mapPath = hashedPath + ".map";
|
|
@@ -2968,13 +3211,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
|
|
|
2968
3211
|
}
|
|
2969
3212
|
}
|
|
2970
3213
|
}
|
|
2971
|
-
const sectionsRegistryPath =
|
|
3214
|
+
const sectionsRegistryPath = path10.join(outputDir, "sections-registry.js");
|
|
2972
3215
|
const content = `// Re-export all sections from bundle-entry
|
|
2973
3216
|
// This file exists to maintain compatibility with the import path
|
|
2974
3217
|
export * from './bundle-entry.js';
|
|
2975
3218
|
`;
|
|
2976
3219
|
await fs.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
2977
|
-
const pkgJsonPath =
|
|
3220
|
+
const pkgJsonPath = path10.join(outputDir, "package.json");
|
|
2978
3221
|
await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
2979
3222
|
}
|
|
2980
3223
|
function showDownloadFailureHelp(themeId, apiUrl) {
|
|
@@ -3005,9 +3248,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3005
3248
|
console.log();
|
|
3006
3249
|
console.log(chalk4.white("2. Check API URL configuration:"));
|
|
3007
3250
|
console.log(chalk4.gray(` Current API URL: ${apiUrl}`));
|
|
3008
|
-
console.log(
|
|
3009
|
-
chalk4.gray(" Override with NEXT_PUBLIC_API_URL or ONEXTHM_API_URL")
|
|
3010
|
-
);
|
|
3251
|
+
console.log(chalk4.gray(" Override with ONEXTHM_API_URL env var if needed"));
|
|
3011
3252
|
console.log();
|
|
3012
3253
|
console.log(chalk4.white("3. Pin a specific version (CI/production):"));
|
|
3013
3254
|
console.log(
|
|
@@ -3017,15 +3258,17 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3017
3258
|
}
|
|
3018
3259
|
async function downloadCommand(options) {
|
|
3019
3260
|
logger.header("Download Theme");
|
|
3261
|
+
const env = options.env ?? "dev";
|
|
3262
|
+
const apiUrl = getApiUrl(env);
|
|
3263
|
+
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3020
3264
|
const spinner = ora("Initializing download...").start();
|
|
3021
|
-
if (options.bucket
|
|
3265
|
+
if (options.bucket) {
|
|
3022
3266
|
spinner.stop();
|
|
3023
3267
|
logger.warning(
|
|
3024
|
-
"--bucket
|
|
3268
|
+
"--bucket is deprecated and ignored. Themes are now served via HTTP from the website-api Lambda."
|
|
3025
3269
|
);
|
|
3026
3270
|
spinner.start();
|
|
3027
3271
|
}
|
|
3028
|
-
const apiUrl = getApiUrl();
|
|
3029
3272
|
try {
|
|
3030
3273
|
const themeId = options.themeId || process.env.NEXT_PUBLIC_THEME_ID || process.env.THEME_ID;
|
|
3031
3274
|
const requestedVersion = options.version || process.env.THEME_VERSION || "latest";
|
|
@@ -3073,7 +3316,7 @@ async function downloadCommand(options) {
|
|
|
3073
3316
|
zip.extractAllTo(outputDir, true);
|
|
3074
3317
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
3075
3318
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
3076
|
-
const manifestPath =
|
|
3319
|
+
const manifestPath = path10.join(outputDir, "manifest.json");
|
|
3077
3320
|
const manifest = await fs.readJson(manifestPath);
|
|
3078
3321
|
await createCompatibilityFiles(outputDir, manifest);
|
|
3079
3322
|
console.log();
|
|
@@ -3082,6 +3325,7 @@ async function downloadCommand(options) {
|
|
|
3082
3325
|
console.log(
|
|
3083
3326
|
chalk4.cyan(" Theme: ") + chalk4.white(`${themeId}@${resolvedVersion}`)
|
|
3084
3327
|
);
|
|
3328
|
+
console.log(chalk4.cyan(" Env: ") + chalk4.white(env));
|
|
3085
3329
|
console.log(chalk4.cyan(" Source: ") + chalk4.white(apiUrl));
|
|
3086
3330
|
console.log(chalk4.cyan(" Output: ") + chalk4.white(outputDir));
|
|
3087
3331
|
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
@@ -3124,11 +3368,9 @@ async function resolveLatestVersion2(apiUrl, themeId) {
|
|
|
3124
3368
|
}
|
|
3125
3369
|
return latest;
|
|
3126
3370
|
}
|
|
3127
|
-
async function fetchSourceZip(apiUrl, themeId, version) {
|
|
3371
|
+
async function fetchSourceZip(apiUrl, themeId, version, env) {
|
|
3128
3372
|
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/source?version=${encodeURIComponent(version)}`;
|
|
3129
|
-
const response = await authenticatedFetch(url, {
|
|
3130
|
-
method: "GET"
|
|
3131
|
-
});
|
|
3373
|
+
const response = await authenticatedFetch(url, { method: "GET" }, env);
|
|
3132
3374
|
if (!response.ok) {
|
|
3133
3375
|
if (response.status === 404) {
|
|
3134
3376
|
throw new Error(
|
|
@@ -3137,7 +3379,7 @@ async function fetchSourceZip(apiUrl, themeId, version) {
|
|
|
3137
3379
|
}
|
|
3138
3380
|
if (response.status === 401 || response.status === 403) {
|
|
3139
3381
|
throw new Error(
|
|
3140
|
-
`Not authorized to download source for "${themeId}". Run \`onexthm login\` first.`
|
|
3382
|
+
`Not authorized to download source for "${themeId}". Run \`onexthm login --env ${env}\` first.`
|
|
3141
3383
|
);
|
|
3142
3384
|
}
|
|
3143
3385
|
throw new Error(
|
|
@@ -3195,7 +3437,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3195
3437
|
const oldPrefix = `${oldName}-`;
|
|
3196
3438
|
const newPrefix = `${newName}-`;
|
|
3197
3439
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3198
|
-
const pkgPath =
|
|
3440
|
+
const pkgPath = path10.join(themeDir, "package.json");
|
|
3199
3441
|
if (await fs.pathExists(pkgPath)) {
|
|
3200
3442
|
const pkg = await fs.readJson(pkgPath);
|
|
3201
3443
|
pkg.name = `@onex-themes/${newName}`;
|
|
@@ -3211,7 +3453,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3211
3453
|
}
|
|
3212
3454
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3213
3455
|
}
|
|
3214
|
-
const configPath =
|
|
3456
|
+
const configPath = path10.join(themeDir, "theme.config.ts");
|
|
3215
3457
|
if (await fs.pathExists(configPath)) {
|
|
3216
3458
|
let content = await fs.readFile(configPath, "utf-8");
|
|
3217
3459
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3221,7 +3463,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3221
3463
|
);
|
|
3222
3464
|
await fs.writeFile(configPath, content);
|
|
3223
3465
|
}
|
|
3224
|
-
const layoutPath =
|
|
3466
|
+
const layoutPath = path10.join(themeDir, "theme.layout.ts");
|
|
3225
3467
|
if (await fs.pathExists(layoutPath)) {
|
|
3226
3468
|
let content = await fs.readFile(layoutPath, "utf-8");
|
|
3227
3469
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3234,7 +3476,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3234
3476
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3235
3477
|
const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
3236
3478
|
for (const file of tsFiles) {
|
|
3237
|
-
const filePath =
|
|
3479
|
+
const filePath = path10.join(themeDir, file);
|
|
3238
3480
|
let content = await fs.readFile(filePath, "utf-8");
|
|
3239
3481
|
const original = content;
|
|
3240
3482
|
content = content.replace(
|
|
@@ -3256,14 +3498,19 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3256
3498
|
}
|
|
3257
3499
|
async function cloneCommand(themeName, options) {
|
|
3258
3500
|
logger.header("Clone Theme Source");
|
|
3259
|
-
|
|
3501
|
+
const env = options.env ?? "dev";
|
|
3502
|
+
const apiUrl = getApiUrl(env);
|
|
3503
|
+
logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3504
|
+
if (options.bucket) {
|
|
3260
3505
|
logger.warning(
|
|
3261
|
-
"--bucket
|
|
3506
|
+
"--bucket is deprecated and ignored. Source is now fetched via HTTP from the website-api Lambda."
|
|
3262
3507
|
);
|
|
3263
3508
|
}
|
|
3264
|
-
const tokens = await getValidTokens();
|
|
3509
|
+
const tokens = await getValidTokens(env);
|
|
3265
3510
|
if (!tokens) {
|
|
3266
|
-
logger.error(
|
|
3511
|
+
logger.error(
|
|
3512
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
3513
|
+
);
|
|
3267
3514
|
process.exit(1);
|
|
3268
3515
|
}
|
|
3269
3516
|
let newName = options.name;
|
|
@@ -3272,8 +3519,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3272
3519
|
}
|
|
3273
3520
|
const spinner = ora("Initializing clone...").start();
|
|
3274
3521
|
try {
|
|
3275
|
-
const
|
|
3276
|
-
const outputDir = options.output || path8.resolve(process.cwd(), newName);
|
|
3522
|
+
const outputDir = options.output || path10.resolve(process.cwd(), newName);
|
|
3277
3523
|
if (await fs.pathExists(outputDir)) {
|
|
3278
3524
|
spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
|
|
3279
3525
|
logger.info(
|
|
@@ -3292,7 +3538,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3292
3538
|
spinner.start(`Downloading source.zip for ${themeName}@${version}...`);
|
|
3293
3539
|
let zipBuffer;
|
|
3294
3540
|
try {
|
|
3295
|
-
zipBuffer = await fetchSourceZip(apiUrl, themeName, version);
|
|
3541
|
+
zipBuffer = await fetchSourceZip(apiUrl, themeName, version, env);
|
|
3296
3542
|
} catch (error) {
|
|
3297
3543
|
spinner.fail(chalk4.red(error.message));
|
|
3298
3544
|
console.log();
|
|
@@ -3319,20 +3565,20 @@ async function cloneCommand(themeName, options) {
|
|
|
3319
3565
|
spinner.succeed(
|
|
3320
3566
|
`Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
|
|
3321
3567
|
);
|
|
3322
|
-
const envExamplePath =
|
|
3568
|
+
const envExamplePath = path10.join(outputDir, ".env.example");
|
|
3323
3569
|
if (!await fs.pathExists(envExamplePath)) {
|
|
3324
3570
|
await fs.writeFile(
|
|
3325
3571
|
envExamplePath,
|
|
3326
3572
|
[
|
|
3327
3573
|
"# API Configuration (enables real data in preview)",
|
|
3328
3574
|
"# Get your Company ID from the OneX dashboard",
|
|
3329
|
-
|
|
3575
|
+
`NEXT_PUBLIC_API_URL=${apiUrl}`,
|
|
3330
3576
|
"NEXT_PUBLIC_COMPANY_ID=",
|
|
3331
3577
|
""
|
|
3332
3578
|
].join("\n")
|
|
3333
3579
|
);
|
|
3334
3580
|
}
|
|
3335
|
-
const mcpJsonPath =
|
|
3581
|
+
const mcpJsonPath = path10.join(outputDir, ".mcp.json");
|
|
3336
3582
|
if (await fs.pathExists(mcpJsonPath)) {
|
|
3337
3583
|
const { default: inquirerMod } = await import('inquirer');
|
|
3338
3584
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
@@ -3357,7 +3603,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3357
3603
|
}
|
|
3358
3604
|
if (options.install !== false) {
|
|
3359
3605
|
const hasPkgJson = await fs.pathExists(
|
|
3360
|
-
|
|
3606
|
+
path10.join(outputDir, "package.json")
|
|
3361
3607
|
);
|
|
3362
3608
|
if (hasPkgJson) {
|
|
3363
3609
|
spinner.start("Installing dependencies...");
|
|
@@ -3379,12 +3625,13 @@ async function cloneCommand(themeName, options) {
|
|
|
3379
3625
|
console.log(
|
|
3380
3626
|
chalk4.cyan(" Source: ") + chalk4.gray(`${themeName}@${version}`)
|
|
3381
3627
|
);
|
|
3628
|
+
console.log(chalk4.cyan(" Env: ") + chalk4.white(env));
|
|
3382
3629
|
console.log(chalk4.cyan(" Theme: ") + chalk4.white(newName));
|
|
3383
3630
|
console.log(chalk4.cyan(" Location: ") + chalk4.white(outputDir));
|
|
3384
3631
|
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
3385
3632
|
console.log();
|
|
3386
3633
|
console.log(chalk4.cyan("Next steps:"));
|
|
3387
|
-
console.log(chalk4.gray(` cd ${
|
|
3634
|
+
console.log(chalk4.gray(` cd ${path10.relative(process.cwd(), outputDir)}`));
|
|
3388
3635
|
console.log(
|
|
3389
3636
|
chalk4.gray(" cp .env.example .env # then add your Company ID")
|
|
3390
3637
|
);
|