@ollie-shop/cli 0.1.3 → 0.2.0
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/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +6 -0
- package/dist/index.js +264 -7
- package/package.json +6 -3
- package/src/commands/docs.ts +24 -0
- package/src/commands/help.ts +28 -0
- package/src/commands/index.ts +10 -3
- package/src/commands/validate.ts +62 -0
- package/src/commands/version.ts +14 -0
- package/src/commands/whoami.ts +51 -0
- package/src/index.ts +27 -6
- package/src/utils/auth.ts +42 -0
- package/src/utils/core.ts +105 -0
- package/src/utils/store.ts +23 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @ollie-shop/cli@0.
|
|
2
|
+
> @ollie-shop/cli@0.2.0 build /home/runner/work/ollie-shop/ollie-shop/packages/cli
|
|
3
3
|
> tsup
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
[34mCLI[39m Target: esnext
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mCJS[39m Build start
|
|
12
|
-
[32mCJS[39m [1mdist/index.js [22m[
|
|
13
|
-
[32mCJS[39m ⚡️ Build success in
|
|
12
|
+
[32mCJS[39m [1mdist/index.js [22m[32m16.06 KB[39m
|
|
13
|
+
[32mCJS[39m ⚡️ Build success in 543ms
|
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -2,16 +2,25 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var commander = require('commander');
|
|
5
|
+
var chalk3 = require('chalk');
|
|
5
6
|
var crypto = require('crypto');
|
|
6
7
|
var fs = require('fs/promises');
|
|
7
8
|
var http = require('http');
|
|
8
9
|
var os = require('os');
|
|
9
|
-
var
|
|
10
|
+
var path2 = require('path');
|
|
11
|
+
var fs3 = require('fs');
|
|
12
|
+
var module$1 = require('module');
|
|
13
|
+
var latestVersion = require('latest-version');
|
|
14
|
+
var jwtDecode = require('jwt-decode');
|
|
10
15
|
|
|
16
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
11
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
18
|
|
|
19
|
+
var chalk3__default = /*#__PURE__*/_interopDefault(chalk3);
|
|
13
20
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
14
|
-
var
|
|
21
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
22
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
23
|
+
var latestVersion__default = /*#__PURE__*/_interopDefault(latestVersion);
|
|
15
24
|
|
|
16
25
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
17
26
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
@@ -19,6 +28,48 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
19
28
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
20
29
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
21
30
|
});
|
|
31
|
+
function configureDocsCommand(program) {
|
|
32
|
+
program.command("docs").description("Show documentation links for Ollie Shop").action(() => {
|
|
33
|
+
console.log(chalk3__default.default.cyanBright("\nOllie Shop Documentation\n"));
|
|
34
|
+
console.log(
|
|
35
|
+
`${chalk3__default.default.green("Main Docs:".padEnd(20))} https://docs.ollie.shop/ollie-shop`
|
|
36
|
+
);
|
|
37
|
+
console.log(
|
|
38
|
+
`${chalk3__default.default.green("Components:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/component`
|
|
39
|
+
);
|
|
40
|
+
console.log(
|
|
41
|
+
`${chalk3__default.default.green("Functions:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/function`
|
|
42
|
+
);
|
|
43
|
+
console.log(
|
|
44
|
+
`${chalk3__default.default.green("Versions:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/version
|
|
45
|
+
`
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function configureHelpCommand(program) {
|
|
50
|
+
program.command("help [command]").description("Display help for a specific command or list all commands").action((cmdName) => {
|
|
51
|
+
if (cmdName) {
|
|
52
|
+
const cmd = program.commands.find((c) => c.name() === cmdName);
|
|
53
|
+
if (cmd) {
|
|
54
|
+
cmd.help();
|
|
55
|
+
} else {
|
|
56
|
+
console.log(chalk3__default.default.red(`Command '${cmdName}' not found.`));
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
console.log(chalk3__default.default.cyanBright("\nAvailable commands:\n"));
|
|
60
|
+
for (const cmd of program.commands) {
|
|
61
|
+
console.log(
|
|
62
|
+
` ${chalk3__default.default.green(cmd.name().padEnd(20))} ${cmd.description()}`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
console.log(
|
|
66
|
+
`
|
|
67
|
+
Use ${chalk3__default.default.yellow("ollieshop help <command>")} to get more info on a command.
|
|
68
|
+
`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
22
73
|
var DEFAULT_CALLBACK_PORT = 7777;
|
|
23
74
|
var AUTH_ENDPOINT = "https://admin.ollie.shop/auth/login";
|
|
24
75
|
function configureLoginCommand(program) {
|
|
@@ -199,8 +250,8 @@ async function startWebAuthFlow(options) {
|
|
|
199
250
|
}
|
|
200
251
|
async function saveCredentials(token) {
|
|
201
252
|
console.log("Saving credentials...");
|
|
202
|
-
const configDir =
|
|
203
|
-
const credentialsPath =
|
|
253
|
+
const configDir = path2__default.default.join(os.homedir(), ".ollie-shop");
|
|
254
|
+
const credentialsPath = path2__default.default.join(configDir, "credentials.json");
|
|
204
255
|
try {
|
|
205
256
|
await fs__default.default.mkdir(configDir, { recursive: true });
|
|
206
257
|
} catch (error) {
|
|
@@ -211,22 +262,228 @@ async function saveCredentials(token) {
|
|
|
211
262
|
await fs__default.default.writeFile(credentialsPath, JSON.stringify(token, null, 2));
|
|
212
263
|
return true;
|
|
213
264
|
}
|
|
265
|
+
function configureValidateCommand(program) {
|
|
266
|
+
program.command("validate [componentPath]").description("Validate the structure of your custom component").action(async (componentPath) => {
|
|
267
|
+
if (!componentPath) {
|
|
268
|
+
console.error(
|
|
269
|
+
`${chalk3__default.default.red("\u274C Missing required argument:")} component path
|
|
270
|
+
|
|
271
|
+
Example usage:
|
|
272
|
+
${chalk3__default.default.cyan("ollieshop validate")} ./path/to/your/component
|
|
273
|
+
`
|
|
274
|
+
);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
const resolvedPath = path2__default.default.resolve(componentPath);
|
|
278
|
+
const requiredFiles = ["index.tsx", "package.json", "meta.json"];
|
|
279
|
+
const optionalFile = "styles.module.css";
|
|
280
|
+
let isValid = true;
|
|
281
|
+
for (const file of requiredFiles) {
|
|
282
|
+
try {
|
|
283
|
+
await fs__default.default.access(path2__default.default.join(resolvedPath, file));
|
|
284
|
+
console.log(`${chalk3__default.default.green("\u2714")} Found: ${chalk3__default.default.cyan(file)}`);
|
|
285
|
+
} catch {
|
|
286
|
+
console.log(`${chalk3__default.default.red("\u2716")} Missing: ${chalk3__default.default.cyan(file)}`);
|
|
287
|
+
isValid = false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
await fs__default.default.access(path2__default.default.join(resolvedPath, optionalFile));
|
|
292
|
+
console.log(
|
|
293
|
+
`${chalk3__default.default.yellow("\u2139")} Optional file found: ${chalk3__default.default.cyan(optionalFile)}`
|
|
294
|
+
);
|
|
295
|
+
} catch {
|
|
296
|
+
console.log(
|
|
297
|
+
`${chalk3__default.default.dim("\u2139")} Optional file not found: ${chalk3__default.default.cyan(optionalFile)}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (isValid) {
|
|
301
|
+
console.log(`
|
|
302
|
+
${chalk3__default.default.green("\u2714")} Component structure looks valid!`);
|
|
303
|
+
} else {
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
309
|
+
var pkg = require2("../package.json");
|
|
310
|
+
async function checkForUpdates() {
|
|
311
|
+
try {
|
|
312
|
+
const latest = await latestVersion__default.default(pkg.name);
|
|
313
|
+
if (latest !== pkg.version) {
|
|
314
|
+
console.log(
|
|
315
|
+
chalk3__default.default.yellow(
|
|
316
|
+
`
|
|
317
|
+
\u26A0\uFE0F A new version ${chalk3__default.default.bold(latest)} is available!
|
|
318
|
+
Update now: ${chalk3__default.default.bold(
|
|
319
|
+
"npm install -g @ollie-shop/cli"
|
|
320
|
+
)}
|
|
321
|
+
`
|
|
322
|
+
)
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function showWelcomeMessage() {
|
|
329
|
+
console.log(
|
|
330
|
+
chalk3__default.default.cyanBright.bold(
|
|
331
|
+
`
|
|
332
|
+
\u2728 Welcome to the Ollie Shop CLI - ${pkg.version} \u2728
|
|
333
|
+
`
|
|
334
|
+
)
|
|
335
|
+
);
|
|
336
|
+
console.log("Build, customize and deploy your e-commerce with ease.\n");
|
|
337
|
+
console.log("Usage:");
|
|
338
|
+
console.log(" ollieshop <command> [options]\n");
|
|
339
|
+
console.log("Available commands:");
|
|
340
|
+
const stableCommands = [
|
|
341
|
+
{ cmd: "login", desc: "Log in to your Ollie Shop account" },
|
|
342
|
+
{ cmd: "validate", desc: "Validate your component files" },
|
|
343
|
+
{ cmd: "whoami", desc: "Show logged-in user and current store" }
|
|
344
|
+
];
|
|
345
|
+
for (const { cmd, desc } of stableCommands) {
|
|
346
|
+
console.log(` ${chalk3__default.default.green(cmd.padEnd(20))} ${desc}`);
|
|
347
|
+
}
|
|
348
|
+
console.log("\nComing soon:");
|
|
349
|
+
const comingSoonCommands = [
|
|
350
|
+
{ cmd: "build", desc: "Compile components for deployment" },
|
|
351
|
+
{ cmd: "deploy", desc: "Deploy a component or function" },
|
|
352
|
+
{ cmd: "dev", desc: "Start local preview server" },
|
|
353
|
+
{ cmd: "status", desc: "Show store status" }
|
|
354
|
+
];
|
|
355
|
+
for (const { cmd, desc } of comingSoonCommands) {
|
|
356
|
+
console.log(` ${chalk3__default.default.yellow(cmd.padEnd(20))} ${desc}`);
|
|
357
|
+
}
|
|
358
|
+
console.log(
|
|
359
|
+
`
|
|
360
|
+
For a full list of commands, run: ${chalk3__default.default.yellow.bold("ollieshop help")}
|
|
361
|
+
`
|
|
362
|
+
);
|
|
363
|
+
console.log(
|
|
364
|
+
"Documentation:",
|
|
365
|
+
chalk3__default.default.underline.blue("https://docs.ollie.shop/ollie-shop")
|
|
366
|
+
);
|
|
367
|
+
console.log();
|
|
368
|
+
}
|
|
369
|
+
function validateProjectLocation() {
|
|
370
|
+
const command = process.argv[2] ?? "";
|
|
371
|
+
const allowedOutside = ["help", "docs", "version"];
|
|
372
|
+
if (allowedOutside.includes(command)) return;
|
|
373
|
+
const configPath = path2__default.default.join(process.cwd(), "ollie.json");
|
|
374
|
+
const isValidProject = fs3__default.default.existsSync(configPath);
|
|
375
|
+
if (!isValidProject) {
|
|
376
|
+
console.log(`
|
|
377
|
+
${chalk3__default.default.red("\u274C")} This command must be run inside an ${chalk3__default.default.bold("Ollie Shop project")}.
|
|
378
|
+
Please navigate to your project directory and try again.
|
|
379
|
+
`);
|
|
380
|
+
process.exit(1);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/commands/version.ts
|
|
385
|
+
function configureVersionCommand(program) {
|
|
386
|
+
program.command("version").description("Display the current CLI version").action(() => {
|
|
387
|
+
console.log(
|
|
388
|
+
`${chalk3__default.default.bold("Ollie Shop CLI version:")} ${chalk3__default.default.cyan(pkg.version)}
|
|
389
|
+
`
|
|
390
|
+
);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
var CREDENTIALS_PATH = path2__default.default.join(
|
|
394
|
+
os.homedir(),
|
|
395
|
+
".ollie-shop",
|
|
396
|
+
"credentials.json"
|
|
397
|
+
);
|
|
398
|
+
async function getCurrentUser() {
|
|
399
|
+
try {
|
|
400
|
+
const raw = await fs__default.default.readFile(CREDENTIALS_PATH, "utf-8");
|
|
401
|
+
const token = JSON.parse(raw);
|
|
402
|
+
if (!token.accessToken) return null;
|
|
403
|
+
const decoded = jwtDecode.jwtDecode(token.accessToken);
|
|
404
|
+
return {
|
|
405
|
+
email: decoded.email
|
|
406
|
+
};
|
|
407
|
+
} catch {
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
async function getOllieConfig() {
|
|
412
|
+
try {
|
|
413
|
+
const configPath = path2__default.default.join(process.cwd(), "ollie.json");
|
|
414
|
+
const raw = await fs__default.default.readFile(configPath, "utf-8");
|
|
415
|
+
const data = JSON.parse(raw);
|
|
416
|
+
return data;
|
|
417
|
+
} catch {
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/commands/whoami.ts
|
|
423
|
+
async function getUserInfo() {
|
|
424
|
+
try {
|
|
425
|
+
const user = await getCurrentUser();
|
|
426
|
+
const store = await getOllieConfig();
|
|
427
|
+
if (!user || !user.email) {
|
|
428
|
+
console.log("\u274C No user authenticated");
|
|
429
|
+
return {};
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
email: user.email,
|
|
433
|
+
store: store ?? void 0
|
|
434
|
+
};
|
|
435
|
+
} catch {
|
|
436
|
+
return {};
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function configureWhoamiCommand(program) {
|
|
440
|
+
program.command("whoami").description("Show logged-in user and current store").action(async () => {
|
|
441
|
+
const { email, store } = await getUserInfo();
|
|
442
|
+
if (!email) {
|
|
443
|
+
console.log(chalk3__default.default.red("You are not authenticated"));
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
console.log();
|
|
447
|
+
console.log(
|
|
448
|
+
`${chalk3__default.default.bold("You are logged in as:")} ${chalk3__default.default.cyan(email)}`
|
|
449
|
+
);
|
|
450
|
+
if (store) {
|
|
451
|
+
console.log(
|
|
452
|
+
`${chalk3__default.default.bold("Current store:")} ${chalk3__default.default.cyan(store.platformStoreId ?? "unknown")}`
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
console.log();
|
|
456
|
+
});
|
|
457
|
+
}
|
|
214
458
|
|
|
215
459
|
// src/commands/index.ts
|
|
216
460
|
function registerCommands(program) {
|
|
461
|
+
configureDocsCommand(program);
|
|
462
|
+
configureHelpCommand(program);
|
|
217
463
|
configureLoginCommand(program);
|
|
464
|
+
configureWhoamiCommand(program);
|
|
465
|
+
configureValidateCommand(program);
|
|
466
|
+
configureVersionCommand(program);
|
|
218
467
|
}
|
|
219
468
|
|
|
220
469
|
// src/index.ts
|
|
221
470
|
function createProgram() {
|
|
222
471
|
const program = new commander.Command();
|
|
223
|
-
program.name("
|
|
472
|
+
program.name("ollieshop").description("Ollie Shop CLI tools").version(pkg.version);
|
|
224
473
|
registerCommands(program);
|
|
225
474
|
return program;
|
|
226
475
|
}
|
|
227
476
|
if (__require.main === module) {
|
|
228
|
-
|
|
229
|
-
|
|
477
|
+
(async () => {
|
|
478
|
+
const program = createProgram();
|
|
479
|
+
if (process.argv.length <= 2) {
|
|
480
|
+
await checkForUpdates();
|
|
481
|
+
showWelcomeMessage();
|
|
482
|
+
process.exit(0);
|
|
483
|
+
}
|
|
484
|
+
validateProjectLocation();
|
|
485
|
+
program.parse();
|
|
486
|
+
})();
|
|
230
487
|
}
|
|
231
488
|
|
|
232
489
|
exports.createProgram = createProgram;
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ollie-shop/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Command-line tools for developing with Ollie Shop",
|
|
5
5
|
"bin": {
|
|
6
|
-
"
|
|
6
|
+
"ollieshop": "./dist/index.js"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
+
"chalk": "^5.4.1",
|
|
9
10
|
"commander": "^11.1.0",
|
|
11
|
+
"jwt-decode": "^4.0.0",
|
|
12
|
+
"latest-version": "^9.0.0",
|
|
10
13
|
"open": "^10.1.2"
|
|
11
14
|
},
|
|
12
15
|
"devDependencies": {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
|
|
4
|
+
export function configureDocsCommand(program: Command): void {
|
|
5
|
+
program
|
|
6
|
+
.command("docs")
|
|
7
|
+
.description("Show documentation links for Ollie Shop")
|
|
8
|
+
.action(() => {
|
|
9
|
+
console.log(chalk.cyanBright("\nOllie Shop Documentation\n"));
|
|
10
|
+
|
|
11
|
+
console.log(
|
|
12
|
+
`${chalk.green("Main Docs:".padEnd(20))} https://docs.ollie.shop/ollie-shop`,
|
|
13
|
+
);
|
|
14
|
+
console.log(
|
|
15
|
+
`${chalk.green("Components:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/component`,
|
|
16
|
+
);
|
|
17
|
+
console.log(
|
|
18
|
+
`${chalk.green("Functions:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/function`,
|
|
19
|
+
);
|
|
20
|
+
console.log(
|
|
21
|
+
`${chalk.green("Versions:".padEnd(20))} https://docs.ollie.shop/ollie-shop/concepts/version\n`,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
|
|
4
|
+
export function configureHelpCommand(program: Command): void {
|
|
5
|
+
program
|
|
6
|
+
.command("help [command]")
|
|
7
|
+
.description("Display help for a specific command or list all commands")
|
|
8
|
+
.action((cmdName) => {
|
|
9
|
+
if (cmdName) {
|
|
10
|
+
const cmd = program.commands.find((c) => c.name() === cmdName);
|
|
11
|
+
if (cmd) {
|
|
12
|
+
cmd.help();
|
|
13
|
+
} else {
|
|
14
|
+
console.log(chalk.red(`Command '${cmdName}' not found.`));
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
console.log(chalk.cyanBright("\nAvailable commands:\n"));
|
|
18
|
+
for (const cmd of program.commands) {
|
|
19
|
+
console.log(
|
|
20
|
+
` ${chalk.green(cmd.name().padEnd(20))} ${cmd.description()}`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
console.log(
|
|
24
|
+
`\nUse ${chalk.yellow("ollieshop help <command>")} to get more info on a command.\n`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
package/src/commands/index.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
+
import { configureDocsCommand } from "./docs";
|
|
3
|
+
import { configureHelpCommand } from "./help";
|
|
2
4
|
import { configureLoginCommand } from "./login";
|
|
5
|
+
import { configureValidateCommand } from "./validate";
|
|
6
|
+
import { configureVersionCommand } from "./version";
|
|
7
|
+
import { configureWhoamiCommand } from "./whoami";
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* Register all CLI commands with the program
|
|
6
11
|
* @param program The commander program instance
|
|
7
12
|
*/
|
|
8
13
|
export function registerCommands(program: Command): void {
|
|
9
|
-
|
|
14
|
+
configureDocsCommand(program);
|
|
15
|
+
configureHelpCommand(program);
|
|
10
16
|
configureLoginCommand(program);
|
|
11
|
-
|
|
12
|
-
|
|
17
|
+
configureWhoamiCommand(program);
|
|
18
|
+
configureValidateCommand(program);
|
|
19
|
+
configureVersionCommand(program);
|
|
13
20
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import type { Command } from "commander";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register the `validate` command
|
|
8
|
+
*/
|
|
9
|
+
export function configureValidateCommand(program: Command): void {
|
|
10
|
+
program
|
|
11
|
+
// Make componentPath optional here to suppress Commander error
|
|
12
|
+
.command("validate [componentPath]")
|
|
13
|
+
.description("Validate the structure of your custom component")
|
|
14
|
+
.action(async (componentPath: string | undefined) => {
|
|
15
|
+
if (!componentPath) {
|
|
16
|
+
console.error(
|
|
17
|
+
`${chalk.red("❌ Missing required argument:")} component path\n\n` +
|
|
18
|
+
`Example usage:\n ${chalk.cyan("ollieshop validate")} ./path/to/your/component\n`,
|
|
19
|
+
);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const resolvedPath = path.resolve(componentPath);
|
|
24
|
+
const requiredFiles = ["index.tsx", "package.json", "meta.json"];
|
|
25
|
+
const optionalFile = "styles.module.css";
|
|
26
|
+
|
|
27
|
+
let isValid = true;
|
|
28
|
+
|
|
29
|
+
// Track missing required files
|
|
30
|
+
const missingFiles: string[] = [];
|
|
31
|
+
|
|
32
|
+
// Check required files
|
|
33
|
+
for (const file of requiredFiles) {
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(path.join(resolvedPath, file));
|
|
36
|
+
console.log(`${chalk.green("✔")} Found: ${chalk.cyan(file)}`);
|
|
37
|
+
} catch {
|
|
38
|
+
console.log(`${chalk.red("✖")} Missing: ${chalk.cyan(file)}`);
|
|
39
|
+
missingFiles.push(file);
|
|
40
|
+
isValid = false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check optional file presence
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(path.join(resolvedPath, optionalFile));
|
|
47
|
+
console.log(
|
|
48
|
+
`${chalk.yellow("ℹ")} Optional file found: ${chalk.cyan(optionalFile)}`,
|
|
49
|
+
);
|
|
50
|
+
} catch {
|
|
51
|
+
console.log(
|
|
52
|
+
`${chalk.dim("ℹ")} Optional file not found: ${chalk.cyan(optionalFile)}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isValid) {
|
|
57
|
+
console.log(`\n${chalk.green("✔")} Component structure looks valid!`);
|
|
58
|
+
} else {
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import { pkg } from "../utils/core";
|
|
4
|
+
|
|
5
|
+
export function configureVersionCommand(program: Command): void {
|
|
6
|
+
program
|
|
7
|
+
.command("version")
|
|
8
|
+
.description("Display the current CLI version")
|
|
9
|
+
.action(() => {
|
|
10
|
+
console.log(
|
|
11
|
+
`${chalk.bold("Ollie Shop CLI version:")} ${chalk.cyan(pkg.version)}\n`,
|
|
12
|
+
);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import { getCurrentUser } from "../utils/auth";
|
|
4
|
+
import { type OllieConfig, getOllieConfig } from "../utils/store";
|
|
5
|
+
|
|
6
|
+
// Reads credentials from ~/.ollie-shop/credentials.json
|
|
7
|
+
async function getUserInfo(): Promise<{ email?: string; store?: OllieConfig }> {
|
|
8
|
+
try {
|
|
9
|
+
const user = await getCurrentUser();
|
|
10
|
+
const store = await getOllieConfig();
|
|
11
|
+
|
|
12
|
+
if (!user || !user.email) {
|
|
13
|
+
console.log("❌ No user authenticated");
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
email: user.email,
|
|
19
|
+
store: store ?? undefined,
|
|
20
|
+
};
|
|
21
|
+
} catch {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function configureWhoamiCommand(program: Command) {
|
|
27
|
+
program
|
|
28
|
+
.command("whoami")
|
|
29
|
+
.description("Show logged-in user and current store")
|
|
30
|
+
.action(async () => {
|
|
31
|
+
const { email, store } = await getUserInfo();
|
|
32
|
+
|
|
33
|
+
if (!email) {
|
|
34
|
+
console.log(chalk.red("You are not authenticated"));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log();
|
|
39
|
+
console.log(
|
|
40
|
+
`${chalk.bold("You are logged in as:")} ${chalk.cyan(email)}`,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (store) {
|
|
44
|
+
console.log(
|
|
45
|
+
`${chalk.bold("Current store:")} ${chalk.cyan(store.platformStoreId ?? "unknown")}`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log();
|
|
50
|
+
});
|
|
51
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { registerCommands } from "./commands";
|
|
3
|
+
import {
|
|
4
|
+
checkForUpdates,
|
|
5
|
+
pkg,
|
|
6
|
+
showWelcomeMessage,
|
|
7
|
+
validateProjectLocation,
|
|
8
|
+
} from "./utils/core";
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
|
-
*
|
|
11
|
+
* Creates and configures the CLI program instance
|
|
6
12
|
*/
|
|
7
13
|
export function createProgram() {
|
|
8
14
|
const program = new Command();
|
|
9
|
-
program.name("ollie").description("Ollie Shop CLI tools").version("0.1.0");
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
program
|
|
17
|
+
.name("ollieshop")
|
|
18
|
+
.description("Ollie Shop CLI tools")
|
|
19
|
+
.version(pkg.version);
|
|
20
|
+
|
|
21
|
+
// Register CLI commands from external modules
|
|
12
22
|
registerCommands(program);
|
|
13
23
|
|
|
14
24
|
return program;
|
|
15
25
|
}
|
|
16
26
|
|
|
17
|
-
// If this file is
|
|
27
|
+
// If this file is executed directly, initialize the CLI
|
|
18
28
|
if (require.main === module) {
|
|
19
|
-
|
|
20
|
-
|
|
29
|
+
(async () => {
|
|
30
|
+
const program = createProgram();
|
|
31
|
+
|
|
32
|
+
if (process.argv.length <= 2) {
|
|
33
|
+
await checkForUpdates();
|
|
34
|
+
showWelcomeMessage();
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
validateProjectLocation();
|
|
39
|
+
|
|
40
|
+
program.parse();
|
|
41
|
+
})();
|
|
21
42
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// lib/auth.ts
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { jwtDecode } from "jwt-decode";
|
|
6
|
+
|
|
7
|
+
const CREDENTIALS_PATH = path.join(
|
|
8
|
+
homedir(),
|
|
9
|
+
".ollie-shop",
|
|
10
|
+
"credentials.json",
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
type Token = {
|
|
14
|
+
accessToken: string;
|
|
15
|
+
refreshToken?: string;
|
|
16
|
+
expiresAt?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type DecodedToken = {
|
|
20
|
+
email?: string;
|
|
21
|
+
exp?: number;
|
|
22
|
+
sub?: string;
|
|
23
|
+
iat?: number;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export async function getCurrentUser(): Promise<{ email?: string } | null> {
|
|
28
|
+
try {
|
|
29
|
+
const raw = await fs.readFile(CREDENTIALS_PATH, "utf-8");
|
|
30
|
+
const token: Token = JSON.parse(raw);
|
|
31
|
+
|
|
32
|
+
if (!token.accessToken) return null;
|
|
33
|
+
|
|
34
|
+
const decoded = jwtDecode<DecodedToken>(token.accessToken);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
email: decoded.email,
|
|
38
|
+
};
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import latestVersion from "latest-version";
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
export const pkg = require("../package.json");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Checks if there is a newer version of the CLI available
|
|
12
|
+
* and notifies the user to update if so.
|
|
13
|
+
*/
|
|
14
|
+
export async function checkForUpdates() {
|
|
15
|
+
try {
|
|
16
|
+
const latest = await latestVersion(pkg.name);
|
|
17
|
+
if (latest !== pkg.version) {
|
|
18
|
+
console.log(
|
|
19
|
+
chalk.yellow(
|
|
20
|
+
`\n⚠️ A new version ${chalk.bold(latest)} is available!\n Update now: ${chalk.bold(
|
|
21
|
+
"npm install -g @ollie-shop/cli",
|
|
22
|
+
)}\n`,
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// Silently ignore errors if offline or failed
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Displays a custom welcome message when no arguments are passed
|
|
33
|
+
*/
|
|
34
|
+
export function showWelcomeMessage() {
|
|
35
|
+
console.log(
|
|
36
|
+
chalk.cyanBright.bold(
|
|
37
|
+
`\n✨ Welcome to the Ollie Shop CLI - ${pkg.version} ✨\n`,
|
|
38
|
+
),
|
|
39
|
+
);
|
|
40
|
+
console.log("Build, customize and deploy your e-commerce with ease.\n");
|
|
41
|
+
|
|
42
|
+
console.log("Usage:");
|
|
43
|
+
console.log(" ollieshop <command> [options]\n");
|
|
44
|
+
|
|
45
|
+
console.log("Available commands:");
|
|
46
|
+
|
|
47
|
+
// Stable commands
|
|
48
|
+
const stableCommands = [
|
|
49
|
+
{ cmd: "login", desc: "Log in to your Ollie Shop account" },
|
|
50
|
+
{ cmd: "validate", desc: "Validate your component files" },
|
|
51
|
+
{ cmd: "whoami", desc: "Show logged-in user and current store" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const { cmd, desc } of stableCommands) {
|
|
55
|
+
console.log(` ${chalk.green(cmd.padEnd(20))} ${desc}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log("\nComing soon:");
|
|
59
|
+
|
|
60
|
+
// Coming soon
|
|
61
|
+
const comingSoonCommands = [
|
|
62
|
+
{ cmd: "build", desc: "Compile components for deployment" },
|
|
63
|
+
{ cmd: "deploy", desc: "Deploy a component or function" },
|
|
64
|
+
{ cmd: "dev", desc: "Start local preview server" },
|
|
65
|
+
{ cmd: "status", desc: "Show store status" },
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const { cmd, desc } of comingSoonCommands) {
|
|
69
|
+
console.log(` ${chalk.yellow(cmd.padEnd(20))} ${desc}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
`\nFor a full list of commands, run: ${chalk.yellow.bold("ollieshop help")}\n`,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
console.log(
|
|
77
|
+
"Documentation:",
|
|
78
|
+
chalk.underline.blue("https://docs.ollie.shop/ollie-shop"),
|
|
79
|
+
);
|
|
80
|
+
console.log();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Ensures the current working directory is a valid Ollie Shop project.
|
|
85
|
+
* If not, it shows an error and exits the process.
|
|
86
|
+
*/
|
|
87
|
+
export function validateProjectLocation() {
|
|
88
|
+
const command = process.argv[2] ?? "";
|
|
89
|
+
|
|
90
|
+
// Commands allowed outside a valid Ollie Shop project
|
|
91
|
+
const allowedOutside = ["help", "docs", "version"];
|
|
92
|
+
|
|
93
|
+
if (allowedOutside.includes(command)) return;
|
|
94
|
+
|
|
95
|
+
const configPath = path.join(process.cwd(), "ollie.json");
|
|
96
|
+
const isValidProject = fs.existsSync(configPath);
|
|
97
|
+
|
|
98
|
+
if (!isValidProject) {
|
|
99
|
+
console.log(`
|
|
100
|
+
${chalk.red("❌")} This command must be run inside an ${chalk.bold("Ollie Shop project")}.
|
|
101
|
+
Please navigate to your project directory and try again.\n`);
|
|
102
|
+
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export type OllieConfig = {
|
|
5
|
+
storeId: string;
|
|
6
|
+
versionId: string;
|
|
7
|
+
platform: string;
|
|
8
|
+
platformStoreId: string;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
props: unknown;
|
|
11
|
+
theme: Record<string, unknown>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export async function getOllieConfig(): Promise<OllieConfig | null> {
|
|
15
|
+
try {
|
|
16
|
+
const configPath = path.join(process.cwd(), "ollie.json");
|
|
17
|
+
const raw = await fs.readFile(configPath, "utf-8");
|
|
18
|
+
const data: OllieConfig = JSON.parse(raw);
|
|
19
|
+
return data;
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|