@platformatic/service 2.0.0-alpha.2 → 2.0.0-alpha.21
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/config.d.ts +11 -2
- package/eslint.config.js +14 -0
- package/index.d.ts +19 -16
- package/index.js +55 -7
- package/index.test-d.ts +34 -31
- package/lib/compile.js +4 -4
- package/lib/create.mjs +7 -7
- package/lib/gen-schema.js +1 -1
- package/lib/gen-types.mjs +2 -2
- package/lib/generator/service-generator.js +16 -16
- package/lib/openapi-schema-defs.js +363 -363
- package/lib/plugins/graphql.js +2 -2
- package/lib/plugins/health-check.js +1 -1
- package/lib/plugins/metrics.js +23 -31
- package/lib/plugins/openapi.js +10 -10
- package/lib/plugins/plugins.js +13 -6
- package/lib/plugins/sandbox-wrapper.js +2 -2
- package/lib/plugins/typescript.js +3 -3
- package/lib/root-endpoint/index.js +2 -2
- package/lib/schema.js +148 -155
- package/lib/stackable.js +271 -0
- package/lib/start.js +64 -65
- package/lib/upgrade.js +1 -4
- package/lib/utils.js +13 -11
- package/lib/versions/0.16.0.js +7 -7
- package/lib/versions/2.0.0.js +11 -0
- package/lib/versions/from-zero-twenty-eight-to-will-see.js +3 -3
- package/lib/versions/no-allow-cycles.js +2 -2
- package/package.json +37 -51
- package/schema.json +30 -6
- package/service.mjs +7 -7
package/lib/plugins/graphql.js
CHANGED
|
@@ -10,7 +10,7 @@ async function setupClients (app, opts) {
|
|
|
10
10
|
exposeStatusRoute: '/status',
|
|
11
11
|
healthCheckInterval: healthCheck.interval !== undefined ? healthCheck.interval : 5000,
|
|
12
12
|
...healthCheck,
|
|
13
|
-
healthCheck: healthCheck.fn
|
|
13
|
+
healthCheck: healthCheck.fn,
|
|
14
14
|
})
|
|
15
15
|
}
|
|
16
16
|
|
package/lib/plugins/metrics.js
CHANGED
|
@@ -12,7 +12,6 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
12
12
|
const register = new promClient.Registry()
|
|
13
13
|
|
|
14
14
|
const defaultMetrics = opts.defaultMetrics ?? { enabled: true }
|
|
15
|
-
const prefix = opts.prefix ?? ''
|
|
16
15
|
|
|
17
16
|
if (opts.labels) {
|
|
18
17
|
const labels = opts.labels ?? {}
|
|
@@ -22,41 +21,42 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
22
21
|
app.register(require('fastify-metrics'), {
|
|
23
22
|
defaultMetrics: {
|
|
24
23
|
...defaultMetrics,
|
|
25
|
-
register
|
|
24
|
+
register,
|
|
26
25
|
},
|
|
27
26
|
endpoint: null,
|
|
28
27
|
name: 'metrics',
|
|
29
28
|
clearRegisterOnInit: false,
|
|
30
29
|
promClient: {
|
|
31
30
|
...promClient,
|
|
32
|
-
register
|
|
31
|
+
register,
|
|
33
32
|
},
|
|
34
33
|
routeMetrics: {
|
|
35
34
|
enabled: true,
|
|
36
35
|
customLabels: {
|
|
37
|
-
|
|
36
|
+
// TODO: check if this is set in prom
|
|
37
|
+
telemetry_id: (req) => req.headers['x-plt-telemetry-id'] ?? 'unknown',
|
|
38
38
|
},
|
|
39
39
|
overrides: {
|
|
40
40
|
histogram: {
|
|
41
|
-
name:
|
|
42
|
-
registers: [register]
|
|
41
|
+
name: 'http_request_duration_seconds',
|
|
42
|
+
registers: [register],
|
|
43
43
|
},
|
|
44
44
|
summary: {
|
|
45
|
-
name:
|
|
46
|
-
registers: [register]
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
45
|
+
name: 'http_request_summary_seconds',
|
|
46
|
+
registers: [register],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
app.register(fp(async (app) => {
|
|
53
53
|
const httpLatencyMetric = new app.metrics.client.Summary({
|
|
54
|
-
name:
|
|
54
|
+
name: 'http_request_all_summary_seconds',
|
|
55
55
|
help: 'request duration in seconds summary for all requests',
|
|
56
56
|
collect: () => {
|
|
57
57
|
process.nextTick(() => httpLatencyMetric.reset())
|
|
58
58
|
},
|
|
59
|
-
registers: [register]
|
|
59
|
+
registers: [register],
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
const ignoredMethods = ['HEAD', 'OPTIONS', 'TRACE', 'CONNECT']
|
|
@@ -75,7 +75,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
75
75
|
}
|
|
76
76
|
})
|
|
77
77
|
}, {
|
|
78
|
-
encapsulate: false
|
|
78
|
+
encapsulate: false,
|
|
79
79
|
}))
|
|
80
80
|
|
|
81
81
|
if (defaultMetrics.enabled) {
|
|
@@ -90,7 +90,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
90
90
|
eluMetric.set(result)
|
|
91
91
|
startELU = endELU
|
|
92
92
|
},
|
|
93
|
-
registers: [register]
|
|
93
|
+
registers: [register],
|
|
94
94
|
})
|
|
95
95
|
app.metrics.client.register.registerMetric(eluMetric)
|
|
96
96
|
|
|
@@ -123,35 +123,27 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
123
123
|
previousIdleTime = idleTime
|
|
124
124
|
previousTotalTime = totalTime
|
|
125
125
|
},
|
|
126
|
-
registers: [register]
|
|
126
|
+
registers: [register],
|
|
127
127
|
})
|
|
128
128
|
app.metrics.client.register.registerMetric(cpuMetric)
|
|
129
129
|
})
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
function cleanMetrics () {
|
|
133
|
+
const httpMetrics = ['http_request_duration_seconds', 'http_request_summary_seconds', 'http_request_all_summary_seconds']
|
|
133
134
|
const metrics = app.metrics.client.register._metrics
|
|
134
135
|
for (const metricName in metrics) {
|
|
135
|
-
if (defaultMetrics.enabled ||
|
|
136
|
+
if (defaultMetrics.enabled || httpMetrics.includes(metricName)) {
|
|
136
137
|
delete metrics[metricName]
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
let isRestarting = false
|
|
142
|
-
app.addHook('onReady', async () => {
|
|
143
|
-
app.addPreRestartHook(async () => {
|
|
144
|
-
isRestarting = true
|
|
145
|
-
cleanMetrics()
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
142
|
app.addHook('onClose', async () => {
|
|
149
|
-
|
|
150
|
-
cleanMetrics()
|
|
151
|
-
}
|
|
143
|
+
cleanMetrics()
|
|
152
144
|
})
|
|
153
145
|
}, {
|
|
154
|
-
encapsulate: false
|
|
146
|
+
encapsulate: false,
|
|
155
147
|
})
|
|
156
148
|
|
|
157
149
|
// This is a global httpServer to match global
|
|
@@ -178,7 +170,7 @@ async function createMetricsServer (app, hostname, port) {
|
|
|
178
170
|
httpServer.on('request', handler)
|
|
179
171
|
return httpServer
|
|
180
172
|
},
|
|
181
|
-
|
|
173
|
+
loggerInstance: app.log.child({ name: 'prometheus' }),
|
|
182
174
|
})
|
|
183
175
|
|
|
184
176
|
app.addHook('onClose', async () => {
|
|
@@ -222,7 +214,7 @@ module.exports = fp(async function (app, opts) {
|
|
|
222
214
|
return reply.code(401).send({ message: 'Unauthorized' })
|
|
223
215
|
}
|
|
224
216
|
return done()
|
|
225
|
-
}
|
|
217
|
+
},
|
|
226
218
|
})
|
|
227
219
|
onRequestHook = metricsServer.basicAuth
|
|
228
220
|
}
|
|
@@ -242,7 +234,7 @@ module.exports = fp(async function (app, opts) {
|
|
|
242
234
|
}
|
|
243
235
|
reply.type('text/plain')
|
|
244
236
|
return promRegistry.metrics()
|
|
245
|
-
}
|
|
237
|
+
},
|
|
246
238
|
})
|
|
247
239
|
}
|
|
248
240
|
|
package/lib/plugins/openapi.js
CHANGED
|
@@ -16,28 +16,28 @@ async function setupOpenAPI (app, opts) {
|
|
|
16
16
|
info: {
|
|
17
17
|
title: 'Platformatic',
|
|
18
18
|
description: 'This is a service built on top of Platformatic',
|
|
19
|
-
version: '1.0.0'
|
|
20
|
-
}
|
|
19
|
+
version: '1.0.0',
|
|
20
|
+
},
|
|
21
21
|
}, typeof openapi === 'object' ? openapi : {})
|
|
22
22
|
app.log.trace({ openapi: openapiConfig })
|
|
23
23
|
const swaggerOptions = {
|
|
24
24
|
exposeRoute: openapiConfig.exposeRoute,
|
|
25
25
|
openapi: {
|
|
26
|
-
...openapiConfig
|
|
26
|
+
...openapiConfig,
|
|
27
27
|
},
|
|
28
28
|
refResolver: {
|
|
29
29
|
buildLocalReference (json, baseUri, fragment, i) {
|
|
30
30
|
// TODO figure out if we need def-${i}
|
|
31
31
|
/* istanbul ignore next */
|
|
32
32
|
return json.$id || `def-${i}`
|
|
33
|
-
}
|
|
34
|
-
}
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
if (openapi.path) {
|
|
38
38
|
swaggerOptions.mode = 'static'
|
|
39
39
|
swaggerOptions.specification = {
|
|
40
|
-
path: openapi.path
|
|
40
|
+
path: openapi.path,
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -49,11 +49,11 @@ async function setupOpenAPI (app, opts) {
|
|
|
49
49
|
/** Serve spec file in yaml and json */
|
|
50
50
|
app.get(`${routePrefix}/json`, {
|
|
51
51
|
schema: { hide: true },
|
|
52
|
-
logLevel: 'warn'
|
|
52
|
+
logLevel: 'warn',
|
|
53
53
|
}, async () => app.swagger())
|
|
54
54
|
app.get(`${routePrefix}/yaml`, {
|
|
55
55
|
schema: { hide: true },
|
|
56
|
-
logLevel: 'warn'
|
|
56
|
+
logLevel: 'warn',
|
|
57
57
|
}, async () => app.swagger({ yaml: true }))
|
|
58
58
|
|
|
59
59
|
app.register(ScalarApiReference, {
|
|
@@ -61,8 +61,8 @@ async function setupOpenAPI (app, opts) {
|
|
|
61
61
|
...openapi,
|
|
62
62
|
routePrefix,
|
|
63
63
|
configuration: {
|
|
64
|
-
customCss: scalarTheme.theme
|
|
65
|
-
}
|
|
64
|
+
customCss: scalarTheme.theme,
|
|
65
|
+
},
|
|
66
66
|
})
|
|
67
67
|
}
|
|
68
68
|
|
package/lib/plugins/plugins.js
CHANGED
|
@@ -7,14 +7,14 @@ const wrapper = require('./sandbox-wrapper')
|
|
|
7
7
|
|
|
8
8
|
const { getJSPluginPath, isFileAccessible } = require('../utils')
|
|
9
9
|
|
|
10
|
-
async function loadPlugins (app) {
|
|
10
|
+
async function loadPlugins (app, opts) {
|
|
11
11
|
const configManager = app.platformatic.configManager
|
|
12
12
|
const config = configManager.current
|
|
13
13
|
|
|
14
14
|
let isOutDirAccessible = false
|
|
15
15
|
let outDir = null
|
|
16
16
|
|
|
17
|
-
const workingDir = configManager.dirname
|
|
17
|
+
const workingDir = opts?.context?.directory ?? configManager.dirname
|
|
18
18
|
const tsConfigPath = configManager.current.plugins.typescript?.tsConfig || join(workingDir, 'tsconfig.json')
|
|
19
19
|
|
|
20
20
|
// If the tsconfig.json file exists, then we need to adjust the plugin paths
|
|
@@ -32,14 +32,21 @@ async function loadPlugins (app) {
|
|
|
32
32
|
|
|
33
33
|
if (outDir) {
|
|
34
34
|
isOutDirAccessible = await isFileAccessible(outDir)
|
|
35
|
+
|
|
36
|
+
if (opts.context?.isProduction && !isOutDirAccessible) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Cannot access directory '${outDir}'. Please run the 'build' command before running in production mode.`
|
|
39
|
+
)
|
|
40
|
+
}
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
if (config.plugins.paths && isOutDirAccessible) {
|
|
38
|
-
config.plugins.paths = config.plugins.paths.map(
|
|
44
|
+
config.plugins.paths = config.plugins.paths.map(plugin => {
|
|
39
45
|
/* c8 ignore next 3 */
|
|
40
|
-
const tmp =
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
const tmp =
|
|
47
|
+
typeof plugin === 'string'
|
|
48
|
+
? getJSPluginPath(workingDir, plugin, outDir)
|
|
49
|
+
: { ...plugin, path: getJSPluginPath(workingDir, plugin.path, outDir) }
|
|
43
50
|
return tmp
|
|
44
51
|
})
|
|
45
52
|
}
|
|
@@ -36,7 +36,7 @@ module.exports = fp(async function (app, opts) {
|
|
|
36
36
|
forceESM: plugin.forceESM,
|
|
37
37
|
ignoreFilter: plugin.ignoreFilter,
|
|
38
38
|
matchFilter: plugin.matchFilter,
|
|
39
|
-
...patternOptions
|
|
39
|
+
...patternOptions,
|
|
40
40
|
})
|
|
41
41
|
} else {
|
|
42
42
|
let loaded = await import(pathToFileURL(plugin.path))
|
|
@@ -71,7 +71,7 @@ function patternOptionsFromPlugin (plugin) {
|
|
|
71
71
|
const patternOptionKeys = [
|
|
72
72
|
'ignorePattern',
|
|
73
73
|
'indexPattern',
|
|
74
|
-
'autoHooksPattern'
|
|
74
|
+
'autoHooksPattern',
|
|
75
75
|
]
|
|
76
76
|
|
|
77
77
|
for (const key of patternOptionKeys) {
|
|
@@ -4,16 +4,16 @@ const fp = require('fastify-plugin')
|
|
|
4
4
|
const compiler = require('@platformatic/ts-compiler')
|
|
5
5
|
const { extractTypeScriptCompileOptionsFromConfig } = require('../compile')
|
|
6
6
|
|
|
7
|
-
async function setupTsCompiler (app) {
|
|
7
|
+
async function setupTsCompiler (app, opts) {
|
|
8
8
|
const configManager = app.platformatic.configManager
|
|
9
9
|
const config = configManager.current
|
|
10
|
-
const workingDir = configManager.dirname
|
|
10
|
+
const workingDir = opts?.context?.directory ?? configManager.dirname
|
|
11
11
|
|
|
12
12
|
await compiler.compile({
|
|
13
13
|
...extractTypeScriptCompileOptionsFromConfig(config),
|
|
14
14
|
cwd: workingDir,
|
|
15
15
|
clean: false,
|
|
16
|
-
logger: app.log
|
|
16
|
+
logger: app.log,
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -6,7 +6,7 @@ const userAgentParser = require('my-ua-parser')
|
|
|
6
6
|
|
|
7
7
|
module.exports = async (app, opts) => {
|
|
8
8
|
app.register(fastifyStatic, {
|
|
9
|
-
root: path.join(__dirname, 'public')
|
|
9
|
+
root: path.join(__dirname, 'public'),
|
|
10
10
|
})
|
|
11
11
|
|
|
12
12
|
// root endpoint
|
|
@@ -23,6 +23,6 @@ module.exports = async (app, opts) => {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return { message: 'Welcome to Platformatic! Please visit https://docs.platformatic.dev' }
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
27
|
})
|
|
28
28
|
}
|