massimo-cli 0.3.0 → 0.4.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/index.js CHANGED
@@ -4,7 +4,7 @@ import { access, mkdir, readFile, rm, writeFile } from 'fs/promises'
4
4
  import graphql from 'graphql'
5
5
  import helpMe from 'help-me'
6
6
  import parseArgs from 'minimist'
7
- import { join } from 'path'
7
+ import { join, dirname } from 'path'
8
8
  import pino from 'pino'
9
9
  import pinoPretty from 'pino-pretty'
10
10
  import { getGlobalDispatcher, interceptors, request } from 'undici'
@@ -43,6 +43,35 @@ export async function createDirectory (path, empty = false) {
43
43
  return mkdir(path, { recursive: true, maxRetries: 10, retryDelay: 1000 })
44
44
  }
45
45
 
46
+ export async function detectModuleFormat (folder, explicitFormat) {
47
+ if (explicitFormat) {
48
+ if (explicitFormat === 'esm' || explicitFormat === 'cjs') {
49
+ return explicitFormat
50
+ }
51
+ throw new Error(
52
+ `Invalid module format: ${explicitFormat}. Valid values are 'esm' or 'cjs'`
53
+ )
54
+ }
55
+ let currentDir = folder
56
+ while (currentDir !== dirname(currentDir)) {
57
+ const packageJsonPath = join(currentDir, 'package.json')
58
+ if (await isFileAccessible(packageJsonPath)) {
59
+ try {
60
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'))
61
+ if (packageJson.type === 'module') return 'esm'
62
+ // If no type field or any other value, it's CommonJS per Node.js defaults
63
+ return 'cjs'
64
+ } catch (err) {
65
+ // If we can't parse it, continue searching
66
+ }
67
+ }
68
+ currentDir = dirname(currentDir)
69
+ }
70
+
71
+ // Default to ESM
72
+ return 'esm'
73
+ }
74
+
46
75
  async function writeOpenAPIClient (
47
76
  folder,
48
77
  name,
@@ -58,17 +87,23 @@ async function writeOpenAPIClient (
58
87
  typesComment,
59
88
  logger,
60
89
  withCredentials,
61
- propsOptional
90
+ propsOptional,
91
+ moduleFormat
62
92
  ) {
63
93
  await createDirectory(folder)
64
94
 
65
95
  // TODO deal with yaml
66
96
  const schema = parseFile(text)
67
97
  if (!schema) {
68
- throw new Error('Cannot parse OpenAPI file. Please make sure is a JSON or a YAML file.')
98
+ throw new Error(
99
+ 'Cannot parse OpenAPI file. Please make sure is a JSON or a YAML file.'
100
+ )
69
101
  }
70
102
  if (!typesOnly) {
71
- await writeFile(join(folder, `${name}.openapi.json`), JSON.stringify(schema, null, 2))
103
+ await writeFile(
104
+ join(folder, `${name}.openapi.json`),
105
+ JSON.stringify(schema, null, 2)
106
+ )
72
107
  }
73
108
 
74
109
  if (isFrontend) {
@@ -80,7 +115,7 @@ async function writeOpenAPIClient (
80
115
  language,
81
116
  logger,
82
117
  withCredentials,
83
- propsOptional
118
+ propsOptional,
84
119
  })
85
120
  await writeFile(join(folder, `${name}-types.d.mts`), types)
86
121
  if (generateImplementation) {
@@ -96,30 +131,54 @@ async function writeOpenAPIClient (
96
131
  optionalHeaders,
97
132
  validateResponse,
98
133
  typesComment,
99
- propsOptional
134
+ propsOptional,
135
+ moduleFormat,
100
136
  })
101
- await writeFile(join(folder, `${name}.d.mts`), types)
137
+ const typeExt = moduleFormat === 'esm' ? 'd.mts' : 'd.cts'
138
+ const implExt = moduleFormat === 'esm' ? 'mjs' : 'cjs'
139
+ await writeFile(join(folder, `${name}.${typeExt}`), types)
102
140
  if (generateImplementation) {
103
- await writeFile(join(folder, `${name}.mjs`), implementation)
141
+ await writeFile(join(folder, `${name}.${implExt}`), implementation)
104
142
  }
105
143
 
106
144
  if (!typesOnly) {
107
- await writeFile(join(folder, 'package.json'), getPackageJSON({ name, generateImplementation }))
145
+ await writeFile(
146
+ join(folder, 'package.json'),
147
+ getPackageJSON({ name, generateImplementation, moduleFormat })
148
+ )
108
149
  }
109
150
  }
110
151
  }
111
152
 
112
- async function writeGraphQLClient (folder, name, schema, url, generateImplementation) {
153
+ async function writeGraphQLClient (
154
+ folder,
155
+ name,
156
+ schema,
157
+ url,
158
+ generateImplementation,
159
+ moduleFormat
160
+ ) {
113
161
  await createDirectory(folder, { recursive: true })
114
- const { types, implementation } = processGraphQL({ schema, name, folder, url })
162
+ const { types, implementation } = processGraphQL({
163
+ schema,
164
+ name,
165
+ folder,
166
+ url,
167
+ moduleFormat,
168
+ })
115
169
  const clientSchema = graphql.buildClientSchema(schema)
116
170
  const sdl = graphql.printSchema(clientSchema)
171
+ const typeExt = moduleFormat === 'esm' ? 'd.mts' : 'd.cts'
172
+ const implExt = moduleFormat === 'esm' ? 'mjs' : 'cjs'
117
173
  await writeFile(join(folder, `${name}.schema.graphql`), sdl)
118
- await writeFile(join(folder, `${name}.d.mts`), types)
174
+ await writeFile(join(folder, `${name}.${typeExt}`), types)
119
175
  if (generateImplementation) {
120
- await writeFile(join(folder, `${name}.mjs`), implementation)
176
+ await writeFile(join(folder, `${name}.${implExt}`), implementation)
121
177
  }
122
- await writeFile(join(folder, 'package.json'), getPackageJSON({ name, generateImplementation }))
178
+ await writeFile(
179
+ join(folder, 'package.json'),
180
+ getPackageJSON({ name, generateImplementation, moduleFormat })
181
+ )
123
182
  }
124
183
 
125
184
  async function downloadAndWriteOpenAPI (
@@ -139,7 +198,8 @@ async function downloadAndWriteOpenAPI (
139
198
  typesComment,
140
199
  withCredentials,
141
200
  propsOptional,
142
- retryTimeoutMs
201
+ retryTimeoutMs,
202
+ moduleFormat
143
203
  ) {
144
204
  logger.debug(`Trying to download OpenAPI schema from ${url}`)
145
205
  let requestOptions
@@ -152,7 +212,9 @@ async function downloadAndWriteOpenAPI (
152
212
  }
153
213
 
154
214
  const dispatcher = retryTimeoutMs
155
- ? getGlobalDispatcher().compose([interceptors.retry({ minTimeout: retryTimeoutMs })])
215
+ ? getGlobalDispatcher().compose([
216
+ interceptors.retry({ minTimeout: retryTimeoutMs })
217
+ ])
156
218
  : undefined
157
219
  const res = await request(url, { ...requestOptions, dispatcher })
158
220
  if (res.statusCode === 200) {
@@ -174,7 +236,8 @@ async function downloadAndWriteOpenAPI (
174
236
  typesComment,
175
237
  logger,
176
238
  withCredentials,
177
- propsOptional
239
+ propsOptional,
240
+ moduleFormat
178
241
  )
179
242
  /* c8 ignore next 3 */
180
243
  } catch (err) {
@@ -188,7 +251,14 @@ async function downloadAndWriteOpenAPI (
188
251
  return false
189
252
  }
190
253
 
191
- async function downloadAndWriteGraphQL (logger, url, folder, name, generateImplementation) {
254
+ async function downloadAndWriteGraphQL (
255
+ logger,
256
+ url,
257
+ folder,
258
+ name,
259
+ generateImplementation,
260
+ moduleFormat
261
+ ) {
192
262
  logger.debug(`Trying to download GraphQL schema from ${url}`)
193
263
  const query = graphql.getIntrospectionQuery()
194
264
  const res = await request(url, {
@@ -198,7 +268,7 @@ async function downloadAndWriteGraphQL (logger, url, folder, name, generateImple
198
268
  },
199
269
  body: JSON.stringify({
200
270
  query
201
- })
271
+ }),
202
272
  })
203
273
 
204
274
  const text = await res.body.text()
@@ -208,7 +278,14 @@ async function downloadAndWriteGraphQL (logger, url, folder, name, generateImple
208
278
  }
209
279
 
210
280
  const { data: schema } = JSON.parse(text)
211
- await writeGraphQLClient(folder, name, schema, url, generateImplementation)
281
+ await writeGraphQLClient(
282
+ folder,
283
+ name,
284
+ schema,
285
+ url,
286
+ generateImplementation,
287
+ moduleFormat
288
+ )
212
289
  return 'graphql'
213
290
  }
214
291
 
@@ -227,7 +304,8 @@ async function readFromFileAndWrite (
227
304
  language,
228
305
  typesComment,
229
306
  withCredentials,
230
- propsOptional
307
+ propsOptional,
308
+ moduleFormat
231
309
  ) {
232
310
  logger.info(`Trying to read schema from file ${file}`)
233
311
  const text = await readFile(file, 'utf8')
@@ -248,17 +326,28 @@ async function readFromFileAndWrite (
248
326
  typesComment,
249
327
  logger,
250
328
  withCredentials,
251
- propsOptional
329
+ propsOptional,
330
+ moduleFormat
252
331
  )
253
332
  return 'openapi'
254
333
  } catch (err) {
255
- logger.error(err, `Error parsing OpenAPI definition: "${err.message}". Trying with GraphQL`)
334
+ logger.error(
335
+ err,
336
+ `Error parsing OpenAPI definition: "${err.message}". Trying with GraphQL`
337
+ )
256
338
  // try GraphQL
257
339
  const schema = graphql.buildSchema(text)
258
340
  const introspectionResult = graphql.introspectionFromSchema(schema)
259
341
 
260
342
  // dummy URL
261
- await writeGraphQLClient(folder, name, introspectionResult, 'http://localhost:3042/graphql', generateImplementation)
343
+ await writeGraphQLClient(
344
+ folder,
345
+ name,
346
+ introspectionResult,
347
+ 'http://localhost:3042/graphql',
348
+ generateImplementation,
349
+ moduleFormat
350
+ )
262
351
  return 'graphql'
263
352
  }
264
353
  }
@@ -280,7 +369,8 @@ async function downloadAndProcess (options) {
280
369
  typesComment,
281
370
  withCredentials,
282
371
  propsOptional,
283
- retryTimeoutMs
372
+ retryTimeoutMs,
373
+ moduleFormat
284
374
  } = options
285
375
 
286
376
  const generateImplementation = options.generateImplementation
@@ -308,7 +398,8 @@ async function downloadAndProcess (options) {
308
398
  typesComment,
309
399
  withCredentials,
310
400
  propsOptional,
311
- retryTimeoutMs
401
+ retryTimeoutMs,
402
+ moduleFormat
312
403
  )
313
404
  )
314
405
  toTry.push(
@@ -330,14 +421,33 @@ async function downloadAndProcess (options) {
330
421
  typesComment,
331
422
  withCredentials,
332
423
  propsOptional,
333
- retryTimeoutMs
424
+ retryTimeoutMs,
425
+ moduleFormat
334
426
  )
335
427
  )
336
428
  } else if (options.type === 'graphql') {
337
429
  toTry.push(
338
- downloadAndWriteGraphQL.bind(null, logger, url + '/graphql', folder, name, generateImplementation, typesOnly)
430
+ downloadAndWriteGraphQL.bind(
431
+ null,
432
+ logger,
433
+ url + '/graphql',
434
+ folder,
435
+ name,
436
+ generateImplementation,
437
+ moduleFormat
438
+ )
439
+ )
440
+ toTry.push(
441
+ downloadAndWriteGraphQL.bind(
442
+ null,
443
+ logger,
444
+ url,
445
+ folder,
446
+ name,
447
+ generateImplementation,
448
+ moduleFormat
449
+ )
339
450
  )
340
- toTry.push(downloadAndWriteGraphQL.bind(null, logger, url, folder, name, generateImplementation, typesOnly))
341
451
  } else {
342
452
  // add download functions only if it's an URL
343
453
  toTry.push(
@@ -359,11 +469,20 @@ async function downloadAndProcess (options) {
359
469
  typesComment,
360
470
  withCredentials,
361
471
  propsOptional,
362
- retryTimeoutMs
472
+ retryTimeoutMs,
473
+ moduleFormat
363
474
  )
364
475
  )
365
476
  toTry.push(
366
- downloadAndWriteGraphQL.bind(null, logger, url + '/graphql', folder, name, generateImplementation, typesOnly)
477
+ downloadAndWriteGraphQL.bind(
478
+ null,
479
+ logger,
480
+ url + '/graphql',
481
+ folder,
482
+ name,
483
+ generateImplementation,
484
+ moduleFormat
485
+ )
367
486
  )
368
487
  toTry.push(
369
488
  downloadAndWriteOpenAPI.bind(
@@ -384,10 +503,21 @@ async function downloadAndProcess (options) {
384
503
  typesComment,
385
504
  withCredentials,
386
505
  propsOptional,
387
- retryTimeoutMs
506
+ retryTimeoutMs,
507
+ moduleFormat
508
+ )
509
+ )
510
+ toTry.push(
511
+ downloadAndWriteGraphQL.bind(
512
+ null,
513
+ logger,
514
+ url,
515
+ folder,
516
+ name,
517
+ generateImplementation,
518
+ moduleFormat
388
519
  )
389
520
  )
390
- toTry.push(downloadAndWriteGraphQL.bind(null, logger, url, folder, name, generateImplementation, typesOnly))
391
521
  }
392
522
  } else {
393
523
  // add readFromFileAndWrite to the functions only if it's not an URL
@@ -408,7 +538,8 @@ async function downloadAndProcess (options) {
408
538
  language,
409
539
  typesComment,
410
540
  withCredentials,
411
- propsOptional
541
+ propsOptional,
542
+ moduleFormat
412
543
  )
413
544
  )
414
545
  }
@@ -420,18 +551,25 @@ async function downloadAndProcess (options) {
420
551
  }
421
552
  /* c8 ignore next 3 */
422
553
  if (!found) {
423
- throw new Error(`Could not find a valid OpenAPI or GraphQL schema at ${url}`)
554
+ throw new Error(
555
+ `Could not find a valid OpenAPI or GraphQL schema at ${url}`
556
+ )
424
557
  }
425
558
  }
426
559
 
427
- function getPackageJSON ({ name, generateImplementation }) {
560
+ function getPackageJSON ({ name, generateImplementation, moduleFormat }) {
561
+ const isESM = moduleFormat === 'esm'
428
562
  const obj = {
429
563
  name,
430
- types: `./${name}.d.mts`
564
+ types: `./${name}.${isESM ? 'd.mts' : 'd.cts'}`
565
+ }
566
+
567
+ if (isESM) {
568
+ obj.type = 'module'
431
569
  }
432
570
 
433
571
  if (generateImplementation) {
434
- obj.main = `./${name}.mjs`
572
+ obj.main = `./${name}.${isESM ? 'mjs' : 'cjs'}`
435
573
  }
436
574
 
437
575
  return JSON.stringify(obj, null, 2)
@@ -447,7 +585,16 @@ export async function command (argv) {
447
585
  _: [url],
448
586
  ...options
449
587
  } = parseArgs(argv, {
450
- string: ['name', 'folder', 'optional-headers', 'language', 'type', 'url-auth-headers', 'types-comment'],
588
+ string: [
589
+ 'name',
590
+ 'folder',
591
+ 'optional-headers',
592
+ 'language',
593
+ 'type',
594
+ 'url-auth-headers',
595
+ 'types-comment',
596
+ 'module'
597
+ ],
451
598
  boolean: [
452
599
  'typescript',
453
600
  'full-response',
@@ -507,7 +654,7 @@ export async function command (argv) {
507
654
  options.propsOptional = options['props-optional'] ?? true
508
655
 
509
656
  options.optionalHeaders = options['optional-headers']
510
- ? options['optional-headers'].split(',').map(h => h.trim())
657
+ ? options['optional-headers'].split(',').map((h) => h.trim())
511
658
  : []
512
659
 
513
660
  options.validateResponse = options['validate-response']
@@ -516,6 +663,10 @@ export async function command (argv) {
516
663
  options.name = options.isFrontend ? 'api' : 'client'
517
664
  }
518
665
  options.folder = options.folder || join(process.cwd(), options.name)
666
+ options.moduleFormat = await detectModuleFormat(options.folder, options.module)
667
+ if (!options.module) {
668
+ logger.info(`Module format detected: ${options.moduleFormat}`)
669
+ }
519
670
  options.urlAuthHeaders = options['url-auth-headers']
520
671
  options.typesComment = options['types-comment']
521
672
  options.withCredentials = options['with-credentials']
@@ -2,11 +2,11 @@ import CodeBlockWriter from 'code-block-writer'
2
2
  import { UnknownTypeError } from './errors.js'
3
3
  import { capitalize, toJavaScriptName } from './utils.js'
4
4
 
5
- export function processGraphQL ({ schema, name, folder, url }) {
5
+ export function processGraphQL ({ schema, name, folder, url, moduleFormat }) {
6
6
  schema = schema.__schema
7
7
  return {
8
8
  types: generateTypesFromGraphQL({ schema, name }),
9
- implementation: generateImplementationFromGraqhQL({ schema, name, url })
9
+ implementation: generateImplementationFromGraqhQL({ schema, name, url, moduleFormat })
10
10
  }
11
11
  }
12
12
 
@@ -60,8 +60,9 @@ function generateTypesFromGraphQL ({ schema, name }) {
60
60
  return writer.toString()
61
61
  }
62
62
 
63
- function generateImplementationFromGraqhQL ({ name, url }) {
63
+ function generateImplementationFromGraqhQL ({ name, url, moduleFormat }) {
64
64
  const camelcasedName = toJavaScriptName(name)
65
+ const isESM = moduleFormat === 'esm'
65
66
 
66
67
  const writer = new CodeBlockWriter({
67
68
  indentNumberOfSpaces: 2,
@@ -69,27 +70,40 @@ function generateImplementationFromGraqhQL ({ name, url }) {
69
70
  useSingleQuote: true
70
71
  })
71
72
 
72
- writer.writeLine("import { buildGraphQLClient } from 'massimo'")
73
- writer.writeLine("import { join } from 'node:path'")
73
+ if (isESM) {
74
+ writer.writeLine("import { buildGraphQLClient } from 'massimo'")
75
+ writer.writeLine("import { join } from 'node:path'")
76
+ } else {
77
+ writer.writeLine("const { buildGraphQLClient } = require('massimo')")
78
+ writer.writeLine("const { join } = require('node:path')")
79
+ }
74
80
  writer.blankLine()
75
81
 
76
82
  url = new URL(url)
77
83
 
78
84
  const functionName = `generate${capitalize(camelcasedName)}Client`
79
- writer.write(`export async function ${functionName} (opts)`).block(() => {
85
+ const funcDecl = isESM ? `export async function ${functionName} (opts)` : `async function ${functionName} (opts)`
86
+ writer.write(funcDecl).block(() => {
80
87
  writer.writeLine('const url = new URL(opts.url)')
81
88
  writer.writeLine(`url.pathname = '${url.pathname}'`)
82
89
  writer.write('return buildGraphQLClient(').inlineBlock(() => {
83
90
  writer.writeLine("type: 'graphql',")
84
91
  writer.writeLine(`name: '${camelcasedName}',`)
85
- writer.writeLine(`path: join(import.meta.dirname, '${name}.schema.graphql'),`)
92
+ const pathExpr = isESM ? `join(import.meta.dirname, '${name}.schema.graphql')` : `join(__dirname, '${name}.schema.graphql')`
93
+ writer.writeLine(`path: ${pathExpr},`)
86
94
  writer.writeLine('serviceId: opts.serviceId,')
87
95
  writer.writeLine('url: url.toString()')
88
96
  })
89
97
  writer.write(')')
90
98
  })
91
99
  writer.blankLine()
92
- writer.writeLine(`export default ${functionName}`)
100
+ if (isESM) {
101
+ writer.writeLine(`export default ${functionName}`)
102
+ } else {
103
+ writer.writeLine(`module.exports = ${functionName}`)
104
+ writer.writeLine(`module.exports.default = ${functionName}`)
105
+ writer.writeLine(`module.exports.${functionName} = ${functionName}`)
106
+ }
93
107
  return writer.toString()
94
108
  }
95
109
 
@@ -11,7 +11,8 @@ export function processOpenAPI ({
11
11
  optionalHeaders,
12
12
  validateResponse,
13
13
  typesComment,
14
- propsOptional
14
+ propsOptional,
15
+ moduleFormat
15
16
  }) {
16
17
  return {
17
18
  types: generateTypesFromOpenAPI({
@@ -23,12 +24,13 @@ export function processOpenAPI ({
23
24
  typesComment,
24
25
  propsOptional
25
26
  }),
26
- implementation: generateImplementationFromOpenAPI({ name, fullResponse, fullRequest, validateResponse })
27
+ implementation: generateImplementationFromOpenAPI({ name, fullResponse, fullRequest, validateResponse, moduleFormat })
27
28
  }
28
29
  }
29
30
 
30
- function generateImplementationFromOpenAPI ({ name, fullResponse, fullRequest, validateResponse }) {
31
+ function generateImplementationFromOpenAPI ({ name, fullResponse, fullRequest, validateResponse, moduleFormat }) {
31
32
  const camelcasedName = toJavaScriptName(name)
33
+ const isESM = moduleFormat === 'esm'
32
34
 
33
35
  const writer = new CodeBlockWriter({
34
36
  indentNumberOfSpaces: 2,
@@ -36,16 +38,23 @@ function generateImplementationFromOpenAPI ({ name, fullResponse, fullRequest, v
36
38
  useSingleQuote: true
37
39
  })
38
40
 
39
- writer.writeLine("import { buildOpenAPIClient } from 'massimo'")
40
- writer.writeLine("import { join } from 'node:path'")
41
+ if (isESM) {
42
+ writer.writeLine("import { buildOpenAPIClient } from 'massimo'")
43
+ writer.writeLine("import { join } from 'node:path'")
44
+ } else {
45
+ writer.writeLine("const { buildOpenAPIClient } = require('massimo')")
46
+ writer.writeLine("const { join } = require('node:path')")
47
+ }
41
48
  writer.blankLine()
42
49
 
43
50
  const functionName = `generate${capitalize(camelcasedName)}Client`
44
- writer.write(`export async function ${functionName} (opts)`).block(() => {
51
+ const funcDecl = isESM ? `export async function ${functionName} (opts)` : `async function ${functionName} (opts)`
52
+ writer.write(funcDecl).block(() => {
45
53
  writer.write('return buildOpenAPIClient(').inlineBlock(() => {
46
54
  writer.writeLine("type: 'openapi',")
47
55
  writer.writeLine(`name: '${camelcasedName}',`)
48
- writer.writeLine(`path: join(import.meta.dirname, '${name}.openapi.json'),`)
56
+ const pathExpr = isESM ? `join(import.meta.dirname, '${name}.openapi.json')` : `join(__dirname, '${name}.openapi.json')`
57
+ writer.writeLine(`path: ${pathExpr},`)
49
58
  writer.writeLine('url: opts.url,')
50
59
  writer.writeLine('serviceId: opts.serviceId,')
51
60
  writer.writeLine('throwOnError: opts.throwOnError,')
@@ -57,7 +66,13 @@ function generateImplementationFromOpenAPI ({ name, fullResponse, fullRequest, v
57
66
  writer.write(')')
58
67
  })
59
68
  writer.blankLine()
60
- writer.writeLine(`export default ${functionName}`)
69
+ if (isESM) {
70
+ writer.writeLine(`export default ${functionName}`)
71
+ } else {
72
+ writer.writeLine(`module.exports = ${functionName}`)
73
+ writer.writeLine(`module.exports.default = ${functionName}`)
74
+ writer.writeLine(`module.exports.${functionName} = ${functionName}`)
75
+ }
61
76
  return writer.toString()
62
77
  }
63
78
 
@@ -68,7 +83,7 @@ function generateTypesFromOpenAPI ({
68
83
  fullRequest,
69
84
  optionalHeaders,
70
85
  typesComment,
71
- propsOptional
86
+ propsOptional,
72
87
  }) {
73
88
  const camelcasedName = toJavaScriptName(name)
74
89
  const capitalizedName = capitalize(camelcasedName)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "massimo-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A client for HTTP services.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -30,7 +30,7 @@
30
30
  "pino-pretty": "^13.0.0",
31
31
  "undici": "^7.0.0",
32
32
  "yaml": "^2.4.1",
33
- "massimo": "0.3.0"
33
+ "massimo": "0.4.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@platformatic/composer": "3.0.0-alpha.6",