@onexapis/cli 1.1.17 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -16
- package/dist/cli.js +522 -286
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +519 -283
- package/dist/cli.mjs.map +1 -1
- package/dist/index.js +47 -270
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +47 -270
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/default/.env.example +1 -1
- package/templates/default/.mcp.json +8 -0
- package/templates/default/CLAUDE.md +941 -0
- package/templates/default/bundle-entry.ts +18 -0
- package/templates/default/index.ts +26 -0
- package/templates/default/package.json +37 -0
- package/templates/default/pages/about.ts +66 -0
- package/templates/default/pages/home.ts +93 -0
- package/templates/default/pages/showcase.ts +146 -0
- package/templates/default/sections/about/about-default.tsx +237 -0
- package/templates/default/sections/about/about.schema.ts +259 -0
- package/templates/default/sections/about/index.ts +15 -0
- package/templates/default/sections/cta/cta-default.tsx +180 -0
- package/templates/default/sections/cta/cta.schema.ts +210 -0
- package/templates/default/sections/cta/index.ts +11 -0
- package/templates/default/sections/features/features-default.tsx +154 -0
- package/templates/default/sections/features/features.schema.ts +330 -0
- package/templates/default/sections/features/index.ts +11 -0
- package/templates/default/sections/gallery/gallery-default.tsx +134 -0
- package/templates/default/sections/gallery/gallery.schema.ts +397 -0
- package/templates/default/sections/gallery/index.ts +11 -0
- package/templates/default/sections/hero/hero-default.tsx +212 -0
- package/templates/default/sections/hero/hero.schema.ts +273 -0
- package/templates/default/sections/hero/index.ts +15 -0
- package/templates/default/sections/stats/index.ts +11 -0
- package/templates/default/sections/stats/stats-default.tsx +103 -0
- package/templates/default/sections/stats/stats.schema.ts +266 -0
- package/templates/default/sections/testimonials/index.ts +11 -0
- package/templates/default/sections/testimonials/testimonials-default.tsx +130 -0
- package/templates/default/sections/testimonials/testimonials.schema.ts +371 -0
- package/templates/default/sections-registry.ts +32 -0
- package/templates/default/theme.config.ts +107 -0
- package/templates/default/theme.layout.ts +21 -0
- package/templates/default/tsconfig.json +16 -7
- package/templates/default/README.md.ejs +0 -129
- package/templates/default/esbuild.config.js +0 -81
- package/templates/default/package.json.ejs +0 -31
- package/templates/default/src/config.ts.ejs +0 -98
- package/templates/default/src/index.ts.ejs +0 -11
- package/templates/default/src/layout.ts +0 -23
- package/templates/default/src/manifest.ts.ejs +0 -47
- package/templates/default/src/pages/home.ts.ejs +0 -37
- package/templates/default/src/sections/footer/footer-default.tsx +0 -28
- package/templates/default/src/sections/footer/footer.schema.ts +0 -45
- package/templates/default/src/sections/footer/index.ts +0 -2
- package/templates/default/src/sections/header/header-default.tsx +0 -61
- package/templates/default/src/sections/header/header.schema.ts +0 -46
- package/templates/default/src/sections/header/index.ts +0 -2
- package/templates/default/src/sections/hero/hero-default.tsx +0 -52
- package/templates/default/src/sections/hero/hero.schema.ts +0 -52
- package/templates/default/src/sections/hero/index.ts +0 -2
package/dist/cli.js
CHANGED
|
@@ -6,10 +6,10 @@ var ora = require('ora');
|
|
|
6
6
|
var esbuild = require('esbuild');
|
|
7
7
|
var path8 = require('path');
|
|
8
8
|
var fs7 = require('fs/promises');
|
|
9
|
-
var
|
|
9
|
+
var crypto2 = require('crypto');
|
|
10
10
|
var glob = require('glob');
|
|
11
11
|
var module$1 = require('module');
|
|
12
|
-
var
|
|
12
|
+
var os3 = require('os');
|
|
13
13
|
var dotenv = require('dotenv');
|
|
14
14
|
var fs = require('fs-extra');
|
|
15
15
|
var ejs = require('ejs');
|
|
@@ -19,7 +19,7 @@ var fs2 = require('fs');
|
|
|
19
19
|
var inquirer = require('inquirer');
|
|
20
20
|
var archiver = require('archiver');
|
|
21
21
|
var FormData = require('form-data');
|
|
22
|
-
var
|
|
22
|
+
var fetch2 = require('node-fetch');
|
|
23
23
|
var clientS3 = require('@aws-sdk/client-s3');
|
|
24
24
|
var AdmZip = require('adm-zip');
|
|
25
25
|
var chokidar = require('chokidar');
|
|
@@ -52,8 +52,8 @@ var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
|
52
52
|
var esbuild__namespace = /*#__PURE__*/_interopNamespace(esbuild);
|
|
53
53
|
var path8__default = /*#__PURE__*/_interopDefault(path8);
|
|
54
54
|
var fs7__default = /*#__PURE__*/_interopDefault(fs7);
|
|
55
|
-
var
|
|
56
|
-
var
|
|
55
|
+
var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
|
|
56
|
+
var os3__default = /*#__PURE__*/_interopDefault(os3);
|
|
57
57
|
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
58
58
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
59
59
|
var ejs__default = /*#__PURE__*/_interopDefault(ejs);
|
|
@@ -61,7 +61,7 @@ var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
|
61
61
|
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
62
62
|
var archiver__default = /*#__PURE__*/_interopDefault(archiver);
|
|
63
63
|
var FormData__default = /*#__PURE__*/_interopDefault(FormData);
|
|
64
|
-
var
|
|
64
|
+
var fetch2__default = /*#__PURE__*/_interopDefault(fetch2);
|
|
65
65
|
var AdmZip__default = /*#__PURE__*/_interopDefault(AdmZip);
|
|
66
66
|
var chokidar__default = /*#__PURE__*/_interopDefault(chokidar);
|
|
67
67
|
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
@@ -138,7 +138,7 @@ __export(compile_theme_exports, {
|
|
|
138
138
|
compilePreviewRuntime: () => compilePreviewRuntime,
|
|
139
139
|
compileStandaloneTheme: () => compileStandaloneTheme,
|
|
140
140
|
compileStandaloneThemeDev: () => compileStandaloneThemeDev,
|
|
141
|
-
generateManifest: () =>
|
|
141
|
+
generateManifest: () => generateManifest
|
|
142
142
|
});
|
|
143
143
|
async function resolveNodeModulesFile(startDir, relativePath) {
|
|
144
144
|
let dir = startDir;
|
|
@@ -526,7 +526,7 @@ async function contentHashEntry(outputDir) {
|
|
|
526
526
|
logger.warning("No entry file found in output, skipping content hash");
|
|
527
527
|
return;
|
|
528
528
|
}
|
|
529
|
-
const hash2 =
|
|
529
|
+
const hash2 = crypto2__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
530
530
|
const hashedName2 = `bundle-entry-${hash2}.js`;
|
|
531
531
|
const indexMapPath = path8__default.default.join(outputDir, "index.js.map");
|
|
532
532
|
const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
|
|
@@ -544,7 +544,7 @@ async function contentHashEntry(outputDir) {
|
|
|
544
544
|
logger.info(`Entry hashed: ${hashedName2}`);
|
|
545
545
|
return;
|
|
546
546
|
}
|
|
547
|
-
const hash =
|
|
547
|
+
const hash = crypto2__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
|
|
548
548
|
const hashedName = `bundle-entry-${hash}.js`;
|
|
549
549
|
const hashedMapName = `bundle-entry-${hash}.js.map`;
|
|
550
550
|
entryContent = entryContent.replace(
|
|
@@ -582,7 +582,7 @@ async function extractDataRequirements(themePath) {
|
|
|
582
582
|
}
|
|
583
583
|
return requirements;
|
|
584
584
|
}
|
|
585
|
-
async function
|
|
585
|
+
async function generateManifest(themeName, themePath, outputDir) {
|
|
586
586
|
let version2 = "1.0.0";
|
|
587
587
|
let themeId = themeName;
|
|
588
588
|
try {
|
|
@@ -717,7 +717,7 @@ async function compileStandaloneTheme(themePath, themeName) {
|
|
|
717
717
|
} catch {
|
|
718
718
|
}
|
|
719
719
|
await contentHashEntry(outputDir);
|
|
720
|
-
await
|
|
720
|
+
await generateManifest(themeName, themePath, outputDir);
|
|
721
721
|
await generateThemeData(themePath, outputDir, themeName);
|
|
722
722
|
if (result.metafile) {
|
|
723
723
|
const outputs = result.metafile.outputs;
|
|
@@ -798,7 +798,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
|
|
|
798
798
|
};
|
|
799
799
|
const context2 = await esbuild__namespace.context(buildOptions);
|
|
800
800
|
await context2.rebuild();
|
|
801
|
-
await
|
|
801
|
+
await generateManifest(themeName, themePath, outputDir);
|
|
802
802
|
await generateThemeData(themePath, outputDir, themeName);
|
|
803
803
|
return { context: context2, outputDir };
|
|
804
804
|
}
|
|
@@ -1534,38 +1534,13 @@ async function initCommand(projectName, options = {}) {
|
|
|
1534
1534
|
try {
|
|
1535
1535
|
fs2__default.default.mkdirSync(projectPath, { recursive: true });
|
|
1536
1536
|
await copyTemplate(template, projectPath, data);
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
const layoutContent = generateThemeLayout(data);
|
|
1544
|
-
await writeFile(path8__default.default.join(srcPath, "layout.ts"), layoutContent);
|
|
1545
|
-
const indexContent = generateThemeIndex(data);
|
|
1546
|
-
await writeFile(path8__default.default.join(srcPath, "index.ts"), indexContent);
|
|
1547
|
-
const sectionsPath = path8__default.default.join(srcPath, "sections");
|
|
1548
|
-
fs2__default.default.mkdirSync(sectionsPath, { recursive: true });
|
|
1549
|
-
await writeFile(
|
|
1550
|
-
path8__default.default.join(sectionsPath, "README.md"),
|
|
1551
|
-
`# ${displayName} Sections
|
|
1552
|
-
|
|
1553
|
-
Add your theme-specific sections here.
|
|
1554
|
-
`
|
|
1555
|
-
);
|
|
1556
|
-
const blocksPath = path8__default.default.join(srcPath, "blocks");
|
|
1557
|
-
fs2__default.default.mkdirSync(blocksPath, { recursive: true });
|
|
1558
|
-
await writeFile(
|
|
1559
|
-
path8__default.default.join(blocksPath, "README.md"),
|
|
1560
|
-
`# ${displayName} Blocks
|
|
1561
|
-
|
|
1562
|
-
Add your theme-specific blocks here.
|
|
1563
|
-
`
|
|
1537
|
+
await renameThemeInFiles(
|
|
1538
|
+
projectPath,
|
|
1539
|
+
name,
|
|
1540
|
+
displayName,
|
|
1541
|
+
description,
|
|
1542
|
+
author
|
|
1564
1543
|
);
|
|
1565
|
-
const pagesPath = path8__default.default.join(srcPath, "pages");
|
|
1566
|
-
fs2__default.default.mkdirSync(pagesPath, { recursive: true });
|
|
1567
|
-
const homePageContent = generateHomePage(data);
|
|
1568
|
-
await writeFile(path8__default.default.join(pagesPath, "home.ts"), homePageContent);
|
|
1569
1544
|
logger.stopSpinner(true, "Project structure created!");
|
|
1570
1545
|
if (options.git) {
|
|
1571
1546
|
logger.startSpinner("Initializing git repository...");
|
|
@@ -1609,14 +1584,14 @@ Add your theme-specific blocks here.
|
|
|
1609
1584
|
logger.log(` npm run dev # Start development mode`);
|
|
1610
1585
|
logger.newLine();
|
|
1611
1586
|
logger.section("Theme structure:");
|
|
1612
|
-
logger.log("
|
|
1587
|
+
logger.log(" bundle-entry.ts - Theme manifest and exports");
|
|
1613
1588
|
logger.log(
|
|
1614
|
-
"
|
|
1589
|
+
" theme.config.ts - Design tokens (colors, typography, etc.)"
|
|
1615
1590
|
);
|
|
1616
|
-
logger.log("
|
|
1617
|
-
logger.log("
|
|
1618
|
-
logger.log("
|
|
1619
|
-
logger.log("
|
|
1591
|
+
logger.log(" theme.layout.ts - Header and footer configuration");
|
|
1592
|
+
logger.log(" sections/ - Custom sections for your theme");
|
|
1593
|
+
logger.log(" pages/ - Page configurations");
|
|
1594
|
+
logger.log(" CLAUDE.md - AI assistant context");
|
|
1620
1595
|
logger.newLine();
|
|
1621
1596
|
logger.success(`Happy theming! \u{1F3A8}`);
|
|
1622
1597
|
} catch (error) {
|
|
@@ -1630,231 +1605,33 @@ Add your theme-specific blocks here.
|
|
|
1630
1605
|
process.exit(1);
|
|
1631
1606
|
}
|
|
1632
1607
|
}
|
|
1633
|
-
function
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
// Example: productCard: () => import("./blocks/product-card").then((m) => m.productCardDefinition),
|
|
1661
|
-
},
|
|
1662
|
-
|
|
1663
|
-
// Default pages
|
|
1664
|
-
pages: {
|
|
1665
|
-
home: () => import("./pages/home").then((m) => m.homePageConfig),
|
|
1666
|
-
},
|
|
1667
|
-
|
|
1668
|
-
// Supported page types
|
|
1669
|
-
supportedPageTypes: ["home", "about", "contact", "custom"],
|
|
1670
|
-
|
|
1671
|
-
// Preview image (optional)
|
|
1672
|
-
preview: undefined,
|
|
1673
|
-
|
|
1674
|
-
// Tags for categorization (optional)
|
|
1675
|
-
tags: ["custom"],
|
|
1676
|
-
};
|
|
1677
|
-
|
|
1678
|
-
export default manifest;
|
|
1679
|
-
`;
|
|
1680
|
-
}
|
|
1681
|
-
function generateThemeConfig(data) {
|
|
1682
|
-
return `import type { ThemeConfig } from "@onexapis/core";
|
|
1683
|
-
|
|
1684
|
-
/**
|
|
1685
|
-
* ${data.displayName} Theme Configuration
|
|
1686
|
-
* Design tokens: colors, typography, spacing, etc.
|
|
1687
|
-
*/
|
|
1688
|
-
export const themeConfig: ThemeConfig = {
|
|
1689
|
-
// Color palette
|
|
1690
|
-
colors: {
|
|
1691
|
-
primary: {
|
|
1692
|
-
50: "#eff6ff",
|
|
1693
|
-
100: "#dbeafe",
|
|
1694
|
-
200: "#bfdbfe",
|
|
1695
|
-
300: "#93c5fd",
|
|
1696
|
-
400: "#60a5fa",
|
|
1697
|
-
500: "#3b82f6",
|
|
1698
|
-
600: "#2563eb",
|
|
1699
|
-
700: "#1d4ed8",
|
|
1700
|
-
800: "#1e40af",
|
|
1701
|
-
900: "#1e3a8a",
|
|
1702
|
-
},
|
|
1703
|
-
secondary: {
|
|
1704
|
-
50: "#f8fafc",
|
|
1705
|
-
100: "#f1f5f9",
|
|
1706
|
-
200: "#e2e8f0",
|
|
1707
|
-
300: "#cbd5e1",
|
|
1708
|
-
400: "#94a3b8",
|
|
1709
|
-
500: "#64748b",
|
|
1710
|
-
600: "#475569",
|
|
1711
|
-
700: "#334155",
|
|
1712
|
-
800: "#1e293b",
|
|
1713
|
-
900: "#0f172a",
|
|
1714
|
-
},
|
|
1715
|
-
accent: {
|
|
1716
|
-
50: "#fdf4ff",
|
|
1717
|
-
100: "#fae8ff",
|
|
1718
|
-
200: "#f5d0fe",
|
|
1719
|
-
300: "#f0abfc",
|
|
1720
|
-
400: "#e879f9",
|
|
1721
|
-
500: "#d946ef",
|
|
1722
|
-
600: "#c026d3",
|
|
1723
|
-
700: "#a21caf",
|
|
1724
|
-
800: "#86198f",
|
|
1725
|
-
900: "#701a75",
|
|
1726
|
-
},
|
|
1727
|
-
},
|
|
1728
|
-
|
|
1729
|
-
// Typography
|
|
1730
|
-
typography: {
|
|
1731
|
-
fontFamily: {
|
|
1732
|
-
sans: ["Inter", "system-ui", "sans-serif"],
|
|
1733
|
-
serif: ["Georgia", "serif"],
|
|
1734
|
-
mono: ["Monaco", "monospace"],
|
|
1735
|
-
},
|
|
1736
|
-
fontSize: {
|
|
1737
|
-
xs: "0.75rem",
|
|
1738
|
-
sm: "0.875rem",
|
|
1739
|
-
base: "1rem",
|
|
1740
|
-
lg: "1.125rem",
|
|
1741
|
-
xl: "1.25rem",
|
|
1742
|
-
"2xl": "1.5rem",
|
|
1743
|
-
"3xl": "1.875rem",
|
|
1744
|
-
"4xl": "2.25rem",
|
|
1745
|
-
"5xl": "3rem",
|
|
1746
|
-
},
|
|
1747
|
-
},
|
|
1748
|
-
|
|
1749
|
-
// Spacing
|
|
1750
|
-
spacing: {
|
|
1751
|
-
xs: "0.5rem",
|
|
1752
|
-
sm: "1rem",
|
|
1753
|
-
md: "1.5rem",
|
|
1754
|
-
lg: "2rem",
|
|
1755
|
-
xl: "3rem",
|
|
1756
|
-
"2xl": "4rem",
|
|
1757
|
-
"3xl": "6rem",
|
|
1758
|
-
"4xl": "8rem",
|
|
1759
|
-
},
|
|
1760
|
-
|
|
1761
|
-
// Border radius
|
|
1762
|
-
borderRadius: {
|
|
1763
|
-
none: "0",
|
|
1764
|
-
sm: "0.125rem",
|
|
1765
|
-
md: "0.375rem",
|
|
1766
|
-
lg: "0.5rem",
|
|
1767
|
-
xl: "0.75rem",
|
|
1768
|
-
full: "9999px",
|
|
1769
|
-
},
|
|
1770
|
-
|
|
1771
|
-
// Breakpoints
|
|
1772
|
-
breakpoints: {
|
|
1773
|
-
sm: "640px",
|
|
1774
|
-
md: "768px",
|
|
1775
|
-
lg: "1024px",
|
|
1776
|
-
xl: "1280px",
|
|
1777
|
-
"2xl": "1536px",
|
|
1778
|
-
},
|
|
1779
|
-
};
|
|
1780
|
-
`;
|
|
1781
|
-
}
|
|
1782
|
-
function generateThemeLayout(data) {
|
|
1783
|
-
return `import type { ThemeLayoutConfig } from "@onexapis/core";
|
|
1784
|
-
|
|
1785
|
-
/**
|
|
1786
|
-
* ${data.themeName} Theme Layout
|
|
1787
|
-
* Define header and footer sections
|
|
1788
|
-
*/
|
|
1789
|
-
export const themeLayout: ThemeLayoutConfig = {
|
|
1790
|
-
// Header section configuration
|
|
1791
|
-
header: undefined,
|
|
1792
|
-
// Example:
|
|
1793
|
-
// header: {
|
|
1794
|
-
// type: "header",
|
|
1795
|
-
// template: "default",
|
|
1796
|
-
// enabled: true,
|
|
1797
|
-
// settings: {},
|
|
1798
|
-
// },
|
|
1799
|
-
|
|
1800
|
-
// Footer section configuration
|
|
1801
|
-
footer: undefined,
|
|
1802
|
-
// Example:
|
|
1803
|
-
// footer: {
|
|
1804
|
-
// type: "footer",
|
|
1805
|
-
// template: "default",
|
|
1806
|
-
// enabled: true,
|
|
1807
|
-
// settings: {},
|
|
1808
|
-
// },
|
|
1809
|
-
};
|
|
1810
|
-
`;
|
|
1811
|
-
}
|
|
1812
|
-
function generateThemeIndex(data) {
|
|
1813
|
-
return `/**
|
|
1814
|
-
* ${data.themeNamePascal} Theme
|
|
1815
|
-
*/
|
|
1816
|
-
|
|
1817
|
-
export { manifest as ${data.themeNamePascal}Manifest } from "./manifest";
|
|
1818
|
-
export { themeConfig as ${data.themeNamePascal}Config } from "./config";
|
|
1819
|
-
export { themeLayout as ${data.themeNamePascal}Layout } from "./layout";
|
|
1820
|
-
`;
|
|
1821
|
-
}
|
|
1822
|
-
function generateHomePage(data) {
|
|
1823
|
-
return `import type { PageConfig } from "@onexapis/core";
|
|
1824
|
-
|
|
1825
|
-
/**
|
|
1826
|
-
* Home Page Configuration
|
|
1827
|
-
*/
|
|
1828
|
-
export const homePageConfig: PageConfig = {
|
|
1829
|
-
type: "home",
|
|
1830
|
-
title: "${data.displayName}",
|
|
1831
|
-
description: "Welcome to ${data.displayName}",
|
|
1832
|
-
|
|
1833
|
-
// SEO metadata
|
|
1834
|
-
seo: {
|
|
1835
|
-
title: "${data.displayName} - Home",
|
|
1836
|
-
description: "Welcome to ${data.displayName}",
|
|
1837
|
-
keywords: [],
|
|
1838
|
-
ogImage: undefined,
|
|
1839
|
-
},
|
|
1840
|
-
|
|
1841
|
-
// Page sections
|
|
1842
|
-
sections: [
|
|
1843
|
-
// Add your sections here
|
|
1844
|
-
// Example:
|
|
1845
|
-
// {
|
|
1846
|
-
// id: "hero-1",
|
|
1847
|
-
// type: "hero",
|
|
1848
|
-
// template: "default",
|
|
1849
|
-
// order: 0,
|
|
1850
|
-
// enabled: true,
|
|
1851
|
-
// settings: {},
|
|
1852
|
-
// components: [],
|
|
1853
|
-
// blocks: [],
|
|
1854
|
-
// },
|
|
1855
|
-
],
|
|
1856
|
-
};
|
|
1857
|
-
`;
|
|
1608
|
+
async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
|
|
1609
|
+
const configPath = path8__default.default.join(projectPath, "theme.config.ts");
|
|
1610
|
+
if (fs2__default.default.existsSync(configPath)) {
|
|
1611
|
+
let content = fs2__default.default.readFileSync(configPath, "utf-8");
|
|
1612
|
+
content = content.replace(
|
|
1613
|
+
/name: "My Simple Theme"/,
|
|
1614
|
+
`name: "${displayName}"`
|
|
1615
|
+
);
|
|
1616
|
+
content = content.replace(
|
|
1617
|
+
/description: ".*?"/,
|
|
1618
|
+
`description: "${description}"`
|
|
1619
|
+
);
|
|
1620
|
+
fs2__default.default.writeFileSync(configPath, content, "utf-8");
|
|
1621
|
+
}
|
|
1622
|
+
const pkgPath = path8__default.default.join(projectPath, "package.json");
|
|
1623
|
+
if (fs2__default.default.existsSync(pkgPath)) {
|
|
1624
|
+
let content = fs2__default.default.readFileSync(pkgPath, "utf-8");
|
|
1625
|
+
content = content.replace(
|
|
1626
|
+
/@onex-themes\/my-simple/g,
|
|
1627
|
+
`@onex-themes/${themeName}`
|
|
1628
|
+
);
|
|
1629
|
+
content = content.replace(
|
|
1630
|
+
/"description": ".*?"/,
|
|
1631
|
+
`"description": "${description}"`
|
|
1632
|
+
);
|
|
1633
|
+
fs2__default.default.writeFileSync(pkgPath, content, "utf-8");
|
|
1634
|
+
}
|
|
1858
1635
|
}
|
|
1859
1636
|
|
|
1860
1637
|
// src/commands/create-section.ts
|
|
@@ -3181,7 +2958,7 @@ async function deployCommand(options) {
|
|
|
3181
2958
|
if (options.environment) {
|
|
3182
2959
|
formData.append("environment", options.environment);
|
|
3183
2960
|
}
|
|
3184
|
-
const response = await
|
|
2961
|
+
const response = await fetch2__default.default(uploadEndpoint, {
|
|
3185
2962
|
method: "POST",
|
|
3186
2963
|
body: formData,
|
|
3187
2964
|
headers: formData.getHeaders()
|
|
@@ -3262,7 +3039,7 @@ function getBucketName(env) {
|
|
|
3262
3039
|
return process.env.BUCKET_NAME;
|
|
3263
3040
|
}
|
|
3264
3041
|
const environment = env || process.env.ENVIRONMENT || "staging";
|
|
3265
|
-
return environment === "production" ? "
|
|
3042
|
+
return environment === "production" ? "theme-s3-bucket" : "theme-s3-bucket";
|
|
3266
3043
|
}
|
|
3267
3044
|
async function findCompiledThemeDir(themeId, version2) {
|
|
3268
3045
|
const searchPaths = [path8__default.default.resolve(process.cwd(), "dist")];
|
|
@@ -3378,7 +3155,7 @@ async function uploadCommand(options) {
|
|
|
3378
3155
|
}
|
|
3379
3156
|
spinner.succeed(`Found compiled theme at: ${compiledDir}`);
|
|
3380
3157
|
spinner.start("Creating bundle.zip...");
|
|
3381
|
-
const tmpDir =
|
|
3158
|
+
const tmpDir = os3__default.default.tmpdir();
|
|
3382
3159
|
const bundleZipPath = path8__default.default.join(tmpDir, `${themeId}-${version2}-bundle.zip`);
|
|
3383
3160
|
await createZipFromDir(compiledDir, bundleZipPath);
|
|
3384
3161
|
const bundleZipBuffer = await fs__default.default.readFile(bundleZipPath);
|
|
@@ -3531,7 +3308,7 @@ function getBucketName2(env) {
|
|
|
3531
3308
|
return process.env.BUCKET_NAME;
|
|
3532
3309
|
}
|
|
3533
3310
|
const environment = env || process.env.ENVIRONMENT || "staging";
|
|
3534
|
-
return environment === "production" ? "
|
|
3311
|
+
return environment === "production" ? "theme-s3-bucket" : "theme-s3-bucket";
|
|
3535
3312
|
}
|
|
3536
3313
|
async function streamToString(stream) {
|
|
3537
3314
|
const chunks = [];
|
|
@@ -3732,7 +3509,7 @@ function getBucketName3(env) {
|
|
|
3732
3509
|
return process.env.BUCKET_NAME;
|
|
3733
3510
|
}
|
|
3734
3511
|
const environment = env || process.env.ENVIRONMENT || "staging";
|
|
3735
|
-
return environment === "production" ? "
|
|
3512
|
+
return environment === "production" ? "theme-s3-bucket" : "theme-s3-bucket";
|
|
3736
3513
|
}
|
|
3737
3514
|
async function streamToString2(stream) {
|
|
3738
3515
|
const chunks = [];
|
|
@@ -3776,8 +3553,8 @@ function runInstall(cwd) {
|
|
|
3776
3553
|
});
|
|
3777
3554
|
}
|
|
3778
3555
|
async function promptThemeName(originalName) {
|
|
3779
|
-
const { default:
|
|
3780
|
-
const { themeName } = await
|
|
3556
|
+
const { default: inquirer7 } = await import('inquirer');
|
|
3557
|
+
const { themeName } = await inquirer7.prompt([
|
|
3781
3558
|
{
|
|
3782
3559
|
type: "input",
|
|
3783
3560
|
name: "themeName",
|
|
@@ -3930,7 +3707,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3930
3707
|
[
|
|
3931
3708
|
"# API Configuration (enables real data in preview)",
|
|
3932
3709
|
"# Get your Company ID from the OneX dashboard",
|
|
3933
|
-
"NEXT_PUBLIC_API_URL=https://
|
|
3710
|
+
"NEXT_PUBLIC_API_URL=https://platform-dev.onexeos.com",
|
|
3934
3711
|
"NEXT_PUBLIC_COMPANY_ID=",
|
|
3935
3712
|
""
|
|
3936
3713
|
].join("\n")
|
|
@@ -4278,7 +4055,7 @@ async function devCommand(options) {
|
|
|
4278
4055
|
logger.info(`File changed: ${filePath}`);
|
|
4279
4056
|
try {
|
|
4280
4057
|
await context2.rebuild();
|
|
4281
|
-
await
|
|
4058
|
+
await generateManifest(themeName, themePath, outputDir);
|
|
4282
4059
|
server.broadcast({ type: "reload", timestamp: Date.now() });
|
|
4283
4060
|
logger.success("Rebuilt successfully");
|
|
4284
4061
|
} catch (error) {
|
|
@@ -4313,7 +4090,7 @@ async function devCommand(options) {
|
|
|
4313
4090
|
|
|
4314
4091
|
// src/commands/config.ts
|
|
4315
4092
|
init_logger();
|
|
4316
|
-
var CONFIG_DIR = path8__default.default.join(
|
|
4093
|
+
var CONFIG_DIR = path8__default.default.join(os3__default.default.homedir(), ".onexthm");
|
|
4317
4094
|
var CONFIG_FILE = path8__default.default.join(CONFIG_DIR, ".env");
|
|
4318
4095
|
var CONFIG_ENTRIES = [
|
|
4319
4096
|
{
|
|
@@ -4343,7 +4120,7 @@ var CONFIG_ENTRIES = [
|
|
|
4343
4120
|
key: "NEXT_PUBLIC_API_URL",
|
|
4344
4121
|
label: "API URL",
|
|
4345
4122
|
required: false,
|
|
4346
|
-
defaultValue: "https://
|
|
4123
|
+
defaultValue: "https://platform-dev.onexeos.com"
|
|
4347
4124
|
},
|
|
4348
4125
|
{
|
|
4349
4126
|
key: "NEXT_PUBLIC_COMPANY_ID",
|
|
@@ -4454,6 +4231,461 @@ async function configCommand() {
|
|
|
4454
4231
|
);
|
|
4455
4232
|
}
|
|
4456
4233
|
|
|
4234
|
+
// src/commands/login.ts
|
|
4235
|
+
init_logger();
|
|
4236
|
+
var AUTH_DIR = path8__default.default.join(os3__default.default.homedir(), ".onexthm");
|
|
4237
|
+
var AUTH_FILE = path8__default.default.join(AUTH_DIR, "auth.json");
|
|
4238
|
+
function getApiUrl() {
|
|
4239
|
+
return process.env.NEXT_PUBLIC_API_URL || process.env.ONEXTHM_API_URL || "https://platform-dev.onexeos.com";
|
|
4240
|
+
}
|
|
4241
|
+
async function saveAuthTokens(tokens) {
|
|
4242
|
+
await fs__default.default.ensureDir(AUTH_DIR);
|
|
4243
|
+
const key = getMachineKey();
|
|
4244
|
+
const data = JSON.stringify(tokens);
|
|
4245
|
+
const encrypted = encrypt(data, key);
|
|
4246
|
+
await fs__default.default.writeFile(AUTH_FILE, encrypted, "utf-8");
|
|
4247
|
+
}
|
|
4248
|
+
function loadAuthTokens() {
|
|
4249
|
+
try {
|
|
4250
|
+
if (!fs__default.default.existsSync(AUTH_FILE)) return null;
|
|
4251
|
+
const encrypted = fs__default.default.readFileSync(AUTH_FILE, "utf-8");
|
|
4252
|
+
const key = getMachineKey();
|
|
4253
|
+
const data = decrypt(encrypted, key);
|
|
4254
|
+
return JSON.parse(data);
|
|
4255
|
+
} catch {
|
|
4256
|
+
return null;
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
async function clearAuthTokens() {
|
|
4260
|
+
try {
|
|
4261
|
+
await fs__default.default.remove(AUTH_FILE);
|
|
4262
|
+
} catch {
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
function isTokenExpired(tokens) {
|
|
4266
|
+
return Date.now() / 1e3 > tokens.expiresAt - 60;
|
|
4267
|
+
}
|
|
4268
|
+
async function getValidTokens() {
|
|
4269
|
+
const tokens = loadAuthTokens();
|
|
4270
|
+
if (!tokens) return null;
|
|
4271
|
+
if (!isTokenExpired(tokens)) return tokens;
|
|
4272
|
+
try {
|
|
4273
|
+
const apiUrl = getApiUrl();
|
|
4274
|
+
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
4275
|
+
method: "POST",
|
|
4276
|
+
headers: { "Content-Type": "application/json" },
|
|
4277
|
+
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
4278
|
+
});
|
|
4279
|
+
if (!response.ok) {
|
|
4280
|
+
await clearAuthTokens();
|
|
4281
|
+
return null;
|
|
4282
|
+
}
|
|
4283
|
+
const data = await response.json();
|
|
4284
|
+
const body = data.statusCode ? data.body : data;
|
|
4285
|
+
const refreshed = {
|
|
4286
|
+
...tokens,
|
|
4287
|
+
accessToken: body.AccessToken || tokens.accessToken,
|
|
4288
|
+
idToken: body.IdToken || tokens.idToken,
|
|
4289
|
+
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
4290
|
+
};
|
|
4291
|
+
await saveAuthTokens(refreshed);
|
|
4292
|
+
return refreshed;
|
|
4293
|
+
} catch {
|
|
4294
|
+
await clearAuthTokens();
|
|
4295
|
+
return null;
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
async function authenticatedFetch(url, init) {
|
|
4299
|
+
const tokens = await getValidTokens();
|
|
4300
|
+
if (!tokens) {
|
|
4301
|
+
throw new Error("Not logged in. Run: onexthm login");
|
|
4302
|
+
}
|
|
4303
|
+
const headers = new Headers(init?.headers);
|
|
4304
|
+
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
4305
|
+
headers.set("Content-Type", "application/json");
|
|
4306
|
+
return fetch(url, { ...init, headers });
|
|
4307
|
+
}
|
|
4308
|
+
function getMachineKey() {
|
|
4309
|
+
let seed;
|
|
4310
|
+
if (process.platform === "darwin") {
|
|
4311
|
+
seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
|
|
4312
|
+
} else if (process.platform === "linux") {
|
|
4313
|
+
try {
|
|
4314
|
+
seed = `onexthm:${fs__default.default.readFileSync("/etc/machine-id", "utf-8").trim()}`;
|
|
4315
|
+
} catch {
|
|
4316
|
+
seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
|
|
4317
|
+
}
|
|
4318
|
+
} else {
|
|
4319
|
+
seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
|
|
4320
|
+
}
|
|
4321
|
+
return crypto2__default.default.createHash("sha256").update(seed).digest();
|
|
4322
|
+
}
|
|
4323
|
+
function encrypt(text, key) {
|
|
4324
|
+
const iv = crypto2__default.default.randomBytes(16);
|
|
4325
|
+
const cipher = crypto2__default.default.createCipheriv("aes-256-gcm", key, iv);
|
|
4326
|
+
let encrypted = cipher.update(text, "utf-8", "hex");
|
|
4327
|
+
encrypted += cipher.final("hex");
|
|
4328
|
+
const tag = cipher.getAuthTag();
|
|
4329
|
+
return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted}`;
|
|
4330
|
+
}
|
|
4331
|
+
function decrypt(text, key) {
|
|
4332
|
+
const [ivHex, tagHex, encrypted] = text.split(":");
|
|
4333
|
+
const iv = Buffer.from(ivHex, "hex");
|
|
4334
|
+
const tag = Buffer.from(tagHex, "hex");
|
|
4335
|
+
const decipher = crypto2__default.default.createDecipheriv("aes-256-gcm", key, iv);
|
|
4336
|
+
decipher.setAuthTag(tag);
|
|
4337
|
+
let decrypted = decipher.update(encrypted, "hex", "utf-8");
|
|
4338
|
+
decrypted += decipher.final("utf-8");
|
|
4339
|
+
return decrypted;
|
|
4340
|
+
}
|
|
4341
|
+
function parseJwtClaims(idToken) {
|
|
4342
|
+
try {
|
|
4343
|
+
const payload = idToken.split(".")[1];
|
|
4344
|
+
const decoded = Buffer.from(payload, "base64url").toString("utf-8");
|
|
4345
|
+
return JSON.parse(decoded);
|
|
4346
|
+
} catch {
|
|
4347
|
+
return {};
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
// src/commands/login.ts
|
|
4352
|
+
async function loginCommand() {
|
|
4353
|
+
logger.header("OneX Theme Developer Login");
|
|
4354
|
+
const existing = loadAuthTokens();
|
|
4355
|
+
if (existing) {
|
|
4356
|
+
logger.info(`Already logged in as: ${existing.user.email}`);
|
|
4357
|
+
const { relogin } = await inquirer__default.default.prompt([
|
|
4358
|
+
{
|
|
4359
|
+
type: "confirm",
|
|
4360
|
+
name: "relogin",
|
|
4361
|
+
message: "Re-login with different account?",
|
|
4362
|
+
default: false
|
|
4363
|
+
}
|
|
4364
|
+
]);
|
|
4365
|
+
if (!relogin) return;
|
|
4366
|
+
}
|
|
4367
|
+
const { email, password } = await inquirer__default.default.prompt([
|
|
4368
|
+
{
|
|
4369
|
+
type: "input",
|
|
4370
|
+
name: "email",
|
|
4371
|
+
message: "Email:",
|
|
4372
|
+
validate: (input) => input.includes("@") ? true : "Enter a valid email"
|
|
4373
|
+
},
|
|
4374
|
+
{
|
|
4375
|
+
type: "password",
|
|
4376
|
+
name: "password",
|
|
4377
|
+
message: "Password:",
|
|
4378
|
+
validate: (input) => input.length >= 6 ? true : "Password too short"
|
|
4379
|
+
}
|
|
4380
|
+
]);
|
|
4381
|
+
logger.startSpinner("Logging in...");
|
|
4382
|
+
try {
|
|
4383
|
+
const apiUrl = getApiUrl();
|
|
4384
|
+
const response = await fetch(`${apiUrl}/auth/login`, {
|
|
4385
|
+
method: "POST",
|
|
4386
|
+
headers: { "Content-Type": "application/json" },
|
|
4387
|
+
body: JSON.stringify({ username: email, password })
|
|
4388
|
+
});
|
|
4389
|
+
const raw = await response.json();
|
|
4390
|
+
const data = raw.statusCode ? raw.body : raw;
|
|
4391
|
+
if (!response.ok || data.error) {
|
|
4392
|
+
logger.stopSpinner(false, "Login failed");
|
|
4393
|
+
logger.error(data.message || data.error || "Invalid credentials");
|
|
4394
|
+
process.exit(1);
|
|
4395
|
+
}
|
|
4396
|
+
const idToken = data.IdToken;
|
|
4397
|
+
const accessToken = data.AccessToken;
|
|
4398
|
+
const refreshToken = data.RefreshToken;
|
|
4399
|
+
const expiresIn = data.ExpiresIn || 3600;
|
|
4400
|
+
if (!idToken) {
|
|
4401
|
+
logger.stopSpinner(false, "Login failed");
|
|
4402
|
+
logger.error("No token received from server");
|
|
4403
|
+
process.exit(1);
|
|
4404
|
+
}
|
|
4405
|
+
const claims = parseJwtClaims(idToken);
|
|
4406
|
+
const tokens = {
|
|
4407
|
+
accessToken,
|
|
4408
|
+
idToken,
|
|
4409
|
+
refreshToken,
|
|
4410
|
+
expiresAt: Math.floor(Date.now() / 1e3) + expiresIn,
|
|
4411
|
+
user: {
|
|
4412
|
+
email: claims.email || email,
|
|
4413
|
+
name: claims.name,
|
|
4414
|
+
companyId: claims["custom:company_id"],
|
|
4415
|
+
userId: claims.sub
|
|
4416
|
+
}
|
|
4417
|
+
};
|
|
4418
|
+
await saveAuthTokens(tokens);
|
|
4419
|
+
logger.stopSpinner(true, "Logged in!");
|
|
4420
|
+
logger.newLine();
|
|
4421
|
+
logger.info(` Email: ${tokens.user.email}`);
|
|
4422
|
+
if (tokens.user.name) logger.info(` Name: ${tokens.user.name}`);
|
|
4423
|
+
if (tokens.user.companyId)
|
|
4424
|
+
logger.info(` Company: ${tokens.user.companyId}`);
|
|
4425
|
+
logger.newLine();
|
|
4426
|
+
logger.success("Token stored securely in ~/.onexthm/auth.json (encrypted)");
|
|
4427
|
+
} catch (error) {
|
|
4428
|
+
logger.stopSpinner(false, "Login failed");
|
|
4429
|
+
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4430
|
+
process.exit(1);
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
// src/commands/logout.ts
|
|
4435
|
+
init_logger();
|
|
4436
|
+
async function logoutCommand() {
|
|
4437
|
+
const tokens = loadAuthTokens();
|
|
4438
|
+
if (!tokens) {
|
|
4439
|
+
logger.info("Not logged in.");
|
|
4440
|
+
return;
|
|
4441
|
+
}
|
|
4442
|
+
await clearAuthTokens();
|
|
4443
|
+
logger.success(`Logged out (was: ${tokens.user.email})`);
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
// src/commands/whoami.ts
|
|
4447
|
+
init_logger();
|
|
4448
|
+
async function whoamiCommand() {
|
|
4449
|
+
const tokens = loadAuthTokens();
|
|
4450
|
+
if (!tokens) {
|
|
4451
|
+
logger.error("Not logged in. Run: onexthm login");
|
|
4452
|
+
process.exit(1);
|
|
4453
|
+
}
|
|
4454
|
+
const expired = isTokenExpired(tokens);
|
|
4455
|
+
logger.header("OneX Theme Developer");
|
|
4456
|
+
logger.info(` Email: ${tokens.user.email}`);
|
|
4457
|
+
if (tokens.user.name) logger.info(` Name: ${tokens.user.name}`);
|
|
4458
|
+
if (tokens.user.companyId)
|
|
4459
|
+
logger.info(` Company: ${tokens.user.companyId}`);
|
|
4460
|
+
logger.info(
|
|
4461
|
+
` Status: ${expired ? "\u26A0 Token expired (will auto-refresh)" : "\u2713 Active"}`
|
|
4462
|
+
);
|
|
4463
|
+
}
|
|
4464
|
+
|
|
4465
|
+
// src/commands/publish.ts
|
|
4466
|
+
init_logger();
|
|
4467
|
+
async function publishCommand(options) {
|
|
4468
|
+
logger.header("OneX Theme Publish");
|
|
4469
|
+
const tokens = await getValidTokens();
|
|
4470
|
+
if (!tokens) {
|
|
4471
|
+
logger.error("Not logged in. Run: onexthm login");
|
|
4472
|
+
process.exit(1);
|
|
4473
|
+
}
|
|
4474
|
+
logger.info(`Logged in as: ${tokens.user.email}`);
|
|
4475
|
+
let themePath;
|
|
4476
|
+
if (options.theme) {
|
|
4477
|
+
themePath = path8__default.default.resolve(options.theme);
|
|
4478
|
+
} else {
|
|
4479
|
+
const isThemeDir = [
|
|
4480
|
+
"theme.config.ts",
|
|
4481
|
+
"bundle-entry.ts",
|
|
4482
|
+
"manifest.ts"
|
|
4483
|
+
].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
|
|
4484
|
+
if (isThemeDir) {
|
|
4485
|
+
themePath = process.cwd();
|
|
4486
|
+
} else {
|
|
4487
|
+
logger.error(
|
|
4488
|
+
"Not in a theme directory. Run from theme root or use --theme flag."
|
|
4489
|
+
);
|
|
4490
|
+
process.exit(1);
|
|
4491
|
+
}
|
|
4492
|
+
}
|
|
4493
|
+
const pkgPath = path8__default.default.join(themePath, "package.json");
|
|
4494
|
+
if (!fs__default.default.existsSync(pkgPath)) {
|
|
4495
|
+
logger.error("No package.json found in theme directory");
|
|
4496
|
+
process.exit(1);
|
|
4497
|
+
}
|
|
4498
|
+
const pkg = fs__default.default.readJsonSync(pkgPath);
|
|
4499
|
+
const themeId = pkg.name?.replace("@onex-themes/", "") || path8__default.default.basename(themePath);
|
|
4500
|
+
const version2 = pkg.version || "1.0.0";
|
|
4501
|
+
logger.newLine();
|
|
4502
|
+
logger.info(`Theme: ${themeId}`);
|
|
4503
|
+
logger.info(`Version: ${version2}`);
|
|
4504
|
+
logger.newLine();
|
|
4505
|
+
const apiUrl = getApiUrl();
|
|
4506
|
+
logger.startSpinner("Registering theme...");
|
|
4507
|
+
try {
|
|
4508
|
+
const regResponse = await authenticatedFetch(
|
|
4509
|
+
`${apiUrl}/website-api/themes/register`,
|
|
4510
|
+
{
|
|
4511
|
+
method: "POST",
|
|
4512
|
+
body: JSON.stringify({
|
|
4513
|
+
themeId,
|
|
4514
|
+
name: pkg.displayName || themeId,
|
|
4515
|
+
description: pkg.description || "",
|
|
4516
|
+
email: tokens.user.email
|
|
4517
|
+
})
|
|
4518
|
+
}
|
|
4519
|
+
);
|
|
4520
|
+
const regData = await regResponse.json();
|
|
4521
|
+
const regBody = regData.statusCode ? regData.body : regData;
|
|
4522
|
+
if (!regResponse.ok && regBody.error && !regBody.error.includes("already registered")) {
|
|
4523
|
+
logger.stopSpinner(false, "Registration failed");
|
|
4524
|
+
logger.error(regBody.error);
|
|
4525
|
+
process.exit(1);
|
|
4526
|
+
}
|
|
4527
|
+
logger.stopSpinner(true, regBody.message || "Theme registered");
|
|
4528
|
+
} catch (error) {
|
|
4529
|
+
logger.stopSpinner(false, "Registration failed");
|
|
4530
|
+
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4531
|
+
process.exit(1);
|
|
4532
|
+
}
|
|
4533
|
+
logger.startSpinner("Building theme...");
|
|
4534
|
+
try {
|
|
4535
|
+
const { execSync: execSync3 } = await import('child_process');
|
|
4536
|
+
execSync3(
|
|
4537
|
+
"npx tsup bundle-entry.ts --format esm --target es2020 --outDir dist",
|
|
4538
|
+
{
|
|
4539
|
+
cwd: themePath,
|
|
4540
|
+
stdio: "ignore"
|
|
4541
|
+
}
|
|
4542
|
+
);
|
|
4543
|
+
logger.stopSpinner(true, "Theme compiled");
|
|
4544
|
+
} catch {
|
|
4545
|
+
logger.stopSpinner(false, "Build failed");
|
|
4546
|
+
logger.error("Run 'onexthm build' to see build errors");
|
|
4547
|
+
process.exit(1);
|
|
4548
|
+
}
|
|
4549
|
+
logger.startSpinner("Getting upload URL...");
|
|
4550
|
+
let bundleUploadUrl;
|
|
4551
|
+
let sourceUploadUrl;
|
|
4552
|
+
try {
|
|
4553
|
+
const pubResponse = await authenticatedFetch(
|
|
4554
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions`,
|
|
4555
|
+
{
|
|
4556
|
+
method: "POST",
|
|
4557
|
+
body: JSON.stringify({ version: version2 })
|
|
4558
|
+
}
|
|
4559
|
+
);
|
|
4560
|
+
const pubData = await pubResponse.json();
|
|
4561
|
+
const pubBody = pubData.statusCode ? pubData.body : pubData;
|
|
4562
|
+
if (!pubResponse.ok || !pubBody.bundleUploadUrl) {
|
|
4563
|
+
logger.stopSpinner(false, "Failed to get upload URL");
|
|
4564
|
+
logger.error(pubBody.error || "Server error");
|
|
4565
|
+
process.exit(1);
|
|
4566
|
+
}
|
|
4567
|
+
bundleUploadUrl = pubBody.bundleUploadUrl;
|
|
4568
|
+
sourceUploadUrl = pubBody.sourceUploadUrl;
|
|
4569
|
+
logger.stopSpinner(true, "Upload URL obtained");
|
|
4570
|
+
} catch (error) {
|
|
4571
|
+
logger.stopSpinner(false, "Failed");
|
|
4572
|
+
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4573
|
+
process.exit(1);
|
|
4574
|
+
}
|
|
4575
|
+
logger.startSpinner("Uploading bundle...");
|
|
4576
|
+
try {
|
|
4577
|
+
const archiver3 = await import('archiver');
|
|
4578
|
+
const { createWriteStream } = await import('fs');
|
|
4579
|
+
const distDir = path8__default.default.join(themePath, "dist");
|
|
4580
|
+
if (!fs__default.default.existsSync(distDir)) {
|
|
4581
|
+
logger.stopSpinner(false, "No dist/ directory");
|
|
4582
|
+
logger.error("Build the theme first: onexthm build");
|
|
4583
|
+
process.exit(1);
|
|
4584
|
+
}
|
|
4585
|
+
const bundleZipPath = path8__default.default.join(themePath, "dist", "bundle.zip");
|
|
4586
|
+
await createZip(distDir, bundleZipPath, ["bundle.zip"]);
|
|
4587
|
+
const bundleBuffer = fs__default.default.readFileSync(bundleZipPath);
|
|
4588
|
+
const bundleRes = await fetch(bundleUploadUrl, {
|
|
4589
|
+
method: "PUT",
|
|
4590
|
+
headers: { "Content-Type": "application/zip" },
|
|
4591
|
+
body: bundleBuffer
|
|
4592
|
+
});
|
|
4593
|
+
if (!bundleRes.ok) {
|
|
4594
|
+
throw new Error(`Upload failed: ${bundleRes.status}`);
|
|
4595
|
+
}
|
|
4596
|
+
const sizeMB = (bundleBuffer.length / 1024 / 1024).toFixed(2);
|
|
4597
|
+
logger.stopSpinner(true, `Bundle uploaded (${sizeMB} MB)`);
|
|
4598
|
+
} catch (error) {
|
|
4599
|
+
logger.stopSpinner(false, "Upload failed");
|
|
4600
|
+
logger.error(error instanceof Error ? error.message : "Upload error");
|
|
4601
|
+
process.exit(1);
|
|
4602
|
+
}
|
|
4603
|
+
logger.startSpinner("Uploading source...");
|
|
4604
|
+
try {
|
|
4605
|
+
const sourceZipPath = path8__default.default.join(themePath, "dist", "source.zip");
|
|
4606
|
+
await createZip(themePath, sourceZipPath, [
|
|
4607
|
+
"node_modules",
|
|
4608
|
+
"dist",
|
|
4609
|
+
".git",
|
|
4610
|
+
".env",
|
|
4611
|
+
".env.local"
|
|
4612
|
+
]);
|
|
4613
|
+
const sourceBuffer = fs__default.default.readFileSync(sourceZipPath);
|
|
4614
|
+
const sourceRes = await fetch(sourceUploadUrl, {
|
|
4615
|
+
method: "PUT",
|
|
4616
|
+
headers: { "Content-Type": "application/zip" },
|
|
4617
|
+
body: sourceBuffer
|
|
4618
|
+
});
|
|
4619
|
+
if (!sourceRes.ok) {
|
|
4620
|
+
throw new Error(`Source upload failed: ${sourceRes.status}`);
|
|
4621
|
+
}
|
|
4622
|
+
const sizeMB = (sourceBuffer.length / 1024 / 1024).toFixed(2);
|
|
4623
|
+
logger.stopSpinner(true, `Source uploaded (${sizeMB} MB)`);
|
|
4624
|
+
} catch (error) {
|
|
4625
|
+
logger.stopSpinner(false, "Source upload failed");
|
|
4626
|
+
logger.info("Source upload skipped (bundle was uploaded successfully)");
|
|
4627
|
+
}
|
|
4628
|
+
logger.startSpinner("Scanning and publishing...");
|
|
4629
|
+
try {
|
|
4630
|
+
const confirmResponse = await authenticatedFetch(
|
|
4631
|
+
`${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/confirm`,
|
|
4632
|
+
{ method: "POST" }
|
|
4633
|
+
);
|
|
4634
|
+
const confirmData = await confirmResponse.json();
|
|
4635
|
+
const confirmBody = confirmData.statusCode ? confirmData.body : confirmData;
|
|
4636
|
+
if (!confirmResponse.ok || !confirmBody.success) {
|
|
4637
|
+
logger.stopSpinner(false, "Publishing failed");
|
|
4638
|
+
if (confirmBody.violations) {
|
|
4639
|
+
logger.error("Theme rejected \u2014 security violations found:");
|
|
4640
|
+
for (const v of confirmBody.violations) {
|
|
4641
|
+
logger.log(` \u274C ${v.file}: ${v.violation}`);
|
|
4642
|
+
}
|
|
4643
|
+
} else {
|
|
4644
|
+
logger.error(confirmBody.error || "Unknown error");
|
|
4645
|
+
}
|
|
4646
|
+
if (confirmBody.warnings?.length) {
|
|
4647
|
+
logger.newLine();
|
|
4648
|
+
logger.info("Warnings:");
|
|
4649
|
+
for (const w of confirmBody.warnings) {
|
|
4650
|
+
logger.log(` \u26A0\uFE0F ${w.file}: ${w.warning}`);
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
process.exit(1);
|
|
4654
|
+
}
|
|
4655
|
+
logger.stopSpinner(true, confirmBody.message || "Published!");
|
|
4656
|
+
if (confirmBody.warnings?.length) {
|
|
4657
|
+
logger.newLine();
|
|
4658
|
+
logger.info("Warnings (non-blocking):");
|
|
4659
|
+
for (const w of confirmBody.warnings) {
|
|
4660
|
+
logger.log(` \u26A0\uFE0F ${w.file}: ${w.warning}`);
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
} catch (error) {
|
|
4664
|
+
logger.stopSpinner(false, "Publishing failed");
|
|
4665
|
+
logger.error(error instanceof Error ? error.message : "Connection failed");
|
|
4666
|
+
process.exit(1);
|
|
4667
|
+
}
|
|
4668
|
+
logger.newLine();
|
|
4669
|
+
logger.success(`\u2713 Theme "${themeId}" v${version2} published!`);
|
|
4670
|
+
}
|
|
4671
|
+
async function createZip(sourceDir, outputPath, exclude) {
|
|
4672
|
+
const archiver3 = (await import('archiver')).default;
|
|
4673
|
+
const { createWriteStream } = await import('fs');
|
|
4674
|
+
return new Promise((resolve, reject) => {
|
|
4675
|
+
const output = createWriteStream(outputPath);
|
|
4676
|
+
const archive = archiver3("zip", { zlib: { level: 9 } });
|
|
4677
|
+
output.on("close", resolve);
|
|
4678
|
+
archive.on("error", reject);
|
|
4679
|
+
archive.pipe(output);
|
|
4680
|
+
archive.glob("**/*", {
|
|
4681
|
+
cwd: sourceDir,
|
|
4682
|
+
ignore: exclude.map((e) => `${e}/**`),
|
|
4683
|
+
dot: false
|
|
4684
|
+
});
|
|
4685
|
+
archive.finalize();
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4688
|
+
|
|
4457
4689
|
// src/cli.ts
|
|
4458
4690
|
try {
|
|
4459
4691
|
const projectRoot = getProjectRoot();
|
|
@@ -4465,7 +4697,7 @@ try {
|
|
|
4465
4697
|
} catch {
|
|
4466
4698
|
}
|
|
4467
4699
|
dotenv__default.default.config({
|
|
4468
|
-
path: path8__default.default.join(
|
|
4700
|
+
path: path8__default.default.join(os3__default.default.homedir(), ".onexthm", ".env"),
|
|
4469
4701
|
quiet: true
|
|
4470
4702
|
});
|
|
4471
4703
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
|
|
@@ -4522,6 +4754,10 @@ program.command("clone").description("Clone theme source code from S3").argument
|
|
|
4522
4754
|
"staging"
|
|
4523
4755
|
).option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
|
|
4524
4756
|
program.command("config").description("Configure OneX CLI credentials (AWS, API keys)").action(configCommand);
|
|
4757
|
+
program.command("login").description("Login to OneX platform").action(loginCommand);
|
|
4758
|
+
program.command("logout").description("Logout from OneX platform").action(logoutCommand);
|
|
4759
|
+
program.command("whoami").description("Show current logged-in developer").action(whoamiCommand);
|
|
4760
|
+
program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").action(publishCommand);
|
|
4525
4761
|
program.configureOutput({
|
|
4526
4762
|
writeErr: (str) => process.stderr.write(chalk4__default.default.red(str))
|
|
4527
4763
|
});
|