@platformatic/service 0.22.0 → 0.23.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/fixtures/hello-client-ts/platformatic.service.json +2 -1
- package/index.js +118 -169
- package/lib/load-config.js +6 -1
- package/lib/plugins/clients.js +12 -0
- package/lib/plugins/cors.js +29 -0
- package/lib/plugins/file-watcher.js +44 -0
- package/lib/plugins/health-check.js +17 -0
- package/lib/plugins/plugins.js +56 -0
- package/lib/plugins/typescript.js +46 -0
- package/lib/root-endpoint/index.js +1 -0
- package/lib/schema.js +8 -1
- package/lib/start.mjs +27 -136
- package/lib/utils.js +2 -2
- package/package.json +9 -8
- package/test/autoload.test.js +77 -59
- package/test/cli/compile.test.mjs +45 -33
- package/test/cli/watch.test.mjs +39 -0
- package/test/clients.test.js +24 -17
- package/test/config.test.js +58 -86
- package/test/cors.test.js +48 -30
- package/test/fixtures/bad-typescript-plugin/platformatic.service.json +3 -1
- package/test/fixtures/typescript-autoload/platformatic.service.json +3 -1
- package/test/fixtures/typescript-plugin/platformatic.service.json +3 -1
- package/test/fixtures/typescript-plugin-nocompile/platformatic.service.json +2 -1
- package/test/graphql.test.js +18 -14
- package/test/healthcheck.test.js +22 -13
- package/test/https.test.js +11 -8
- package/test/lambda.test.js +103 -0
- package/test/load-and-reload-files.test.js +97 -112
- package/test/load-plugin.test.js +8 -4
- package/test/metrics.test.js +59 -39
- package/test/routes.test.js +43 -25
- package/test/utils.test.js +2 -2
- package/test/watch.test.js +182 -0
- /package/lib/{graphql.js → plugins/graphql.js} +0 -0
- /package/lib/{metrics-plugin.js → plugins/metrics.js} +0 -0
- /package/lib/{openapi.js → plugins/openapi.js} +0 -0
- /package/lib/{sandbox-wrapper.js → plugins/sandbox-wrapper.js} +0 -0
package/index.js
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
const underPressure = require('@fastify/under-pressure')
|
|
6
|
-
const { schema } = require('./lib/schema')
|
|
3
|
+
const { readFile } = require('fs/promises')
|
|
4
|
+
|
|
7
5
|
const ConfigManager = require('@platformatic/config')
|
|
8
|
-
const {
|
|
9
|
-
const { addLoggerToTheConfig, getJSPluginPath, isFileAccessible } = require('./lib/utils')
|
|
6
|
+
const { restartable } = require('@fastify/restartable')
|
|
10
7
|
const { isKeyEnabled } = require('@platformatic/utils')
|
|
8
|
+
|
|
11
9
|
const compiler = require('./lib/compile')
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
origin = new RegExp(origin.regexp)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
10
|
+
const setupCors = require('./lib/plugins/cors')
|
|
11
|
+
const setupOpenAPI = require('./lib/plugins/openapi.js')
|
|
12
|
+
const setupGraphQL = require('./lib/plugins/graphql.js')
|
|
13
|
+
const setupClients = require('./lib/plugins/clients')
|
|
14
|
+
const setupMetrics = require('./lib/plugins/metrics')
|
|
15
|
+
const setupTsCompiler = require('./lib/plugins/typescript')
|
|
16
|
+
const setupFileWatcher = require('./lib/plugins/file-watcher')
|
|
17
|
+
const setupHealthCheck = require('./lib/plugins/health-check')
|
|
18
|
+
const loadPlugins = require('./lib/plugins/plugins')
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
}
|
|
20
|
+
const { schema } = require('./lib/schema')
|
|
21
|
+
const { loadConfig, generateDefaultConfig } = require('./lib/load-config')
|
|
22
|
+
const { addLoggerToTheConfig } = require('./lib/utils')
|
|
27
23
|
|
|
28
24
|
async function platformaticService (app, opts, toLoad = []) {
|
|
29
25
|
const configManager = app.platformatic.configManager
|
|
30
26
|
const config = configManager.current
|
|
31
27
|
|
|
32
28
|
if (isKeyEnabled('metrics', config)) {
|
|
33
|
-
app.register(
|
|
29
|
+
app.register(setupMetrics, config.metrics)
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
if (Array.isArray(toLoad)) {
|
|
@@ -39,99 +35,37 @@ async function platformaticService (app, opts, toLoad = []) {
|
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
37
|
|
|
42
|
-
const serviceConfig =
|
|
38
|
+
const serviceConfig = config.service || {}
|
|
43
39
|
|
|
44
|
-
if (serviceConfig
|
|
45
|
-
await setupOpenAPI
|
|
40
|
+
if (isKeyEnabled('openapi', serviceConfig)) {
|
|
41
|
+
await app.register(setupOpenAPI, serviceConfig.openapi)
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
if (serviceConfig
|
|
49
|
-
await setupGraphQL
|
|
44
|
+
if (isKeyEnabled('graphql', serviceConfig)) {
|
|
45
|
+
await app.register(setupGraphQL, serviceConfig.graphql)
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
|
|
53
|
-
app.register(
|
|
54
|
-
url: plugin.url
|
|
55
|
-
})
|
|
48
|
+
if (isKeyEnabled('clients', config)) {
|
|
49
|
+
app.register(setupClients, config.clients)
|
|
56
50
|
}
|
|
57
51
|
|
|
58
52
|
if (config.plugins) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const tsConfigPath = join(dirname(configPath), 'tsconfig.json')
|
|
62
|
-
/* c8 ignore next 21 */
|
|
63
|
-
if (await isFileAccessible(tsConfigPath)) {
|
|
64
|
-
const tsConfig = JSON.parse(await readFile(tsConfigPath, 'utf8'))
|
|
65
|
-
const outDir = resolve(dirname(tsConfigPath), tsConfig.compilerOptions.outDir)
|
|
66
|
-
config.plugins.paths = config.plugins.paths.map((plugin) => {
|
|
67
|
-
if (typeof plugin === 'string') {
|
|
68
|
-
return getJSPluginPath(configPath, plugin, outDir)
|
|
69
|
-
} else {
|
|
70
|
-
return {
|
|
71
|
-
path: getJSPluginPath(configPath, plugin.path, outDir),
|
|
72
|
-
options: plugin.options
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
} else {
|
|
77
|
-
for (const plugin of config.plugins.paths) {
|
|
78
|
-
const path = typeof plugin === 'string' ? plugin : plugin.path
|
|
79
|
-
if (path.endsWith('.ts')) {
|
|
80
|
-
throw new Error(`Cannot load plugin ${path}, tsconfig.json not found`)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
53
|
+
if (config.plugins.typescript) {
|
|
54
|
+
await app.register(setupTsCompiler)
|
|
83
55
|
}
|
|
56
|
+
await app.register(loadPlugins)
|
|
57
|
+
}
|
|
84
58
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// all individual plugin hot reload settings will be overloaded by global hot reload
|
|
88
|
-
/* c8 ignore next 1 */
|
|
89
|
-
const hotReload = config.plugins.hotReload !== false
|
|
90
|
-
const isWatchEnabled = config.watch !== false
|
|
91
|
-
|
|
92
|
-
app.log.debug({ plugins: config.plugins.paths, hotReload, isWatchEnabled }, 'loading plugins')
|
|
93
|
-
|
|
94
|
-
if (isWatchEnabled && hotReload) {
|
|
95
|
-
await app.register(sandbox, {
|
|
96
|
-
path: wrapperPath,
|
|
97
|
-
options: { paths: config.plugins.paths },
|
|
98
|
-
customizeGlobalThis (_globalThis) {
|
|
99
|
-
// Taken from https://github.com/nodejs/undici/blob/fa9fd9066569b6357acacffb806aa804b688c9d8/lib/global.js#L5
|
|
100
|
-
const globalDispatcher = Symbol.for('undici.globalDispatcher.1')
|
|
101
|
-
const dispatcher = globalThis[globalDispatcher]
|
|
102
|
-
/* istanbul ignore else */
|
|
103
|
-
if (dispatcher) {
|
|
104
|
-
_globalThis[globalDispatcher] = dispatcher
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
} else {
|
|
109
|
-
await app.register(require(wrapperPath), { paths: config.plugins.paths })
|
|
110
|
-
}
|
|
59
|
+
if (isKeyEnabled('watch', config)) {
|
|
60
|
+
await app.register(setupFileWatcher, { onFilesUpdated })
|
|
111
61
|
}
|
|
112
62
|
|
|
113
|
-
// Enable CORS
|
|
114
63
|
if (config.server.cors) {
|
|
115
|
-
|
|
116
|
-
if (Array.isArray(origin)) {
|
|
117
|
-
origin = origin.map(originToRegexp)
|
|
118
|
-
} else {
|
|
119
|
-
origin = originToRegexp(origin)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
config.server.cors.origin = origin
|
|
123
|
-
|
|
124
|
-
app.register(require('@fastify/cors'), config.server.cors)
|
|
64
|
+
app.register(setupCors, config.server.cors)
|
|
125
65
|
}
|
|
126
66
|
|
|
127
67
|
if (isKeyEnabled('healthCheck', config.server)) {
|
|
128
|
-
|
|
129
|
-
app.register(underPressure, {
|
|
130
|
-
exposeStatusRoute: '/status',
|
|
131
|
-
healthCheckInterval: healthCheck.interval !== undefined ? healthCheck.interval : 5000,
|
|
132
|
-
...healthCheck,
|
|
133
|
-
healthCheck: healthCheck.fn
|
|
134
|
-
})
|
|
68
|
+
app.register(setupHealthCheck, config.server.healthCheck)
|
|
135
69
|
}
|
|
136
70
|
|
|
137
71
|
if (!app.hasRoute({ url: '/', method: 'GET' }) && !Array.isArray(toLoad)) {
|
|
@@ -178,107 +112,122 @@ function defaultConfig (app, source) {
|
|
|
178
112
|
|
|
179
113
|
async function buildServer (options, app) {
|
|
180
114
|
app = app || platformaticService
|
|
181
|
-
let cm
|
|
182
115
|
|
|
183
|
-
|
|
116
|
+
let configManager = options.configManager
|
|
117
|
+
if (!configManager) {
|
|
184
118
|
// instantiate a new config manager from current options
|
|
185
|
-
|
|
186
|
-
await
|
|
187
|
-
} else {
|
|
188
|
-
cm = options.configManager
|
|
119
|
+
configManager = new ConfigManager(defaultConfig(app, options))
|
|
120
|
+
await configManager.parseAndValidate()
|
|
189
121
|
}
|
|
190
122
|
|
|
191
123
|
// options is a path
|
|
192
124
|
if (typeof options === 'string') {
|
|
193
|
-
options =
|
|
125
|
+
options = configManager.current
|
|
194
126
|
}
|
|
195
127
|
|
|
196
|
-
|
|
197
|
-
root.decorate('platformatic', {})
|
|
128
|
+
let url = null
|
|
198
129
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
root.platformatic.configManager = cm
|
|
205
|
-
root.platformatic.config = cm.current
|
|
130
|
+
async function createRestartable (fastify) {
|
|
131
|
+
const config = configManager.current
|
|
132
|
+
const root = fastify(config.server)
|
|
133
|
+
|
|
134
|
+
root.decorate('platformatic', { configManager, config })
|
|
206
135
|
root.register(app)
|
|
207
|
-
}
|
|
208
|
-
jumpApp[Symbol.for('skip-override')] = true
|
|
209
136
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
137
|
+
root.decorate('url', {
|
|
138
|
+
getter () {
|
|
139
|
+
return url
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
if (root.restarted) {
|
|
144
|
+
root.log.info('restarted')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return root
|
|
214
148
|
}
|
|
215
149
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
} else if (options.server) {
|
|
222
|
-
serverConfig.protocol = 'http'
|
|
150
|
+
const { port, hostname, ...serverOptions } = options.server
|
|
151
|
+
|
|
152
|
+
if (serverOptions.https) {
|
|
153
|
+
serverOptions.https.key = await adjustHttpsKeyAndCert(serverOptions.https.key)
|
|
154
|
+
serverOptions.https.cert = await adjustHttpsKeyAndCert(serverOptions.https.cert)
|
|
223
155
|
}
|
|
224
156
|
|
|
225
|
-
const handler = await
|
|
157
|
+
const handler = await restartable(createRestartable)
|
|
158
|
+
|
|
159
|
+
configManager.on('update', async (newConfig) => {
|
|
160
|
+
handler.log.debug('config changed')
|
|
161
|
+
handler.log.trace({ newConfig }, 'new config')
|
|
162
|
+
|
|
163
|
+
if (newConfig.watch === false) {
|
|
164
|
+
/* c8 ignore next 4 */
|
|
165
|
+
if (handler.tsCompilerWatcher) {
|
|
166
|
+
handler.tsCompilerWatcher.kill('SIGTERM')
|
|
167
|
+
handler.log.debug('stop watching typescript files')
|
|
168
|
+
}
|
|
226
169
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const port = handler.port
|
|
232
|
-
const url = `${protocol}://${address}:${port}`
|
|
233
|
-
return url
|
|
170
|
+
if (handler.fileWatcher) {
|
|
171
|
+
await handler.fileWatcher.stopWatching()
|
|
172
|
+
handler.log.debug('stop watching files')
|
|
173
|
+
}
|
|
234
174
|
}
|
|
175
|
+
|
|
176
|
+
await safeRestart(handler)
|
|
177
|
+
/* c8 ignore next 1 */
|
|
235
178
|
})
|
|
236
179
|
|
|
237
|
-
|
|
180
|
+
configManager.on('error', function (err) {
|
|
181
|
+
/* c8 ignore next 1 */
|
|
182
|
+
handler.log.error({ err }, 'error reloading the configuration')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
handler.decorate('start', async () => {
|
|
186
|
+
url = await handler.listen({ host: hostname, port })
|
|
187
|
+
return url
|
|
188
|
+
})
|
|
238
189
|
|
|
239
190
|
return handler
|
|
240
191
|
}
|
|
241
192
|
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const restartOpts = {
|
|
262
|
-
...(cm.current.server),
|
|
263
|
-
fileWatcher: handler.app.platformatic.fileWatcher,
|
|
264
|
-
configManager: cm,
|
|
265
|
-
app: jumpApp
|
|
266
|
-
}
|
|
193
|
+
async function onFilesUpdated (app) {
|
|
194
|
+
// Reload the config as well, otherwise we will have problems
|
|
195
|
+
// in case the files watcher triggers the config watcher too
|
|
196
|
+
const configManager = app.platformatic.configManager
|
|
197
|
+
try {
|
|
198
|
+
app.log.debug('files changed')
|
|
199
|
+
await configManager.parse()
|
|
200
|
+
await app.restart()
|
|
201
|
+
/* c8 ignore next 8 */
|
|
202
|
+
} catch (err) {
|
|
203
|
+
app.log.error({
|
|
204
|
+
err: {
|
|
205
|
+
message: err.message,
|
|
206
|
+
stack: err.stack
|
|
207
|
+
}
|
|
208
|
+
}, 'failed to reload server')
|
|
209
|
+
}
|
|
210
|
+
}
|
|
267
211
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
212
|
+
async function safeRestart (app) {
|
|
213
|
+
try {
|
|
214
|
+
await app.restart()
|
|
215
|
+
/* c8 ignore next 8 */
|
|
216
|
+
} catch (err) {
|
|
217
|
+
app.log.error({
|
|
218
|
+
err: {
|
|
219
|
+
message: err.message,
|
|
220
|
+
stack: err.stack
|
|
221
|
+
}
|
|
222
|
+
}, 'failed to reload server')
|
|
274
223
|
}
|
|
275
224
|
}
|
|
276
225
|
|
|
277
226
|
// This is for @platformatic/db to use
|
|
278
227
|
/* c8 ignore next 4 */
|
|
279
|
-
async function buildStart (loadConfig, buildServer) {
|
|
228
|
+
async function buildStart (loadConfig, buildServer, configManagerConfig) {
|
|
280
229
|
const { buildStart } = await import('./lib/start.mjs')
|
|
281
|
-
return buildStart(loadConfig, buildServer)
|
|
230
|
+
return buildStart(loadConfig, buildServer, configManagerConfig)
|
|
282
231
|
}
|
|
283
232
|
|
|
284
233
|
module.exports.buildServer = buildServer
|
package/lib/load-config.js
CHANGED
|
@@ -21,7 +21,12 @@ function generateDefaultConfig () {
|
|
|
21
21
|
// Unfortunately c8 does not see those on Windows
|
|
22
22
|
/* c8 ignore next 70 */
|
|
23
23
|
async function loadConfig (minimistConfig, _args, defaultConfig, configType = 'service') {
|
|
24
|
-
defaultConfig
|
|
24
|
+
if (defaultConfig === undefined) {
|
|
25
|
+
defaultConfig = generateDefaultConfig()
|
|
26
|
+
} else if (defaultConfig?.mergeDefaults) {
|
|
27
|
+
defaultConfig = { ...generateDefaultConfig(), ...defaultConfig }
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
const args = parseArgs(_args, deepmerge({ all: true })({
|
|
26
31
|
string: ['allow-env'],
|
|
27
32
|
boolean: ['hotReload'],
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fp = require('fastify-plugin')
|
|
4
|
+
|
|
5
|
+
async function setupClients (app, opts) {
|
|
6
|
+
const clientsConfig = opts
|
|
7
|
+
for (const { path, url } of clientsConfig) {
|
|
8
|
+
app.register(require(path), { url })
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = fp(setupClients)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fp = require('fastify-plugin')
|
|
4
|
+
|
|
5
|
+
function originToRegexp (origin) {
|
|
6
|
+
if (typeof origin === 'object') {
|
|
7
|
+
if (origin.regexp) {
|
|
8
|
+
origin = new RegExp(origin.regexp)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return origin
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function setupClients (app, opts) {
|
|
16
|
+
const cors = opts
|
|
17
|
+
|
|
18
|
+
let origin = cors.origin
|
|
19
|
+
if (Array.isArray(origin)) {
|
|
20
|
+
origin = origin.map(originToRegexp)
|
|
21
|
+
} else {
|
|
22
|
+
origin = originToRegexp(origin)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
cors.origin = origin
|
|
26
|
+
app.register(require('@fastify/cors'), cors)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = fp(setupClients)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { FileWatcher } = require('@platformatic/utils')
|
|
4
|
+
const fp = require('fastify-plugin')
|
|
5
|
+
|
|
6
|
+
async function setupFileWatcher (app, opts) {
|
|
7
|
+
// TODO: move params to opts
|
|
8
|
+
|
|
9
|
+
const configManager = app.platformatic.configManager
|
|
10
|
+
const config = configManager.current
|
|
11
|
+
|
|
12
|
+
const isRestartableApp = app.restarted !== undefined
|
|
13
|
+
|
|
14
|
+
// to run the plugin without restartable
|
|
15
|
+
/* c8 ignore next 1 */
|
|
16
|
+
const persistentRef = isRestartableApp ? app.persistentRef : app
|
|
17
|
+
|
|
18
|
+
let fileWatcher = persistentRef.fileWatcher
|
|
19
|
+
if (!fileWatcher) {
|
|
20
|
+
fileWatcher = new FileWatcher({
|
|
21
|
+
path: configManager.dirname,
|
|
22
|
+
allowToWatch: config.watch?.allow,
|
|
23
|
+
watchIgnore: config.watch?.ignore
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
fileWatcher.on('update', () => {
|
|
27
|
+
opts.onFilesUpdated(persistentRef)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
app.log.debug('start watching files')
|
|
31
|
+
fileWatcher.startWatching()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
app.decorate('fileWatcher', fileWatcher)
|
|
35
|
+
|
|
36
|
+
app.addHook('onClose', async () => {
|
|
37
|
+
if (!isRestartableApp || app.closingRestartable) {
|
|
38
|
+
app.fileWatcher.stopWatching()
|
|
39
|
+
app.log.debug('stop watching files')
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = fp(setupFileWatcher)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const underPressure = require('@fastify/under-pressure')
|
|
4
|
+
const fp = require('fastify-plugin')
|
|
5
|
+
|
|
6
|
+
async function setupClients (app, opts) {
|
|
7
|
+
const healthCheck = opts
|
|
8
|
+
|
|
9
|
+
app.register(underPressure, {
|
|
10
|
+
exposeStatusRoute: '/status',
|
|
11
|
+
healthCheckInterval: healthCheck.interval !== undefined ? healthCheck.interval : 5000,
|
|
12
|
+
...healthCheck,
|
|
13
|
+
healthCheck: healthCheck.fn
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = fp(setupClients)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join, resolve } = require('path')
|
|
4
|
+
const { readFile } = require('fs/promises')
|
|
5
|
+
|
|
6
|
+
const sandbox = require('fastify-sandbox')
|
|
7
|
+
const fp = require('fastify-plugin')
|
|
8
|
+
|
|
9
|
+
const { getJSPluginPath, isFileAccessible } = require('../utils')
|
|
10
|
+
|
|
11
|
+
const wrapperPath = join(__dirname, 'sandbox-wrapper.js')
|
|
12
|
+
|
|
13
|
+
async function loadPlugins (app) {
|
|
14
|
+
const configManager = app.platformatic.configManager
|
|
15
|
+
const config = configManager.current
|
|
16
|
+
|
|
17
|
+
if (config.plugins.typescript) {
|
|
18
|
+
const workingDir = configManager.dirname
|
|
19
|
+
const tsConfigPath = join(workingDir, 'tsconfig.json')
|
|
20
|
+
|
|
21
|
+
const isTsConfigAccessible = await isFileAccessible(tsConfigPath)
|
|
22
|
+
if (!isTsConfigAccessible) {
|
|
23
|
+
throw new Error('Cannot load typescript plugin, tsconfig.json not found')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const tsConfig = JSON.parse(await readFile(tsConfigPath, 'utf8'))
|
|
27
|
+
const outDir = resolve(workingDir, tsConfig.compilerOptions.outDir)
|
|
28
|
+
|
|
29
|
+
config.plugins.paths = config.plugins.paths.map((plugin) => {
|
|
30
|
+
/* c8 ignore next 3 */
|
|
31
|
+
return typeof plugin === 'string'
|
|
32
|
+
? getJSPluginPath(workingDir, plugin, outDir)
|
|
33
|
+
: { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (config.plugins.hotReload !== false) {
|
|
38
|
+
await app.register(sandbox, {
|
|
39
|
+
path: wrapperPath,
|
|
40
|
+
options: { paths: config.plugins.paths },
|
|
41
|
+
customizeGlobalThis (_globalThis) {
|
|
42
|
+
// Taken from https://github.com/nodejs/undici/blob/fa9fd9066569b6357acacffb806aa804b688c9d8/lib/global.js#L5
|
|
43
|
+
const globalDispatcher = Symbol.for('undici.globalDispatcher.1')
|
|
44
|
+
const dispatcher = globalThis[globalDispatcher]
|
|
45
|
+
/* istanbul ignore else */
|
|
46
|
+
if (dispatcher) {
|
|
47
|
+
_globalThis[globalDispatcher] = dispatcher
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
} else {
|
|
52
|
+
await app.register(require(wrapperPath), { paths: config.plugins.paths })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = fp(loadPlugins)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { isKeyEnabled } = require('@platformatic/utils')
|
|
4
|
+
const fp = require('fastify-plugin')
|
|
5
|
+
|
|
6
|
+
const compiler = require('../compile')
|
|
7
|
+
|
|
8
|
+
async function setupTsCompiler (app) {
|
|
9
|
+
// TODO: move params to opts
|
|
10
|
+
|
|
11
|
+
const configManager = app.platformatic.configManager
|
|
12
|
+
const config = configManager.current
|
|
13
|
+
|
|
14
|
+
const isRestartableApp = app.restarted !== undefined
|
|
15
|
+
|
|
16
|
+
// to run the plugin without restartable
|
|
17
|
+
/* c8 ignore next 1 */
|
|
18
|
+
const persistentRef = isRestartableApp ? app.persistentRef : app
|
|
19
|
+
|
|
20
|
+
const workingDir = configManager.dirname
|
|
21
|
+
|
|
22
|
+
if (isKeyEnabled('watch', config)) {
|
|
23
|
+
let tsCompilerWatcher = persistentRef.tsCompilerWatcher
|
|
24
|
+
if (!tsCompilerWatcher) {
|
|
25
|
+
/* c8 ignore next 5 */
|
|
26
|
+
const { child } = await compiler.compileWatch(workingDir, config)
|
|
27
|
+
app.log.debug('start watching typescript files')
|
|
28
|
+
tsCompilerWatcher = child
|
|
29
|
+
}
|
|
30
|
+
app.decorate('tsCompilerWatcher', tsCompilerWatcher)
|
|
31
|
+
} else {
|
|
32
|
+
await compiler.compile(workingDir, config)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
app.addHook('onClose', async () => {
|
|
36
|
+
if (!isRestartableApp || app.closingRestartable) {
|
|
37
|
+
/* c8 ignore next 4 */
|
|
38
|
+
if (app.tsCompilerWatcher) {
|
|
39
|
+
app.tsCompilerWatcher.kill('SIGTERM')
|
|
40
|
+
app.log.debug('stop watching typescript files')
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = fp(setupTsCompiler)
|
package/lib/schema.js
CHANGED
|
@@ -134,7 +134,8 @@ const server = {
|
|
|
134
134
|
type: 'integer'
|
|
135
135
|
},
|
|
136
136
|
keepAliveTimeout: {
|
|
137
|
-
type: 'integer'
|
|
137
|
+
type: 'integer',
|
|
138
|
+
default: 5000
|
|
138
139
|
},
|
|
139
140
|
maxRequestsPerSocket: {
|
|
140
141
|
type: 'integer'
|
|
@@ -313,6 +314,12 @@ const server = {
|
|
|
313
314
|
}
|
|
314
315
|
}
|
|
315
316
|
]
|
|
317
|
+
},
|
|
318
|
+
requestCert: {
|
|
319
|
+
type: 'boolean'
|
|
320
|
+
},
|
|
321
|
+
rejectUnauthorized: {
|
|
322
|
+
type: 'boolean'
|
|
316
323
|
}
|
|
317
324
|
},
|
|
318
325
|
additionalProperties: false,
|