@platformatic/service 0.20.0 → 0.21.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/.taprc CHANGED
@@ -1,2 +1,2 @@
1
- timeout: 160
2
- coverage: false
1
+ timeout: 500
2
+ coverage: false
@@ -3,14 +3,17 @@
3
3
  "hostname": "127.0.0.1",
4
4
  "port": 0,
5
5
  "logger": {
6
- "level": "info"
6
+ "level": "info",
7
+ "name": "hello server"
7
8
  }
8
9
  },
9
10
  "plugins": {
10
- "paths": ["./plugin.js"]
11
+ "paths": ["./plugin.js"],
12
+ "hotReload": false
11
13
  },
12
14
  "service": {
13
15
  "openapi": true
14
16
  },
15
- "metrics": false
17
+ "metrics": false,
18
+ "watch": false
16
19
  }
@@ -3,15 +3,18 @@
3
3
  "hostname": "127.0.0.1",
4
4
  "port": 0,
5
5
  "logger": {
6
- "level": "info"
6
+ "level": "info",
7
+ "name": "hello client"
7
8
  }
8
9
  },
9
10
  "plugins": {
10
- "paths": ["./plugin.js"]
11
+ "paths": ["./plugin.js"],
12
+ "hotReload": false
11
13
  },
12
14
  "clients": [{
13
15
  "path": "./hello",
14
16
  "url": "{PLT_CLIENT_URL}"
15
17
  }],
16
- "metrics": false
18
+ "metrics": false,
19
+ "watch": false
17
20
  }
@@ -3,16 +3,19 @@
3
3
  "hostname": "127.0.0.1",
4
4
  "port": 0,
5
5
  "logger": {
6
- "level": "info"
6
+ "level": "info",
7
+ "name": "hello client ts"
7
8
  }
8
9
  },
9
10
  "plugins": {
10
11
  "paths": ["./plugin.ts"],
11
- "typescript": true
12
+ "typescript": true,
13
+ "hotReload": false
12
14
  },
13
15
  "clients": [{
14
16
  "path": "./hello",
15
17
  "url": "{PLT_CLIENT_URL}"
16
18
  }],
17
- "metrics": false
19
+ "metrics": false,
20
+ "watch": false
18
21
  }
package/index.js CHANGED
@@ -4,9 +4,9 @@ const { start } = require('@fastify/restartable')
4
4
  const sandbox = require('fastify-sandbox')
5
5
  const underPressure = require('@fastify/under-pressure')
6
6
  const { schema } = require('./lib/schema')
7
- const ConfigManager = require('./lib/config.js')
7
+ const ConfigManager = require('@platformatic/config')
8
+ const { loadConfig, generateDefaultConfig } = require('./lib/load-config')
8
9
  const { addLoggerToTheConfig, getJSPluginPath, isFileAccessible } = require('./lib/utils')
9
- const loadConfig = require('./lib/load-config')
10
10
  const { isKeyEnabled, deepmerge } = require('@platformatic/utils')
11
11
  const compiler = require('./lib/compile')
12
12
  const { join, dirname, resolve } = require('path')
@@ -58,6 +58,9 @@ async function platformaticService (app, opts, toLoad = []) {
58
58
  if (configManager !== undefined) {
59
59
  app.platformatic.configManager = configManager
60
60
  app.platformatic.config = configManager.current
61
+ /* c8 ignore next 3 */
62
+ } else {
63
+ throw new Error('configManager is required')
61
64
  }
62
65
  }
63
66
 
@@ -167,6 +170,7 @@ async function platformaticService (app, opts, toLoad = []) {
167
170
 
168
171
  platformaticService[Symbol.for('skip-override')] = true
169
172
  platformaticService.schema = schema
173
+ platformaticService.envWhitelist = ['PORT', 'HOSTNAME']
170
174
 
171
175
  function adjustConfigBeforeMerge (cm) {
172
176
  // This function and adjustConfigAfterMerge() are needed because there are
@@ -217,16 +221,27 @@ async function adjustHttpsKeyAndCert (arg) {
217
221
  return arg
218
222
  }
219
223
 
220
- async function buildServer (options, app, ConfigManagerContructor) {
224
+ function defaultConfig (app, source) {
225
+ const res = {
226
+ source,
227
+ ...generateDefaultConfig(),
228
+ allowToWatch: ['.env', ...(app?.allowToWatch || [])],
229
+ envWhitelist: ['PORT', ...(app?.envWhitelist || [])]
230
+ }
231
+
232
+ if (app.schema) {
233
+ res.schema = app.schema
234
+ }
235
+
236
+ return res
237
+ }
238
+
239
+ async function buildServer (options, app) {
221
240
  app = app || platformaticService
222
- ConfigManagerContructor = ConfigManagerContructor || ConfigManager
223
241
 
224
242
  if (!options.configManager) {
225
243
  // instantiate a new config manager from current options
226
- const cm = new ConfigManagerContructor({
227
- source: options,
228
- schema: app?.schema ?? schema
229
- })
244
+ const cm = new ConfigManager(defaultConfig(app, options))
230
245
  await cm.parseAndValidate()
231
246
  const stash = adjustConfigBeforeMerge(cm.current)
232
247
  options = deepmerge({}, options, cm.current)
@@ -310,6 +325,6 @@ module.exports.createServerConfig = createServerConfig
310
325
  module.exports.platformaticService = platformaticService
311
326
  module.exports.addLoggerToTheConfig = addLoggerToTheConfig
312
327
  module.exports.loadConfig = loadConfig
328
+ module.exports.generateConfigManagerConfig = generateDefaultConfig
313
329
  module.exports.tsCompiler = compiler
314
- module.exports.ConfigManager = ConfigManager
315
330
  module.exports.buildStart = buildStart
package/lib/compile.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const { resolve, join, dirname } = require('path')
4
4
  const pino = require('pino')
5
5
  const pretty = require('pino-pretty')
6
- const loadConfig = require('./load-config.js')
6
+ const { loadConfig } = require('./load-config.js')
7
7
  const { isFileAccessible } = require('./utils.js')
8
8
 
9
9
  async function getTSCExecutablePath (cwd) {
@@ -2,9 +2,10 @@
2
2
 
3
3
  const parseArgs = require('minimist')
4
4
  const { access } = require('fs/promises')
5
- const ConfigManager = require('./config.js')
5
+ const ConfigManager = require('@platformatic/config')
6
6
  const deepmerge = require('@fastify/deepmerge')
7
7
  const { findConfigFile } = require('./utils.js')
8
+ const { schema } = require('./schema.js')
8
9
 
9
10
  const ourConfigFiles = [
10
11
  'platformatic.service.json',
@@ -15,7 +16,22 @@ const ourConfigFiles = [
15
16
  'platformatic.service.tml'
16
17
  ]
17
18
 
18
- async function loadConfig (minimistConfig, _args, configOpts = {}, Manager = ConfigManager, configFileNames = ourConfigFiles) {
19
+ function generateDefaultConfig () {
20
+ return {
21
+ schema,
22
+ schemaOptions: {
23
+ useDefaults: true,
24
+ coerceTypes: true,
25
+ allErrors: true,
26
+ strict: false
27
+ }
28
+ }
29
+ }
30
+
31
+ // Unfortunately c8 does not see those on Windows
32
+ /* c8 ignore next 70 */
33
+ async function loadConfig (minimistConfig, _args, defaultConfig, configFileNames = ourConfigFiles) {
34
+ defaultConfig ??= generateDefaultConfig()
19
35
  const args = parseArgs(_args, deepmerge({ all: true })({
20
36
  string: ['allow-env'],
21
37
  boolean: ['hotReload'],
@@ -46,10 +62,9 @@ Error: ${err}
46
62
  process.exit(1)
47
63
  }
48
64
 
49
- const configManager = new Manager({
65
+ const configManager = new ConfigManager({
50
66
  source: args.config,
51
- envWhitelist: [...args.allowEnv.split(',')],
52
- ...configOpts
67
+ ...defaultConfig
53
68
  })
54
69
 
55
70
  const parsingResult = await configManager.parse()
@@ -71,4 +86,5 @@ function printConfigValidationErrors (configManager) {
71
86
  console.table(tabularData, ['path', 'message'])
72
87
  }
73
88
 
74
- module.exports = loadConfig
89
+ module.exports.loadConfig = loadConfig
90
+ module.exports.generateDefaultConfig = generateDefaultConfig
package/lib/start.mjs CHANGED
@@ -2,7 +2,7 @@ import { dirname } from 'path'
2
2
  import { FileWatcher } from '@platformatic/utils'
3
3
  import { buildServer } from '../index.js'
4
4
  import close from 'close-with-grace'
5
- import loadConfig from './load-config.js'
5
+ import { loadConfig, generateDefaultConfig } from './load-config.js'
6
6
  import { compileWatch } from './compile.js'
7
7
  import { addLoggerToTheConfig } from './utils.js'
8
8
 
@@ -10,9 +10,18 @@ import { addLoggerToTheConfig } from './utils.js'
10
10
  // Currently C8 is not reporting it
11
11
  /* c8 ignore start */
12
12
 
13
+ function defaultConfig () {
14
+ const _defaultConfig = generateDefaultConfig()
15
+ return {
16
+ watch: true,
17
+ ..._defaultConfig
18
+ }
19
+ }
20
+
13
21
  export function buildStart (_loadConfig, _buildServer) {
14
22
  return async function start (_args) {
15
- const { configManager, args } = await _loadConfig({}, _args, { watch: true })
23
+ const _defaultConfig = defaultConfig()
24
+ const { configManager, args } = await _loadConfig({}, _args, _defaultConfig)
16
25
 
17
26
  const config = configManager.current
18
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/service",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -26,8 +26,8 @@
26
26
  "standard": "^17.0.0",
27
27
  "strip-ansi": "^7.0.1",
28
28
  "tap": "^16.3.4",
29
- "typescript": "^5.0.0",
30
29
  "tsd": "^0.28.0",
30
+ "typescript": "^5.0.0",
31
31
  "undici": "^5.20.0",
32
32
  "vscode-json-languageservice": "^5.3.0",
33
33
  "why-is-node-running": "^2.2.2",
@@ -63,9 +63,9 @@
63
63
  "pino-pretty": "^10.0.0",
64
64
  "rfdc": "^1.3.0",
65
65
  "ua-parser-js": "^1.0.33",
66
- "@platformatic/config": "0.20.0",
67
- "@platformatic/utils": "0.20.0",
68
- "@platformatic/client": "0.20.0"
66
+ "@platformatic/client": "0.21.0",
67
+ "@platformatic/config": "0.21.0",
68
+ "@platformatic/utils": "0.21.0"
69
69
  },
70
70
  "standard": {
71
71
  "ignore": [
package/service.mjs CHANGED
@@ -34,6 +34,7 @@ export async function runService (argv) {
34
34
  }
35
35
  })
36
36
 
37
+ /* c8 ignore next 4 */
37
38
  if (args.version) {
38
39
  console.log('v' + JSON.parse(await readFile(join(import.meta.url, 'package.json'))).version)
39
40
  process.exit(0)
@@ -361,7 +361,9 @@ test('nested directories', async ({ teardown, equal, same }) => {
361
361
  const config = {
362
362
  server: {
363
363
  hostname: '127.0.0.1',
364
- port: 0
364
+ port: 0,
365
+ // Windows CI is slow
366
+ pluginTimeout: 60 * 1000
365
367
  },
366
368
  service: {
367
369
  openapi: true
@@ -1,16 +1,9 @@
1
- import why from 'why-is-node-running'
2
1
  import { Agent, setGlobalDispatcher } from 'undici'
3
2
  import { on } from 'events'
4
3
  import { execa } from 'execa'
5
4
  import split from 'split2'
6
5
  import { join } from 'desm'
7
-
8
- // This file must be required/imported as the first file
9
- // in the test suite. It sets up the global environment
10
- // to track the open handles via why-is-node-running.
11
- setInterval(() => {
12
- why()
13
- }, 20000).unref()
6
+ import tap from 'tap'
14
7
 
15
8
  setGlobalDispatcher(new Agent({
16
9
  keepAliveTimeout: 10,
@@ -20,6 +13,12 @@ setGlobalDispatcher(new Agent({
20
13
  }
21
14
  }))
22
15
 
16
+ // This should not be needed, but a weird combination
17
+ // of node-tap, Windows, c8 and ESM makes this necessary.
18
+ tap.teardown(() => {
19
+ process.exit(0)
20
+ })
21
+
23
22
  export const cliPath = join(import.meta.url, '..', '..', 'service.mjs')
24
23
 
25
24
  export async function start (...args) {
@@ -19,8 +19,9 @@ function createLoggingPlugin (text, reloaded = false) {
19
19
  `
20
20
  }
21
21
 
22
- test('should watch js files by default', async ({ equal, teardown }) => {
22
+ test('should watch js files by default', async ({ equal, teardown, comment }) => {
23
23
  const tmpDir = await mkdtemp(join(os.tmpdir(), 'watch-'))
24
+ comment(`using ${tmpDir}`)
24
25
  const pluginFilePath = join(tmpDir, 'plugin.js')
25
26
  const configFilePath = join(tmpDir, 'platformatic.service.json')
26
27
 
@@ -44,6 +45,8 @@ test('should watch js files by default', async ({ equal, teardown }) => {
44
45
  ])
45
46
 
46
47
  const { child, url } = await start('-c', configFilePath)
48
+ child.stdout.pipe(process.stderr)
49
+ child.stderr.pipe(process.stderr)
47
50
  teardown(() => child.kill('SIGINT'))
48
51
 
49
52
  await writeFile(pluginFilePath, createLoggingPlugin('v2', true))
@@ -5,28 +5,22 @@ const { test } = require('tap')
5
5
  const { buildServer } = require('..')
6
6
  const { join } = require('path')
7
7
  const { request } = require('undici')
8
- const ConfigManager = require('../lib/config')
9
8
  const { compile } = require('../lib/compile')
10
9
  const { rmdir } = require('fs/promises')
11
10
 
12
- class NoLogConfigManager extends ConfigManager {
13
- _transformConfig () {
14
- super._transformConfig()
15
- this.current.server.logger.level = 'error'
16
- }
17
- }
18
-
19
- test('client is loaded', async ({ teardown, equal, pass, same }) => {
20
- const server1 = await buildServer(join(__dirname, '..', 'fixtures', 'hello', 'platformatic.service.json'), undefined, NoLogConfigManager)
21
- teardown(server1.stop)
11
+ test('client is loaded', async ({ teardown, equal, pass, same, comment }) => {
12
+ const server1 = await buildServer(join(__dirname, '..', 'fixtures', 'hello', 'platformatic.service.json'))
22
13
  await server1.listen()
23
14
 
24
15
  process.env.PLT_CLIENT_URL = server1.url
25
16
 
26
- const server2 = await buildServer(join(__dirname, '..', 'fixtures', 'hello-client', 'platformatic.service.json'), undefined, NoLogConfigManager)
27
- teardown(server2.stop)
28
- await server2.listen()
17
+ const server2 = await buildServer(join(__dirname, '..', 'fixtures', 'hello-client', 'platformatic.service.json'))
29
18
 
19
+ teardown(async () => {
20
+ await server2.stop()
21
+ await server1.stop()
22
+ })
23
+ await server2.listen()
30
24
  const res = await request(`${server2.url}/`)
31
25
  equal(res.statusCode, 200, 'status code')
32
26
  const data = await res.body.json()
@@ -34,8 +28,7 @@ test('client is loaded', async ({ teardown, equal, pass, same }) => {
34
28
  })
35
29
 
36
30
  test('client is loaded (ts)', async ({ teardown, equal, pass, same }) => {
37
- const server1 = await buildServer(join(__dirname, '..', 'fixtures', 'hello', 'platformatic.service.json'), undefined, NoLogConfigManager)
38
- teardown(server1.stop)
31
+ const server1 = await buildServer(join(__dirname, '..', 'fixtures', 'hello', 'platformatic.service.json'))
39
32
  await server1.listen()
40
33
 
41
34
  process.env.PLT_CLIENT_URL = server1.url
@@ -48,8 +41,11 @@ test('client is loaded (ts)', async ({ teardown, equal, pass, same }) => {
48
41
 
49
42
  await compile(targetDir)
50
43
 
51
- const server2 = await buildServer(join(targetDir, 'platformatic.service.json'), undefined, NoLogConfigManager)
52
- teardown(server2.stop)
44
+ const server2 = await buildServer(join(targetDir, 'platformatic.service.json'))
45
+ teardown(async () => {
46
+ await server2.stop()
47
+ await server1.stop()
48
+ })
53
49
  await server2.listen()
54
50
 
55
51
  const res = await request(`${server2.url}/`)
@@ -2,7 +2,7 @@
2
2
 
3
3
  require('./helper')
4
4
  const { test } = require('tap')
5
- const { buildServer, ConfigManager } = require('..')
5
+ const { buildServer } = require('..')
6
6
  const { request } = require('undici')
7
7
  const { join } = require('path')
8
8
  const os = require('os')
@@ -226,69 +226,6 @@ test('config is adjusted to handle custom loggers', async (t) => {
226
226
  t.equal(called, true)
227
227
  })
228
228
 
229
- test('custom ConfigManager', async ({ teardown, equal, pass, same }) => {
230
- const file = join(os.tmpdir(), `${process.pid}-2.js`)
231
-
232
- await writeFile(file, `
233
- module.exports = async function (app, options) {
234
- app.get('/', () => options.message)
235
- }`)
236
-
237
- class MyConfigManager extends ConfigManager {
238
- _transformConfig () {
239
- super._transformConfig.call(this)
240
- this.current.plugins = {
241
- paths: [{
242
- path: file,
243
- options: {
244
- message: 'hello'
245
- }
246
- }]
247
- }
248
- }
249
- }
250
-
251
- const server = await buildServer({
252
- server: {
253
- hostname: '127.0.0.1',
254
- port: 0
255
- },
256
- metrics: false
257
- }, null, MyConfigManager)
258
- teardown(server.stop)
259
- await server.listen()
260
-
261
- {
262
- const res = await request(`${server.url}/`)
263
- equal(res.statusCode, 200, 'add status code')
264
- same(await res.body.text(), 'hello', 'response')
265
- }
266
-
267
- await server.app.platformatic.configManager.update({
268
- server: {
269
- hostname: '127.0.0.1',
270
- port: 0
271
- },
272
- plugins: {
273
- paths: [{
274
- path: file,
275
- options: {
276
- message: 'ciao mondo'
277
- }
278
- }]
279
- },
280
- metrics: false
281
- })
282
-
283
- await server.restart()
284
-
285
- {
286
- const res = await request(`${server.url}/`)
287
- equal(res.statusCode, 200, 'add status code')
288
- same(await res.body.text(), 'hello', 'response')
289
- }
290
- })
291
-
292
229
  test('config reloads', async ({ teardown, equal, pass, same }) => {
293
230
  const file = join(os.tmpdir(), `${process.pid}-1.js`)
294
231
 
@@ -9,5 +9,6 @@
9
9
  "plugins": {
10
10
  "paths": ["routes"],
11
11
  "typescript": true
12
- }
13
- }
12
+ },
13
+ "watch": false
14
+ }
@@ -9,5 +9,6 @@
9
9
  "plugins": {
10
10
  "paths": ["plugin.ts"],
11
11
  "typescript": true
12
- }
12
+ },
13
+ "watch": false
13
14
  }
@@ -4,10 +4,12 @@
4
4
  "level": "info"
5
5
  },
6
6
  "hostname": "127.0.0.1",
7
- "port": "0"
7
+ "port": "0",
8
+ "pluginTimeout": 60000
8
9
  },
9
10
  "plugins": {
10
11
  "paths": ["plugin.ts"],
11
12
  "typescript": false
12
- }
13
+ },
14
+ "watch": false
13
15
  }
package/test/helper.js CHANGED
@@ -1,14 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const why = require('why-is-node-running')
4
3
  const { Agent, setGlobalDispatcher } = require('undici')
5
-
6
- // This file must be required/imported as the first file
7
- // in the test suite. It sets up the global environment
8
- // to track the open handles via why-is-node-running.
9
- setInterval(() => {
10
- why()
11
- }, 20000).unref()
4
+ const tap = require('tap')
12
5
 
13
6
  const agent = new Agent({
14
7
  keepAliveTimeout: 10,
@@ -17,8 +10,15 @@ const agent = new Agent({
17
10
  rejectUnauthorized: false
18
11
  }
19
12
  })
13
+
20
14
  setGlobalDispatcher(agent)
21
15
 
16
+ // This should not be needed, but a weird combination
17
+ // of node-tap, Windows, c8 and ESM makes this necessary.
18
+ tap.teardown(() => {
19
+ process.exit(0)
20
+ })
21
+
22
22
  function buildConfig (options) {
23
23
  const base = {
24
24
  server: {}
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { mkdtempSync, writeFileSync } = require('fs')
3
+ const { mkdtemp, writeFile } = require('fs/promises')
4
4
  const { tmpdir } = require('os')
5
5
  const { isAbsolute, join, relative } = require('path')
6
6
  const selfCert = require('self-cert')
@@ -9,17 +9,21 @@ const { Agent, setGlobalDispatcher, request } = require('undici')
9
9
  const { buildServer } = require('..')
10
10
  const { buildConfig } = require('./helper')
11
11
 
12
- test('supports https options', async ({ teardown, equal, same, plan }) => {
12
+ test('supports https options', async ({ teardown, equal, same, plan, comment }) => {
13
13
  plan(7)
14
14
 
15
15
  const { certificate, privateKey } = selfCert({})
16
- const tmpDir = mkdtempSync(join(tmpdir(), 'plt-service-https-test-'))
16
+ const localDir = tmpdir()
17
+ comment(`system tmpdir ${localDir}`)
18
+ const tmpDir = await mkdtemp(join(localDir, 'plt-service-https-test-'))
19
+ comment(`writing in ${tmpDir}`)
17
20
  const privateKeyPath = join(tmpDir, 'plt.key')
18
21
  const certificatePath = join(tmpDir, 'plt.cert')
19
- const certificateRelativePath = relative(__dirname, certificatePath)
22
+ const certificateRelativePath = relative(process.cwd(), certificatePath)
23
+ comment(`certificate relative path ${certificateRelativePath}`)
20
24
 
21
- writeFileSync(privateKeyPath, privateKey)
22
- writeFileSync(certificatePath, certificate)
25
+ await writeFile(privateKeyPath, privateKey)
26
+ await writeFile(certificatePath, certificate)
23
27
 
24
28
  setGlobalDispatcher(new Agent({
25
29
  connect: {
package/lib/config.js DELETED
@@ -1,23 +0,0 @@
1
- 'use strict'
2
-
3
- const ConfigManager = require('@platformatic/config')
4
- const { schema } = require('./schema')
5
-
6
- class ServiceConfigManager extends ConfigManager {
7
- constructor (opts) {
8
- super({
9
- ...opts,
10
- schema: opts.schema || schema,
11
- schemaOptions: {
12
- useDefaults: true,
13
- coerceTypes: true,
14
- allErrors: true,
15
- strict: false
16
- },
17
- allowToWatch: ['.env'],
18
- envWhitelist: ['PORT', ...(opts.envWhitelist || [])]
19
- })
20
- }
21
- }
22
-
23
- module.exports = ServiceConfigManager