@platformatic/nest 2.74.3 → 3.0.0-alpha.2
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 +1 -1
- package/index.js +24 -305
- package/lib/schema.js +6 -6
- package/lib/stackable.js +287 -0
- package/package.json +11 -9
- package/schema.json +3 -2
package/config.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -1,312 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '@platformatic/basic'
|
|
12
|
-
import { ConfigManager } from '@platformatic/config'
|
|
13
|
-
import { features } from '@platformatic/utils'
|
|
14
|
-
import getPort from 'get-port'
|
|
15
|
-
import inject from 'light-my-request'
|
|
16
|
-
import { readFile } from 'node:fs/promises'
|
|
17
|
-
import { dirname, resolve } from 'node:path'
|
|
18
|
-
import { pinoHttp } from 'pino-http'
|
|
19
|
-
import { satisfies } from 'semver'
|
|
20
|
-
import { packageJson, schema } from './lib/schema.js'
|
|
21
|
-
|
|
22
|
-
const supportedVersions = '^11.0.0'
|
|
23
|
-
|
|
24
|
-
export class NestStackable extends BaseStackable {
|
|
25
|
-
#basePath
|
|
26
|
-
#nestjsCore
|
|
27
|
-
#nestjsCli
|
|
28
|
-
#isFastify
|
|
29
|
-
#app
|
|
30
|
-
#server
|
|
31
|
-
#dispatcher
|
|
32
|
-
|
|
33
|
-
constructor (options, root, configManager) {
|
|
34
|
-
super('nest', packageJson.version, options, root, configManager)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async init () {
|
|
38
|
-
const config = this.configManager.current
|
|
39
|
-
|
|
40
|
-
this.#isFastify = config.nest.adapter === 'fastify'
|
|
41
|
-
this.#nestjsCore = resolve(resolvePackage(this.root, '@nestjs/core'))
|
|
42
|
-
// As @nest/cli is not exporting any file, we assume it's in the same folder of @nestjs/core.
|
|
43
|
-
this.#nestjsCli = resolve(this.#nestjsCore, '../../cli/bin/nest.js')
|
|
44
|
-
|
|
45
|
-
const nestPackage = JSON.parse(await readFile(resolve(dirname(this.#nestjsCore), 'package.json'), 'utf-8'))
|
|
46
|
-
|
|
47
|
-
if (!this.isProduction && !satisfies(nestPackage.version, supportedVersions)) {
|
|
48
|
-
throw new errors.UnsupportedVersion('@nestjs/core', nestPackage.version, supportedVersions)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
this.#basePath = config.application?.basePath
|
|
52
|
-
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
53
|
-
: undefined
|
|
54
|
-
|
|
55
|
-
this.registerGlobals({ basePath: this.#basePath })
|
|
56
|
-
|
|
57
|
-
this.subprocessForceClose = true
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async start ({ listen }) {
|
|
61
|
-
// Make this idempotent
|
|
62
|
-
if (this.url) {
|
|
63
|
-
return this.url
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const config = this.configManager.current
|
|
67
|
-
const command = config.application.commands[this.isProduction ? 'production' : 'development']
|
|
68
|
-
|
|
69
|
-
// In development mode, we use the Nest CLI in a children thread - Using build then start would result in a bad DX
|
|
70
|
-
this.on('config', config => {
|
|
71
|
-
this.#basePath = config.basePath
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
if (command || !this.isProduction) {
|
|
75
|
-
await this.startWithCommand(command || `node ${this.#nestjsCli} start --watch --preserveWatchOutput`)
|
|
76
|
-
} else {
|
|
77
|
-
return this.#startProduction(listen)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
async stop () {
|
|
82
|
-
if (this.childManager) {
|
|
83
|
-
return this.stopCommand()
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (this.#isFastify) {
|
|
87
|
-
return this.#server.close()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/* c8 ignore next 3 */
|
|
91
|
-
if (!this.#server?.listening) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return new Promise((resolve, reject) => {
|
|
96
|
-
this.#server.close(error => {
|
|
97
|
-
/* c8 ignore next 3 */
|
|
98
|
-
if (error) {
|
|
99
|
-
return reject(error)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
resolve()
|
|
103
|
-
})
|
|
104
|
-
})
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async build () {
|
|
108
|
-
if (!this.#nestjsCore) {
|
|
109
|
-
await this.init()
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const config = this.configManager.current
|
|
113
|
-
this.#basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
|
|
114
|
-
|
|
115
|
-
return this.buildWithCommand(config.application.commands.build ?? `node ${this.#nestjsCli} build`, this.#basePath)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async inject (injectParams, onInject) {
|
|
119
|
-
let res
|
|
120
|
-
|
|
121
|
-
if (this.#isFastify) {
|
|
122
|
-
res = await this.#server.inject(injectParams, onInject)
|
|
123
|
-
} else {
|
|
124
|
-
res = await inject(this.#dispatcher, injectParams, onInject)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/* c8 ignore next 3 */
|
|
128
|
-
if (onInject) {
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
133
|
-
const { statusCode, headers, body, payload, rawPayload } = res
|
|
134
|
-
return { statusCode, headers, body, payload, rawPayload }
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
getMeta () {
|
|
138
|
-
const hasBasePath = this.basePath || this.#basePath
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
composer: {
|
|
142
|
-
tcp: typeof this.url !== 'undefined',
|
|
143
|
-
url: this.url,
|
|
144
|
-
prefix: this.basePath ?? this.#basePath,
|
|
145
|
-
wantsAbsoluteUrls: !!hasBasePath,
|
|
146
|
-
needsRootTrailingSlash: false
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* c8 ignore next 5 */
|
|
152
|
-
async getWatchConfig () {
|
|
153
|
-
return {
|
|
154
|
-
enabled: false
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async getChildManagerContext (basePath) {
|
|
159
|
-
const context = await super.getChildManagerContext(basePath)
|
|
160
|
-
|
|
161
|
-
// In development mode we need to choose the random port in advance as the Nest CLI will start a new process
|
|
162
|
-
// every time the code changes and thus we need to ensure that the port is always the same.
|
|
163
|
-
if (!this.isProduction && (context.port === true || context.port === 0)) {
|
|
164
|
-
context.port = await getPort()
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return context
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
async #startProduction (listen) {
|
|
171
|
-
// Listen if entrypoint
|
|
172
|
-
if (this.#app && listen) {
|
|
173
|
-
await this.#listen()
|
|
174
|
-
return this.url
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const outputDirectory = this.configManager.current.application.outputDirectory
|
|
178
|
-
const { path, name } = this.configManager.current.nest.appModule
|
|
179
|
-
this.verifyOutputDirectory(resolve(this.root, outputDirectory))
|
|
180
|
-
|
|
181
|
-
// Import all the necessary modules
|
|
182
|
-
const { NestFactory } = await importFile(this.#nestjsCore)
|
|
183
|
-
const Adapter = await this.#importAdapter()
|
|
184
|
-
const appModuleExport = await importFile(resolve(this.root, `${outputDirectory}/${path}.js`))
|
|
185
|
-
const appModule = appModuleExport[name]
|
|
186
|
-
const setup = await this.#importSetup()
|
|
187
|
-
|
|
188
|
-
// Create the server
|
|
189
|
-
if (this.#isFastify) {
|
|
190
|
-
this.#app = await NestFactory.create(appModule, new Adapter({ loggerInstance: this.logger }))
|
|
191
|
-
|
|
192
|
-
setup?.(this.#app)
|
|
193
|
-
await this.#app.init()
|
|
194
|
-
|
|
195
|
-
this.#server = this.#app.getInstance()
|
|
196
|
-
} else {
|
|
197
|
-
this.#app = await NestFactory.create(appModule, new Adapter())
|
|
198
|
-
|
|
199
|
-
const instance = this.#app.getInstance()
|
|
200
|
-
instance.disable('x-powered-by')
|
|
201
|
-
instance.use(pinoHttp({ logger: this.logger }))
|
|
202
|
-
|
|
203
|
-
setup?.(this.#app)
|
|
204
|
-
await this.#app.init()
|
|
205
|
-
|
|
206
|
-
this.#server = this.#app.getHttpServer()
|
|
207
|
-
this.#dispatcher = this.#server.listeners('request')[0]
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (listen) {
|
|
211
|
-
await this.#listen()
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
await this._collectMetrics()
|
|
215
|
-
return this.url
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
async #listen () {
|
|
219
|
-
const serverOptions = this.serverConfig
|
|
220
|
-
const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
|
|
221
|
-
|
|
222
|
-
if (this.isProduction && features.node.reusePort) {
|
|
223
|
-
listenOptions.reusePort = true
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
await this.#app.listen(listenOptions)
|
|
227
|
-
this.url = getServerUrl(this.#isFastify ? this.#server.server : this.#server)
|
|
228
|
-
|
|
229
|
-
return this.url
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
async #importAdapter () {
|
|
233
|
-
let adapter
|
|
234
|
-
const toImport = `@nestjs/platform-${this.configManager.current.nest.adapter}`
|
|
235
|
-
|
|
236
|
-
this.logger.debug(`Using NestJS adapter ${toImport}.`)
|
|
237
|
-
|
|
238
|
-
try {
|
|
239
|
-
adapter = await importFile(resolvePackage(this.root, toImport))
|
|
240
|
-
return adapter[this.#isFastify ? 'FastifyAdapter' : 'ExpressAdapter']
|
|
241
|
-
} catch (e) {
|
|
242
|
-
throw new Error(`Cannot import the NestJS adapter. Please add ${toImport} to the dependencies and try again.`)
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async #importSetup () {
|
|
247
|
-
const config = this.configManager.current
|
|
248
|
-
|
|
249
|
-
if (!config.nest.setup.path) {
|
|
250
|
-
return undefined
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let setupModule
|
|
254
|
-
let setup
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
setupModule = await importFile(
|
|
258
|
-
resolve(this.root, `${config.application.outputDirectory}/${config.nest.setup.path}.js`)
|
|
259
|
-
)
|
|
260
|
-
} catch (e) {
|
|
261
|
-
throw new Error(`Cannot import the NestJS setup file: ${e.message}.`)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// This is for improved compatibility
|
|
265
|
-
if (config.nest.setup.name) {
|
|
266
|
-
setup = setupModule[config.setup.name]
|
|
267
|
-
} else {
|
|
268
|
-
setup = setupModule.default
|
|
269
|
-
|
|
270
|
-
if (setup && typeof setup !== 'function' && typeof setup.default === 'function') {
|
|
271
|
-
setup = setup.default
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (typeof setup !== 'function') {
|
|
276
|
-
const name = config.setup.name ? ` named ${config.setup.name}` : ''
|
|
277
|
-
throw new Error(`The NestJS setup file must export a function named ${name}, but got ${typeof setup}.`)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return setup
|
|
281
|
-
}
|
|
1
|
+
import { transform as basicTransform, resolve, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
|
|
3
|
+
import { schema } from './lib/schema.js'
|
|
4
|
+
import { NestStackable } from './lib/stackable.js'
|
|
5
|
+
|
|
6
|
+
/* c8 ignore next 5 */
|
|
7
|
+
export async function transform (config, schema, options) {
|
|
8
|
+
config = await basicTransform(config, schema, options)
|
|
9
|
+
config.watch = { enabled: false }
|
|
10
|
+
return config
|
|
282
11
|
}
|
|
283
12
|
|
|
284
|
-
export async function
|
|
285
|
-
const root =
|
|
13
|
+
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
14
|
+
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
|
|
286
15
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
context: opts.context
|
|
16
|
+
return utilsLoadConfiguration(source, context?.schema ?? schema, {
|
|
17
|
+
validationOptions,
|
|
18
|
+
transform,
|
|
19
|
+
replaceEnv: true,
|
|
20
|
+
root,
|
|
21
|
+
...context
|
|
294
22
|
})
|
|
295
|
-
await configManager.parseAndValidate()
|
|
296
|
-
|
|
297
|
-
return new NestStackable(opts, root, configManager)
|
|
298
23
|
}
|
|
299
24
|
|
|
300
|
-
export
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
configType: 'nest',
|
|
304
|
-
configManagerConfig: {
|
|
305
|
-
schemaOptions,
|
|
306
|
-
transformConfig
|
|
307
|
-
},
|
|
308
|
-
buildStackable,
|
|
309
|
-
schema,
|
|
310
|
-
version: packageJson.version,
|
|
311
|
-
modulesToLoad: []
|
|
25
|
+
export async function create (configOrRoot, sourceOrConfig, context) {
|
|
26
|
+
const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
|
|
27
|
+
return new NestStackable(config[kMetadata].root, config, context)
|
|
312
28
|
}
|
|
29
|
+
|
|
30
|
+
export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
|
|
31
|
+
export * from './lib/stackable.js'
|
package/lib/schema.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { schemaComponents as basicSchemaComponents } from '@platformatic/basic'
|
|
2
|
-
import { schemaComponents as utilsSchemaComponents } from '@platformatic/
|
|
2
|
+
import { schemaComponents as utilsSchemaComponents } from '@platformatic/foundation'
|
|
3
3
|
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { resolve } from 'node:path'
|
|
4
5
|
|
|
5
|
-
export const packageJson = JSON.parse(readFileSync(
|
|
6
|
-
|
|
6
|
+
export const packageJson = JSON.parse(readFileSync(resolve(import.meta.dirname, '../package.json'), 'utf8'))
|
|
7
7
|
export const version = packageJson.version
|
|
8
8
|
|
|
9
9
|
const nest = {
|
|
@@ -49,12 +49,12 @@ const nest = {
|
|
|
49
49
|
additionalProperties: false
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export const schemaComponents = {
|
|
52
|
+
export const schemaComponents = { nest }
|
|
53
53
|
|
|
54
54
|
export const schema = {
|
|
55
55
|
$id: `https://schemas.platformatic.dev/@platformatic/nest/${version}.json`,
|
|
56
56
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
57
|
-
title: 'Platformatic NestJS
|
|
57
|
+
title: 'Platformatic NestJS Config',
|
|
58
58
|
type: 'object',
|
|
59
59
|
properties: {
|
|
60
60
|
$schema: {
|
|
@@ -63,7 +63,7 @@ export const schema = {
|
|
|
63
63
|
logger: utilsSchemaComponents.logger,
|
|
64
64
|
server: utilsSchemaComponents.server,
|
|
65
65
|
watch: basicSchemaComponents.watch,
|
|
66
|
-
application: basicSchemaComponents.
|
|
66
|
+
application: basicSchemaComponents.buildableApplication,
|
|
67
67
|
runtime: utilsSchemaComponents.wrappedRuntime,
|
|
68
68
|
nest
|
|
69
69
|
},
|
package/lib/stackable.js
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BaseStackable,
|
|
3
|
+
cleanBasePath,
|
|
4
|
+
ensureTrailingSlash,
|
|
5
|
+
errors,
|
|
6
|
+
getServerUrl,
|
|
7
|
+
importFile,
|
|
8
|
+
resolvePackage
|
|
9
|
+
} from '@platformatic/basic'
|
|
10
|
+
import { features } from '@platformatic/foundation'
|
|
11
|
+
import getPort from 'get-port'
|
|
12
|
+
import inject from 'light-my-request'
|
|
13
|
+
import { readFile } from 'node:fs/promises'
|
|
14
|
+
import { dirname, resolve } from 'node:path'
|
|
15
|
+
import { pinoHttp } from 'pino-http'
|
|
16
|
+
import { satisfies } from 'semver'
|
|
17
|
+
import { version } from './schema.js'
|
|
18
|
+
|
|
19
|
+
const kITC = Symbol.for('plt.runtime.itc')
|
|
20
|
+
const supportedVersions = '^11.0.0'
|
|
21
|
+
|
|
22
|
+
export class NestStackable extends BaseStackable {
|
|
23
|
+
#basePath
|
|
24
|
+
#nestjsCore
|
|
25
|
+
#nestjsCli
|
|
26
|
+
#isFastify
|
|
27
|
+
#app
|
|
28
|
+
#server
|
|
29
|
+
#dispatcher
|
|
30
|
+
|
|
31
|
+
constructor (root, config, context) {
|
|
32
|
+
super('nest', version, root, config, context)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async init () {
|
|
36
|
+
await super.init()
|
|
37
|
+
|
|
38
|
+
const config = this.config
|
|
39
|
+
|
|
40
|
+
this.#isFastify = config.nest.adapter === 'fastify'
|
|
41
|
+
this.#nestjsCore = resolve(resolvePackage(this.root, '@nestjs/core'))
|
|
42
|
+
// As @nest/cli is not exporting any file, we assume it's in the same folder of @nestjs/core.
|
|
43
|
+
this.#nestjsCli = resolve(this.#nestjsCore, '../../cli/bin/nest.js')
|
|
44
|
+
|
|
45
|
+
const nestPackage = JSON.parse(await readFile(resolve(dirname(this.#nestjsCore), 'package.json'), 'utf-8'))
|
|
46
|
+
|
|
47
|
+
if (!this.isProduction && !satisfies(nestPackage.version, supportedVersions)) {
|
|
48
|
+
throw new errors.UnsupportedVersion('@nestjs/core', nestPackage.version, supportedVersions)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.#basePath = config.application?.basePath
|
|
52
|
+
? ensureTrailingSlash(cleanBasePath(config.application?.basePath))
|
|
53
|
+
: undefined
|
|
54
|
+
|
|
55
|
+
this.registerGlobals({ basePath: this.#basePath })
|
|
56
|
+
|
|
57
|
+
this.subprocessForceClose = true
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async start ({ listen }) {
|
|
61
|
+
// Make this idempotent
|
|
62
|
+
if (this.url) {
|
|
63
|
+
return this.url
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const config = this.config
|
|
67
|
+
const command = config.application.commands[this.isProduction ? 'production' : 'development']
|
|
68
|
+
|
|
69
|
+
// In development mode, we use the Nest CLI in a children thread - Using build then start would result in a bad DX
|
|
70
|
+
this.on('config', config => {
|
|
71
|
+
this.#basePath = config.basePath
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (command || !this.isProduction) {
|
|
75
|
+
await this.startWithCommand(command || `node ${this.#nestjsCli} start --watch --preserveWatchOutput`)
|
|
76
|
+
|
|
77
|
+
// We use url changing as a way to notify restarts
|
|
78
|
+
this.childManager.on('url', () => {
|
|
79
|
+
globalThis[kITC].notify('event', { event: 'url', url: this.url })
|
|
80
|
+
})
|
|
81
|
+
} else {
|
|
82
|
+
return this.#startProduction(listen)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async stop () {
|
|
87
|
+
if (this.childManager) {
|
|
88
|
+
return this.stopCommand()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (this.#isFastify) {
|
|
92
|
+
return this.#server.close()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* c8 ignore next 3 */
|
|
96
|
+
if (!this.#server?.listening) {
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
this.#server.close(error => {
|
|
102
|
+
/* c8 ignore next 3 */
|
|
103
|
+
if (error) {
|
|
104
|
+
return reject(error)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
resolve()
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async build () {
|
|
113
|
+
if (!this.#nestjsCore) {
|
|
114
|
+
await this.init()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const config = this.config
|
|
118
|
+
this.#basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
|
|
119
|
+
|
|
120
|
+
return this.buildWithCommand(config.application.commands.build ?? `node ${this.#nestjsCli} build`, this.#basePath)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async inject (injectParams, onInject) {
|
|
124
|
+
let res
|
|
125
|
+
|
|
126
|
+
if (this.#isFastify) {
|
|
127
|
+
res = await this.#server.inject(injectParams, onInject)
|
|
128
|
+
} else {
|
|
129
|
+
res = await inject(this.#dispatcher, injectParams, onInject)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* c8 ignore next 3 */
|
|
133
|
+
if (onInject) {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Since inject might be called from the main thread directly via ITC, let's clean it up
|
|
138
|
+
const { statusCode, headers, body, payload, rawPayload } = res
|
|
139
|
+
return { statusCode, headers, body, payload, rawPayload }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getMeta () {
|
|
143
|
+
const hasBasePath = this.basePath || this.#basePath
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
composer: {
|
|
147
|
+
tcp: typeof this.url !== 'undefined',
|
|
148
|
+
url: this.url,
|
|
149
|
+
prefix: this.basePath ?? this.#basePath,
|
|
150
|
+
wantsAbsoluteUrls: !!hasBasePath,
|
|
151
|
+
needsRootTrailingSlash: false
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* c8 ignore next 5 */
|
|
157
|
+
async getWatchConfig () {
|
|
158
|
+
return {
|
|
159
|
+
enabled: false
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async getChildManagerContext (basePath) {
|
|
164
|
+
const context = await super.getChildManagerContext(basePath)
|
|
165
|
+
|
|
166
|
+
// In development mode we need to choose the random port in advance as the Nest CLI will start a new process
|
|
167
|
+
// every time the code changes and thus we need to ensure that the port is always the same.
|
|
168
|
+
if (!this.isProduction && (context.port === true || context.port === 0)) {
|
|
169
|
+
context.port = await getPort()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return context
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async #startProduction (listen) {
|
|
176
|
+
// Listen if entrypoint
|
|
177
|
+
if (this.#app && listen) {
|
|
178
|
+
await this.#listen()
|
|
179
|
+
return this.url
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const outputDirectory = this.config.application.outputDirectory
|
|
183
|
+
const { path, name } = this.config.nest.appModule
|
|
184
|
+
this.verifyOutputDirectory(resolve(this.root, outputDirectory))
|
|
185
|
+
|
|
186
|
+
// Import all the necessary modules
|
|
187
|
+
const { NestFactory } = await importFile(this.#nestjsCore)
|
|
188
|
+
const Adapter = await this.#importAdapter()
|
|
189
|
+
const appModuleExport = await importFile(resolve(this.root, `${outputDirectory}/${path}.js`))
|
|
190
|
+
const appModule = appModuleExport[name]
|
|
191
|
+
const setup = await this.#importSetup()
|
|
192
|
+
|
|
193
|
+
// Create the server
|
|
194
|
+
if (this.#isFastify) {
|
|
195
|
+
this.#app = await NestFactory.create(appModule, new Adapter({ loggerInstance: this.logger }))
|
|
196
|
+
|
|
197
|
+
setup?.(this.#app)
|
|
198
|
+
await this.#app.init()
|
|
199
|
+
|
|
200
|
+
this.#server = this.#app.getInstance()
|
|
201
|
+
} else {
|
|
202
|
+
this.#app = await NestFactory.create(appModule, new Adapter())
|
|
203
|
+
|
|
204
|
+
const instance = this.#app.getInstance()
|
|
205
|
+
instance.disable('x-powered-by')
|
|
206
|
+
instance.use(pinoHttp({ logger: this.logger }))
|
|
207
|
+
|
|
208
|
+
setup?.(this.#app)
|
|
209
|
+
await this.#app.init()
|
|
210
|
+
|
|
211
|
+
this.#server = this.#app.getHttpServer()
|
|
212
|
+
this.#dispatcher = this.#server.listeners('request')[0]
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (listen) {
|
|
216
|
+
await this.#listen()
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
await this._collectMetrics()
|
|
220
|
+
return this.url
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async #listen () {
|
|
224
|
+
const serverOptions = this.serverConfig
|
|
225
|
+
const listenOptions = { host: serverOptions?.hostname || '127.0.0.1', port: serverOptions?.port || 0 }
|
|
226
|
+
|
|
227
|
+
if (this.isProduction && features.node.reusePort) {
|
|
228
|
+
listenOptions.reusePort = true
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
await this.#app.listen(listenOptions)
|
|
232
|
+
this.url = getServerUrl(this.#isFastify ? this.#server.server : this.#server)
|
|
233
|
+
|
|
234
|
+
return this.url
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async #importAdapter () {
|
|
238
|
+
let adapter
|
|
239
|
+
const toImport = `@nestjs/platform-${this.config.nest.adapter}`
|
|
240
|
+
|
|
241
|
+
this.logger.debug(`Using NestJS adapter ${toImport}.`)
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
adapter = await importFile(resolvePackage(this.root, toImport))
|
|
245
|
+
return adapter[this.#isFastify ? 'FastifyAdapter' : 'ExpressAdapter']
|
|
246
|
+
} catch (e) {
|
|
247
|
+
throw new Error(`Cannot import the NestJS adapter. Please add ${toImport} to the dependencies and try again.`)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async #importSetup () {
|
|
252
|
+
const config = this.config
|
|
253
|
+
|
|
254
|
+
if (!config.nest.setup.path) {
|
|
255
|
+
return undefined
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
let setupModule
|
|
259
|
+
let setup
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
setupModule = await importFile(
|
|
263
|
+
resolve(this.root, `${config.application.outputDirectory}/${config.nest.setup.path}.js`)
|
|
264
|
+
)
|
|
265
|
+
} catch (e) {
|
|
266
|
+
throw new Error(`Cannot import the NestJS setup file: ${e.message}.`)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// This is for improved compatibility
|
|
270
|
+
if (config.nest.setup.name) {
|
|
271
|
+
setup = setupModule[config.setup.name]
|
|
272
|
+
} else {
|
|
273
|
+
setup = setupModule.default
|
|
274
|
+
|
|
275
|
+
if (setup && typeof setup !== 'function' && typeof setup.default === 'function') {
|
|
276
|
+
setup = setup.default
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (typeof setup !== 'function') {
|
|
281
|
+
const name = config.setup.name ? ` named ${config.setup.name}` : ''
|
|
282
|
+
throw new Error(`The NestJS setup file must export a function named ${name}, but got ${typeof setup}.`)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return setup
|
|
286
|
+
}
|
|
287
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/nest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.2",
|
|
4
4
|
"description": "Platformatic Nest.js Stackable",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,10 +18,9 @@
|
|
|
18
18
|
"get-port": "^7.1.0",
|
|
19
19
|
"light-my-request": "^6.0.0",
|
|
20
20
|
"pino-http": "^10.2.0",
|
|
21
|
-
"@platformatic/
|
|
22
|
-
"@platformatic/
|
|
23
|
-
"@platformatic/
|
|
24
|
-
"@platformatic/basic": "2.74.3"
|
|
21
|
+
"@platformatic/generators": "3.0.0-alpha.2",
|
|
22
|
+
"@platformatic/basic": "3.0.0-alpha.2",
|
|
23
|
+
"@platformatic/foundation": "3.0.0-alpha.2"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"@nestjs/cli": "^11.0.7",
|
|
@@ -34,12 +33,15 @@
|
|
|
34
33
|
"neostandard": "^0.12.0",
|
|
35
34
|
"tsx": "^4.19.0",
|
|
36
35
|
"typescript": "^5.5.4",
|
|
37
|
-
"@platformatic/composer": "
|
|
38
|
-
"@platformatic/service": "
|
|
36
|
+
"@platformatic/composer": "3.0.0-alpha.2",
|
|
37
|
+
"@platformatic/service": "3.0.0-alpha.2"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.18.0"
|
|
39
41
|
},
|
|
40
42
|
"scripts": {
|
|
41
|
-
"test": "pnpm run lint && borp --concurrency=1 --
|
|
42
|
-
"coverage": "pnpm run lint && borp -C -X test -X test/fixtures --concurrency=1 --
|
|
43
|
+
"test": "pnpm run lint && borp --concurrency=1 --timeout 1200000",
|
|
44
|
+
"coverage": "pnpm run lint && borp -C -X test -X test/fixtures --concurrency=1 --timeout 1200000",
|
|
43
45
|
"gen-schema": "node lib/schema.js > schema.json",
|
|
44
46
|
"gen-types": "json2ts > config.d.ts < schema.json",
|
|
45
47
|
"build": "pnpm run gen-schema && pnpm run gen-types",
|
package/schema.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/nest/
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/nest/3.0.0-alpha.2.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
-
"title": "Platformatic NestJS
|
|
4
|
+
"title": "Platformatic NestJS Config",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"$schema": {
|
|
@@ -362,6 +362,7 @@
|
|
|
362
362
|
}
|
|
363
363
|
},
|
|
364
364
|
"additionalProperties": false,
|
|
365
|
+
"required": [],
|
|
365
366
|
"default": {}
|
|
366
367
|
},
|
|
367
368
|
"runtime": {
|