@friggframework/devtools 2.0.0--canary.625.6bef7de.0 → 2.0.0--canary.625.eaeb79b.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.
@@ -32,17 +32,30 @@ const {
32
32
  * present at /var/task. esbuild-bundled functions (e.g. defaultWebsocket,
33
33
  * adopter custom functions) do NOT ship it — and a missing --import target is a
34
34
  * fatal Node startup error — so they are left with the handler-time loader
35
- * fallback instead. Set at function scope (function env wins over provider env).
35
+ * fallback instead.
36
+ *
37
+ * Set at function scope (function env wins over provider env), APPENDED to any
38
+ * NODE_OPTIONS already on the function or provider — so an app's own flags
39
+ * (OTel auto-instrumentation, source maps, memory tuning) survive instead of
40
+ * being clobbered. A function-level assignment shadows provider env in Lambda,
41
+ * so the provider value must be folded in here. Only a value already in the
42
+ * definition is appended — never a synthesized ${env:NODE_OPTIONS}, which would
43
+ * leak the deploy host's shell into every Lambda.
36
44
  */
37
- function applySsmPreloadNodeOptions(appDefinition, functions) {
45
+ function applySsmPreloadNodeOptions(appDefinition, functions, providerEnvironment = {}) {
38
46
  if (!isSsmOffloadActive(appDefinition)) {
39
47
  return;
40
48
  }
41
49
  for (const fn of Object.values(functions)) {
42
- if (fn.skipEsbuild) {
43
- fn.environment = fn.environment || {};
44
- fn.environment.NODE_OPTIONS = SSM_PRELOAD_NODE_OPTIONS;
50
+ if (!fn.skipEsbuild) {
51
+ continue;
45
52
  }
53
+ fn.environment = fn.environment || {};
54
+ const existing =
55
+ fn.environment.NODE_OPTIONS ?? providerEnvironment.NODE_OPTIONS;
56
+ fn.environment.NODE_OPTIONS = existing
57
+ ? `${existing} ${SSM_PRELOAD_NODE_OPTIONS}`
58
+ : SSM_PRELOAD_NODE_OPTIONS;
46
59
  }
47
60
  }
48
61
  const { modifyHandlerPaths } = require('./domains/shared/utilities/handler-path-resolver');
@@ -104,7 +117,11 @@ const composeServerlessDefinition = async (AppDefinition) => {
104
117
  definition.functions,
105
118
  merged.functionEnvironments
106
119
  );
107
- applySsmPreloadNodeOptions(AppDefinition, definition.functions);
120
+ applySsmPreloadNodeOptions(
121
+ AppDefinition,
122
+ definition.functions,
123
+ definition.provider.environment
124
+ );
108
125
 
109
126
  if (merged.vpcConfig) {
110
127
  definition.provider.vpc = merged.vpcConfig;
@@ -147,5 +164,5 @@ const composeServerlessDefinition = async (AppDefinition) => {
147
164
  return definition;
148
165
  };
149
166
 
150
- module.exports = { composeServerlessDefinition };
167
+ module.exports = { composeServerlessDefinition, applySsmPreloadNodeOptions };
151
168
 
@@ -1,4 +1,10 @@
1
- const { composeServerlessDefinition } = require('./infrastructure-composer');
1
+ const {
2
+ composeServerlessDefinition,
3
+ applySsmPreloadNodeOptions,
4
+ } = require('./infrastructure-composer');
5
+ const {
6
+ SSM_PRELOAD_NODE_OPTIONS,
7
+ } = require('./domains/parameters/offload-utils');
2
8
 
3
9
  // Helper to build discovery responses with overridable fields
4
10
  const createDiscoveryResponse = (overrides = {}) => ({
@@ -1949,3 +1955,88 @@ describe('composeServerlessDefinition', () => {
1949
1955
  });
1950
1956
  });
1951
1957
  });
1958
+
1959
+ describe('applySsmPreloadNodeOptions', () => {
1960
+ const appDefinition = {
1961
+ ssm: { enable: true },
1962
+ environment: { FOO: 'ssm' },
1963
+ };
1964
+ const savedSkip = process.env.FRIGG_SKIP_AWS_DISCOVERY;
1965
+
1966
+ beforeEach(() => {
1967
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1968
+ });
1969
+
1970
+ afterEach(() => {
1971
+ if (savedSkip === undefined) {
1972
+ delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
1973
+ } else {
1974
+ process.env.FRIGG_SKIP_AWS_DISCOVERY = savedSkip;
1975
+ }
1976
+ });
1977
+
1978
+ it('sets the preload NODE_OPTIONS on a skipEsbuild function with no existing value', () => {
1979
+ const functions = { auth: { skipEsbuild: true } };
1980
+ applySsmPreloadNodeOptions(appDefinition, functions);
1981
+ expect(functions.auth.environment.NODE_OPTIONS).toBe(
1982
+ SSM_PRELOAD_NODE_OPTIONS
1983
+ );
1984
+ });
1985
+
1986
+ it('appends to an existing function-level NODE_OPTIONS instead of clobbering it', () => {
1987
+ const functions = {
1988
+ auth: {
1989
+ skipEsbuild: true,
1990
+ environment: { NODE_OPTIONS: '--enable-source-maps' },
1991
+ },
1992
+ };
1993
+ applySsmPreloadNodeOptions(appDefinition, functions);
1994
+ expect(functions.auth.environment.NODE_OPTIONS).toBe(
1995
+ `--enable-source-maps ${SSM_PRELOAD_NODE_OPTIONS}`
1996
+ );
1997
+ });
1998
+
1999
+ it('folds in a provider-level NODE_OPTIONS (which the function env would otherwise shadow)', () => {
2000
+ const functions = { auth: { skipEsbuild: true } };
2001
+ applySsmPreloadNodeOptions(appDefinition, functions, {
2002
+ NODE_OPTIONS: '--require ./otel.js',
2003
+ });
2004
+ expect(functions.auth.environment.NODE_OPTIONS).toBe(
2005
+ `--require ./otel.js ${SSM_PRELOAD_NODE_OPTIONS}`
2006
+ );
2007
+ });
2008
+
2009
+ it('prefers a function-level value over the provider-level one', () => {
2010
+ const functions = {
2011
+ auth: {
2012
+ skipEsbuild: true,
2013
+ environment: { NODE_OPTIONS: '--fn-flag' },
2014
+ },
2015
+ };
2016
+ applySsmPreloadNodeOptions(appDefinition, functions, {
2017
+ NODE_OPTIONS: '--provider-flag',
2018
+ });
2019
+ expect(functions.auth.environment.NODE_OPTIONS).toBe(
2020
+ `--fn-flag ${SSM_PRELOAD_NODE_OPTIONS}`
2021
+ );
2022
+ });
2023
+
2024
+ it('never touches esbuild-bundled functions', () => {
2025
+ const functions = {
2026
+ websocket: { environment: { NODE_OPTIONS: '--keep-me' } },
2027
+ };
2028
+ applySsmPreloadNodeOptions(appDefinition, functions, {
2029
+ NODE_OPTIONS: '--provider',
2030
+ });
2031
+ expect(functions.websocket.environment.NODE_OPTIONS).toBe('--keep-me');
2032
+ });
2033
+
2034
+ it('is a no-op when offload is inactive', () => {
2035
+ const functions = { auth: { skipEsbuild: true } };
2036
+ applySsmPreloadNodeOptions(
2037
+ { ssm: { enable: true } }, // no offloaded keys → inactive
2038
+ functions
2039
+ );
2040
+ expect(functions.auth.environment).toBeUndefined();
2041
+ });
2042
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/devtools",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "2.0.0--canary.625.6bef7de.0",
4
+ "version": "2.0.0--canary.625.eaeb79b.0",
5
5
  "bin": {
6
6
  "frigg": "./frigg-cli/index.js"
7
7
  },
@@ -26,9 +26,9 @@
26
26
  "@babel/eslint-parser": "^7.18.9",
27
27
  "@babel/parser": "^7.25.3",
28
28
  "@babel/traverse": "^7.25.3",
29
- "@friggframework/core": "2.0.0--canary.625.6bef7de.0",
30
- "@friggframework/schemas": "2.0.0--canary.625.6bef7de.0",
31
- "@friggframework/test": "2.0.0--canary.625.6bef7de.0",
29
+ "@friggframework/core": "2.0.0--canary.625.eaeb79b.0",
30
+ "@friggframework/schemas": "2.0.0--canary.625.eaeb79b.0",
31
+ "@friggframework/test": "2.0.0--canary.625.eaeb79b.0",
32
32
  "@hapi/boom": "^10.0.1",
33
33
  "@inquirer/prompts": "^5.3.8",
34
34
  "axios": "^1.18.0",
@@ -56,8 +56,8 @@
56
56
  "validate-npm-package-name": "^5.0.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@friggframework/eslint-config": "2.0.0--canary.625.6bef7de.0",
60
- "@friggframework/prettier-config": "2.0.0--canary.625.6bef7de.0",
59
+ "@friggframework/eslint-config": "2.0.0--canary.625.eaeb79b.0",
60
+ "@friggframework/prettier-config": "2.0.0--canary.625.eaeb79b.0",
61
61
  "aws-sdk-client-mock": "^4.1.0",
62
62
  "aws-sdk-client-mock-jest": "^4.1.0",
63
63
  "jest": "^30.1.3",
@@ -89,5 +89,5 @@
89
89
  "publishConfig": {
90
90
  "access": "public"
91
91
  },
92
- "gitHead": "6bef7de84e4deea31c8dea40c177e2f7343eea4c"
92
+ "gitHead": "eaeb79b0e8f8bbe466ac40f389d603e86bd806b7"
93
93
  }