@intelligems/sst 2.49.6-ig.9 → 2.49.8-ig.1

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 (44) hide show
  1. package/cli/commands/dev.js +10 -6
  2. package/constructs/AstroSite.d.ts +1 -1
  3. package/constructs/EdgeFunction.d.ts +1 -1
  4. package/constructs/EdgeFunction.js +8 -6
  5. package/constructs/Function.d.ts +3 -2
  6. package/constructs/Function.js +2 -1
  7. package/constructs/Job.d.ts +2 -2
  8. package/constructs/Job.js +4 -2
  9. package/constructs/NextjsSite.d.ts +1 -1
  10. package/constructs/NextjsSite.js +2 -2
  11. package/constructs/RemixSite.d.ts +1 -1
  12. package/constructs/SolidStartSite.d.ts +1 -1
  13. package/constructs/SsrFunction.d.ts +2 -2
  14. package/constructs/SsrFunction.js +7 -5
  15. package/constructs/SsrSite.d.ts +2 -2
  16. package/constructs/SsrSite.js +1 -1
  17. package/constructs/Stack.d.ts +1 -1
  18. package/constructs/Stack.js +1 -1
  19. package/constructs/SvelteKitSite.d.ts +1 -1
  20. package/constructs/deprecated/NextjsSite.d.ts +3 -3
  21. package/constructs/deprecated/NextjsSite.js +4 -1
  22. package/constructs/deprecated/cross-region-helper.js +3 -3
  23. package/package.json +3 -3
  24. package/runtime/handlers/node.js +24 -2
  25. package/runtime/handlers.d.ts +4 -0
  26. package/runtime/memory-logging.d.ts +26 -0
  27. package/runtime/memory-logging.js +112 -0
  28. package/runtime/mono-build-config.d.ts +6 -3
  29. package/runtime/mono-build-config.js +34 -10
  30. package/runtime/server.js +35 -44
  31. package/runtime/stdout-attribution.d.ts +18 -0
  32. package/runtime/stdout-attribution.js +43 -0
  33. package/runtime/worker-config.d.ts +19 -0
  34. package/runtime/worker-config.js +26 -0
  35. package/runtime/worker-pool-logging.d.ts +2 -2
  36. package/runtime/worker-pool-logging.js +5 -5
  37. package/runtime/worker-pool.d.ts +77 -0
  38. package/runtime/worker-pool.js +162 -0
  39. package/runtime/workers.d.ts +33 -11
  40. package/runtime/workers.js +405 -513
  41. package/support/nodejs-runtime/index.mjs +214 -100
  42. package/watcher.js +2 -0
  43. package/README.md +0 -43
  44. package/package.json.bak +0 -156
@@ -401,12 +401,16 @@ export const dev = (program) => program.command(["dev", "start"], "Work on your
401
401
  import("./plugins/warmer.js").then((mod) => mod.useRDSWarmer()),
402
402
  useFunctionLogger(),
403
403
  ]);
404
- // Trigger warmup by invoking Lambda functions with warmup payloads
405
- // This creates workers through the real request flow
406
- import("../../runtime/workers.js").then(async (mod) => {
407
- const workers = await mod.useRuntimeWorkers();
408
- await workers.triggerWarmup(30);
409
- });
404
+ // Warm the pool through the real request flow. SST_WARMUP_COUNT=0
405
+ // turns this off; the count is capped at the pool size so warmup can
406
+ // never hold more isolates than steady state would.
407
+ const { WARMUP_COUNT } = await import("../../runtime/worker-config.js");
408
+ if (WARMUP_COUNT > 0) {
409
+ import("../../runtime/workers.js").then(async (mod) => {
410
+ const workers = await mod.useRuntimeWorkers();
411
+ await workers.triggerWarmup(WARMUP_COUNT);
412
+ });
413
+ }
410
414
  }
411
415
  catch (e) {
412
416
  await exitWithError(e);
@@ -43,7 +43,7 @@ export declare class AstroSite extends SsrSite {
43
43
  data: {
44
44
  mode: "placeholder" | "deployed";
45
45
  path: string;
46
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
46
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
47
47
  customDomainUrl: string | undefined;
48
48
  url: string | undefined;
49
49
  edge: boolean | undefined;
@@ -9,7 +9,7 @@ import { Permissions } from "./util/permission.js";
9
9
  export interface EdgeFunctionProps {
10
10
  bundle?: string;
11
11
  handler: string;
12
- runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
12
+ runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
13
13
  timeout?: number | Duration;
14
14
  memorySize?: number | Size;
15
15
  permissions?: Permissions;
@@ -43,7 +43,7 @@ export class EdgeFunction extends Construct {
43
43
  // them.
44
44
  this.scope = props.scopeOverride || this;
45
45
  this.props = {
46
- runtime: "nodejs18.x",
46
+ runtime: "nodejs24.x",
47
47
  timeout: 10,
48
48
  memorySize: 1024,
49
49
  ...props,
@@ -345,11 +345,13 @@ export class EdgeFunction extends Construct {
345
345
  S3Bucket: assetBucket,
346
346
  S3Key: assetKey,
347
347
  },
348
- Runtime: runtime === "nodejs22.x"
349
- ? Runtime.NODEJS_22_X.name
350
- : runtime === "nodejs20.x"
351
- ? Runtime.NODEJS_20_X.name
352
- : Runtime.NODEJS_18_X.name,
348
+ Runtime: runtime === "nodejs24.x"
349
+ ? Runtime.NODEJS_24_X.name
350
+ : runtime === "nodejs22.x"
351
+ ? Runtime.NODEJS_22_X.name
352
+ : runtime === "nodejs20.x"
353
+ ? Runtime.NODEJS_20_X.name
354
+ : Runtime.NODEJS_18_X.name,
353
355
  MemorySize: typeof memorySize === "string"
354
356
  ? toCdkSize(memorySize).toMebibytes()
355
357
  : memorySize,
@@ -18,6 +18,7 @@ declare const supportedRuntimes: {
18
18
  "nodejs18.x": CDKRuntime;
19
19
  "nodejs20.x": CDKRuntime;
20
20
  "nodejs22.x": CDKRuntime;
21
+ "nodejs24.x": CDKRuntime;
21
22
  "python3.7": CDKRuntime;
22
23
  "python3.8": CDKRuntime;
23
24
  "python3.9": CDKRuntime;
@@ -150,7 +151,7 @@ export interface FunctionProps extends Omit<FunctionOptions, "functionName" | "m
150
151
  handler?: string;
151
152
  /**
152
153
  * The runtime environment for the function.
153
- * @default "nodejs22.x"
154
+ * @default "nodejs24.x"
154
155
  * @example
155
156
  * ```js
156
157
  * new Function(stack, "Function", {
@@ -799,7 +800,7 @@ export declare class Function extends CDKFunction implements SSTConstruct {
799
800
  type: "Function";
800
801
  data: {
801
802
  arn: string;
802
- runtime: "container" | "rust" | "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "python3.7" | "python3.8" | "python3.9" | "python3.10" | "python3.11" | "python3.12" | "python3.13" | "dotnetcore3.1" | "dotnet6" | "dotnet8" | "java8" | "java11" | "java17" | "java21" | "go1.x" | "go" | undefined;
803
+ runtime: "container" | "rust" | "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x" | "python3.7" | "python3.8" | "python3.9" | "python3.10" | "python3.11" | "python3.12" | "python3.13" | "dotnetcore3.1" | "dotnet6" | "dotnet8" | "java8" | "java11" | "java17" | "java21" | "go1.x" | "go" | undefined;
803
804
  handler: string | undefined;
804
805
  missingSourcemap: boolean | undefined;
805
806
  localId: string;
@@ -37,6 +37,7 @@ const supportedRuntimes = {
37
37
  "nodejs18.x": CDKRuntime.NODEJS_18_X,
38
38
  "nodejs20.x": CDKRuntime.NODEJS_20_X,
39
39
  "nodejs22.x": CDKRuntime.NODEJS_22_X,
40
+ "nodejs24.x": CDKRuntime.NODEJS_24_X,
40
41
  "python3.7": CDKRuntime.PYTHON_3_7,
41
42
  "python3.8": CDKRuntime.PYTHON_3_8,
42
43
  "python3.9": CDKRuntime.PYTHON_3_9,
@@ -89,7 +90,7 @@ export class Function extends CDKFunction {
89
90
  .forEach((per) => {
90
91
  props = Function.mergeProps(per, props);
91
92
  });
92
- props.runtime = props.runtime || "nodejs22.x";
93
+ props.runtime = props.runtime || "nodejs24.x";
93
94
  if (props.runtime === "go1.x")
94
95
  useWarning().add("go.deprecated");
95
96
  // Set defaults
@@ -100,7 +100,7 @@ export interface JobProps {
100
100
  architecture?: "x86_64" | "arm_64";
101
101
  /**
102
102
  * The runtime environment for the job.
103
- * @default "nodejs18.x"
103
+ * @default "nodejs24.x"
104
104
  * @example
105
105
  * ```js
106
106
  * new Job(stack, "MyJob", {
@@ -109,7 +109,7 @@ export interface JobProps {
109
109
  * })
110
110
  *```
111
111
  */
112
- runtime?: "nodejs" | "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "container";
112
+ runtime?: "nodejs" | "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x" | "container";
113
113
  /**
114
114
  * For "nodejs" runtime, point to the entry point and handler function.
115
115
  * Of the format: `/path/to/file.function`.
package/constructs/Job.js CHANGED
@@ -285,6 +285,7 @@ export class Job extends Construct {
285
285
  "nodejs18.x": "amazon/aws-lambda-nodejs:18.2023.12.14.13",
286
286
  "nodejs20.x": "amazon/aws-lambda-nodejs:20.2023.12.14.13",
287
287
  "nodejs22.x": "amazon/aws-lambda-nodejs:22.2024.11.22.14",
288
+ "nodejs24.x": "amazon/aws-lambda-nodejs:24.2025.12.21.13",
288
289
  },
289
290
  x86_64: {
290
291
  nodejs: "amazon/aws-lambda-nodejs:16",
@@ -292,11 +293,12 @@ export class Job extends Construct {
292
293
  "nodejs18.x": "amazon/aws-lambda-nodejs:18",
293
294
  "nodejs20.x": "amazon/aws-lambda-nodejs:20",
294
295
  "nodejs22.x": "amazon/aws-lambda-nodejs:22",
296
+ "nodejs24.x": "amazon/aws-lambda-nodejs:24",
295
297
  },
296
298
  };
297
299
  const image = LinuxBuildImage.fromDockerRegistry(
298
300
  // ARM images can be found here https://hub.docker.com/r/amazon/aws-lambda-nodejs
299
- dockerImageMap[architecture ?? "x86_64"][runtime ?? "nodejs18.x"]);
301
+ dockerImageMap[architecture ?? "x86_64"][runtime ?? "nodejs24.x"]);
300
302
  project.environment = {
301
303
  ...project.environment,
302
304
  type: architecture === "arm_64" ? "ARM_CONTAINER" : "LINUX_CONTAINER",
@@ -415,6 +417,6 @@ export class Job extends Construct {
415
417
  }
416
418
  convertJobRuntimeToFunctionRuntime() {
417
419
  const { runtime } = this.props;
418
- return runtime === "container" ? "container" : "nodejs18.x";
420
+ return runtime === "container" ? "container" : "nodejs24.x";
419
421
  }
420
422
  }
@@ -163,7 +163,7 @@ export declare class NextjsSite extends SsrSite {
163
163
  data: {
164
164
  mode: "placeholder" | "deployed";
165
165
  path: string;
166
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
166
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
167
167
  customDomainUrl: string | undefined;
168
168
  url: string | undefined;
169
169
  edge: boolean | undefined;
@@ -78,7 +78,7 @@ export class NextjsSite extends SsrSite {
78
78
  ...baseServerConfig,
79
79
  handler: fn.handler,
80
80
  bundle: path.join(sitePath, fn.bundle),
81
- runtime: this.props.runtime ?? "nodejs18.x",
81
+ runtime: this.props.runtime ?? "nodejs24.x",
82
82
  architecture: Architecture.ARM_64,
83
83
  memorySize: this.props.memorySize ?? 1536,
84
84
  environment: {
@@ -107,7 +107,7 @@ export class NextjsSite extends SsrSite {
107
107
  function: {
108
108
  handler: fn.handler,
109
109
  bundle: path.join(sitePath, fn.bundle),
110
- runtime: "nodejs18.x",
110
+ runtime: "nodejs24.x",
111
111
  memorySize: 1024,
112
112
  environment: {
113
113
  ...environment,
@@ -101,7 +101,7 @@ export declare class RemixSite extends SsrSite {
101
101
  data: {
102
102
  mode: "placeholder" | "deployed";
103
103
  path: string;
104
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
104
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
105
105
  customDomainUrl: string | undefined;
106
106
  url: string | undefined;
107
107
  edge: boolean | undefined;
@@ -80,7 +80,7 @@ export declare class SolidStartSite extends SsrSite {
80
80
  data: {
81
81
  mode: "placeholder" | "deployed";
82
82
  path: string;
83
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
83
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
84
84
  customDomainUrl: string | undefined;
85
85
  url: string | undefined;
86
86
  edge: boolean | undefined;
@@ -11,7 +11,7 @@ import { Duration } from "./util/duration.js";
11
11
  export interface SsrFunctionProps extends Omit<FunctionOptions, "memorySize" | "timeout" | "runtime"> {
12
12
  bundle?: string;
13
13
  handler: string;
14
- runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
14
+ runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
15
15
  timeout?: number | Duration;
16
16
  memorySize?: number | Size;
17
17
  permissions?: Permissions;
@@ -58,7 +58,7 @@ export declare class SsrFunction extends Construct implements SSTConstruct {
58
58
  type: "Function";
59
59
  data: {
60
60
  arn: string;
61
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | undefined;
61
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x" | undefined;
62
62
  handler: string;
63
63
  missingSourcemap: boolean | undefined;
64
64
  localId: string;
@@ -107,11 +107,13 @@ export class SsrFunction extends Construct {
107
107
  handler: handler.split(path.sep).join(path.posix.sep),
108
108
  logRetention: logRetention ?? RetentionDays.THREE_DAYS,
109
109
  code: Code.fromBucket(Bucket.fromBucketName(this, "IServerFunctionBucket", assetBucket), assetKey),
110
- runtime: runtime === "nodejs22.x"
111
- ? Runtime.NODEJS_22_X
112
- : runtime === "nodejs20.x"
113
- ? Runtime.NODEJS_20_X
114
- : Runtime.NODEJS_18_X,
110
+ runtime: runtime === "nodejs24.x"
111
+ ? Runtime.NODEJS_24_X
112
+ : runtime === "nodejs22.x"
113
+ ? Runtime.NODEJS_22_X
114
+ : runtime === "nodejs20.x"
115
+ ? Runtime.NODEJS_20_X
116
+ : Runtime.NODEJS_18_X,
115
117
  architecture,
116
118
  memorySize: typeof memorySize === "string"
117
119
  ? toCdkSize(memorySize).toMebibytes()
@@ -139,7 +139,7 @@ export interface SsrSiteProps {
139
139
  * runtime: "nodejs20.x",
140
140
  * ```
141
141
  */
142
- runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
142
+ runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
143
143
  /**
144
144
  * Used to configure nodejs function properties
145
145
  */
@@ -465,7 +465,7 @@ export declare abstract class SsrSite extends Construct implements SSTConstruct
465
465
  data: {
466
466
  mode: "placeholder" | "deployed";
467
467
  path: string;
468
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
468
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
469
469
  customDomainUrl: string | undefined;
470
470
  url: string | undefined;
471
471
  edge: boolean | undefined;
@@ -634,7 +634,7 @@ function handler(event) {
634
634
  singletonUrlSigner ??
635
635
  new EdgeFunction(self, "ServerUrlSigningFunction", {
636
636
  bundle: path.join(__dirname, "../support/signing-function"),
637
- runtime: "nodejs18.x",
637
+ runtime: "nodejs24.x",
638
638
  handler: "index.handler",
639
639
  timeout: 10,
640
640
  memorySize: 128,
@@ -47,7 +47,7 @@ export declare class Stack extends CDKStack {
47
47
  * ```js
48
48
  * stack.setDefaultFunctionProps({
49
49
  * srcPath: "backend",
50
- * runtime: "nodejs18.x",
50
+ * runtime: "nodejs24.x",
51
51
  * });
52
52
  * ```
53
53
  */
@@ -68,7 +68,7 @@ export class Stack extends CDKStack {
68
68
  * ```js
69
69
  * stack.setDefaultFunctionProps({
70
70
  * srcPath: "backend",
71
- * runtime: "nodejs18.x",
71
+ * runtime: "nodejs24.x",
72
72
  * });
73
73
  * ```
74
74
  */
@@ -121,7 +121,7 @@ export declare class SvelteKitSite extends SsrSite {
121
121
  data: {
122
122
  mode: "placeholder" | "deployed";
123
123
  path: string;
124
- runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
124
+ runtime: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
125
125
  customDomainUrl: string | undefined;
126
126
  url: string | undefined;
127
127
  edge: boolean | undefined;
@@ -74,16 +74,16 @@ export interface NextjsSiteProps {
74
74
  permissions?: Permissions;
75
75
  /**
76
76
  * The runtime environment.
77
- * @default "nodejs18.x"
77
+ * @default "nodejs24.x"
78
78
  * @example
79
79
  * ```js
80
80
  * new Function(stack, "Function", {
81
81
  * path: "path/to/site",
82
- * runtime: "nodejs18.x",
82
+ * runtime: "nodejs24.x",
83
83
  * })
84
84
  *```
85
85
  */
86
- runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x";
86
+ runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "nodejs22.x" | "nodejs24.x";
87
87
  };
88
88
  };
89
89
  /**
@@ -1039,13 +1039,16 @@ export class NextjsSite extends Construct {
1039
1039
  return replaceValues;
1040
1040
  }
1041
1041
  normalizeRuntime(runtime) {
1042
+ if (runtime === "nodejs24.x") {
1043
+ return lambda.Runtime.NODEJS_24_X;
1044
+ }
1042
1045
  if (runtime === "nodejs22.x") {
1043
1046
  return lambda.Runtime.NODEJS_22_X;
1044
1047
  }
1045
1048
  if (runtime === "nodejs20.x") {
1046
1049
  return lambda.Runtime.NODEJS_20_X;
1047
1050
  }
1048
- return lambda.Runtime.NODEJS_18_X;
1051
+ return lambda.Runtime.NODEJS_24_X;
1049
1052
  }
1050
1053
  }
1051
1054
  export const useSites = createAppContext(() => {
@@ -18,7 +18,7 @@ export function getOrCreateBucket(scope) {
18
18
  const provider = new lambda.Function(stack, providerId, {
19
19
  code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
20
20
  handler: "s3-bucket.handler",
21
- runtime: lambda.Runtime.NODEJS_20_X,
21
+ runtime: lambda.Runtime.NODEJS_22_X,
22
22
  timeout: Duration.minutes(15),
23
23
  memorySize: 1024,
24
24
  initialPolicy: [
@@ -50,7 +50,7 @@ export function createFunction(scope, name, role, bucketName, functionParams) {
50
50
  provider = new lambda.Function(stack, providerId, {
51
51
  code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
52
52
  handler: "edge-lambda.handler",
53
- runtime: lambda.Runtime.NODEJS_20_X,
53
+ runtime: lambda.Runtime.NODEJS_22_X,
54
54
  timeout: Duration.minutes(15),
55
55
  memorySize: 1024,
56
56
  initialPolicy: [
@@ -88,7 +88,7 @@ export function createVersion(scope, name, functionArn) {
88
88
  provider = new lambda.Function(stack, providerId, {
89
89
  code: lambda.Code.fromAsset(path.join(__dirname, "../../support/edge-function")),
90
90
  handler: "edge-lambda-version.handler",
91
- runtime: lambda.Runtime.NODEJS_20_X,
91
+ runtime: lambda.Runtime.NODEJS_22_X,
92
92
  timeout: Duration.minutes(15),
93
93
  memorySize: 1024,
94
94
  initialPolicy: [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "@intelligems/sst",
4
- "version": "2.49.6-ig.9",
4
+ "version": "2.49.8-ig.1",
5
5
  "bin": {
6
6
  "sst": "cli/sst.js"
7
7
  },
@@ -32,7 +32,7 @@
32
32
  "homepage": "https://sst.dev",
33
33
  "dependencies": {
34
34
  "@aws-cdk/aws-lambda-python-alpha": "2.201.0-alpha.0",
35
- "@aws-cdk/cloud-assembly-schema": "44.5.0",
35
+ "@aws-cdk/cloud-assembly-schema": "48.0.0",
36
36
  "@aws-cdk/cloudformation-diff": "2.182.0",
37
37
  "@aws-cdk/cx-api": "2.201.0",
38
38
  "@aws-cdk/toolkit-lib": "1.1.1",
@@ -60,7 +60,7 @@
60
60
  "@smithy/signature-v4": "2.0.16",
61
61
  "@trpc/server": "9.18.0",
62
62
  "adm-zip": "0.5.14",
63
- "aws-cdk-lib": "2.201.0",
63
+ "aws-cdk-lib": "2.224.0",
64
64
  "aws-iot-device-sdk": "^2.2.13",
65
65
  "aws-sdk": "^2.1501.0",
66
66
  "builtin-modules": "3.2.0",
@@ -12,6 +12,8 @@ import { Colors } from "../../cli/colors.js";
12
12
  import { Logger } from "../../logger.js";
13
13
  import { findAbove } from "../../util/fs.js";
14
14
  import { useMonoBuildConfig } from "../mono-build-config.js";
15
+ import { SOURCE_MAPS, WORKER_MAX_HEAP_MB } from "../worker-config.js";
16
+ import { forgetWorkerMemory, recordWorkerMemory } from "../memory-logging.js";
15
17
  export const useNodeHandler = () => {
16
18
  const rebuildCache = {};
17
19
  process.on("exit", () => {
@@ -40,7 +42,13 @@ export const useNodeHandler = () => {
40
42
  ...input.environment,
41
43
  IS_LOCAL: "true",
42
44
  },
43
- execArgv: ["--enable-source-maps"],
45
+ // Source maps cost memory in every isolate; opt in with SST_SOURCE_MAPS=true
46
+ execArgv: SOURCE_MAPS ? ["--enable-source-maps"] : [],
47
+ // Cap each isolate so a leaking handler kills its own worker
48
+ // instead of growing the whole dev process until the machine stalls
49
+ resourceLimits: WORKER_MAX_HEAP_MB > 0
50
+ ? { maxOldGenerationSizeMb: WORKER_MAX_HEAP_MB }
51
+ : undefined,
44
52
  workerData: input,
45
53
  stderr: true,
46
54
  stdin: true,
@@ -52,11 +60,25 @@ export const useNodeHandler = () => {
52
60
  worker.stderr.on("data", (data) => {
53
61
  workers.stdout(input.workerID, data.toString());
54
62
  });
55
- worker.on("exit", () => workers.exited(input.workerID));
63
+ worker.on("message", (msg) => {
64
+ if (msg && msg.type === "sst.memory") {
65
+ recordWorkerMemory(input.workerID, msg.report);
66
+ }
67
+ });
68
+ worker.on("error", (err) => {
69
+ Logger.debug("Worker error", input.workerID, err);
70
+ });
71
+ worker.on("exit", () => {
72
+ threads.delete(input.workerID);
73
+ forgetWorkerMemory(input.workerID);
74
+ workers.exited(input.workerID);
75
+ });
56
76
  threads.set(input.workerID, worker);
57
77
  },
58
78
  stopWorker: async (workerID) => {
59
79
  const worker = threads.get(workerID);
80
+ threads.delete(workerID);
81
+ forgetWorkerMemory(workerID);
60
82
  await worker?.terminate();
61
83
  },
62
84
  build: async (input) => {
@@ -30,6 +30,10 @@ export interface StartWorkerInput {
30
30
  runtime: string;
31
31
  /** Whether this worker is using mono build mode */
32
32
  isMonoBuild?: boolean;
33
+ /** Invocations this worker may run at once (Node only; others run one). */
34
+ concurrency?: number;
35
+ /** Ask the worker to report its memory usage to the parent. */
36
+ debugMemory?: boolean;
33
37
  }
34
38
  interface ShouldBuildInput {
35
39
  file: string;
@@ -0,0 +1,26 @@
1
+ export interface WorkerMemoryReport {
2
+ rss: number;
3
+ heapUsed: number;
4
+ heapTotal: number;
5
+ external: number;
6
+ /** "loaded" right after the bundle import, "response" after an invocation. */
7
+ phase: "loaded" | "response";
8
+ loadMs?: number;
9
+ }
10
+ interface WorkerStatsProvider {
11
+ (): {
12
+ workers: number;
13
+ inFlight: number;
14
+ queued: number;
15
+ };
16
+ }
17
+ export declare const isMemoryTrackingEnabled: () => boolean;
18
+ /** Called by the Node handler whenever a worker posts a memory report. */
19
+ export declare function recordWorkerMemory(workerID: string, report: WorkerMemoryReport): void;
20
+ /** Called by the Node handler when a worker goes away. */
21
+ export declare function forgetWorkerMemory(workerID: string): void;
22
+ /** Start periodic sampling. No-op unless SST_DEBUG_MEMORY=true. */
23
+ export declare function startMemorySampling(stats: WorkerStatsProvider): void;
24
+ /** Peak line for the pool session summary. Empty when tracking is off. */
25
+ export declare function memorySummary(): string;
26
+ export {};
@@ -0,0 +1,112 @@
1
+ import os from "os";
2
+ import { createDebugFileLogger } from "./debug-file-logger.js";
3
+ import { DEBUG_MEMORY, POOL_SIZE, WORKER_CONCURRENCY } from "./worker-config.js";
4
+ /**
5
+ * Memory tracking for `sst dev`, enabled with SST_DEBUG_MEMORY=true.
6
+ *
7
+ * Every SAMPLE_INTERVAL_MS a line goes to .sst/memory.log with the parent
8
+ * process's memory, the number of live workers and in-flight invocations, and
9
+ * the sum of what the workers last reported for themselves. Node workers report
10
+ * their own heap through `parentPort` after they load the bundle and after
11
+ * each response (see support/nodejs-runtime). Peaks are folded into the pool
12
+ * session summary so a run can be compared with the previous version at a glance.
13
+ */
14
+ const MEMORY_LOG_FILE = process.env.SST_DEBUG_MEMORY_FILE || ".sst/memory.log";
15
+ const SAMPLE_INTERVAL_MS = 10_000;
16
+ const mb = (bytes) => Math.round(bytes / 1024 / 1024);
17
+ let logger = null;
18
+ let timer;
19
+ const workerReports = new Map();
20
+ const peaks = {
21
+ rss: 0,
22
+ heapUsed: 0,
23
+ workers: 0,
24
+ inFlight: 0,
25
+ queued: 0,
26
+ workerHeap: 0,
27
+ firstLoadMs: undefined,
28
+ };
29
+ function getLogger() {
30
+ if (!DEBUG_MEMORY)
31
+ return null;
32
+ if (!logger) {
33
+ logger = createDebugFileLogger({
34
+ filePath: MEMORY_LOG_FILE,
35
+ sessionName: "MEMORY",
36
+ sessionHeader: `POOL_SIZE=${POOL_SIZE} CONCURRENCY=${WORKER_CONCURRENCY} totalMem=${mb(os.totalmem())}MB`,
37
+ width: 100,
38
+ });
39
+ }
40
+ return logger;
41
+ }
42
+ export const isMemoryTrackingEnabled = () => DEBUG_MEMORY;
43
+ /** Called by the Node handler whenever a worker posts a memory report. */
44
+ export function recordWorkerMemory(workerID, report) {
45
+ if (!DEBUG_MEMORY)
46
+ return;
47
+ workerReports.set(workerID, report);
48
+ if (report.phase === "loaded" && peaks.firstLoadMs === undefined) {
49
+ peaks.firstLoadMs = report.loadMs;
50
+ }
51
+ const log = getLogger();
52
+ log?.log("WORKER", {
53
+ worker: workerID.slice(0, 8),
54
+ phase: report.phase,
55
+ heapUsedMB: mb(report.heapUsed),
56
+ heapTotalMB: mb(report.heapTotal),
57
+ externalMB: mb(report.external),
58
+ ...(report.loadMs !== undefined ? { loadMs: report.loadMs } : {}),
59
+ });
60
+ }
61
+ /** Called by the Node handler when a worker goes away. */
62
+ export function forgetWorkerMemory(workerID) {
63
+ workerReports.delete(workerID);
64
+ }
65
+ function sample(stats) {
66
+ const log = getLogger();
67
+ if (!log)
68
+ return;
69
+ const usage = process.memoryUsage();
70
+ const { workers, inFlight, queued } = stats();
71
+ let workerHeap = 0;
72
+ for (const report of workerReports.values())
73
+ workerHeap += report.heapUsed;
74
+ peaks.rss = Math.max(peaks.rss, usage.rss);
75
+ peaks.heapUsed = Math.max(peaks.heapUsed, usage.heapUsed);
76
+ peaks.workers = Math.max(peaks.workers, workers);
77
+ peaks.inFlight = Math.max(peaks.inFlight, inFlight);
78
+ peaks.queued = Math.max(peaks.queued, queued);
79
+ peaks.workerHeap = Math.max(peaks.workerHeap, workerHeap);
80
+ log.log("SAMPLE", {
81
+ rssMB: mb(usage.rss),
82
+ heapUsedMB: mb(usage.heapUsed),
83
+ externalMB: mb(usage.external),
84
+ workers,
85
+ inFlight,
86
+ queued,
87
+ workerHeapMB: mb(workerHeap),
88
+ freeMB: mb(os.freemem()),
89
+ });
90
+ }
91
+ /** Start periodic sampling. No-op unless SST_DEBUG_MEMORY=true. */
92
+ export function startMemorySampling(stats) {
93
+ if (!DEBUG_MEMORY || timer)
94
+ return;
95
+ sample(stats);
96
+ timer = setInterval(() => sample(stats), SAMPLE_INTERVAL_MS);
97
+ timer.unref();
98
+ process.on("exit", () => {
99
+ clearInterval(timer);
100
+ getLogger()?.close(memorySummary());
101
+ });
102
+ }
103
+ /** Peak line for the pool session summary. Empty when tracking is off. */
104
+ export function memorySummary() {
105
+ if (!DEBUG_MEMORY)
106
+ return "";
107
+ return (` memory: peakRSS=${mb(peaks.rss)}MB peakHeap=${mb(peaks.heapUsed)}MB ` +
108
+ `peakWorkers=${peaks.workers} peakInFlight=${peaks.inFlight} peakQueued=${peaks.queued} ` +
109
+ `peakWorkerHeap=${mb(peaks.workerHeap)}MB` +
110
+ (peaks.firstLoadMs !== undefined ? ` firstBundleLoad=${peaks.firstLoadMs}ms` : "") +
111
+ "\n");
112
+ }
@@ -5,14 +5,17 @@
5
5
  * instead of building each handler individually. This significantly speeds up dev mode
6
6
  * by sharing compilation work across all handlers.
7
7
  *
8
- * Detection happens once at startup and the result is cached for the session.
8
+ * Detection latches on: the first check that finds the bundle enables mono
9
+ * build for the rest of the session. It deliberately does NOT latch off, so a
10
+ * caller arriving before the bundle has been written cannot disable it.
9
11
  */
10
12
  export declare const useMonoBuildConfig: () => {
11
13
  /**
12
- * Whether mono build mode is enabled (detected at startup).
14
+ * Whether mono build mode is enabled. Re-checked until the bundle is
15
+ * found, so a check made before it was written does not stick.
13
16
  * When true, all Node.js handlers use the shared .mono-build bundle.
14
17
  */
15
- enabled: boolean;
18
+ readonly enabled: boolean;
16
19
  /**
17
20
  * The mono bundle directory (.mono-build)
18
21
  */