@platformatic/service 1.53.3 → 2.0.0-alpha.10
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 +4 -17
- package/eslint.config.js +14 -0
- package/help/help.txt +0 -2
- package/index.d.ts +20 -21
- package/index.js +56 -22
- package/index.test-d.ts +34 -31
- package/lib/compile.js +24 -102
- 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 +18 -30
- package/lib/plugins/openapi.js +10 -21
- package/lib/plugins/plugins.js +13 -6
- package/lib/plugins/sandbox-wrapper.js +2 -2
- package/lib/plugins/typescript.js +10 -6
- package/lib/root-endpoint/index.js +2 -19
- package/lib/root-endpoint/public/index.html +4 -21
- package/lib/schema.js +199 -576
- package/lib/stackable.js +259 -0
- package/lib/start.js +51 -68
- package/lib/upgrade.js +2 -2
- package/lib/utils.js +12 -133
- package/lib/versions/0.16.0.js +7 -7
- package/lib/versions/from-zero-twenty-eight-to-will-see.js +3 -3
- package/lib/versions/no-allow-cycles.js +15 -0
- package/package.json +50 -66
- package/schema.json +8 -195
- package/service.mjs +9 -13
- package/help/versions bump.txt +0 -25
- package/help/versions update.txt +0 -23
- package/lib/bump-version.js +0 -178
- package/lib/errors.js +0 -16
- package/lib/get-openapi-schema.js +0 -47
- package/lib/plugins/versions.js +0 -217
- package/lib/update-version.js +0 -863
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
|
@@ -13,43 +13,40 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
13
13
|
|
|
14
14
|
const defaultMetrics = opts.defaultMetrics ?? { enabled: true }
|
|
15
15
|
|
|
16
|
-
if (opts.labels
|
|
16
|
+
if (opts.labels) {
|
|
17
17
|
const labels = opts.labels ?? {}
|
|
18
|
-
if (opts.prefix) {
|
|
19
|
-
labels.prefix = opts.prefix
|
|
20
|
-
}
|
|
21
18
|
register.setDefaultLabels(labels)
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
app.register(require('fastify-metrics'), {
|
|
25
22
|
defaultMetrics: {
|
|
26
23
|
...defaultMetrics,
|
|
27
|
-
register
|
|
24
|
+
register,
|
|
28
25
|
},
|
|
29
26
|
endpoint: null,
|
|
30
27
|
name: 'metrics',
|
|
31
28
|
clearRegisterOnInit: false,
|
|
32
29
|
promClient: {
|
|
33
30
|
...promClient,
|
|
34
|
-
register
|
|
31
|
+
register,
|
|
35
32
|
},
|
|
36
33
|
routeMetrics: {
|
|
37
34
|
enabled: true,
|
|
38
35
|
customLabels: {
|
|
39
36
|
// TODO: check if this is set in prom
|
|
40
|
-
telemetry_id: (req) => req.headers['x-telemetry-id'] ?? 'unknown'
|
|
37
|
+
telemetry_id: (req) => req.headers['x-plt-telemetry-id'] ?? 'unknown',
|
|
41
38
|
},
|
|
42
39
|
overrides: {
|
|
43
40
|
histogram: {
|
|
44
41
|
name: 'http_request_duration_seconds',
|
|
45
|
-
registers: [register]
|
|
42
|
+
registers: [register],
|
|
46
43
|
},
|
|
47
44
|
summary: {
|
|
48
45
|
name: 'http_request_summary_seconds',
|
|
49
|
-
registers: [register]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
46
|
+
registers: [register],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
53
50
|
})
|
|
54
51
|
|
|
55
52
|
app.register(fp(async (app) => {
|
|
@@ -59,7 +56,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
59
56
|
collect: () => {
|
|
60
57
|
process.nextTick(() => httpLatencyMetric.reset())
|
|
61
58
|
},
|
|
62
|
-
registers: [register]
|
|
59
|
+
registers: [register],
|
|
63
60
|
})
|
|
64
61
|
|
|
65
62
|
const ignoredMethods = ['HEAD', 'OPTIONS', 'TRACE', 'CONNECT']
|
|
@@ -78,7 +75,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
78
75
|
}
|
|
79
76
|
})
|
|
80
77
|
}, {
|
|
81
|
-
encapsulate: false
|
|
78
|
+
encapsulate: false,
|
|
82
79
|
}))
|
|
83
80
|
|
|
84
81
|
if (defaultMetrics.enabled) {
|
|
@@ -93,7 +90,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
93
90
|
eluMetric.set(result)
|
|
94
91
|
startELU = endELU
|
|
95
92
|
},
|
|
96
|
-
registers: [register]
|
|
93
|
+
registers: [register],
|
|
97
94
|
})
|
|
98
95
|
app.metrics.client.register.registerMetric(eluMetric)
|
|
99
96
|
|
|
@@ -126,7 +123,7 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
126
123
|
previousIdleTime = idleTime
|
|
127
124
|
previousTotalTime = totalTime
|
|
128
125
|
},
|
|
129
|
-
registers: [register]
|
|
126
|
+
registers: [register],
|
|
130
127
|
})
|
|
131
128
|
app.metrics.client.register.registerMetric(cpuMetric)
|
|
132
129
|
})
|
|
@@ -142,20 +139,11 @@ const metricsPlugin = fp(async function (app, opts = {}) {
|
|
|
142
139
|
}
|
|
143
140
|
}
|
|
144
141
|
|
|
145
|
-
let isRestarting = false
|
|
146
|
-
app.addHook('onReady', async () => {
|
|
147
|
-
app.addPreRestartHook(async () => {
|
|
148
|
-
isRestarting = true
|
|
149
|
-
cleanMetrics()
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
142
|
app.addHook('onClose', async () => {
|
|
153
|
-
|
|
154
|
-
cleanMetrics()
|
|
155
|
-
}
|
|
143
|
+
cleanMetrics()
|
|
156
144
|
})
|
|
157
145
|
}, {
|
|
158
|
-
encapsulate: false
|
|
146
|
+
encapsulate: false,
|
|
159
147
|
})
|
|
160
148
|
|
|
161
149
|
// This is a global httpServer to match global
|
|
@@ -182,7 +170,7 @@ async function createMetricsServer (app, hostname, port) {
|
|
|
182
170
|
httpServer.on('request', handler)
|
|
183
171
|
return httpServer
|
|
184
172
|
},
|
|
185
|
-
|
|
173
|
+
loggerInstance: app.log.child({ name: 'prometheus' }),
|
|
186
174
|
})
|
|
187
175
|
|
|
188
176
|
app.addHook('onClose', async () => {
|
|
@@ -226,7 +214,7 @@ module.exports = fp(async function (app, opts) {
|
|
|
226
214
|
return reply.code(401).send({ message: 'Unauthorized' })
|
|
227
215
|
}
|
|
228
216
|
return done()
|
|
229
|
-
}
|
|
217
|
+
},
|
|
230
218
|
})
|
|
231
219
|
onRequestHook = metricsServer.basicAuth
|
|
232
220
|
}
|
|
@@ -246,7 +234,7 @@ module.exports = fp(async function (app, opts) {
|
|
|
246
234
|
}
|
|
247
235
|
reply.type('text/plain')
|
|
248
236
|
return promRegistry.metrics()
|
|
249
|
-
}
|
|
237
|
+
},
|
|
250
238
|
})
|
|
251
239
|
}
|
|
252
240
|
|
package/lib/plugins/openapi.js
CHANGED
|
@@ -10,45 +10,34 @@ const fp = require('fastify-plugin')
|
|
|
10
10
|
// despite being covered by test/routes.test.js
|
|
11
11
|
/* c8 ignore next 33 */
|
|
12
12
|
async function setupOpenAPI (app, opts) {
|
|
13
|
-
const { openapi
|
|
13
|
+
const { openapi } = opts
|
|
14
14
|
const openapiConfig = deepmerge({
|
|
15
15
|
exposeRoute: true,
|
|
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
|
-
}
|
|
33
|
+
},
|
|
34
34
|
},
|
|
35
|
-
transform: ({ schema, url }) => {
|
|
36
|
-
// Hide versioned endpoints
|
|
37
|
-
for (const version of versions?.configs ?? []) {
|
|
38
|
-
if (url.startsWith(version.openapi.prefix)) {
|
|
39
|
-
if (!schema) schema = {}
|
|
40
|
-
schema.hide = true
|
|
41
|
-
break
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return { schema, url }
|
|
45
|
-
}
|
|
46
35
|
}
|
|
47
36
|
|
|
48
37
|
if (openapi.path) {
|
|
49
38
|
swaggerOptions.mode = 'static'
|
|
50
39
|
swaggerOptions.specification = {
|
|
51
|
-
path: openapi.path
|
|
40
|
+
path: openapi.path,
|
|
52
41
|
}
|
|
53
42
|
}
|
|
54
43
|
|
|
@@ -60,11 +49,11 @@ async function setupOpenAPI (app, opts) {
|
|
|
60
49
|
/** Serve spec file in yaml and json */
|
|
61
50
|
app.get(`${routePrefix}/json`, {
|
|
62
51
|
schema: { hide: true },
|
|
63
|
-
logLevel: 'warn'
|
|
52
|
+
logLevel: 'warn',
|
|
64
53
|
}, async () => app.swagger())
|
|
65
54
|
app.get(`${routePrefix}/yaml`, {
|
|
66
55
|
schema: { hide: true },
|
|
67
|
-
logLevel: 'warn'
|
|
56
|
+
logLevel: 'warn',
|
|
68
57
|
}, async () => app.swagger({ yaml: true }))
|
|
69
58
|
|
|
70
59
|
app.register(ScalarApiReference, {
|
|
@@ -72,8 +61,8 @@ async function setupOpenAPI (app, opts) {
|
|
|
72
61
|
...openapi,
|
|
73
62
|
routePrefix,
|
|
74
63
|
configuration: {
|
|
75
|
-
customCss: scalarTheme.theme
|
|
76
|
-
}
|
|
64
|
+
customCss: scalarTheme.theme,
|
|
65
|
+
},
|
|
77
66
|
})
|
|
78
67
|
}
|
|
79
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
|
|
@@ -34,12 +34,19 @@ async function loadPlugins (app) {
|
|
|
34
34
|
isOutDirAccessible = await isFileAccessible(outDir)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
if (opts.context?.isProduction && !isOutDirAccessible) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`Cannot access directory '${outDir}'. Please run the 'build' command before running in production mode.`
|
|
40
|
+
)
|
|
41
|
+
}
|
|
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) {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const fp = require('fastify-plugin')
|
|
4
|
-
const compiler = require('
|
|
5
|
-
|
|
6
|
-
async function setupTsCompiler (app) {
|
|
7
|
-
// TODO: move params to opts
|
|
4
|
+
const compiler = require('@platformatic/ts-compiler')
|
|
5
|
+
const { extractTypeScriptCompileOptionsFromConfig } = require('../compile')
|
|
8
6
|
|
|
7
|
+
async function setupTsCompiler (app, opts) {
|
|
9
8
|
const configManager = app.platformatic.configManager
|
|
10
9
|
const config = configManager.current
|
|
11
|
-
const workingDir = configManager.dirname
|
|
10
|
+
const workingDir = opts?.context?.directory ?? configManager.dirname
|
|
12
11
|
|
|
13
|
-
await compiler.compile(
|
|
12
|
+
await compiler.compile({
|
|
13
|
+
...extractTypeScriptCompileOptionsFromConfig(config),
|
|
14
|
+
cwd: workingDir,
|
|
15
|
+
clean: false,
|
|
16
|
+
logger: app.log,
|
|
17
|
+
})
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
module.exports = fp(setupTsCompiler)
|
|
@@ -5,25 +5,8 @@ const fastifyStatic = require('@fastify/static')
|
|
|
5
5
|
const userAgentParser = require('my-ua-parser')
|
|
6
6
|
|
|
7
7
|
module.exports = async (app, opts) => {
|
|
8
|
-
const versions = opts.versions || {}
|
|
9
|
-
|
|
10
8
|
app.register(fastifyStatic, {
|
|
11
|
-
root: path.join(__dirname, 'public')
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
app.route({
|
|
15
|
-
method: 'GET',
|
|
16
|
-
path: '/_platformatic_versions',
|
|
17
|
-
schema: { hide: true },
|
|
18
|
-
handler: () => {
|
|
19
|
-
const openapiUrls = []
|
|
20
|
-
for (const versionConfig of versions?.configs ?? []) {
|
|
21
|
-
const name = versionConfig.version
|
|
22
|
-
const prefix = versionConfig.openapi.prefix
|
|
23
|
-
openapiUrls.push({ name, prefix })
|
|
24
|
-
}
|
|
25
|
-
return openapiUrls
|
|
26
|
-
}
|
|
9
|
+
root: path.join(__dirname, 'public'),
|
|
27
10
|
})
|
|
28
11
|
|
|
29
12
|
// root endpoint
|
|
@@ -40,6 +23,6 @@ module.exports = async (app, opts) => {
|
|
|
40
23
|
}
|
|
41
24
|
}
|
|
42
25
|
return { message: 'Welcome to Platformatic! Please visit https://docs.platformatic.dev' }
|
|
43
|
-
}
|
|
26
|
+
},
|
|
44
27
|
})
|
|
45
28
|
}
|
|
@@ -197,6 +197,7 @@
|
|
|
197
197
|
<div class="button-container">
|
|
198
198
|
<a href="https://docs.platformatic.dev" target="_blank" class="button-link">Documentation</a>
|
|
199
199
|
<div class="open-documentation-version buttons-list-container"> </div>
|
|
200
|
+
<a id="openapi-link" target="_blank" class="button-link">OpenAPI Documentation</a>
|
|
200
201
|
<a id="graphql-link" target="_blank" class="button-link">GraphiQL</a>
|
|
201
202
|
</div>
|
|
202
203
|
</div>
|
|
@@ -205,6 +206,9 @@
|
|
|
205
206
|
<script>
|
|
206
207
|
const currentPath = window.location.pathname
|
|
207
208
|
|
|
209
|
+
const openApiLink = document.getElementById('openapi-link')
|
|
210
|
+
openApiLink.href = currentPath + 'documentation'
|
|
211
|
+
|
|
208
212
|
const graphqlLink = document.getElementById('graphql-link')
|
|
209
213
|
graphqlLink.href = currentPath + 'graphiql'
|
|
210
214
|
|
|
@@ -225,27 +229,6 @@
|
|
|
225
229
|
document.getElementById('logo').src = 'images/platformatic-logo-dark.svg'
|
|
226
230
|
}
|
|
227
231
|
}
|
|
228
|
-
|
|
229
|
-
function join (...paths) {
|
|
230
|
-
return paths.join('/').replace(/\/+/g, '/')
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
fetch('/_platformatic_versions')
|
|
234
|
-
.then(response => response.json())
|
|
235
|
-
.then(versions => {
|
|
236
|
-
const sharedOpenapiHref = join(currentPath, 'documentation')
|
|
237
|
-
const openapiButtons = [
|
|
238
|
-
`<a href="${sharedOpenapiHref}"target="_blank" class="button-link">OpenAPI Documentation</a>`
|
|
239
|
-
]
|
|
240
|
-
|
|
241
|
-
for (const version of versions) {
|
|
242
|
-
const href = join(currentPath, version.prefix, 'documentation')
|
|
243
|
-
openapiButtons.push(`<a href="${href}" target="_blank" class="button-link">OpenAPI Documentation ${version.name}</a>`)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const buttonList = document.getElementsByClassName('open-documentation-version')[0]
|
|
247
|
-
buttonList.innerHTML = openapiButtons.join('')
|
|
248
|
-
})
|
|
249
232
|
</script>
|
|
250
233
|
</body>
|
|
251
234
|
</html>
|