@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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @ollie-shop/cli@0.1.3 build /home/runner/work/ollie-shop/ollie-shop/packages/cli
2
+ > @ollie-shop/cli@0.2.0 build /home/runner/work/ollie-shop/ollie-shop/packages/cli
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -9,5 +9,5 @@
9
9
  CLI Target: esnext
10
10
  CLI Cleaning output folder
11
11
  CJS Build start
12
- CJS dist/index.js 7.27 KB
13
- CJS ⚡️ Build success in 409ms
12
+ CJS dist/index.js 16.06 KB
13
+ CJS ⚡️ Build success in 543ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ollie-shop/cli
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8f99b17: new CLI commands—docs, help, whoami, and validate—to the Ollie Shop CLI, along with supporting utility modules
8
+
3
9
  ## 0.1.3
4
10
 
5
11
  ### Patch Changes
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 path = require('path');
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 path__default = /*#__PURE__*/_interopDefault(path);
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 = path__default.default.join(os.homedir(), ".ollie-shop");
203
- const credentialsPath = path__default.default.join(configDir, "credentials.json");
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("ollie").description("Ollie Shop CLI tools").version("0.1.0");
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
- const program = createProgram();
229
- program.parse();
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.1.3",
4
- "description": "CLI tools for Ollie Shop",
3
+ "version": "0.2.0",
4
+ "description": "Command-line tools for developing with Ollie Shop",
5
5
  "bin": {
6
- "ollie-shop": "./dist/index.js"
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
+ }
@@ -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
- // Register individual commands
14
+ configureDocsCommand(program);
15
+ configureHelpCommand(program);
10
16
  configureLoginCommand(program);
11
-
12
- // Add more commands here as they are implemented
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
- * Create and configure the CLI program
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
- // Register all commands
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 run directly, execute the CLI
27
+ // If this file is executed directly, initialize the CLI
18
28
  if (require.main === module) {
19
- const program = createProgram();
20
- program.parse();
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
+ }