@friggframework/devtools 2.0.0--canary.625.8f60019.0 → 2.0.0--canary.625.0de0db4.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/infrastructure/__tests__/ssm-preload-node-options.test.js +79 -0
- package/infrastructure/domains/networking/vpc-discovery.js +9 -2
- package/infrastructure/domains/networking/vpc-discovery.test.js +19 -1
- package/infrastructure/domains/parameters/offload-utils.js +16 -1
- package/infrastructure/domains/parameters/ssm-builder.js +6 -14
- package/infrastructure/domains/parameters/ssm-builder.test.js +3 -13
- package/infrastructure/domains/security/iam-generator.js +4 -1
- package/infrastructure/domains/security/iam-generator.test.js +10 -0
- package/infrastructure/domains/security/templates/frigg-deployment-iam-stack.yaml +3 -1
- package/infrastructure/domains/security/templates/iam-policy-full.json +1 -1
- package/infrastructure/infrastructure-composer.js +25 -0
- package/package.json +7 -7
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The SSM INIT preload (NODE_OPTIONS=--import) must be scoped to skipEsbuild
|
|
3
|
+
* functions only. esbuild-bundled functions (e.g. defaultWebsocket) do not
|
|
4
|
+
* package the preload .mjs, and a missing --import target fatally aborts Node
|
|
5
|
+
* startup — so a global NODE_OPTIONS would brick them (ADR-027 review finding).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { composeServerlessDefinition } = require('../infrastructure-composer');
|
|
9
|
+
|
|
10
|
+
jest.mock('../domains/shared/resource-discovery', () => {
|
|
11
|
+
const original = jest.requireActual('../domains/shared/resource-discovery');
|
|
12
|
+
return {
|
|
13
|
+
...original,
|
|
14
|
+
gatherDiscoveredResources: jest.fn().mockResolvedValue({
|
|
15
|
+
defaultVpcId: 'vpc-123456',
|
|
16
|
+
defaultSecurityGroupId: 'sg-123456',
|
|
17
|
+
privateSubnetId1: 'subnet-1',
|
|
18
|
+
privateSubnetId2: 'subnet-2',
|
|
19
|
+
defaultKmsKeyId:
|
|
20
|
+
'arn:aws:kms:us-east-1:123456789012:key/abc-123',
|
|
21
|
+
auroraClusterEndpoint: 'c.cluster-x.us-east-1.rds.amazonaws.com',
|
|
22
|
+
auroraPort: 5432,
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const buildApp = (overrides = {}) => ({
|
|
28
|
+
name: 'preload-test',
|
|
29
|
+
provider: 'aws',
|
|
30
|
+
usePrismaLambdaLayer: false,
|
|
31
|
+
encryption: { fieldLevelEncryptionMethod: 'aes' },
|
|
32
|
+
vpc: { enable: false },
|
|
33
|
+
database: { postgres: { enable: true } },
|
|
34
|
+
websockets: { enable: true },
|
|
35
|
+
integrations: [{ Definition: { name: 'hubspot' } }],
|
|
36
|
+
...overrides,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const IMPORT_FRAGMENT = '--import file:///var/task/node_modules/@friggframework/core/core/ssm-preload.mjs';
|
|
40
|
+
|
|
41
|
+
describe('SSM preload NODE_OPTIONS scoping', () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
process.argv = ['node', 'test'];
|
|
44
|
+
delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('sets NODE_OPTIONS --import on skipEsbuild functions and NOT on esbuild-bundled ones when offload is active', async () => {
|
|
48
|
+
const definition = await composeServerlessDefinition(
|
|
49
|
+
buildApp({
|
|
50
|
+
ssm: { enable: true },
|
|
51
|
+
environment: { HUBSPOT_SECRET: 'ssm' },
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
const fns = definition.functions;
|
|
55
|
+
|
|
56
|
+
// skipEsbuild handlers (auth/user/health + integration) package the
|
|
57
|
+
// preload → they get the flag.
|
|
58
|
+
expect(fns.auth.skipEsbuild).toBe(true);
|
|
59
|
+
expect(fns.auth.environment.NODE_OPTIONS).toBe(IMPORT_FRAGMENT);
|
|
60
|
+
expect(fns.hubspot.environment.NODE_OPTIONS).toBe(IMPORT_FRAGMENT);
|
|
61
|
+
|
|
62
|
+
// defaultWebsocket is esbuild-bundled (no skipEsbuild) → MUST NOT get it.
|
|
63
|
+
expect(fns.defaultWebsocket.skipEsbuild).toBeFalsy();
|
|
64
|
+
expect(fns.defaultWebsocket.environment?.NODE_OPTIONS).toBeUndefined();
|
|
65
|
+
|
|
66
|
+
// Never global.
|
|
67
|
+
expect(definition.provider.environment.NODE_OPTIONS).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('sets no NODE_OPTIONS anywhere when offload is inactive', async () => {
|
|
71
|
+
const definition = await composeServerlessDefinition(
|
|
72
|
+
buildApp({ ssm: { enable: true } }) // enabled, but no 'ssm' keys
|
|
73
|
+
);
|
|
74
|
+
for (const fn of Object.values(definition.functions)) {
|
|
75
|
+
expect(fn.environment?.NODE_OPTIONS).toBeUndefined();
|
|
76
|
+
}
|
|
77
|
+
expect(definition.provider.environment.NODE_OPTIONS).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -123,6 +123,10 @@ class VpcDiscovery {
|
|
|
123
123
|
const sqsEndpoint = rawResources.vpcEndpoints.find(
|
|
124
124
|
ep => ep.ServiceName && ep.ServiceName.includes('.sqs')
|
|
125
125
|
);
|
|
126
|
+
// endsWith avoids matching sibling services like `.ssmmessages`
|
|
127
|
+
const ssmEndpoint = rawResources.vpcEndpoints.find(
|
|
128
|
+
ep => ep.ServiceName && ep.ServiceName.endsWith('.ssm')
|
|
129
|
+
);
|
|
126
130
|
|
|
127
131
|
if (s3Endpoint) {
|
|
128
132
|
result.s3VpcEndpointId = s3Endpoint.VpcEndpointId;
|
|
@@ -139,6 +143,9 @@ class VpcDiscovery {
|
|
|
139
143
|
if (sqsEndpoint) {
|
|
140
144
|
result.sqsVpcEndpointId = sqsEndpoint.VpcEndpointId;
|
|
141
145
|
}
|
|
146
|
+
if (ssmEndpoint) {
|
|
147
|
+
result.ssmVpcEndpointId = ssmEndpoint.VpcEndpointId;
|
|
148
|
+
}
|
|
142
149
|
}
|
|
143
150
|
|
|
144
151
|
console.log(` ✓ Found VPC: ${result.defaultVpcId}`);
|
|
@@ -151,8 +158,8 @@ class VpcDiscovery {
|
|
|
151
158
|
if (result.existingNatGatewayId) {
|
|
152
159
|
console.log(` ✓ Found NAT Gateway: ${result.existingNatGatewayId}`);
|
|
153
160
|
}
|
|
154
|
-
if (result.s3VpcEndpointId || result.dynamodbVpcEndpointId || result.kmsVpcEndpointId || result.secretsManagerVpcEndpointId || result.sqsVpcEndpointId) {
|
|
155
|
-
console.log(` ✓ Found VPC Endpoints: S3=${result.s3VpcEndpointId ? 'Yes' : 'No'}, DynamoDB=${result.dynamodbVpcEndpointId ? 'Yes' : 'No'}, KMS=${result.kmsVpcEndpointId ? 'Yes' : 'No'}, SecretsManager=${result.secretsManagerVpcEndpointId ? 'Yes' : 'No'}, SQS=${result.sqsVpcEndpointId ? 'Yes' : 'No'}`);
|
|
161
|
+
if (result.s3VpcEndpointId || result.dynamodbVpcEndpointId || result.kmsVpcEndpointId || result.secretsManagerVpcEndpointId || result.sqsVpcEndpointId || result.ssmVpcEndpointId) {
|
|
162
|
+
console.log(` ✓ Found VPC Endpoints: S3=${result.s3VpcEndpointId ? 'Yes' : 'No'}, DynamoDB=${result.dynamodbVpcEndpointId ? 'Yes' : 'No'}, KMS=${result.kmsVpcEndpointId ? 'Yes' : 'No'}, SecretsManager=${result.secretsManagerVpcEndpointId ? 'Yes' : 'No'}, SQS=${result.sqsVpcEndpointId ? 'Yes' : 'No'}, SSM=${result.ssmVpcEndpointId ? 'Yes' : 'No'}`);
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
return result;
|
|
@@ -253,7 +253,7 @@ describe('VpcDiscovery', () => {
|
|
|
253
253
|
expect(mockProvider.discoverVpc).toHaveBeenCalledWith(config);
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
-
it('should discover all VPC endpoints (S3, DynamoDB, KMS, Secrets Manager)', async () => {
|
|
256
|
+
it('should discover all VPC endpoints (S3, DynamoDB, KMS, Secrets Manager, SQS, SSM)', async () => {
|
|
257
257
|
mockProvider.discoverVpc.mockResolvedValue({
|
|
258
258
|
vpcId: 'vpc-123',
|
|
259
259
|
vpcCidr: '10.0.0.0/16',
|
|
@@ -283,6 +283,22 @@ describe('VpcDiscovery', () => {
|
|
|
283
283
|
ServiceName: 'com.amazonaws.us-east-1.secretsmanager',
|
|
284
284
|
State: 'available',
|
|
285
285
|
},
|
|
286
|
+
{
|
|
287
|
+
VpcEndpointId: 'vpce-sqs-def',
|
|
288
|
+
ServiceName: 'com.amazonaws.us-east-1.sqs',
|
|
289
|
+
State: 'available',
|
|
290
|
+
},
|
|
291
|
+
// ssmmessages must NOT be mistaken for the ssm endpoint
|
|
292
|
+
{
|
|
293
|
+
VpcEndpointId: 'vpce-ssmmessages-000',
|
|
294
|
+
ServiceName: 'com.amazonaws.us-east-1.ssmmessages',
|
|
295
|
+
State: 'available',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
VpcEndpointId: 'vpce-ssm-ghi',
|
|
299
|
+
ServiceName: 'com.amazonaws.us-east-1.ssm',
|
|
300
|
+
State: 'available',
|
|
301
|
+
},
|
|
286
302
|
],
|
|
287
303
|
});
|
|
288
304
|
|
|
@@ -292,6 +308,8 @@ describe('VpcDiscovery', () => {
|
|
|
292
308
|
expect(result.dynamodbVpcEndpointId).toBe('vpce-ddb-456');
|
|
293
309
|
expect(result.kmsVpcEndpointId).toBe('vpce-kms-789');
|
|
294
310
|
expect(result.secretsManagerVpcEndpointId).toBe('vpce-sm-abc');
|
|
311
|
+
expect(result.sqsVpcEndpointId).toBe('vpce-sqs-def');
|
|
312
|
+
expect(result.ssmVpcEndpointId).toBe('vpce-ssm-ghi');
|
|
295
313
|
});
|
|
296
314
|
|
|
297
315
|
it('should handle partial VPC endpoint discovery', async () => {
|
|
@@ -16,6 +16,19 @@ const ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/;
|
|
|
16
16
|
const DEFAULT_PARAMETER_PREFIX =
|
|
17
17
|
'/frigg/${self:service}/${self:provider.stage}';
|
|
18
18
|
|
|
19
|
+
// INIT-phase preload shipped in @friggframework/core, present at this path in
|
|
20
|
+
// every skipEsbuild handler (which packages the full node_modules tree).
|
|
21
|
+
// LAMBDA_TASK_ROOT = /var/task.
|
|
22
|
+
const SSM_PRELOAD_PATH =
|
|
23
|
+
'/var/task/node_modules/@friggframework/core/core/ssm-preload.mjs';
|
|
24
|
+
|
|
25
|
+
// NODE_OPTIONS value that loads the INIT preload. Set ONLY on skipEsbuild
|
|
26
|
+
// functions (esbuild-bundled functions do not package the .mjs, and a missing
|
|
27
|
+
// --import target is a fatal Node startup error). No `${env:NODE_OPTIONS}`
|
|
28
|
+
// prefix: that source resolves the deploy host's shell at package time, which
|
|
29
|
+
// would leak an unrelated value into every Lambda.
|
|
30
|
+
const SSM_PRELOAD_NODE_OPTIONS = `--import file://${SSM_PRELOAD_PATH}`;
|
|
31
|
+
|
|
19
32
|
// Keys the framework itself sets (from discovered resources or the base
|
|
20
33
|
// template) or that the loader/bypass handlers depend on before SSM values
|
|
21
34
|
// are available. Never offloadable.
|
|
@@ -81,7 +94,7 @@ function getOffloadedKeys(appDefinition = {}) {
|
|
|
81
94
|
keys.add(key);
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
return [...keys].sort();
|
|
97
|
+
return [...keys].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
/**
|
|
@@ -172,4 +185,6 @@ module.exports = {
|
|
|
172
185
|
validateOffloadConfig,
|
|
173
186
|
FRAMEWORK_ENV_BLOCKLIST,
|
|
174
187
|
DEFAULT_PARAMETER_PREFIX,
|
|
188
|
+
SSM_PRELOAD_PATH,
|
|
189
|
+
SSM_PRELOAD_NODE_OPTIONS,
|
|
175
190
|
};
|
|
@@ -16,11 +16,6 @@ const {
|
|
|
16
16
|
validateOffloadConfig,
|
|
17
17
|
} = require('./offload-utils');
|
|
18
18
|
|
|
19
|
-
// INIT-phase preload shipped in @friggframework/core, packaged into every
|
|
20
|
-
// skipEsbuild handler at this stable path (LAMBDA_TASK_ROOT = /var/task).
|
|
21
|
-
const SSM_PRELOAD_PATH =
|
|
22
|
-
'/var/task/node_modules/@friggframework/core/core/ssm-preload.mjs';
|
|
23
|
-
|
|
24
19
|
class SsmBuilder extends InfrastructureBuilder {
|
|
25
20
|
constructor() {
|
|
26
21
|
super();
|
|
@@ -98,15 +93,12 @@ class SsmBuilder extends InfrastructureBuilder {
|
|
|
98
93
|
result.environment.SSM_PARAMETER_PREFIX = prefix;
|
|
99
94
|
result.environment.FRIGG_SSM_OFFLOADED_KEYS = offloadedKeys.join(',');
|
|
100
95
|
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// every skipEsbuild handler at a stable path). Appended to any
|
|
108
|
-
// app-provided NODE_OPTIONS.
|
|
109
|
-
result.environment.NODE_OPTIONS = `\${env:NODE_OPTIONS, ''} --import file://${SSM_PRELOAD_PATH}`;
|
|
96
|
+
// The INIT-phase preload (NODE_OPTIONS=--import) that populates
|
|
97
|
+
// process.env before app modules load is set per-function on
|
|
98
|
+
// skipEsbuild handlers only — see infrastructure-composer.js. It
|
|
99
|
+
// cannot go here (provider.environment is global) because a missing
|
|
100
|
+
// --import target fatally aborts Node startup, and esbuild-bundled
|
|
101
|
+
// functions do not package the preload file.
|
|
110
102
|
|
|
111
103
|
// Prefix-scoped read grant. Built as a plain serverless string (not
|
|
112
104
|
// Fn::Sub) because the prefix contains serverless variables like
|
|
@@ -234,7 +234,7 @@ describe('SsmBuilder', () => {
|
|
|
234
234
|
expect(result.environment.FRIGG_SSM_OFFLOADED_KEYS).toBe('BAR,FOO');
|
|
235
235
|
});
|
|
236
236
|
|
|
237
|
-
it('
|
|
237
|
+
it('does not set NODE_OPTIONS globally (the composer scopes it to skipEsbuild functions)', async () => {
|
|
238
238
|
const appDefinition = {
|
|
239
239
|
ssm: { enable: true },
|
|
240
240
|
environment: { FOO: 'ssm' },
|
|
@@ -242,18 +242,8 @@ describe('SsmBuilder', () => {
|
|
|
242
242
|
|
|
243
243
|
const result = await ssmBuilder.build(appDefinition, {});
|
|
244
244
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
'@friggframework/core/core/ssm-preload.mjs'
|
|
248
|
-
);
|
|
249
|
-
// Appends to any app-provided NODE_OPTIONS rather than clobbering it.
|
|
250
|
-
expect(result.environment.NODE_OPTIONS).toContain(
|
|
251
|
-
"${env:NODE_OPTIONS, ''}"
|
|
252
|
-
);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('does not set NODE_OPTIONS when no keys are offloaded', async () => {
|
|
256
|
-
const result = await ssmBuilder.build({ ssm: { enable: true } }, {});
|
|
245
|
+
// NODE_OPTIONS=--import would fatally abort esbuild-bundled functions
|
|
246
|
+
// that lack the preload file, so it must never be provider-global.
|
|
257
247
|
expect(result.environment.NODE_OPTIONS).toBeUndefined();
|
|
258
248
|
});
|
|
259
249
|
|
|
@@ -703,7 +703,10 @@ function generateIAMCloudFormation(options = {}) {
|
|
|
703
703
|
},
|
|
704
704
|
],
|
|
705
705
|
Condition: {
|
|
706
|
-
|
|
706
|
+
// StringLike: kms:ViaService is regional
|
|
707
|
+
// (ssm.us-east-1.amazonaws.com), so the wildcard
|
|
708
|
+
// must be matched, not compared literally.
|
|
709
|
+
StringLike: {
|
|
707
710
|
'kms:ViaService': [
|
|
708
711
|
'ssm.*.amazonaws.com',
|
|
709
712
|
],
|
|
@@ -166,6 +166,16 @@ describe('IAM Generator', () => {
|
|
|
166
166
|
expect(yaml).toContain('ssm.*.amazonaws.com');
|
|
167
167
|
// No customer-managed key configured: falls back to the account key wildcard
|
|
168
168
|
expect(yaml).toContain('arn:aws:kms:*:${AWS::AccountId}:key/*');
|
|
169
|
+
|
|
170
|
+
// The regional ViaService wildcard must be matched with StringLike;
|
|
171
|
+
// StringEquals would compare literally and never match
|
|
172
|
+
// ssm.<region>.amazonaws.com, denying the SecureString KMS call.
|
|
173
|
+
const ssmKmsBlock = yaml.slice(
|
|
174
|
+
yaml.indexOf('FriggSSMParameterKMSEncryption'),
|
|
175
|
+
yaml.indexOf('FriggSSMParameterKMSEncryption') + 600
|
|
176
|
+
);
|
|
177
|
+
expect(ssmKmsBlock).toContain('StringLike');
|
|
178
|
+
expect(ssmKmsBlock).not.toContain('StringEquals');
|
|
169
179
|
});
|
|
170
180
|
|
|
171
181
|
it('should scope the SSM KMS grant to ssm.kmsKeyArn when provided', () => {
|
|
@@ -375,7 +375,9 @@ Resources:
|
|
|
375
375
|
Resource:
|
|
376
376
|
- !Sub 'arn:aws:kms:*:${AWS::AccountId}:key/*'
|
|
377
377
|
Condition:
|
|
378
|
-
|
|
378
|
+
# StringLike: kms:ViaService is regional (ssm.us-east-1.amazonaws.com),
|
|
379
|
+
# so the wildcard must be matched, not compared literally.
|
|
380
|
+
StringLike:
|
|
379
381
|
'kms:ViaService':
|
|
380
382
|
- 'ssm.*.amazonaws.com'
|
|
381
383
|
|
|
@@ -21,6 +21,30 @@ const { AdminScriptBuilder } = require('./domains/admin-scripts/admin-script-bui
|
|
|
21
21
|
|
|
22
22
|
// Utilities
|
|
23
23
|
const { applyFunctionEnvironments } = require('./domains/shared/function-environments');
|
|
24
|
+
const {
|
|
25
|
+
isSsmOffloadActive,
|
|
26
|
+
SSM_PRELOAD_NODE_OPTIONS,
|
|
27
|
+
} = require('./domains/parameters/offload-utils');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Load the SSM INIT preload (NODE_OPTIONS=--import) on skipEsbuild handlers
|
|
31
|
+
* only. Those package the full node_modules tree, so the preload .mjs is
|
|
32
|
+
* present at /var/task. esbuild-bundled functions (e.g. defaultWebsocket,
|
|
33
|
+
* adopter custom functions) do NOT ship it — and a missing --import target is a
|
|
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).
|
|
36
|
+
*/
|
|
37
|
+
function applySsmPreloadNodeOptions(appDefinition, functions) {
|
|
38
|
+
if (!isSsmOffloadActive(appDefinition)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
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;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
24
48
|
const { modifyHandlerPaths } = require('./domains/shared/utilities/handler-path-resolver');
|
|
25
49
|
const { createBaseDefinition } = require('./domains/shared/utilities/base-definition-factory');
|
|
26
50
|
const { ensurePrismaLayerExists } = require('./domains/shared/utilities/prisma-layer-manager');
|
|
@@ -80,6 +104,7 @@ const composeServerlessDefinition = async (AppDefinition) => {
|
|
|
80
104
|
definition.functions,
|
|
81
105
|
merged.functionEnvironments
|
|
82
106
|
);
|
|
107
|
+
applySsmPreloadNodeOptions(AppDefinition, definition.functions);
|
|
83
108
|
|
|
84
109
|
if (merged.vpcConfig) {
|
|
85
110
|
definition.provider.vpc = merged.vpcConfig;
|
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.
|
|
4
|
+
"version": "2.0.0--canary.625.0de0db4.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.
|
|
30
|
-
"@friggframework/schemas": "2.0.0--canary.625.
|
|
31
|
-
"@friggframework/test": "2.0.0--canary.625.
|
|
29
|
+
"@friggframework/core": "2.0.0--canary.625.0de0db4.0",
|
|
30
|
+
"@friggframework/schemas": "2.0.0--canary.625.0de0db4.0",
|
|
31
|
+
"@friggframework/test": "2.0.0--canary.625.0de0db4.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.
|
|
60
|
-
"@friggframework/prettier-config": "2.0.0--canary.625.
|
|
59
|
+
"@friggframework/eslint-config": "2.0.0--canary.625.0de0db4.0",
|
|
60
|
+
"@friggframework/prettier-config": "2.0.0--canary.625.0de0db4.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": "
|
|
92
|
+
"gitHead": "0de0db43a6403eb99de205e24fcde7e9761ba4f6"
|
|
93
93
|
}
|