@mbc-cqrs-serverless/cli 1.2.7-beta.0 → 1.3.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbc-cqrs-serverless/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "a CLI to get started with MBC CQRS serverless framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mbc",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"@faker-js/faker": "^8.3.1",
|
|
59
59
|
"copyfiles": "^2.4.1"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "3e6f1b6d57bf38433d5f63dfb9f5e03a4c9bb25d"
|
|
62
62
|
}
|
|
@@ -10,8 +10,33 @@ export type Config = {
|
|
|
10
10
|
domain: {
|
|
11
11
|
http: string
|
|
12
12
|
appsync: string
|
|
13
|
+
appsyncEvents?: string // optional: custom domain for AppSync Events API
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
appsyncEvents?: {
|
|
17
|
+
/** Set true to create the AppSync Events API and inject env vars into Lambda/ECS */
|
|
18
|
+
enabled: boolean
|
|
19
|
+
/**
|
|
20
|
+
* Channel namespace name — must be a pre-registered name in the AppSync Event API.
|
|
21
|
+
* Becomes segment 1 of every channel path: /{namespace}/{tenantCode}/{table}/{action}/{id}
|
|
22
|
+
* Defaults to 'default'.
|
|
23
|
+
*/
|
|
24
|
+
namespace: string
|
|
25
|
+
/** API key TTL in days. Defaults to 365. */
|
|
26
|
+
apiKeyExpireDays?: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Value injected as NOTIFICATION_TRANSPORTS env var into Lambda/ECS.
|
|
31
|
+
* Controls which transports NotificationEventHandler uses.
|
|
32
|
+
* Examples:
|
|
33
|
+
* 'appsync-event' — Events API only
|
|
34
|
+
* 'appsync-graphql' — GraphQL API only
|
|
35
|
+
* 'appsync-graphql,appsync-event' — dual-publish (migration mode)
|
|
36
|
+
* Defaults to 'appsync-event' when appsyncEvents is enabled.
|
|
37
|
+
*/
|
|
38
|
+
notificationTransports?: string
|
|
39
|
+
|
|
15
40
|
// existing resources
|
|
16
41
|
userPoolId?: string
|
|
17
42
|
|
|
@@ -249,6 +249,76 @@ export class InfraStack extends cdk.Stack {
|
|
|
249
249
|
this.graphqlApiKey = new cdk.CfnOutput(this, 'GraphQLAPIKey', {
|
|
250
250
|
value: appSyncApi.apiKey || '',
|
|
251
251
|
})
|
|
252
|
+
|
|
253
|
+
// AppSync Events API (HTTP pub/sub, schema-free)
|
|
254
|
+
// Uses L2 EventApi so that ChannelNamespace can set explicit publishAuthModeTypes
|
|
255
|
+
// and subscribeAuthModeTypes — without these the namespace has no effective
|
|
256
|
+
// authorization and Lambda publish calls receive 401.
|
|
257
|
+
let appSyncEventsApi: cdk.aws_appsync.EventApi | undefined
|
|
258
|
+
if (props.config.appsyncEvents?.enabled) {
|
|
259
|
+
const expireDays = props.config.appsyncEvents.apiKeyExpireDays ?? 365
|
|
260
|
+
|
|
261
|
+
appSyncEventsApi = new cdk.aws_appsync.EventApi(this, 'events-api', {
|
|
262
|
+
apiName: prefix + 'events',
|
|
263
|
+
authorizationConfig: {
|
|
264
|
+
authProviders: [
|
|
265
|
+
{
|
|
266
|
+
authorizationType: cdk.aws_appsync.AppSyncAuthorizationType.IAM,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
authorizationType:
|
|
270
|
+
cdk.aws_appsync.AppSyncAuthorizationType.API_KEY,
|
|
271
|
+
apiKeyConfig: {
|
|
272
|
+
expires: cdk.Expiration.after(cdk.Duration.days(expireDays)),
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
// API-level defaults — overridden per-namespace below
|
|
277
|
+
connectionAuthModeTypes: [
|
|
278
|
+
cdk.aws_appsync.AppSyncAuthorizationType.API_KEY,
|
|
279
|
+
],
|
|
280
|
+
defaultPublishAuthModeTypes: [
|
|
281
|
+
cdk.aws_appsync.AppSyncAuthorizationType.IAM,
|
|
282
|
+
],
|
|
283
|
+
defaultSubscribeAuthModeTypes: [
|
|
284
|
+
cdk.aws_appsync.AppSyncAuthorizationType.API_KEY,
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
// Namespace — explicitly sets auth per operation so it is never left
|
|
290
|
+
// without authorization (which caused the 401).
|
|
291
|
+
// publish = AWS_IAM → Lambda signs with its execution role
|
|
292
|
+
// subscribe = API_KEY → browser clients pass x-api-key header
|
|
293
|
+
new cdk.aws_appsync.ChannelNamespace(this, 'events-namespace', {
|
|
294
|
+
api: appSyncEventsApi,
|
|
295
|
+
channelNamespaceName: props.config.appsyncEvents.namespace ?? 'default',
|
|
296
|
+
authorizationConfig: {
|
|
297
|
+
publishAuthModeTypes: [cdk.aws_appsync.AppSyncAuthorizationType.IAM],
|
|
298
|
+
subscribeAuthModeTypes: [
|
|
299
|
+
cdk.aws_appsync.AppSyncAuthorizationType.API_KEY,
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
// Outputs
|
|
305
|
+
new cdk.CfnOutput(this, 'AppSyncEventsHttpEndpoint', {
|
|
306
|
+
value: `https://${appSyncEventsApi.httpDns}/event`,
|
|
307
|
+
description:
|
|
308
|
+
'AppSync Events HTTP endpoint — APPSYNC_EVENTS_ENDPOINT env var',
|
|
309
|
+
})
|
|
310
|
+
new cdk.CfnOutput(this, 'AppSyncEventsRealtimeEndpoint', {
|
|
311
|
+
value: `wss://${appSyncEventsApi.realtimeDns}/event/realtime`,
|
|
312
|
+
description:
|
|
313
|
+
'AppSync Events WebSocket endpoint for client subscriptions',
|
|
314
|
+
})
|
|
315
|
+
new cdk.CfnOutput(this, 'AppSyncEventsNamespace', {
|
|
316
|
+
value: props.config.appsyncEvents.namespace ?? 'default',
|
|
317
|
+
description:
|
|
318
|
+
'AppSync Events namespace — APPSYNC_EVENTS_NAMESPACE env var',
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
|
|
252
322
|
// S3
|
|
253
323
|
const ddbBucket = new cdk.aws_s3.Bucket(this, 'ddb-attributes', {
|
|
254
324
|
bucketName: prefix + 'ddb-attributes', // Globally unique bucket name
|
|
@@ -398,6 +468,16 @@ export class InfraStack extends cdk.Stack {
|
|
|
398
468
|
SNS_ALARM_TOPIC_ARN: alarmSns.topicArn,
|
|
399
469
|
COGNITO_USER_POOL_ID: userPool.userPoolId,
|
|
400
470
|
APPSYNC_ENDPOINT: appSyncApi.graphqlUrl,
|
|
471
|
+
// AppSync Events — only injected when feature is enabled
|
|
472
|
+
...(props.config.appsyncEvents?.enabled && appSyncEventsApi
|
|
473
|
+
? {
|
|
474
|
+
NOTIFICATION_TRANSPORTS:
|
|
475
|
+
props.config.notificationTransports ?? 'appsync-event',
|
|
476
|
+
APPSYNC_EVENTS_ENDPOINT: `https://${appSyncEventsApi.httpDns}/event`,
|
|
477
|
+
APPSYNC_EVENTS_NAMESPACE:
|
|
478
|
+
props.config.appsyncEvents.namespace ?? 'default',
|
|
479
|
+
}
|
|
480
|
+
: {}),
|
|
401
481
|
SES_FROM_EMAIL: props.config.fromEmailAddress,
|
|
402
482
|
DATABASE_URL: `postgresql://${props.config.rds.accountSsmKey}@${props.config.rds.endpoint}/${props.config.rds.dbName}?schema=public`,
|
|
403
483
|
S3_PUBLIC_BUCKET_NAME: publicBucket.bucketName,
|
|
@@ -645,6 +725,14 @@ export class InfraStack extends cdk.Stack {
|
|
|
645
725
|
domainName: httpDistribution.distributionDomainName,
|
|
646
726
|
})
|
|
647
727
|
|
|
728
|
+
if (props.config.domain.appsyncEvents && appSyncEventsApi) {
|
|
729
|
+
new cdk.aws_route53.CnameRecord(this, 'AppSyncEventsCnameRecord', {
|
|
730
|
+
zone: hostedZone,
|
|
731
|
+
recordName: props.config.domain.appsyncEvents,
|
|
732
|
+
domainName: appSyncEventsApi.httpDns,
|
|
733
|
+
})
|
|
734
|
+
}
|
|
735
|
+
|
|
648
736
|
this.httpDistributionDomain = new cdk.CfnOutput(
|
|
649
737
|
this,
|
|
650
738
|
'http-distribution-domain',
|
|
@@ -1100,6 +1188,8 @@ export class InfraStack extends cdk.Stack {
|
|
|
1100
1188
|
appSyncApi.grantMutation(lambdaApi)
|
|
1101
1189
|
importActionSqs.grantSendMessages(lambdaApi)
|
|
1102
1190
|
|
|
1191
|
+
appSyncEventsApi?.grantPublish(lambdaApi)
|
|
1192
|
+
|
|
1103
1193
|
// Define an IAM policy for full DynamoDB access
|
|
1104
1194
|
const dynamoDbTablePrefixArn = cdk.Arn.format({
|
|
1105
1195
|
partition: 'aws',
|
|
@@ -1231,6 +1321,7 @@ export class InfraStack extends cdk.Stack {
|
|
|
1231
1321
|
statements: [ssmPolicy],
|
|
1232
1322
|
}),
|
|
1233
1323
|
)
|
|
1324
|
+
appSyncEventsApi?.grantPublish(taskRole)
|
|
1234
1325
|
}
|
|
1235
1326
|
}
|
|
1236
1327
|
}
|