@platformatic/next 3.53.0 → 3.55.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 +9 -1
- package/index.js +4 -27
- package/lib/capability.js +5 -55
- package/lib/commands/index.js +26 -0
- package/lib/commands/pack.js +121 -0
- package/lib/config.js +26 -0
- package/lib/pack.js +467 -0
- package/lib/standalone.js +51 -0
- package/package.json +5 -5
- package/schema.json +89 -2
package/config.d.ts
CHANGED
|
@@ -259,6 +259,8 @@ export interface PlatformaticNextJsConfig {
|
|
|
259
259
|
maxHeapTotal?: number | string;
|
|
260
260
|
maxYoungGeneration?: number | string;
|
|
261
261
|
codeRangeSize?: number | string;
|
|
262
|
+
bufferPoolSize?: number | string;
|
|
263
|
+
defaultHighWaterMark?: number | string;
|
|
262
264
|
};
|
|
263
265
|
undici?: {
|
|
264
266
|
agentOptions?: {
|
|
@@ -361,6 +363,10 @@ export interface PlatformaticNextJsConfig {
|
|
|
361
363
|
* The label name to use for the application identifier in metrics (e.g., applicationId, serviceId)
|
|
362
364
|
*/
|
|
363
365
|
applicationLabel?: string;
|
|
366
|
+
/**
|
|
367
|
+
* Enable outgoing HTTP client request duration metrics
|
|
368
|
+
*/
|
|
369
|
+
httpClientMetrics?: boolean | string;
|
|
364
370
|
readiness?:
|
|
365
371
|
| boolean
|
|
366
372
|
| {
|
|
@@ -517,7 +523,7 @@ export interface PlatformaticNextJsConfig {
|
|
|
517
523
|
/**
|
|
518
524
|
* Enable the OpenTelemetry diagnostic logger. Diagnostic messages are forwarded to the Platformatic global logger using the current logger level.
|
|
519
525
|
*/
|
|
520
|
-
diagLogger?: boolean;
|
|
526
|
+
diagLogger?: boolean | string;
|
|
521
527
|
};
|
|
522
528
|
verticalScaler?: {
|
|
523
529
|
enabled?: boolean;
|
|
@@ -619,6 +625,8 @@ export interface PlatformaticNextJsConfig {
|
|
|
619
625
|
maxHeapTotal?: number | string;
|
|
620
626
|
maxYoungGeneration?: number | string;
|
|
621
627
|
codeRangeSize?: number | string;
|
|
628
|
+
bufferPoolSize?: number | string;
|
|
629
|
+
defaultHighWaterMark?: number | string;
|
|
622
630
|
};
|
|
623
631
|
arguments?: string[];
|
|
624
632
|
env?: {
|
package/index.js
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { kMetadata, loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
|
|
1
|
+
import { kMetadata } from '@platformatic/foundation'
|
|
3
2
|
import { resolve as resolvePath } from 'node:path'
|
|
4
3
|
import { getCacheHandlerPath, NextCapability } from './lib/capability.js'
|
|
4
|
+
import { loadConfiguration } from './lib/config.js'
|
|
5
5
|
import { NextImageOptimizerCapability } from './lib/image-optimizer.js'
|
|
6
|
-
import { schema } from './lib/schema.js'
|
|
7
|
-
|
|
8
|
-
/* c8 ignore next 9 */
|
|
9
|
-
export async function transform (config, schema, options) {
|
|
10
|
-
config = await basicTransform(config, schema, options)
|
|
11
|
-
config.watch = { enabled: false }
|
|
12
|
-
|
|
13
|
-
if (config.cache?.adapter === 'redis') {
|
|
14
|
-
config.cache.adapter = 'valkey'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return config
|
|
18
|
-
}
|
|
19
6
|
|
|
20
7
|
export function getAdapterPath () {
|
|
21
8
|
return resolvePath(import.meta.dirname, 'lib', 'adapter.js')
|
|
@@ -99,18 +86,6 @@ export async function enhanceNextConfig (nextConfig, ...args) {
|
|
|
99
86
|
return nextConfig
|
|
100
87
|
}
|
|
101
88
|
|
|
102
|
-
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
103
|
-
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
|
|
104
|
-
|
|
105
|
-
return utilsLoadConfiguration(source, context?.schema ?? schema, {
|
|
106
|
-
validationOptions,
|
|
107
|
-
transform,
|
|
108
|
-
replaceEnv: true,
|
|
109
|
-
root,
|
|
110
|
-
...context
|
|
111
|
-
})
|
|
112
|
-
}
|
|
113
|
-
|
|
114
89
|
export async function create (configOrRoot, sourceOrConfig, context) {
|
|
115
90
|
const config = await loadConfiguration(configOrRoot, sourceOrConfig, context)
|
|
116
91
|
|
|
@@ -119,6 +94,8 @@ export async function create (configOrRoot, sourceOrConfig, context) {
|
|
|
119
94
|
}
|
|
120
95
|
|
|
121
96
|
export * from './lib/capability.js'
|
|
97
|
+
export * from './lib/commands/index.js'
|
|
98
|
+
export * from './lib/config.js'
|
|
122
99
|
export * as errors from './lib/errors.js'
|
|
123
100
|
export * from './lib/image-optimizer.js'
|
|
124
101
|
export { packageJson, schema, schemaComponents, version } from './lib/schema.js'
|
package/lib/capability.js
CHANGED
|
@@ -11,14 +11,12 @@ import {
|
|
|
11
11
|
} from '@platformatic/basic'
|
|
12
12
|
import { ChildProcess } from 'node:child_process'
|
|
13
13
|
import { once } from 'node:events'
|
|
14
|
-
import {
|
|
15
|
-
import { glob, readFile, writeFile } from 'node:fs/promises'
|
|
16
|
-
import { createRequire } from 'node:module'
|
|
14
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
17
15
|
import { dirname, resolve as resolvePath, sep } from 'node:path'
|
|
18
16
|
import { fileURLToPath } from 'node:url'
|
|
19
17
|
import { parse, satisfies } from 'semver'
|
|
20
|
-
import * as errors from './errors.js'
|
|
21
18
|
import { version } from './schema.js'
|
|
19
|
+
import { parseStandaloneNextConfig, requireStandaloneStartServer, resolveStandaloneEntrypoint } from './standalone.js'
|
|
22
20
|
|
|
23
21
|
export const supportedVersions = ['^14.0.0', '^15.0.0', '^16.0.0']
|
|
24
22
|
|
|
@@ -53,7 +51,7 @@ export class NextCapability extends BaseCapability {
|
|
|
53
51
|
process.env.NEXT_IGNORE_INCORRECT_LOCKFILE = 'true'
|
|
54
52
|
|
|
55
53
|
if (!building && this.isProduction && this.config.next?.standalone) {
|
|
56
|
-
this.#standaloneEntrypoint = await
|
|
54
|
+
this.#standaloneEntrypoint = await resolveStandaloneEntrypoint(this.root)
|
|
57
55
|
this.#next = resolvePath(dirname(await resolvePackageViaCJS(this.#standaloneEntrypoint, 'next')), '../..')
|
|
58
56
|
} else {
|
|
59
57
|
this.#next = resolvePath(dirname(await resolvePackageViaCJS(this.root, 'next')), '../..')
|
|
@@ -382,14 +380,7 @@ export class NextCapability extends BaseCapability {
|
|
|
382
380
|
|
|
383
381
|
// Parse the server.js to extract the nextConfig.
|
|
384
382
|
// For now we use simple regex parsing, if it breaks, we can switch to proper AST parsing.
|
|
385
|
-
|
|
386
|
-
try {
|
|
387
|
-
const serverJsContent = await readFile(this.#standaloneEntrypoint, 'utf-8')
|
|
388
|
-
const nextConfigMatch = serverJsContent.match(/(?:const|let)\s*nextConfig\s*=\s*(\{.+)/)
|
|
389
|
-
nextConfig = JSON.parse(nextConfigMatch[1])
|
|
390
|
-
} catch (e) {
|
|
391
|
-
throw new errors.CannotParseStandaloneServer({ cause: e })
|
|
392
|
-
}
|
|
383
|
+
const nextConfig = await parseStandaloneNextConfig(this.#standaloneEntrypoint)
|
|
393
384
|
|
|
394
385
|
// Fix cache handlers path
|
|
395
386
|
if (nextConfig.env?.PLT_NEXT_MODIFICATIONS) {
|
|
@@ -430,7 +421,7 @@ export class NextCapability extends BaseCapability {
|
|
|
430
421
|
|
|
431
422
|
// This is needed by Next.js standalone server to pick up the correct configuration
|
|
432
423
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
433
|
-
const { startServer } =
|
|
424
|
+
const { startServer } = requireStandaloneStartServer(this.#standaloneEntrypoint)
|
|
434
425
|
|
|
435
426
|
await startServer({
|
|
436
427
|
dir: dirname(this.#standaloneEntrypoint),
|
|
@@ -529,45 +520,4 @@ export class NextCapability extends BaseCapability {
|
|
|
529
520
|
|
|
530
521
|
return distDir
|
|
531
522
|
}
|
|
532
|
-
|
|
533
|
-
async #resolveStandaloneEntrypoint () {
|
|
534
|
-
// If built in standalone mode, the generated standalone directory is not on the root of the project but somewhere
|
|
535
|
-
// inside .next/standalone due to turbopack limitations in determining the root of the project.
|
|
536
|
-
// In that case we search a server.js next to a .next folder inside the .next /standalone folder.
|
|
537
|
-
const serverEntrypoints = await Array.fromAsync(
|
|
538
|
-
glob(['**/server.js'], { cwd: this.root, ignore: ['node_modules', '**/node_modules/**'] })
|
|
539
|
-
)
|
|
540
|
-
|
|
541
|
-
let serverEntrypoint
|
|
542
|
-
for (const entrypoint of serverEntrypoints) {
|
|
543
|
-
if (existsSync(resolvePath(this.root, dirname(entrypoint), '.next'))) {
|
|
544
|
-
const candidate = resolvePath(this.root, entrypoint)
|
|
545
|
-
const contents = await readFile(candidate, 'utf-8')
|
|
546
|
-
|
|
547
|
-
if (contents.includes('process.env.__NEXT_PRIVATE_STANDALONE_CONFIG =')) {
|
|
548
|
-
serverEntrypoint = candidate
|
|
549
|
-
break
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (!serverEntrypoint) {
|
|
555
|
-
throw new errors.StandaloneServerNotFound()
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return serverEntrypoint
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
#requireStandaloneEntrypoint (serverEntrypoint) {
|
|
562
|
-
let serverModule
|
|
563
|
-
|
|
564
|
-
try {
|
|
565
|
-
serverModule = createRequire(serverEntrypoint)('next/dist/server/lib/start-server.js')
|
|
566
|
-
} catch (e) {
|
|
567
|
-
// Fallback to bundled capability
|
|
568
|
-
serverModule = createRequire(import.meta.file)('next/dist/server/lib/start-server.js')
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
return serverModule.default ?? serverModule
|
|
572
|
-
}
|
|
573
523
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { packCommand, helpFooter as packHelpFooter } from './pack.js'
|
|
2
|
+
|
|
3
|
+
export function createCommands (id) {
|
|
4
|
+
return {
|
|
5
|
+
commands: {
|
|
6
|
+
[`${id}:pack`]: packCommand
|
|
7
|
+
},
|
|
8
|
+
help: {
|
|
9
|
+
[`${id}:pack`]: {
|
|
10
|
+
usage: `${id}:pack`,
|
|
11
|
+
description: 'Create a self-contained standalone bundle for a Next.js application',
|
|
12
|
+
footer: packHelpFooter,
|
|
13
|
+
options: [
|
|
14
|
+
{
|
|
15
|
+
usage: '-o, --output <path>',
|
|
16
|
+
description: 'Output directory for the packed bundle'
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
usage: '--no-build',
|
|
20
|
+
description: 'Fail if the standalone build output is missing instead of building it first'
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { ensureLoggableError, findRuntimeConfigurationFile, kMetadata, logFatalError } from '@platformatic/foundation'
|
|
2
|
+
import { dirname } from 'node:path'
|
|
3
|
+
import {
|
|
4
|
+
copyStandaloneFiles,
|
|
5
|
+
ensurePortableNodeModules,
|
|
6
|
+
materializeRuntimeDependencies,
|
|
7
|
+
prepareBundleDirectory,
|
|
8
|
+
resolveOutputDirectory,
|
|
9
|
+
writeBundleConfiguration,
|
|
10
|
+
writeBundleMetadata
|
|
11
|
+
} from '../pack.js'
|
|
12
|
+
import { NextCapability } from '../capability.js'
|
|
13
|
+
import { loadConfiguration } from '../config.js'
|
|
14
|
+
import { resolveStandaloneEntrypoint } from '../standalone.js'
|
|
15
|
+
|
|
16
|
+
export async function packCommand (logger, configFile, args, context) {
|
|
17
|
+
const {
|
|
18
|
+
values: { output, 'no-build': noBuild },
|
|
19
|
+
positionals
|
|
20
|
+
} = context.parseArgs(
|
|
21
|
+
args,
|
|
22
|
+
{
|
|
23
|
+
output: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
short: 'o'
|
|
26
|
+
},
|
|
27
|
+
'no-build': {
|
|
28
|
+
type: 'boolean'
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
false
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if (positionals.length > 0) {
|
|
35
|
+
return logFatalError(logger, `Unexpected positional arguments: ${positionals.join(' ')}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let config
|
|
39
|
+
try {
|
|
40
|
+
config = await loadConfiguration(configFile)
|
|
41
|
+
} catch (error) {
|
|
42
|
+
return logFatalError(
|
|
43
|
+
logger,
|
|
44
|
+
{ err: ensureLoggableError(error) },
|
|
45
|
+
`Cannot load the Next.js application configuration: ${error.message}`
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.next?.standalone !== true) {
|
|
50
|
+
return logFatalError(logger, 'The Next.js pack command requires next.standalone to be set to true.')
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const applicationRoot = config[kMetadata].root
|
|
54
|
+
const applicationId = context.application?.id ?? 'main'
|
|
55
|
+
const invocationCwd = context.cwd ?? process.cwd()
|
|
56
|
+
const bundleRoot = resolveOutputDirectory(output, `.platformatic/${applicationId}-bundle`, invocationCwd)
|
|
57
|
+
|
|
58
|
+
let standaloneEntrypoint
|
|
59
|
+
try {
|
|
60
|
+
standaloneEntrypoint = await resolveStandaloneEntrypoint(applicationRoot)
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (noBuild) {
|
|
63
|
+
return logFatalError(logger, 'Cannot find a Next standalone build. Run the build first or omit --no-build.')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const capability = new NextCapability(applicationRoot, config, {
|
|
67
|
+
applicationId,
|
|
68
|
+
isProduction: true
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
logger.info(`Building application ${applicationId} before packing ...`)
|
|
73
|
+
await capability.build()
|
|
74
|
+
standaloneEntrypoint = await resolveStandaloneEntrypoint(applicationRoot)
|
|
75
|
+
} catch (buildError) {
|
|
76
|
+
return logFatalError(
|
|
77
|
+
logger,
|
|
78
|
+
{ err: ensureLoggableError(buildError) },
|
|
79
|
+
`Cannot build the Next.js application for packing: ${buildError.message}`
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const standaloneRoot = dirname(standaloneEntrypoint)
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const runtimeConfig = await findRuntimeConfigurationFile(logger, invocationCwd, null, false, false, false)
|
|
88
|
+
|
|
89
|
+
await prepareBundleDirectory(bundleRoot)
|
|
90
|
+
await copyStandaloneFiles({ applicationRoot, standaloneRoot, bundleRoot })
|
|
91
|
+
await writeBundleConfiguration(config, bundleRoot)
|
|
92
|
+
const packages = await materializeRuntimeDependencies({ bundleRoot, logger })
|
|
93
|
+
await writeBundleMetadata({
|
|
94
|
+
applicationId,
|
|
95
|
+
applicationConfig: configFile,
|
|
96
|
+
runtimeConfig,
|
|
97
|
+
bundleRoot,
|
|
98
|
+
packages
|
|
99
|
+
})
|
|
100
|
+
await ensurePortableNodeModules(bundleRoot)
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return logFatalError(
|
|
103
|
+
logger,
|
|
104
|
+
{ err: ensureLoggableError(error) },
|
|
105
|
+
`Cannot pack the Next.js application: ${error.message}`
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
logger.done(`Packed application ${applicationId} into ${bundleRoot}.`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const helpFooter = `
|
|
113
|
+
This command only supports Next.js applications configured with:
|
|
114
|
+
|
|
115
|
+
- Next.js standalone output enabled in next.config.js
|
|
116
|
+
- next.standalone = true in the Platformatic application config
|
|
117
|
+
|
|
118
|
+
The packed output is intended to be started with:
|
|
119
|
+
|
|
120
|
+
- ./node_modules/.bin/wattpm start
|
|
121
|
+
`
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { transform as basicTransform, resolve, validationOptions } from '@platformatic/basic'
|
|
2
|
+
import { loadConfiguration as utilsLoadConfiguration } from '@platformatic/foundation'
|
|
3
|
+
import { schema } from './schema.js'
|
|
4
|
+
|
|
5
|
+
export async function transform (config, schema, options) {
|
|
6
|
+
config = await basicTransform(config, schema, options)
|
|
7
|
+
config.watch = { enabled: false }
|
|
8
|
+
|
|
9
|
+
if (config.cache?.adapter === 'redis') {
|
|
10
|
+
config.cache.adapter = 'valkey'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return config
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function loadConfiguration (configOrRoot, sourceOrConfig, context) {
|
|
17
|
+
const { root, source } = await resolve(configOrRoot, sourceOrConfig, 'application')
|
|
18
|
+
|
|
19
|
+
return utilsLoadConfiguration(source, context?.schema ?? schema, {
|
|
20
|
+
validationOptions,
|
|
21
|
+
transform,
|
|
22
|
+
replaceEnv: true,
|
|
23
|
+
root,
|
|
24
|
+
...context
|
|
25
|
+
})
|
|
26
|
+
}
|
package/lib/pack.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { saveConfigurationFile } from '@platformatic/foundation'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import {
|
|
5
|
+
chmod,
|
|
6
|
+
cp,
|
|
7
|
+
lstat,
|
|
8
|
+
mkdir,
|
|
9
|
+
mkdtemp,
|
|
10
|
+
readFile,
|
|
11
|
+
readdir,
|
|
12
|
+
readlink,
|
|
13
|
+
realpath,
|
|
14
|
+
rm,
|
|
15
|
+
symlink,
|
|
16
|
+
writeFile
|
|
17
|
+
} from 'node:fs/promises'
|
|
18
|
+
import { createRequire } from 'node:module'
|
|
19
|
+
import { tmpdir } from 'node:os'
|
|
20
|
+
import { dirname, isAbsolute, relative, resolve as resolvePath } from 'node:path'
|
|
21
|
+
import { version as platformaticVersion } from './schema.js'
|
|
22
|
+
|
|
23
|
+
const runtimePackages = ['wattpm', '@platformatic/next']
|
|
24
|
+
|
|
25
|
+
export function resolveOutputDirectory (output, fallback, cwd) {
|
|
26
|
+
const target = output ?? fallback
|
|
27
|
+
return isAbsolute(target) ? target : resolvePath(cwd, target)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function prepareBundleDirectory (directory) {
|
|
31
|
+
await rm(directory, { recursive: true, force: true })
|
|
32
|
+
await mkdir(directory, { recursive: true })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function copyStandaloneFiles ({ applicationRoot, standaloneRoot, bundleRoot }) {
|
|
36
|
+
await cp(standaloneRoot, bundleRoot, {
|
|
37
|
+
recursive: true,
|
|
38
|
+
dereference: true,
|
|
39
|
+
preserveTimestamps: true
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await cp(resolvePath(applicationRoot, '.next', 'static'), resolvePath(bundleRoot, '.next', 'static'), {
|
|
44
|
+
recursive: true,
|
|
45
|
+
force: true,
|
|
46
|
+
errorOnExist: false,
|
|
47
|
+
preserveTimestamps: true
|
|
48
|
+
})
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error.code !== 'ENOENT') {
|
|
51
|
+
throw error
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await cp(resolvePath(applicationRoot, 'public'), resolvePath(bundleRoot, 'public'), {
|
|
57
|
+
recursive: true,
|
|
58
|
+
force: true,
|
|
59
|
+
errorOnExist: false,
|
|
60
|
+
preserveTimestamps: true
|
|
61
|
+
})
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error.code !== 'ENOENT') {
|
|
64
|
+
throw error
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function writeBundleConfiguration (config, bundleRoot) {
|
|
70
|
+
const bundleConfig = JSON.parse(JSON.stringify(config))
|
|
71
|
+
bundleConfig.next ??= {}
|
|
72
|
+
bundleConfig.next.standalone = true
|
|
73
|
+
await saveConfigurationFile(resolvePath(bundleRoot, 'watt.json'), bundleConfig)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function materializeRuntimeDependencies ({ bundleRoot, logger }) {
|
|
77
|
+
const bundleNodeModules = resolvePath(bundleRoot, 'node_modules')
|
|
78
|
+
const stagingRoot = await mkdtemp(resolvePath(tmpdir(), 'platformatic-next-pack-'))
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await mkdir(bundleNodeModules, { recursive: true })
|
|
82
|
+
|
|
83
|
+
const workspacePackages = await collectWorkspacePackages(runtimePackages)
|
|
84
|
+
const tarballDirectory = resolvePath(stagingRoot, 'tarballs')
|
|
85
|
+
const dependencies = {}
|
|
86
|
+
const packages = new Map()
|
|
87
|
+
|
|
88
|
+
await mkdir(tarballDirectory, { recursive: true })
|
|
89
|
+
|
|
90
|
+
for (const name of runtimePackages) {
|
|
91
|
+
const pkg = workspacePackages.get(name) ?? (await loadInstalledPackage(name, import.meta.url))
|
|
92
|
+
packages.set(pkg.name, pkg)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const pkg of workspacePackages.values()) {
|
|
96
|
+
const tarball = await packWorkspacePackage(pkg, tarballDirectory)
|
|
97
|
+
dependencies[pkg.name] = `file:${relative(stagingRoot, tarball)}`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const pkg of packages.values()) {
|
|
101
|
+
dependencies[pkg.name] ??= pkg.version
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await writeFile(
|
|
105
|
+
resolvePath(stagingRoot, 'package.json'),
|
|
106
|
+
JSON.stringify({ name: 'platformatic-next-pack', private: true, dependencies }, null, 2),
|
|
107
|
+
'utf-8'
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
await runCommand('npm', ['install', '--omit=dev', '--ignore-scripts', '--no-fund', '--no-audit'], { cwd: stagingRoot })
|
|
111
|
+
await mergeDirectory(resolvePath(stagingRoot, 'node_modules'), bundleNodeModules)
|
|
112
|
+
await cleanupBrokenSymlinks(resolvePath(bundleNodeModules, '.bin'))
|
|
113
|
+
await writePackageBins(packages, bundleNodeModules)
|
|
114
|
+
|
|
115
|
+
logger?.debug?.({ packages: [...packages.keys()] }, 'Materialized runtime packages for packed bundle.')
|
|
116
|
+
|
|
117
|
+
return packages
|
|
118
|
+
} finally {
|
|
119
|
+
await rm(stagingRoot, { recursive: true, force: true })
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async function collectWorkspacePackages (rootNames) {
|
|
124
|
+
const packages = new Map()
|
|
125
|
+
const queue = [...rootNames]
|
|
126
|
+
|
|
127
|
+
while (queue.length) {
|
|
128
|
+
const name = queue.shift()
|
|
129
|
+
if (packages.has(name)) {
|
|
130
|
+
continue
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const root = resolveWorkspacePackageRoot(name)
|
|
134
|
+
if (!root) {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const pkg = await loadPackageFromRoot(root, name)
|
|
139
|
+
packages.set(pkg.name, pkg)
|
|
140
|
+
|
|
141
|
+
for (const dependencyName of listWorkspaceDependencies(pkg.packageJson)) {
|
|
142
|
+
queue.push(dependencyName)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return packages
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function listWorkspaceDependencies (packageJson) {
|
|
150
|
+
return Object.keys({
|
|
151
|
+
...(packageJson.dependencies ?? {}),
|
|
152
|
+
...(packageJson.optionalDependencies ?? {})
|
|
153
|
+
}).filter(name => !!resolveWorkspacePackageRoot(name))
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function loadInstalledPackage (name, from) {
|
|
157
|
+
const root = await realpath(await resolvePackageRoot(name, from))
|
|
158
|
+
return loadPackageFromRoot(root, name)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function loadPackageFromRoot (root, fallbackName) {
|
|
162
|
+
const packageJson = JSON.parse(await readFile(resolvePath(root, 'package.json'), 'utf-8'))
|
|
163
|
+
return {
|
|
164
|
+
name: packageJson.name ?? fallbackName,
|
|
165
|
+
version: packageJson.version,
|
|
166
|
+
root,
|
|
167
|
+
packageJson
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function resolvePackageRoot (name, from) {
|
|
172
|
+
const require = createRequire(from)
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const packageJsonPath = require.resolve(`${name}/package.json`)
|
|
176
|
+
return dirname(packageJsonPath)
|
|
177
|
+
} catch (error) {
|
|
178
|
+
const packageJsonPath = resolvePackageJsonFromSearchPaths(require, name)
|
|
179
|
+
if (packageJsonPath) {
|
|
180
|
+
return dirname(packageJsonPath)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const resolvedEntry = require.resolve(name)
|
|
185
|
+
return await findPackageRoot(dirname(resolvedEntry))
|
|
186
|
+
} catch (resolveError) {
|
|
187
|
+
const workspacePackage = resolveWorkspacePackageRoot(name)
|
|
188
|
+
if (workspacePackage) {
|
|
189
|
+
return workspacePackage
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
throw resolveError
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function resolvePackageJsonFromSearchPaths (require, name) {
|
|
198
|
+
const searchPaths = require.resolve.paths(name) ?? []
|
|
199
|
+
const packageSegments = name.split('/')
|
|
200
|
+
|
|
201
|
+
for (const searchPath of searchPaths) {
|
|
202
|
+
const candidate = resolvePath(searchPath, ...packageSegments, 'package.json')
|
|
203
|
+
if (existsSync(candidate)) {
|
|
204
|
+
return candidate
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return null
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function findPackageRoot (directory) {
|
|
212
|
+
let current = directory
|
|
213
|
+
|
|
214
|
+
while (true) {
|
|
215
|
+
const candidate = resolvePath(current, 'package.json')
|
|
216
|
+
if (existsSync(candidate)) {
|
|
217
|
+
return current
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const parent = resolvePath(current, '..')
|
|
221
|
+
if (parent === current) {
|
|
222
|
+
throw new Error(`Cannot determine package root for ${directory}.`)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
current = parent
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function resolveWorkspacePackageRoot (name) {
|
|
230
|
+
if (name !== 'wattpm' && !name.startsWith('@platformatic/')) {
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const packageDirectory = name === 'wattpm' ? 'wattpm' : name.replace('@platformatic/', '')
|
|
235
|
+
const candidate = resolvePath(import.meta.dirname, '..', '..', packageDirectory)
|
|
236
|
+
|
|
237
|
+
if (existsSync(resolvePath(candidate, 'package.json'))) {
|
|
238
|
+
return candidate
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return null
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function packWorkspacePackage (pkg, tarballDirectory) {
|
|
245
|
+
const { stdout } = await runCommand('pnpm', ['pack', '--pack-destination', tarballDirectory], { cwd: pkg.root })
|
|
246
|
+
const tarball = stdout
|
|
247
|
+
.split('\n')
|
|
248
|
+
.map(line => line.trim())
|
|
249
|
+
.filter(line => line.endsWith('.tgz'))
|
|
250
|
+
.at(-1)
|
|
251
|
+
|
|
252
|
+
if (!tarball) {
|
|
253
|
+
throw new Error(`Cannot determine the tarball path for ${pkg.name}.`)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return tarball
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function runCommand (command, args, options) {
|
|
260
|
+
return await new Promise((resolve, reject) => {
|
|
261
|
+
const child = spawn(command, args, {
|
|
262
|
+
cwd: options.cwd,
|
|
263
|
+
env: process.env,
|
|
264
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
let stdout = ''
|
|
268
|
+
let stderr = ''
|
|
269
|
+
|
|
270
|
+
child.stdout.on('data', chunk => {
|
|
271
|
+
stdout += chunk.toString()
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
child.stderr.on('data', chunk => {
|
|
275
|
+
stderr += chunk.toString()
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
child.on('error', reject)
|
|
279
|
+
child.on('close', code => {
|
|
280
|
+
if (code === 0) {
|
|
281
|
+
resolve({ stdout, stderr })
|
|
282
|
+
} else {
|
|
283
|
+
reject(new Error(`Command failed: ${command} ${args.join(' ')}\n${stderr || stdout}`))
|
|
284
|
+
}
|
|
285
|
+
})
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async function mergeDirectory (source, destination) {
|
|
290
|
+
await mkdir(destination, { recursive: true })
|
|
291
|
+
const entries = await readdir(source, { withFileTypes: true })
|
|
292
|
+
|
|
293
|
+
for (const entry of entries) {
|
|
294
|
+
const sourcePath = resolvePath(source, entry.name)
|
|
295
|
+
const destinationPath = resolvePath(destination, entry.name)
|
|
296
|
+
const stats = await lstat(sourcePath)
|
|
297
|
+
|
|
298
|
+
if (stats.isSymbolicLink()) {
|
|
299
|
+
await copySymlink(sourcePath, destinationPath)
|
|
300
|
+
continue
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (entry.isDirectory()) {
|
|
304
|
+
if (!existsSync(destinationPath)) {
|
|
305
|
+
await cp(sourcePath, destinationPath, {
|
|
306
|
+
recursive: true,
|
|
307
|
+
dereference: false,
|
|
308
|
+
preserveTimestamps: true
|
|
309
|
+
})
|
|
310
|
+
} else {
|
|
311
|
+
await mergeDirectory(sourcePath, destinationPath)
|
|
312
|
+
}
|
|
313
|
+
continue
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!existsSync(destinationPath)) {
|
|
317
|
+
await cp(sourcePath, destinationPath, { dereference: false, preserveTimestamps: true })
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function copySymlink (source, destination) {
|
|
323
|
+
if (existsSync(destination)) {
|
|
324
|
+
return
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
await mkdir(dirname(destination), { recursive: true })
|
|
328
|
+
await symlink(await readlink(source), destination)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function cleanupBrokenSymlinks (directory) {
|
|
332
|
+
if (!existsSync(directory)) {
|
|
333
|
+
return
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const entries = await readdir(directory, { withFileTypes: true })
|
|
337
|
+
|
|
338
|
+
for (const entry of entries) {
|
|
339
|
+
const path = resolvePath(directory, entry.name)
|
|
340
|
+
const stats = await lstat(path)
|
|
341
|
+
|
|
342
|
+
if (!stats.isSymbolicLink()) {
|
|
343
|
+
continue
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
await realpath(path)
|
|
348
|
+
} catch (error) {
|
|
349
|
+
if (error.code === 'ENOENT') {
|
|
350
|
+
await rm(path, { force: true })
|
|
351
|
+
continue
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
throw error
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function writePackageBins (packages, bundleNodeModules) {
|
|
360
|
+
const binDirectory = resolvePath(bundleNodeModules, '.bin')
|
|
361
|
+
await mkdir(binDirectory, { recursive: true })
|
|
362
|
+
|
|
363
|
+
for (const pkg of packages.values()) {
|
|
364
|
+
const bin = normalizeBinField(pkg.packageJson.bin, pkg.name)
|
|
365
|
+
for (const [name, target] of Object.entries(bin)) {
|
|
366
|
+
await writeNodeShim(resolvePath(binDirectory, name), pkg.name, target)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function normalizeBinField (bin, pkgName) {
|
|
372
|
+
if (!bin) {
|
|
373
|
+
return {}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (typeof bin === 'string') {
|
|
377
|
+
return { [pkgName]: bin }
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return bin
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function writeNodeShim (destination, packageName, target) {
|
|
384
|
+
const normalizedTarget = target.replaceAll('\\', '/')
|
|
385
|
+
const unixScript = `#!/usr/bin/env node\nimport '../${packageName}/${normalizedTarget}'\n`
|
|
386
|
+
|
|
387
|
+
await rm(destination, { force: true })
|
|
388
|
+
await rm(`${destination}.cmd`, { force: true })
|
|
389
|
+
await writeFile(destination, unixScript, 'utf-8')
|
|
390
|
+
await chmod(destination, 0o755)
|
|
391
|
+
await writeFile(
|
|
392
|
+
`${destination}.cmd`,
|
|
393
|
+
`@ECHO off\r\nnode "%~dp0\\..\\${packageName.replaceAll('/', '\\')}\\${normalizedTarget.replaceAll('/', '\\')}" %*\r\n`,
|
|
394
|
+
'utf-8'
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export async function writeBundleMetadata ({
|
|
399
|
+
applicationId,
|
|
400
|
+
applicationConfig,
|
|
401
|
+
runtimeConfig,
|
|
402
|
+
bundleRoot,
|
|
403
|
+
packages
|
|
404
|
+
}) {
|
|
405
|
+
const metadataRoot = resolvePath(bundleRoot, '.platformatic')
|
|
406
|
+
await mkdir(metadataRoot, { recursive: true })
|
|
407
|
+
|
|
408
|
+
await writeFile(
|
|
409
|
+
resolvePath(metadataRoot, 'manifest.json'),
|
|
410
|
+
JSON.stringify(
|
|
411
|
+
{
|
|
412
|
+
bundleVersion: 1,
|
|
413
|
+
applicationId,
|
|
414
|
+
packedAt: new Date().toISOString(),
|
|
415
|
+
source: {
|
|
416
|
+
applicationConfig,
|
|
417
|
+
runtimeConfig: runtimeConfig ?? null
|
|
418
|
+
},
|
|
419
|
+
platformaticVersion,
|
|
420
|
+
packages: Object.fromEntries(
|
|
421
|
+
[...packages.values()].map(pkg => [pkg.name, { version: pkg.version, root: pkg.root }])
|
|
422
|
+
)
|
|
423
|
+
},
|
|
424
|
+
null,
|
|
425
|
+
2
|
|
426
|
+
) + '\n',
|
|
427
|
+
'utf-8'
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
await writeFile(
|
|
431
|
+
resolvePath(metadataRoot, 'NOTICE'),
|
|
432
|
+
'This directory was generated by the Next standalone pack command.\n',
|
|
433
|
+
'utf-8'
|
|
434
|
+
)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export async function ensurePortableNodeModules (bundleRoot) {
|
|
438
|
+
const nodeModules = resolvePath(bundleRoot, 'node_modules')
|
|
439
|
+
await assertNoExternalSymlinks(nodeModules, bundleRoot)
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async function assertNoExternalSymlinks (directory, bundleRoot) {
|
|
443
|
+
const entries = await readdir(directory, { withFileTypes: true })
|
|
444
|
+
|
|
445
|
+
for (const entry of entries) {
|
|
446
|
+
const path = resolvePath(directory, entry.name)
|
|
447
|
+
const stats = await lstat(path)
|
|
448
|
+
|
|
449
|
+
if (stats.isSymbolicLink()) {
|
|
450
|
+
let target
|
|
451
|
+
try {
|
|
452
|
+
target = await realpath(path)
|
|
453
|
+
} catch (error) {
|
|
454
|
+
if (error.code === 'ENOENT') {
|
|
455
|
+
continue
|
|
456
|
+
}
|
|
457
|
+
throw error
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!target.startsWith(bundleRoot)) {
|
|
461
|
+
throw new Error(`Packed bundle contains a symlink outside the bundle: ${relative(bundleRoot, path)} -> ${target}`)
|
|
462
|
+
}
|
|
463
|
+
} else if (entry.isDirectory()) {
|
|
464
|
+
await assertNoExternalSymlinks(path, bundleRoot)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { glob, readFile } from 'node:fs/promises'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import { dirname, resolve as resolvePath } from 'node:path'
|
|
5
|
+
import * as errors from './errors.js'
|
|
6
|
+
|
|
7
|
+
export async function resolveStandaloneEntrypoint (root) {
|
|
8
|
+
const serverEntrypoints = await Array.fromAsync(
|
|
9
|
+
glob(['server.js', '.next/standalone/**/server.js', '**/server.js'], {
|
|
10
|
+
cwd: root,
|
|
11
|
+
exclude: ['node_modules', '**/node_modules/**']
|
|
12
|
+
})
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
for (const entrypoint of serverEntrypoints) {
|
|
16
|
+
if (entrypoint !== 'server.js' && !existsSync(resolvePath(root, dirname(entrypoint), '.next'))) {
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const candidate = resolvePath(root, entrypoint)
|
|
21
|
+
const contents = await readFile(candidate, 'utf-8')
|
|
22
|
+
|
|
23
|
+
if (contents.includes('process.env.__NEXT_PRIVATE_STANDALONE_CONFIG =')) {
|
|
24
|
+
return candidate
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
throw new errors.StandaloneServerNotFound()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function parseStandaloneNextConfig (serverEntrypoint) {
|
|
32
|
+
try {
|
|
33
|
+
const serverJsContent = await readFile(serverEntrypoint, 'utf-8')
|
|
34
|
+
const nextConfigMatch = serverJsContent.match(/(?:const|let)\s*nextConfig\s*=\s*(\{.+)/)
|
|
35
|
+
return JSON.parse(nextConfigMatch[1])
|
|
36
|
+
} catch (e) {
|
|
37
|
+
throw new errors.CannotParseStandaloneServer({ cause: e })
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function requireStandaloneStartServer (serverEntrypoint) {
|
|
42
|
+
let serverModule
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
serverModule = createRequire(serverEntrypoint)('next/dist/server/lib/start-server.js')
|
|
46
|
+
} catch (e) {
|
|
47
|
+
serverModule = createRequire(import.meta.url)('next/dist/server/lib/start-server.js')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return serverModule.default ?? serverModule
|
|
51
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/next",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.55.0",
|
|
4
4
|
"description": "Platformatic Next.js Capability",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"light-my-request": "^6.0.0",
|
|
26
26
|
"msgpackr": "^1.11.2",
|
|
27
27
|
"semver": "^7.6.3",
|
|
28
|
-
"@platformatic/basic": "3.
|
|
29
|
-
"@platformatic/foundation": "3.
|
|
28
|
+
"@platformatic/basic": "3.55.0",
|
|
29
|
+
"@platformatic/foundation": "3.55.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@fastify/reply-from": "^12.0.0",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"next": "^16.1.0",
|
|
44
44
|
"typescript": "^5.5.4",
|
|
45
45
|
"ws": "^8.18.0",
|
|
46
|
-
"@platformatic/gateway": "3.
|
|
47
|
-
"@platformatic/service": "3.
|
|
46
|
+
"@platformatic/gateway": "3.55.0",
|
|
47
|
+
"@platformatic/service": "3.55.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=22.19.0"
|
package/schema.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://schemas.platformatic.dev/@platformatic/next/3.
|
|
2
|
+
"$id": "https://schemas.platformatic.dev/@platformatic/next/3.55.0.json",
|
|
3
3
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
4
|
"title": "Platformatic Next.js Config",
|
|
5
5
|
"type": "object",
|
|
@@ -606,6 +606,28 @@
|
|
|
606
606
|
"type": "string"
|
|
607
607
|
}
|
|
608
608
|
]
|
|
609
|
+
},
|
|
610
|
+
"bufferPoolSize": {
|
|
611
|
+
"anyOf": [
|
|
612
|
+
{
|
|
613
|
+
"type": "number",
|
|
614
|
+
"minimum": 0
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
"type": "string"
|
|
618
|
+
}
|
|
619
|
+
]
|
|
620
|
+
},
|
|
621
|
+
"defaultHighWaterMark": {
|
|
622
|
+
"anyOf": [
|
|
623
|
+
{
|
|
624
|
+
"type": "number",
|
|
625
|
+
"minimum": 0
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
"type": "string"
|
|
629
|
+
}
|
|
630
|
+
]
|
|
609
631
|
}
|
|
610
632
|
},
|
|
611
633
|
"additionalProperties": false
|
|
@@ -1315,6 +1337,30 @@
|
|
|
1315
1337
|
}
|
|
1316
1338
|
],
|
|
1317
1339
|
"default": 268435456
|
|
1340
|
+
},
|
|
1341
|
+
"bufferPoolSize": {
|
|
1342
|
+
"anyOf": [
|
|
1343
|
+
{
|
|
1344
|
+
"type": "number",
|
|
1345
|
+
"minimum": 0
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
"type": "string"
|
|
1349
|
+
}
|
|
1350
|
+
],
|
|
1351
|
+
"default": 262144
|
|
1352
|
+
},
|
|
1353
|
+
"defaultHighWaterMark": {
|
|
1354
|
+
"anyOf": [
|
|
1355
|
+
{
|
|
1356
|
+
"type": "number",
|
|
1357
|
+
"minimum": 0
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
"type": "string"
|
|
1361
|
+
}
|
|
1362
|
+
],
|
|
1363
|
+
"default": 262144
|
|
1318
1364
|
}
|
|
1319
1365
|
},
|
|
1320
1366
|
"additionalProperties": false
|
|
@@ -1597,6 +1643,18 @@
|
|
|
1597
1643
|
"default": "applicationId",
|
|
1598
1644
|
"description": "The label name to use for the application identifier in metrics (e.g., applicationId, serviceId)"
|
|
1599
1645
|
},
|
|
1646
|
+
"httpClientMetrics": {
|
|
1647
|
+
"anyOf": [
|
|
1648
|
+
{
|
|
1649
|
+
"type": "boolean"
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
"type": "string"
|
|
1653
|
+
}
|
|
1654
|
+
],
|
|
1655
|
+
"default": false,
|
|
1656
|
+
"description": "Enable outgoing HTTP client request duration metrics"
|
|
1657
|
+
},
|
|
1600
1658
|
"readiness": {
|
|
1601
1659
|
"anyOf": [
|
|
1602
1660
|
{
|
|
@@ -1918,7 +1976,14 @@
|
|
|
1918
1976
|
]
|
|
1919
1977
|
},
|
|
1920
1978
|
"diagLogger": {
|
|
1921
|
-
"
|
|
1979
|
+
"anyOf": [
|
|
1980
|
+
{
|
|
1981
|
+
"type": "boolean"
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
"type": "string"
|
|
1985
|
+
}
|
|
1986
|
+
],
|
|
1922
1987
|
"description": "Enable the OpenTelemetry diagnostic logger. Diagnostic messages are forwarded to the Platformatic global logger using the current logger level."
|
|
1923
1988
|
}
|
|
1924
1989
|
},
|
|
@@ -2321,6 +2386,28 @@
|
|
|
2321
2386
|
"type": "string"
|
|
2322
2387
|
}
|
|
2323
2388
|
]
|
|
2389
|
+
},
|
|
2390
|
+
"bufferPoolSize": {
|
|
2391
|
+
"anyOf": [
|
|
2392
|
+
{
|
|
2393
|
+
"type": "number",
|
|
2394
|
+
"minimum": 0
|
|
2395
|
+
},
|
|
2396
|
+
{
|
|
2397
|
+
"type": "string"
|
|
2398
|
+
}
|
|
2399
|
+
]
|
|
2400
|
+
},
|
|
2401
|
+
"defaultHighWaterMark": {
|
|
2402
|
+
"anyOf": [
|
|
2403
|
+
{
|
|
2404
|
+
"type": "number",
|
|
2405
|
+
"minimum": 0
|
|
2406
|
+
},
|
|
2407
|
+
{
|
|
2408
|
+
"type": "string"
|
|
2409
|
+
}
|
|
2410
|
+
]
|
|
2324
2411
|
}
|
|
2325
2412
|
},
|
|
2326
2413
|
"additionalProperties": false
|