@onexapis/cli 1.0.0 → 1.0.1
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 +197 -214
- package/dist/cli.js +423 -183
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +422 -184
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +418 -184
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +416 -186
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.mjs
CHANGED
|
@@ -6,8 +6,10 @@ import chalk4 from 'chalk';
|
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import ejs from 'ejs';
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
9
|
+
import { PutObjectCommand, GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
import archiver from 'archiver';
|
|
12
|
+
import AdmZip from 'adm-zip';
|
|
11
13
|
|
|
12
14
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
13
15
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -87,8 +89,8 @@ function validateThemeName(name) {
|
|
|
87
89
|
return /^[a-z][a-z0-9-]*$/.test(name);
|
|
88
90
|
}
|
|
89
91
|
function pathExists(filePath) {
|
|
90
|
-
const
|
|
91
|
-
return
|
|
92
|
+
const fs8 = __require("fs-extra");
|
|
93
|
+
return fs8.existsSync(filePath);
|
|
92
94
|
}
|
|
93
95
|
function validateCategory(category) {
|
|
94
96
|
const validCategories = [
|
|
@@ -205,18 +207,19 @@ function getProjectRoot() {
|
|
|
205
207
|
return process.cwd();
|
|
206
208
|
}
|
|
207
209
|
function getThemesDir() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return
|
|
210
|
+
const root = getProjectRoot();
|
|
211
|
+
const themesDir = path.join(root, "themes");
|
|
212
|
+
if (fs.existsSync(themesDir)) {
|
|
213
|
+
return themesDir;
|
|
212
214
|
}
|
|
215
|
+
return path.join(root, "src/themes");
|
|
213
216
|
}
|
|
214
217
|
function getFeaturesDir() {
|
|
215
218
|
return path.join(getProjectRoot(), "src/features");
|
|
216
219
|
}
|
|
217
220
|
function isOneXProject() {
|
|
218
221
|
const root = getProjectRoot();
|
|
219
|
-
return fs.existsSync(path.join(root, "
|
|
222
|
+
return fs.existsSync(path.join(root, "themes")) || fs.existsSync(path.join(root, "src/themes"));
|
|
220
223
|
}
|
|
221
224
|
function ensureOneXProject() {
|
|
222
225
|
if (!isOneXProject()) {
|
|
@@ -233,12 +236,12 @@ function listThemes() {
|
|
|
233
236
|
}
|
|
234
237
|
return fs.readdirSync(themesDir).filter((name) => {
|
|
235
238
|
const themePath = path.join(themesDir, name);
|
|
236
|
-
return fs.statSync(themePath).isDirectory() && fs.existsSync(path.join(themePath, "manifest.ts"));
|
|
239
|
+
return fs.statSync(themePath).isDirectory() && (fs.existsSync(path.join(themePath, "theme.config.ts")) || fs.existsSync(path.join(themePath, "bundle-entry.ts")) || fs.existsSync(path.join(themePath, "manifest.ts")));
|
|
237
240
|
});
|
|
238
241
|
}
|
|
239
242
|
function themeExists(themeName) {
|
|
240
243
|
const themePath = path.join(getThemesDir(), themeName);
|
|
241
|
-
return fs.existsSync(themePath) && fs.existsSync(path.join(themePath, "manifest.ts"));
|
|
244
|
+
return fs.existsSync(themePath) && (fs.existsSync(path.join(themePath, "theme.config.ts")) || fs.existsSync(path.join(themePath, "bundle-entry.ts")) || fs.existsSync(path.join(themePath, "manifest.ts")));
|
|
242
245
|
}
|
|
243
246
|
function detectPackageManager() {
|
|
244
247
|
const userAgent = process.env.npm_config_user_agent || "";
|
|
@@ -432,7 +435,9 @@ Add your theme-specific blocks here.
|
|
|
432
435
|
logger.newLine();
|
|
433
436
|
logger.section("Theme structure:");
|
|
434
437
|
logger.log(" src/manifest.ts - Theme manifest and exports");
|
|
435
|
-
logger.log(
|
|
438
|
+
logger.log(
|
|
439
|
+
" src/config.ts - Design tokens (colors, typography, etc.)"
|
|
440
|
+
);
|
|
436
441
|
logger.log(" src/layout.ts - Header and footer configuration");
|
|
437
442
|
logger.log(" src/sections/ - Custom sections for your theme");
|
|
438
443
|
logger.log(" src/blocks/ - Reusable blocks");
|
|
@@ -1435,8 +1440,16 @@ async function listThemesInfo() {
|
|
|
1435
1440
|
}
|
|
1436
1441
|
logger.log("");
|
|
1437
1442
|
for (const theme of themes) {
|
|
1438
|
-
const
|
|
1439
|
-
const
|
|
1443
|
+
const themeDir = path.join(getThemesDir(), theme);
|
|
1444
|
+
const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
|
|
1445
|
+
let manifestContent = "";
|
|
1446
|
+
for (const candidate of candidates) {
|
|
1447
|
+
const candidatePath = path.join(themeDir, candidate);
|
|
1448
|
+
if (fs.existsSync(candidatePath)) {
|
|
1449
|
+
manifestContent = fs.readFileSync(candidatePath, "utf-8");
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1440
1453
|
const nameMatch = manifestContent.match(/name:\s*["'](.+)["']/);
|
|
1441
1454
|
const versionMatch = manifestContent.match(/version:\s*["'](.+)["']/);
|
|
1442
1455
|
const descMatch = manifestContent.match(/description:\s*["'](.+)["']/);
|
|
@@ -1569,13 +1582,11 @@ function getS3Client() {
|
|
|
1569
1582
|
return new S3Client({
|
|
1570
1583
|
endpoint: endpointUrl,
|
|
1571
1584
|
region: "us-east-1",
|
|
1572
|
-
// MinIO doesn't use real regions
|
|
1573
1585
|
credentials: {
|
|
1574
1586
|
accessKeyId: process.env.MINIO_ACCESS_KEY || "minioadmin",
|
|
1575
1587
|
secretAccessKey: process.env.MINIO_SECRET_KEY || "minioadmin"
|
|
1576
1588
|
},
|
|
1577
1589
|
forcePathStyle: true
|
|
1578
|
-
// Required for MinIO
|
|
1579
1590
|
});
|
|
1580
1591
|
}
|
|
1581
1592
|
if (adapterMode === "local") {
|
|
@@ -1645,36 +1656,40 @@ async function readManifest() {
|
|
|
1645
1656
|
"No manifest.ts or package.json found. Are you in a theme directory?"
|
|
1646
1657
|
);
|
|
1647
1658
|
}
|
|
1648
|
-
function
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
"
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
".ts": "text/plain"
|
|
1663
|
-
};
|
|
1664
|
-
return types[ext] || "application/octet-stream";
|
|
1659
|
+
async function createZipFromDir(sourceDir, outputPath, excludePatterns = []) {
|
|
1660
|
+
return new Promise((resolve, reject) => {
|
|
1661
|
+
const output = fs.createWriteStream(outputPath);
|
|
1662
|
+
const archive = archiver("zip", { zlib: { level: 6 } });
|
|
1663
|
+
output.on("close", () => resolve());
|
|
1664
|
+
archive.on("error", (err) => reject(err));
|
|
1665
|
+
archive.pipe(output);
|
|
1666
|
+
archive.glob("**/*", {
|
|
1667
|
+
cwd: sourceDir,
|
|
1668
|
+
dot: true,
|
|
1669
|
+
ignore: excludePatterns
|
|
1670
|
+
});
|
|
1671
|
+
archive.finalize();
|
|
1672
|
+
});
|
|
1665
1673
|
}
|
|
1666
|
-
async function
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
)
|
|
1674
|
+
async function findSourceDir(themeId, explicitDir) {
|
|
1675
|
+
if (explicitDir) {
|
|
1676
|
+
if (await fs.pathExists(explicitDir)) return explicitDir;
|
|
1677
|
+
return null;
|
|
1678
|
+
}
|
|
1679
|
+
const searchPaths = [
|
|
1680
|
+
process.cwd(),
|
|
1681
|
+
path.resolve(process.cwd(), `../../themes/${themeId}`),
|
|
1682
|
+
path.resolve(process.cwd(), `../themes/${themeId}`)
|
|
1683
|
+
];
|
|
1684
|
+
const markers = ["theme.config.ts", "bundle-entry.ts"];
|
|
1685
|
+
for (const dir of searchPaths) {
|
|
1686
|
+
for (const marker of markers) {
|
|
1687
|
+
if (await fs.pathExists(path.join(dir, marker))) {
|
|
1688
|
+
return dir;
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return null;
|
|
1678
1693
|
}
|
|
1679
1694
|
async function updateLatestPointer(s3Client, bucket, themeId, version) {
|
|
1680
1695
|
const latestData = {
|
|
@@ -1692,12 +1707,18 @@ async function updateLatestPointer(s3Client, bucket, themeId, version) {
|
|
|
1692
1707
|
}
|
|
1693
1708
|
async function uploadCommand(options) {
|
|
1694
1709
|
logger.header("Upload Theme to S3");
|
|
1695
|
-
ensureOneXProject();
|
|
1696
1710
|
const spinner = ora("Preparing theme upload...").start();
|
|
1697
1711
|
try {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1712
|
+
let themeId;
|
|
1713
|
+
let version;
|
|
1714
|
+
if (options.theme) {
|
|
1715
|
+
themeId = options.theme;
|
|
1716
|
+
version = options.version || "1.0.0";
|
|
1717
|
+
} else {
|
|
1718
|
+
const manifest = await readManifest();
|
|
1719
|
+
themeId = manifest.themeId;
|
|
1720
|
+
version = options.version || manifest.version || "1.0.0";
|
|
1721
|
+
}
|
|
1701
1722
|
spinner.text = `Found theme: ${themeId}@${version}`;
|
|
1702
1723
|
const bucket = options.bucket || getBucketName(options.environment);
|
|
1703
1724
|
const s3Client = getS3Client();
|
|
@@ -1718,67 +1739,113 @@ async function uploadCommand(options) {
|
|
|
1718
1739
|
process.exit(1);
|
|
1719
1740
|
}
|
|
1720
1741
|
spinner.succeed(`Found compiled theme at: ${compiledDir}`);
|
|
1721
|
-
spinner.start(
|
|
1722
|
-
const
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
spinner.fail(chalk4.red("No files found in compiled theme directory"));
|
|
1729
|
-
process.exit(1);
|
|
1730
|
-
}
|
|
1731
|
-
spinner.succeed(`Found ${files.length} files to upload`);
|
|
1742
|
+
spinner.start("Creating bundle.zip...");
|
|
1743
|
+
const tmpDir = os.tmpdir();
|
|
1744
|
+
const bundleZipPath = path.join(tmpDir, `${themeId}-${version}-bundle.zip`);
|
|
1745
|
+
await createZipFromDir(compiledDir, bundleZipPath);
|
|
1746
|
+
const bundleZipBuffer = await fs.readFile(bundleZipPath);
|
|
1747
|
+
const bundleSizeMB = (bundleZipBuffer.length / 1024 / 1024).toFixed(2);
|
|
1748
|
+
spinner.succeed(`Created bundle.zip (${bundleSizeMB} MB)`);
|
|
1732
1749
|
if (options.dryRun) {
|
|
1733
|
-
spinner.info(chalk4.yellow("Dry run mode
|
|
1734
|
-
console.log(
|
|
1735
|
-
|
|
1736
|
-
displayFiles.forEach((file) => console.log(chalk4.gray(` - ${file}`)));
|
|
1737
|
-
if (files.length > 10) {
|
|
1738
|
-
console.log(chalk4.gray(` ... and ${files.length - 10} more files
|
|
1739
|
-
`));
|
|
1740
|
-
}
|
|
1741
|
-
console.log(chalk4.cyan(`
|
|
1742
|
-
S3 bucket: ${bucket}`));
|
|
1750
|
+
spinner.info(chalk4.yellow("Dry run mode \u2014 no files will be uploaded"));
|
|
1751
|
+
console.log();
|
|
1752
|
+
console.log(chalk4.gray(` bundle.zip: ${bundleSizeMB} MB`));
|
|
1743
1753
|
console.log(
|
|
1744
|
-
chalk4.cyan(
|
|
1745
|
-
`
|
|
1754
|
+
chalk4.cyan(
|
|
1755
|
+
` S3 path: s3://${bucket}/themes/${themeId}/${version}/bundle.zip`
|
|
1756
|
+
)
|
|
1746
1757
|
);
|
|
1758
|
+
if (!options.skipSource) {
|
|
1759
|
+
const sourceDir = await findSourceDir(themeId, options.sourceDir);
|
|
1760
|
+
if (sourceDir) {
|
|
1761
|
+
console.log(chalk4.gray(` source dir: ${sourceDir}`));
|
|
1762
|
+
console.log(
|
|
1763
|
+
chalk4.cyan(
|
|
1764
|
+
` S3 path: s3://${bucket}/themes/${themeId}/${version}/source.zip`
|
|
1765
|
+
)
|
|
1766
|
+
);
|
|
1767
|
+
} else {
|
|
1768
|
+
console.log(
|
|
1769
|
+
chalk4.yellow(" source dir: not found (source.zip will be skipped)")
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
console.log();
|
|
1774
|
+
await fs.remove(bundleZipPath);
|
|
1747
1775
|
return;
|
|
1748
1776
|
}
|
|
1749
|
-
spinner.start(
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1777
|
+
spinner.start("Uploading bundle.zip to S3...");
|
|
1778
|
+
const bundleS3Key = `themes/${themeId}/${version}/bundle.zip`;
|
|
1779
|
+
await s3Client.send(
|
|
1780
|
+
new PutObjectCommand({
|
|
1781
|
+
Bucket: bucket,
|
|
1782
|
+
Key: bundleS3Key,
|
|
1783
|
+
Body: bundleZipBuffer,
|
|
1784
|
+
ContentType: "application/zip"
|
|
1785
|
+
})
|
|
1786
|
+
);
|
|
1787
|
+
spinner.succeed(
|
|
1788
|
+
`Uploaded bundle.zip ${chalk4.gray(`\u2192 s3://${bucket}/${bundleS3Key}`)}`
|
|
1789
|
+
);
|
|
1790
|
+
await fs.remove(bundleZipPath);
|
|
1791
|
+
let sourceUploaded = false;
|
|
1792
|
+
if (!options.skipSource) {
|
|
1793
|
+
spinner.start("Looking for source directory...");
|
|
1794
|
+
const sourceDir = await findSourceDir(themeId, options.sourceDir);
|
|
1795
|
+
if (sourceDir) {
|
|
1796
|
+
spinner.succeed(`Found source at: ${sourceDir}`);
|
|
1797
|
+
spinner.start("Creating source.zip...");
|
|
1798
|
+
const sourceZipPath = path.join(
|
|
1799
|
+
tmpDir,
|
|
1800
|
+
`${themeId}-${version}-source.zip`
|
|
1801
|
+
);
|
|
1802
|
+
await createZipFromDir(sourceDir, sourceZipPath, [
|
|
1803
|
+
"node_modules/**",
|
|
1804
|
+
"dist/**",
|
|
1805
|
+
".git/**",
|
|
1806
|
+
"*.zip",
|
|
1807
|
+
".next/**",
|
|
1808
|
+
".turbo/**"
|
|
1809
|
+
]);
|
|
1810
|
+
const sourceZipBuffer = await fs.readFile(sourceZipPath);
|
|
1811
|
+
const sourceSizeMB = (sourceZipBuffer.length / 1024 / 1024).toFixed(2);
|
|
1812
|
+
spinner.succeed(`Created source.zip (${sourceSizeMB} MB)`);
|
|
1813
|
+
spinner.start("Uploading source.zip to S3...");
|
|
1814
|
+
const sourceS3Key = `themes/${themeId}/${version}/source.zip`;
|
|
1815
|
+
await s3Client.send(
|
|
1816
|
+
new PutObjectCommand({
|
|
1817
|
+
Bucket: bucket,
|
|
1818
|
+
Key: sourceS3Key,
|
|
1819
|
+
Body: sourceZipBuffer,
|
|
1820
|
+
ContentType: "application/zip"
|
|
1821
|
+
})
|
|
1822
|
+
);
|
|
1823
|
+
spinner.succeed(
|
|
1824
|
+
`Uploaded source.zip ${chalk4.gray(`\u2192 s3://${bucket}/${sourceS3Key}`)}`
|
|
1825
|
+
);
|
|
1826
|
+
await fs.remove(sourceZipPath);
|
|
1827
|
+
sourceUploaded = true;
|
|
1828
|
+
} else {
|
|
1829
|
+
spinner.warn(
|
|
1830
|
+
chalk4.yellow("Source directory not found \u2014 skipping source.zip")
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1769
1833
|
}
|
|
1770
|
-
spinner.succeed(`Uploaded ${total} files to S3`);
|
|
1771
1834
|
spinner.start("Updating latest.json pointer...");
|
|
1772
1835
|
await updateLatestPointer(s3Client, bucket, themeId, version);
|
|
1773
1836
|
spinner.succeed("Updated latest.json pointer");
|
|
1774
1837
|
console.log();
|
|
1775
|
-
logger.success(chalk4.green.bold("
|
|
1838
|
+
logger.success(chalk4.green.bold("Theme uploaded successfully!"));
|
|
1776
1839
|
console.log();
|
|
1777
1840
|
console.log(
|
|
1778
1841
|
chalk4.cyan(" Theme: ") + chalk4.white(`${themeId}@${version}`)
|
|
1779
1842
|
);
|
|
1780
1843
|
console.log(chalk4.cyan(" Bucket: ") + chalk4.white(bucket));
|
|
1781
|
-
console.log(
|
|
1844
|
+
console.log(
|
|
1845
|
+
chalk4.cyan(" Files: ") + chalk4.white(
|
|
1846
|
+
`bundle.zip${sourceUploaded ? " + source.zip" : ""}`
|
|
1847
|
+
)
|
|
1848
|
+
);
|
|
1782
1849
|
console.log(
|
|
1783
1850
|
chalk4.cyan(" Path: ") + chalk4.gray(`s3://${bucket}/themes/${themeId}/${version}/`)
|
|
1784
1851
|
);
|
|
@@ -1882,79 +1949,45 @@ async function resolveLatestVersion(s3Client, bucket, themeId) {
|
|
|
1882
1949
|
);
|
|
1883
1950
|
}
|
|
1884
1951
|
}
|
|
1885
|
-
async function
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
`Failed to download manifest for ${themeId}@${version}: ${error.message}
|
|
1898
|
-
The theme may not exist in S3 bucket "${bucket}".`
|
|
1899
|
-
);
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
async function downloadFile(s3Client, bucket, themeId, version, file, outputDir) {
|
|
1903
|
-
const s3Key = `themes/${themeId}/${version}/${file}`;
|
|
1904
|
-
const localPath = path.join(outputDir, file);
|
|
1905
|
-
await fs.ensureDir(path.dirname(localPath));
|
|
1906
|
-
try {
|
|
1907
|
-
const response = await s3Client.send(
|
|
1908
|
-
new GetObjectCommand({
|
|
1909
|
-
Bucket: bucket,
|
|
1910
|
-
Key: s3Key
|
|
1911
|
-
})
|
|
1912
|
-
);
|
|
1913
|
-
const content = await streamToBuffer(response.Body);
|
|
1914
|
-
await fs.writeFile(localPath, content);
|
|
1915
|
-
} catch (error) {
|
|
1916
|
-
throw new Error(`Failed to download ${file}: ${error.message}`);
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
function collectFilesToDownload(manifest) {
|
|
1920
|
-
const files = ["manifest.json"];
|
|
1921
|
-
if (manifest.output) {
|
|
1922
|
-
if (manifest.output.entry) {
|
|
1923
|
-
files.push(manifest.output.entry);
|
|
1924
|
-
}
|
|
1925
|
-
if (manifest.output.chunks) {
|
|
1926
|
-
files.push(...manifest.output.chunks);
|
|
1927
|
-
}
|
|
1928
|
-
if (manifest.output.assets) {
|
|
1929
|
-
files.push(...manifest.output.assets);
|
|
1952
|
+
async function createCompatibilityFiles(outputDir, manifest) {
|
|
1953
|
+
var _a;
|
|
1954
|
+
const entryFile = ((_a = manifest.output) == null ? void 0 : _a.entry) || "bundle-entry.js";
|
|
1955
|
+
if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
|
|
1956
|
+
const hashedPath = path.join(outputDir, entryFile);
|
|
1957
|
+
const stablePath = path.join(outputDir, "bundle-entry.js");
|
|
1958
|
+
if (await fs.pathExists(hashedPath)) {
|
|
1959
|
+
await fs.copy(hashedPath, stablePath);
|
|
1960
|
+
const mapPath = hashedPath + ".map";
|
|
1961
|
+
if (await fs.pathExists(mapPath)) {
|
|
1962
|
+
await fs.copy(mapPath, stablePath + ".map");
|
|
1963
|
+
}
|
|
1930
1964
|
}
|
|
1931
1965
|
}
|
|
1932
|
-
return files;
|
|
1933
|
-
}
|
|
1934
|
-
async function createCompatibilityFiles(outputDir) {
|
|
1935
1966
|
const sectionsRegistryPath = path.join(outputDir, "sections-registry.js");
|
|
1936
1967
|
const content = `// Re-export all sections from bundle-entry
|
|
1937
1968
|
// This file exists to maintain compatibility with the import path
|
|
1938
1969
|
export * from './bundle-entry.js';
|
|
1939
1970
|
`;
|
|
1940
1971
|
await fs.writeFile(sectionsRegistryPath, content, "utf-8");
|
|
1972
|
+
const pkgJsonPath = path.join(outputDir, "package.json");
|
|
1973
|
+
await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
|
|
1941
1974
|
}
|
|
1942
1975
|
function showDownloadFailureHelp(themeId, bucket) {
|
|
1943
1976
|
console.log();
|
|
1944
|
-
logger.error(chalk4.red.bold("
|
|
1977
|
+
logger.error(chalk4.red.bold("Theme download failed"));
|
|
1945
1978
|
console.log();
|
|
1946
1979
|
console.log(chalk4.yellow("Possible reasons:"));
|
|
1947
1980
|
console.log(chalk4.gray(" 1. Theme not uploaded to S3 yet"));
|
|
1948
1981
|
console.log(chalk4.gray(" 2. AWS credentials not configured correctly"));
|
|
1949
1982
|
console.log(chalk4.gray(" 3. Bucket name or region is incorrect"));
|
|
1950
|
-
console.log(chalk4.gray(" 4.
|
|
1983
|
+
console.log(chalk4.gray(" 4. bundle.zip is missing or corrupted"));
|
|
1951
1984
|
console.log();
|
|
1952
1985
|
console.log(chalk4.cyan.bold("To fix this:"));
|
|
1953
1986
|
console.log();
|
|
1954
1987
|
console.log(chalk4.white("1. Compile and upload the theme:"));
|
|
1955
1988
|
console.log(chalk4.gray(` cd themes/${themeId}`));
|
|
1956
1989
|
console.log(chalk4.gray(" pnpm build"));
|
|
1957
|
-
console.log(chalk4.gray("
|
|
1990
|
+
console.log(chalk4.gray(" onex upload"));
|
|
1958
1991
|
console.log();
|
|
1959
1992
|
console.log(chalk4.white("2. Verify AWS credentials are set:"));
|
|
1960
1993
|
console.log(
|
|
@@ -1970,7 +2003,11 @@ function showDownloadFailureHelp(themeId, bucket) {
|
|
|
1970
2003
|
);
|
|
1971
2004
|
console.log();
|
|
1972
2005
|
console.log(chalk4.white("4. Verify theme exists in S3:"));
|
|
1973
|
-
console.log(
|
|
2006
|
+
console.log(
|
|
2007
|
+
chalk4.gray(
|
|
2008
|
+
` aws s3 ls s3://${bucket}/themes/${themeId}/`
|
|
2009
|
+
)
|
|
2010
|
+
);
|
|
1974
2011
|
console.log();
|
|
1975
2012
|
}
|
|
1976
2013
|
async function downloadCommand(options) {
|
|
@@ -1998,55 +2035,44 @@ async function downloadCommand(options) {
|
|
|
1998
2035
|
spinner.succeed(
|
|
1999
2036
|
`Resolved latest version: ${chalk4.cyan(resolvedVersion)}`
|
|
2000
2037
|
);
|
|
2001
|
-
spinner.start("Downloading manifest...");
|
|
2002
2038
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2039
|
+
spinner.start(
|
|
2040
|
+
`Downloading bundle.zip for ${themeId}@${resolvedVersion}...`
|
|
2041
|
+
);
|
|
2042
|
+
const s3Key = `themes/${themeId}/${resolvedVersion}/bundle.zip`;
|
|
2043
|
+
const response = await s3Client.send(
|
|
2044
|
+
new GetObjectCommand({
|
|
2045
|
+
Bucket: bucket,
|
|
2046
|
+
Key: s3Key
|
|
2047
|
+
})
|
|
2008
2048
|
);
|
|
2009
|
-
|
|
2010
|
-
|
|
2049
|
+
const zipBuffer = await streamToBuffer(response.Body);
|
|
2050
|
+
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2051
|
+
spinner.succeed(`Downloaded bundle.zip (${sizeMB} MB)`);
|
|
2052
|
+
spinner.start("Extracting bundle...");
|
|
2011
2053
|
await fs.remove(outputDir);
|
|
2012
2054
|
await fs.ensureDir(outputDir);
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
const
|
|
2016
|
-
|
|
2017
|
-
const
|
|
2018
|
-
const
|
|
2019
|
-
|
|
2020
|
-
const batch = files.slice(i, i + batchSize);
|
|
2021
|
-
await Promise.all(
|
|
2022
|
-
batch.map(async (file) => {
|
|
2023
|
-
await downloadFile(
|
|
2024
|
-
s3Client,
|
|
2025
|
-
bucket,
|
|
2026
|
-
themeId,
|
|
2027
|
-
resolvedVersion,
|
|
2028
|
-
file,
|
|
2029
|
-
outputDir
|
|
2030
|
-
);
|
|
2031
|
-
downloaded++;
|
|
2032
|
-
spinner.text = `Downloading... ${downloaded}/${total} files (${Math.round(downloaded / total * 100)}%)`;
|
|
2033
|
-
})
|
|
2034
|
-
);
|
|
2035
|
-
}
|
|
2036
|
-
spinner.succeed(`Downloaded ${total} files`);
|
|
2037
|
-
await createCompatibilityFiles(outputDir);
|
|
2055
|
+
const zip = new AdmZip(zipBuffer);
|
|
2056
|
+
zip.extractAllTo(outputDir, true);
|
|
2057
|
+
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
2058
|
+
spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
|
|
2059
|
+
const manifestPath = path.join(outputDir, "manifest.json");
|
|
2060
|
+
const manifest = await fs.readJson(manifestPath);
|
|
2061
|
+
await createCompatibilityFiles(outputDir, manifest);
|
|
2038
2062
|
console.log();
|
|
2039
|
-
logger.success(chalk4.green.bold("
|
|
2063
|
+
logger.success(chalk4.green.bold("Theme downloaded successfully!"));
|
|
2040
2064
|
console.log();
|
|
2041
2065
|
console.log(
|
|
2042
2066
|
chalk4.cyan(" Theme: ") + chalk4.white(`${themeId}@${resolvedVersion}`)
|
|
2043
2067
|
);
|
|
2044
2068
|
console.log(chalk4.cyan(" Bucket: ") + chalk4.white(bucket));
|
|
2045
2069
|
console.log(chalk4.cyan(" Output: ") + chalk4.white(outputDir));
|
|
2046
|
-
console.log(chalk4.cyan(" Files: ") + chalk4.white(
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2070
|
+
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
2071
|
+
if (manifest.counts) {
|
|
2072
|
+
console.log(
|
|
2073
|
+
chalk4.cyan(" Sections:") + chalk4.white(` ${manifest.counts.sections}`)
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2050
2076
|
console.log();
|
|
2051
2077
|
} catch (error) {
|
|
2052
2078
|
spinner.fail(chalk4.red("Download failed"));
|
|
@@ -2057,7 +2083,211 @@ async function downloadCommand(options) {
|
|
|
2057
2083
|
process.exit(1);
|
|
2058
2084
|
}
|
|
2059
2085
|
}
|
|
2086
|
+
function getS3Client3() {
|
|
2087
|
+
const adapterMode = (process.env.ADAPTER_MODE || "aws").trim().toLowerCase();
|
|
2088
|
+
if (adapterMode === "vps") {
|
|
2089
|
+
const endpoint = process.env.MINIO_ENDPOINT || "localhost:9000";
|
|
2090
|
+
const secure = process.env.MINIO_SECURE === "true";
|
|
2091
|
+
const endpointUrl = endpoint.startsWith("http") ? endpoint : `${secure ? "https" : "http"}://${endpoint}`;
|
|
2092
|
+
return new S3Client({
|
|
2093
|
+
endpoint: endpointUrl,
|
|
2094
|
+
region: "us-east-1",
|
|
2095
|
+
credentials: {
|
|
2096
|
+
accessKeyId: process.env.MINIO_ACCESS_KEY || "minioadmin",
|
|
2097
|
+
secretAccessKey: process.env.MINIO_SECRET_KEY || "minioadmin"
|
|
2098
|
+
},
|
|
2099
|
+
forcePathStyle: true
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
if (adapterMode === "local") {
|
|
2103
|
+
return new S3Client({
|
|
2104
|
+
endpoint: "http://localhost:4569",
|
|
2105
|
+
region: "ap-southeast-1",
|
|
2106
|
+
credentials: {
|
|
2107
|
+
accessKeyId: "S3RVER",
|
|
2108
|
+
secretAccessKey: "S3RVER"
|
|
2109
|
+
},
|
|
2110
|
+
forcePathStyle: true
|
|
2111
|
+
});
|
|
2112
|
+
}
|
|
2113
|
+
return new S3Client({
|
|
2114
|
+
region: process.env.AWS_REGION || "ap-southeast-1"
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
function getBucketName3(env) {
|
|
2118
|
+
if (process.env.BUCKET_NAME) {
|
|
2119
|
+
return process.env.BUCKET_NAME;
|
|
2120
|
+
}
|
|
2121
|
+
const environment = env || process.env.ENVIRONMENT || "staging";
|
|
2122
|
+
return environment === "production" ? "onex-themes-prod" : "onex-themes-staging";
|
|
2123
|
+
}
|
|
2124
|
+
async function streamToString2(stream) {
|
|
2125
|
+
const chunks = [];
|
|
2126
|
+
try {
|
|
2127
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
2128
|
+
const chunk = temp.value;
|
|
2129
|
+
chunks.push(Buffer.from(chunk));
|
|
2130
|
+
}
|
|
2131
|
+
} catch (temp) {
|
|
2132
|
+
error = [temp];
|
|
2133
|
+
} finally {
|
|
2134
|
+
try {
|
|
2135
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
2136
|
+
} finally {
|
|
2137
|
+
if (error)
|
|
2138
|
+
throw error[0];
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
2142
|
+
}
|
|
2143
|
+
async function streamToBuffer2(stream) {
|
|
2144
|
+
const chunks = [];
|
|
2145
|
+
try {
|
|
2146
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
2147
|
+
const chunk = temp.value;
|
|
2148
|
+
chunks.push(Buffer.from(chunk));
|
|
2149
|
+
}
|
|
2150
|
+
} catch (temp) {
|
|
2151
|
+
error = [temp];
|
|
2152
|
+
} finally {
|
|
2153
|
+
try {
|
|
2154
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
2155
|
+
} finally {
|
|
2156
|
+
if (error)
|
|
2157
|
+
throw error[0];
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return Buffer.concat(chunks);
|
|
2161
|
+
}
|
|
2162
|
+
async function resolveLatestVersion2(s3Client, bucket, themeId) {
|
|
2163
|
+
try {
|
|
2164
|
+
const response = await s3Client.send(
|
|
2165
|
+
new GetObjectCommand({
|
|
2166
|
+
Bucket: bucket,
|
|
2167
|
+
Key: `themes/${themeId}/latest.json`
|
|
2168
|
+
})
|
|
2169
|
+
);
|
|
2170
|
+
const body = await streamToString2(response.Body);
|
|
2171
|
+
return JSON.parse(body).version;
|
|
2172
|
+
} catch (error) {
|
|
2173
|
+
throw new Error(
|
|
2174
|
+
`Failed to resolve latest version for theme "${themeId}": ${error.message}`
|
|
2175
|
+
);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
function runInstall(cwd) {
|
|
2179
|
+
return new Promise((resolve) => {
|
|
2180
|
+
const proc = spawn("pnpm", ["install"], {
|
|
2181
|
+
cwd,
|
|
2182
|
+
stdio: "inherit",
|
|
2183
|
+
shell: true
|
|
2184
|
+
});
|
|
2185
|
+
proc.on("close", (code) => resolve(code === 0));
|
|
2186
|
+
proc.on("error", () => resolve(false));
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
async function cloneCommand(themeName, options) {
|
|
2190
|
+
logger.header("Clone Theme Source");
|
|
2191
|
+
const spinner = ora("Initializing clone...").start();
|
|
2192
|
+
try {
|
|
2193
|
+
const bucket = options.bucket || getBucketName3(options.environment);
|
|
2194
|
+
const outputDir = options.output || path.resolve(process.cwd(), themeName);
|
|
2195
|
+
const s3Client = getS3Client3();
|
|
2196
|
+
if (await fs.pathExists(outputDir)) {
|
|
2197
|
+
spinner.fail(
|
|
2198
|
+
chalk4.red(`Directory already exists: ${outputDir}`)
|
|
2199
|
+
);
|
|
2200
|
+
logger.info(
|
|
2201
|
+
chalk4.gray(
|
|
2202
|
+
"Use -o to specify a different output directory, or remove the existing directory."
|
|
2203
|
+
)
|
|
2204
|
+
);
|
|
2205
|
+
process.exit(1);
|
|
2206
|
+
}
|
|
2207
|
+
let version = options.version || "latest";
|
|
2208
|
+
if (version === "latest") {
|
|
2209
|
+
spinner.text = "Resolving latest version...";
|
|
2210
|
+
version = await resolveLatestVersion2(s3Client, bucket, themeName);
|
|
2211
|
+
spinner.succeed(`Resolved latest version: ${chalk4.cyan(version)}`);
|
|
2212
|
+
}
|
|
2213
|
+
spinner.start(
|
|
2214
|
+
`Downloading source.zip for ${themeName}@${version}...`
|
|
2215
|
+
);
|
|
2216
|
+
const s3Key = `themes/${themeName}/${version}/source.zip`;
|
|
2217
|
+
let zipBuffer;
|
|
2218
|
+
try {
|
|
2219
|
+
const response = await s3Client.send(
|
|
2220
|
+
new GetObjectCommand({
|
|
2221
|
+
Bucket: bucket,
|
|
2222
|
+
Key: s3Key
|
|
2223
|
+
})
|
|
2224
|
+
);
|
|
2225
|
+
zipBuffer = await streamToBuffer2(response.Body);
|
|
2226
|
+
} catch (error) {
|
|
2227
|
+
spinner.fail(chalk4.red(`Source not found: s3://${bucket}/${s3Key}`));
|
|
2228
|
+
console.log();
|
|
2229
|
+
console.log(
|
|
2230
|
+
chalk4.yellow("The theme source may not have been uploaded yet.")
|
|
2231
|
+
);
|
|
2232
|
+
console.log(
|
|
2233
|
+
chalk4.gray(
|
|
2234
|
+
`Upload source with: onex upload --theme ${themeName}`
|
|
2235
|
+
)
|
|
2236
|
+
);
|
|
2237
|
+
console.log();
|
|
2238
|
+
process.exit(1);
|
|
2239
|
+
}
|
|
2240
|
+
const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
|
|
2241
|
+
spinner.succeed(`Downloaded source.zip (${sizeMB} MB)`);
|
|
2242
|
+
spinner.start(`Extracting to ${outputDir}...`);
|
|
2243
|
+
await fs.ensureDir(outputDir);
|
|
2244
|
+
const zip = new AdmZip(zipBuffer);
|
|
2245
|
+
zip.extractAllTo(outputDir, true);
|
|
2246
|
+
const entries = zip.getEntries().filter((e) => !e.isDirectory);
|
|
2247
|
+
spinner.succeed(`Extracted ${entries.length} files`);
|
|
2248
|
+
if (options.install !== false) {
|
|
2249
|
+
const hasPkgJson = await fs.pathExists(
|
|
2250
|
+
path.join(outputDir, "package.json")
|
|
2251
|
+
);
|
|
2252
|
+
if (hasPkgJson) {
|
|
2253
|
+
spinner.start("Installing dependencies...");
|
|
2254
|
+
const success = await runInstall(outputDir);
|
|
2255
|
+
if (success) {
|
|
2256
|
+
spinner.succeed("Dependencies installed");
|
|
2257
|
+
} else {
|
|
2258
|
+
spinner.warn(
|
|
2259
|
+
chalk4.yellow(
|
|
2260
|
+
"Failed to install dependencies \u2014 run 'pnpm install' manually"
|
|
2261
|
+
)
|
|
2262
|
+
);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
console.log();
|
|
2267
|
+
logger.success(chalk4.green.bold("Theme cloned successfully!"));
|
|
2268
|
+
console.log();
|
|
2269
|
+
console.log(
|
|
2270
|
+
chalk4.cyan(" Theme: ") + chalk4.white(`${themeName}@${version}`)
|
|
2271
|
+
);
|
|
2272
|
+
console.log(chalk4.cyan(" Location: ") + chalk4.white(outputDir));
|
|
2273
|
+
console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
|
|
2274
|
+
console.log();
|
|
2275
|
+
console.log(chalk4.cyan("Next steps:"));
|
|
2276
|
+
console.log(
|
|
2277
|
+
chalk4.gray(` cd ${path.relative(process.cwd(), outputDir)}`)
|
|
2278
|
+
);
|
|
2279
|
+
if (options.install === false) {
|
|
2280
|
+
console.log(chalk4.gray(" pnpm install"));
|
|
2281
|
+
}
|
|
2282
|
+
console.log(chalk4.gray(" onex build"));
|
|
2283
|
+
console.log();
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
spinner.fail(chalk4.red(`Clone failed: ${error.message}`));
|
|
2286
|
+
logger.error(error.stack || error.message);
|
|
2287
|
+
process.exit(1);
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2060
2290
|
|
|
2061
|
-
export { Logger, buildCommand, copyTemplate, createBlockCommand, createComponentCommand, createSectionCommand, detectPackageManager, downloadCommand, ensureOneXProject, getFeaturesDir, getProjectRoot, getThemesDir, getValidCategories, initCommand, installDependencies, isOneXProject, listCommand, listThemes, logger, pathExists, renderTemplate, themeExists, toCamelCase, toKebabCase, toPascalCase, uploadCommand, validateCategory, validateName, validateThemeName, writeFile };
|
|
2291
|
+
export { Logger, buildCommand, cloneCommand, copyTemplate, createBlockCommand, createComponentCommand, createSectionCommand, detectPackageManager, downloadCommand, ensureOneXProject, getFeaturesDir, getProjectRoot, getThemesDir, getValidCategories, initCommand, installDependencies, isOneXProject, listCommand, listThemes, logger, pathExists, renderTemplate, themeExists, toCamelCase, toKebabCase, toPascalCase, uploadCommand, validateCategory, validateName, validateThemeName, writeFile };
|
|
2062
2292
|
//# sourceMappingURL=index.mjs.map
|
|
2063
2293
|
//# sourceMappingURL=index.mjs.map
|