@ollie-shop/cli 0.3.0 → 0.3.3

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 (139) hide show
  1. package/.turbo/turbo-build.log +14 -2
  2. package/CHANGELOG.md +48 -0
  3. package/__tests__/mocks/core.ts +1 -1
  4. package/dist/index.d.ts +0 -2
  5. package/dist/index.js +40631 -75
  6. package/package.json +7 -6
  7. package/src/actions/component.actions.ts +148 -204
  8. package/src/actions/function.actions.ts +78 -171
  9. package/src/actions/project.actions.ts +16 -11
  10. package/src/commands/__tests__/component.test.ts +4 -7
  11. package/src/commands/__tests__/function.test.ts +1 -1
  12. package/src/commands/__tests__/store-version.test.ts +1 -4
  13. package/src/commands/component.ts +0 -10
  14. package/src/commands/function.ts +5 -56
  15. package/src/schemas/command.schema.ts +296 -6
  16. package/src/utils/__tests__/rich-progress.test.ts +22 -11
  17. package/src/utils/cli-progress-reporter.ts +2 -2
  18. package/src/utils/command-parser.ts +0 -5
  19. package/src/utils/console.ts +33 -4
  20. package/src/utils/constants.ts +32 -0
  21. package/src/utils/deploy-helpers.ts +357 -0
  22. package/src/utils/errors.ts +133 -2
  23. package/src/utils/interactive-builder.ts +61 -7
  24. package/src/utils/rich-progress.ts +25 -14
  25. package/src/utils/validation-helpers.ts +145 -12
  26. package/tsup.config.ts +15 -0
  27. package/dist/__tests__/helpers/cli-test-helper.d.ts +0 -89
  28. package/dist/__tests__/helpers/cli-test-helper.d.ts.map +0 -1
  29. package/dist/__tests__/helpers/cli-test-helper.js +0 -220
  30. package/dist/__tests__/mocks/index.d.ts +0 -69
  31. package/dist/__tests__/mocks/index.d.ts.map +0 -1
  32. package/dist/__tests__/mocks/index.js +0 -77
  33. package/dist/actions/component.actions.d.ts +0 -14
  34. package/dist/actions/component.actions.d.ts.map +0 -1
  35. package/dist/actions/component.actions.js +0 -273
  36. package/dist/actions/function.actions.d.ts +0 -15
  37. package/dist/actions/function.actions.d.ts.map +0 -1
  38. package/dist/actions/function.actions.js +0 -254
  39. package/dist/actions/project.actions.d.ts +0 -17
  40. package/dist/actions/project.actions.d.ts.map +0 -1
  41. package/dist/actions/project.actions.js +0 -97
  42. package/dist/actions/version.actions.d.ts +0 -19
  43. package/dist/actions/version.actions.d.ts.map +0 -1
  44. package/dist/actions/version.actions.js +0 -216
  45. package/dist/commands/component.d.ts +0 -3
  46. package/dist/commands/component.d.ts.map +0 -1
  47. package/dist/commands/component.js +0 -192
  48. package/dist/commands/docs.d.ts +0 -3
  49. package/dist/commands/docs.d.ts.map +0 -1
  50. package/dist/commands/docs.js +0 -16
  51. package/dist/commands/function.d.ts +0 -3
  52. package/dist/commands/function.d.ts.map +0 -1
  53. package/dist/commands/function.js +0 -243
  54. package/dist/commands/help.d.ts +0 -3
  55. package/dist/commands/help.d.ts.map +0 -1
  56. package/dist/commands/help.js +0 -20
  57. package/dist/commands/index.d.ts +0 -3
  58. package/dist/commands/index.d.ts.map +0 -1
  59. package/dist/commands/index.js +0 -26
  60. package/dist/commands/login.d.ts +0 -3
  61. package/dist/commands/login.d.ts.map +0 -1
  62. package/dist/commands/login.js +0 -175
  63. package/dist/commands/project.d.ts +0 -3
  64. package/dist/commands/project.d.ts.map +0 -1
  65. package/dist/commands/project.js +0 -78
  66. package/dist/commands/store-version.d.ts +0 -3
  67. package/dist/commands/store-version.d.ts.map +0 -1
  68. package/dist/commands/store-version.js +0 -241
  69. package/dist/commands/version.d.ts +0 -3
  70. package/dist/commands/version.d.ts.map +0 -1
  71. package/dist/commands/version.js +0 -46
  72. package/dist/commands/whoami.d.ts +0 -3
  73. package/dist/commands/whoami.d.ts.map +0 -1
  74. package/dist/commands/whoami.js +0 -41
  75. package/dist/index.d.ts.map +0 -1
  76. package/dist/prompts/component.prompts.d.ts +0 -14
  77. package/dist/prompts/component.prompts.d.ts.map +0 -1
  78. package/dist/prompts/component.prompts.js +0 -75
  79. package/dist/prompts/function.prompts.d.ts +0 -21
  80. package/dist/prompts/function.prompts.d.ts.map +0 -1
  81. package/dist/prompts/function.prompts.js +0 -127
  82. package/dist/schemas/command.schema.d.ts +0 -516
  83. package/dist/schemas/command.schema.d.ts.map +0 -1
  84. package/dist/schemas/command.schema.js +0 -267
  85. package/dist/types/index.d.ts +0 -147
  86. package/dist/types/index.d.ts.map +0 -1
  87. package/dist/types/index.js +0 -18
  88. package/dist/utils/auth.d.ts +0 -4
  89. package/dist/utils/auth.d.ts.map +0 -1
  90. package/dist/utils/auth.js +0 -26
  91. package/dist/utils/cli-progress-reporter.d.ts +0 -12
  92. package/dist/utils/cli-progress-reporter.d.ts.map +0 -1
  93. package/dist/utils/cli-progress-reporter.js +0 -77
  94. package/dist/utils/command-builder.d.ts +0 -22
  95. package/dist/utils/command-builder.d.ts.map +0 -1
  96. package/dist/utils/command-builder.js +0 -268
  97. package/dist/utils/command-helpers.d.ts +0 -19
  98. package/dist/utils/command-helpers.d.ts.map +0 -1
  99. package/dist/utils/command-helpers.js +0 -79
  100. package/dist/utils/command-parser.d.ts +0 -146
  101. package/dist/utils/command-parser.d.ts.map +0 -1
  102. package/dist/utils/command-parser.js +0 -179
  103. package/dist/utils/command-suggestions.d.ts +0 -35
  104. package/dist/utils/command-suggestions.d.ts.map +0 -1
  105. package/dist/utils/command-suggestions.js +0 -152
  106. package/dist/utils/console.d.ts +0 -44
  107. package/dist/utils/console.d.ts.map +0 -1
  108. package/dist/utils/console.js +0 -233
  109. package/dist/utils/constants.d.ts +0 -8
  110. package/dist/utils/constants.d.ts.map +0 -1
  111. package/dist/utils/constants.js +0 -10
  112. package/dist/utils/context-detector.d.ts +0 -12
  113. package/dist/utils/context-detector.d.ts.map +0 -1
  114. package/dist/utils/context-detector.js +0 -155
  115. package/dist/utils/enhanced-error-handler.d.ts +0 -47
  116. package/dist/utils/enhanced-error-handler.d.ts.map +0 -1
  117. package/dist/utils/enhanced-error-handler.js +0 -221
  118. package/dist/utils/error-handler.d.ts +0 -3
  119. package/dist/utils/error-handler.d.ts.map +0 -1
  120. package/dist/utils/error-handler.js +0 -55
  121. package/dist/utils/errors.d.ts +0 -44
  122. package/dist/utils/errors.d.ts.map +0 -1
  123. package/dist/utils/errors.js +0 -76
  124. package/dist/utils/interactive-builder.d.ts +0 -22
  125. package/dist/utils/interactive-builder.d.ts.map +0 -1
  126. package/dist/utils/interactive-builder.js +0 -246
  127. package/dist/utils/rich-progress.d.ts +0 -59
  128. package/dist/utils/rich-progress.d.ts.map +0 -1
  129. package/dist/utils/rich-progress.js +0 -234
  130. package/dist/utils/store.d.ts +0 -11
  131. package/dist/utils/store.d.ts.map +0 -1
  132. package/dist/utils/store.js +0 -19
  133. package/dist/utils/validation-error-formatter.d.ts +0 -25
  134. package/dist/utils/validation-error-formatter.d.ts.map +0 -1
  135. package/dist/utils/validation-error-formatter.js +0 -258
  136. package/dist/utils/validation-helpers.d.ts +0 -60
  137. package/dist/utils/validation-helpers.d.ts.map +0 -1
  138. package/dist/utils/validation-helpers.js +0 -152
  139. package/src/commands/__tests__/version.test.ts +0 -71
@@ -16,21 +16,55 @@ export { ComponentNameSchema, FunctionNameSchema };
16
16
  /**
17
17
  * CLI-specific schemas (only for CLI-specific concerns)
18
18
  */
19
+
20
+ /**
21
+ * Schema for file system paths
22
+ * @example "./src/components/header"
23
+ * @example "/absolute/path/to/component"
24
+ */
19
25
  export const PathSchema = z.string().min(1, "Path cannot be empty");
20
26
 
27
+ /**
28
+ * Schema for store identifiers
29
+ * Must be a valid UUID v4 format
30
+ * @example "123e4567-e89b-12d3-a456-426614174000"
31
+ */
21
32
  export const StoreIdSchema = z.string().uuid("Invalid store ID format");
22
33
 
34
+ /**
35
+ * Schema for version names
36
+ * @example "Production v2.0"
37
+ * @example "Holiday Sale Version"
38
+ * @minLength 1
39
+ * @maxLength 100
40
+ */
23
41
  export const VersionNameSchema = z
24
42
  .string()
25
43
  .min(1, "Version name is required")
26
44
  .max(100, "Version name is too long (max 100 characters)");
27
45
 
46
+ /**
47
+ * Schema for function execution priority
48
+ * Higher numbers execute first
49
+ * @minimum 0
50
+ * @maximum 100
51
+ * @example 50 - Default priority
52
+ * @example 90 - High priority (executes early)
53
+ * @example 10 - Low priority (executes late)
54
+ */
28
55
  export const PrioritySchema = z
29
56
  .number()
30
57
  .int("Priority must be a whole number")
31
58
  .min(0, "Priority must be between 0 and 100")
32
59
  .max(100, "Priority must be between 0 and 100");
33
60
 
61
+ /**
62
+ * Schema for URLs and URL patterns
63
+ * Supports both full URLs and path patterns
64
+ * @example "https://api.example.com/webhook"
65
+ * @example "/api/cart/*"
66
+ * @example "/*" - Matches all paths
67
+ */
34
68
  export const UrlSchema = z
35
69
  .string()
36
70
  .min(1, "URL is required")
@@ -48,6 +82,13 @@ export const UrlSchema = z
48
82
  }
49
83
  }, "URL must be a valid URL or path pattern");
50
84
 
85
+ /**
86
+ * Schema for semantic version numbers
87
+ * @pattern ^\d+\.\d+\.\d+$
88
+ * @example "1.0.0"
89
+ * @example "2.4.6"
90
+ * @see https://semver.org/
91
+ */
51
92
  export const SemverSchema = z
52
93
  .string()
53
94
  .regex(
@@ -58,6 +99,19 @@ export const SemverSchema = z
58
99
  /**
59
100
  * Component command schemas
60
101
  */
102
+
103
+ /**
104
+ * Options for creating a new component
105
+ * @property {string} [name] - Component name in kebab-case (e.g., "header-banner")
106
+ * @property {"header"|"main"|"footer"|"sidebar"} [slot="main"] - Where the component renders in the checkout
107
+ * @property {boolean} [tests=true] - Whether to generate test files
108
+ * @property {string} [template] - Custom template to use for generation
109
+ * @property {boolean} [interactive] - Use interactive mode with prompts
110
+ * @example
111
+ * // CLI usage:
112
+ * ollieshop component create --name header-banner --slot header
113
+ * ollieshop component create --interactive
114
+ */
61
115
  export const ComponentCreateOptionsSchema = z
62
116
  .object({
63
117
  name: ComponentNameSchema.optional(), // Optional for interactive mode
@@ -71,6 +125,18 @@ export const ComponentCreateOptionsSchema = z
71
125
  path: ["name"],
72
126
  });
73
127
 
128
+ /**
129
+ * Options for building a component
130
+ * @property {string} [path] - Path to component directory (defaults to current directory)
131
+ * @property {boolean} [watch=false] - Watch for file changes and rebuild automatically
132
+ * @property {boolean} [minify=true] - Minify the output bundle
133
+ * @property {boolean} [sourcemap=true] - Generate source maps for debugging
134
+ * @example
135
+ * // CLI usage:
136
+ * ollieshop component build
137
+ * ollieshop component build --watch
138
+ * ollieshop component build --path ./components/header --no-minify
139
+ */
74
140
  export const ComponentBuildOptionsSchema = z.object({
75
141
  path: PathSchema.optional(),
76
142
  watch: z.boolean().optional(),
@@ -78,22 +144,57 @@ export const ComponentBuildOptionsSchema = z.object({
78
144
  sourcemap: z.boolean().optional(),
79
145
  });
80
146
 
147
+ /**
148
+ * Options for validating a component
149
+ * @property {string} [path] - Path to component directory (defaults to current directory)
150
+ * @property {boolean} [strict=false] - Enable strict validation mode with additional checks
151
+ * @property {boolean} [fix=false] - Automatically fix fixable validation issues
152
+ * @example
153
+ * // CLI usage:
154
+ * ollieshop component validate
155
+ * ollieshop component validate --strict
156
+ * ollieshop component validate --fix
157
+ */
81
158
  export const ComponentValidateOptionsSchema = z.object({
82
159
  path: PathSchema.optional(),
83
160
  strict: z.boolean().optional(),
84
161
  fix: z.boolean().optional(),
85
162
  });
86
163
 
164
+ /**
165
+ * Options for deploying a component
166
+ * @property {string} [path] - Path to component directory (defaults to current directory)
167
+ * @property {string} [componentId] - UUID of the component to deploy (internal use)
168
+ * @property {string} [id] - UUID of the component to deploy (CLI flag)
169
+ * @example
170
+ * // CLI usage:
171
+ * ollieshop component deploy --id 123e4567-e89b-12d3-a456-426614174000
172
+ * ollieshop component deploy --id 123e4567-e89b-12d3-a456-426614174000 --path ./dist
173
+ */
87
174
  export const ComponentDeployOptionsSchema = z.object({
88
175
  path: PathSchema.optional(),
89
- componentId: z.string().optional(),
90
- id: z.string().optional(), // CLI uses --id flag
91
- wait: z.boolean().optional(),
176
+ componentId: z.string().uuid("Invalid component ID format").optional(),
177
+ id: z.string().uuid("Invalid component ID format").optional(), // CLI uses --id flag
92
178
  });
93
179
 
94
180
  /**
95
181
  * Function command schemas
96
182
  */
183
+
184
+ /**
185
+ * Options for creating a new function
186
+ * @property {string} name - Function name in kebab-case (e.g., "validate-cart")
187
+ * @property {"request"|"response"} [invocation="request"] - When the function executes in the request lifecycle
188
+ * @property {number} [priority=0] - Execution priority (0-100, higher executes first)
189
+ * @property {"throw"|"skip"} [onError="throw"] - Error handling behavior
190
+ * @property {boolean} [tests=true] - Whether to generate test files
191
+ * @property {string} [template] - Custom template to use for generation
192
+ * @property {string} [description] - Human-readable description of function purpose
193
+ * @example
194
+ * // CLI usage:
195
+ * ollieshop function create --name validate-cart --invocation request --priority 90
196
+ * ollieshop function create --name apply-discount --on-error skip
197
+ */
97
198
  export const FunctionCreateOptionsSchema = z.object({
98
199
  name: FunctionNameSchema,
99
200
  invocation: FunctionInvocationType.optional().default("request"),
@@ -104,6 +205,18 @@ export const FunctionCreateOptionsSchema = z.object({
104
205
  description: z.string().optional(),
105
206
  });
106
207
 
208
+ /**
209
+ * Options for building a function
210
+ * @property {string} [path] - Path to function directory (defaults to current directory)
211
+ * @property {boolean} [watch=false] - Watch for file changes and rebuild automatically
212
+ * @property {boolean} [minify=true] - Minify the output bundle
213
+ * @property {"node16"|"node18"|"node20"} [target="node18"] - Target Node.js runtime version
214
+ * @example
215
+ * // CLI usage:
216
+ * ollieshop function build
217
+ * ollieshop function build --watch --target node20
218
+ * ollieshop function build --no-minify
219
+ */
107
220
  export const FunctionBuildOptionsSchema = z.object({
108
221
  path: PathSchema.optional(),
109
222
  watch: z.boolean().optional(),
@@ -117,6 +230,19 @@ export const FunctionValidateOptionsSchema = z.object({
117
230
  fix: z.boolean().optional(),
118
231
  });
119
232
 
233
+ /**
234
+ * Options for testing a function
235
+ * @property {string} [path] - Path to function directory (defaults to current directory)
236
+ * @property {string} [payload] - JSON payload to send to the function
237
+ * @property {number} [timeout=30000] - Test timeout in milliseconds
238
+ * @property {boolean} [coverage=false] - Generate code coverage report
239
+ * @property {boolean} [watch=false] - Run tests in watch mode
240
+ * @example
241
+ * // CLI usage:
242
+ * ollieshop function test
243
+ * ollieshop function test --payload '{"cart": {"total": 100}}'
244
+ * ollieshop function test --watch --coverage
245
+ */
120
246
  export const FunctionTestOptionsSchema = z.object({
121
247
  path: PathSchema.optional(),
122
248
  payload: z.string().optional(),
@@ -125,16 +251,42 @@ export const FunctionTestOptionsSchema = z.object({
125
251
  watch: z.boolean().optional(),
126
252
  });
127
253
 
254
+ /**
255
+ * Options for deploying a function
256
+ * @property {string} [path] - Path to function directory (defaults to current directory)
257
+ * @property {string} [functionId] - UUID of the function to deploy (internal use)
258
+ * @property {string} [id] - UUID of the function to deploy (CLI flag)
259
+ * @example
260
+ * // CLI usage:
261
+ * ollieshop function deploy --id 123e4567-e89b-12d3-a456-426614174000
262
+ * ollieshop function deploy --id 123e4567-e89b-12d3-a456-426614174000 --path ./dist
263
+ */
128
264
  export const FunctionDeployOptionsSchema = z.object({
129
265
  path: PathSchema.optional(),
130
- functionId: z.string().optional(),
131
- id: z.string().optional(), // CLI uses --id flag
132
- wait: z.boolean().optional(),
266
+ functionId: z.string().uuid("Invalid function ID format").optional(),
267
+ id: z.string().uuid("Invalid function ID format").optional(), // CLI uses --id flag
133
268
  });
134
269
 
135
270
  /**
136
271
  * Development server schemas
137
272
  */
273
+
274
+ /**
275
+ * Options for running a development server
276
+ * @property {number} [port=3000] - Port number to run the server on (1000-65535)
277
+ * @property {string} [host="localhost"] - Host to bind the server to
278
+ * @property {boolean} [open=true] - Open browser automatically when server starts
279
+ * @property {string} [component] - Path to specific component to develop
280
+ * @property {string} [function] - Path to specific function to develop
281
+ * @property {string} [mockData] - Path to mock data file for testing
282
+ * @property {boolean} [hot=true] - Enable hot module replacement
283
+ * @property {boolean} [https=false] - Enable HTTPS with self-signed certificate
284
+ * @example
285
+ * // CLI usage:
286
+ * ollieshop dev
287
+ * ollieshop dev --port 8080 --no-open
288
+ * ollieshop dev --component ./components/header --hot
289
+ */
138
290
  export const DevServerOptionsSchema = z.object({
139
291
  port: z.number().min(1000).max(65535).default(3000),
140
292
  host: z.string().default("localhost"),
@@ -149,6 +301,20 @@ export const DevServerOptionsSchema = z.object({
149
301
  /**
150
302
  * Global CLI options schemas
151
303
  */
304
+
305
+ /**
306
+ * Global options available for all CLI commands
307
+ * @property {boolean} [verbose=false] - Show detailed output and debug information
308
+ * @property {boolean} [quiet=false] - Suppress all output except errors
309
+ * @property {boolean} [color=true] - Enable colored output (use --no-color to disable)
310
+ * @property {string} [config] - Path to custom configuration file
311
+ * @property {"error"|"warn"|"info"|"debug"} [logLevel="info"] - Minimum log level to display
312
+ * @example
313
+ * // CLI usage:
314
+ * ollieshop --verbose component create --name header
315
+ * ollieshop --quiet function deploy --id abc-123
316
+ * ollieshop --no-color --log-level debug component build
317
+ */
152
318
  export const GlobalOptionsSchema = z.object({
153
319
  verbose: z.boolean().default(false),
154
320
  quiet: z.boolean().default(false),
@@ -160,6 +326,21 @@ export const GlobalOptionsSchema = z.object({
160
326
  /**
161
327
  * Build command schemas
162
328
  */
329
+
330
+ /**
331
+ * Options for building projects, components, or functions
332
+ * @property {string} [path] - Path to build (defaults to current directory)
333
+ * @property {string} [output] - Output directory for build artifacts
334
+ * @property {boolean} [minify=true] - Minify the output
335
+ * @property {boolean} [sourcemap=true] - Generate source maps
336
+ * @property {boolean} [watch=false] - Watch mode for continuous builds
337
+ * @property {boolean} [clean=true] - Clean output directory before building
338
+ * @example
339
+ * // CLI usage:
340
+ * ollieshop build
341
+ * ollieshop build --output ./dist --no-minify
342
+ * ollieshop build --watch --no-clean
343
+ */
163
344
  export const BuildOptionsSchema = z.object({
164
345
  path: PathSchema.optional(),
165
346
  output: PathSchema.optional(),
@@ -172,6 +353,18 @@ export const BuildOptionsSchema = z.object({
172
353
  /**
173
354
  * Login/Auth schemas
174
355
  */
356
+
357
+ /**
358
+ * Options for CLI authentication
359
+ * @property {string} [token] - Authentication token (if not using interactive login)
360
+ * @property {boolean} [interactive=true] - Use interactive browser-based login
361
+ * @property {boolean} [save=true] - Save credentials for future use
362
+ * @example
363
+ * // CLI usage:
364
+ * ollieshop login
365
+ * ollieshop login --token abc123
366
+ * ollieshop login --no-save
367
+ */
175
368
  export const LoginOptionsSchema = z.object({
176
369
  token: z.string().optional(),
177
370
  interactive: z.boolean().default(true),
@@ -181,6 +374,20 @@ export const LoginOptionsSchema = z.object({
181
374
  /**
182
375
  * Init project schemas
183
376
  */
377
+
378
+ /**
379
+ * Options for initializing a new Ollie Shop project
380
+ * @property {string} [name="my-ollie-shop"] - Project name
381
+ * @property {"default"|"grocery"|"sales"} [template="default"] - Checkout template to use
382
+ * @property {boolean} [git=true] - Initialize git repository
383
+ * @property {boolean} [install=true] - Install dependencies automatically
384
+ * @property {string} [path] - Where to create the project (defaults to project name)
385
+ * @example
386
+ * // CLI usage:
387
+ * ollieshop init --name my-checkout
388
+ * ollieshop init --template grocery --no-install
389
+ * ollieshop init --name holiday-sale --path ./projects/holiday
390
+ */
184
391
  export const InitOptionsSchema = z.object({
185
392
  name: z.string().optional(),
186
393
  template: Template.optional().default("default"),
@@ -192,6 +399,18 @@ export const InitOptionsSchema = z.object({
192
399
  /**
193
400
  * Store version command schemas
194
401
  */
402
+
403
+ /**
404
+ * Options for creating a store version
405
+ * @property {string} store - UUID of the store
406
+ * @property {string} name - Version name (1-100 characters)
407
+ * @property {"default"|"grocery"|"sales"} [template] - Checkout template
408
+ * @property {boolean} [active=true] - Whether version is active immediately
409
+ * @example
410
+ * // CLI usage:
411
+ * ollieshop version create --store 123e4567-e89b-12d3-a456-426614174000 --name "Black Friday"
412
+ * ollieshop version create --store abc-123 --name "Test" --template grocery --no-active
413
+ */
195
414
  export const StoreVersionCreateOptionsSchema = z.object({
196
415
  store: StoreIdSchema,
197
416
  name: VersionNameSchema,
@@ -291,6 +510,77 @@ export function validateSemver(version: string): boolean {
291
510
  return SemverSchema.safeParse(version).success;
292
511
  }
293
512
 
513
+ export function validateUUID(id: string): boolean {
514
+ const uuidSchema = z.string().uuid();
515
+ return uuidSchema.safeParse(id).success;
516
+ }
517
+
518
+ /**
519
+ * Environment variable validation schemas and helpers
520
+ */
521
+ export const BuilderApiUrlSchema = z
522
+ .string()
523
+ .url("BUILDER_API_URL must be a valid URL")
524
+ .refine(
525
+ (url) => {
526
+ try {
527
+ const parsed = new URL(url);
528
+ return ["http:", "https:"].includes(parsed.protocol);
529
+ } catch {
530
+ return false;
531
+ }
532
+ },
533
+ {
534
+ message: "BUILDER_API_URL must use http or https protocol",
535
+ },
536
+ );
537
+
538
+ export const EnvironmentVariablesSchema = z.object({
539
+ BUILDER_API_URL: BuilderApiUrlSchema.optional(),
540
+ DEBUG: z.string().optional(),
541
+ NODE_ENV: z.enum(["development", "test", "production"]).optional(),
542
+ });
543
+
544
+ /**
545
+ * Validates all CLI environment variables
546
+ * @returns {Object} Validation result with success flag and optional errors
547
+ * @returns {boolean} result.success - True if all env vars are valid
548
+ * @returns {string[]} [result.errors] - Array of validation error messages
549
+ * @example
550
+ * const result = validateEnvironmentVariables();
551
+ * if (!result.success) {
552
+ * console.error("Invalid environment:", result.errors);
553
+ * }
554
+ */
555
+ export function validateEnvironmentVariables(): {
556
+ success: boolean;
557
+ errors?: string[];
558
+ } {
559
+ const envVars = {
560
+ BUILDER_API_URL: process.env.BUILDER_API_URL,
561
+ DEBUG: process.env.DEBUG,
562
+ NODE_ENV: process.env.NODE_ENV,
563
+ };
564
+
565
+ const result = EnvironmentVariablesSchema.safeParse(envVars);
566
+
567
+ if (!result.success) {
568
+ return {
569
+ success: false,
570
+ errors: result.error.issues.map(
571
+ (issue) => `${issue.path.join(".")}: ${issue.message}`,
572
+ ),
573
+ };
574
+ }
575
+
576
+ return { success: true };
577
+ }
578
+
579
+ export function validateBuilderApiUrl(url?: string): boolean {
580
+ if (!url) return true; // Optional
581
+ return BuilderApiUrlSchema.safeParse(url).success;
582
+ }
583
+
294
584
  /**
295
585
  * CLI Data Display Schemas
296
586
  * These schemas define the structure for data displayed in CLI commands
@@ -1,4 +1,5 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+ import type { CliConsole } from "../console";
2
3
  import { RichProgressReporter, SimpleProgressReporter } from "../rich-progress";
3
4
 
4
5
  // Mock cli-progress
@@ -34,10 +35,20 @@ vi.mock("ora", () => ({
34
35
 
35
36
  describe("RichProgressReporter", () => {
36
37
  let reporter: RichProgressReporter;
38
+ let mockConsole: CliConsole;
37
39
  let consoleLogSpy: ReturnType<typeof vi.spyOn>;
38
40
 
39
41
  beforeEach(() => {
40
- // Skip creating the actual reporter to avoid mocking issues
42
+ // Create a mock console with all required methods
43
+ mockConsole = {
44
+ info: vi.fn(),
45
+ success: vi.fn(),
46
+ error: vi.fn(),
47
+ warn: vi.fn(),
48
+ debug: vi.fn(),
49
+ log: vi.fn(),
50
+ } as unknown as CliConsole;
51
+
41
52
  consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {
42
53
  // Intentionally empty for test isolation
43
54
  });
@@ -49,16 +60,16 @@ describe("RichProgressReporter", () => {
49
60
  });
50
61
 
51
62
  it("should start progress tracking", () => {
52
- reporter = new RichProgressReporter();
63
+ reporter = new RichProgressReporter(mockConsole);
53
64
  reporter.start();
54
65
 
55
- expect(consoleLogSpy).toHaveBeenCalledWith(
66
+ expect(mockConsole.info).toHaveBeenCalledWith(
56
67
  expect.stringContaining("🚀 Starting deployment..."),
57
68
  );
58
69
  });
59
70
 
60
71
  it("should update progress with build status", () => {
61
- reporter = new RichProgressReporter();
72
+ reporter = new RichProgressReporter(mockConsole);
62
73
 
63
74
  const progress = {
64
75
  phase: "build",
@@ -72,21 +83,21 @@ describe("RichProgressReporter", () => {
72
83
 
73
84
  it("should show success summary", () => {
74
85
  // Test just the summary method
75
- const reporter = new RichProgressReporter();
86
+ const reporter = new RichProgressReporter(mockConsole);
76
87
  // Access private method for testing
77
88
  const reporterWithPrivate = reporter as unknown as {
78
89
  showSuccessSummary(): void;
79
90
  };
80
91
  reporterWithPrivate.showSuccessSummary();
81
92
 
82
- expect(consoleLogSpy).toHaveBeenCalledWith(
93
+ expect(mockConsole.success).toHaveBeenCalledWith(
83
94
  expect.stringContaining("✅ Deployment completed successfully!"),
84
95
  );
85
96
  });
86
97
 
87
98
  it("should show failure message", () => {
88
99
  // Create a minimal test that doesn't rely on bars
89
- const reporter = new RichProgressReporter();
100
+ const reporter = new RichProgressReporter(mockConsole);
90
101
  // Access private properties for testing
91
102
  const reporterWithPrivate = reporter as unknown as {
92
103
  multibar: { stop: () => void };
@@ -97,13 +108,13 @@ describe("RichProgressReporter", () => {
97
108
 
98
109
  reporter.stop(false);
99
110
 
100
- expect(consoleLogSpy).toHaveBeenCalledWith(
111
+ expect(mockConsole.error).toHaveBeenCalledWith(
101
112
  expect.stringContaining("❌ Deployment failed"),
102
113
  );
103
114
  });
104
115
 
105
116
  it("should display build stats when available", () => {
106
- const reporter = new RichProgressReporter();
117
+ const reporter = new RichProgressReporter(mockConsole);
107
118
 
108
119
  // Set stats directly for testing
109
120
  const reporterWithPrivate = reporter as unknown as {
@@ -120,10 +131,10 @@ describe("RichProgressReporter", () => {
120
131
  };
121
132
  reporterWithSummary.showSuccessSummary();
122
133
 
123
- expect(consoleLogSpy).toHaveBeenCalledWith(
134
+ expect(mockConsole.info).toHaveBeenCalledWith(
124
135
  expect.stringContaining("📊 Build Stats:"),
125
136
  );
126
- expect(consoleLogSpy).toHaveBeenCalledWith(
137
+ expect(mockConsole.info).toHaveBeenCalledWith(
127
138
  expect.stringContaining("Bundle size: 146.5KB"),
128
139
  );
129
140
  });
@@ -37,8 +37,8 @@ export class CLIProgressReporter {
37
37
  }
38
38
 
39
39
  updateProgress(progress: BuildProgress): void {
40
- const phaseDisplay = this.formatPhase(progress.currentPhase);
41
- const etaFormatted = this.formatETA(progress.estimatedRemainingSeconds);
40
+ const phaseDisplay = this.formatPhase(progress.status);
41
+ const etaFormatted = this.formatETA(0); // ETA not available in BuildProgress
42
42
 
43
43
  this.bar.update(progress.percentComplete, {
44
44
  phase: phaseDisplay,
@@ -200,11 +200,6 @@ export const COMMON_OPTIONS = {
200
200
  description: "Path to component or function directory",
201
201
  parser: parsePath,
202
202
  },
203
- wait: {
204
- flags: "-w, --wait",
205
- description: "Wait for operation to complete",
206
- defaultValue: false,
207
- },
208
203
  storeId: {
209
204
  flags: "-s, --store <id>",
210
205
  description: "Store ID (UUID format)",
@@ -1,4 +1,5 @@
1
1
  import chalk from "chalk";
2
+ import inquirer from "inquirer";
2
3
  import ora, { type Ora } from "ora";
3
4
  import type { OllieShopCLIError } from "./errors";
4
5
 
@@ -234,10 +235,38 @@ export class Console {
234
235
  }
235
236
 
236
237
  async confirm(message: string): Promise<boolean> {
237
- // For now, return false in non-interactive mode
238
- // TODO: Implement interactive confirmation
239
- this.warn(`${message} (y/N)`);
240
- return false;
238
+ // In quiet mode, default to false for non-interactive usage
239
+ if (this.options.quiet) {
240
+ return false;
241
+ }
242
+
243
+ // Check if we're in a TTY environment (interactive terminal)
244
+ if (!process.stdin.isTTY) {
245
+ this.warn(`${message} (y/N) - Non-interactive mode, defaulting to 'No'`);
246
+ return false;
247
+ }
248
+
249
+ try {
250
+ const answer = await inquirer.prompt([
251
+ {
252
+ type: "confirm",
253
+ name: "confirmed",
254
+ message,
255
+ default: false,
256
+ },
257
+ ]);
258
+
259
+ return answer.confirmed;
260
+ } catch (error) {
261
+ // Handle Ctrl+C or other interruptions gracefully
262
+ if (error && typeof error === "object" && "isTtyError" in error) {
263
+ this.warn("Interactive prompt not supported in this environment");
264
+ return false;
265
+ }
266
+
267
+ // For other errors, re-throw
268
+ throw error;
269
+ }
241
270
  }
242
271
 
243
272
  listResults<T>(items: T[], formatter: (item: T) => string) {
@@ -5,3 +5,35 @@ export const META_FILE = "meta.json";
5
5
  export const CONFIG_FILE = "ollie.json";
6
6
  export const OLLIE_SHOP_ASSETS_DIR = "node_modules/.ollie-shop";
7
7
  export const TEMPLATES_DIR = "templates";
8
+
9
+ // Note: Deployment URLs are dynamically generated by the infrastructure
10
+ // Components are deployed to CloudFront (router.url from SST)
11
+ // Functions are deployed to Lambda (managed by AWS)
12
+
13
+ // Error messages with actionable guidance
14
+ export const ERROR_MESSAGES = {
15
+ DEPLOYMENT_TIMEOUT:
16
+ "⏱️ Deployment timed out after 5 minutes. This may indicate a network issue or resource constraints.",
17
+ BUILD_FAILED:
18
+ "❌ Build failed. Check the build logs above for specific error details.",
19
+ BUILD_VALIDATION_FAILED:
20
+ "❌ Build validation failed. Ensure your code meets the required standards.",
21
+ UNKNOWN_ERROR:
22
+ "❌ An unexpected error occurred. Please try again or contact support if the issue persists.",
23
+ COMPONENT_ID_REQUIRED:
24
+ "Component ID is required for deployment. Use: ollieshop component deploy --id <component-id>",
25
+ FUNCTION_ID_REQUIRED:
26
+ "Function ID is required for deployment. Use: ollieshop function deploy --id <function-id>",
27
+ } as const;
28
+
29
+ // Note: Build status messages are available from @ollie-shop/core
30
+ // Use getBuildProgressMessage() from core instead of duplicating
31
+
32
+ // Deployment settings
33
+ export const DEPLOYMENT_SETTINGS = {
34
+ DEFAULT_POLL_INTERVAL_MS: 2000,
35
+ DEFAULT_MAX_WAIT_MS: 300000, // 5 minutes
36
+ PROGRESS_UPDATE_INTERVAL_MS: 1000,
37
+ ESTIMATED_BUILD_DURATION_MS: 30000, // 30 seconds
38
+ MAX_PROGRESS_BEFORE_COMPLETION: 0.95,
39
+ } as const;