@platformatic/service 3.4.1 → 3.5.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/LICENSE +1 -1
- package/config.d.ts +450 -94
- package/eslint.config.js +4 -6
- package/index.d.ts +55 -48
- package/index.js +44 -179
- package/lib/application.js +35 -0
- package/lib/capability.js +281 -0
- package/lib/compile.js +2 -52
- package/lib/generator.js +426 -0
- package/lib/plugins/cors.js +5 -8
- package/lib/plugins/graphql.js +16 -14
- package/lib/plugins/health-check.js +6 -8
- package/lib/plugins/openapi.js +43 -32
- package/lib/plugins/plugins.js +6 -53
- package/lib/{root-endpoint/index.js → plugins/root.js} +9 -8
- package/lib/plugins/sandbox-wrapper.js +65 -63
- package/lib/schema.js +1075 -203
- package/lib/upgrade.js +6 -8
- package/lib/utils.js +30 -83
- package/lib/versions/0.16.0.js +14 -15
- package/lib/versions/{from-zero-twenty-eight-to-will-see.js → 0.28.0.js} +3 -6
- package/lib/versions/2.0.0.js +4 -7
- package/lib/versions/3.0.0.js +14 -0
- package/package.json +28 -36
- package/schema.json +1452 -165
- package/tsconfig.json +16 -6
- package/.c8rc +0 -6
- package/help/compile.txt +0 -19
- package/help/create.txt +0 -11
- package/help/help.txt +0 -8
- package/help/schema.txt +0 -9
- package/help/start.txt +0 -23
- package/index.test-d.ts +0 -107
- package/lib/create.mjs +0 -85
- package/lib/gen-schema.js +0 -15
- package/lib/gen-types.mjs +0 -38
- package/lib/generator/README.md +0 -31
- package/lib/generator/service-generator.d.ts +0 -11
- package/lib/generator/service-generator.js +0 -126
- package/lib/openapi-schema-defs.js +0 -1108
- package/lib/plugins/clients.js +0 -16
- package/lib/plugins/metrics.js +0 -244
- package/lib/plugins/typescript.js +0 -20
- package/lib/stackable.js +0 -306
- package/lib/start.js +0 -175
- package/service.mjs +0 -71
- /package/{lib/root-endpoint/public → public}/images/dark_mode.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/favicon.ico +0 -0
- /package/{lib/root-endpoint/public → public}/images/light_mode.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/platformatic-logo-dark.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/platformatic-logo-light.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/triangle_dark.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/triangle_light.svg +0 -0
- /package/{lib/root-endpoint/public → public}/index.html +0 -0
package/lib/compile.js
CHANGED
|
@@ -1,56 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { compile } = require('@platformatic/ts-compiler')
|
|
4
|
-
const { loadConfig } = require('@platformatic/config')
|
|
5
|
-
const pino = require('pino')
|
|
6
|
-
const pretty = require('pino-pretty')
|
|
7
|
-
const { dirname } = require('path')
|
|
8
|
-
|
|
9
|
-
function buildCompileCmd (app) {
|
|
10
|
-
return async function compileCmd (_args) {
|
|
11
|
-
let fullPath = null
|
|
12
|
-
let config = null
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const { configManager } = await loadConfig({}, _args, app, {
|
|
16
|
-
watch: false,
|
|
17
|
-
})
|
|
18
|
-
await configManager.parseAndValidate()
|
|
19
|
-
config = configManager.current
|
|
20
|
-
fullPath = dirname(configManager.fullPath)
|
|
21
|
-
/* c8 ignore next 4 */
|
|
22
|
-
} catch (err) {
|
|
23
|
-
console.error(err)
|
|
24
|
-
process.exit(1)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const logger = pino(
|
|
28
|
-
pretty({
|
|
29
|
-
translateTime: 'SYS:HH:MM:ss',
|
|
30
|
-
ignore: 'hostname,pid',
|
|
31
|
-
})
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
const compileOptions = {
|
|
35
|
-
...extractTypeScriptCompileOptionsFromConfig(config),
|
|
36
|
-
cwd: fullPath,
|
|
37
|
-
logger,
|
|
38
|
-
clean: _args.includes('--clean'),
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!await compile(compileOptions)) {
|
|
42
|
-
process.exit(1)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module.exports.buildCompileCmd = buildCompileCmd
|
|
48
|
-
|
|
49
|
-
function extractTypeScriptCompileOptionsFromConfig (config) {
|
|
1
|
+
export function getTypescriptCompilationOptions (config) {
|
|
50
2
|
return {
|
|
51
3
|
tsConfig: config.plugins?.typescript?.tsConfig,
|
|
52
|
-
flags: config.plugins?.typescript?.flags
|
|
4
|
+
flags: config.plugins?.typescript?.flags
|
|
53
5
|
}
|
|
54
6
|
}
|
|
55
|
-
|
|
56
|
-
module.exports.extractTypeScriptCompileOptionsFromConfig = extractTypeScriptCompileOptionsFromConfig
|
package/lib/generator.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { BaseGenerator } from '@platformatic/generators'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
const JS_PLUGIN_WITH_TYPES_SUPPORT = `\
|
|
5
|
+
'use strict'
|
|
6
|
+
|
|
7
|
+
/** @param {import('fastify').FastifyInstance} fastify */
|
|
8
|
+
module.exports = async function (fastify, opts) {
|
|
9
|
+
fastify.decorate('example', 'foobar')
|
|
10
|
+
}
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
const TS_PLUGIN_WITH_TYPES_SUPPORT = `\
|
|
14
|
+
import { type FastifyInstance, type FastifyPluginOptions } from 'fastify'
|
|
15
|
+
|
|
16
|
+
export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
|
|
17
|
+
fastify.decorate('example', 'foobar')
|
|
18
|
+
}
|
|
19
|
+
`
|
|
20
|
+
|
|
21
|
+
const JS_ROUTES_WITH_TYPES_SUPPORT = `\
|
|
22
|
+
'use strict'
|
|
23
|
+
|
|
24
|
+
/** @param {import('fastify').FastifyInstance} fastify */
|
|
25
|
+
module.exports = async function (fastify, opts) {
|
|
26
|
+
fastify.get('/example', async (request, reply) => {
|
|
27
|
+
return { hello: fastify.example }
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
`
|
|
31
|
+
|
|
32
|
+
const TS_ROUTES_WITH_TYPES_SUPPORT = `\
|
|
33
|
+
import { type FastifyInstance, type FastifyPluginOptions } from 'fastify'
|
|
34
|
+
|
|
35
|
+
declare module 'fastify' {
|
|
36
|
+
interface FastifyInstance {
|
|
37
|
+
example: string
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
|
|
42
|
+
fastify.get('/example', async (request, reply) => {
|
|
43
|
+
return { hello: fastify.example }
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
`
|
|
47
|
+
|
|
48
|
+
const TEST_ROUTES_JS = `\
|
|
49
|
+
'use strict'
|
|
50
|
+
|
|
51
|
+
const test = require('node:test')
|
|
52
|
+
const assert = require('node:assert')
|
|
53
|
+
const { getServer } = require('../helper')
|
|
54
|
+
|
|
55
|
+
test('example', async (t) => {
|
|
56
|
+
const server = await getServer(t)
|
|
57
|
+
const res = await server.inject({
|
|
58
|
+
method: 'GET',
|
|
59
|
+
url: '/example'
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
assert.strictEqual(res.statusCode, 200)
|
|
63
|
+
assert.deepStrictEqual(res.json(), {
|
|
64
|
+
hello: 'foobar'
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
`
|
|
68
|
+
|
|
69
|
+
const TEST_PLUGIN_JS = `\
|
|
70
|
+
'use strict'
|
|
71
|
+
|
|
72
|
+
const test = require('node:test')
|
|
73
|
+
const assert = require('node:assert')
|
|
74
|
+
const { getServer } = require('../helper')
|
|
75
|
+
|
|
76
|
+
test('example decorator', async (t) => {
|
|
77
|
+
const server = await getServer(t)
|
|
78
|
+
|
|
79
|
+
assert.strictEqual(server.example, 'foobar')
|
|
80
|
+
})
|
|
81
|
+
`
|
|
82
|
+
|
|
83
|
+
const TEST_ROUTES_TS = `\
|
|
84
|
+
import test from 'node:test'
|
|
85
|
+
import assert from 'node:assert'
|
|
86
|
+
import { getServer } from '../helper'
|
|
87
|
+
|
|
88
|
+
test('root', async (t) => {
|
|
89
|
+
const server = await getServer(t)
|
|
90
|
+
const res = await server.inject({
|
|
91
|
+
method: 'GET',
|
|
92
|
+
url: '/example'
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
assert.strictEqual(res.statusCode, 200)
|
|
96
|
+
assert.deepStrictEqual(res.json(), {
|
|
97
|
+
hello: 'foobar'
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
`
|
|
101
|
+
|
|
102
|
+
const TEST_PLUGIN_TS = `\
|
|
103
|
+
import test from 'node:test'
|
|
104
|
+
import assert from 'node:assert'
|
|
105
|
+
import { getServer } from '../helper'
|
|
106
|
+
|
|
107
|
+
test('example decorator', async (t) => {
|
|
108
|
+
const server = await getServer(t)
|
|
109
|
+
|
|
110
|
+
assert.strictEqual(server.example, 'foobar')
|
|
111
|
+
})
|
|
112
|
+
`
|
|
113
|
+
|
|
114
|
+
const TEST_HELPER_JS = `
|
|
115
|
+
'use strict'
|
|
116
|
+
|
|
117
|
+
const { join } = require('node:path')
|
|
118
|
+
const { readFile } = require('node:fs/promises')
|
|
119
|
+
const { create } = require('$__MOD__')
|
|
120
|
+
$__REQUIRES__
|
|
121
|
+
|
|
122
|
+
async function getServer (t) {
|
|
123
|
+
$__PRE__
|
|
124
|
+
const config = JSON.parse(await readFile(join(__dirname, '..', 'watt.json'), 'utf8'))
|
|
125
|
+
// Add your config customizations here. For example you want to set
|
|
126
|
+
// all things that are set in the config file to read from an env variable
|
|
127
|
+
config.server ||= {}
|
|
128
|
+
config.server.logger ||= {}
|
|
129
|
+
config.watch = false
|
|
130
|
+
$__CONFIG__
|
|
131
|
+
// Add your config customizations here
|
|
132
|
+
const server = await create(join(__dirname, '../'),config)
|
|
133
|
+
await server.start({}) // sets .getApplication()
|
|
134
|
+
t.after(() => server.stop())
|
|
135
|
+
$__POST__
|
|
136
|
+
return server.getApplication()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports.getServer = getServer
|
|
140
|
+
`
|
|
141
|
+
|
|
142
|
+
const TEST_HELPER_TS = `
|
|
143
|
+
import { join } from 'node:path'
|
|
144
|
+
import { readFile } from 'node:fs/promises'
|
|
145
|
+
import { create } from '$__MOD__'
|
|
146
|
+
import { test } from 'node:test'
|
|
147
|
+
$__REQUIRES__
|
|
148
|
+
|
|
149
|
+
type testfn = Parameters<typeof test>[0]
|
|
150
|
+
type TestContext = Parameters<Exclude<testfn, undefined>>[0]
|
|
151
|
+
|
|
152
|
+
export async function getServer (t: TestContext) {
|
|
153
|
+
$__PRE__
|
|
154
|
+
// We go up two folder because this files executes in the dist folder
|
|
155
|
+
const config = JSON.parse(await readFile(join(import.meta.dirname, "..", "watt.json"), 'utf8'))
|
|
156
|
+
// Add your config customizations here. For example you want to set
|
|
157
|
+
// all things that are set in the config file to read from an env variable
|
|
158
|
+
config.server ||= {}
|
|
159
|
+
config.server.logger ||= {}
|
|
160
|
+
config.server.logger.level = 'warn'
|
|
161
|
+
config.watch = false
|
|
162
|
+
$__CONFIG__
|
|
163
|
+
// Add your config customizations here
|
|
164
|
+
const server = await create(join(import.meta.dirname, "../"), config)
|
|
165
|
+
await server.start({}) // sets .getApplication()
|
|
166
|
+
t.after(() => server.stop())
|
|
167
|
+
$__POST__
|
|
168
|
+
return server.getApplication();
|
|
169
|
+
}
|
|
170
|
+
`
|
|
171
|
+
|
|
172
|
+
const TS_CONFIG = `
|
|
173
|
+
{
|
|
174
|
+
compilerOptions: {
|
|
175
|
+
module: 'commonjs',
|
|
176
|
+
esModuleInterop: true,
|
|
177
|
+
target: 'es2020',
|
|
178
|
+
sourceMap: true,
|
|
179
|
+
pretty: true,
|
|
180
|
+
noEmitOnError: true,
|
|
181
|
+
incremental: true,
|
|
182
|
+
strict: true,
|
|
183
|
+
outDir: 'dist',
|
|
184
|
+
skipLibCheck: true
|
|
185
|
+
},
|
|
186
|
+
watchOptions: {
|
|
187
|
+
watchFile: 'fixedPollingInterval',
|
|
188
|
+
watchDirectory: 'fixedPollingInterval',
|
|
189
|
+
fallbackPolling: 'dynamicPriority',
|
|
190
|
+
synchronousWatchDirectory: true,
|
|
191
|
+
excludeDirectories: ['**/node_modules', 'dist']
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
`
|
|
195
|
+
|
|
196
|
+
const PLT_ENVIRONMENT_TEMPLATE = `
|
|
197
|
+
import { type FastifyInstance } from 'fastify'
|
|
198
|
+
import { PlatformaticApplication, PlatformaticServiceConfig } from '@platformatic/service'
|
|
199
|
+
|
|
200
|
+
declare module 'fastify' {
|
|
201
|
+
interface FastifyInstance {
|
|
202
|
+
platformatic: PlatformaticApplication<PlatformaticServiceConfig>
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
`
|
|
206
|
+
|
|
207
|
+
const README = `
|
|
208
|
+
# Platformatic Service API
|
|
209
|
+
|
|
210
|
+
This is a generated [Platformatic Service](https://docs.platformatic.dev/docs/service/overview) application.
|
|
211
|
+
|
|
212
|
+
## Requirements
|
|
213
|
+
|
|
214
|
+
Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
|
|
215
|
+
You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0
|
|
216
|
+
|
|
217
|
+
## Setup
|
|
218
|
+
|
|
219
|
+
Install dependencies:
|
|
220
|
+
|
|
221
|
+
\`\`\`bash
|
|
222
|
+
npm install
|
|
223
|
+
\`\`\`
|
|
224
|
+
|
|
225
|
+
## Usage
|
|
226
|
+
|
|
227
|
+
Run the API with:
|
|
228
|
+
|
|
229
|
+
\`\`\`bash
|
|
230
|
+
npm start
|
|
231
|
+
\`\`\`
|
|
232
|
+
|
|
233
|
+
### Explore
|
|
234
|
+
- ⚡ The Platformatic DB server is running at http://localhost:3042/
|
|
235
|
+
- 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
|
|
236
|
+
- 🔍 Try out the GraphiQL web UI at http://localhost:3042/graphiql
|
|
237
|
+
`
|
|
238
|
+
|
|
239
|
+
export function applyTestHelperCustomizations (testHelper, mod, customizations) {
|
|
240
|
+
return testHelper
|
|
241
|
+
.replaceAll('$__MOD__', mod || '@platformatic/service')
|
|
242
|
+
.replaceAll('$__REQUIRES__', customizations.requires || '')
|
|
243
|
+
.replaceAll('$__PRE__', customizations.pre || '')
|
|
244
|
+
.replaceAll('$__CONFIG__', customizations.config || '')
|
|
245
|
+
.replaceAll('$__POST__', customizations.post || '')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export class Generator extends BaseGenerator {
|
|
249
|
+
constructor (opts = {}) {
|
|
250
|
+
super({
|
|
251
|
+
module: '@platformatic/service',
|
|
252
|
+
...opts
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
getConfigFieldsDefinitions () {
|
|
257
|
+
if (this.config.isRuntimeContext) {
|
|
258
|
+
return []
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return [
|
|
262
|
+
{
|
|
263
|
+
var: 'PLT_SERVER_HOSTNAME',
|
|
264
|
+
label: 'What is the hostname?',
|
|
265
|
+
default: '0.0.0.0',
|
|
266
|
+
type: 'string',
|
|
267
|
+
configValue: 'hostname'
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
var: 'PLT_SERVER_LOGGER_LEVEL',
|
|
271
|
+
label: 'What is the logger level?',
|
|
272
|
+
default: 'info',
|
|
273
|
+
type: 'string',
|
|
274
|
+
configValue: ''
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
label: 'Which port do you want to use?',
|
|
278
|
+
var: 'PORT',
|
|
279
|
+
default: 3042,
|
|
280
|
+
type: 'number',
|
|
281
|
+
configValue: 'port'
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
getDefaultConfig () {
|
|
287
|
+
const defaultBaseConfig = super.getDefaultConfig()
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
...defaultBaseConfig,
|
|
291
|
+
plugin: true,
|
|
292
|
+
tests: true
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async prepareQuestions () {
|
|
297
|
+
await super.prepareQuestions()
|
|
298
|
+
|
|
299
|
+
if (!this.config.skipTypescript) {
|
|
300
|
+
this.questions.push({
|
|
301
|
+
type: 'list',
|
|
302
|
+
name: 'typescript',
|
|
303
|
+
message: 'Do you want to use TypeScript?',
|
|
304
|
+
default: false,
|
|
305
|
+
choices: [
|
|
306
|
+
{ name: 'yes', value: true },
|
|
307
|
+
{ name: 'no', value: false }
|
|
308
|
+
]
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async _beforePrepare () {
|
|
314
|
+
if (this.config.isUpdating) {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!this.config.isRuntimeContext) {
|
|
319
|
+
this.addEnvVars(
|
|
320
|
+
{
|
|
321
|
+
PLT_SERVER_HOSTNAME: this.config.hostname,
|
|
322
|
+
PLT_SERVER_LOGGER_LEVEL: 'info',
|
|
323
|
+
PORT: 3042
|
|
324
|
+
},
|
|
325
|
+
{ overwrite: false }
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
this.config.dependencies = {
|
|
330
|
+
'@platformatic/service': `^${this.platformaticVersion}`
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async _afterPrepare () {
|
|
335
|
+
// if we are NOT updating, create env and files, otherwise leave as it is
|
|
336
|
+
if (this.config.isUpdating) {
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (this.config.typescript) {
|
|
341
|
+
this.addFile({ path: '', file: 'tsconfig.json', contents: TS_CONFIG })
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
this.addFile({ path: '', file: 'plt-env.d.ts', contents: PLT_ENVIRONMENT_TEMPLATE })
|
|
345
|
+
this.addFile({ path: '', file: 'README.md', contents: README })
|
|
346
|
+
|
|
347
|
+
if (this.config.plugin) {
|
|
348
|
+
// create plugin
|
|
349
|
+
this.files.push({
|
|
350
|
+
path: 'plugins',
|
|
351
|
+
file: this.config.typescript ? 'example.ts' : 'example.js',
|
|
352
|
+
contents: this.config.typescript ? TS_PLUGIN_WITH_TYPES_SUPPORT : JS_PLUGIN_WITH_TYPES_SUPPORT
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
this.files.push({
|
|
356
|
+
path: 'routes',
|
|
357
|
+
file: this.config.typescript ? 'root.ts' : 'root.js',
|
|
358
|
+
contents: this.config.typescript ? TS_ROUTES_WITH_TYPES_SUPPORT : JS_ROUTES_WITH_TYPES_SUPPORT
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
if (this.config.tests) {
|
|
362
|
+
if (this.config.typescript) {
|
|
363
|
+
this.files.push({
|
|
364
|
+
path: 'test',
|
|
365
|
+
file: 'helper.ts',
|
|
366
|
+
contents: applyTestHelperCustomizations(TEST_HELPER_TS, this.module, this.testHelperCustomizations ?? {})
|
|
367
|
+
})
|
|
368
|
+
this.files.push({
|
|
369
|
+
path: join('test', 'plugins'),
|
|
370
|
+
file: 'example.test.ts',
|
|
371
|
+
contents: TEST_PLUGIN_TS
|
|
372
|
+
})
|
|
373
|
+
this.files.push({
|
|
374
|
+
path: join('test', 'routes'),
|
|
375
|
+
file: 'root.test.ts',
|
|
376
|
+
contents: TEST_ROUTES_TS
|
|
377
|
+
})
|
|
378
|
+
} else {
|
|
379
|
+
this.files.push({
|
|
380
|
+
path: 'test',
|
|
381
|
+
file: 'helper.js',
|
|
382
|
+
contents: applyTestHelperCustomizations(TEST_HELPER_JS, this.module, this.testHelperCustomizations ?? {})
|
|
383
|
+
})
|
|
384
|
+
this.files.push({
|
|
385
|
+
path: join('test', 'plugins'),
|
|
386
|
+
file: 'example.test.js',
|
|
387
|
+
contents: TEST_PLUGIN_JS
|
|
388
|
+
})
|
|
389
|
+
this.files.push({
|
|
390
|
+
path: join('test', 'routes'),
|
|
391
|
+
file: 'root.test.js',
|
|
392
|
+
contents: TEST_ROUTES_JS
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async _getConfigFileContents () {
|
|
400
|
+
const config = {
|
|
401
|
+
$schema: `https://schemas.platformatic.dev/@platformatic/service/${this.platformaticVersion}.json`,
|
|
402
|
+
service: {
|
|
403
|
+
openapi: true
|
|
404
|
+
},
|
|
405
|
+
watch: true
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (this.config.plugin) {
|
|
409
|
+
config.plugins = {
|
|
410
|
+
paths: [{ path: './plugins', encapsulate: false }, './routes']
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (!this.config.isRuntimeContext) {
|
|
415
|
+
config.server = {
|
|
416
|
+
hostname: '{PLT_SERVER_HOSTNAME}',
|
|
417
|
+
port: '{PORT}',
|
|
418
|
+
logger: {
|
|
419
|
+
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return config
|
|
425
|
+
}
|
|
426
|
+
}
|
package/lib/plugins/cors.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fp = require('fastify-plugin')
|
|
1
|
+
import fastifyCors from '@fastify/cors'
|
|
2
|
+
import fp from 'fastify-plugin'
|
|
4
3
|
|
|
5
4
|
function originToRegexp (origin) {
|
|
6
5
|
if (typeof origin === 'object') {
|
|
@@ -12,9 +11,7 @@ function originToRegexp (origin) {
|
|
|
12
11
|
return origin
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
async function
|
|
16
|
-
const cors = opts
|
|
17
|
-
|
|
14
|
+
async function setupCorsPlugin (app, cors) {
|
|
18
15
|
let origin = cors.origin
|
|
19
16
|
if (Array.isArray(origin)) {
|
|
20
17
|
origin = origin.map(originToRegexp)
|
|
@@ -23,7 +20,7 @@ async function setupClients (app, opts) {
|
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
cors.origin = origin
|
|
26
|
-
app.register(
|
|
23
|
+
app.register(fastifyCors, cors)
|
|
27
24
|
}
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
export const setupCors = fp(setupCorsPlugin)
|
package/lib/plugins/graphql.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const deepmerge = require('@fastify/deepmerge')({ all: true })
|
|
5
|
-
const fp = require('fastify-plugin')
|
|
1
|
+
import { deepmerge } from '@platformatic/foundation'
|
|
2
|
+
import fp from 'fastify-plugin'
|
|
3
|
+
import mercurius from 'mercurius'
|
|
6
4
|
|
|
7
5
|
// For some unknown reason, c8 is not detecting any of this
|
|
8
6
|
// despite being covered by test/graphql.test.js
|
|
9
7
|
/* c8 ignore next 12 */
|
|
10
|
-
async function
|
|
11
|
-
if (typeof
|
|
12
|
-
|
|
8
|
+
async function setupGraphQLPlugin (app, options) {
|
|
9
|
+
if (typeof options !== 'object') {
|
|
10
|
+
options = {}
|
|
13
11
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
|
|
13
|
+
const graphqlOptions = deepmerge(
|
|
14
|
+
{
|
|
15
|
+
graphiql: true,
|
|
16
|
+
additionalRouteOptions: {
|
|
17
|
+
schema: { hide: true }
|
|
18
|
+
}
|
|
18
19
|
},
|
|
19
|
-
|
|
20
|
+
options
|
|
21
|
+
)
|
|
20
22
|
|
|
21
23
|
app.register(mercurius, graphqlOptions)
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
export const setupGraphQL = fp(setupGraphQLPlugin)
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import underPressure from '@fastify/under-pressure'
|
|
2
|
+
import fp from 'fastify-plugin'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
async function setupClients (app, opts) {
|
|
7
|
-
const healthCheck = opts
|
|
4
|
+
async function setupHealthCheckPlugin (app, options) {
|
|
5
|
+
const healthCheck = options
|
|
8
6
|
|
|
9
7
|
app.register(underPressure, {
|
|
10
8
|
exposeStatusRoute: '/status',
|
|
11
9
|
healthCheckInterval: healthCheck.interval !== undefined ? healthCheck.interval : 5000,
|
|
12
10
|
...healthCheck,
|
|
13
|
-
healthCheck: healthCheck.fn
|
|
11
|
+
healthCheck: healthCheck.fn
|
|
14
12
|
})
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
export const setupHealthCheck = fp(setupHealthCheckPlugin)
|
package/lib/plugins/openapi.js
CHANGED
|
@@ -1,70 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const ScalarApiReference = require('@scalar/fastify-api-reference')
|
|
5
|
-
const deepmerge = require('@fastify/deepmerge')({ all: true })
|
|
6
|
-
const fp = require('fastify-plugin')
|
|
1
|
+
import Swagger from '@fastify/swagger'
|
|
2
|
+
import { deepmerge } from '@platformatic/foundation'
|
|
3
|
+
import fp from 'fastify-plugin'
|
|
7
4
|
|
|
8
5
|
// For some unknown reason, c8 is not detecting any of this
|
|
9
6
|
// pf
|
|
10
7
|
// despite being covered by test/routes.test.js
|
|
11
8
|
/* c8 ignore next 33 */
|
|
12
|
-
async function
|
|
13
|
-
const { openapi } =
|
|
14
|
-
const openapiConfig = deepmerge(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
async function setupOpenAPIPlugin (app, options) {
|
|
10
|
+
const { openapi } = options
|
|
11
|
+
const openapiConfig = deepmerge(
|
|
12
|
+
{
|
|
13
|
+
exposeRoute: true,
|
|
14
|
+
info: {
|
|
15
|
+
title: 'Platformatic',
|
|
16
|
+
description: 'This is a service built on top of Platformatic',
|
|
17
|
+
version: '1.0.0'
|
|
18
|
+
},
|
|
19
|
+
servers: [{ url: globalThis.platformatic?.runtimeBasePath ?? '/' }]
|
|
20
20
|
},
|
|
21
|
-
|
|
21
|
+
typeof openapi === 'object' ? openapi : {}
|
|
22
|
+
)
|
|
22
23
|
app.log.trace({ openapi: openapiConfig })
|
|
23
24
|
const swaggerOptions = {
|
|
24
25
|
exposeRoute: openapiConfig.exposeRoute,
|
|
25
26
|
openapi: {
|
|
26
|
-
...openapiConfig
|
|
27
|
+
...openapiConfig
|
|
27
28
|
},
|
|
28
29
|
refResolver: {
|
|
29
30
|
buildLocalReference (json, baseUri, fragment, i) {
|
|
30
31
|
// TODO figure out if we need def-${i}
|
|
31
32
|
/* istanbul ignore next */
|
|
32
33
|
return json.$id || `def-${i}`
|
|
33
|
-
}
|
|
34
|
-
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
if (openapi.path) {
|
|
38
39
|
swaggerOptions.mode = 'static'
|
|
39
40
|
swaggerOptions.specification = {
|
|
40
|
-
path: openapi.path
|
|
41
|
+
path: openapi.path
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
await app.register(Swagger, swaggerOptions)
|
|
45
46
|
|
|
46
47
|
const { default: scalarTheme } = await import('@platformatic/scalar-theme')
|
|
48
|
+
const { default: scalarApiReference } = await import('@scalar/fastify-api-reference')
|
|
49
|
+
|
|
47
50
|
const routePrefix = openapi.swaggerPrefix || '/documentation'
|
|
48
51
|
|
|
49
52
|
/** Serve spec file in yaml and json */
|
|
50
|
-
app.get(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
app.get(
|
|
54
|
+
`${routePrefix}/json`,
|
|
55
|
+
{
|
|
56
|
+
schema: { hide: true },
|
|
57
|
+
logLevel: 'warn'
|
|
58
|
+
},
|
|
59
|
+
async () => app.swagger()
|
|
60
|
+
)
|
|
61
|
+
app.get(
|
|
62
|
+
`${routePrefix}/yaml`,
|
|
63
|
+
{
|
|
64
|
+
schema: { hide: true },
|
|
65
|
+
logLevel: 'warn'
|
|
66
|
+
},
|
|
67
|
+
async () => app.swagger({ yaml: true })
|
|
68
|
+
)
|
|
58
69
|
|
|
59
|
-
app.register(
|
|
60
|
-
...
|
|
70
|
+
app.register(scalarApiReference, {
|
|
71
|
+
...options,
|
|
61
72
|
...openapi,
|
|
62
73
|
routePrefix,
|
|
63
74
|
publicPath: './',
|
|
64
75
|
configuration: {
|
|
65
|
-
customCss: scalarTheme.theme
|
|
66
|
-
}
|
|
76
|
+
customCss: scalarTheme.theme
|
|
77
|
+
}
|
|
67
78
|
})
|
|
68
79
|
}
|
|
69
80
|
|
|
70
|
-
|
|
81
|
+
export const setupOpenAPI = fp(setupOpenAPIPlugin)
|