@platformatic/next 3.67.0 → 4.0.0-new-config.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/config.d.ts CHANGED
@@ -66,7 +66,7 @@ export interface PlatformaticNextJsConfig {
66
66
  hostname?: string;
67
67
  port?: number | string;
68
68
  /**
69
- * Configures how entrypoint server worker ports are assigned. When set to shared, all workers listen on the same port. When set to perWorkerIncrement, each worker will use its own port, starting from port (worker 0).
69
+ * Configures how the port is assigned when the application runs multiple workers. When set to shared (the default), all workers listen on the same port (which requires SO_REUSEPORT support). When set to perWorkerIncrement, each worker listens on its own port, starting from port (worker 0) and incrementing by one for each additional worker.
70
70
  */
71
71
  portAssignment?: "shared" | "perWorkerIncrement";
72
72
  /**
@@ -224,46 +224,6 @@ export interface PlatformaticNextJsConfig {
224
224
  };
225
225
  [k: string]: unknown;
226
226
  };
227
- server?: {
228
- hostname?: string;
229
- port?: number | string;
230
- /**
231
- * Configures how entrypoint server worker ports are assigned. When set to shared, all workers listen on the same port. When set to perWorkerIncrement, each worker will use its own port, starting from port (worker 0).
232
- */
233
- portAssignment?: "shared" | "perWorkerIncrement";
234
- /**
235
- * The maximum length of the queue of pending connections
236
- */
237
- backlog?: number;
238
- http2?: boolean;
239
- https?: {
240
- allowHTTP1?: boolean;
241
- key:
242
- | string
243
- | {
244
- path?: string;
245
- }
246
- | (
247
- | string
248
- | {
249
- path?: string;
250
- }
251
- )[];
252
- cert:
253
- | string
254
- | {
255
- path?: string;
256
- }
257
- | (
258
- | string
259
- | {
260
- path?: string;
261
- }
262
- )[];
263
- requestCert?: boolean;
264
- rejectUnauthorized?: boolean;
265
- };
266
- };
267
227
  reuseTcpPorts?: boolean;
268
228
  startTimeout?: number;
269
229
  restartOnError?: boolean | number;
package/index.js CHANGED
@@ -109,3 +109,5 @@ export * from './lib/config.js'
109
109
  export * as errors from './lib/errors.js'
110
110
  export * from './lib/image-optimizer.js'
111
111
  export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
112
+
113
+ export * from './lib/factory.js'
package/lib/capability.js CHANGED
@@ -75,13 +75,8 @@ export class NextCapability extends BaseCapability {
75
75
  }
76
76
  }
77
77
 
78
- async start ({ listen }) {
79
- // Make this idempotent
80
- if (this.url) {
81
- return this.url
82
- }
83
-
84
- await super._start({ listen })
78
+ async _start () {
79
+ await super._start()
85
80
 
86
81
  this.on('config', config => {
87
82
  this.#configModified = true
@@ -89,9 +84,9 @@ export class NextCapability extends BaseCapability {
89
84
  })
90
85
 
91
86
  if (this.isProduction) {
92
- await this.#startProduction(listen)
87
+ await this.#startProduction()
93
88
  } else {
94
- await this.#startDevelopment(listen)
89
+ await this.#startDevelopment()
95
90
  }
96
91
 
97
92
  await this._collectMetrics()
@@ -109,8 +104,8 @@ export class NextCapability extends BaseCapability {
109
104
  }
110
105
  }
111
106
 
112
- async stop () {
113
- await super.stop()
107
+ async _stop () {
108
+ await super._stop()
114
109
 
115
110
  if (this.subprocess) {
116
111
  return this.stopCommand()
@@ -211,7 +206,11 @@ export class NextCapability extends BaseCapability {
211
206
  return this.startWithCommand(command, loaderUrl, this.#getChildManagerScripts())
212
207
  }
213
208
 
214
- const { hostname, port } = this.serverConfig ?? {}
209
+ if (typeof this.serverConfig?.port === 'undefined') {
210
+ return
211
+ }
212
+
213
+ const { hostname, port } = this.serverConfig
215
214
  const serverOptions = {
216
215
  host: hostname || '127.0.0.1',
217
216
  port: port || 0
@@ -324,6 +323,10 @@ export class NextCapability extends BaseCapability {
324
323
  return this.startWithCommand(command, loaderUrl, childManagerScripts)
325
324
  }
326
325
 
326
+ if (typeof this.serverConfig?.port === 'undefined') {
327
+ return
328
+ }
329
+
327
330
  this.childManager = this.#createChildManager(
328
331
  loaderUrl,
329
332
  await this.getChildManagerContext(this.#basePath),
@@ -344,7 +347,7 @@ export class NextCapability extends BaseCapability {
344
347
  await this.childManager.inject()
345
348
  const { nextStart } = await importFile(resolvePath(this.#next, './dist/cli/next-start.js'))
346
349
 
347
- const { hostname, port, backlog } = this.serverConfig ?? {}
350
+ const { hostname, port } = this.serverConfig ?? {}
348
351
  const serverOptions = {
349
352
  hostname: hostname || '127.0.0.1',
350
353
  port: port || 0
@@ -352,15 +355,11 @@ export class NextCapability extends BaseCapability {
352
355
 
353
356
  await this.childManager.register()
354
357
 
355
- const serverPromise = createServerListener(
356
- (this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
357
- (this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true,
358
- typeof backlog === 'number' ? { backlog } : {}
359
- )
358
+ const serverPromise = createServerListener()
360
359
 
361
360
  if (this.#nextVersion.major === 14 && this.#nextVersion.minor < 2) {
362
361
  await nextStart({
363
- '--hostname': serverOptions.host,
362
+ '--hostname': serverOptions.hostname,
364
363
  '--port': serverOptions.port,
365
364
  _: [this.root]
366
365
  })
@@ -403,17 +402,13 @@ export class NextCapability extends BaseCapability {
403
402
  await this.childManager.inject()
404
403
  await this.childManager.register()
405
404
 
406
- const { hostname, port, backlog } = this.serverConfig ?? {}
405
+ const { hostname, port } = this.serverConfig ?? {}
407
406
  const serverOptions = {
408
407
  hostname: hostname || '127.0.0.1',
409
408
  port: port || 0
410
409
  }
411
410
 
412
- const serverPromise = createServerListener(
413
- (this.isEntrypoint ? serverOptions?.port : undefined) ?? true,
414
- (this.isEntrypoint ? serverOptions?.hostname : undefined) ?? true,
415
- typeof backlog === 'number' ? { backlog } : {}
416
- )
411
+ const serverPromise = createServerListener()
417
412
 
418
413
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
419
414
  if (Number.isNaN(keepAliveTimeout) || !Number.isFinite(keepAliveTimeout) || keepAliveTimeout < 0) {
package/lib/factory.js ADDED
@@ -0,0 +1,7 @@
1
+ import { defineCapabilityFactory } from '@platformatic/basic'
2
+ import { schema, version } from './schema.js'
3
+
4
+ export const next = defineCapabilityFactory('@platformatic/next', schema, {
5
+ version,
6
+ flatten: ['next']
7
+ })
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  BaseCapability,
3
3
  buildListenOptions,
4
- errors as basicErrors,
5
4
  createServerListener,
5
+ errors as basicErrors,
6
6
  getServerUrl,
7
7
  importFile,
8
8
  resolvePackageViaCJS
@@ -72,37 +72,10 @@ export class NextImageOptimizerCapability extends BaseCapability {
72
72
  this.#queue = await this.#createQueue(imageOptimizerConfig)
73
73
  }
74
74
 
75
- async start ({ listen }) {
76
- // Make this idempotent
77
- if (this.url) {
78
- return this.url
79
- }
80
-
75
+ async _start () {
81
76
  const config = this.config
82
77
  this.#basePath = config.application?.basePath ? cleanBasePath(config.application?.basePath) : ''
83
- await super._start({ listen })
84
-
85
- if (this.#app && listen) {
86
- const serverOptions = this.serverConfig
87
- const listenOptions = buildListenOptions(serverOptions)
88
-
89
- if (typeof serverOptions?.backlog === 'number') {
90
- createServerListener(false, false, { backlog: serverOptions.backlog })
91
- listenOptions.backlog = serverOptions.backlog
92
- }
93
-
94
- this.#server = await new Promise((resolve, reject) => {
95
- return this.#app
96
- .listen(listenOptions, function () {
97
- resolve(this)
98
- })
99
- .on('error', reject)
100
- })
101
-
102
- this.url = getServerUrl(this.#server)
103
-
104
- return this.url
105
- }
78
+ await super._start()
106
79
 
107
80
  const { ImageOptimizerCache } = await importFile(resolvePath(this.#next, './dist/server/image-optimizer.js'))
108
81
  this.#validateParams = ImageOptimizerCache.validateParams.bind(ImageOptimizerCache)
@@ -118,10 +91,32 @@ export class NextImageOptimizerCapability extends BaseCapability {
118
91
  this.#app = createServer(this.#handleRequest.bind(this))
119
92
  this.#dispatcher = this.#app.listeners('request')[0]
120
93
  await this.#queue.start()
94
+
95
+ if (typeof this.serverConfig?.port === 'undefined') {
96
+ return
97
+ }
98
+
99
+ const serverOptions = this.serverConfig
100
+ const listenOptions = buildListenOptions(serverOptions)
101
+ const serverPromise = createServerListener()
102
+
103
+ const [server] = await Promise.all([
104
+ new Promise((resolve, reject) => {
105
+ return this.#app
106
+ .listen(listenOptions, function () {
107
+ resolve(this)
108
+ })
109
+ .on('error', reject)
110
+ }),
111
+ serverPromise
112
+ ])
113
+ this.#server = server
114
+
115
+ this.url = getServerUrl(this.#server)
121
116
  }
122
117
 
123
- async stop () {
124
- await super.stop()
118
+ async _stop () {
119
+ await super._stop()
125
120
  await this.#queue?.stop()
126
121
 
127
122
  const events = getEvents()
package/lib/schema.js CHANGED
@@ -1,11 +1,14 @@
1
- import { schemaComponents as basicSchemaComponents } from '@platformatic/basic'
2
- import { schemaComponents as utilsSchemaComponents } from '@platformatic/foundation'
1
+ import { schemaComponents as basicSchemaComponents } from '@platformatic/basic/lib/schema.js'
2
+ import { schemaComponents as utilsSchemaComponents } from '@platformatic/foundation/lib/schema.js'
3
3
  import { readFileSync } from 'node:fs'
4
4
  import { resolve } from 'node:path'
5
5
 
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
+ // The port is checked before any startup path is selected, so no port means no start.
10
+ export const servesWithoutPort = { development: false, production: false }
11
+
9
12
  export const cache = {
10
13
  type: 'object',
11
14
  properties: {
package/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "@platformatic/next",
3
- "version": "3.67.0",
3
+ "version": "4.0.0-new-config.0",
4
4
  "description": "Platformatic Next.js Capability",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./schema": "./schema.js",
10
+ "./package.json": "./package.json",
11
+ "./*": "./*"
12
+ },
7
13
  "repository": {
8
14
  "type": "git",
9
15
  "url": "git+https://github.com/platformatic/platformatic.git"
@@ -25,9 +31,9 @@
25
31
  "light-my-request": "^6.0.0",
26
32
  "msgpackr": "^1.11.2",
27
33
  "semver": "^7.6.3",
28
- "@platformatic/basic": "3.67.0",
29
- "@platformatic/globals": "3.67.0",
30
- "@platformatic/foundation": "3.67.0"
34
+ "@platformatic/basic": "4.0.0-new-config.0",
35
+ "@platformatic/globals": "4.0.0-new-config.0",
36
+ "@platformatic/foundation": "4.0.0-new-config.0"
31
37
  },
32
38
  "devDependencies": {
33
39
  "@fastify/reply-from": "^12.0.0",
@@ -44,8 +50,8 @@
44
50
  "next": "^16.1.0",
45
51
  "typescript": "~6.0.3",
46
52
  "ws": "^8.18.0",
47
- "@platformatic/gateway": "3.67.0",
48
- "@platformatic/service": "3.67.0"
53
+ "@platformatic/gateway": "4.0.0-new-config.0",
54
+ "@platformatic/service": "4.0.0-new-config.0"
49
55
  },
50
56
  "engines": {
51
57
  "node": ">=22.19.0"
package/schema.js ADDED
@@ -0,0 +1,7 @@
1
+ // The light /schema subpath, part of the v4 capability contract. It carries the schema and the
2
+ // package-level metadata main-side preparation needs, and imports nothing that would pull the
3
+ // capability's implementation in with it — boot resolves this rather than the package entry.
4
+ //
5
+ // Light is a statement about import cost, never about safety: this executes in the main process
6
+ // with full privileges, like any capability code.
7
+ export * from './lib/schema.js'
package/schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://schemas.platformatic.dev/@platformatic/next/3.67.0.json",
2
+ "$id": "https://schemas.platformatic.dev/@platformatic/next/4.0.0-new-config.0.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "title": "Platformatic Next.js Config",
5
5
  "type": "object",
@@ -202,7 +202,7 @@
202
202
  "shared",
203
203
  "perWorkerIncrement"
204
204
  ],
205
- "description": "Configures how entrypoint server worker ports are assigned. When set to shared, all workers listen on the same port. When set to perWorkerIncrement, each worker will use its own port, starting from port (worker 0)."
205
+ "description": "Configures how the port is assigned when the application runs multiple workers. When set to shared (the default), all workers listen on the same port (which requires SO_REUSEPORT support). When set to perWorkerIncrement, each worker listens on its own port, starting from port (worker 0) and incrementing by one for each additional worker."
206
206
  },
207
207
  "backlog": {
208
208
  "type": "integer",
@@ -536,7 +536,14 @@
536
536
  "resolvePath": true
537
537
  },
538
538
  "config": {
539
- "type": "string"
539
+ "anyOf": [
540
+ {
541
+ "type": "string"
542
+ },
543
+ {
544
+ "type": "object"
545
+ }
546
+ ]
540
547
  },
541
548
  "url": {
542
549
  "type": "string"
@@ -545,9 +552,6 @@
545
552
  "type": "string",
546
553
  "default": "main"
547
554
  },
548
- "useHttp": {
549
- "type": "boolean"
550
- },
551
555
  "reuseTcpPorts": {
552
556
  "type": "boolean",
553
557
  "default": true
@@ -1161,133 +1165,6 @@
1161
1165
  "default": {},
1162
1166
  "additionalProperties": true
1163
1167
  },
1164
- "server": {
1165
- "type": "object",
1166
- "properties": {
1167
- "hostname": {
1168
- "type": "string"
1169
- },
1170
- "port": {
1171
- "anyOf": [
1172
- {
1173
- "type": "integer"
1174
- },
1175
- {
1176
- "type": "string"
1177
- }
1178
- ]
1179
- },
1180
- "portAssignment": {
1181
- "type": "string",
1182
- "enum": [
1183
- "shared",
1184
- "perWorkerIncrement"
1185
- ],
1186
- "description": "Configures how entrypoint server worker ports are assigned. When set to shared, all workers listen on the same port. When set to perWorkerIncrement, each worker will use its own port, starting from port (worker 0)."
1187
- },
1188
- "backlog": {
1189
- "type": "integer",
1190
- "description": "The maximum length of the queue of pending connections"
1191
- },
1192
- "http2": {
1193
- "type": "boolean"
1194
- },
1195
- "https": {
1196
- "type": "object",
1197
- "properties": {
1198
- "allowHTTP1": {
1199
- "type": "boolean"
1200
- },
1201
- "key": {
1202
- "anyOf": [
1203
- {
1204
- "type": "string"
1205
- },
1206
- {
1207
- "type": "object",
1208
- "properties": {
1209
- "path": {
1210
- "type": "string",
1211
- "resolvePath": true
1212
- }
1213
- },
1214
- "additionalProperties": false
1215
- },
1216
- {
1217
- "type": "array",
1218
- "items": {
1219
- "anyOf": [
1220
- {
1221
- "type": "string"
1222
- },
1223
- {
1224
- "type": "object",
1225
- "properties": {
1226
- "path": {
1227
- "type": "string",
1228
- "resolvePath": true
1229
- }
1230
- },
1231
- "additionalProperties": false
1232
- }
1233
- ]
1234
- }
1235
- }
1236
- ]
1237
- },
1238
- "cert": {
1239
- "anyOf": [
1240
- {
1241
- "type": "string"
1242
- },
1243
- {
1244
- "type": "object",
1245
- "properties": {
1246
- "path": {
1247
- "type": "string",
1248
- "resolvePath": true
1249
- }
1250
- },
1251
- "additionalProperties": false
1252
- },
1253
- {
1254
- "type": "array",
1255
- "items": {
1256
- "anyOf": [
1257
- {
1258
- "type": "string"
1259
- },
1260
- {
1261
- "type": "object",
1262
- "properties": {
1263
- "path": {
1264
- "type": "string",
1265
- "resolvePath": true
1266
- }
1267
- },
1268
- "additionalProperties": false
1269
- }
1270
- ]
1271
- }
1272
- }
1273
- ]
1274
- },
1275
- "requestCert": {
1276
- "type": "boolean"
1277
- },
1278
- "rejectUnauthorized": {
1279
- "type": "boolean"
1280
- }
1281
- },
1282
- "additionalProperties": false,
1283
- "required": [
1284
- "key",
1285
- "cert"
1286
- ]
1287
- }
1288
- },
1289
- "additionalProperties": false
1290
- },
1291
1168
  "reuseTcpPorts": {
1292
1169
  "type": "boolean",
1293
1170
  "default": true