@onexapis/cli 1.1.37 → 1.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +639 -401
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +633 -396
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +255 -203
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +252 -200
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -4
- package/templates/default/CLAUDE.md +334 -1
- package/templates/default/esbuild.config.js +20 -0
- package/templates/default/pages/about.ts +2 -2
- package/templates/default/pages/forgot-password.ts +1 -3
- package/templates/default/pages/home.ts +4 -4
- package/templates/default/pages/login.ts +1 -3
- package/templates/default/pages/profile.ts +2 -2
- package/templates/default/pages/register.ts +1 -3
- package/templates/default/pages/showcase.ts +7 -7
- package/templates/default/pages/verify-code.ts +1 -3
- package/templates/default/sections/about/about.schema.ts +1 -1
- package/templates/default/sections/auth-forgot-password/auth-forgot-password.schema.ts +1 -1
- package/templates/default/sections/auth-login/auth-login.schema.ts +1 -1
- package/templates/default/sections/auth-register/auth-register.schema.ts +1 -1
- package/templates/default/sections/auth-verify-code/auth-verify-code.schema.ts +1 -1
- package/templates/default/sections/cta/cta.schema.ts +1 -1
- package/templates/default/sections/features/features.schema.ts +1 -1
- package/templates/default/sections/footer/footer.schema.ts +1 -1
- package/templates/default/sections/gallery/gallery.schema.ts +1 -1
- package/templates/default/sections/header/header.schema.ts +1 -1
- package/templates/default/sections/hero/hero.schema.ts +1 -1
- package/templates/default/sections/profile/profile.schema.ts +1 -1
- package/templates/default/sections/stats/stats.schema.ts +1 -1
- package/templates/default/sections/testimonials/testimonials.schema.ts +1 -1
- package/templates/default/theme.layout.ts +18 -0
package/dist/cli.mjs
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
import chalk4 from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
4
|
import * as esbuild from 'esbuild';
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
5
|
+
import path9 from 'path';
|
|
6
|
+
import fs8 from 'fs/promises';
|
|
7
|
+
import crypto from 'crypto';
|
|
8
8
|
import { glob } from 'glob';
|
|
9
9
|
import { createRequire } from 'module';
|
|
10
|
-
import
|
|
10
|
+
import os from 'os';
|
|
11
11
|
import dotenv from 'dotenv';
|
|
12
12
|
import fs from 'fs-extra';
|
|
13
13
|
import ejs from 'ejs';
|
|
14
14
|
import { execSync, spawn } from 'child_process';
|
|
15
15
|
import { Command } from 'commander';
|
|
16
|
-
import
|
|
16
|
+
import fs3 from 'fs';
|
|
17
17
|
import inquirer from 'inquirer';
|
|
18
18
|
import archiver from 'archiver';
|
|
19
19
|
import FormData from 'form-data';
|
|
@@ -23,6 +23,7 @@ import AdmZip from 'adm-zip';
|
|
|
23
23
|
import chokidar from 'chokidar';
|
|
24
24
|
import http from 'http';
|
|
25
25
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
26
|
+
import semver from 'semver';
|
|
26
27
|
|
|
27
28
|
var __defProp = Object.defineProperty;
|
|
28
29
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -104,8 +105,8 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
104
105
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
105
106
|
const tailwindConfig = {
|
|
106
107
|
content: [
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
path9.join(themePath, "sections/**/*.{ts,tsx}"),
|
|
109
|
+
path9.join(themePath, "components/**/*.{ts,tsx}")
|
|
109
110
|
],
|
|
110
111
|
theme: { extend: {} },
|
|
111
112
|
plugins: []
|
|
@@ -115,7 +116,7 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
115
116
|
inputCSS,
|
|
116
117
|
{ from: void 0 }
|
|
117
118
|
);
|
|
118
|
-
await
|
|
119
|
+
await fs8.writeFile(path9.join(outDir, "bundle.css"), result.css);
|
|
119
120
|
logger.info("Generated bundle.css");
|
|
120
121
|
} catch (err) {
|
|
121
122
|
logger.warning(
|
|
@@ -126,12 +127,12 @@ async function generateThemeCSS(themePath, outDir) {
|
|
|
126
127
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
127
128
|
let dir = startDir;
|
|
128
129
|
while (true) {
|
|
129
|
-
const candidate =
|
|
130
|
+
const candidate = path9.join(dir, "node_modules", relativePath);
|
|
130
131
|
try {
|
|
131
|
-
await
|
|
132
|
+
await fs8.access(candidate);
|
|
132
133
|
return candidate;
|
|
133
134
|
} catch {
|
|
134
|
-
const parent =
|
|
135
|
+
const parent = path9.dirname(dir);
|
|
135
136
|
if (parent === dir) break;
|
|
136
137
|
dir = parent;
|
|
137
138
|
}
|
|
@@ -155,7 +156,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
|
|
|
155
156
|
});
|
|
156
157
|
for (const file of sourceFiles) {
|
|
157
158
|
try {
|
|
158
|
-
const content = await
|
|
159
|
+
const content = await fs8.readFile(path9.join(sourceDir, file), "utf-8");
|
|
159
160
|
for (const match of content.matchAll(namespaceImportRegex)) {
|
|
160
161
|
const subpath = match[1] ? match[1].slice(1) : "";
|
|
161
162
|
if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
|
|
@@ -209,17 +210,17 @@ function createCoreGlobalPlugin(themePath) {
|
|
|
209
210
|
const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
|
|
210
211
|
let distPath = await resolveNodeModulesFile(
|
|
211
212
|
themePath,
|
|
212
|
-
|
|
213
|
+
path9.join("@onexapis", "core", "dist", distFileName)
|
|
213
214
|
);
|
|
214
215
|
if (!distPath) {
|
|
215
216
|
distPath = await resolveNodeModulesFile(
|
|
216
217
|
__dirname,
|
|
217
|
-
|
|
218
|
+
path9.join("@onexapis", "core", "dist", distFileName)
|
|
218
219
|
);
|
|
219
220
|
}
|
|
220
221
|
try {
|
|
221
222
|
if (!distPath) throw new Error("not found");
|
|
222
|
-
const distContent = await
|
|
223
|
+
const distContent = await fs8.readFile(distPath, "utf-8");
|
|
223
224
|
const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
|
|
224
225
|
for (const m of exportMatches) {
|
|
225
226
|
const names = m[1].split(",").map((n) => {
|
|
@@ -448,7 +449,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
448
449
|
const pages = {};
|
|
449
450
|
for (const ext of [".ts", ".js"]) {
|
|
450
451
|
try {
|
|
451
|
-
const mod = await jiti.import(
|
|
452
|
+
const mod = await jiti.import(path9.join(themePath, `theme.config${ext}`));
|
|
452
453
|
themeConfig = mod.default || mod;
|
|
453
454
|
break;
|
|
454
455
|
} catch {
|
|
@@ -456,20 +457,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
456
457
|
}
|
|
457
458
|
for (const ext of [".ts", ".js"]) {
|
|
458
459
|
try {
|
|
459
|
-
const mod = await jiti.import(
|
|
460
|
+
const mod = await jiti.import(path9.join(themePath, `theme.layout${ext}`));
|
|
460
461
|
layoutConfig = mod.default || mod;
|
|
461
462
|
break;
|
|
462
463
|
} catch {
|
|
463
464
|
}
|
|
464
465
|
}
|
|
465
466
|
const schemas = {};
|
|
466
|
-
const sectionsDir =
|
|
467
|
+
const sectionsDir = path9.join(themePath, "sections");
|
|
467
468
|
try {
|
|
468
|
-
const sectionDirs = await
|
|
469
|
+
const sectionDirs = await fs8.readdir(sectionsDir);
|
|
469
470
|
for (const dir of sectionDirs) {
|
|
470
|
-
const schemaFile =
|
|
471
|
+
const schemaFile = path9.join(sectionsDir, dir, `${dir}.schema.ts`);
|
|
471
472
|
try {
|
|
472
|
-
await
|
|
473
|
+
await fs8.access(schemaFile);
|
|
473
474
|
const mod = await jiti.import(schemaFile);
|
|
474
475
|
for (const [key, value] of Object.entries(mod)) {
|
|
475
476
|
if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
|
|
@@ -481,14 +482,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
481
482
|
}
|
|
482
483
|
} catch {
|
|
483
484
|
}
|
|
484
|
-
const pagesDir =
|
|
485
|
+
const pagesDir = path9.join(themePath, "pages");
|
|
485
486
|
try {
|
|
486
|
-
const files = await
|
|
487
|
+
const files = await fs8.readdir(pagesDir);
|
|
487
488
|
for (const file of files) {
|
|
488
489
|
if (!file.match(/\.(ts|js)$/)) continue;
|
|
489
490
|
const name = file.replace(/\.(ts|js)$/, "");
|
|
490
491
|
try {
|
|
491
|
-
const mod = await jiti.import(
|
|
492
|
+
const mod = await jiti.import(path9.join(pagesDir, file));
|
|
492
493
|
const config = mod.default || mod;
|
|
493
494
|
const sections = (config.sections || []).map((section) => {
|
|
494
495
|
const schema = schemas[section.type];
|
|
@@ -516,8 +517,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
516
517
|
}
|
|
517
518
|
} catch {
|
|
518
519
|
}
|
|
519
|
-
await
|
|
520
|
-
|
|
520
|
+
await fs8.writeFile(
|
|
521
|
+
path9.join(outputDir, "theme-data.json"),
|
|
521
522
|
JSON.stringify(
|
|
522
523
|
{
|
|
523
524
|
themeId,
|
|
@@ -540,53 +541,53 @@ async function generateThemeData(themePath, outputDir, themeId) {
|
|
|
540
541
|
logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
|
|
541
542
|
}
|
|
542
543
|
async function contentHashEntry(outputDir) {
|
|
543
|
-
const entryPath =
|
|
544
|
-
const mapPath =
|
|
544
|
+
const entryPath = path9.join(outputDir, "bundle-entry.js");
|
|
545
|
+
const mapPath = path9.join(outputDir, "bundle-entry.js.map");
|
|
545
546
|
const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
|
|
546
547
|
for (const f of oldFiles) {
|
|
547
|
-
await
|
|
548
|
+
await fs8.unlink(path9.join(outputDir, f));
|
|
548
549
|
}
|
|
549
550
|
let entryContent;
|
|
550
551
|
try {
|
|
551
|
-
entryContent = await
|
|
552
|
+
entryContent = await fs8.readFile(entryPath, "utf-8");
|
|
552
553
|
} catch {
|
|
553
|
-
const indexPath =
|
|
554
|
+
const indexPath = path9.join(outputDir, "index.js");
|
|
554
555
|
try {
|
|
555
|
-
entryContent = await
|
|
556
|
+
entryContent = await fs8.readFile(indexPath, "utf-8");
|
|
556
557
|
} catch {
|
|
557
558
|
logger.warning("No entry file found in output, skipping content hash");
|
|
558
559
|
return;
|
|
559
560
|
}
|
|
560
|
-
const hash2 =
|
|
561
|
+
const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
561
562
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
562
|
-
const indexMapPath =
|
|
563
|
+
const indexMapPath = path9.join(outputDir, "index.js.map");
|
|
563
564
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
564
565
|
entryContent = entryContent.replace(
|
|
565
566
|
/\/\/# sourceMappingURL=index\.js\.map/,
|
|
566
567
|
`//# sourceMappingURL=${hashedMapName2}`
|
|
567
568
|
);
|
|
568
|
-
await
|
|
569
|
-
await
|
|
569
|
+
await fs8.writeFile(path9.join(outputDir, hashedName2), entryContent);
|
|
570
|
+
await fs8.unlink(indexPath);
|
|
570
571
|
try {
|
|
571
|
-
await
|
|
572
|
-
await
|
|
572
|
+
await fs8.access(indexMapPath);
|
|
573
|
+
await fs8.rename(indexMapPath, path9.join(outputDir, hashedMapName2));
|
|
573
574
|
} catch {
|
|
574
575
|
}
|
|
575
576
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
576
577
|
return;
|
|
577
578
|
}
|
|
578
|
-
const hash =
|
|
579
|
+
const hash = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
579
580
|
const hashedName = `bundle-entry-${hash}.js`;
|
|
580
581
|
const hashedMapName = `bundle-entry-${hash}.js.map`;
|
|
581
582
|
entryContent = entryContent.replace(
|
|
582
583
|
/\/\/# sourceMappingURL=bundle-entry\.js\.map/,
|
|
583
584
|
`//# sourceMappingURL=${hashedMapName}`
|
|
584
585
|
);
|
|
585
|
-
await
|
|
586
|
-
await
|
|
586
|
+
await fs8.writeFile(path9.join(outputDir, hashedName), entryContent);
|
|
587
|
+
await fs8.unlink(entryPath);
|
|
587
588
|
try {
|
|
588
|
-
await
|
|
589
|
-
await
|
|
589
|
+
await fs8.access(mapPath);
|
|
590
|
+
await fs8.rename(mapPath, path9.join(outputDir, hashedMapName));
|
|
590
591
|
} catch {
|
|
591
592
|
}
|
|
592
593
|
logger.info(`Entry hashed: ${hashedName}`);
|
|
@@ -598,7 +599,7 @@ async function extractDataRequirements(themePath) {
|
|
|
598
599
|
const requirements = {};
|
|
599
600
|
for (const file of schemaFiles) {
|
|
600
601
|
try {
|
|
601
|
-
const mod = await jiti.import(
|
|
602
|
+
const mod = await jiti.import(path9.join(themePath, file));
|
|
602
603
|
const exports$1 = mod;
|
|
603
604
|
for (const value of Object.values(exports$1)) {
|
|
604
605
|
if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
|
|
@@ -617,8 +618,8 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
617
618
|
let version2 = "1.0.0";
|
|
618
619
|
let themeId = themeName;
|
|
619
620
|
try {
|
|
620
|
-
const pkgContent = await
|
|
621
|
-
|
|
621
|
+
const pkgContent = await fs8.readFile(
|
|
622
|
+
path9.join(themePath, "package.json"),
|
|
622
623
|
"utf-8"
|
|
623
624
|
);
|
|
624
625
|
const pkg = JSON.parse(pkgContent);
|
|
@@ -636,7 +637,7 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
636
637
|
const dataRequirements = await extractDataRequirements(themePath);
|
|
637
638
|
let hasThemeConfig = false;
|
|
638
639
|
try {
|
|
639
|
-
await
|
|
640
|
+
await fs8.access(path9.join(themePath, "theme.config.ts"));
|
|
640
641
|
hasThemeConfig = true;
|
|
641
642
|
} catch {
|
|
642
643
|
}
|
|
@@ -677,24 +678,24 @@ async function generateManifest(themeName, themePath, outputDir) {
|
|
|
677
678
|
// Section data requirements for server-side prefetching (keyed by section type)
|
|
678
679
|
dataRequirements
|
|
679
680
|
};
|
|
680
|
-
await
|
|
681
|
-
|
|
681
|
+
await fs8.writeFile(
|
|
682
|
+
path9.join(outputDir, "manifest.json"),
|
|
682
683
|
JSON.stringify(manifest, null, 2)
|
|
683
684
|
);
|
|
684
685
|
}
|
|
685
686
|
async function compileStandaloneTheme(themePath, themeName) {
|
|
686
|
-
const outputDir =
|
|
687
|
-
const bundleEntry =
|
|
688
|
-
const indexEntry =
|
|
687
|
+
const outputDir = path9.join(themePath, "dist");
|
|
688
|
+
const bundleEntry = path9.join(themePath, "bundle-entry.ts");
|
|
689
|
+
const indexEntry = path9.join(themePath, "index.ts");
|
|
689
690
|
let entryPoint = indexEntry;
|
|
690
691
|
try {
|
|
691
|
-
await
|
|
692
|
+
await fs8.access(bundleEntry);
|
|
692
693
|
entryPoint = bundleEntry;
|
|
693
694
|
} catch {
|
|
694
695
|
}
|
|
695
|
-
const shimPath =
|
|
696
|
-
await
|
|
697
|
-
await
|
|
696
|
+
const shimPath = path9.join(outputDir, ".process-shim.js");
|
|
697
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
698
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
698
699
|
const buildOptions = {
|
|
699
700
|
entryPoints: [entryPoint],
|
|
700
701
|
bundle: true,
|
|
@@ -744,7 +745,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
744
745
|
try {
|
|
745
746
|
const result = await esbuild.build(buildOptions);
|
|
746
747
|
try {
|
|
747
|
-
await
|
|
748
|
+
await fs8.unlink(shimPath);
|
|
748
749
|
} catch {
|
|
749
750
|
}
|
|
750
751
|
await contentHashEntry(outputDir);
|
|
@@ -763,7 +764,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
763
764
|
return true;
|
|
764
765
|
} catch (error) {
|
|
765
766
|
try {
|
|
766
|
-
await
|
|
767
|
+
await fs8.unlink(shimPath);
|
|
767
768
|
} catch {
|
|
768
769
|
}
|
|
769
770
|
logger.error(`esbuild compilation failed: ${error}`);
|
|
@@ -771,18 +772,18 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
771
772
|
}
|
|
772
773
|
}
|
|
773
774
|
async function compileStandaloneThemeDev(themePath, themeName) {
|
|
774
|
-
const outputDir =
|
|
775
|
-
const bundleEntry =
|
|
776
|
-
const indexEntry =
|
|
775
|
+
const outputDir = path9.join(themePath, "dist");
|
|
776
|
+
const bundleEntry = path9.join(themePath, "bundle-entry.ts");
|
|
777
|
+
const indexEntry = path9.join(themePath, "index.ts");
|
|
777
778
|
let entryPoint = indexEntry;
|
|
778
779
|
try {
|
|
779
|
-
await
|
|
780
|
+
await fs8.access(bundleEntry);
|
|
780
781
|
entryPoint = bundleEntry;
|
|
781
782
|
} catch {
|
|
782
783
|
}
|
|
783
|
-
const shimPath =
|
|
784
|
-
await
|
|
785
|
-
await
|
|
784
|
+
const shimPath = path9.join(outputDir, ".process-shim.js");
|
|
785
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
786
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
786
787
|
const buildOptions = {
|
|
787
788
|
entryPoints: [entryPoint],
|
|
788
789
|
bundle: true,
|
|
@@ -835,18 +836,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
835
836
|
return { context: context2, outputDir };
|
|
836
837
|
}
|
|
837
838
|
async function compilePreviewRuntime(themePath) {
|
|
838
|
-
const outputDir =
|
|
839
|
-
await
|
|
840
|
-
const outputPath =
|
|
839
|
+
const outputDir = path9.join(themePath, "dist");
|
|
840
|
+
await fs8.mkdir(outputDir, { recursive: true });
|
|
841
|
+
const outputPath = path9.join(outputDir, "preview-runtime.js");
|
|
841
842
|
const locations = [
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
843
|
+
path9.join(__dirname, "..", "preview", "preview-app.tsx"),
|
|
844
|
+
path9.join(__dirname, "preview", "preview-app.tsx"),
|
|
845
|
+
path9.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
|
|
845
846
|
];
|
|
846
847
|
let previewEntryPath = null;
|
|
847
848
|
for (const loc of locations) {
|
|
848
849
|
try {
|
|
849
|
-
await
|
|
850
|
+
await fs8.access(loc);
|
|
850
851
|
previewEntryPath = loc;
|
|
851
852
|
break;
|
|
852
853
|
} catch {
|
|
@@ -929,10 +930,10 @@ ${locations.join("\n")}`
|
|
|
929
930
|
if (!lucideScanned) {
|
|
930
931
|
lucideScanned = true;
|
|
931
932
|
const coreSrcCandidates = [
|
|
932
|
-
|
|
933
|
-
|
|
933
|
+
path9.join(themePath, "node_modules", "@onexapis", "core", "src"),
|
|
934
|
+
path9.join(themePath, "..", "..", "packages", "core", "src"),
|
|
934
935
|
// monorepo sibling
|
|
935
|
-
|
|
936
|
+
path9.join(
|
|
936
937
|
__dirname,
|
|
937
938
|
"..",
|
|
938
939
|
"..",
|
|
@@ -947,7 +948,7 @@ ${locations.join("\n")}`
|
|
|
947
948
|
let coreSourceDir = null;
|
|
948
949
|
for (const candidate of coreSrcCandidates) {
|
|
949
950
|
try {
|
|
950
|
-
await
|
|
951
|
+
await fs8.access(candidate);
|
|
951
952
|
coreSourceDir = candidate;
|
|
952
953
|
break;
|
|
953
954
|
} catch {
|
|
@@ -966,21 +967,21 @@ ${locations.join("\n")}`
|
|
|
966
967
|
}
|
|
967
968
|
} else {
|
|
968
969
|
const coreDistCandidates = [
|
|
969
|
-
|
|
970
|
+
path9.join(themePath, "node_modules", "@onexapis", "core", "dist")
|
|
970
971
|
];
|
|
971
972
|
const resolvedDist = await resolveNodeModulesFile(
|
|
972
973
|
__dirname,
|
|
973
|
-
|
|
974
|
+
path9.join("@onexapis", "core", "dist")
|
|
974
975
|
);
|
|
975
976
|
if (resolvedDist) coreDistCandidates.push(resolvedDist);
|
|
976
977
|
for (const candidate of coreDistCandidates) {
|
|
977
978
|
try {
|
|
978
|
-
await
|
|
979
|
+
await fs8.access(candidate);
|
|
979
980
|
const mjsFiles = await glob("*.mjs", { cwd: candidate });
|
|
980
981
|
const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
|
|
981
982
|
for (const file of mjsFiles) {
|
|
982
|
-
const content = await
|
|
983
|
-
|
|
983
|
+
const content = await fs8.readFile(
|
|
984
|
+
path9.join(candidate, file),
|
|
984
985
|
"utf-8"
|
|
985
986
|
);
|
|
986
987
|
for (const match of content.matchAll(importRegex)) {
|
|
@@ -1035,7 +1036,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
|
|
|
1035
1036
|
const req = createRequire(import.meta.url || __filename);
|
|
1036
1037
|
const cjsPath = req.resolve("framer-motion");
|
|
1037
1038
|
const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
|
|
1038
|
-
const esmEntry =
|
|
1039
|
+
const esmEntry = path9.join(pkgDir, "dist", "es", "index.mjs");
|
|
1039
1040
|
const { existsSync } = await import('fs');
|
|
1040
1041
|
if (existsSync(esmEntry)) {
|
|
1041
1042
|
return { path: esmEntry, namespace: "file" };
|
|
@@ -1134,8 +1135,8 @@ export function headers() { return new Headers(); }
|
|
|
1134
1135
|
});
|
|
1135
1136
|
}
|
|
1136
1137
|
};
|
|
1137
|
-
const shimPath =
|
|
1138
|
-
await
|
|
1138
|
+
const shimPath = path9.join(outputDir, ".process-shim-preview.js");
|
|
1139
|
+
await fs8.writeFile(shimPath, PROCESS_SHIM);
|
|
1139
1140
|
await esbuild.build({
|
|
1140
1141
|
entryPoints: [previewEntryPath],
|
|
1141
1142
|
bundle: true,
|
|
@@ -1170,7 +1171,7 @@ export function headers() { return new Headers(); }
|
|
|
1170
1171
|
}
|
|
1171
1172
|
});
|
|
1172
1173
|
try {
|
|
1173
|
-
await
|
|
1174
|
+
await fs8.unlink(shimPath);
|
|
1174
1175
|
} catch {
|
|
1175
1176
|
}
|
|
1176
1177
|
return outputPath;
|
|
@@ -1303,18 +1304,18 @@ async function renderTemplate(templatePath, data) {
|
|
|
1303
1304
|
return ejs.render(template, data);
|
|
1304
1305
|
}
|
|
1305
1306
|
async function writeFile(filePath, content) {
|
|
1306
|
-
await fs.ensureDir(
|
|
1307
|
+
await fs.ensureDir(path9.dirname(filePath));
|
|
1307
1308
|
await fs.writeFile(filePath, content, "utf-8");
|
|
1308
1309
|
}
|
|
1309
1310
|
function getTemplatesDir() {
|
|
1310
1311
|
const locations = [
|
|
1311
|
-
|
|
1312
|
+
path9.join(__dirname, "../../templates"),
|
|
1312
1313
|
// Development
|
|
1313
|
-
|
|
1314
|
+
path9.join(__dirname, "../templates"),
|
|
1314
1315
|
// Production (dist/)
|
|
1315
|
-
|
|
1316
|
+
path9.join(process.cwd(), "templates"),
|
|
1316
1317
|
// Fallback
|
|
1317
|
-
|
|
1318
|
+
path9.join(process.cwd(), "packages/cli/templates")
|
|
1318
1319
|
// Monorepo
|
|
1319
1320
|
];
|
|
1320
1321
|
for (const location of locations) {
|
|
@@ -1326,7 +1327,7 @@ function getTemplatesDir() {
|
|
|
1326
1327
|
}
|
|
1327
1328
|
async function copyTemplate(templateName, targetDir, data) {
|
|
1328
1329
|
const templatesDir = getTemplatesDir();
|
|
1329
|
-
const templateDir =
|
|
1330
|
+
const templateDir = path9.join(templatesDir, templateName);
|
|
1330
1331
|
if (!fs.existsSync(templateDir)) {
|
|
1331
1332
|
throw new Error(
|
|
1332
1333
|
`Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
|
|
@@ -1335,8 +1336,8 @@ async function copyTemplate(templateName, targetDir, data) {
|
|
|
1335
1336
|
await fs.ensureDir(targetDir);
|
|
1336
1337
|
const files = await fs.readdir(templateDir);
|
|
1337
1338
|
for (const file of files) {
|
|
1338
|
-
const templatePath =
|
|
1339
|
-
const targetPath =
|
|
1339
|
+
const templatePath = path9.join(templateDir, file);
|
|
1340
|
+
const targetPath = path9.join(targetDir, file);
|
|
1340
1341
|
const stat = await fs.stat(templatePath);
|
|
1341
1342
|
if (stat.isDirectory()) {
|
|
1342
1343
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1353,8 +1354,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1353
1354
|
await fs.ensureDir(targetDir);
|
|
1354
1355
|
const files = await fs.readdir(templateDir);
|
|
1355
1356
|
for (const file of files) {
|
|
1356
|
-
const templatePath =
|
|
1357
|
-
const targetPath =
|
|
1357
|
+
const templatePath = path9.join(templateDir, file);
|
|
1358
|
+
const targetPath = path9.join(targetDir, file);
|
|
1358
1359
|
const stat = await fs.stat(templatePath);
|
|
1359
1360
|
if (stat.isDirectory()) {
|
|
1360
1361
|
await copyTemplateDir(templatePath, targetPath, data);
|
|
@@ -1369,32 +1370,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
|
|
|
1369
1370
|
}
|
|
1370
1371
|
function getProjectRoot() {
|
|
1371
1372
|
let currentDir = process.cwd();
|
|
1372
|
-
while (currentDir !==
|
|
1373
|
-
const packageJsonPath =
|
|
1373
|
+
while (currentDir !== path9.parse(currentDir).root) {
|
|
1374
|
+
const packageJsonPath = path9.join(currentDir, "package.json");
|
|
1374
1375
|
if (fs.existsSync(packageJsonPath)) {
|
|
1375
1376
|
const packageJson = fs.readJsonSync(packageJsonPath);
|
|
1376
|
-
if (packageJson.workspaces || fs.existsSync(
|
|
1377
|
+
if (packageJson.workspaces || fs.existsSync(path9.join(currentDir, "src/themes")) || fs.existsSync(path9.join(currentDir, "themes"))) {
|
|
1377
1378
|
return currentDir;
|
|
1378
1379
|
}
|
|
1379
1380
|
}
|
|
1380
|
-
currentDir =
|
|
1381
|
+
currentDir = path9.dirname(currentDir);
|
|
1381
1382
|
}
|
|
1382
1383
|
return process.cwd();
|
|
1383
1384
|
}
|
|
1384
1385
|
function getThemesDir() {
|
|
1385
1386
|
const root = getProjectRoot();
|
|
1386
|
-
if (fs.existsSync(
|
|
1387
|
-
return
|
|
1388
|
-
if (fs.existsSync(
|
|
1389
|
-
return
|
|
1390
|
-
return
|
|
1387
|
+
if (fs.existsSync(path9.join(root, "themes")))
|
|
1388
|
+
return path9.join(root, "themes");
|
|
1389
|
+
if (fs.existsSync(path9.join(root, "src/themes")))
|
|
1390
|
+
return path9.join(root, "src/themes");
|
|
1391
|
+
return path9.dirname(root);
|
|
1391
1392
|
}
|
|
1392
1393
|
function getFeaturesDir() {
|
|
1393
|
-
return
|
|
1394
|
+
return path9.join(getProjectRoot(), "src/features");
|
|
1394
1395
|
}
|
|
1395
1396
|
function isOneXProject() {
|
|
1396
1397
|
const root = getProjectRoot();
|
|
1397
|
-
return fs.existsSync(
|
|
1398
|
+
return fs.existsSync(path9.join(root, "themes")) || fs.existsSync(path9.join(root, "src/themes")) || fs.existsSync(path9.join(root, "theme.config.ts")) || fs.existsSync(path9.join(root, "bundle-entry.ts"));
|
|
1398
1399
|
}
|
|
1399
1400
|
function ensureOneXProject() {
|
|
1400
1401
|
if (!isOneXProject()) {
|
|
@@ -1410,13 +1411,13 @@ function listThemes() {
|
|
|
1410
1411
|
return [];
|
|
1411
1412
|
}
|
|
1412
1413
|
return fs.readdirSync(themesDir).filter((name) => {
|
|
1413
|
-
const themePath =
|
|
1414
|
-
return fs.statSync(themePath).isDirectory() && (fs.existsSync(
|
|
1414
|
+
const themePath = path9.join(themesDir, name);
|
|
1415
|
+
return fs.statSync(themePath).isDirectory() && (fs.existsSync(path9.join(themePath, "theme.config.ts")) || fs.existsSync(path9.join(themePath, "bundle-entry.ts")) || fs.existsSync(path9.join(themePath, "manifest.ts")));
|
|
1415
1416
|
});
|
|
1416
1417
|
}
|
|
1417
1418
|
function themeExists(themeName) {
|
|
1418
|
-
const themePath =
|
|
1419
|
-
return fs.existsSync(themePath) && (fs.existsSync(
|
|
1419
|
+
const themePath = path9.join(getThemesDir(), themeName);
|
|
1420
|
+
return fs.existsSync(themePath) && (fs.existsSync(path9.join(themePath, "theme.config.ts")) || fs.existsSync(path9.join(themePath, "bundle-entry.ts")) || fs.existsSync(path9.join(themePath, "manifest.ts")));
|
|
1420
1421
|
}
|
|
1421
1422
|
function detectPackageManager() {
|
|
1422
1423
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -1424,9 +1425,9 @@ function detectPackageManager() {
|
|
|
1424
1425
|
if (userAgent.includes("yarn")) return "yarn";
|
|
1425
1426
|
if (userAgent.includes("bun")) return "bun";
|
|
1426
1427
|
const cwd = process.cwd();
|
|
1427
|
-
if (fs.existsSync(
|
|
1428
|
-
if (fs.existsSync(
|
|
1429
|
-
if (fs.existsSync(
|
|
1428
|
+
if (fs.existsSync(path9.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
1429
|
+
if (fs.existsSync(path9.join(cwd, "yarn.lock"))) return "yarn";
|
|
1430
|
+
if (fs.existsSync(path9.join(cwd, "bun.lockb"))) return "bun";
|
|
1430
1431
|
return "npm";
|
|
1431
1432
|
}
|
|
1432
1433
|
async function installDependencies(projectPath, packageManager = "npm") {
|
|
@@ -1475,6 +1476,120 @@ function getValidCategories() {
|
|
|
1475
1476
|
"contact"
|
|
1476
1477
|
];
|
|
1477
1478
|
}
|
|
1479
|
+
var AUTH_DIR = path9.join(os.homedir(), ".onexthm");
|
|
1480
|
+
var AUTH_FILE = path9.join(AUTH_DIR, "auth.json");
|
|
1481
|
+
function getApiUrl() {
|
|
1482
|
+
return process.env.ONEXTHM_API_URL || process.env.NEXT_PUBLIC_API_URL || "https://platform-dev.onexeos.com";
|
|
1483
|
+
}
|
|
1484
|
+
async function saveAuthTokens(tokens) {
|
|
1485
|
+
await fs.ensureDir(AUTH_DIR);
|
|
1486
|
+
const key = getMachineKey();
|
|
1487
|
+
const data = JSON.stringify(tokens);
|
|
1488
|
+
const encrypted = encrypt(data, key);
|
|
1489
|
+
await fs.writeFile(AUTH_FILE, encrypted, "utf-8");
|
|
1490
|
+
}
|
|
1491
|
+
function loadAuthTokens() {
|
|
1492
|
+
try {
|
|
1493
|
+
if (!fs.existsSync(AUTH_FILE)) return null;
|
|
1494
|
+
const encrypted = fs.readFileSync(AUTH_FILE, "utf-8");
|
|
1495
|
+
const key = getMachineKey();
|
|
1496
|
+
const data = decrypt(encrypted, key);
|
|
1497
|
+
return JSON.parse(data);
|
|
1498
|
+
} catch {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
async function clearAuthTokens() {
|
|
1503
|
+
try {
|
|
1504
|
+
await fs.remove(AUTH_FILE);
|
|
1505
|
+
} catch {
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
function isTokenExpired(tokens) {
|
|
1509
|
+
return Date.now() / 1e3 > tokens.expiresAt - 60;
|
|
1510
|
+
}
|
|
1511
|
+
async function getValidTokens() {
|
|
1512
|
+
const tokens = loadAuthTokens();
|
|
1513
|
+
if (!tokens) return null;
|
|
1514
|
+
if (!isTokenExpired(tokens)) return tokens;
|
|
1515
|
+
try {
|
|
1516
|
+
const apiUrl = getApiUrl();
|
|
1517
|
+
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
1518
|
+
method: "POST",
|
|
1519
|
+
headers: { "Content-Type": "application/json" },
|
|
1520
|
+
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
1521
|
+
});
|
|
1522
|
+
if (!response.ok) {
|
|
1523
|
+
await clearAuthTokens();
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
const data = await response.json();
|
|
1527
|
+
const body = data.statusCode ? data.body : data;
|
|
1528
|
+
const refreshed = {
|
|
1529
|
+
...tokens,
|
|
1530
|
+
accessToken: body.AccessToken || tokens.accessToken,
|
|
1531
|
+
idToken: body.IdToken || tokens.idToken,
|
|
1532
|
+
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
1533
|
+
};
|
|
1534
|
+
await saveAuthTokens(refreshed);
|
|
1535
|
+
return refreshed;
|
|
1536
|
+
} catch {
|
|
1537
|
+
await clearAuthTokens();
|
|
1538
|
+
return null;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
async function authenticatedFetch(url, init) {
|
|
1542
|
+
const tokens = await getValidTokens();
|
|
1543
|
+
if (!tokens) {
|
|
1544
|
+
throw new Error("Not logged in. Run: onexthm login");
|
|
1545
|
+
}
|
|
1546
|
+
const headers = new Headers(init?.headers);
|
|
1547
|
+
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
1548
|
+
headers.set("Content-Type", "application/json");
|
|
1549
|
+
return fetch(url, { ...init, headers });
|
|
1550
|
+
}
|
|
1551
|
+
function getMachineKey() {
|
|
1552
|
+
let seed;
|
|
1553
|
+
if (process.platform === "darwin") {
|
|
1554
|
+
seed = `onexthm:${os.hostname()}:${os.userInfo().username}`;
|
|
1555
|
+
} else if (process.platform === "linux") {
|
|
1556
|
+
try {
|
|
1557
|
+
seed = `onexthm:${fs.readFileSync("/etc/machine-id", "utf-8").trim()}`;
|
|
1558
|
+
} catch {
|
|
1559
|
+
seed = `onexthm:${os.hostname()}:${os.userInfo().username}`;
|
|
1560
|
+
}
|
|
1561
|
+
} else {
|
|
1562
|
+
seed = `onexthm:${os.hostname()}:${os.userInfo().username}`;
|
|
1563
|
+
}
|
|
1564
|
+
return crypto.createHash("sha256").update(seed).digest();
|
|
1565
|
+
}
|
|
1566
|
+
function encrypt(text, key) {
|
|
1567
|
+
const iv = crypto.randomBytes(16);
|
|
1568
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
|
|
1569
|
+
let encrypted = cipher.update(text, "utf-8", "hex");
|
|
1570
|
+
encrypted += cipher.final("hex");
|
|
1571
|
+
const tag = cipher.getAuthTag();
|
|
1572
|
+
return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted}`;
|
|
1573
|
+
}
|
|
1574
|
+
function decrypt(text, key) {
|
|
1575
|
+
const [ivHex, tagHex, encrypted] = text.split(":");
|
|
1576
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
1577
|
+
const tag = Buffer.from(tagHex, "hex");
|
|
1578
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
|
|
1579
|
+
decipher.setAuthTag(tag);
|
|
1580
|
+
let decrypted = decipher.update(encrypted, "hex", "utf-8");
|
|
1581
|
+
decrypted += decipher.final("utf-8");
|
|
1582
|
+
return decrypted;
|
|
1583
|
+
}
|
|
1584
|
+
function parseJwtClaims(idToken) {
|
|
1585
|
+
try {
|
|
1586
|
+
const payload = idToken.split(".")[1];
|
|
1587
|
+
const decoded = Buffer.from(payload, "base64url").toString("utf-8");
|
|
1588
|
+
return JSON.parse(decoded);
|
|
1589
|
+
} catch {
|
|
1590
|
+
return {};
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1478
1593
|
|
|
1479
1594
|
// src/commands/init.ts
|
|
1480
1595
|
async function initCommand(projectName, options = {}) {
|
|
@@ -1492,7 +1607,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1492
1607
|
if (!validateThemeName(kebabName)) {
|
|
1493
1608
|
return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
|
|
1494
1609
|
}
|
|
1495
|
-
if (
|
|
1610
|
+
if (fs3.existsSync(path9.join(process.cwd(), kebabName))) {
|
|
1496
1611
|
return `Directory "${kebabName}" already exists`;
|
|
1497
1612
|
}
|
|
1498
1613
|
return true;
|
|
@@ -1503,11 +1618,46 @@ async function initCommand(projectName, options = {}) {
|
|
|
1503
1618
|
} else {
|
|
1504
1619
|
name = toKebabCase(projectName);
|
|
1505
1620
|
}
|
|
1506
|
-
const projectPath =
|
|
1507
|
-
if (
|
|
1621
|
+
const projectPath = path9.join(process.cwd(), name);
|
|
1622
|
+
if (fs3.existsSync(projectPath)) {
|
|
1508
1623
|
logger.error(`Directory "${name}" already exists.`);
|
|
1509
1624
|
process.exit(1);
|
|
1510
1625
|
}
|
|
1626
|
+
if (!options.yes) {
|
|
1627
|
+
try {
|
|
1628
|
+
const apiUrl = getApiUrl();
|
|
1629
|
+
const controller = new AbortController();
|
|
1630
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1631
|
+
const response = await fetch(
|
|
1632
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(name)}/exists`,
|
|
1633
|
+
{ signal: controller.signal }
|
|
1634
|
+
);
|
|
1635
|
+
clearTimeout(timeout);
|
|
1636
|
+
if (response.ok) {
|
|
1637
|
+
const data2 = await response.json();
|
|
1638
|
+
const body = data2.statusCode ? data2.body : data2;
|
|
1639
|
+
if (body.exists && body.owner === "other") {
|
|
1640
|
+
logger.warning(
|
|
1641
|
+
`Theme ID "${name}" is already registered by another developer.
|
|
1642
|
+
You can still create this locally, but publishing will fail.
|
|
1643
|
+
Consider using a different name.`
|
|
1644
|
+
);
|
|
1645
|
+
const { proceed } = await inquirer.prompt([
|
|
1646
|
+
{
|
|
1647
|
+
type: "confirm",
|
|
1648
|
+
name: "proceed",
|
|
1649
|
+
message: "Continue anyway?",
|
|
1650
|
+
default: false
|
|
1651
|
+
}
|
|
1652
|
+
]);
|
|
1653
|
+
if (!proceed) {
|
|
1654
|
+
process.exit(0);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
} catch {
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1511
1661
|
let displayName;
|
|
1512
1662
|
let description;
|
|
1513
1663
|
let author;
|
|
@@ -1575,7 +1725,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1575
1725
|
}
|
|
1576
1726
|
logger.startSpinner("Creating project structure...");
|
|
1577
1727
|
try {
|
|
1578
|
-
|
|
1728
|
+
fs3.mkdirSync(projectPath, { recursive: true });
|
|
1579
1729
|
await copyTemplate(template, projectPath, data);
|
|
1580
1730
|
await renameThemeInFiles(
|
|
1581
1731
|
projectPath,
|
|
@@ -1584,9 +1734,9 @@ async function initCommand(projectName, options = {}) {
|
|
|
1584
1734
|
description,
|
|
1585
1735
|
author
|
|
1586
1736
|
);
|
|
1587
|
-
const mcpJsonPath =
|
|
1588
|
-
if (
|
|
1589
|
-
let mcpContent =
|
|
1737
|
+
const mcpJsonPath = path9.join(projectPath, ".mcp.json");
|
|
1738
|
+
if (fs3.existsSync(mcpJsonPath)) {
|
|
1739
|
+
let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
|
|
1590
1740
|
if (figmaApiKey) {
|
|
1591
1741
|
mcpContent = mcpContent.replace("__FIGMA_API_KEY__", figmaApiKey);
|
|
1592
1742
|
} else {
|
|
@@ -1597,7 +1747,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1597
1747
|
} catch {
|
|
1598
1748
|
}
|
|
1599
1749
|
}
|
|
1600
|
-
|
|
1750
|
+
fs3.writeFileSync(mcpJsonPath, mcpContent, "utf-8");
|
|
1601
1751
|
}
|
|
1602
1752
|
logger.stopSpinner(true, "Project structure created!");
|
|
1603
1753
|
if (options.git) {
|
|
@@ -1657,16 +1807,16 @@ async function initCommand(projectName, options = {}) {
|
|
|
1657
1807
|
logger.error(
|
|
1658
1808
|
error instanceof Error ? error.message : "Unknown error occurred"
|
|
1659
1809
|
);
|
|
1660
|
-
if (
|
|
1661
|
-
|
|
1810
|
+
if (fs3.existsSync(projectPath)) {
|
|
1811
|
+
fs3.rmSync(projectPath, { recursive: true, force: true });
|
|
1662
1812
|
}
|
|
1663
1813
|
process.exit(1);
|
|
1664
1814
|
}
|
|
1665
1815
|
}
|
|
1666
1816
|
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
1667
|
-
const configPath =
|
|
1668
|
-
if (
|
|
1669
|
-
let content =
|
|
1817
|
+
const configPath = path9.join(projectPath, "theme.config.ts");
|
|
1818
|
+
if (fs3.existsSync(configPath)) {
|
|
1819
|
+
let content = fs3.readFileSync(configPath, "utf-8");
|
|
1670
1820
|
content = content.replace(
|
|
1671
1821
|
/name: "My Simple Theme"/,
|
|
1672
1822
|
`name: "${displayName}"`
|
|
@@ -1675,11 +1825,11 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
1675
1825
|
/description: ".*?"/,
|
|
1676
1826
|
`description: "${description}"`
|
|
1677
1827
|
);
|
|
1678
|
-
|
|
1828
|
+
fs3.writeFileSync(configPath, content, "utf-8");
|
|
1679
1829
|
}
|
|
1680
|
-
const pkgPath =
|
|
1681
|
-
if (
|
|
1682
|
-
let content =
|
|
1830
|
+
const pkgPath = path9.join(projectPath, "package.json");
|
|
1831
|
+
if (fs3.existsSync(pkgPath)) {
|
|
1832
|
+
let content = fs3.readFileSync(pkgPath, "utf-8");
|
|
1683
1833
|
content = content.replace(
|
|
1684
1834
|
/@onex-themes\/my-simple/g,
|
|
1685
1835
|
`@onex-themes/${themeName}`
|
|
@@ -1688,7 +1838,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
|
|
|
1688
1838
|
/"description": ".*?"/,
|
|
1689
1839
|
`"description": "${description}"`
|
|
1690
1840
|
);
|
|
1691
|
-
|
|
1841
|
+
fs3.writeFileSync(pkgPath, content, "utf-8");
|
|
1692
1842
|
}
|
|
1693
1843
|
}
|
|
1694
1844
|
|
|
@@ -1699,10 +1849,10 @@ async function createSectionCommand(name, options) {
|
|
|
1699
1849
|
ensureOneXProject();
|
|
1700
1850
|
if (!options.theme) {
|
|
1701
1851
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
1702
|
-
(f) => fs.existsSync(
|
|
1852
|
+
(f) => fs.existsSync(path9.join(process.cwd(), f))
|
|
1703
1853
|
);
|
|
1704
1854
|
if (isStandaloneTheme) {
|
|
1705
|
-
options.theme =
|
|
1855
|
+
options.theme = path9.basename(process.cwd());
|
|
1706
1856
|
}
|
|
1707
1857
|
}
|
|
1708
1858
|
const sectionName = toKebabCase(name);
|
|
@@ -1765,35 +1915,35 @@ async function createSectionCommand(name, options) {
|
|
|
1765
1915
|
};
|
|
1766
1916
|
logger.startSpinner("Creating section files...");
|
|
1767
1917
|
try {
|
|
1768
|
-
const themePath =
|
|
1769
|
-
const sectionPath =
|
|
1918
|
+
const themePath = path9.join(getThemesDir(), themeName);
|
|
1919
|
+
const sectionPath = path9.join(themePath, "sections", sectionName);
|
|
1770
1920
|
const schemaContent = generateSectionSchema(data);
|
|
1771
1921
|
await writeFile(
|
|
1772
|
-
|
|
1922
|
+
path9.join(sectionPath, `${sectionName}.schema.ts`),
|
|
1773
1923
|
schemaContent
|
|
1774
1924
|
);
|
|
1775
1925
|
if (createTemplate) {
|
|
1776
1926
|
const templateContent = generateSectionTemplate(data);
|
|
1777
1927
|
await writeFile(
|
|
1778
|
-
|
|
1928
|
+
path9.join(sectionPath, `${sectionName}-default.tsx`),
|
|
1779
1929
|
templateContent
|
|
1780
1930
|
);
|
|
1781
1931
|
}
|
|
1782
1932
|
const indexContent = generateSectionIndex(data, createTemplate);
|
|
1783
|
-
await writeFile(
|
|
1933
|
+
await writeFile(path9.join(sectionPath, "index.ts"), indexContent);
|
|
1784
1934
|
logger.stopSpinner(true, "Section files created successfully!");
|
|
1785
1935
|
logger.newLine();
|
|
1786
1936
|
logger.section("Next steps:");
|
|
1787
1937
|
logger.log(
|
|
1788
|
-
` 1. Edit schema: ${
|
|
1938
|
+
` 1. Edit schema: ${path9.relative(process.cwd(), path9.join(sectionPath, `${sectionName}.schema.ts`))}`
|
|
1789
1939
|
);
|
|
1790
1940
|
if (createTemplate) {
|
|
1791
1941
|
logger.log(
|
|
1792
|
-
` 2. Edit template: ${
|
|
1942
|
+
` 2. Edit template: ${path9.relative(process.cwd(), path9.join(sectionPath, `${sectionName}-default.tsx`))}`
|
|
1793
1943
|
);
|
|
1794
1944
|
}
|
|
1795
1945
|
logger.log(
|
|
1796
|
-
` 3. Add to theme manifest: ${
|
|
1946
|
+
` 3. Add to theme manifest: ${path9.relative(process.cwd(), path9.join(themePath, "manifest.ts"))}`
|
|
1797
1947
|
);
|
|
1798
1948
|
logger.newLine();
|
|
1799
1949
|
logger.success("Section created successfully!");
|
|
@@ -1941,10 +2091,10 @@ async function createBlockCommand(name, options) {
|
|
|
1941
2091
|
ensureOneXProject();
|
|
1942
2092
|
if (!options.theme) {
|
|
1943
2093
|
const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
|
|
1944
|
-
(f) => fs.existsSync(
|
|
2094
|
+
(f) => fs.existsSync(path9.join(process.cwd(), f))
|
|
1945
2095
|
);
|
|
1946
2096
|
if (isStandaloneTheme) {
|
|
1947
|
-
options.theme =
|
|
2097
|
+
options.theme = path9.basename(process.cwd());
|
|
1948
2098
|
}
|
|
1949
2099
|
}
|
|
1950
2100
|
const blockName = toKebabCase(name);
|
|
@@ -2019,24 +2169,24 @@ async function createBlockCommand(name, options) {
|
|
|
2019
2169
|
};
|
|
2020
2170
|
logger.startSpinner("Creating block files...");
|
|
2021
2171
|
try {
|
|
2022
|
-
const blockPath = scope === "shared" ?
|
|
2172
|
+
const blockPath = scope === "shared" ? path9.join(getFeaturesDir(), "blocks", blockName) : path9.join(getThemesDir(), themeName, "blocks", blockName);
|
|
2023
2173
|
const schemaContent = generateBlockSchema(data);
|
|
2024
2174
|
await writeFile(
|
|
2025
|
-
|
|
2175
|
+
path9.join(blockPath, `${blockName}.schema.ts`),
|
|
2026
2176
|
schemaContent
|
|
2027
2177
|
);
|
|
2028
2178
|
const componentContent = generateBlockComponent(data);
|
|
2029
|
-
await writeFile(
|
|
2179
|
+
await writeFile(path9.join(blockPath, `${blockName}.tsx`), componentContent);
|
|
2030
2180
|
const indexContent = generateBlockIndex(data);
|
|
2031
|
-
await writeFile(
|
|
2181
|
+
await writeFile(path9.join(blockPath, "index.ts"), indexContent);
|
|
2032
2182
|
logger.stopSpinner(true, "Block files created successfully!");
|
|
2033
2183
|
logger.newLine();
|
|
2034
2184
|
logger.section("Next steps:");
|
|
2035
2185
|
logger.log(
|
|
2036
|
-
` 1. Edit schema: ${
|
|
2186
|
+
` 1. Edit schema: ${path9.relative(process.cwd(), path9.join(blockPath, `${blockName}.schema.ts`))}`
|
|
2037
2187
|
);
|
|
2038
2188
|
logger.log(
|
|
2039
|
-
` 2. Edit component: ${
|
|
2189
|
+
` 2. Edit component: ${path9.relative(process.cwd(), path9.join(blockPath, `${blockName}.tsx`))}`
|
|
2040
2190
|
);
|
|
2041
2191
|
logger.log(
|
|
2042
2192
|
` 3. Register in block registry: src/lib/registry/block-registry.ts`
|
|
@@ -2214,31 +2364,31 @@ async function createComponentCommand(name, options) {
|
|
|
2214
2364
|
};
|
|
2215
2365
|
logger.startSpinner("Creating component files...");
|
|
2216
2366
|
try {
|
|
2217
|
-
const componentPath =
|
|
2367
|
+
const componentPath = path9.join(
|
|
2218
2368
|
getFeaturesDir(),
|
|
2219
2369
|
"components",
|
|
2220
2370
|
componentName
|
|
2221
2371
|
);
|
|
2222
2372
|
const schemaContent = generateComponentSchema(data);
|
|
2223
2373
|
await writeFile(
|
|
2224
|
-
|
|
2374
|
+
path9.join(componentPath, `${componentName}.schema.ts`),
|
|
2225
2375
|
schemaContent
|
|
2226
2376
|
);
|
|
2227
2377
|
const componentContent = generateComponent(data);
|
|
2228
2378
|
await writeFile(
|
|
2229
|
-
|
|
2379
|
+
path9.join(componentPath, `${componentName}.tsx`),
|
|
2230
2380
|
componentContent
|
|
2231
2381
|
);
|
|
2232
2382
|
const indexContent = generateComponentIndex(data);
|
|
2233
|
-
await writeFile(
|
|
2383
|
+
await writeFile(path9.join(componentPath, "index.ts"), indexContent);
|
|
2234
2384
|
logger.stopSpinner(true, "Component files created successfully!");
|
|
2235
2385
|
logger.newLine();
|
|
2236
2386
|
logger.section("Next steps:");
|
|
2237
2387
|
logger.log(
|
|
2238
|
-
` 1. Edit schema: ${
|
|
2388
|
+
` 1. Edit schema: ${path9.relative(process.cwd(), path9.join(componentPath, `${componentName}.schema.ts`))}`
|
|
2239
2389
|
);
|
|
2240
2390
|
logger.log(
|
|
2241
|
-
` 2. Edit component: ${
|
|
2391
|
+
` 2. Edit component: ${path9.relative(process.cwd(), path9.join(componentPath, `${componentName}.tsx`))}`
|
|
2242
2392
|
);
|
|
2243
2393
|
logger.log(
|
|
2244
2394
|
` 3. Register in component registry: src/lib/registry/component-registry.ts`
|
|
@@ -2395,13 +2545,13 @@ async function listSections(themeFilter) {
|
|
|
2395
2545
|
return;
|
|
2396
2546
|
}
|
|
2397
2547
|
for (const theme of themes) {
|
|
2398
|
-
const sectionsDir =
|
|
2548
|
+
const sectionsDir = path9.join(getThemesDir(), theme, "sections");
|
|
2399
2549
|
if (!fs.existsSync(sectionsDir)) {
|
|
2400
2550
|
continue;
|
|
2401
2551
|
}
|
|
2402
2552
|
const sections = fs.readdirSync(sectionsDir).filter((name) => {
|
|
2403
|
-
const sectionPath =
|
|
2404
|
-
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(
|
|
2553
|
+
const sectionPath = path9.join(sectionsDir, name);
|
|
2554
|
+
return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path9.join(sectionPath, "index.ts"));
|
|
2405
2555
|
});
|
|
2406
2556
|
if (sections.length > 0) {
|
|
2407
2557
|
logger.log(chalk4.cyan(`
|
|
@@ -2415,11 +2565,11 @@ async function listSections(themeFilter) {
|
|
|
2415
2565
|
}
|
|
2416
2566
|
async function listBlocks(themeFilter) {
|
|
2417
2567
|
logger.section("\u{1F9F1} Blocks");
|
|
2418
|
-
const sharedBlocksDir =
|
|
2568
|
+
const sharedBlocksDir = path9.join(getFeaturesDir(), "blocks");
|
|
2419
2569
|
if (fs.existsSync(sharedBlocksDir)) {
|
|
2420
2570
|
const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
|
|
2421
|
-
const blockPath =
|
|
2422
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
2571
|
+
const blockPath = path9.join(sharedBlocksDir, name);
|
|
2572
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path9.join(blockPath, "index.ts"));
|
|
2423
2573
|
});
|
|
2424
2574
|
if (sharedBlocks.length > 0) {
|
|
2425
2575
|
logger.log(chalk4.cyan("\n Shared:"));
|
|
@@ -2430,13 +2580,13 @@ async function listBlocks(themeFilter) {
|
|
|
2430
2580
|
}
|
|
2431
2581
|
const themes = themeFilter ? [themeFilter] : listThemes();
|
|
2432
2582
|
for (const theme of themes) {
|
|
2433
|
-
const blocksDir =
|
|
2583
|
+
const blocksDir = path9.join(getThemesDir(), theme, "blocks");
|
|
2434
2584
|
if (!fs.existsSync(blocksDir)) {
|
|
2435
2585
|
continue;
|
|
2436
2586
|
}
|
|
2437
2587
|
const blocks = fs.readdirSync(blocksDir).filter((name) => {
|
|
2438
|
-
const blockPath =
|
|
2439
|
-
return fs.statSync(blockPath).isDirectory() && fs.existsSync(
|
|
2588
|
+
const blockPath = path9.join(blocksDir, name);
|
|
2589
|
+
return fs.statSync(blockPath).isDirectory() && fs.existsSync(path9.join(blockPath, "index.ts"));
|
|
2440
2590
|
});
|
|
2441
2591
|
if (blocks.length > 0) {
|
|
2442
2592
|
logger.log(chalk4.cyan(`
|
|
@@ -2450,14 +2600,14 @@ async function listBlocks(themeFilter) {
|
|
|
2450
2600
|
}
|
|
2451
2601
|
async function listComponents() {
|
|
2452
2602
|
logger.section("\u2699\uFE0F Components");
|
|
2453
|
-
const componentsDir =
|
|
2603
|
+
const componentsDir = path9.join(getFeaturesDir(), "components");
|
|
2454
2604
|
if (!fs.existsSync(componentsDir)) {
|
|
2455
2605
|
logger.warning("No components directory found");
|
|
2456
2606
|
return;
|
|
2457
2607
|
}
|
|
2458
2608
|
const components = fs.readdirSync(componentsDir).filter((name) => {
|
|
2459
|
-
const componentPath =
|
|
2460
|
-
return fs.statSync(componentPath).isDirectory() && fs.existsSync(
|
|
2609
|
+
const componentPath = path9.join(componentsDir, name);
|
|
2610
|
+
return fs.statSync(componentPath).isDirectory() && fs.existsSync(path9.join(componentPath, "index.ts"));
|
|
2461
2611
|
});
|
|
2462
2612
|
if (components.length === 0) {
|
|
2463
2613
|
logger.warning("No components found");
|
|
@@ -2478,11 +2628,11 @@ async function listThemesInfo() {
|
|
|
2478
2628
|
}
|
|
2479
2629
|
logger.log("");
|
|
2480
2630
|
for (const theme of themes) {
|
|
2481
|
-
const themeDir =
|
|
2631
|
+
const themeDir = path9.join(getThemesDir(), theme);
|
|
2482
2632
|
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
2483
2633
|
let manifestContent = "";
|
|
2484
2634
|
for (const candidate of candidates) {
|
|
2485
|
-
const candidatePath =
|
|
2635
|
+
const candidatePath = path9.join(themeDir, candidate);
|
|
2486
2636
|
if (fs.existsSync(candidatePath)) {
|
|
2487
2637
|
manifestContent = fs.readFileSync(candidatePath, "utf-8");
|
|
2488
2638
|
break;
|
|
@@ -2520,9 +2670,9 @@ async function validateCommand(options) {
|
|
|
2520
2670
|
"theme.config.ts",
|
|
2521
2671
|
"bundle-entry.ts",
|
|
2522
2672
|
"manifest.ts"
|
|
2523
|
-
].some((f) => fs.existsSync(
|
|
2673
|
+
].some((f) => fs.existsSync(path9.join(process.cwd(), f)));
|
|
2524
2674
|
if (isThemeDir) {
|
|
2525
|
-
themeToValidate =
|
|
2675
|
+
themeToValidate = path9.basename(process.cwd());
|
|
2526
2676
|
logger.info(`Validating current theme: ${themeToValidate}`);
|
|
2527
2677
|
} else {
|
|
2528
2678
|
logger.error(
|
|
@@ -2531,11 +2681,11 @@ async function validateCommand(options) {
|
|
|
2531
2681
|
process.exit(1);
|
|
2532
2682
|
}
|
|
2533
2683
|
}
|
|
2534
|
-
const themePath =
|
|
2684
|
+
const themePath = path9.join(getThemesDir(), themeToValidate);
|
|
2535
2685
|
logger.startSpinner("Running validation checks...");
|
|
2536
2686
|
const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
|
|
2537
2687
|
const foundEntry = entryFiles.find(
|
|
2538
|
-
(f) => fs.existsSync(
|
|
2688
|
+
(f) => fs.existsSync(path9.join(themePath, f))
|
|
2539
2689
|
);
|
|
2540
2690
|
if (!foundEntry) {
|
|
2541
2691
|
issues.push({
|
|
@@ -2545,7 +2695,7 @@ async function validateCommand(options) {
|
|
|
2545
2695
|
});
|
|
2546
2696
|
} else if (foundEntry === "manifest.ts") {
|
|
2547
2697
|
const manifestContent = fs.readFileSync(
|
|
2548
|
-
|
|
2698
|
+
path9.join(themePath, foundEntry),
|
|
2549
2699
|
"utf-8"
|
|
2550
2700
|
);
|
|
2551
2701
|
if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
|
|
@@ -2556,7 +2706,7 @@ async function validateCommand(options) {
|
|
|
2556
2706
|
});
|
|
2557
2707
|
}
|
|
2558
2708
|
}
|
|
2559
|
-
const configPath =
|
|
2709
|
+
const configPath = path9.join(themePath, "theme.config.ts");
|
|
2560
2710
|
if (!fs.existsSync(configPath)) {
|
|
2561
2711
|
issues.push({
|
|
2562
2712
|
type: "warning",
|
|
@@ -2564,7 +2714,7 @@ async function validateCommand(options) {
|
|
|
2564
2714
|
message: "Theme config file not found (recommended)"
|
|
2565
2715
|
});
|
|
2566
2716
|
}
|
|
2567
|
-
const indexPath =
|
|
2717
|
+
const indexPath = path9.join(themePath, "index.ts");
|
|
2568
2718
|
if (!fs.existsSync(indexPath)) {
|
|
2569
2719
|
issues.push({
|
|
2570
2720
|
type: "warning",
|
|
@@ -2572,7 +2722,7 @@ async function validateCommand(options) {
|
|
|
2572
2722
|
message: "Index file not found (recommended)"
|
|
2573
2723
|
});
|
|
2574
2724
|
}
|
|
2575
|
-
const sectionsDir =
|
|
2725
|
+
const sectionsDir = path9.join(themePath, "sections");
|
|
2576
2726
|
if (!fs.existsSync(sectionsDir)) {
|
|
2577
2727
|
issues.push({
|
|
2578
2728
|
type: "warning",
|
|
@@ -2581,16 +2731,16 @@ async function validateCommand(options) {
|
|
|
2581
2731
|
});
|
|
2582
2732
|
} else {
|
|
2583
2733
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
2584
|
-
(name) => fs.statSync(
|
|
2734
|
+
(name) => fs.statSync(path9.join(sectionsDir, name)).isDirectory()
|
|
2585
2735
|
);
|
|
2586
2736
|
for (const sectionName of sections) {
|
|
2587
|
-
const sectionPath =
|
|
2588
|
-
const schemaFile =
|
|
2589
|
-
const defaultTemplate =
|
|
2737
|
+
const sectionPath = path9.join(sectionsDir, sectionName);
|
|
2738
|
+
const schemaFile = path9.join(sectionPath, `${sectionName}.schema.ts`);
|
|
2739
|
+
const defaultTemplate = path9.join(
|
|
2590
2740
|
sectionPath,
|
|
2591
2741
|
`${sectionName}-default.tsx`
|
|
2592
2742
|
);
|
|
2593
|
-
const indexFile =
|
|
2743
|
+
const indexFile = path9.join(sectionPath, "index.ts");
|
|
2594
2744
|
if (!fs.existsSync(schemaFile)) {
|
|
2595
2745
|
issues.push({
|
|
2596
2746
|
type: "error",
|
|
@@ -2614,14 +2764,14 @@ async function validateCommand(options) {
|
|
|
2614
2764
|
}
|
|
2615
2765
|
}
|
|
2616
2766
|
}
|
|
2617
|
-
const blocksDir =
|
|
2767
|
+
const blocksDir = path9.join(themePath, "blocks");
|
|
2618
2768
|
if (fs.existsSync(blocksDir)) {
|
|
2619
|
-
const blocks = fs.readdirSync(blocksDir).filter((name) => fs.statSync(
|
|
2769
|
+
const blocks = fs.readdirSync(blocksDir).filter((name) => fs.statSync(path9.join(blocksDir, name)).isDirectory());
|
|
2620
2770
|
for (const blockName of blocks) {
|
|
2621
|
-
const blockPath =
|
|
2622
|
-
const schemaFile =
|
|
2623
|
-
const componentFile =
|
|
2624
|
-
const indexFile =
|
|
2771
|
+
const blockPath = path9.join(blocksDir, blockName);
|
|
2772
|
+
const schemaFile = path9.join(blockPath, `${blockName}.schema.ts`);
|
|
2773
|
+
const componentFile = path9.join(blockPath, `${blockName}.tsx`);
|
|
2774
|
+
const indexFile = path9.join(blockPath, "index.ts");
|
|
2625
2775
|
if (!fs.existsSync(schemaFile)) {
|
|
2626
2776
|
issues.push({
|
|
2627
2777
|
type: "error",
|
|
@@ -2647,13 +2797,13 @@ async function validateCommand(options) {
|
|
|
2647
2797
|
}
|
|
2648
2798
|
if (fs.existsSync(sectionsDir)) {
|
|
2649
2799
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
2650
|
-
(name) => fs.statSync(
|
|
2800
|
+
(name) => fs.statSync(path9.join(sectionsDir, name)).isDirectory()
|
|
2651
2801
|
);
|
|
2652
2802
|
for (const sectionName of sections) {
|
|
2653
|
-
const sectionPath =
|
|
2803
|
+
const sectionPath = path9.join(sectionsDir, sectionName);
|
|
2654
2804
|
const tsxFiles = fs.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
|
|
2655
2805
|
for (const tsxFile of tsxFiles) {
|
|
2656
|
-
const filePath =
|
|
2806
|
+
const filePath = path9.join(sectionPath, tsxFile);
|
|
2657
2807
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
2658
2808
|
const relPath = `sections/${sectionName}/${tsxFile}`;
|
|
2659
2809
|
if (!content.includes('"use client"') && !content.includes("'use client'")) {
|
|
@@ -2701,23 +2851,46 @@ async function validateCommand(options) {
|
|
|
2701
2851
|
}
|
|
2702
2852
|
}
|
|
2703
2853
|
}
|
|
2704
|
-
const registryPath =
|
|
2705
|
-
const bundleEntryPath =
|
|
2854
|
+
const registryPath = path9.join(themePath, "sections-registry.ts");
|
|
2855
|
+
const bundleEntryPath = path9.join(themePath, "bundle-entry.ts");
|
|
2706
2856
|
const registryContent = fs.existsSync(registryPath) ? fs.readFileSync(registryPath, "utf-8") : fs.existsSync(bundleEntryPath) ? fs.readFileSync(bundleEntryPath, "utf-8") : "";
|
|
2707
2857
|
if (fs.existsSync(sectionsDir) && registryContent) {
|
|
2708
2858
|
const sections = fs.readdirSync(sectionsDir).filter(
|
|
2709
|
-
(name) => fs.statSync(
|
|
2859
|
+
(name) => fs.statSync(path9.join(sectionsDir, name)).isDirectory()
|
|
2710
2860
|
);
|
|
2711
2861
|
for (const sectionName of sections) {
|
|
2712
2862
|
if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
|
|
2713
2863
|
issues.push({
|
|
2714
|
-
type: "
|
|
2864
|
+
type: "error",
|
|
2715
2865
|
file: `sections/${sectionName}/`,
|
|
2716
|
-
message: "Section not
|
|
2866
|
+
message: "Section not exported in sections-registry.ts or bundle-entry.ts \u2014 will not be included in build"
|
|
2717
2867
|
});
|
|
2718
2868
|
}
|
|
2719
2869
|
}
|
|
2720
2870
|
}
|
|
2871
|
+
if (fs.existsSync(sectionsDir)) {
|
|
2872
|
+
const schemaTypes = await loadSchemaTypes(themePath, sectionsDir);
|
|
2873
|
+
for (const { folderName, schemaType } of schemaTypes) {
|
|
2874
|
+
if (schemaType && schemaType !== folderName) {
|
|
2875
|
+
issues.push({
|
|
2876
|
+
type: "error",
|
|
2877
|
+
file: `sections/${folderName}/${folderName}.schema.ts`,
|
|
2878
|
+
message: `Schema type "${schemaType}" doesn't match folder name "${folderName}". Rename folder to "${schemaType}/" or change schema type to "${folderName}".`
|
|
2879
|
+
});
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
const pagesDir = path9.join(themePath, "pages");
|
|
2883
|
+
if (fs.existsSync(pagesDir)) {
|
|
2884
|
+
const allSchemaTypeSet = new Set(
|
|
2885
|
+
schemaTypes.map((s) => s.schemaType || s.folderName)
|
|
2886
|
+
);
|
|
2887
|
+
const pageIssues = await validatePageSectionTypes(
|
|
2888
|
+
pagesDir,
|
|
2889
|
+
allSchemaTypeSet
|
|
2890
|
+
);
|
|
2891
|
+
issues.push(...pageIssues);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2721
2894
|
logger.stopSpinner(true, "Validation complete");
|
|
2722
2895
|
const errors = issues.filter((i) => i.type === "error");
|
|
2723
2896
|
const warnings = issues.filter((i) => i.type === "warning");
|
|
@@ -2756,6 +2929,116 @@ async function validateCommand(options) {
|
|
|
2756
2929
|
}
|
|
2757
2930
|
}
|
|
2758
2931
|
}
|
|
2932
|
+
async function loadSchemaTypes(themePath, sectionsDir) {
|
|
2933
|
+
const results = [];
|
|
2934
|
+
const sections = fs.readdirSync(sectionsDir).filter((name) => fs.statSync(path9.join(sectionsDir, name)).isDirectory());
|
|
2935
|
+
for (const sectionName of sections) {
|
|
2936
|
+
const schemaFile = path9.join(
|
|
2937
|
+
sectionsDir,
|
|
2938
|
+
sectionName,
|
|
2939
|
+
`${sectionName}.schema.ts`
|
|
2940
|
+
);
|
|
2941
|
+
if (!fs.existsSync(schemaFile)) {
|
|
2942
|
+
results.push({ folderName: sectionName, schemaType: null });
|
|
2943
|
+
continue;
|
|
2944
|
+
}
|
|
2945
|
+
const content = fs.readFileSync(schemaFile, "utf-8");
|
|
2946
|
+
let schemaType = null;
|
|
2947
|
+
const schemaExportMatch = content.match(
|
|
2948
|
+
/:\s*SectionSchema\s*=\s*\{[\s\S]*?\btype:\s*["']([^"']+)["']/
|
|
2949
|
+
);
|
|
2950
|
+
if (schemaExportMatch) {
|
|
2951
|
+
schemaType = schemaExportMatch[1];
|
|
2952
|
+
} else {
|
|
2953
|
+
const allTypeMatches = [
|
|
2954
|
+
...content.matchAll(/\btype:\s*["']([^"']+)["']/g)
|
|
2955
|
+
];
|
|
2956
|
+
for (const m of allTypeMatches) {
|
|
2957
|
+
if (!FIELD_TYPES.has(m[1])) {
|
|
2958
|
+
schemaType = m[1];
|
|
2959
|
+
break;
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
results.push({
|
|
2964
|
+
folderName: sectionName,
|
|
2965
|
+
schemaType
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2968
|
+
return results;
|
|
2969
|
+
}
|
|
2970
|
+
async function validatePageSectionTypes(pagesDir, validTypes) {
|
|
2971
|
+
const issues = [];
|
|
2972
|
+
const files = fs.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
|
|
2973
|
+
for (const file of files) {
|
|
2974
|
+
const content = fs.readFileSync(path9.join(pagesDir, file), "utf-8");
|
|
2975
|
+
const pageName = file.replace(/\.(ts|js)$/, "");
|
|
2976
|
+
const sectionsMatch = content.match(/\bsections:\s*\[/);
|
|
2977
|
+
if (!sectionsMatch || sectionsMatch.index === void 0) continue;
|
|
2978
|
+
const startIdx = sectionsMatch.index + sectionsMatch[0].length;
|
|
2979
|
+
let depth = 1;
|
|
2980
|
+
let endIdx = startIdx;
|
|
2981
|
+
for (let i = startIdx; i < content.length && depth > 0; i++) {
|
|
2982
|
+
if (content[i] === "[") depth++;
|
|
2983
|
+
else if (content[i] === "]") depth--;
|
|
2984
|
+
endIdx = i;
|
|
2985
|
+
}
|
|
2986
|
+
const sectionsBlock = content.slice(startIdx, endIdx);
|
|
2987
|
+
const typeMatches = sectionsBlock.matchAll(/\btype:\s*["']([^"']+)["']/g);
|
|
2988
|
+
for (const match of typeMatches) {
|
|
2989
|
+
const sectionType = match[1];
|
|
2990
|
+
if (!validTypes.has(sectionType)) {
|
|
2991
|
+
issues.push({
|
|
2992
|
+
type: "error",
|
|
2993
|
+
file: `pages/${file}`,
|
|
2994
|
+
message: `Page "${pageName}" uses section type "${sectionType}" which doesn't exist in sections/`
|
|
2995
|
+
});
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
return issues;
|
|
3000
|
+
}
|
|
3001
|
+
var FIELD_TYPES = /* @__PURE__ */ new Set([
|
|
3002
|
+
"text",
|
|
3003
|
+
"textarea",
|
|
3004
|
+
"richtext",
|
|
3005
|
+
"number",
|
|
3006
|
+
"range",
|
|
3007
|
+
"toggle",
|
|
3008
|
+
"switch",
|
|
3009
|
+
"select",
|
|
3010
|
+
"radio",
|
|
3011
|
+
"checkbox",
|
|
3012
|
+
"color",
|
|
3013
|
+
"image",
|
|
3014
|
+
"video",
|
|
3015
|
+
"url",
|
|
3016
|
+
"link",
|
|
3017
|
+
"icon",
|
|
3018
|
+
"date",
|
|
3019
|
+
"datetime",
|
|
3020
|
+
"collection",
|
|
3021
|
+
"product",
|
|
3022
|
+
"blog",
|
|
3023
|
+
"page",
|
|
3024
|
+
"html",
|
|
3025
|
+
"code",
|
|
3026
|
+
"json",
|
|
3027
|
+
"array",
|
|
3028
|
+
"object",
|
|
3029
|
+
"group",
|
|
3030
|
+
"section",
|
|
3031
|
+
"boolean",
|
|
3032
|
+
"color_token",
|
|
3033
|
+
"color_background",
|
|
3034
|
+
"image_picker",
|
|
3035
|
+
"video_url",
|
|
3036
|
+
"font",
|
|
3037
|
+
"font_picker",
|
|
3038
|
+
"text_alignment",
|
|
3039
|
+
"inline_richtext",
|
|
3040
|
+
"repeater"
|
|
3041
|
+
]);
|
|
2759
3042
|
|
|
2760
3043
|
// src/commands/build.ts
|
|
2761
3044
|
init_logger();
|
|
@@ -2766,14 +3049,14 @@ async function buildCommand(options) {
|
|
|
2766
3049
|
if (options.theme) {
|
|
2767
3050
|
themeName = options.theme;
|
|
2768
3051
|
try {
|
|
2769
|
-
const workspaceThemePath =
|
|
3052
|
+
const workspaceThemePath = path9.join(getThemesDir(), themeName);
|
|
2770
3053
|
if (fs.existsSync(workspaceThemePath)) {
|
|
2771
3054
|
themePath = workspaceThemePath;
|
|
2772
3055
|
} else {
|
|
2773
|
-
themePath =
|
|
3056
|
+
themePath = path9.join(process.cwd(), themeName);
|
|
2774
3057
|
}
|
|
2775
3058
|
} catch {
|
|
2776
|
-
themePath =
|
|
3059
|
+
themePath = path9.join(process.cwd(), themeName);
|
|
2777
3060
|
}
|
|
2778
3061
|
if (!fs.existsSync(themePath)) {
|
|
2779
3062
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -2784,10 +3067,10 @@ async function buildCommand(options) {
|
|
|
2784
3067
|
"theme.config.ts",
|
|
2785
3068
|
"bundle-entry.ts",
|
|
2786
3069
|
"manifest.ts"
|
|
2787
|
-
].some((f) => fs.existsSync(
|
|
3070
|
+
].some((f) => fs.existsSync(path9.join(process.cwd(), f)));
|
|
2788
3071
|
if (isThemeDir) {
|
|
2789
3072
|
themePath = process.cwd();
|
|
2790
|
-
themeName =
|
|
3073
|
+
themeName = path9.basename(themePath);
|
|
2791
3074
|
logger.info(`Building current theme: ${themeName}`);
|
|
2792
3075
|
} else {
|
|
2793
3076
|
logger.error(
|
|
@@ -2796,7 +3079,7 @@ async function buildCommand(options) {
|
|
|
2796
3079
|
process.exit(1);
|
|
2797
3080
|
}
|
|
2798
3081
|
}
|
|
2799
|
-
const packageJsonPath =
|
|
3082
|
+
const packageJsonPath = path9.join(themePath, "package.json");
|
|
2800
3083
|
const hasPkgJson = fs.existsSync(packageJsonPath);
|
|
2801
3084
|
if (!hasPkgJson) {
|
|
2802
3085
|
logger.warning(
|
|
@@ -2852,9 +3135,9 @@ async function buildCommand(options) {
|
|
|
2852
3135
|
logger.success("\u2713 Theme built successfully!");
|
|
2853
3136
|
logger.newLine();
|
|
2854
3137
|
logger.info(`Theme: ${themeName}`);
|
|
2855
|
-
const distPath =
|
|
3138
|
+
const distPath = path9.join(themePath, "dist");
|
|
2856
3139
|
if (fs.existsSync(distPath)) {
|
|
2857
|
-
logger.log(`Output: ${
|
|
3140
|
+
logger.log(`Output: ${path9.relative(process.cwd(), distPath)}`);
|
|
2858
3141
|
const files = fs.readdirSync(distPath);
|
|
2859
3142
|
logger.log(`Files: ${files.length}`);
|
|
2860
3143
|
}
|
|
@@ -2910,7 +3193,7 @@ async function packageCommand(options) {
|
|
|
2910
3193
|
let themeName;
|
|
2911
3194
|
if (options.theme) {
|
|
2912
3195
|
themeName = options.theme;
|
|
2913
|
-
themePath =
|
|
3196
|
+
themePath = path9.join(getThemesDir(), themeName);
|
|
2914
3197
|
if (!fs.existsSync(themePath)) {
|
|
2915
3198
|
logger.error(`Theme "${themeName}" not found.`);
|
|
2916
3199
|
process.exit(1);
|
|
@@ -2920,10 +3203,10 @@ async function packageCommand(options) {
|
|
|
2920
3203
|
"theme.config.ts",
|
|
2921
3204
|
"bundle-entry.ts",
|
|
2922
3205
|
"manifest.ts"
|
|
2923
|
-
].some((f) => fs.existsSync(
|
|
3206
|
+
].some((f) => fs.existsSync(path9.join(process.cwd(), f)));
|
|
2924
3207
|
if (isThemeDir) {
|
|
2925
3208
|
themePath = process.cwd();
|
|
2926
|
-
themeName =
|
|
3209
|
+
themeName = path9.basename(themePath);
|
|
2927
3210
|
logger.info(`Packaging current theme: ${themeName}`);
|
|
2928
3211
|
} else {
|
|
2929
3212
|
logger.error(
|
|
@@ -2932,7 +3215,7 @@ async function packageCommand(options) {
|
|
|
2932
3215
|
process.exit(1);
|
|
2933
3216
|
}
|
|
2934
3217
|
}
|
|
2935
|
-
const packageJsonPath =
|
|
3218
|
+
const packageJsonPath = path9.join(themePath, "package.json");
|
|
2936
3219
|
let version2 = "1.0.0";
|
|
2937
3220
|
if (fs.existsSync(packageJsonPath)) {
|
|
2938
3221
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
@@ -2942,7 +3225,7 @@ async function packageCommand(options) {
|
|
|
2942
3225
|
logger.info(`Theme: ${themeName}`);
|
|
2943
3226
|
logger.info(`Version: ${version2}`);
|
|
2944
3227
|
logger.newLine();
|
|
2945
|
-
const compiledThemePath =
|
|
3228
|
+
const compiledThemePath = path9.join(
|
|
2946
3229
|
process.cwd(),
|
|
2947
3230
|
"themes",
|
|
2948
3231
|
themeName,
|
|
@@ -2976,8 +3259,8 @@ async function packageCommand(options) {
|
|
|
2976
3259
|
logger.newLine();
|
|
2977
3260
|
logger.section("Step 2: Create Package");
|
|
2978
3261
|
const packageName = options.name || `${themeName}-${version2}`;
|
|
2979
|
-
const outputDir = options.output ||
|
|
2980
|
-
const outputPath =
|
|
3262
|
+
const outputDir = options.output || path9.join(process.cwd(), "dist");
|
|
3263
|
+
const outputPath = path9.join(outputDir, `${packageName}.zip`);
|
|
2981
3264
|
await fs.ensureDir(outputDir);
|
|
2982
3265
|
logger.startSpinner("Creating zip archive...");
|
|
2983
3266
|
try {
|
|
@@ -2990,11 +3273,11 @@ async function packageCommand(options) {
|
|
|
2990
3273
|
logger.newLine();
|
|
2991
3274
|
logger.info(`Package: ${packageName}.zip`);
|
|
2992
3275
|
logger.log(`Size: ${sizeMB} MB`);
|
|
2993
|
-
logger.log(`Location: ${
|
|
3276
|
+
logger.log(`Location: ${path9.relative(process.cwd(), outputPath)}`);
|
|
2994
3277
|
logger.newLine();
|
|
2995
3278
|
logger.section("Next steps:");
|
|
2996
3279
|
logger.log(
|
|
2997
|
-
` onexthm deploy --package ${
|
|
3280
|
+
` onexthm deploy --package ${path9.relative(process.cwd(), outputPath)}`
|
|
2998
3281
|
);
|
|
2999
3282
|
} catch (error) {
|
|
3000
3283
|
logger.stopSpinner(false, "Failed to create package");
|
|
@@ -3052,9 +3335,9 @@ async function deployCommand(options) {
|
|
|
3052
3335
|
ensureOneXProject();
|
|
3053
3336
|
let packagePath;
|
|
3054
3337
|
if (options.package) {
|
|
3055
|
-
packagePath =
|
|
3338
|
+
packagePath = path9.resolve(options.package);
|
|
3056
3339
|
} else if (options.theme) {
|
|
3057
|
-
const distDir =
|
|
3340
|
+
const distDir = path9.join(process.cwd(), "dist");
|
|
3058
3341
|
if (!fs.existsSync(distDir)) {
|
|
3059
3342
|
logger.error("No dist/ directory found. Run 'onexthm package' first.");
|
|
3060
3343
|
process.exit(1);
|
|
@@ -3069,7 +3352,7 @@ async function deployCommand(options) {
|
|
|
3069
3352
|
process.exit(1);
|
|
3070
3353
|
}
|
|
3071
3354
|
packageFiles.sort().reverse();
|
|
3072
|
-
packagePath =
|
|
3355
|
+
packagePath = path9.join(distDir, packageFiles[0]);
|
|
3073
3356
|
} else {
|
|
3074
3357
|
logger.error("Either --package or --theme must be specified.");
|
|
3075
3358
|
logger.info("Examples:");
|
|
@@ -3083,11 +3366,11 @@ async function deployCommand(options) {
|
|
|
3083
3366
|
}
|
|
3084
3367
|
const stats = await fs.stat(packagePath);
|
|
3085
3368
|
const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
|
|
3086
|
-
const fileName =
|
|
3369
|
+
const fileName = path9.basename(packagePath);
|
|
3087
3370
|
logger.newLine();
|
|
3088
3371
|
logger.info(`Package: ${fileName}`);
|
|
3089
3372
|
logger.log(`Size: ${sizeMB} MB`);
|
|
3090
|
-
logger.log(`Path: ${
|
|
3373
|
+
logger.log(`Path: ${path9.relative(process.cwd(), packagePath)}`);
|
|
3091
3374
|
logger.newLine();
|
|
3092
3375
|
const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
|
|
3093
3376
|
const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
|
|
@@ -3191,11 +3474,11 @@ function getBucketName(env) {
|
|
|
3191
3474
|
return environment === "production" ? "theme-s3-bucket" : "theme-s3-bucket";
|
|
3192
3475
|
}
|
|
3193
3476
|
async function findCompiledThemeDir(themeId, version2) {
|
|
3194
|
-
const searchPaths = [
|
|
3477
|
+
const searchPaths = [path9.resolve(process.cwd(), "dist")];
|
|
3195
3478
|
for (const dir of searchPaths) {
|
|
3196
3479
|
if (await fs.pathExists(dir)) {
|
|
3197
|
-
const hasManifest = await fs.pathExists(
|
|
3198
|
-
const hasThemeEntry = await fs.pathExists(
|
|
3480
|
+
const hasManifest = await fs.pathExists(path9.join(dir, "manifest.json"));
|
|
3481
|
+
const hasThemeEntry = await fs.pathExists(path9.join(dir, "bundle-entry.js")) || await fs.pathExists(path9.join(dir, "theme.config.js")) || await fs.pathExists(path9.join(dir, "index.js"));
|
|
3199
3482
|
if (hasManifest || hasThemeEntry) {
|
|
3200
3483
|
return dir;
|
|
3201
3484
|
}
|
|
@@ -3204,7 +3487,7 @@ async function findCompiledThemeDir(themeId, version2) {
|
|
|
3204
3487
|
return null;
|
|
3205
3488
|
}
|
|
3206
3489
|
async function readManifest() {
|
|
3207
|
-
const manifestTsPath =
|
|
3490
|
+
const manifestTsPath = path9.resolve(process.cwd(), "manifest.ts");
|
|
3208
3491
|
if (await fs.pathExists(manifestTsPath)) {
|
|
3209
3492
|
try {
|
|
3210
3493
|
const module = await import(manifestTsPath);
|
|
@@ -3213,7 +3496,7 @@ async function readManifest() {
|
|
|
3213
3496
|
logger.warning("Failed to import manifest.ts, trying package.json");
|
|
3214
3497
|
}
|
|
3215
3498
|
}
|
|
3216
|
-
const packageJsonPath =
|
|
3499
|
+
const packageJsonPath = path9.resolve(process.cwd(), "package.json");
|
|
3217
3500
|
if (await fs.pathExists(packageJsonPath)) {
|
|
3218
3501
|
const pkg = await fs.readJson(packageJsonPath);
|
|
3219
3502
|
return {
|
|
@@ -3247,13 +3530,13 @@ async function findSourceDir(themeId, explicitDir) {
|
|
|
3247
3530
|
}
|
|
3248
3531
|
const searchPaths = [
|
|
3249
3532
|
process.cwd(),
|
|
3250
|
-
|
|
3251
|
-
|
|
3533
|
+
path9.resolve(process.cwd(), `../../themes/${themeId}`),
|
|
3534
|
+
path9.resolve(process.cwd(), `../themes/${themeId}`)
|
|
3252
3535
|
];
|
|
3253
3536
|
const markers = ["theme.config.ts", "bundle-entry.ts"];
|
|
3254
3537
|
for (const dir of searchPaths) {
|
|
3255
3538
|
for (const marker of markers) {
|
|
3256
|
-
if (await fs.pathExists(
|
|
3539
|
+
if (await fs.pathExists(path9.join(dir, marker))) {
|
|
3257
3540
|
return dir;
|
|
3258
3541
|
}
|
|
3259
3542
|
}
|
|
@@ -3304,8 +3587,8 @@ async function uploadCommand(options) {
|
|
|
3304
3587
|
}
|
|
3305
3588
|
spinner.succeed(`Found compiled theme at: ${compiledDir}`);
|
|
3306
3589
|
spinner.start("Creating bundle.zip...");
|
|
3307
|
-
const tmpDir =
|
|
3308
|
-
const bundleZipPath =
|
|
3590
|
+
const tmpDir = os.tmpdir();
|
|
3591
|
+
const bundleZipPath = path9.join(tmpDir, `${themeId}-${version2}-bundle.zip`);
|
|
3309
3592
|
await createZipFromDir(compiledDir, bundleZipPath);
|
|
3310
3593
|
const bundleZipBuffer = await fs.readFile(bundleZipPath);
|
|
3311
3594
|
const bundleSizeMB = (bundleZipBuffer.length / 1024 / 1024).toFixed(2);
|
|
@@ -3359,7 +3642,7 @@ async function uploadCommand(options) {
|
|
|
3359
3642
|
if (sourceDir) {
|
|
3360
3643
|
spinner.succeed(`Found source at: ${sourceDir}`);
|
|
3361
3644
|
spinner.start("Creating source.zip...");
|
|
3362
|
-
const sourceZipPath =
|
|
3645
|
+
const sourceZipPath = path9.join(
|
|
3363
3646
|
tmpDir,
|
|
3364
3647
|
`${themeId}-${version2}-source.zip`
|
|
3365
3648
|
);
|
|
@@ -3493,8 +3776,8 @@ async function resolveLatestVersion(s3Client, bucket, themeId) {
|
|
|
3493
3776
|
async function createCompatibilityFiles(outputDir, manifest) {
|
|
3494
3777
|
const entryFile = manifest.output?.entry || "bundle-entry.js";
|
|
3495
3778
|
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
3496
|
-
const hashedPath =
|
|
3497
|
-
const stablePath =
|
|
3779
|
+
const hashedPath = path9.join(outputDir, entryFile);
|
|
3780
|
+
const stablePath = path9.join(outputDir, "bundle-entry.js");
|
|
3498
3781
|
if (await fs.pathExists(hashedPath)) {
|
|
3499
3782
|
await fs.copy(hashedPath, stablePath);
|
|
3500
3783
|
const mapPath = hashedPath + ".map";
|
|
@@ -3503,13 +3786,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
|
|
|
3503
3786
|
}
|
|
3504
3787
|
}
|
|
3505
3788
|
}
|
|
3506
|
-
const sectionsRegistryPath =
|
|
3789
|
+
const sectionsRegistryPath = path9.join(outputDir, "sections-registry.js");
|
|
3507
3790
|
const content = `// Re-export all sections from bundle-entry
|
|
3508
3791
|
// This file exists to maintain compatibility with the import path
|
|
3509
3792
|
export * from './bundle-entry.js';
|
|
3510
3793
|
`;
|
|
3511
3794
|
await fs.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
3512
|
-
const pkgJsonPath =
|
|
3795
|
+
const pkgJsonPath = path9.join(outputDir, "package.json");
|
|
3513
3796
|
await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
3514
3797
|
}
|
|
3515
3798
|
function showDownloadFailureHelp(themeId, bucket) {
|
|
@@ -3571,6 +3854,18 @@ async function downloadCommand(options) {
|
|
|
3571
3854
|
spinner.succeed(
|
|
3572
3855
|
`Resolved latest version: ${chalk4.cyan(resolvedVersion)}`
|
|
3573
3856
|
);
|
|
3857
|
+
const isCI = !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.VERCEL);
|
|
3858
|
+
if (isCI) {
|
|
3859
|
+
console.log(
|
|
3860
|
+
chalk4.yellow(
|
|
3861
|
+
`
|
|
3862
|
+
Warning: Resolved "latest" to ${resolvedVersion} in CI environment.
|
|
3863
|
+
For production builds, pin to a specific version:
|
|
3864
|
+
THEME_VERSION=${resolvedVersion}
|
|
3865
|
+
`
|
|
3866
|
+
)
|
|
3867
|
+
);
|
|
3868
|
+
}
|
|
3574
3869
|
}
|
|
3575
3870
|
spinner.start(
|
|
3576
3871
|
`Downloading bundle.zip for ${themeId}@${resolvedVersion}...`
|
|
@@ -3592,7 +3887,7 @@ async function downloadCommand(options) {
|
|
|
3592
3887
|
zip.extractAllTo(outputDir, true);
|
|
3593
3888
|
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
3594
3889
|
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
3595
|
-
const manifestPath =
|
|
3890
|
+
const manifestPath = path9.join(outputDir, "manifest.json");
|
|
3596
3891
|
const manifest = await fs.readJson(manifestPath);
|
|
3597
3892
|
await createCompatibilityFiles(outputDir, manifest);
|
|
3598
3893
|
console.log();
|
|
@@ -3726,7 +4021,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3726
4021
|
const oldPrefix = `${oldName}-`;
|
|
3727
4022
|
const newPrefix = `${newName}-`;
|
|
3728
4023
|
const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3729
|
-
const pkgPath =
|
|
4024
|
+
const pkgPath = path9.join(themeDir, "package.json");
|
|
3730
4025
|
if (await fs.pathExists(pkgPath)) {
|
|
3731
4026
|
const pkg = await fs.readJson(pkgPath);
|
|
3732
4027
|
pkg.name = `@onex-themes/${newName}`;
|
|
@@ -3742,7 +4037,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3742
4037
|
}
|
|
3743
4038
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3744
4039
|
}
|
|
3745
|
-
const configPath =
|
|
4040
|
+
const configPath = path9.join(themeDir, "theme.config.ts");
|
|
3746
4041
|
if (await fs.pathExists(configPath)) {
|
|
3747
4042
|
let content = await fs.readFile(configPath, "utf-8");
|
|
3748
4043
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3752,7 +4047,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3752
4047
|
);
|
|
3753
4048
|
await fs.writeFile(configPath, content);
|
|
3754
4049
|
}
|
|
3755
|
-
const layoutPath =
|
|
4050
|
+
const layoutPath = path9.join(themeDir, "theme.layout.ts");
|
|
3756
4051
|
if (await fs.pathExists(layoutPath)) {
|
|
3757
4052
|
let content = await fs.readFile(layoutPath, "utf-8");
|
|
3758
4053
|
content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
|
|
@@ -3765,7 +4060,7 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3765
4060
|
const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3766
4061
|
const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
|
|
3767
4062
|
for (const file of tsFiles) {
|
|
3768
|
-
const filePath =
|
|
4063
|
+
const filePath = path9.join(themeDir, file);
|
|
3769
4064
|
let content = await fs.readFile(filePath, "utf-8");
|
|
3770
4065
|
const original = content;
|
|
3771
4066
|
content = content.replace(
|
|
@@ -3794,7 +4089,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3794
4089
|
const spinner = ora("Initializing clone...").start();
|
|
3795
4090
|
try {
|
|
3796
4091
|
const bucket = options.bucket || getBucketName3(options.environment);
|
|
3797
|
-
const outputDir = options.output ||
|
|
4092
|
+
const outputDir = options.output || path9.resolve(process.cwd(), newName);
|
|
3798
4093
|
const s3Client = getS3Client3();
|
|
3799
4094
|
if (await fs.pathExists(outputDir)) {
|
|
3800
4095
|
spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
|
|
@@ -3849,7 +4144,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3849
4144
|
spinner.succeed(
|
|
3850
4145
|
`Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
|
|
3851
4146
|
);
|
|
3852
|
-
const envExamplePath =
|
|
4147
|
+
const envExamplePath = path9.join(outputDir, ".env.example");
|
|
3853
4148
|
if (!await fs.pathExists(envExamplePath)) {
|
|
3854
4149
|
await fs.writeFile(
|
|
3855
4150
|
envExamplePath,
|
|
@@ -3862,7 +4157,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3862
4157
|
].join("\n")
|
|
3863
4158
|
);
|
|
3864
4159
|
}
|
|
3865
|
-
const mcpJsonPath =
|
|
4160
|
+
const mcpJsonPath = path9.join(outputDir, ".mcp.json");
|
|
3866
4161
|
if (await fs.pathExists(mcpJsonPath)) {
|
|
3867
4162
|
const { default: inquirerMod } = await import('inquirer');
|
|
3868
4163
|
const { figmaApiKey } = await inquirerMod.prompt([
|
|
@@ -3887,7 +4182,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3887
4182
|
}
|
|
3888
4183
|
if (options.install !== false) {
|
|
3889
4184
|
const hasPkgJson = await fs.pathExists(
|
|
3890
|
-
|
|
4185
|
+
path9.join(outputDir, "package.json")
|
|
3891
4186
|
);
|
|
3892
4187
|
if (hasPkgJson) {
|
|
3893
4188
|
spinner.start("Installing dependencies...");
|
|
@@ -3914,7 +4209,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3914
4209
|
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
3915
4210
|
console.log();
|
|
3916
4211
|
console.log(chalk4.cyan("Next steps:"));
|
|
3917
|
-
console.log(chalk4.gray(` cd ${
|
|
4212
|
+
console.log(chalk4.gray(` cd ${path9.relative(process.cwd(), outputDir)}`));
|
|
3918
4213
|
console.log(
|
|
3919
4214
|
chalk4.gray(" cp .env.example .env # then add your Company ID")
|
|
3920
4215
|
);
|
|
@@ -3949,7 +4244,7 @@ var MIME_TYPES = {
|
|
|
3949
4244
|
};
|
|
3950
4245
|
function createDevServer(options) {
|
|
3951
4246
|
const clients = /* @__PURE__ */ new Set();
|
|
3952
|
-
const themeDataPath =
|
|
4247
|
+
const themeDataPath = path9.join(options.distDir, "theme-data.json");
|
|
3953
4248
|
const server = http.createServer((req, res) => {
|
|
3954
4249
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
3955
4250
|
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
@@ -3975,8 +4270,8 @@ function createDevServer(options) {
|
|
|
3975
4270
|
if (pathname.startsWith("/_assets/")) {
|
|
3976
4271
|
const parts = pathname.replace(/^\/_assets\//, "").split("/");
|
|
3977
4272
|
const assetSubpath = parts.slice(1).join("/");
|
|
3978
|
-
const assetPath =
|
|
3979
|
-
if (!assetPath.startsWith(
|
|
4273
|
+
const assetPath = path9.join(options.themePath, "assets", assetSubpath);
|
|
4274
|
+
if (!assetPath.startsWith(path9.join(options.themePath, "assets"))) {
|
|
3980
4275
|
res.writeHead(403);
|
|
3981
4276
|
res.end("Forbidden");
|
|
3982
4277
|
return;
|
|
@@ -3987,8 +4282,8 @@ function createDevServer(options) {
|
|
|
3987
4282
|
if (pathname.startsWith("/themes/")) {
|
|
3988
4283
|
const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
|
|
3989
4284
|
if (match) {
|
|
3990
|
-
const assetPath =
|
|
3991
|
-
if (!assetPath.startsWith(
|
|
4285
|
+
const assetPath = path9.join(options.themePath, "assets", match[1]);
|
|
4286
|
+
if (!assetPath.startsWith(path9.join(options.themePath, "assets"))) {
|
|
3992
4287
|
res.writeHead(403);
|
|
3993
4288
|
res.end("Forbidden");
|
|
3994
4289
|
return;
|
|
@@ -4002,26 +4297,26 @@ function createDevServer(options) {
|
|
|
4002
4297
|
const segments = subpath.split("/");
|
|
4003
4298
|
let assetPath;
|
|
4004
4299
|
if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
|
|
4005
|
-
assetPath =
|
|
4300
|
+
assetPath = path9.join(
|
|
4006
4301
|
options.themePath,
|
|
4007
4302
|
"assets",
|
|
4008
4303
|
segments.slice(1).join("/")
|
|
4009
4304
|
);
|
|
4010
4305
|
} else {
|
|
4011
|
-
assetPath =
|
|
4306
|
+
assetPath = path9.join(options.themePath, "assets", subpath);
|
|
4012
4307
|
}
|
|
4013
|
-
if (assetPath.startsWith(
|
|
4308
|
+
if (assetPath.startsWith(path9.join(options.themePath, "assets")) && fs3.existsSync(assetPath)) {
|
|
4014
4309
|
serveFile(res, assetPath);
|
|
4015
4310
|
return;
|
|
4016
4311
|
}
|
|
4017
4312
|
}
|
|
4018
|
-
const filePath =
|
|
4313
|
+
const filePath = path9.join(options.distDir, pathname);
|
|
4019
4314
|
if (!filePath.startsWith(options.distDir)) {
|
|
4020
4315
|
res.writeHead(403);
|
|
4021
4316
|
res.end("Forbidden");
|
|
4022
4317
|
return;
|
|
4023
4318
|
}
|
|
4024
|
-
if (
|
|
4319
|
+
if (fs3.existsSync(filePath) && fs3.statSync(filePath).isFile()) {
|
|
4025
4320
|
serveFile(res, filePath);
|
|
4026
4321
|
} else {
|
|
4027
4322
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
@@ -4053,14 +4348,14 @@ function createDevServer(options) {
|
|
|
4053
4348
|
}
|
|
4054
4349
|
function serveFile(res, filePath) {
|
|
4055
4350
|
try {
|
|
4056
|
-
if (!
|
|
4351
|
+
if (!fs3.existsSync(filePath)) {
|
|
4057
4352
|
res.writeHead(404);
|
|
4058
4353
|
res.end("Not Found");
|
|
4059
4354
|
return;
|
|
4060
4355
|
}
|
|
4061
|
-
const ext =
|
|
4356
|
+
const ext = path9.extname(filePath);
|
|
4062
4357
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
4063
|
-
const content =
|
|
4358
|
+
const content = fs3.readFileSync(filePath);
|
|
4064
4359
|
res.writeHead(200, { "Content-Type": contentType });
|
|
4065
4360
|
res.end(content);
|
|
4066
4361
|
} catch {
|
|
@@ -4073,7 +4368,7 @@ function generatePreviewHTML(themeName, port, themeDataPath) {
|
|
|
4073
4368
|
let fontVarsCSS = "";
|
|
4074
4369
|
if (themeDataPath) {
|
|
4075
4370
|
try {
|
|
4076
|
-
const themeData = JSON.parse(
|
|
4371
|
+
const themeData = JSON.parse(fs3.readFileSync(themeDataPath, "utf-8"));
|
|
4077
4372
|
const typography = (themeData?.themeConfig || themeData?.theme?.config)?.typography?.fontFamily;
|
|
4078
4373
|
if (typography) {
|
|
4079
4374
|
const fontFamilies = /* @__PURE__ */ new Set();
|
|
@@ -4161,14 +4456,14 @@ async function devCommand(options) {
|
|
|
4161
4456
|
if (options.theme) {
|
|
4162
4457
|
themeName = options.theme;
|
|
4163
4458
|
try {
|
|
4164
|
-
const workspaceThemePath =
|
|
4459
|
+
const workspaceThemePath = path9.join(getThemesDir(), themeName);
|
|
4165
4460
|
if (fs.existsSync(workspaceThemePath)) {
|
|
4166
4461
|
themePath = workspaceThemePath;
|
|
4167
4462
|
} else {
|
|
4168
|
-
themePath =
|
|
4463
|
+
themePath = path9.join(process.cwd(), themeName);
|
|
4169
4464
|
}
|
|
4170
4465
|
} catch {
|
|
4171
|
-
themePath =
|
|
4466
|
+
themePath = path9.join(process.cwd(), themeName);
|
|
4172
4467
|
}
|
|
4173
4468
|
if (!fs.existsSync(themePath)) {
|
|
4174
4469
|
logger.error(`Theme "${themeName}" not found.`);
|
|
@@ -4179,10 +4474,10 @@ async function devCommand(options) {
|
|
|
4179
4474
|
"theme.config.ts",
|
|
4180
4475
|
"bundle-entry.ts",
|
|
4181
4476
|
"manifest.ts"
|
|
4182
|
-
].some((f) => fs.existsSync(
|
|
4477
|
+
].some((f) => fs.existsSync(path9.join(process.cwd(), f)));
|
|
4183
4478
|
if (isThemeDir) {
|
|
4184
4479
|
themePath = process.cwd();
|
|
4185
|
-
themeName =
|
|
4480
|
+
themeName = path9.basename(themePath);
|
|
4186
4481
|
} else {
|
|
4187
4482
|
logger.error(
|
|
4188
4483
|
"Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
|
|
@@ -4251,9 +4546,9 @@ async function devCommand(options) {
|
|
|
4251
4546
|
watcher.close();
|
|
4252
4547
|
await context2.dispose();
|
|
4253
4548
|
server.close();
|
|
4254
|
-
const shimPath =
|
|
4549
|
+
const shimPath = path9.join(outputDir, ".process-shim.js");
|
|
4255
4550
|
try {
|
|
4256
|
-
await
|
|
4551
|
+
await fs8.unlink(shimPath);
|
|
4257
4552
|
} catch {
|
|
4258
4553
|
}
|
|
4259
4554
|
process.exit(0);
|
|
@@ -4262,8 +4557,8 @@ async function devCommand(options) {
|
|
|
4262
4557
|
|
|
4263
4558
|
// src/commands/config.ts
|
|
4264
4559
|
init_logger();
|
|
4265
|
-
var CONFIG_DIR =
|
|
4266
|
-
var CONFIG_FILE =
|
|
4560
|
+
var CONFIG_DIR = path9.join(os.homedir(), ".onexthm");
|
|
4561
|
+
var CONFIG_FILE = path9.join(CONFIG_DIR, ".env");
|
|
4267
4562
|
var CONFIG_ENTRIES = [
|
|
4268
4563
|
{
|
|
4269
4564
|
key: "AWS_ACCESS_KEY_ID",
|
|
@@ -4405,122 +4700,6 @@ async function configCommand() {
|
|
|
4405
4700
|
|
|
4406
4701
|
// src/commands/login.ts
|
|
4407
4702
|
init_logger();
|
|
4408
|
-
var AUTH_DIR = path8.join(os3.homedir(), ".onexthm");
|
|
4409
|
-
var AUTH_FILE = path8.join(AUTH_DIR, "auth.json");
|
|
4410
|
-
function getApiUrl() {
|
|
4411
|
-
return process.env.ONEXTHM_API_URL || process.env.NEXT_PUBLIC_API_URL || "https://platform-dev.onexeos.com";
|
|
4412
|
-
}
|
|
4413
|
-
async function saveAuthTokens(tokens) {
|
|
4414
|
-
await fs.ensureDir(AUTH_DIR);
|
|
4415
|
-
const key = getMachineKey();
|
|
4416
|
-
const data = JSON.stringify(tokens);
|
|
4417
|
-
const encrypted = encrypt(data, key);
|
|
4418
|
-
await fs.writeFile(AUTH_FILE, encrypted, "utf-8");
|
|
4419
|
-
}
|
|
4420
|
-
function loadAuthTokens() {
|
|
4421
|
-
try {
|
|
4422
|
-
if (!fs.existsSync(AUTH_FILE)) return null;
|
|
4423
|
-
const encrypted = fs.readFileSync(AUTH_FILE, "utf-8");
|
|
4424
|
-
const key = getMachineKey();
|
|
4425
|
-
const data = decrypt(encrypted, key);
|
|
4426
|
-
return JSON.parse(data);
|
|
4427
|
-
} catch {
|
|
4428
|
-
return null;
|
|
4429
|
-
}
|
|
4430
|
-
}
|
|
4431
|
-
async function clearAuthTokens() {
|
|
4432
|
-
try {
|
|
4433
|
-
await fs.remove(AUTH_FILE);
|
|
4434
|
-
} catch {
|
|
4435
|
-
}
|
|
4436
|
-
}
|
|
4437
|
-
function isTokenExpired(tokens) {
|
|
4438
|
-
return Date.now() / 1e3 > tokens.expiresAt - 60;
|
|
4439
|
-
}
|
|
4440
|
-
async function getValidTokens() {
|
|
4441
|
-
const tokens = loadAuthTokens();
|
|
4442
|
-
if (!tokens) return null;
|
|
4443
|
-
if (!isTokenExpired(tokens)) return tokens;
|
|
4444
|
-
try {
|
|
4445
|
-
const apiUrl = getApiUrl();
|
|
4446
|
-
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
4447
|
-
method: "POST",
|
|
4448
|
-
headers: { "Content-Type": "application/json" },
|
|
4449
|
-
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
4450
|
-
});
|
|
4451
|
-
if (!response.ok) {
|
|
4452
|
-
await clearAuthTokens();
|
|
4453
|
-
return null;
|
|
4454
|
-
}
|
|
4455
|
-
const data = await response.json();
|
|
4456
|
-
const body = data.statusCode ? data.body : data;
|
|
4457
|
-
const refreshed = {
|
|
4458
|
-
...tokens,
|
|
4459
|
-
accessToken: body.AccessToken || tokens.accessToken,
|
|
4460
|
-
idToken: body.IdToken || tokens.idToken,
|
|
4461
|
-
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
4462
|
-
};
|
|
4463
|
-
await saveAuthTokens(refreshed);
|
|
4464
|
-
return refreshed;
|
|
4465
|
-
} catch {
|
|
4466
|
-
await clearAuthTokens();
|
|
4467
|
-
return null;
|
|
4468
|
-
}
|
|
4469
|
-
}
|
|
4470
|
-
async function authenticatedFetch(url, init) {
|
|
4471
|
-
const tokens = await getValidTokens();
|
|
4472
|
-
if (!tokens) {
|
|
4473
|
-
throw new Error("Not logged in. Run: onexthm login");
|
|
4474
|
-
}
|
|
4475
|
-
const headers = new Headers(init?.headers);
|
|
4476
|
-
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
4477
|
-
headers.set("Content-Type", "application/json");
|
|
4478
|
-
return fetch(url, { ...init, headers });
|
|
4479
|
-
}
|
|
4480
|
-
function getMachineKey() {
|
|
4481
|
-
let seed;
|
|
4482
|
-
if (process.platform === "darwin") {
|
|
4483
|
-
seed = `onexthm:${os3.hostname()}:${os3.userInfo().username}`;
|
|
4484
|
-
} else if (process.platform === "linux") {
|
|
4485
|
-
try {
|
|
4486
|
-
seed = `onexthm:${fs.readFileSync("/etc/machine-id", "utf-8").trim()}`;
|
|
4487
|
-
} catch {
|
|
4488
|
-
seed = `onexthm:${os3.hostname()}:${os3.userInfo().username}`;
|
|
4489
|
-
}
|
|
4490
|
-
} else {
|
|
4491
|
-
seed = `onexthm:${os3.hostname()}:${os3.userInfo().username}`;
|
|
4492
|
-
}
|
|
4493
|
-
return crypto2.createHash("sha256").update(seed).digest();
|
|
4494
|
-
}
|
|
4495
|
-
function encrypt(text, key) {
|
|
4496
|
-
const iv = crypto2.randomBytes(16);
|
|
4497
|
-
const cipher = crypto2.createCipheriv("aes-256-gcm", key, iv);
|
|
4498
|
-
let encrypted = cipher.update(text, "utf-8", "hex");
|
|
4499
|
-
encrypted += cipher.final("hex");
|
|
4500
|
-
const tag = cipher.getAuthTag();
|
|
4501
|
-
return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted}`;
|
|
4502
|
-
}
|
|
4503
|
-
function decrypt(text, key) {
|
|
4504
|
-
const [ivHex, tagHex, encrypted] = text.split(":");
|
|
4505
|
-
const iv = Buffer.from(ivHex, "hex");
|
|
4506
|
-
const tag = Buffer.from(tagHex, "hex");
|
|
4507
|
-
const decipher = crypto2.createDecipheriv("aes-256-gcm", key, iv);
|
|
4508
|
-
decipher.setAuthTag(tag);
|
|
4509
|
-
let decrypted = decipher.update(encrypted, "hex", "utf-8");
|
|
4510
|
-
decrypted += decipher.final("utf-8");
|
|
4511
|
-
return decrypted;
|
|
4512
|
-
}
|
|
4513
|
-
function parseJwtClaims(idToken) {
|
|
4514
|
-
try {
|
|
4515
|
-
const payload = idToken.split(".")[1];
|
|
4516
|
-
const decoded = Buffer.from(payload, "base64url").toString("utf-8");
|
|
4517
|
-
return JSON.parse(decoded);
|
|
4518
|
-
} catch {
|
|
4519
|
-
return {};
|
|
4520
|
-
}
|
|
4521
|
-
}
|
|
4522
|
-
|
|
4523
|
-
// src/commands/login.ts
|
|
4524
4703
|
async function loginCommand() {
|
|
4525
4704
|
logger.header("OneX Theme Developer Login");
|
|
4526
4705
|
const existing = loadAuthTokens();
|
|
@@ -4646,13 +4825,13 @@ async function publishCommand(options) {
|
|
|
4646
4825
|
logger.info(`Logged in as: ${tokens.user.email}`);
|
|
4647
4826
|
let themePath;
|
|
4648
4827
|
if (options.theme) {
|
|
4649
|
-
themePath =
|
|
4828
|
+
themePath = path9.resolve(options.theme);
|
|
4650
4829
|
} else {
|
|
4651
4830
|
const isThemeDir = [
|
|
4652
4831
|
"theme.config.ts",
|
|
4653
4832
|
"bundle-entry.ts",
|
|
4654
4833
|
"manifest.ts"
|
|
4655
|
-
].some((f) => fs.existsSync(
|
|
4834
|
+
].some((f) => fs.existsSync(path9.join(process.cwd(), f)));
|
|
4656
4835
|
if (isThemeDir) {
|
|
4657
4836
|
themePath = process.cwd();
|
|
4658
4837
|
} else {
|
|
@@ -4662,14 +4841,31 @@ async function publishCommand(options) {
|
|
|
4662
4841
|
process.exit(1);
|
|
4663
4842
|
}
|
|
4664
4843
|
}
|
|
4665
|
-
const pkgPath =
|
|
4844
|
+
const pkgPath = path9.join(themePath, "package.json");
|
|
4666
4845
|
if (!fs.existsSync(pkgPath)) {
|
|
4667
4846
|
logger.error("No package.json found in theme directory");
|
|
4668
4847
|
process.exit(1);
|
|
4669
4848
|
}
|
|
4670
4849
|
const pkg = fs.readJsonSync(pkgPath);
|
|
4671
|
-
const themeId = pkg.name?.replace("@onex-themes/", "") ||
|
|
4850
|
+
const themeId = pkg.name?.replace("@onex-themes/", "") || path9.basename(themePath);
|
|
4851
|
+
if (options.bump) {
|
|
4852
|
+
const currentVersion = pkg.version || "1.0.0";
|
|
4853
|
+
const newVersion = semver.inc(currentVersion, options.bump);
|
|
4854
|
+
if (!newVersion) {
|
|
4855
|
+
logger.error(`Failed to bump version from ${currentVersion}`);
|
|
4856
|
+
process.exit(1);
|
|
4857
|
+
}
|
|
4858
|
+
pkg.version = newVersion;
|
|
4859
|
+
fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
|
|
4860
|
+
logger.info(`Bumped version: ${currentVersion} -> ${newVersion}`);
|
|
4861
|
+
}
|
|
4672
4862
|
const version2 = pkg.version || "1.0.0";
|
|
4863
|
+
if (!semver.valid(version2)) {
|
|
4864
|
+
logger.error(
|
|
4865
|
+
`Invalid version "${version2}" in package.json. Must be valid semver (e.g., 1.0.0)`
|
|
4866
|
+
);
|
|
4867
|
+
process.exit(1);
|
|
4868
|
+
}
|
|
4673
4869
|
logger.newLine();
|
|
4674
4870
|
logger.info(`Theme: ${themeId}`);
|
|
4675
4871
|
logger.info(`Version: ${version2}`);
|
|
@@ -4706,6 +4902,38 @@ async function publishCommand(options) {
|
|
|
4706
4902
|
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4707
4903
|
process.exit(1);
|
|
4708
4904
|
}
|
|
4905
|
+
logger.startSpinner("Checking version availability...");
|
|
4906
|
+
try {
|
|
4907
|
+
const checkResponse = await authenticatedFetch(
|
|
4908
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/exists`,
|
|
4909
|
+
{ method: "GET" }
|
|
4910
|
+
);
|
|
4911
|
+
const checkData = await checkResponse.json();
|
|
4912
|
+
const checkBody = checkData.statusCode ? checkData.body : checkData;
|
|
4913
|
+
if (checkBody.exists) {
|
|
4914
|
+
logger.stopSpinner(false, "Version already published");
|
|
4915
|
+
const patchVer = semver.inc(version2, "patch") || "?";
|
|
4916
|
+
const minorVer = semver.inc(version2, "minor") || "?";
|
|
4917
|
+
const majorVer = semver.inc(version2, "major") || "?";
|
|
4918
|
+
logger.error(
|
|
4919
|
+
`
|
|
4920
|
+
Version ${version2} of "${themeId}" is already published and cannot be overwritten.
|
|
4921
|
+
|
|
4922
|
+
To publish a new version:
|
|
4923
|
+
1. Bump version in package.json (e.g., ${version2} -> ${patchVer})
|
|
4924
|
+
2. Run: onexthm publish
|
|
4925
|
+
|
|
4926
|
+
Or use the --bump flag:
|
|
4927
|
+
onexthm publish --bump patch (${version2} -> ${patchVer})
|
|
4928
|
+
onexthm publish --bump minor (${version2} -> ${minorVer})
|
|
4929
|
+
onexthm publish --bump major (${version2} -> ${majorVer})`
|
|
4930
|
+
);
|
|
4931
|
+
process.exit(1);
|
|
4932
|
+
}
|
|
4933
|
+
logger.stopSpinner(true, `Version ${version2} is available`);
|
|
4934
|
+
} catch (error) {
|
|
4935
|
+
logger.stopSpinner(true, "Version check skipped (endpoint not available)");
|
|
4936
|
+
}
|
|
4709
4937
|
logger.startSpinner("Building theme...");
|
|
4710
4938
|
try {
|
|
4711
4939
|
const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
|
|
@@ -4751,13 +4979,13 @@ async function publishCommand(options) {
|
|
|
4751
4979
|
try {
|
|
4752
4980
|
const archiver3 = await import('archiver');
|
|
4753
4981
|
const { createWriteStream } = await import('fs');
|
|
4754
|
-
const distDir =
|
|
4982
|
+
const distDir = path9.join(themePath, "dist");
|
|
4755
4983
|
if (!fs.existsSync(distDir)) {
|
|
4756
4984
|
logger.stopSpinner(false, "No dist/ directory");
|
|
4757
4985
|
logger.error("Build the theme first: onexthm build");
|
|
4758
4986
|
process.exit(1);
|
|
4759
4987
|
}
|
|
4760
|
-
const bundleZipPath =
|
|
4988
|
+
const bundleZipPath = path9.join(themePath, "dist", "bundle.zip");
|
|
4761
4989
|
await createZip(distDir, bundleZipPath, [
|
|
4762
4990
|
"bundle.zip",
|
|
4763
4991
|
"source.zip",
|
|
@@ -4782,7 +5010,7 @@ async function publishCommand(options) {
|
|
|
4782
5010
|
}
|
|
4783
5011
|
logger.startSpinner("Uploading source...");
|
|
4784
5012
|
try {
|
|
4785
|
-
const sourceZipPath =
|
|
5013
|
+
const sourceZipPath = path9.join(themePath, "dist", "source.zip");
|
|
4786
5014
|
await createZip(themePath, sourceZipPath, [
|
|
4787
5015
|
"node_modules",
|
|
4788
5016
|
"dist",
|
|
@@ -4867,17 +5095,23 @@ async function createZip(sourceDir, outputPath, exclude) {
|
|
|
4867
5095
|
}
|
|
4868
5096
|
|
|
4869
5097
|
// src/cli.ts
|
|
5098
|
+
dotenv.config({
|
|
5099
|
+
path: path9.join(process.cwd(), ".env.local"),
|
|
5100
|
+
override: true
|
|
5101
|
+
});
|
|
5102
|
+
dotenv.config({ path: path9.join(process.cwd(), ".env") });
|
|
4870
5103
|
try {
|
|
4871
5104
|
const projectRoot = getProjectRoot();
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
5105
|
+
if (path9.resolve(projectRoot) !== path9.resolve(process.cwd())) {
|
|
5106
|
+
dotenv.config({
|
|
5107
|
+
path: path9.join(projectRoot, ".env.local")
|
|
5108
|
+
});
|
|
5109
|
+
dotenv.config({ path: path9.join(projectRoot, ".env") });
|
|
5110
|
+
}
|
|
4877
5111
|
} catch {
|
|
4878
5112
|
}
|
|
4879
5113
|
dotenv.config({
|
|
4880
|
-
path:
|
|
5114
|
+
path: path9.join(os.homedir(), ".onexthm", ".env"),
|
|
4881
5115
|
quiet: true
|
|
4882
5116
|
});
|
|
4883
5117
|
var require2 = createRequire(import.meta.url);
|
|
@@ -4937,7 +5171,10 @@ program.command("config").description("Configure OneX CLI credentials (AWS, API
|
|
|
4937
5171
|
program.command("login").description("Login to OneX platform").action(loginCommand);
|
|
4938
5172
|
program.command("logout").description("Logout from OneX platform").action(logoutCommand);
|
|
4939
5173
|
program.command("whoami").description("Show current logged-in developer").action(whoamiCommand);
|
|
4940
|
-
program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").
|
|
5174
|
+
program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").option(
|
|
5175
|
+
"--bump <type>",
|
|
5176
|
+
"Auto-bump version before publish (patch|minor|major)"
|
|
5177
|
+
).action(publishCommand);
|
|
4941
5178
|
program.configureOutput({
|
|
4942
5179
|
writeErr: (str) => process.stderr.write(chalk4.red(str))
|
|
4943
5180
|
});
|