@onexapis/cli 1.1.63 → 1.1.65
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 +267 -105
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +267 -105
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +10 -17
- package/dist/index.d.ts +10 -17
- package/dist/index.js +67 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/templates/default/.env.example +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Auth Utilities
|
|
3
|
+
* Token storage, refresh, and API authentication for onexthm CLI.
|
|
4
|
+
*/
|
|
5
|
+
/** Supported target environments. */
|
|
6
|
+
type Env = "dev" | "prod";
|
|
7
|
+
|
|
1
8
|
interface InitOptions {
|
|
2
9
|
template?: string;
|
|
3
10
|
noInstall?: boolean;
|
|
4
11
|
git?: boolean;
|
|
5
12
|
yes?: boolean;
|
|
13
|
+
env?: Env;
|
|
6
14
|
}
|
|
7
15
|
declare function initCommand(projectName?: string, options?: InitOptions): Promise<void>;
|
|
8
16
|
|
|
@@ -72,41 +80,26 @@ interface DownloadOptions {
|
|
|
72
80
|
themeId?: string;
|
|
73
81
|
version?: string;
|
|
74
82
|
output?: string;
|
|
83
|
+
env?: Env;
|
|
75
84
|
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
76
85
|
bucket?: string;
|
|
77
|
-
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
78
|
-
environment?: "staging" | "production";
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
88
|
* Download a published theme via the website-api Lambda endpoints.
|
|
82
|
-
*
|
|
83
|
-
* This command no longer talks to S3 directly — the platform now serves
|
|
84
|
-
* theme content through HTTP-only endpoints, so AWS credentials, bucket
|
|
85
|
-
* names, and region settings are no longer required. The legacy
|
|
86
|
-
* `--bucket` and `--environment` flags are accepted but ignored for
|
|
87
|
-
* backwards compatibility with existing scripts.
|
|
88
89
|
*/
|
|
89
90
|
declare function downloadCommand(options: DownloadOptions): Promise<void>;
|
|
90
91
|
|
|
91
92
|
interface CloneOptions {
|
|
92
93
|
version?: string;
|
|
93
94
|
output?: string;
|
|
95
|
+
env?: Env;
|
|
94
96
|
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
95
97
|
bucket?: string;
|
|
96
|
-
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
97
|
-
environment?: "staging" | "production";
|
|
98
98
|
install?: boolean;
|
|
99
99
|
name?: string;
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Clone theme source code via the website-api.
|
|
103
|
-
*
|
|
104
|
-
* Calls the authenticated `/source` Lambda to get a presigned S3 URL,
|
|
105
|
-
* downloads the source.zip, and extracts it to a local directory. Asks
|
|
106
|
-
* the user for a new theme name to differentiate from the original.
|
|
107
|
-
*
|
|
108
|
-
* Requires login (`onexthm login`) — the source endpoint is JWT-gated
|
|
109
|
-
* because cloning grants access to a developer's full theme source.
|
|
110
103
|
*/
|
|
111
104
|
declare function cloneCommand(themeName: string, options: CloneOptions): Promise<void>;
|
|
112
105
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Auth Utilities
|
|
3
|
+
* Token storage, refresh, and API authentication for onexthm CLI.
|
|
4
|
+
*/
|
|
5
|
+
/** Supported target environments. */
|
|
6
|
+
type Env = "dev" | "prod";
|
|
7
|
+
|
|
1
8
|
interface InitOptions {
|
|
2
9
|
template?: string;
|
|
3
10
|
noInstall?: boolean;
|
|
4
11
|
git?: boolean;
|
|
5
12
|
yes?: boolean;
|
|
13
|
+
env?: Env;
|
|
6
14
|
}
|
|
7
15
|
declare function initCommand(projectName?: string, options?: InitOptions): Promise<void>;
|
|
8
16
|
|
|
@@ -72,41 +80,26 @@ interface DownloadOptions {
|
|
|
72
80
|
themeId?: string;
|
|
73
81
|
version?: string;
|
|
74
82
|
output?: string;
|
|
83
|
+
env?: Env;
|
|
75
84
|
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
76
85
|
bucket?: string;
|
|
77
|
-
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
78
|
-
environment?: "staging" | "production";
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
88
|
* Download a published theme via the website-api Lambda endpoints.
|
|
82
|
-
*
|
|
83
|
-
* This command no longer talks to S3 directly — the platform now serves
|
|
84
|
-
* theme content through HTTP-only endpoints, so AWS credentials, bucket
|
|
85
|
-
* names, and region settings are no longer required. The legacy
|
|
86
|
-
* `--bucket` and `--environment` flags are accepted but ignored for
|
|
87
|
-
* backwards compatibility with existing scripts.
|
|
88
89
|
*/
|
|
89
90
|
declare function downloadCommand(options: DownloadOptions): Promise<void>;
|
|
90
91
|
|
|
91
92
|
interface CloneOptions {
|
|
92
93
|
version?: string;
|
|
93
94
|
output?: string;
|
|
95
|
+
env?: Env;
|
|
94
96
|
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
95
97
|
bucket?: string;
|
|
96
|
-
/** @deprecated kept for backwards-compat with older scripts; ignored. */
|
|
97
|
-
environment?: "staging" | "production";
|
|
98
98
|
install?: boolean;
|
|
99
99
|
name?: string;
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Clone theme source code via the website-api.
|
|
103
|
-
*
|
|
104
|
-
* Calls the authenticated `/source` Lambda to get a presigned S3 URL,
|
|
105
|
-
* downloads the source.zip, and extracts it to a local directory. Asks
|
|
106
|
-
* the user for a new theme name to differentiate from the original.
|
|
107
|
-
*
|
|
108
|
-
* Requires login (`onexthm login`) — the source endpoint is JWT-gated
|
|
109
|
-
* because cloning grants access to a developer's full theme source.
|
|
110
103
|
*/
|
|
111
104
|
declare function cloneCommand(themeName: string, options: CloneOptions): Promise<void>;
|
|
112
105
|
|
package/dist/index.js
CHANGED
|
@@ -1586,21 +1586,43 @@ async function installDependencies(projectPath, packageManager = "npm") {
|
|
|
1586
1586
|
});
|
|
1587
1587
|
}
|
|
1588
1588
|
var AUTH_DIR = path8__default.default.join(os__default.default.homedir(), ".onexthm");
|
|
1589
|
-
var
|
|
1590
|
-
|
|
1591
|
-
|
|
1589
|
+
var ENV_URLS = {
|
|
1590
|
+
dev: "https://platform-dev.onexeos.com",
|
|
1591
|
+
prod: "https://platform-staging.onexeos.com"
|
|
1592
|
+
};
|
|
1593
|
+
function getAuthFile(env = "dev") {
|
|
1594
|
+
const newFile = path8__default.default.join(AUTH_DIR, `auth-${env}.json`);
|
|
1595
|
+
if (env === "dev") {
|
|
1596
|
+
const legacyFile = path8__default.default.join(AUTH_DIR, "auth.json");
|
|
1597
|
+
if (fs__default.default.existsSync(legacyFile) && !fs__default.default.existsSync(newFile)) {
|
|
1598
|
+
try {
|
|
1599
|
+
fs__default.default.moveSync(legacyFile, newFile);
|
|
1600
|
+
} catch {
|
|
1601
|
+
try {
|
|
1602
|
+
fs__default.default.copySync(legacyFile, newFile);
|
|
1603
|
+
fs__default.default.removeSync(legacyFile);
|
|
1604
|
+
} catch {
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
return newFile;
|
|
1592
1610
|
}
|
|
1593
|
-
|
|
1611
|
+
function getApiUrl(env = "dev") {
|
|
1612
|
+
return process.env.ONEXTHM_API_URL || ENV_URLS[env];
|
|
1613
|
+
}
|
|
1614
|
+
async function saveAuthTokens(tokens, env = "dev") {
|
|
1594
1615
|
await fs__default.default.ensureDir(AUTH_DIR);
|
|
1595
1616
|
const key = getMachineKey();
|
|
1596
1617
|
const data = JSON.stringify(tokens);
|
|
1597
1618
|
const encrypted = encrypt(data, key);
|
|
1598
|
-
await fs__default.default.writeFile(
|
|
1619
|
+
await fs__default.default.writeFile(getAuthFile(env), encrypted, "utf-8");
|
|
1599
1620
|
}
|
|
1600
|
-
function loadAuthTokens() {
|
|
1621
|
+
function loadAuthTokens(env = "dev") {
|
|
1601
1622
|
try {
|
|
1602
|
-
|
|
1603
|
-
|
|
1623
|
+
const file = getAuthFile(env);
|
|
1624
|
+
if (!fs__default.default.existsSync(file)) return null;
|
|
1625
|
+
const encrypted = fs__default.default.readFileSync(file, "utf-8");
|
|
1604
1626
|
const key = getMachineKey();
|
|
1605
1627
|
const data = decrypt(encrypted, key);
|
|
1606
1628
|
return JSON.parse(data);
|
|
@@ -1608,34 +1630,34 @@ function loadAuthTokens() {
|
|
|
1608
1630
|
return null;
|
|
1609
1631
|
}
|
|
1610
1632
|
}
|
|
1611
|
-
async function clearAuthTokens() {
|
|
1633
|
+
async function clearAuthTokens(env = "dev") {
|
|
1612
1634
|
try {
|
|
1613
|
-
await fs__default.default.remove(
|
|
1635
|
+
await fs__default.default.remove(getAuthFile(env));
|
|
1614
1636
|
} catch {
|
|
1615
1637
|
}
|
|
1616
1638
|
}
|
|
1617
1639
|
function isTokenExpired(tokens) {
|
|
1618
1640
|
return Date.now() / 1e3 > tokens.expiresAt - 300;
|
|
1619
1641
|
}
|
|
1620
|
-
async function getValidTokens() {
|
|
1621
|
-
const tokens = loadAuthTokens();
|
|
1642
|
+
async function getValidTokens(env = "dev") {
|
|
1643
|
+
const tokens = loadAuthTokens(env);
|
|
1622
1644
|
if (!tokens) return null;
|
|
1623
1645
|
if (!isTokenExpired(tokens)) return tokens;
|
|
1624
1646
|
try {
|
|
1625
|
-
const apiUrl = getApiUrl();
|
|
1647
|
+
const apiUrl = getApiUrl(env);
|
|
1626
1648
|
const response = await fetch(`${apiUrl}/auth/refresh`, {
|
|
1627
1649
|
method: "POST",
|
|
1628
1650
|
headers: { "Content-Type": "application/json" },
|
|
1629
1651
|
body: JSON.stringify({ refresh_token: tokens.refreshToken })
|
|
1630
1652
|
});
|
|
1631
1653
|
if (!response.ok) {
|
|
1632
|
-
await clearAuthTokens();
|
|
1654
|
+
await clearAuthTokens(env);
|
|
1633
1655
|
return null;
|
|
1634
1656
|
}
|
|
1635
1657
|
const data = await response.json();
|
|
1636
1658
|
const body = data.statusCode ? data.body : data;
|
|
1637
1659
|
if (!body.IdToken) {
|
|
1638
|
-
await clearAuthTokens();
|
|
1660
|
+
await clearAuthTokens(env);
|
|
1639
1661
|
return null;
|
|
1640
1662
|
}
|
|
1641
1663
|
const refreshed = {
|
|
@@ -1644,17 +1666,19 @@ async function getValidTokens() {
|
|
|
1644
1666
|
idToken: body.IdToken,
|
|
1645
1667
|
expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
|
|
1646
1668
|
};
|
|
1647
|
-
await saveAuthTokens(refreshed);
|
|
1669
|
+
await saveAuthTokens(refreshed, env);
|
|
1648
1670
|
return refreshed;
|
|
1649
1671
|
} catch {
|
|
1650
|
-
await clearAuthTokens();
|
|
1672
|
+
await clearAuthTokens(env);
|
|
1651
1673
|
return null;
|
|
1652
1674
|
}
|
|
1653
1675
|
}
|
|
1654
|
-
async function authenticatedFetch(url, init) {
|
|
1655
|
-
const tokens = await getValidTokens();
|
|
1676
|
+
async function authenticatedFetch(url, init, env = "dev") {
|
|
1677
|
+
const tokens = await getValidTokens(env);
|
|
1656
1678
|
if (!tokens) {
|
|
1657
|
-
throw new Error(
|
|
1679
|
+
throw new Error(
|
|
1680
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
1681
|
+
);
|
|
1658
1682
|
}
|
|
1659
1683
|
const headers = new Headers(init?.headers);
|
|
1660
1684
|
headers.set("Authorization", `Bearer ${tokens.idToken}`);
|
|
@@ -1729,7 +1753,7 @@ async function initCommand(projectName, options = {}) {
|
|
|
1729
1753
|
}
|
|
1730
1754
|
if (!options.yes) {
|
|
1731
1755
|
try {
|
|
1732
|
-
const apiUrl = getApiUrl();
|
|
1756
|
+
const apiUrl = getApiUrl(options.env ?? "dev");
|
|
1733
1757
|
const controller = new AbortController();
|
|
1734
1758
|
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
1735
1759
|
const response = await fetch(
|
|
@@ -3041,9 +3065,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3041
3065
|
console.log();
|
|
3042
3066
|
console.log(chalk4__default.default.white("2. Check API URL configuration:"));
|
|
3043
3067
|
console.log(chalk4__default.default.gray(` Current API URL: ${apiUrl}`));
|
|
3044
|
-
console.log(
|
|
3045
|
-
chalk4__default.default.gray(" Override with NEXT_PUBLIC_API_URL or ONEXTHM_API_URL")
|
|
3046
|
-
);
|
|
3068
|
+
console.log(chalk4__default.default.gray(" Override with ONEXTHM_API_URL env var if needed"));
|
|
3047
3069
|
console.log();
|
|
3048
3070
|
console.log(chalk4__default.default.white("3. Pin a specific version (CI/production):"));
|
|
3049
3071
|
console.log(
|
|
@@ -3053,15 +3075,17 @@ function showDownloadFailureHelp(themeId, apiUrl) {
|
|
|
3053
3075
|
}
|
|
3054
3076
|
async function downloadCommand(options) {
|
|
3055
3077
|
exports.logger.header("Download Theme");
|
|
3078
|
+
const env = options.env ?? "dev";
|
|
3079
|
+
const apiUrl = getApiUrl(env);
|
|
3080
|
+
exports.logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3056
3081
|
const spinner = ora__default.default("Initializing download...").start();
|
|
3057
|
-
if (options.bucket
|
|
3082
|
+
if (options.bucket) {
|
|
3058
3083
|
spinner.stop();
|
|
3059
3084
|
exports.logger.warning(
|
|
3060
|
-
"--bucket
|
|
3085
|
+
"--bucket is deprecated and ignored. Themes are now served via HTTP from the website-api Lambda."
|
|
3061
3086
|
);
|
|
3062
3087
|
spinner.start();
|
|
3063
3088
|
}
|
|
3064
|
-
const apiUrl = getApiUrl();
|
|
3065
3089
|
try {
|
|
3066
3090
|
const themeId = options.themeId || process.env.NEXT_PUBLIC_THEME_ID || process.env.THEME_ID;
|
|
3067
3091
|
const requestedVersion = options.version || process.env.THEME_VERSION || "latest";
|
|
@@ -3118,6 +3142,7 @@ async function downloadCommand(options) {
|
|
|
3118
3142
|
console.log(
|
|
3119
3143
|
chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(`${themeId}@${resolvedVersion}`)
|
|
3120
3144
|
);
|
|
3145
|
+
console.log(chalk4__default.default.cyan(" Env: ") + chalk4__default.default.white(env));
|
|
3121
3146
|
console.log(chalk4__default.default.cyan(" Source: ") + chalk4__default.default.white(apiUrl));
|
|
3122
3147
|
console.log(chalk4__default.default.cyan(" Output: ") + chalk4__default.default.white(outputDir));
|
|
3123
3148
|
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|
|
@@ -3160,11 +3185,9 @@ async function resolveLatestVersion2(apiUrl, themeId) {
|
|
|
3160
3185
|
}
|
|
3161
3186
|
return latest;
|
|
3162
3187
|
}
|
|
3163
|
-
async function fetchSourceZip(apiUrl, themeId, version) {
|
|
3188
|
+
async function fetchSourceZip(apiUrl, themeId, version, env) {
|
|
3164
3189
|
const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/source?version=${encodeURIComponent(version)}`;
|
|
3165
|
-
const response = await authenticatedFetch(url, {
|
|
3166
|
-
method: "GET"
|
|
3167
|
-
});
|
|
3190
|
+
const response = await authenticatedFetch(url, { method: "GET" }, env);
|
|
3168
3191
|
if (!response.ok) {
|
|
3169
3192
|
if (response.status === 404) {
|
|
3170
3193
|
throw new Error(
|
|
@@ -3173,7 +3196,7 @@ async function fetchSourceZip(apiUrl, themeId, version) {
|
|
|
3173
3196
|
}
|
|
3174
3197
|
if (response.status === 401 || response.status === 403) {
|
|
3175
3198
|
throw new Error(
|
|
3176
|
-
`Not authorized to download source for "${themeId}". Run \`onexthm login\` first.`
|
|
3199
|
+
`Not authorized to download source for "${themeId}". Run \`onexthm login --env ${env}\` first.`
|
|
3177
3200
|
);
|
|
3178
3201
|
}
|
|
3179
3202
|
throw new Error(
|
|
@@ -3292,14 +3315,19 @@ async function renameTheme(themeDir, oldName, newName) {
|
|
|
3292
3315
|
}
|
|
3293
3316
|
async function cloneCommand(themeName, options) {
|
|
3294
3317
|
exports.logger.header("Clone Theme Source");
|
|
3295
|
-
|
|
3318
|
+
const env = options.env ?? "dev";
|
|
3319
|
+
const apiUrl = getApiUrl(env);
|
|
3320
|
+
exports.logger.info(`Environment: ${env} (${apiUrl})`);
|
|
3321
|
+
if (options.bucket) {
|
|
3296
3322
|
exports.logger.warning(
|
|
3297
|
-
"--bucket
|
|
3323
|
+
"--bucket is deprecated and ignored. Source is now fetched via HTTP from the website-api Lambda."
|
|
3298
3324
|
);
|
|
3299
3325
|
}
|
|
3300
|
-
const tokens = await getValidTokens();
|
|
3326
|
+
const tokens = await getValidTokens(env);
|
|
3301
3327
|
if (!tokens) {
|
|
3302
|
-
exports.logger.error(
|
|
3328
|
+
exports.logger.error(
|
|
3329
|
+
`Not logged in to ${env} environment. Run: onexthm login --env ${env}`
|
|
3330
|
+
);
|
|
3303
3331
|
process.exit(1);
|
|
3304
3332
|
}
|
|
3305
3333
|
let newName = options.name;
|
|
@@ -3308,7 +3336,6 @@ async function cloneCommand(themeName, options) {
|
|
|
3308
3336
|
}
|
|
3309
3337
|
const spinner = ora__default.default("Initializing clone...").start();
|
|
3310
3338
|
try {
|
|
3311
|
-
const apiUrl = getApiUrl();
|
|
3312
3339
|
const outputDir = options.output || path8__default.default.resolve(process.cwd(), newName);
|
|
3313
3340
|
if (await fs__default.default.pathExists(outputDir)) {
|
|
3314
3341
|
spinner.fail(chalk4__default.default.red(`Directory already exists: ${outputDir}`));
|
|
@@ -3328,7 +3355,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3328
3355
|
spinner.start(`Downloading source.zip for ${themeName}@${version}...`);
|
|
3329
3356
|
let zipBuffer;
|
|
3330
3357
|
try {
|
|
3331
|
-
zipBuffer = await fetchSourceZip(apiUrl, themeName, version);
|
|
3358
|
+
zipBuffer = await fetchSourceZip(apiUrl, themeName, version, env);
|
|
3332
3359
|
} catch (error) {
|
|
3333
3360
|
spinner.fail(chalk4__default.default.red(error.message));
|
|
3334
3361
|
console.log();
|
|
@@ -3362,7 +3389,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3362
3389
|
[
|
|
3363
3390
|
"# API Configuration (enables real data in preview)",
|
|
3364
3391
|
"# Get your Company ID from the OneX dashboard",
|
|
3365
|
-
|
|
3392
|
+
`NEXT_PUBLIC_API_URL=${apiUrl}`,
|
|
3366
3393
|
"NEXT_PUBLIC_COMPANY_ID=",
|
|
3367
3394
|
""
|
|
3368
3395
|
].join("\n")
|
|
@@ -3415,6 +3442,7 @@ async function cloneCommand(themeName, options) {
|
|
|
3415
3442
|
console.log(
|
|
3416
3443
|
chalk4__default.default.cyan(" Source: ") + chalk4__default.default.gray(`${themeName}@${version}`)
|
|
3417
3444
|
);
|
|
3445
|
+
console.log(chalk4__default.default.cyan(" Env: ") + chalk4__default.default.white(env));
|
|
3418
3446
|
console.log(chalk4__default.default.cyan(" Theme: ") + chalk4__default.default.white(newName));
|
|
3419
3447
|
console.log(chalk4__default.default.cyan(" Location: ") + chalk4__default.default.white(outputDir));
|
|
3420
3448
|
console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
|