@ollie-shop/cli 0.3.3 → 1.0.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.
Files changed (79) hide show
  1. package/.turbo/turbo-build.log +6 -9
  2. package/CHANGELOG.md +27 -0
  3. package/dist/index.js +1003 -40565
  4. package/package.json +15 -37
  5. package/src/README.md +126 -0
  6. package/src/cli.tsx +45 -0
  7. package/src/commands/help.tsx +79 -0
  8. package/src/commands/login.tsx +92 -0
  9. package/src/commands/start.tsx +411 -0
  10. package/src/index.tsx +8 -0
  11. package/src/utils/auth.ts +218 -21
  12. package/src/utils/bundle.ts +177 -0
  13. package/src/utils/config.ts +123 -0
  14. package/src/utils/esbuild.ts +533 -0
  15. package/tsconfig.json +10 -15
  16. package/tsup.config.ts +8 -10
  17. package/CLAUDE_CLI.md +0 -265
  18. package/README.md +0 -711
  19. package/__tests__/mocks/console.ts +0 -22
  20. package/__tests__/mocks/core.ts +0 -137
  21. package/__tests__/mocks/index.ts +0 -4
  22. package/__tests__/mocks/inquirer.ts +0 -16
  23. package/__tests__/mocks/progress.ts +0 -19
  24. package/dist/index.d.ts +0 -1
  25. package/src/__tests__/helpers/cli-test-helper.ts +0 -281
  26. package/src/__tests__/mocks/index.ts +0 -142
  27. package/src/actions/component.actions.ts +0 -278
  28. package/src/actions/function.actions.ts +0 -220
  29. package/src/actions/project.actions.ts +0 -131
  30. package/src/actions/version.actions.ts +0 -233
  31. package/src/commands/__tests__/component-validation.test.ts +0 -250
  32. package/src/commands/__tests__/component.test.ts +0 -318
  33. package/src/commands/__tests__/function-validation.test.ts +0 -220
  34. package/src/commands/__tests__/function.test.ts +0 -286
  35. package/src/commands/__tests__/store-version-validation.test.ts +0 -414
  36. package/src/commands/__tests__/store-version.test.ts +0 -402
  37. package/src/commands/component.ts +0 -178
  38. package/src/commands/docs.ts +0 -24
  39. package/src/commands/function.ts +0 -201
  40. package/src/commands/help.ts +0 -18
  41. package/src/commands/index.ts +0 -27
  42. package/src/commands/login.ts +0 -267
  43. package/src/commands/project.ts +0 -107
  44. package/src/commands/store-version.ts +0 -242
  45. package/src/commands/version.ts +0 -51
  46. package/src/commands/whoami.ts +0 -46
  47. package/src/index.ts +0 -116
  48. package/src/prompts/component.prompts.ts +0 -94
  49. package/src/prompts/function.prompts.ts +0 -168
  50. package/src/schemas/command.schema.ts +0 -644
  51. package/src/types/index.ts +0 -183
  52. package/src/utils/__tests__/command-parser.test.ts +0 -159
  53. package/src/utils/__tests__/command-suggestions.test.ts +0 -185
  54. package/src/utils/__tests__/console.test.ts +0 -192
  55. package/src/utils/__tests__/context-detector.test.ts +0 -258
  56. package/src/utils/__tests__/enhanced-error-handler.test.ts +0 -137
  57. package/src/utils/__tests__/error-handler.test.ts +0 -107
  58. package/src/utils/__tests__/rich-progress.test.ts +0 -181
  59. package/src/utils/__tests__/validation-error-formatter.test.ts +0 -175
  60. package/src/utils/__tests__/validation-helpers.test.ts +0 -125
  61. package/src/utils/cli-progress-reporter.ts +0 -84
  62. package/src/utils/command-builder.ts +0 -390
  63. package/src/utils/command-helpers.ts +0 -83
  64. package/src/utils/command-parser.ts +0 -245
  65. package/src/utils/command-suggestions.ts +0 -176
  66. package/src/utils/console.ts +0 -320
  67. package/src/utils/constants.ts +0 -39
  68. package/src/utils/context-detector.ts +0 -177
  69. package/src/utils/deploy-helpers.ts +0 -357
  70. package/src/utils/enhanced-error-handler.ts +0 -264
  71. package/src/utils/error-handler.ts +0 -60
  72. package/src/utils/errors.ts +0 -256
  73. package/src/utils/interactive-builder.ts +0 -325
  74. package/src/utils/rich-progress.ts +0 -331
  75. package/src/utils/store.ts +0 -23
  76. package/src/utils/validation-error-formatter.ts +0 -337
  77. package/src/utils/validation-helpers.ts +0 -325
  78. package/vitest.config.ts +0 -35
  79. package/vitest.setup.ts +0 -29
@@ -1,233 +0,0 @@
1
- import * as core from "@ollie-shop/core";
2
- import type { VersionListItem } from "../schemas/command.schema";
3
- import { console as cliConsole } from "../utils/console";
4
- import { handleError } from "../utils/error-handler";
5
-
6
- interface CreateOptions {
7
- store: string;
8
- name: string;
9
- template?: string;
10
- active?: boolean;
11
- }
12
-
13
- interface ListOptions {
14
- store: string;
15
- }
16
-
17
- export async function create(options: CreateOptions): Promise<void> {
18
- const spinner = cliConsole.spinner("Creating version...");
19
-
20
- try {
21
- const version = await core.createVersion({
22
- storeId: options.store,
23
- name: options.name,
24
- template: options.template || "default",
25
- active: options.active ?? true,
26
- });
27
-
28
- spinner.succeed(`Version "${version.name}" created successfully`);
29
-
30
- cliConsole.info("\nVersion details:");
31
- cliConsole.table([
32
- {
33
- ID: version.id,
34
- Name: version.name,
35
- Template: version.template || "default",
36
- Active: version.active ? "✓" : "✗",
37
- Default: version.default ? "✓" : "✗",
38
- },
39
- ]);
40
-
41
- if (!version.active) {
42
- cliConsole.dim("\nNote: This version is inactive. Activate it with:");
43
- cliConsole.dim(` ollieshop version activate ${version.id}`);
44
- }
45
- } catch (error) {
46
- spinner.fail("Failed to create version");
47
- handleError(error);
48
- }
49
- }
50
-
51
- export async function list(options: ListOptions): Promise<void> {
52
- const spinner = cliConsole.spinner("Loading versions...");
53
-
54
- try {
55
- const versions: VersionListItem[] = await core.listVersions(options.store);
56
-
57
- spinner.succeed();
58
-
59
- if (versions.length === 0) {
60
- cliConsole.warn("No versions found for this store");
61
- cliConsole.dim("\nCreate a version with:");
62
- cliConsole.dim(
63
- ` ollieshop version create --store ${options.store} --name "My Version"`,
64
- );
65
- return;
66
- }
67
-
68
- cliConsole.info(
69
- `Found ${versions.length} version${versions.length === 1 ? "" : "s"}:\n`,
70
- );
71
-
72
- cliConsole.table(
73
- versions.map((v) => ({
74
- ID: v.id,
75
- Name: v.name,
76
- Template: v.template || "default",
77
- Active: v.active ? "✓" : "✗",
78
- Default: v.default ? "✓" : "✗",
79
- Created: new Date(v.createdAt).toLocaleDateString(),
80
- })),
81
- );
82
- } catch (error) {
83
- spinner.fail("Failed to list versions");
84
- handleError(error);
85
- }
86
- }
87
-
88
- export async function get(versionId: string): Promise<void> {
89
- const spinner = cliConsole.spinner("Loading version...");
90
-
91
- try {
92
- const version = await core.getVersion(versionId);
93
-
94
- spinner.succeed();
95
-
96
- cliConsole.info("Version details:\n");
97
-
98
- const details = {
99
- ID: version.id,
100
- Name: version.name,
101
- "Store ID": version.storeId,
102
- Template: version.template || "default",
103
- Active: version.active ? "Yes" : "No",
104
- Default: version.default ? "Yes" : "No",
105
- Created: new Date(version.createdAt).toLocaleString(),
106
- Updated: new Date(version.updatedAt).toLocaleString(),
107
- };
108
-
109
- for (const [key, value] of Object.entries(details)) {
110
- cliConsole.log(`${cliConsole.bold(`${key}:`)} ${value}`);
111
- }
112
-
113
- if (version.theme) {
114
- cliConsole.info("\nTheme configuration:");
115
- cliConsole.json(version.theme);
116
- }
117
-
118
- if (version.props) {
119
- cliConsole.info("\nProps configuration:");
120
- cliConsole.json(version.props);
121
- }
122
- } catch (error) {
123
- spinner.fail("Failed to get version");
124
- handleError(error);
125
- }
126
- }
127
-
128
- export async function setDefault(versionId: string): Promise<void> {
129
- const spinner = cliConsole.spinner("Setting default version...");
130
-
131
- try {
132
- await core.setDefaultVersion(versionId);
133
-
134
- spinner.succeed("Version set as default successfully");
135
-
136
- cliConsole.dim(
137
- "\nThis version will now be used for all new checkout sessions.",
138
- );
139
- } catch (error) {
140
- spinner.fail("Failed to set default version");
141
- handleError(error);
142
- }
143
- }
144
-
145
- export async function activate(versionId: string): Promise<void> {
146
- const spinner = cliConsole.spinner("Activating version...");
147
-
148
- try {
149
- const version = await core.activateVersion(versionId);
150
-
151
- spinner.succeed(`Version "${version.name}" activated successfully`);
152
-
153
- if (!version.default) {
154
- cliConsole.dim("\nTo make this the default version, run:");
155
- cliConsole.dim(` ollieshop version set-default ${versionId}`);
156
- }
157
- } catch (error) {
158
- spinner.fail("Failed to activate version");
159
- handleError(error);
160
- }
161
- }
162
-
163
- export async function deactivate(versionId: string): Promise<void> {
164
- const spinner = cliConsole.spinner("Deactivating version...");
165
-
166
- try {
167
- const version = await core.deactivateVersion(versionId);
168
-
169
- spinner.succeed(`Version "${version.name}" deactivated successfully`);
170
-
171
- cliConsole.warn(
172
- "\nWarning: This version can no longer be used for checkout sessions.",
173
- );
174
- } catch (error) {
175
- spinner.fail("Failed to deactivate version");
176
- handleError(error);
177
- }
178
- }
179
-
180
- export async function clone(sourceId: string, name: string): Promise<void> {
181
- const spinner = cliConsole.spinner("Cloning version...");
182
-
183
- try {
184
- const newVersion = await core.cloneVersion(sourceId, name);
185
-
186
- spinner.succeed(`Version cloned successfully as "${newVersion.name}"`);
187
-
188
- cliConsole.info("\nCloned version details:");
189
- cliConsole.table([
190
- {
191
- ID: newVersion.id,
192
- Name: newVersion.name,
193
- Template: newVersion.template || "default",
194
- Active: newVersion.active ? "✓" : "✗",
195
- Default: newVersion.default ? "✓" : "✗",
196
- },
197
- ]);
198
-
199
- cliConsole.dim("\nNote: The cloned version is inactive. To activate it:");
200
- cliConsole.dim(` ollieshop version activate ${newVersion.id}`);
201
- } catch (error) {
202
- spinner.fail("Failed to clone version");
203
- handleError(error);
204
- }
205
- }
206
-
207
- export async function deleteVersion(
208
- versionId: string,
209
- force?: boolean,
210
- ): Promise<void> {
211
- // Confirm deletion if not forced
212
- if (!force) {
213
- const confirmed = await cliConsole.confirm(
214
- "Are you sure you want to delete this version? This action cannot be undone.",
215
- );
216
-
217
- if (!confirmed) {
218
- cliConsole.info("Deletion cancelled");
219
- return;
220
- }
221
- }
222
-
223
- const spinner = cliConsole.spinner("Deleting version...");
224
-
225
- try {
226
- await core.deleteVersion(versionId);
227
-
228
- spinner.succeed("Version deleted successfully");
229
- } catch (error) {
230
- spinner.fail("Failed to delete version");
231
- handleError(error);
232
- }
233
- }
@@ -1,250 +0,0 @@
1
- import type { Command } from "@commander-js/extra-typings";
2
- import {
3
- createTestProgram,
4
- executeCLI,
5
- resetCLIMocks,
6
- } from "@tests/helpers/cli-test-helper";
7
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
- import { registerComponentCommands } from "../component";
9
-
10
- // Mock the component actions module
11
- vi.mock("../../actions/component.actions", () => ({
12
- createComponent: vi.fn(),
13
- listComponents: vi.fn(),
14
- deployComponent: vi.fn(),
15
- validateComponent: vi.fn(),
16
- }));
17
-
18
- import * as componentActions from "../../actions/component.actions";
19
-
20
- describe("Component Command Validation and DX", () => {
21
- let program: Command;
22
- let testSetup: ReturnType<typeof createTestProgram>;
23
-
24
- beforeEach(() => {
25
- testSetup = createTestProgram();
26
- program = testSetup.program;
27
- registerComponentCommands(program);
28
- vi.clearAllMocks();
29
- });
30
-
31
- afterEach(() => {
32
- resetCLIMocks();
33
- });
34
-
35
- describe("validation messages", () => {
36
- it("should provide helpful error for uppercase component names", async () => {
37
- const result = await executeCLI(program, [
38
- "component",
39
- "create",
40
- "--name",
41
- "TestComponent",
42
- ]);
43
-
44
- // The validation errors are written through console.error which is captured by our mocks
45
- const consoleErrorCalls = testSetup.mocks.console.error.mock.calls;
46
- const consoleLogCalls = testSetup.mocks.console.log.mock.calls;
47
-
48
- const consoleOutput = [
49
- ...consoleErrorCalls.map((call) => call.join(" ")),
50
- ...consoleLogCalls.map((call) => call.join(" ")),
51
- ].join("\n");
52
-
53
- expect(result.exitCode).toBe(1);
54
- expect(consoleOutput).toContain("Validation failed");
55
- expect(consoleOutput).toContain("name:");
56
- expect(consoleOutput).toContain("Must be lowercase with hyphens only");
57
- expect(consoleOutput).toContain("Examples:");
58
- expect(componentActions.createComponent).not.toHaveBeenCalled();
59
- });
60
-
61
- it("should provide helpful error for component names with spaces", async () => {
62
- const result = await executeCLI(program, [
63
- "component",
64
- "create",
65
- "--name",
66
- "test component",
67
- ]);
68
-
69
- const consoleOutput = testSetup.mocks.console.error.mock.calls
70
- .map((call) => call.join(" "))
71
- .join("\n");
72
-
73
- expect(result.exitCode).toBe(1);
74
- expect(consoleOutput).toContain("Validation failed");
75
- expect(consoleOutput).toContain("Must be lowercase with hyphens only");
76
- expect(componentActions.createComponent).not.toHaveBeenCalled();
77
- });
78
-
79
- it("should provide helpful error for component names with underscores", async () => {
80
- const result = await executeCLI(program, [
81
- "component",
82
- "create",
83
- "--name",
84
- "test_component",
85
- ]);
86
-
87
- const consoleOutput = testSetup.mocks.console.error.mock.calls
88
- .map((call) => call.join(" "))
89
- .join("\n");
90
-
91
- expect(result.exitCode).toBe(1);
92
- expect(consoleOutput).toContain("Validation failed");
93
- expect(consoleOutput).toContain("Must be lowercase with hyphens only");
94
- expect(componentActions.createComponent).not.toHaveBeenCalled();
95
- });
96
-
97
- it("should fail when name is missing", async () => {
98
- const result = await executeCLI(program, [
99
- "component",
100
- "create",
101
- "--slot",
102
- "header",
103
- ]);
104
-
105
- expect(result.exitCode).toBe(1);
106
- expect(componentActions.createComponent).not.toHaveBeenCalled();
107
- });
108
-
109
- it("should provide helpful error for invalid slot", async () => {
110
- const result = await executeCLI(program, [
111
- "component",
112
- "create",
113
- "--name",
114
- "test-component",
115
- "--slot",
116
- "invalid",
117
- ]);
118
-
119
- // The slot validation happens at the Commander.js level with a parser
120
- // So we get a different error message format
121
- const allOutput = [
122
- ...result.stderr,
123
- ...testSetup.mocks.console.error.mock.calls.map((call) =>
124
- call.join(" "),
125
- ),
126
- ].join("\n");
127
-
128
- expect(result.exitCode).toBe(1);
129
- expect(allOutput).toContain("Invalid component slot");
130
- expect(allOutput).toContain(
131
- "Valid slots: header, footer, sidebar, main, checkout-summary, payment-method, shipping-method, customer-info, order-confirmation",
132
- );
133
- expect(componentActions.createComponent).not.toHaveBeenCalled();
134
- });
135
- });
136
-
137
- describe("unknown options and commands", () => {
138
- it("should provide helpful error for unknown options", async () => {
139
- const result = await executeCLI(program, [
140
- "component",
141
- "create",
142
- "--name",
143
- "test",
144
- "--unknown",
145
- ]);
146
-
147
- expect(result.exitCode).toBe(1);
148
- // Commander.js formats the error as "error: unknown option '--unknown'"
149
- expect(result.stderr.join("")).toContain("unknown option '--unknown'");
150
- });
151
-
152
- it("should provide helpful error for unknown commands", async () => {
153
- const result = await executeCLI(program, [
154
- "component",
155
- "craete",
156
- "--name",
157
- "test",
158
- ]);
159
-
160
- expect(result.exitCode).toBe(1);
161
- // Commander.js formats the error as "error: unknown command 'craete'"
162
- expect(result.stderr.join("")).toContain("unknown command 'craete'");
163
- // Commander has built-in suggestions
164
- expect(result.stderr.join("")).toContain("Did you mean");
165
- });
166
- });
167
-
168
- describe("valid inputs", () => {
169
- it("should accept valid kebab-case component names", async () => {
170
- vi.mocked(componentActions.createComponent).mockResolvedValue();
171
-
172
- const result = await executeCLI(program, [
173
- "component",
174
- "create",
175
- "--name",
176
- "header-navigation",
177
- ]);
178
-
179
- expect(result.exitCode).toBe(0);
180
- expect(componentActions.createComponent).toHaveBeenCalledWith(
181
- expect.objectContaining({
182
- name: "header-navigation",
183
- slot: "main",
184
- tests: true,
185
- interactive: false,
186
- }),
187
- expect.any(Object),
188
- );
189
- });
190
-
191
- it("should accept component names with numbers", async () => {
192
- vi.mocked(componentActions.createComponent).mockResolvedValue();
193
-
194
- const result = await executeCLI(program, [
195
- "component",
196
- "create",
197
- "--name",
198
- "product-list-v2",
199
- ]);
200
-
201
- expect(result.exitCode).toBe(0);
202
- expect(componentActions.createComponent).toHaveBeenCalledWith(
203
- expect.objectContaining({
204
- name: "product-list-v2",
205
- }),
206
- expect.any(Object),
207
- );
208
- });
209
-
210
- it("should accept single word lowercase names", async () => {
211
- vi.mocked(componentActions.createComponent).mockResolvedValue();
212
-
213
- const result = await executeCLI(program, [
214
- "component",
215
- "create",
216
- "--name",
217
- "header",
218
- ]);
219
-
220
- expect(result.exitCode).toBe(0);
221
- expect(componentActions.createComponent).toHaveBeenCalledWith(
222
- expect.objectContaining({
223
- name: "header",
224
- }),
225
- expect.any(Object),
226
- );
227
- });
228
- });
229
-
230
- describe("help command", () => {
231
- it("should show examples in help output", async () => {
232
- const result = await executeCLI(program, [
233
- "component",
234
- "create",
235
- "--help",
236
- ]);
237
-
238
- const output = result.stdout.join("") + result.stderr.join("");
239
- expect(output).toContain("Examples:");
240
- expect(output).toContain("Create a header component:");
241
- expect(output).toContain(
242
- "$ ollieshop component create --name header --slot header",
243
- );
244
- expect(output).toContain("Create a component with TypeScript:");
245
- expect(output).toContain(
246
- "$ ollieshop component create --name product-list --typescript",
247
- );
248
- });
249
- });
250
- });