@platformatic/runtime 0.44.0 → 0.45.1

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.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { InjectOptions, LightMyRequestResponse } from 'fastify'
2
+ import { FastifyError } from '@fastify/error'
2
3
 
3
4
  export type pltRuntimeBuildServer = {
4
5
  address: string
@@ -11,3 +12,26 @@ export type pltRuntimeBuildServer = {
11
12
  declare module '@platformatic/runtime' {
12
13
  export function buildServer(opts: object): Promise<pltRuntimeBuildServer>
13
14
  }
15
+
16
+ /**
17
+ * All the errors thrown by the plugin.
18
+ */
19
+ export module errors {
20
+ export const RuntimeExitedError: () => FastifyError
21
+ export const UnknownRuntimeAPICommandError: (command: string) => FastifyError
22
+ export const ServiceNotFoundError: (id: string) => FastifyError
23
+ export const ServiceNotStartedError: (id: string) => FastifyError
24
+ export const FailedToRetrieveOpenAPISchemaError: (id: string, error: string) => FastifyError
25
+ export const ApplicationAlreadyStartedError: () => FastifyError
26
+ export const ApplicationNotStartedError: () => FastifyError
27
+ export const ConfigPathMustBeStringError: () => FastifyError
28
+ export const NoConfigFileFoundError: (id: string) => FastifyError
29
+ export const InvalidEntrypointError: (entrypoint: string) => FastifyError
30
+ export const MissingDependencyError: (dependency: string) => FastifyError
31
+ export const InspectAndInspectBrkError: () => FastifyError
32
+ export const InspectorPortError: () => FastifyError
33
+ export const InspectorHostError: () => FastifyError
34
+ export const CannotMapSpecifierToAbsolutePathError: (specifier: string) => FastifyError
35
+ export const NodeInspectorFlagsNotSupportedError: () => FastifyError
36
+ }
37
+
package/index.js CHANGED
@@ -5,6 +5,7 @@ const { start, startCommand } = require('./lib/start')
5
5
  const RuntimeApi = require('./lib/api')
6
6
  const { compile } = require('./lib/compile')
7
7
  const { loadConfig } = require('./lib/load-config')
8
+ const errors = require('./lib/errors')
8
9
 
9
10
  module.exports.buildServer = buildServer
10
11
  module.exports.platformaticRuntime = platformaticRuntime
@@ -14,3 +15,4 @@ module.exports.start = start
14
15
  module.exports.startCommand = startCommand
15
16
  module.exports.compile = compile
16
17
  module.exports.loadConfig = loadConfig
18
+ module.exports.errors = errors
package/index.test-d.ts CHANGED
@@ -1,18 +1,43 @@
1
1
  import { expectError, expectType } from 'tsd';
2
2
  import { LightMyRequestResponse } from 'fastify';
3
- import { pltRuntimeBuildServer } from '.';
3
+ import { pltRuntimeBuildServer, errors } from '.';
4
+ import { FastifyError } from '@fastify/error'
4
5
 
5
6
  const server: pltRuntimeBuildServer = {
6
7
  address: 'localhost',
7
8
  port: 3000,
8
- restart: async () => {},
9
- stop: async () => {},
9
+ restart: async () => { },
10
+ stop: async () => { },
10
11
  inject: async () => ({} as LightMyRequestResponse),
11
12
  };
12
13
 
13
14
  expectType<pltRuntimeBuildServer>(server);
14
- expectError<pltRuntimeBuildServer>({...server, address: 42 });
15
- expectError<pltRuntimeBuildServer>({...server, port: 'WRONG' });
16
- expectError<pltRuntimeBuildServer>({...server, restart: 'WRONG' });
17
- expectError<pltRuntimeBuildServer>({...server, stop: 'WRONG' });
18
- expectError<pltRuntimeBuildServer>({...server, inject: 'WRONG' });
15
+ expectError<pltRuntimeBuildServer>({ ...server, address: 42 });
16
+ expectError<pltRuntimeBuildServer>({ ...server, port: 'WRONG' });
17
+ expectError<pltRuntimeBuildServer>({ ...server, restart: 'WRONG' });
18
+ expectError<pltRuntimeBuildServer>({ ...server, stop: 'WRONG' });
19
+ expectError<pltRuntimeBuildServer>({ ...server, inject: 'WRONG' });
20
+
21
+ // Errors
22
+ type ErrorWithNoParams = () => FastifyError
23
+ type ErrorWithOneParam = (param: string) => FastifyError
24
+ type ErrorWithOneAnyParam = (param: string) => FastifyError
25
+ type ErrorWithTwoParams = (param1: string, param2: string) => FastifyError
26
+
27
+ expectType<ErrorWithNoParams>(errors.RuntimeExitedError)
28
+ expectType<ErrorWithOneParam>(errors.UnknownRuntimeAPICommandError)
29
+ expectType<ErrorWithOneParam>(errors.ServiceNotFoundError)
30
+ expectType<ErrorWithOneParam>(errors.ServiceNotStartedError)
31
+ expectType<ErrorWithTwoParams>(errors.FailedToRetrieveOpenAPISchemaError)
32
+ expectType<ErrorWithNoParams>(errors.ApplicationAlreadyStartedError)
33
+ expectType<ErrorWithNoParams>(errors.ApplicationNotStartedError)
34
+ expectType<ErrorWithNoParams>(errors.ConfigPathMustBeStringError)
35
+ expectType<ErrorWithOneParam>(errors.NoConfigFileFoundError)
36
+ expectType<ErrorWithOneParam>(errors.InvalidEntrypointError)
37
+ expectType<ErrorWithOneParam>(errors.MissingDependencyError)
38
+ expectType<ErrorWithNoParams>(errors.InspectAndInspectBrkError)
39
+ expectType<ErrorWithNoParams>(errors.InspectorPortError)
40
+ expectType<ErrorWithNoParams>(errors.InspectorHostError)
41
+ expectType<ErrorWithOneParam>(errors.CannotMapSpecifierToAbsolutePathError)
42
+ expectType<ErrorWithNoParams>(errors.NodeInspectorFlagsNotSupportedError)
43
+
package/lib/api-client.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  const { once, EventEmitter } = require('node:events')
4
4
  const { randomUUID } = require('node:crypto')
5
+ const errors = require('./errors')
5
6
 
6
7
  const MAX_LISTENERS_COUNT = 100
7
8
 
@@ -72,7 +73,7 @@ class RuntimeApiClient extends EventEmitter {
72
73
  )
73
74
 
74
75
  if (this.#exitCode !== undefined) {
75
- throw new Error('The runtime exited before the operation completed')
76
+ throw new errors.RuntimeExitedError()
76
77
  }
77
78
 
78
79
  const { error, data } = message
package/lib/api.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const FastifyUndiciDispatcher = require('fastify-undici-dispatcher')
4
4
  const { Agent, setGlobalDispatcher } = require('undici')
5
5
  const { PlatformaticApp } = require('./app')
6
+ const errors = require('./errors')
6
7
 
7
8
  class RuntimeApi {
8
9
  #services
@@ -96,7 +97,7 @@ class RuntimeApi {
96
97
  return this.#inject(params)
97
98
  /* c8 ignore next 2 */
98
99
  default:
99
- throw new Error(`Unknown Runtime API command: '${command}'`)
100
+ throw new errors.UnknownRuntimeAPICommandError(command)
100
101
  }
101
102
  }
102
103
 
@@ -160,7 +161,7 @@ class RuntimeApi {
160
161
  const service = this.#services.get(id)
161
162
 
162
163
  if (!service) {
163
- throw new Error(`Service with id '${id}' not found`)
164
+ throw new errors.ServiceNotFoundError(id)
164
165
  }
165
166
 
166
167
  return service
@@ -179,7 +180,7 @@ class RuntimeApi {
179
180
 
180
181
  const { config } = service
181
182
  if (!config) {
182
- throw new Error(`Service with id '${id}' is not started`)
183
+ throw new errors.ServiceNotStartedError(id)
183
184
  }
184
185
 
185
186
  return config.configManager.current
@@ -189,7 +190,7 @@ class RuntimeApi {
189
190
  const service = this.#getServiceById(id)
190
191
 
191
192
  if (!service.config) {
192
- throw new Error(`Service with id '${id}' is not started`)
193
+ throw new errors.ServiceNotStartedError(id)
193
194
  }
194
195
 
195
196
  if (typeof service.server.swagger !== 'function') {
@@ -201,7 +202,7 @@ class RuntimeApi {
201
202
  const openapiSchema = service.server.swagger()
202
203
  return openapiSchema
203
204
  } catch (err) {
204
- throw new Error(`Failed to retrieve OpenAPI schema for service with id '${id}': ${err.message}`)
205
+ throw new errors.FailedToRetrieveOpenAPISchemaError(id, err.message)
205
206
  }
206
207
  }
207
208
 
@@ -220,7 +221,7 @@ class RuntimeApi {
220
221
 
221
222
  const serviceStatus = service.getStatus()
222
223
  if (serviceStatus !== 'started') {
223
- throw new Error(`Service with id '${id}' is not started`)
224
+ throw new errors.ServiceNotStartedError(id)
224
225
  }
225
226
 
226
227
  const res = await service.server.inject(injectParams)
package/lib/app.js CHANGED
@@ -6,6 +6,7 @@ const { FileWatcher } = require('@platformatic/utils')
6
6
  const debounce = require('debounce')
7
7
  const { buildServer } = require('./build-server')
8
8
  const { loadConfig } = require('./load-config')
9
+ const errors = require('./errors')
9
10
 
10
11
  class PlatformaticApp {
11
12
  #hotReload
@@ -78,7 +79,7 @@ class PlatformaticApp {
78
79
 
79
80
  async start () {
80
81
  if (this.#started) {
81
- throw new Error('application is already started')
82
+ throw new errors.ApplicationAlreadyStartedError()
82
83
  }
83
84
 
84
85
  this.#started = true
@@ -131,7 +132,7 @@ class PlatformaticApp {
131
132
 
132
133
  async stop () {
133
134
  if (!this.#started) {
134
- throw new Error('application has not been started')
135
+ throw new errors.ApplicationNotStartedError()
135
136
  }
136
137
 
137
138
  await this.#stopFileWatching()
@@ -190,7 +191,7 @@ class PlatformaticApp {
190
191
  if (appConfig._configOverrides instanceof Map) {
191
192
  appConfig._configOverrides.forEach((value, key) => {
192
193
  if (typeof key !== 'string') {
193
- throw new Error('config path must be a string.')
194
+ throw new errors.ConfigPathMustBeStringError()
194
195
  }
195
196
 
196
197
  const parts = key.split('.')
package/lib/config.js CHANGED
@@ -5,6 +5,7 @@ const { closest } = require('fastest-levenshtein')
5
5
  const Topo = require('@hapi/topo')
6
6
  const ConfigManager = require('@platformatic/config')
7
7
  const { schema } = require('./schema')
8
+ const errors = require('./errors')
8
9
 
9
10
  async function _transformConfig (configManager) {
10
11
  const config = configManager.current
@@ -27,7 +28,7 @@ async function _transformConfig (configManager) {
27
28
  const configFilename = mapping.config ?? await ConfigManager.findConfigFile(entryPath)
28
29
 
29
30
  if (typeof configFilename !== 'string') {
30
- throw new Error(`no config file found for service '${id}'`)
31
+ throw new errors.NoConfigFileFoundError(id)
31
32
  }
32
33
 
33
34
  const config = join(entryPath, configFilename)
@@ -61,7 +62,7 @@ async function _transformConfig (configManager) {
61
62
  }
62
63
 
63
64
  if (!hasValidEntrypoint) {
64
- throw new Error(`invalid entrypoint: '${config.entrypoint}' does not exist`)
65
+ throw new errors.InvalidEntrypointError(config.entrypoint)
65
66
  }
66
67
 
67
68
  configManager.current.services = services
@@ -104,6 +105,8 @@ async function parseClientsAndComposer (configManager) {
104
105
  isLocal = false
105
106
  /* c8 ignore next 4 */
106
107
  } catch (err) {
108
+ // The MissingValueError is an error coming from pupa: https://github.com/sindresorhus/pupa#missingvalueerror
109
+ // All other errors are simply rethrown.
107
110
  if (err.name !== 'MissingValueError') {
108
111
  throw err
109
112
  }
@@ -117,7 +120,7 @@ async function parseClientsAndComposer (configManager) {
117
120
 
118
121
  if (isLocal) {
119
122
  if (dependency === undefined) {
120
- throw new Error(missingDependencyErrorMessage(clientName, service, configManager))
123
+ throw new errors.MissingDependencyError(missingDependencyErrorMessage(clientName, service, configManager))
121
124
  }
122
125
  clientUrl = `http://${clientName}.plt.local`
123
126
  dependency.dependents.push(service.id)
@@ -195,8 +198,7 @@ async function parseClientsAndComposer (configManager) {
195
198
 
196
199
  /* c8 ignore next 4 */
197
200
  if (dependency === undefined) {
198
- reject(new Error(missingDependencyErrorMessage(clientName, service, configManager)))
199
- return
201
+ throw new errors.MissingDependencyError(missingDependencyErrorMessage(clientName, service, configManager))
200
202
  }
201
203
 
202
204
  dependency.dependents.push(service.id)
@@ -291,7 +293,7 @@ function parseInspectorOptions (configManager) {
291
293
  inspectFlag = args.inspect
292
294
 
293
295
  if (hasInspectBrk) {
294
- throw new Error('--inspect and --inspect-brk cannot be used together')
296
+ throw new errors.InspectAndInspectBrkError()
295
297
  }
296
298
  } else if (hasInspectBrk) {
297
299
  inspectFlag = args['inspect-brk']
@@ -314,11 +316,11 @@ function parseInspectorOptions (configManager) {
314
316
  port = Number.parseInt(port, 10)
315
317
 
316
318
  if (!(port === 0 || (port >= 1024 && port <= 65535))) {
317
- throw new Error('inspector port must be 0 or in range 1024 to 65535')
319
+ throw new errors.InspectorPortError()
318
320
  }
319
321
 
320
322
  if (!host) {
321
- throw new Error('inspector host cannot be empty')
323
+ throw new errors.InspectorHostError()
322
324
  }
323
325
  }
324
326
 
package/lib/errors.js ADDED
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ const createError = require('@fastify/error')
4
+
5
+ const ERROR_PREFIX = 'PLT_SQL_RUNTIME'
6
+
7
+ module.exports = {
8
+ RuntimeExitedError: createError(`${ERROR_PREFIX}_RUNTIME_EXIT`, 'The runtime exited before the operation completed'),
9
+ UnknownRuntimeAPICommandError: createError(`${ERROR_PREFIX}_UNKNOWN_RUNTIME_API_COMMAND`, 'Unknown Runtime API command "%s"'),
10
+ ServiceNotFoundError: createError(`${ERROR_PREFIX}_SERVICE_NOT_FOUND`, "Service with id '%s' not found"),
11
+ ServiceNotStartedError: createError(`${ERROR_PREFIX}_SERVICE_NOT_STARTED`, "Service with id '%s' is not started"),
12
+ FailedToRetrieveOpenAPISchemaError: createError(`${ERROR_PREFIX}_FAILED_TO_RETRIEVE_OPENAPI_SCHEMA`, 'Failed to retrieve OpenAPI schema for service with id "%s": %s'),
13
+ ApplicationAlreadyStartedError: createError(`${ERROR_PREFIX}_APPLICATION_ALREADY_STARTED`, 'Application is already started'),
14
+ ApplicationNotStartedError: createError(`${ERROR_PREFIX}_APPLICATION_NOT_STARTED`, 'Application has not been started'),
15
+ ConfigPathMustBeStringError: createError(`${ERROR_PREFIX}_CONFIG_PATH_MUST_BE_STRING`, 'Config path must be a string'),
16
+ NoConfigFileFoundError: createError(`${ERROR_PREFIX}_NO_CONFIG_FILE_FOUND`, "No config file found for service '%s'"),
17
+ InvalidEntrypointError: createError(`${ERROR_PREFIX}_INVALID_ENTRYPOINT`, "Invalid entrypoint: '%s' does not exist"),
18
+ MissingDependencyError: createError(`${ERROR_PREFIX}_MISSING_DEPENDENCY`, 'Missing dependency: "%s"'),
19
+ InspectAndInspectBrkError: createError(`${ERROR_PREFIX}_INSPECT_AND_INSPECT_BRK`, '--inspect and --inspect-brk cannot be used together'),
20
+ InspectorPortError: createError(`${ERROR_PREFIX}_INSPECTOR_PORT`, 'Inspector port must be 0 or in range 1024 to 65535'),
21
+ InspectorHostError: createError(`${ERROR_PREFIX}_INSPECTOR_HOST`, 'Inspector host cannot be empty'),
22
+ CannotMapSpecifierToAbsolutePathError: createError(`${ERROR_PREFIX}_CANNOT_MAP_SPECIFIER_TO_ABSOLUTE_PATH`, 'Cannot map "%s" to an absolute path'),
23
+ NodeInspectorFlagsNotSupportedError: createError(`${ERROR_PREFIX}_NODE_INSPECTOR_FLAGS_NOT_SUPPORTED`, 'The Node.js inspector flags are not supported. Please use \'platformatic start --inspect\' instead.')
24
+
25
+ }
package/lib/loader.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createRequire, isBuiltin } from 'node:module'
2
2
  import { dirname, isAbsolute, resolve as pathResolve } from 'node:path'
3
3
  import { fileURLToPath, pathToFileURL } from 'node:url'
4
+ import errors from './errors.js'
4
5
  const isWindows = process.platform === 'win32'
5
6
  let timestamp = process.hrtime.bigint()
6
7
  let port
@@ -54,7 +55,7 @@ function specifierToFileUrl (specifier, referencingModuleId) {
54
55
 
55
56
  /* c8 ignore next 3 */
56
57
  if (!referencingModuleId) {
57
- throw new Error(`cannot map '${specifier}' to an absolute path`)
58
+ throw new errors.CannotMapSpecifierToAbsolutePathError(specifier)
58
59
  }
59
60
 
60
61
  /* c8 ignore next 5 - c8 upgrade marked many existing things as uncovered */
package/lib/start.js CHANGED
@@ -10,6 +10,7 @@ const { loadConfig } = require('./load-config')
10
10
  const { parseInspectorOptions, wrapConfigInRuntimeConfig } = require('./config')
11
11
  const RuntimeApiClient = require('./api-client.js')
12
12
  const { printConfigValidationErrors } = require('@platformatic/config')
13
+ const errors = require('./errors')
13
14
 
14
15
  const kLoaderFile = pathToFileURL(join(__dirname, 'loader.mjs')).href
15
16
  const kWorkerFile = join(__dirname, 'worker.js')
@@ -23,7 +24,7 @@ async function startWithConfig (configManager, env = process.env) {
23
24
  const config = configManager.current
24
25
 
25
26
  if (inspector.url()) {
26
- throw new Error('The Node.js inspector flags are not supported. Please use \'platformatic start --inspect\' instead.')
27
+ throw new errors.NodeInspectorFlagsNotSupportedError()
27
28
  }
28
29
 
29
30
  if (configManager.args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/runtime",
3
- "version": "0.44.0",
3
+ "version": "0.45.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -24,11 +24,12 @@
24
24
  "standard": "^17.1.0",
25
25
  "tsd": "^0.29.0",
26
26
  "typescript": "^5.1.6",
27
- "@platformatic/sql-graphql": "0.44.0",
28
- "@platformatic/sql-mapper": "0.44.0"
27
+ "@platformatic/sql-graphql": "0.45.1",
28
+ "@platformatic/sql-mapper": "0.45.1"
29
29
  },
30
30
  "dependencies": {
31
31
  "@hapi/topo": "^6.0.2",
32
+ "@fastify/error": "^3.2.1",
32
33
  "close-with-grace": "^1.2.0",
33
34
  "commist": "^3.2.0",
34
35
  "debounce": "^1.2.1",
@@ -42,12 +43,12 @@
42
43
  "pino": "^8.14.1",
43
44
  "pino-pretty": "^10.0.0",
44
45
  "undici": "^5.22.1",
45
- "@platformatic/composer": "0.44.0",
46
- "@platformatic/config": "0.44.0",
47
- "@platformatic/db": "0.44.0",
48
- "@platformatic/service": "0.44.0",
49
- "@platformatic/telemetry": "0.44.0",
50
- "@platformatic/utils": "0.44.0"
46
+ "@platformatic/config": "0.45.1",
47
+ "@platformatic/db": "0.45.1",
48
+ "@platformatic/composer": "0.45.1",
49
+ "@platformatic/service": "0.45.1",
50
+ "@platformatic/utils": "0.45.1",
51
+ "@platformatic/telemetry": "0.45.1"
51
52
  },
52
53
  "standard": {
53
54
  "ignore": [
package/test/api.test.js CHANGED
@@ -230,7 +230,7 @@ test('should fail to start running service', async (t) => {
230
230
  await app.startService('with-logger')
231
231
  assert.fail('should have thrown')
232
232
  } catch (err) {
233
- assert.strictEqual(err.message, 'application is already started')
233
+ assert.strictEqual(err.message, 'Application is already started')
234
234
  }
235
235
  })
236
236
 
package/test/app.test.js CHANGED
@@ -65,7 +65,7 @@ test('errors when starting an already started application', async (t) => {
65
65
  await app.start()
66
66
  await assert.rejects(async () => {
67
67
  await app.start()
68
- }, /application is already started/)
68
+ }, /Application is already started/)
69
69
  })
70
70
 
71
71
  test('errors when stopping an already stopped application', async (t) => {
@@ -86,7 +86,7 @@ test('errors when stopping an already stopped application', async (t) => {
86
86
 
87
87
  await assert.rejects(async () => {
88
88
  await app.stop()
89
- }, /application has not been started/)
89
+ }, /Application has not been started/)
90
90
  })
91
91
 
92
92
  test('does not restart while restarting', async (t) => {
@@ -244,7 +244,7 @@ test('supports configuration overrides', async (t) => {
244
244
 
245
245
  await assert.rejects(async () => {
246
246
  await app.start()
247
- }, /config path must be a string/)
247
+ }, /Config path must be a string/)
248
248
  })
249
249
 
250
250
  await t.test('ignores invalid config paths', async (t) => {
@@ -15,7 +15,7 @@ test('throws if no entrypoint is found', async (t) => {
15
15
 
16
16
  await assert.rejects(async () => {
17
17
  await loadConfig({}, ['-c', configFile], platformaticRuntime)
18
- }, /invalid entrypoint: 'invalid' does not exist/)
18
+ }, /Invalid entrypoint: 'invalid' does not exist/)
19
19
  })
20
20
 
21
21
  test('throws if a config file is not found for an individual service', async (t) => {
@@ -23,7 +23,7 @@ test('throws if a config file is not found for an individual service', async (t)
23
23
 
24
24
  await assert.rejects(async () => {
25
25
  await loadConfig({}, ['-c', configFile], platformaticRuntime)
26
- }, /no config file found for service 'docs'/)
26
+ }, /No config file found for service 'docs'/)
27
27
  })
28
28
 
29
29
  test('performs a topological sort on services depending on allowCycles', async (t) => {
@@ -173,7 +173,7 @@ test('parseInspectorOptions()', async (t) => {
173
173
  }
174
174
 
175
175
  parseInspectorOptions(cm)
176
- }, /inspector host cannot be empty/)
176
+ }, /Inspector host cannot be empty/)
177
177
  })
178
178
 
179
179
  await t.test('differentiates valid and invalid ports', () => {
@@ -185,7 +185,7 @@ test('parseInspectorOptions()', async (t) => {
185
185
  }
186
186
 
187
187
  parseInspectorOptions(cm)
188
- }, /inspector port must be 0 or in range 1024 to 65535/)
188
+ }, /Inspector port must be 0 or in range 1024 to 65535/)
189
189
  })
190
190
 
191
191
  const cm = {