@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.
Files changed (54) hide show
  1. package/LICENSE +1 -1
  2. package/config.d.ts +450 -94
  3. package/eslint.config.js +4 -6
  4. package/index.d.ts +55 -48
  5. package/index.js +44 -179
  6. package/lib/application.js +35 -0
  7. package/lib/capability.js +281 -0
  8. package/lib/compile.js +2 -52
  9. package/lib/generator.js +426 -0
  10. package/lib/plugins/cors.js +5 -8
  11. package/lib/plugins/graphql.js +16 -14
  12. package/lib/plugins/health-check.js +6 -8
  13. package/lib/plugins/openapi.js +43 -32
  14. package/lib/plugins/plugins.js +6 -53
  15. package/lib/{root-endpoint/index.js → plugins/root.js} +9 -8
  16. package/lib/plugins/sandbox-wrapper.js +65 -63
  17. package/lib/schema.js +1075 -203
  18. package/lib/upgrade.js +6 -8
  19. package/lib/utils.js +30 -83
  20. package/lib/versions/0.16.0.js +14 -15
  21. package/lib/versions/{from-zero-twenty-eight-to-will-see.js → 0.28.0.js} +3 -6
  22. package/lib/versions/2.0.0.js +4 -7
  23. package/lib/versions/3.0.0.js +14 -0
  24. package/package.json +28 -36
  25. package/schema.json +1452 -165
  26. package/tsconfig.json +16 -6
  27. package/.c8rc +0 -6
  28. package/help/compile.txt +0 -19
  29. package/help/create.txt +0 -11
  30. package/help/help.txt +0 -8
  31. package/help/schema.txt +0 -9
  32. package/help/start.txt +0 -23
  33. package/index.test-d.ts +0 -107
  34. package/lib/create.mjs +0 -85
  35. package/lib/gen-schema.js +0 -15
  36. package/lib/gen-types.mjs +0 -38
  37. package/lib/generator/README.md +0 -31
  38. package/lib/generator/service-generator.d.ts +0 -11
  39. package/lib/generator/service-generator.js +0 -126
  40. package/lib/openapi-schema-defs.js +0 -1108
  41. package/lib/plugins/clients.js +0 -16
  42. package/lib/plugins/metrics.js +0 -244
  43. package/lib/plugins/typescript.js +0 -20
  44. package/lib/stackable.js +0 -306
  45. package/lib/start.js +0 -175
  46. package/service.mjs +0 -71
  47. /package/{lib/root-endpoint/public → public}/images/dark_mode.svg +0 -0
  48. /package/{lib/root-endpoint/public → public}/images/favicon.ico +0 -0
  49. /package/{lib/root-endpoint/public → public}/images/light_mode.svg +0 -0
  50. /package/{lib/root-endpoint/public → public}/images/platformatic-logo-dark.svg +0 -0
  51. /package/{lib/root-endpoint/public → public}/images/platformatic-logo-light.svg +0 -0
  52. /package/{lib/root-endpoint/public → public}/images/triangle_dark.svg +0 -0
  53. /package/{lib/root-endpoint/public → public}/images/triangle_light.svg +0 -0
  54. /package/{lib/root-endpoint/public → public}/index.html +0 -0
package/index.d.ts CHANGED
@@ -1,66 +1,73 @@
1
- /// <reference types="mercurius" />
2
- /// <reference types="@fastify/swagger" />
3
- import { FastifyInstance, FastifyBaseLogger } from 'fastify'
4
- import ConfigManager from '@platformatic/config'
5
- import type { ConfigManagerConfig } from '@platformatic/config'
6
- import type { Stackable as _Stackable, StackableInterface } from '@platformatic/config'
1
+ import { BaseCapability, BaseContext, BaseOptions } from '@platformatic/basic'
2
+ import { Configuration, ConfigurationOptions } from '@platformatic/foundation'
7
3
  import { BaseGenerator } from '@platformatic/generators'
8
- import { PlatformaticService } from './config'
9
- import type { JSONSchemaType } from 'ajv'
10
- import { ServiceGenerator } from './lib/generator/service-generator'
4
+ import { JSONSchemaType } from 'ajv'
5
+ import { FastifyInstance } from 'fastify'
6
+ import type { PlatformaticServiceConfig } from './config.d.ts'
11
7
 
12
- export import Generator = ServiceGenerator.ServiceGenerator
8
+ export type { PlatformaticServiceConfig } from './config.d.ts'
13
9
 
14
- export interface PlatformaticApp<T> {
15
- configManager: ConfigManager<T>
16
- config: T
10
+ export interface ServiceContext extends BaseContext {
11
+ applicationFactory?: typeof platformaticService
12
+ fastifyPlugins?: Function[]
17
13
  }
18
14
 
19
- export type PlatformaticServiceConfig = PlatformaticService
20
-
21
- export function buildServer (opts: object, app?: object, ConfigManagerConstructor?: object): Promise<FastifyInstance>
22
- export function start<ConfigType> (app: Stackable<ConfigType>, args: string[]): Promise<void>
15
+ export interface PlatformaticApplication<Config> {
16
+ config: Configuration<Config>
17
+ }
23
18
 
24
- declare module 'fastify' {
25
- interface FastifyInstance {
26
- restart: () => Promise<void>
27
- }
19
+ export type ServerInstance<Configuration = PlatformaticServiceConfig> = FastifyInstance & {
20
+ platformatic: PlatformaticApplication<Configuration>
28
21
  }
29
22
 
30
- type DefaultGenerator = new () => BaseGenerator.BaseGenerator
23
+ export type ServiceConfiguration<T = {}> = Configuration<PlatformaticServiceConfig & T>
31
24
 
32
- export interface Stackable<ConfigType, Generator = DefaultGenerator> extends _Stackable<ConfigType> {
33
- app: (app: FastifyInstance, opts: object) => Promise<void>
34
- Generator?: Generator
35
- version?: string
36
- upgrade?: (config: any, version: string) => Promise<any>
37
- transformConfig?: (config: any) => Promise<any>
38
- buildStackable: (opts: { config: string }, app?: object) => Promise<StackableInterface>
39
- }
25
+ export declare function transform (config: ServiceConfiguration): Promise<ServiceConfiguration>
40
26
 
41
- interface TSCompilerOptions {
42
- clean: boolean
43
- }
44
- interface TSCompiler {
45
- compile: (cwd: string, config: object, originalLogger: FastifyBaseLogger, options: TSCompilerOptions) => Promise<boolean>
46
- }
27
+ export declare function loadConfiguration (
28
+ root: string | PlatformaticServiceConfig,
29
+ source?: string | PlatformaticServiceConfig,
30
+ context?: ConfigurationOptions
31
+ ): Promise<Configuration<PlatformaticServiceConfig>>
32
+
33
+ export declare function create (
34
+ root: string | PlatformaticServiceConfig,
35
+ source?: string | PlatformaticServiceConfig,
36
+ context?: ConfigurationOptions
37
+ ): Promise<ServiceCapability>
47
38
 
48
- export const schema: JSONSchemaType<PlatformaticServiceConfig>
49
- export const configManagerConfig: ConfigManagerConfig<PlatformaticServiceConfig>
39
+ export declare const skipTelemetryHooks: boolean
50
40
 
51
- export declare const platformaticService: Stackable<PlatformaticServiceConfig>
41
+ export declare function platformaticService (app: FastifyInstance, capability: ServiceCapability): Promise<void>
52
42
 
53
- export declare const app: (app: FastifyInstance, opts: object) => Promise<void>
43
+ export declare class Generator extends BaseGenerator {}
44
+ export declare function applyTestHelperCustomizations (
45
+ helper: string,
46
+ mod: string,
47
+ customizations: Record<string, string>
48
+ ): string
54
49
 
55
- export const tsCompiler: TSCompiler
50
+ export declare const packageJson: Record<string, unknown>
56
51
 
57
- type defaultExport = Stackable<PlatformaticServiceConfig> & {
58
- buildServer: (opts: object, app?: object, ConfigManagerConstructor?: object) => Promise<FastifyInstance>,
59
- start: <ConfigType>(app: Stackable<ConfigType>, args: string[]) => Promise<void>,
60
- tsCompiler: TSCompiler,
61
- schema: JSONSchemaType<PlatformaticServiceConfig>,
52
+ export declare const schema: JSONSchemaType<PlatformaticServiceConfig>
53
+
54
+ export declare const schemaComponents: {
55
+ $defs: JSONSchemaType<object>
56
+ plugins: JSONSchemaType<object>
57
+ openApiBase: JSONSchemaType<object>
58
+ openapi: JSONSchemaType<object>
59
+ proxy: JSONSchemaType<object>
60
+ graphqlBase: JSONSchemaType<object>
61
+ graphql: JSONSchemaType<object>
62
+ application: JSONSchemaType<object>
62
63
  }
63
64
 
64
- export function buildStackable (opts: { config: string }, app?: object): Promise<StackableInterface>
65
+ export declare const version: string
65
66
 
66
- export default defaultExport
67
+ export declare class ServiceCapability<Config = PlatformaticServiceConfig> extends BaseCapability<
68
+ Config,
69
+ BaseOptions<ServiceContext>
70
+ > {
71
+ constructor (root: string, config: Config, context?: object)
72
+ getApplication (): FastifyInstance
73
+ }
package/index.js CHANGED
@@ -1,198 +1,63 @@
1
- 'use strict'
1
+ import { transform as basicTransform, resolve, validationOptions } from '@platformatic/basic'
2
+ import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
3
+ import { readFile } from 'node:fs/promises'
4
+ import { join } from 'node:path'
5
+ import { ServiceCapability } from './lib/capability.js'
6
+ import { schema } from './lib/schema.js'
7
+ import { upgrade } from './lib/upgrade.js'
8
+ import { isDocker } from './lib/utils.js'
2
9
 
3
- const { isKeyEnabled } = require('@platformatic/utils')
4
- const { loadConfig, ConfigManager } = require('@platformatic/config')
5
- const { readFile } = require('fs/promises')
6
- const { join } = require('path')
10
+ export async function transform (config, schema, options) {
11
+ config = await basicTransform(config, schema, options)
7
12
 
8
- const setupCors = require('./lib/plugins/cors')
9
- const setupOpenAPI = require('./lib/plugins/openapi.js')
10
- const setupGraphQL = require('./lib/plugins/graphql.js')
11
- const setupClients = require('./lib/plugins/clients')
12
- const setupMetrics = require('./lib/plugins/metrics')
13
- const setupTsCompiler = require('./lib/plugins/typescript')
14
- const setupHealthCheck = require('./lib/plugins/health-check')
15
- const loadPlugins = require('./lib/plugins/plugins')
16
- const upgrade = require('./lib/upgrade')
17
- const { telemetry } = require('@platformatic/telemetry')
18
-
19
- const { buildCompileCmd, extractTypeScriptCompileOptionsFromConfig } = require('./lib/compile')
20
- const { schema } = require('./lib/schema')
21
- const { addLoggerToTheConfig } = require('./lib/utils')
22
- const { start, buildServer } = require('./lib/start')
23
- const ServiceGenerator = require('./lib/generator/service-generator.js')
24
- const { ServiceStackable } = require('./lib/stackable')
25
-
26
- const { version } = require('./package.json')
27
-
28
- // TODO(mcollina): arugments[2] is deprecated, remove it in the next major version.
29
- async function platformaticService (app, opts) {
30
- const configManager = app.platformatic.configManager
31
- const config = configManager.current
32
- const beforePlugins = opts.beforePlugins || arguments[2] || []
33
-
34
- if (isKeyEnabled('metrics', config)) {
35
- if (config.metrics.server === 'own' && parseInt(config.server.port) === parseInt(config.metrics.port)) {
36
- app.log.warn('In order to serve metrics on the same port as the core applicaton, set metrics.server to "parent".')
37
- config.metrics.server = 'parent'
38
- }
39
-
40
- app.register(setupMetrics, config.metrics)
41
- }
42
-
43
- // This must be done before loading the plugins, so they can inspect if the
44
- // openTelemetry decorator exists and then configure accordingly.
45
- if (isKeyEnabled('telemetry', config)) {
46
- await app.register(telemetry, config.telemetry)
47
- }
48
-
49
- // This must be done before loading the plugins, so they can be
50
- // configured accordingly
51
- if (isKeyEnabled('clients', config)) {
52
- app.register(setupClients, config.clients)
13
+ if (config.server && (await isDocker())) {
14
+ config.server.hostname = '0.0.0.0'
53
15
  }
54
16
 
55
- if (Array.isArray(beforePlugins)) {
56
- for (const plugin of beforePlugins) {
57
- app.register(plugin)
58
- }
59
- }
17
+ const typescript = config.plugins?.typescript
60
18
 
61
- const serviceConfig = config.service || {}
62
-
63
- if (isKeyEnabled('openapi', serviceConfig)) {
64
- const openapi = serviceConfig.openapi
65
- app.register(setupOpenAPI, { openapi })
66
- }
19
+ if (typescript) {
20
+ let { outDir, tsConfigFile } = typescript
21
+ tsConfigFile ??= 'tsconfig.json'
67
22
 
68
- if (isKeyEnabled('graphql', serviceConfig)) {
69
- app.register(setupGraphQL, serviceConfig.graphql)
70
- }
71
-
72
- if (config.plugins) {
73
- let registerTsCompiler = false
74
- const typescript = config.plugins.paths && config.plugins.typescript
75
- /* c8 ignore next 6 */
76
- if (typescript === true) {
77
- registerTsCompiler = true
78
- } else if (typeof typescript === 'object') {
79
- registerTsCompiler = typescript.enabled === true || typescript.enabled === undefined
80
- }
23
+ if (typeof outDir === 'undefined') {
24
+ try {
25
+ outDir = JSON.parse(await readFile(join(this.dirname, tsConfigFile), 'utf8')).compilerOptions.outDir
26
+ } catch {
27
+ // No-op
28
+ }
81
29
 
82
- if (registerTsCompiler) {
83
- app.register(setupTsCompiler, { context: opts.context })
30
+ outDir ||= 'dist'
84
31
  }
85
- app.register(loadPlugins, { context: opts.context })
86
- }
87
32
 
88
- if (isKeyEnabled('cors', config.server)) {
89
- app.register(setupCors, config.server.cors)
33
+ config.watch.ignore ??= []
34
+ config.watch.ignore.push(outDir + '/**/*')
90
35
  }
91
36
 
92
- if (isKeyEnabled('healthCheck', config.server)) {
93
- app.register(setupHealthCheck, config.server.healthCheck)
94
- }
37
+ return config
95
38
  }
96
39
 
97
- platformaticService[Symbol.for('skip-override')] = true
40
+ export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
41
+ const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'service')
98
42
 
99
- module.exports.configManagerConfig = {
100
- version,
101
- schema,
102
- allowToWatch: ['.env'],
103
- schemaOptions: {
104
- useDefaults: true,
105
- coerceTypes: true,
106
- allErrors: true,
107
- strict: false
108
- },
109
- async transformConfig () {
110
- // Set watch to true by default. This is not possible
111
- // to do in the schema, because it is uses an anyOf.
112
- if (this.current.watch === undefined) {
113
- this.current.watch = { enabled: false }
114
- }
115
-
116
- if (typeof this.current.watch !== 'object') {
117
- this.current.watch = { enabled: this.current.watch || false }
118
- }
119
-
120
- const typescript = this.current.plugins?.typescript
121
- if (typescript) {
122
- let outDir = typescript.outDir
123
- if (outDir === undefined) {
124
- let tsConfigFile = typescript.tsConfigFile || 'tsconfig.json'
125
- tsConfigFile = join(this.dirname, tsConfigFile)
126
- try {
127
- const tsConfig = JSON.parse(await readFile(tsConfigFile, 'utf8'))
128
- outDir = tsConfig.compilerOptions.outDir
129
- } catch {}
130
- outDir ||= 'dist'
131
- }
132
-
133
- this.current.watch.ignore ||= []
134
- this.current.watch.ignore.push(outDir + '/**/*')
135
- }
136
- },
137
- upgrade
43
+ return utilsLoadConfiguration(source, context?.schema ?? schema, {
44
+ validationOptions,
45
+ transform,
46
+ upgrade,
47
+ replaceEnv: true,
48
+ root,
49
+ ...context
50
+ })
138
51
  }
139
52
 
140
- platformaticService.configType = 'service'
141
- platformaticService.schema = schema
142
- platformaticService.configManagerConfig = module.exports.configManagerConfig
143
-
144
- function _buildServer (options, app) {
145
- return buildServer(options, app || module.exports)
53
+ export async function create (configOrRoot, sourceOrConfig, context) {
54
+ const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
55
+ return new ServiceCapability(config[kMetadata].root, config, context)
146
56
  }
147
57
 
148
- async function buildStackable (options, app = platformaticService, Stackable = ServiceStackable) {
149
- let configManager = options.configManager
150
-
151
- if (configManager === undefined) {
152
- if (typeof options.config === 'string') {
153
- ;({ configManager } = await loadConfig(
154
- {},
155
- ['-c', options.config],
156
- app,
157
- {
158
- onMissingEnv: options.onMissingEnv,
159
- context: options.context
160
- },
161
- true
162
- ))
163
- } else {
164
- configManager = new ConfigManager({
165
- ...app.configManagerConfig,
166
- source: options.config,
167
- dirname: options.context?.directory
168
- })
169
- await configManager.parseAndValidate()
170
- }
171
- }
172
-
173
- const stackable = new Stackable({
174
- init: () => buildServer({
175
- configManager,
176
- ...configManager.current,
177
- }, app, options.context),
178
- stackable: app,
179
- configManager,
180
- context: options.context
181
- })
182
-
183
- return stackable
184
- }
58
+ export const skipTelemetryHooks = true
185
59
 
186
- module.exports.configType = 'service'
187
- module.exports.app = platformaticService
188
- module.exports.schema = schema
189
- module.exports.buildServer = _buildServer
190
- module.exports.buildStackable = buildStackable
191
- module.exports.schemas = require('./lib/schema')
192
- module.exports.platformaticService = platformaticService
193
- module.exports.addLoggerToTheConfig = addLoggerToTheConfig
194
- module.exports.start = start
195
- module.exports.Generator = ServiceGenerator
196
- module.exports.ServiceStackable = ServiceStackable
197
- module.exports.buildCompileCmd = buildCompileCmd
198
- module.exports.extractTypeScriptCompileOptionsFromConfig = extractTypeScriptCompileOptionsFromConfig
60
+ export { platformaticService } from './lib/application.js'
61
+ export { ServiceCapability } from './lib/capability.js'
62
+ export { applyTestHelperCustomizations, Generator } from './lib/generator.js'
63
+ export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
@@ -0,0 +1,35 @@
1
+ import { isKeyEnabled } from '@platformatic/foundation'
2
+ import { setupCors } from './plugins/cors.js'
3
+ import { setupGraphQL } from './plugins/graphql.js'
4
+ import { setupHealthCheck } from './plugins/health-check.js'
5
+ import { setupOpenAPI } from './plugins/openapi.js'
6
+ import { loadPlugins } from './plugins/plugins.js'
7
+
8
+ export async function platformaticService (app, capability) {
9
+ const config = await capability.getConfig()
10
+
11
+ const serviceConfig = config.service || {}
12
+
13
+ if (isKeyEnabled('openapi', serviceConfig)) {
14
+ const openapi = serviceConfig.openapi
15
+ await app.register(setupOpenAPI, { openapi })
16
+ }
17
+
18
+ if (isKeyEnabled('graphql', serviceConfig)) {
19
+ await app.register(setupGraphQL, serviceConfig.graphql)
20
+ }
21
+
22
+ if (config.plugins) {
23
+ await app.register(loadPlugins, capability.context)
24
+ }
25
+
26
+ if (isKeyEnabled('cors', config.server)) {
27
+ await app.register(setupCors, config.server.cors)
28
+ }
29
+
30
+ if (isKeyEnabled('healthCheck', config.server)) {
31
+ await app.register(setupHealthCheck, config.server.healthCheck)
32
+ }
33
+ }
34
+
35
+ platformaticService[Symbol.for('skip-override')] = true
@@ -0,0 +1,281 @@
1
+ import { BaseCapability, cleanBasePath, ensureTrailingSlash, getServerUrl } from '@platformatic/basic'
2
+ import { buildPinoFormatters, buildPinoTimestamp, deepmerge, features, isKeyEnabled } from '@platformatic/foundation'
3
+ import { telemetry } from '@platformatic/telemetry'
4
+ import fastify from 'fastify'
5
+ import { printSchema } from 'graphql'
6
+ import { randomUUID } from 'node:crypto'
7
+ import { hostname } from 'node:os'
8
+ import pino from 'pino'
9
+ import { platformaticService } from './application.js'
10
+ import { setupRoot } from './plugins/root.js'
11
+ import { version } from './schema.js'
12
+ import { sanitizeHTTPSArgument } from './utils.js'
13
+
14
+ export class ServiceCapability extends BaseCapability {
15
+ #app
16
+ #basePath
17
+
18
+ constructor (root, config, context) {
19
+ super('service', version, root, config, context)
20
+ this.applicationFactory = this.context.applicationFactory ?? platformaticService
21
+ }
22
+
23
+ async init () {
24
+ await super.init()
25
+
26
+ if (this.#app) {
27
+ return
28
+ }
29
+
30
+ const config = this.config
31
+ this.#basePath = ensureTrailingSlash(cleanBasePath(config.basePath ?? this.applicationId))
32
+
33
+ // Create the application
34
+ this.#app = fastify({
35
+ ...this.serverConfig,
36
+ ...this.fastifyOptions,
37
+ genReqId () {
38
+ return randomUUID()
39
+ }
40
+ })
41
+
42
+ // This must be done before loading the plugins, so they can inspect if the
43
+ // openTelemetry decorator exists and then configure accordingly.
44
+ if (isKeyEnabled('telemetry', config)) {
45
+ await this.#app.register(telemetry, config.telemetry)
46
+ }
47
+
48
+ this.#app.decorate('platformatic', { config: this.config })
49
+
50
+ await this.#app.register(this.applicationFactory, this)
51
+
52
+ if (Array.isArray(this.context.fastifyPlugins)) {
53
+ for (const plugin of this.context.fastifyPlugins) {
54
+ await this.#app.register(plugin)
55
+ }
56
+ }
57
+
58
+ if (!this.#app.hasRoute({ url: '/', method: 'GET' }) && !this.#app.hasRoute({ url: '/*', method: 'GET' })) {
59
+ await this.#app.register(setupRoot)
60
+ }
61
+ }
62
+
63
+ async start (startOptions) {
64
+ // Compatibility with v2 service
65
+ const { listen } = startOptions ?? { listen: true }
66
+
67
+ // Make this idempotent
68
+ if (this.url) {
69
+ return this.url
70
+ }
71
+
72
+ // Create the application if needed
73
+ if (!this.#app) {
74
+ await this.init()
75
+ await this.#app.ready()
76
+ }
77
+
78
+ if (listen) {
79
+ await this._listen()
80
+ }
81
+
82
+ await this._collectMetrics()
83
+ return this.url
84
+ }
85
+
86
+ async stop () {
87
+ await super.stop()
88
+ await this.#app?.close()
89
+ }
90
+
91
+ async inject (injectParams, onInject) {
92
+ const response = await this.#app.inject(injectParams, onInject)
93
+
94
+ if (onInject) {
95
+ return
96
+ }
97
+
98
+ const { statusCode, statusMessage, headers, body } = response
99
+ return { statusCode, statusMessage, headers, body }
100
+ }
101
+
102
+ getApplication () {
103
+ return this.#app
104
+ }
105
+
106
+ async getDispatchFunc () {
107
+ await this.init()
108
+ return this.#app
109
+ }
110
+
111
+ async getConfig (includeMeta = false) {
112
+ let config = await super.getConfig(includeMeta)
113
+ const loggerInstance = this.serverConfig?.loggerInstance
114
+
115
+ if (loggerInstance) {
116
+ config = Object.assign({}, config)
117
+ const { loggerInstance: _, ...serverConfig } = this.serverConfig
118
+ config.server = { ...serverConfig, logger: { level: loggerInstance.level } }
119
+ }
120
+
121
+ return config
122
+ }
123
+
124
+ async getWatchConfig () {
125
+ const config = this.config
126
+
127
+ const enabled = config.watch?.enabled !== false && config.plugins !== undefined
128
+
129
+ if (!enabled) {
130
+ return { enabled, path: this.root }
131
+ }
132
+
133
+ return {
134
+ enabled,
135
+ path: this.root,
136
+ allow: config.watch?.allow,
137
+ ignore: config.watch?.ignore
138
+ }
139
+ }
140
+
141
+ getMeta () {
142
+ return {
143
+ gateway: {
144
+ tcp: typeof this.url !== 'undefined',
145
+ url: this.url,
146
+ prefix: this.basePath ?? this.#basePath,
147
+ wantsAbsoluteUrls: false,
148
+ needsRootTrailingSlash: false
149
+ },
150
+ connectionStrings: [this.connectionString]
151
+ }
152
+ }
153
+
154
+ async getOpenapiSchema () {
155
+ await this.init()
156
+ await this.#app.ready()
157
+ return this.#app.swagger ? this.#app.swagger() : null
158
+ }
159
+
160
+ async getGraphqlSchema () {
161
+ await this.init()
162
+ await this.#app.ready()
163
+ return this.#app.graphql ? printSchema(this.#app.graphql.schema) : null
164
+ }
165
+
166
+ async updateContext (context) {
167
+ super.updateContext(context)
168
+
169
+ this.context = { ...this.context, ...context }
170
+
171
+ if (!this.context) {
172
+ return
173
+ }
174
+
175
+ const { telemetryConfig, serverConfig, isEntrypoint, isProduction, logger } = this.context
176
+
177
+ const config = { ...this.config }
178
+
179
+ if (telemetryConfig) {
180
+ config.telemetry = telemetryConfig
181
+ }
182
+
183
+ const loggerInstance = logger ?? serverConfig?.loggerInstance ?? this.serverConfig?.loggerInstance
184
+
185
+ if (serverConfig) {
186
+ config.server = deepmerge(this.serverConfig, serverConfig ?? {})
187
+ }
188
+
189
+ config.server ??= {}
190
+
191
+ if (isProduction) {
192
+ if (config.plugins) {
193
+ config.plugins.typescript = false
194
+ }
195
+ config.watch = { enabled: false }
196
+ }
197
+
198
+ // Adjust server options
199
+ if (!isEntrypoint) {
200
+ config.server.trustProxy = true
201
+ }
202
+
203
+ if (config.server.https) {
204
+ config.server.https.key = await sanitizeHTTPSArgument(config.server.https.key)
205
+ config.server.https.cert = await sanitizeHTTPSArgument(config.server.https.cert)
206
+ }
207
+
208
+ // Assign the logger instance if it exists
209
+ if (loggerInstance) {
210
+ config.server = { ...config.server }
211
+ config.server.loggerInstance = loggerInstance
212
+ delete config.server.logger
213
+ }
214
+
215
+ this.serverConfig = config.server
216
+ this.config = config
217
+ }
218
+
219
+ _initializeLogger () {
220
+ if (this.context?.logger) {
221
+ return this.context.logger
222
+ } else if (this.config.server?.loggerInstance) {
223
+ return this.config.server?.loggerInstance
224
+ }
225
+
226
+ this.serverConfig ??= {}
227
+ this.loggerConfig = deepmerge(this.context.loggerConfig ?? {}, this.serverConfig?.logger ?? {})
228
+
229
+ const pinoOptions = {
230
+ ...(this.loggerConfig ?? {}),
231
+ level: this.loggerConfig?.level ?? 'trace'
232
+ }
233
+
234
+ this.registerGlobals({
235
+ logLevel: pinoOptions.level
236
+ })
237
+
238
+ if (this.context?.applicationId) {
239
+ pinoOptions.name = this.context.applicationId
240
+ }
241
+
242
+ if (this.context?.worker?.count > 1 && this.loggerConfig?.base !== null) {
243
+ pinoOptions.base = { pid: process.pid, hostname: hostname(), worker: this.context.worker.index }
244
+ } else if (this.loggerConfig?.base === null) {
245
+ pinoOptions.base = undefined
246
+ }
247
+
248
+ if (this.loggerConfig?.formatters) {
249
+ pinoOptions.formatters = buildPinoFormatters(this.loggerConfig?.formatters)
250
+ }
251
+ if (this.loggerConfig?.timestamp) {
252
+ pinoOptions.timestamp = buildPinoTimestamp(this.loggerConfig?.timestamp)
253
+ }
254
+
255
+ const logger = pino(pinoOptions)
256
+
257
+ // Only one of logger and loggerInstance should be set
258
+ this.serverConfig.loggerInstance = logger
259
+ delete this.serverConfig.logger
260
+
261
+ return logger
262
+ }
263
+
264
+ async _listen () {
265
+ const serverOptions = this.serverConfig
266
+ const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
267
+
268
+ if (this.isProduction && features.node.reusePort) {
269
+ listenOptions.reusePort = true
270
+ }
271
+
272
+ await this.#app.listen(listenOptions)
273
+ this.url = getServerUrl(this.#app.server)
274
+
275
+ if (this.serverConfig.http2 || this.serverConfig.https?.key) {
276
+ this.url = this.url.replace('http://', 'https://')
277
+ }
278
+
279
+ return this.url
280
+ }
281
+ }