From 6f284ead65cf4a09944b3a0b0fbd81a4ef4c5d01 Mon Sep 17 00:00:00 2001
From: Addie Rudy
Date: Tue, 28 May 2024 09:14:00 -0400
Subject: [PATCH] style(formatting): cleaned code formatting using prettier
Commit changes code style only, no logic or functionality changed
re: #55
---
cli/config-manage.ts | 70 +-
cli/config.ts | 8 +-
lib/api/functions/bundle.ts | 47 +-
.../pipeline/createDataFeed/index.ts | 7 +-
.../pipeline/createNewsletter/index.ts | 7 +-
.../filterListByAuthorization/index.ts | 19 +-
.../functions/pipeline/getDataFeed/index.ts | 5 +-
.../functions/pipeline/getNewsletter/index.ts | 9 +-
.../pipeline/getPublication/index.ts | 8 +-
.../functions/pipeline/isAuthorized/index.ts | 11 +-
.../pipeline/listDataFeedsById/index.ts | 4 +-
.../listDataFeedsDiscoverable/index.ts | 11 +-
.../pipeline/listDataFeedsOwned/index.ts | 11 +-
.../pipeline/listDataFeedsShared/index.ts | 11 +-
.../pipeline/listNewslettersById/index.ts | 21 +-
.../listNewslettersDiscoverable/index.ts | 11 +-
.../pipeline/listNewslettersOwned/index.ts | 11 +-
.../pipeline/listNewslettersShared/index.ts | 11 +-
.../pipeline/listUserSubscriptions/index.ts | 6 +-
.../pipeline/subscribeToNewsletter/index.ts | 7 +-
.../unsubscribeFromNewsletter/index.ts | 7 +-
.../pipeline/updateDataFeed/index.ts | 18 +-
.../pipeline/updateNewsletter/index.ts | 6 +-
lib/api/functions/resolver-helper.ts | 46 +-
.../resolver/createNewsletter/index.ts | 7 +-
.../index.ts | 5 +-
.../functions/resolver/listDataFeeds/index.ts | 7 +-
.../resolver/listNewsletters/index.ts | 7 +-
.../unsubscribeFromNewsletter/index.ts | 7 +-
lib/api/resolvers.ts | 643 +++++++++++-------
.../index.pre-token-generation-hook.ts | 39 +-
lib/authentication/index.ts | 152 +++--
lib/authorization/authorization-helper.ts | 53 +-
.../index.action-authorization.ts | 65 +-
.../index.list-filter-authorization.ts | 69 +-
lib/authorization/index.read-authorization.ts | 47 +-
lib/authorization/index.ts | 193 +++---
lib/cdk-nag-supressions.ts | 39 +-
lib/config.ts | 8 +-
lib/data-feed-ingestion/index.ts | 19 +-
lib/data-feed-ingestion/prompts.ts | 2 +-
...-feed-poll-step-function.get-data-feeds.ts | 3 +-
.../data-feed-poll-step-function.ts | 50 +-
.../index.feed-subscriber.ts | 11 +-
.../rss-atom-ingestion/index.ts | 28 +-
...ngestion-step-function.article-ingestor.ts | 12 +-
.../ingestion-step-function.feed-reader.ts | 4 +-
...-step-function.filter-ingested-articles.ts | 4 +-
.../ingestion-step-function.ts | 11 +-
lib/index.ts | 19 +-
.../index.email-generator.ts | 14 +-
.../index.get-newsletter.ts | 10 +-
.../index.newsletter-campaign-creator.ts | 11 +-
.../index.newsletter-creator.ts | 16 +-
lib/newsletter-generator/index.ts | 70 +-
.../index.user-subscriber.ts | 12 +-
lib/newsletter-generator/pinpoint-app.ts | 15 +-
.../api/schema-to-avp/codegen-auth-plugin.ts | 175 +++--
lib/shared/api/schema-to-avp/codegen.ts | 5 +-
lib/shared/api/types.ts | 1 -
lib/shared/common/newsletter-style.ts | 2 +-
lib/shared/common/types.ts | 5 +-
.../emails-preview/newsletter.tsx | 2 +-
.../email-generator/emails/newsletter.tsx | 91 ++-
.../email-generator/newsletter-json-data.ts | 12 +-
.../prompts/newsletter-summary-prompt.ts | 5 +-
lib/shared/prompts/prompt-handler.ts | 6 +-
lib/shared/prompts/prompt-processing.ts | 2 +-
.../genai-newsletter-ui/src/app.tsx | 10 +-
.../common/helpers/graphql-client-helper.ts | 22 +-
.../src/common/helpers/index.ts | 2 +-
.../genai-newsletter-ui/src/common/types.ts | 20 +-
.../src/components/app-configured.tsx | 33 +-
.../components/auth/custom-authenticator.tsx | 24 +-
.../src/components/base-content-layout.tsx | 6 +-
.../components/data-feeds/article-table.tsx | 8 +-
.../data-feeds/data-feed-detail.tsx | 40 +-
.../data-feeds/data-feeds-table.tsx | 22 +-
.../forms/data-feed-details-form.tsx | 46 +-
.../src/components/global-header.tsx | 16 +-
.../components/newsletters/definitions.tsx | 5 +-
.../forms/data-feeds-selection-table.tsx | 28 +-
.../newsletters/forms/newsletter-details.tsx | 7 +-
.../newsletters/forms/newsletter-review.tsx | 44 +-
.../newsletters/forms/newsletter-wizard.tsx | 69 +-
.../src/components/newsletters/newsletter.tsx | 111 +--
.../newsletters/newsletters-table.tsx | 98 ++-
.../src/components/newsletters/preview.tsx | 5 +-
.../newsletters/publications-table.tsx | 33 +-
.../newsletters/user-subscriber-data.tsx | 19 +-
.../genai-newsletter-ui/src/main.tsx | 4 +-
.../src/pages/data-feeds/dashboard.tsx | 11 +-
.../src/pages/newsletters/create.tsx | 1 -
.../src/pages/newsletters/dashboard.tsx | 10 +-
.../src/pages/newsletters/detail.tsx | 61 +-
.../src/pages/newsletters/my-newsletters.tsx | 11 +-
.../pages/newsletters/my-subscriptions.tsx | 11 +-
.../genai-newsletter-ui/src/pages/welcome.tsx | 203 +++++-
.../genai-newsletter-ui/unsubscribe/main.tsx | 4 -
.../unsubscribe/unsubscribe-app.tsx | 211 +++---
.../genai-newsletter-ui/vite.config.ts | 10 +-
lib/user-interface/index.ts | 92 ++-
102 files changed, 2292 insertions(+), 1335 deletions(-)
diff --git a/cli/config-manage.ts b/cli/config-manage.ts
index 2129b9d..1584d6d 100644
--- a/cli/config-manage.ts
+++ b/cli/config-manage.ts
@@ -15,7 +15,12 @@ if (fs.existsSync(deployConfig)) {
const configFromFile: DeployConfig = JSON.parse(
fs.readFileSync(deployConfig, 'utf8')
)
- console.log(formatText('A configuration already exists.', { bold: true, backgroundColor: 'bg-yellow' }))
+ console.log(
+ formatText('A configuration already exists.', {
+ bold: true,
+ backgroundColor: 'bg-yellow'
+ })
+ )
let existingConfigChoice: string | null = null
let readyToProceed = false
while (!readyToProceed) {
@@ -289,16 +294,30 @@ if (['UPDATE', 'NEW'].includes(configStyle)) {
* Does the user want to configure a Host Name & ACM Cert for the Frontend Cloudfront
*/
let configHostname = false
- if (config.ui?.acmCertificateArn === undefined || config.ui.hostName === undefined) {
- console.log(formatText('Do you want to configure a custom hostname for the frontend?',
- { textColor: 'blue' }))
- console.log(formatText('Requires a hostname & a pre-existing AWS Certificate Manager public cert ARN.' +
- 'For more information, visit https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html',
- { italic: true }))
+ if (
+ config.ui?.acmCertificateArn === undefined ||
+ config.ui.hostName === undefined
+ ) {
+ console.log(
+ formatText(
+ 'Do you want to configure a custom hostname for the frontend?',
+ { textColor: 'blue' }
+ )
+ )
+ console.log(
+ formatText(
+ 'Requires a hostname & a pre-existing AWS Certificate Manager public cert ARN.' +
+ 'For more information, visit https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request-public.html',
+ { italic: true }
+ )
+ )
let loopA = true
while (loopA) {
const response = prompter(
- formatText('Do you want to proceed? (y/N):', { bold: true, textColor: 'blue' }),
+ formatText('Do you want to proceed? (y/N):', {
+ bold: true,
+ textColor: 'blue'
+ }),
'N'
)
if (response.toLowerCase() === 'y') {
@@ -321,11 +340,16 @@ if (['UPDATE', 'NEW'].includes(configStyle)) {
if (configHostname) {
let loopB = true
while (loopB) {
- const existingHostname = ((config.ui?.hostName) != null) ? config.ui.hostName : ''
+ const existingHostname =
+ config.ui?.hostName != null ? config.ui.hostName : ''
const response = prompter(
- formatText(`Enter the hostname you want to use for the frontend:(${existingHostname})`, { textColor: 'blue' })
+ formatText(
+ `Enter the hostname you want to use for the frontend:(${existingHostname})`,
+ { textColor: 'blue' }
+ )
)
- const hostnameRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
+ const hostnameRegex =
+ /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/
if (response.length > 0 && hostnameRegex.test(response)) {
if (config.ui === undefined) {
config.ui = {}
@@ -333,7 +357,11 @@ if (['UPDATE', 'NEW'].includes(configStyle)) {
config.ui.hostName = response
loopB = false
break
- } else if (response.length < 1 && config.ui?.hostName !== undefined && config.ui.hostName !== null) {
+ } else if (
+ response.length < 1 &&
+ config.ui?.hostName !== undefined &&
+ config.ui.hostName !== null
+ ) {
loopB = false
break
} else {
@@ -348,9 +376,15 @@ if (['UPDATE', 'NEW'].includes(configStyle)) {
}
let loopC = true
while (loopC) {
- const existingAcmCert = ((config.ui?.acmCertificateArn) != null) ? config.ui.acmCertificateArn : ''
+ const existingAcmCert =
+ config.ui?.acmCertificateArn != null
+ ? config.ui.acmCertificateArn
+ : ''
const response = prompter(
- formatText(`Enter the ACM Certificate ARN you want to use for the frontend:(${existingAcmCert})`, { textColor: 'blue' })
+ formatText(
+ `Enter the ACM Certificate ARN you want to use for the frontend:(${existingAcmCert})`,
+ { textColor: 'blue' }
+ )
)
const acmCertRegex = /^arn:aws:acm:\S+:\d+:\w+\/\S+$/
if (response.length > 0 && acmCertRegex.test(response)) {
@@ -360,8 +394,12 @@ if (['UPDATE', 'NEW'].includes(configStyle)) {
config.ui.acmCertificateArn = response
loopC = false
break
- } else if (response.length < 1 && config.ui?.acmCertificateArn !== undefined && config.ui.acmCertificateArn !== null) {
- loopC = false;
+ } else if (
+ response.length < 1 &&
+ config.ui?.acmCertificateArn !== undefined &&
+ config.ui.acmCertificateArn !== null
+ ) {
+ loopC = false
break
} else {
console.log(
diff --git a/cli/config.ts b/cli/config.ts
index 7c572a0..5f8e953 100644
--- a/cli/config.ts
+++ b/cli/config.ts
@@ -4,9 +4,11 @@ import figlet from 'figlet'
const program = new Command()
-console.log(figlet.textSync('GenAI Newsletter', {
- font: 'Slant'
-}))
+console.log(
+ figlet.textSync('GenAI Newsletter', {
+ font: 'Slant'
+ })
+)
program
.name('npm run config')
diff --git a/lib/api/functions/bundle.ts b/lib/api/functions/bundle.ts
index 6baff3f..72fdc67 100644
--- a/lib/api/functions/bundle.ts
+++ b/lib/api/functions/bundle.ts
@@ -16,26 +16,29 @@ import path from 'path'
const outDir = path.join(__dirname, 'out')
-const resolverFunctions = fs.readdirSync(path.join(__dirname, 'resolver')).map((functionName) => {
- return path.join(__dirname, 'resolver', functionName, 'index.ts')
-})
-const pipelineFunctions = fs.readdirSync(path.join(__dirname, 'pipeline')).map((functionName) => {
- return path.join(__dirname, 'pipeline', functionName, 'index.ts')
-})
+const resolverFunctions = fs
+ .readdirSync(path.join(__dirname, 'resolver'))
+ .map((functionName) => {
+ return path.join(__dirname, 'resolver', functionName, 'index.ts')
+ })
+const pipelineFunctions = fs
+ .readdirSync(path.join(__dirname, 'pipeline'))
+ .map((functionName) => {
+ return path.join(__dirname, 'pipeline', functionName, 'index.ts')
+ })
-esbuild.build({
- bundle: true,
- entryPoints: [
- ...resolverFunctions,
- ...pipelineFunctions
- ],
- outdir: outDir,
- sourcemap: 'inline',
- sourcesContent: false,
- external: ['@aws-appsync/utils'],
- platform: 'node',
- target: 'esnext',
- format: 'esm',
- minify: false,
- logLevel: 'info'
-}).catch(() => process.exit(1))
+esbuild
+ .build({
+ bundle: true,
+ entryPoints: [...resolverFunctions, ...pipelineFunctions],
+ outdir: outDir,
+ sourcemap: 'inline',
+ sourcesContent: false,
+ external: ['@aws-appsync/utils'],
+ platform: 'node',
+ target: 'esnext',
+ format: 'esm',
+ minify: false,
+ logLevel: 'info'
+ })
+ .catch(() => process.exit(1))
diff --git a/lib/api/functions/pipeline/createDataFeed/index.ts b/lib/api/functions/pipeline/createDataFeed/index.ts
index f3b7e45..fd52d44 100644
--- a/lib/api/functions/pipeline/createDataFeed/index.ts
+++ b/lib/api/functions/pipeline/createDataFeed/index.ts
@@ -1,4 +1,9 @@
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
const { args } = ctx
diff --git a/lib/api/functions/pipeline/createNewsletter/index.ts b/lib/api/functions/pipeline/createNewsletter/index.ts
index dd53352..6d21a61 100644
--- a/lib/api/functions/pipeline/createNewsletter/index.ts
+++ b/lib/api/functions/pipeline/createNewsletter/index.ts
@@ -1,4 +1,9 @@
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
const { args } = ctx
diff --git a/lib/api/functions/pipeline/filterListByAuthorization/index.ts b/lib/api/functions/pipeline/filterListByAuthorization/index.ts
index 30c5439..955045f 100644
--- a/lib/api/functions/pipeline/filterListByAuthorization/index.ts
+++ b/lib/api/functions/pipeline/filterListByAuthorization/index.ts
@@ -4,11 +4,18 @@
* SPDX-License-Identifier: MIT-0
*/
-import { type LambdaRequest, util, type Context, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type LambdaRequest,
+ util,
+ type Context,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
import { convertAvpObjectsToGraphql } from '../../resolver-helper'
export function request (ctx: Context): LambdaRequest {
- console.log(`[Filter List by Authorization Request] request ctx ${JSON.stringify(ctx)}`)
+ console.log(
+ `[Filter List by Authorization Request] request ctx ${JSON.stringify(ctx)}`
+ )
const { source, args } = ctx
const identity = ctx.identity as AppSyncIdentityLambda
return {
@@ -16,7 +23,9 @@ export function request (ctx: Context): LambdaRequest {
payload: {
userId: identity.resolverContext.userId,
accountId: identity.resolverContext.accountId,
- requestContext: JSON.parse(identity.resolverContext.requestContext as string),
+ requestContext: JSON.parse(
+ identity.resolverContext.requestContext as string
+ ),
result: ctx.prev.result,
arguments: args,
source
@@ -33,7 +42,9 @@ export function response (ctx: Context): any {
if (result.isAuthorized !== true) {
util.unauthorized()
}
- console.log('[IsAuthorized] response result $', { result: JSON.stringify(result) })
+ console.log('[IsAuthorized] response result $', {
+ result: JSON.stringify(result)
+ })
return {
isAuthorized: true,
items: convertAvpObjectsToGraphql(result)
diff --git a/lib/api/functions/pipeline/getDataFeed/index.ts b/lib/api/functions/pipeline/getDataFeed/index.ts
index 952ff79..e529ea2 100644
--- a/lib/api/functions/pipeline/getDataFeed/index.ts
+++ b/lib/api/functions/pipeline/getDataFeed/index.ts
@@ -1,6 +1,9 @@
import { type DynamoDBGetItemRequest, type Context } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItem, convertFieldIdToObjectId } from '../../resolver-helper'
+import {
+ addAccountToItem,
+ convertFieldIdToObjectId
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBGetItemRequest {
const { id } = ctx.args.input
diff --git a/lib/api/functions/pipeline/getNewsletter/index.ts b/lib/api/functions/pipeline/getNewsletter/index.ts
index d66bff2..93e3974 100644
--- a/lib/api/functions/pipeline/getNewsletter/index.ts
+++ b/lib/api/functions/pipeline/getNewsletter/index.ts
@@ -4,11 +4,12 @@ import {
type DynamoDBGetItemRequest
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItem, convertFieldIdToObjectId } from '../../resolver-helper'
+import {
+ addAccountToItem,
+ convertFieldIdToObjectId
+} from '../../resolver-helper'
-export function request (
- ctx: Context
-): DynamoDBGetItemRequest {
+export function request (ctx: Context): DynamoDBGetItemRequest {
console.log('getNewsletter request', { ctx })
const { id } = ctx.args.input
return ddb.get({
diff --git a/lib/api/functions/pipeline/getPublication/index.ts b/lib/api/functions/pipeline/getPublication/index.ts
index 6544f9c..552ac79 100644
--- a/lib/api/functions/pipeline/getPublication/index.ts
+++ b/lib/api/functions/pipeline/getPublication/index.ts
@@ -4,7 +4,10 @@ import {
type DynamoDBGetItemRequest
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItem, convertFieldIdToObjectId } from '../../resolver-helper'
+import {
+ addAccountToItem,
+ convertFieldIdToObjectId
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBGetItemRequest {
const { newsletterId, publicationId } = ctx.args.input
@@ -20,7 +23,8 @@ export const response = (ctx: Context): any => {
if (ctx.error !== undefined && ctx.error !== null) {
util.error(ctx.error.message, ctx.error.type)
}
- const { emailKey, createdAt, newsletterId, publicationId, accountId } = ctx.result
+ const { emailKey, createdAt, newsletterId, publicationId, accountId } =
+ ctx.result
let path = ''
if (emailKey !== undefined) {
path = emailKey
diff --git a/lib/api/functions/pipeline/isAuthorized/index.ts b/lib/api/functions/pipeline/isAuthorized/index.ts
index 0017b7d..f72ea40 100644
--- a/lib/api/functions/pipeline/isAuthorized/index.ts
+++ b/lib/api/functions/pipeline/isAuthorized/index.ts
@@ -4,7 +4,12 @@
* SPDX-License-Identifier: MIT-0
*/
-import { type LambdaRequest, util, type Context, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type LambdaRequest,
+ util,
+ type Context,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
import { convertAvpObjectToGraphql } from '../../resolver-helper'
export function request (ctx: Context): LambdaRequest {
@@ -15,7 +20,9 @@ export function request (ctx: Context): LambdaRequest {
payload: {
userId: identity.resolverContext.userId,
accountId: identity.resolverContext.accountId,
- requestContext: JSON.parse(identity.resolverContext.requestContext as string),
+ requestContext: JSON.parse(
+ identity.resolverContext.requestContext as string
+ ),
result: ctx.prev.result,
arguments: args,
source,
diff --git a/lib/api/functions/pipeline/listDataFeedsById/index.ts b/lib/api/functions/pipeline/listDataFeedsById/index.ts
index 1da531c..0dc9b13 100644
--- a/lib/api/functions/pipeline/listDataFeedsById/index.ts
+++ b/lib/api/functions/pipeline/listDataFeedsById/index.ts
@@ -9,7 +9,9 @@ export function request (ctx: Context): DynamoDBBatchGetItemRequest {
return {
operation: 'BatchGetItem',
tables: {
- [NEWSLETTER_TABLE]: ctx.args.dataFeedIds.map((dataFeedId: string) => util.dynamodb.toMapValues({ dataFeedId }))
+ [NEWSLETTER_TABLE]: ctx.args.dataFeedIds.map((dataFeedId: string) =>
+ util.dynamodb.toMapValues({ dataFeedId })
+ )
}
}
}
diff --git a/lib/api/functions/pipeline/listDataFeedsDiscoverable/index.ts b/lib/api/functions/pipeline/listDataFeedsDiscoverable/index.ts
index b2ec2b6..919c7c0 100644
--- a/lib/api/functions/pipeline/listDataFeedsDiscoverable/index.ts
+++ b/lib/api/functions/pipeline/listDataFeedsDiscoverable/index.ts
@@ -5,12 +5,19 @@ import {
type DynamoDBQueryRequest
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
const dataFeedTypeIndex = 'type-index' // TODO - Make ENV variable
const input = ctx.args.input
- const includeDiscoverable = input?.includeDiscoverable !== undefined ? input.includeDiscoverable : ctx.stash.lookupDefinition.includeDiscoverable ?? false
+ const includeDiscoverable =
+ input?.includeDiscoverable !== undefined
+ ? input.includeDiscoverable
+ : ctx.stash.lookupDefinition.includeDiscoverable ?? false
if (includeDiscoverable === false) {
runtime.earlyReturn(ctx.prev.result)
}
diff --git a/lib/api/functions/pipeline/listDataFeedsOwned/index.ts b/lib/api/functions/pipeline/listDataFeedsOwned/index.ts
index 3a629b0..99cf7b7 100644
--- a/lib/api/functions/pipeline/listDataFeedsOwned/index.ts
+++ b/lib/api/functions/pipeline/listDataFeedsOwned/index.ts
@@ -11,13 +11,20 @@ import {
type AppSyncIdentityLambda
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
const dataFeedTypeIndex = 'type-index' // TODO - Make ENV variable
export function request (ctx: Context): DynamoDBQueryRequest {
const identity = ctx.identity as AppSyncIdentityLambda
const input = ctx.args.input
- const includeOwned = input?.includeOwned !== undefined ? input.includeOwned : ctx.stash.lookupDefinition.includeOwned ?? true
+ const includeOwned =
+ input?.includeOwned !== undefined
+ ? input.includeOwned
+ : ctx.stash.lookupDefinition.includeOwned ?? true
if (includeOwned === false) {
runtime.earlyReturn(ctx.prev.result)
}
diff --git a/lib/api/functions/pipeline/listDataFeedsShared/index.ts b/lib/api/functions/pipeline/listDataFeedsShared/index.ts
index cc9a77b..8326640 100644
--- a/lib/api/functions/pipeline/listDataFeedsShared/index.ts
+++ b/lib/api/functions/pipeline/listDataFeedsShared/index.ts
@@ -5,12 +5,19 @@ import {
type DynamoDBQueryRequest
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
const dataFeedTypeIndex = 'type-index' // TODO - Make ENV variable
const input = ctx.args.input
- const includeShared = input?.includeShared !== undefined ? input.includeShared : ctx.stash.lookupDefinition.includeShared ?? false
+ const includeShared =
+ input?.includeShared !== undefined
+ ? input.includeShared
+ : ctx.stash.lookupDefinition.includeShared ?? false
if (includeShared === false) {
runtime.earlyReturn(ctx.prev.result)
}
diff --git a/lib/api/functions/pipeline/listNewslettersById/index.ts b/lib/api/functions/pipeline/listNewslettersById/index.ts
index ce98018..f86b5c0 100644
--- a/lib/api/functions/pipeline/listNewslettersById/index.ts
+++ b/lib/api/functions/pipeline/listNewslettersById/index.ts
@@ -3,18 +3,29 @@ import {
util,
type DynamoDBBatchGetItemRequest
} from '@aws-appsync/utils'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBBatchGetItemRequest {
const { NEWSLETTER_TABLE } = ctx.env
- const newsletterIds = ctx.args.newsletterIds ?? ctx.prev.result.newsletterIds ?? undefined
- if (newsletterIds === undefined) { util.error('No newsletter Ids defined', 'ValidationException') }
- if (newsletterIds.length === 0) { runtime.earlyReturn([]) }
+ const newsletterIds =
+ ctx.args.newsletterIds ?? ctx.prev.result.newsletterIds ?? undefined
+ if (newsletterIds === undefined) {
+ util.error('No newsletter Ids defined', 'ValidationException')
+ }
+ if (newsletterIds.length === 0) {
+ runtime.earlyReturn([])
+ }
return {
operation: 'BatchGetItem',
tables: {
[NEWSLETTER_TABLE]: {
- keys: newsletterIds.map((newsletterId: string) => util.dynamodb.toMapValues({ newsletterId, sk: 'newsletter' }))
+ keys: newsletterIds.map((newsletterId: string) =>
+ util.dynamodb.toMapValues({ newsletterId, sk: 'newsletter' })
+ )
}
}
}
diff --git a/lib/api/functions/pipeline/listNewslettersDiscoverable/index.ts b/lib/api/functions/pipeline/listNewslettersDiscoverable/index.ts
index f9245a7..ec096ca 100644
--- a/lib/api/functions/pipeline/listNewslettersDiscoverable/index.ts
+++ b/lib/api/functions/pipeline/listNewslettersDiscoverable/index.ts
@@ -5,13 +5,20 @@ import {
type DynamoDBQueryRequest
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
const tableSKIndex = 'newsletter-item-type-index' // CDK doesn't have env variables yet
const { nextToken, limit = 500 } = ctx.args
const input = ctx.args.input
- const includeDiscoverable = input?.includeDiscoverable !== undefined ? input.includeDiscoverable : ctx.stash.lookupDefinition.includeDiscoverable ?? false
+ const includeDiscoverable =
+ input?.includeDiscoverable !== undefined
+ ? input.includeDiscoverable
+ : ctx.stash.lookupDefinition.includeDiscoverable ?? false
if (includeDiscoverable === true) {
return ddb.query({
query: {
diff --git a/lib/api/functions/pipeline/listNewslettersOwned/index.ts b/lib/api/functions/pipeline/listNewslettersOwned/index.ts
index c98dcad..166f6fc 100644
--- a/lib/api/functions/pipeline/listNewslettersOwned/index.ts
+++ b/lib/api/functions/pipeline/listNewslettersOwned/index.ts
@@ -6,14 +6,21 @@ import {
type AppSyncIdentityLambda
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
const identity = ctx.identity as AppSyncIdentityLambda
const tableSKIndex = 'newsletter-item-type-index' // CDK doesn't have env variables yet
const { nextToken, limit = 1000 } = ctx.args
const input = ctx.args.input
- const includeOwned = input?.includeOwned !== undefined ? input.includeOwned : ctx.stash.lookupDefinition.includeOwned ?? false as boolean
+ const includeOwned =
+ input?.includeOwned !== undefined
+ ? input.includeOwned
+ : ctx.stash.lookupDefinition.includeOwned ?? (false as boolean)
if (includeOwned === true) {
return ddb.query({
query: {
diff --git a/lib/api/functions/pipeline/listNewslettersShared/index.ts b/lib/api/functions/pipeline/listNewslettersShared/index.ts
index 13aade0..45b3bba 100644
--- a/lib/api/functions/pipeline/listNewslettersShared/index.ts
+++ b/lib/api/functions/pipeline/listNewslettersShared/index.ts
@@ -6,7 +6,11 @@ import {
type AppSyncIdentityLambda
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
// const { tableSKIndex } = ctx.env
@@ -14,7 +18,10 @@ export function request (ctx: Context): DynamoDBQueryRequest {
const tableSKIndex = 'newsletter-item-type-index' // CDK doesn't have env variables yet
const { nextToken, limit = 500 } = ctx.args
const input = ctx.args.input
- const includeShared = input?.includeShared !== undefined ? input.includeShared : ctx.stash.lookupDefinition.includeShared ?? false
+ const includeShared =
+ input?.includeShared !== undefined
+ ? input.includeShared
+ : ctx.stash.lookupDefinition.includeShared ?? false
if (includeShared === true) {
return ddb.query({
query: {
diff --git a/lib/api/functions/pipeline/listUserSubscriptions/index.ts b/lib/api/functions/pipeline/listUserSubscriptions/index.ts
index dafe0a3..5100582 100644
--- a/lib/api/functions/pipeline/listUserSubscriptions/index.ts
+++ b/lib/api/functions/pipeline/listUserSubscriptions/index.ts
@@ -4,7 +4,11 @@ import {
type AppSyncIdentityLambda
} from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
-import { addAccountToItems, convertFieldIdsToObjectIds, filterForDuplicatesById } from '../../resolver-helper'
+import {
+ addAccountToItems,
+ convertFieldIdsToObjectIds,
+ filterForDuplicatesById
+} from '../../resolver-helper'
export function request (ctx: Context): DynamoDBQueryRequest {
const identity = ctx.identity as AppSyncIdentityLambda
diff --git a/lib/api/functions/pipeline/subscribeToNewsletter/index.ts b/lib/api/functions/pipeline/subscribeToNewsletter/index.ts
index 23b65fc..ed375a6 100644
--- a/lib/api/functions/pipeline/subscribeToNewsletter/index.ts
+++ b/lib/api/functions/pipeline/subscribeToNewsletter/index.ts
@@ -1,4 +1,9 @@
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
const { args } = ctx
diff --git a/lib/api/functions/pipeline/unsubscribeFromNewsletter/index.ts b/lib/api/functions/pipeline/unsubscribeFromNewsletter/index.ts
index b39d39f..802c984 100644
--- a/lib/api/functions/pipeline/unsubscribeFromNewsletter/index.ts
+++ b/lib/api/functions/pipeline/unsubscribeFromNewsletter/index.ts
@@ -1,4 +1,9 @@
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
const { args } = ctx
diff --git a/lib/api/functions/pipeline/updateDataFeed/index.ts b/lib/api/functions/pipeline/updateDataFeed/index.ts
index ebe14f7..e4f7aec 100644
--- a/lib/api/functions/pipeline/updateDataFeed/index.ts
+++ b/lib/api/functions/pipeline/updateDataFeed/index.ts
@@ -8,12 +8,20 @@ import * as ddb from '@aws-appsync/utils/dynamodb'
export function request (ctx: Context): DynamoDBUpdateItemRequest {
const { dataFeedId } = ctx.args.input
const values: Record = {}
- Object.keys(ctx.args.input as Record).forEach((key: string) => {
- if (ctx.args?.input[key] !== undefined && ctx.args?.input[key] !== null && key !== 'dataFeedId') {
- console.log(`UpdateDataFeed. Loop values: ${key} ---- ${ctx.args.input[key]}`)
- values[key] = ctx.args.input[key]
+ Object.keys(ctx.args.input as Record).forEach(
+ (key: string) => {
+ if (
+ ctx.args?.input[key] !== undefined &&
+ ctx.args?.input[key] !== null &&
+ key !== 'dataFeedId'
+ ) {
+ console.log(
+ `UpdateDataFeed. Loop values: ${key} ---- ${ctx.args.input[key]}`
+ )
+ values[key] = ctx.args.input[key]
+ }
}
- })
+ )
return ddb.update({
key: {
diff --git a/lib/api/functions/pipeline/updateNewsletter/index.ts b/lib/api/functions/pipeline/updateNewsletter/index.ts
index e6d9fe0..91802b3 100644
--- a/lib/api/functions/pipeline/updateNewsletter/index.ts
+++ b/lib/api/functions/pipeline/updateNewsletter/index.ts
@@ -27,9 +27,9 @@ export function request (ctx: Context): DynamoDBUpdateItemRequest {
if (input.dataFeeds != null) {
expression += '#dataFeedIds = :dataFeedIds, '
expressionNames['#dataFeedIds'] = 'dataFeedIds'
- expressionValues[':dataFeedIds'] = util.dynamodb.toDynamoDB(
- [...input.dataFeeds]
- )
+ expressionValues[':dataFeedIds'] = util.dynamodb.toDynamoDB([
+ ...input.dataFeeds
+ ])
updates = updates + 1
}
if (input.isPrivate !== null) {
diff --git a/lib/api/functions/resolver-helper.ts b/lib/api/functions/resolver-helper.ts
index f85c625..7469a9b 100644
--- a/lib/api/functions/resolver-helper.ts
+++ b/lib/api/functions/resolver-helper.ts
@@ -44,17 +44,20 @@ export const convertAvpObjectsToGraphql = (obj: any): any => {
}
/**
- * Converts field id to object's "id" field and removes the provided id field
- * @param item
- * @param idFieldName
- * @returns item
- */
-export const convertFieldIdToObjectId = (obj: any, idFieldName: string): any => {
+ * Converts field id to object's "id" field and removes the provided id field
+ * @param item
+ * @param idFieldName
+ * @returns item
+ */
+export const convertFieldIdToObjectId = (
+ obj: any,
+ idFieldName: string
+): any => {
if (obj === undefined) {
return obj
}
obj.id = obj[idFieldName]
-
+
delete obj[idFieldName]
return obj
}
@@ -65,7 +68,11 @@ export const convertFieldIdToObjectId = (obj: any, idFieldName: string): any =>
* @param objectName
* @returns
*/
-export const convertFieldIdToObject = (obj: any, fieldIdName: string, objectName: string): any => {
+export const convertFieldIdToObject = (
+ obj: any,
+ fieldIdName: string,
+ objectName: string
+): any => {
if (obj === undefined) {
return obj
}
@@ -73,7 +80,7 @@ export const convertFieldIdToObject = (obj: any, fieldIdName: string, objectName
__typename: objectName,
id: obj[fieldIdName]
}
-
+
delete obj[fieldIdName]
return obj
}
@@ -88,9 +95,13 @@ export const filterForDuplicatesById = (obj: any): any => {
return obj
}
return {
- items: obj.items.filter((item: { id: any }, index: any, itemArray: any[]) => {
- return itemArray.findIndex((i: { id: any }) => i.id === item.id) === index
- })
+ items: obj.items.filter(
+ (item: { id: any }, index: any, itemArray: any[]) => {
+ return (
+ itemArray.findIndex((i: { id: any }) => i.id === item.id) === index
+ )
+ }
+ )
}
}
@@ -99,7 +110,10 @@ export const filterForDuplicatesById = (obj: any): any => {
* @param idFieldName
* @returns
*/
-export const convertFieldIdsToObjectIds = (obj: any, idFieldName: string): any => {
+export const convertFieldIdsToObjectIds = (
+ obj: any,
+ idFieldName: string
+): any => {
if (obj === undefined || obj.items === undefined) {
return obj
}
@@ -117,7 +131,11 @@ export const convertFieldIdsToObjectIds = (obj: any, idFieldName: string): any =
* @param objectName
* @returns
*/
-export const convertFieldIdsToObjects = (obj: any, idFieldName: string, objectName: string): any => {
+export const convertFieldIdsToObjects = (
+ obj: any,
+ idFieldName: string,
+ objectName: string
+): any => {
if (obj === undefined || obj.items === undefined) {
return obj
}
diff --git a/lib/api/functions/resolver/createNewsletter/index.ts b/lib/api/functions/resolver/createNewsletter/index.ts
index e6ac607..b2d06f6 100644
--- a/lib/api/functions/resolver/createNewsletter/index.ts
+++ b/lib/api/functions/resolver/createNewsletter/index.ts
@@ -4,7 +4,12 @@
* SPDX-License-Identifier: MIT-0
*/
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
ctx.stash.root = 'Newsletter'
diff --git a/lib/api/functions/resolver/externalUnsubscribeFromNewsletter/index.ts b/lib/api/functions/resolver/externalUnsubscribeFromNewsletter/index.ts
index f236869..ca3ab77 100644
--- a/lib/api/functions/resolver/externalUnsubscribeFromNewsletter/index.ts
+++ b/lib/api/functions/resolver/externalUnsubscribeFromNewsletter/index.ts
@@ -3,7 +3,10 @@ import { type Context, util, type LambdaRequest } from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
const { newsletterId, userId } = ctx.args.input
if (newsletterId === null || userId === null) {
- util.error('Newsletter ID & User ID are both required', 'ValidationException')
+ util.error(
+ 'Newsletter ID & User ID are both required',
+ 'ValidationException'
+ )
}
return {
operation: 'Invoke',
diff --git a/lib/api/functions/resolver/listDataFeeds/index.ts b/lib/api/functions/resolver/listDataFeeds/index.ts
index 773f550..d699047 100644
--- a/lib/api/functions/resolver/listDataFeeds/index.ts
+++ b/lib/api/functions/resolver/listDataFeeds/index.ts
@@ -3,7 +3,12 @@ import { type Context, util } from '@aws-appsync/utils'
export function request (ctx: Context): any {
const input = ctx.args.input
ctx.stash.root = 'DataFeeds'
- if (input === undefined || (input.includeOwned === undefined && input.includeShared === undefined && input.includeDiscoverable === undefined)) {
+ if (
+ input === undefined ||
+ (input.includeOwned === undefined &&
+ input.includeShared === undefined &&
+ input.includeDiscoverable === undefined)
+ ) {
ctx.stash.lookupDefinition = {
includeOwned: true,
includeShared: false,
diff --git a/lib/api/functions/resolver/listNewsletters/index.ts b/lib/api/functions/resolver/listNewsletters/index.ts
index 75d814e..ef22c51 100644
--- a/lib/api/functions/resolver/listNewsletters/index.ts
+++ b/lib/api/functions/resolver/listNewsletters/index.ts
@@ -10,7 +10,12 @@ export function request (ctx: Context): any {
ctx.stash.root = 'Newsletters'
console.log('[listNewslettersResolverRequest]', { ctx })
const input = ctx.args.input
- if (input === undefined || (input.includeDiscoverable === undefined && input.includeOwned === undefined && input.includeShared === undefined)) {
+ if (
+ input === undefined ||
+ (input.includeDiscoverable === undefined &&
+ input.includeOwned === undefined &&
+ input.includeShared === undefined)
+ ) {
ctx.stash.lookupDefinition = {
includeOwned: true,
includeShared: false,
diff --git a/lib/api/functions/resolver/unsubscribeFromNewsletter/index.ts b/lib/api/functions/resolver/unsubscribeFromNewsletter/index.ts
index bcf859e..aee08a4 100644
--- a/lib/api/functions/resolver/unsubscribeFromNewsletter/index.ts
+++ b/lib/api/functions/resolver/unsubscribeFromNewsletter/index.ts
@@ -4,7 +4,12 @@
* SPDX-License-Identifier: MIT-0
*/
-import { type Context, util, type LambdaRequest, type AppSyncIdentityLambda } from '@aws-appsync/utils'
+import {
+ type Context,
+ util,
+ type LambdaRequest,
+ type AppSyncIdentityLambda
+} from '@aws-appsync/utils'
export function request (ctx: Context): LambdaRequest {
ctx.stash.root = 'Newsletter'
diff --git a/lib/api/resolvers.ts b/lib/api/resolvers.ts
index e31694f..436ce7d 100644
--- a/lib/api/resolvers.ts
+++ b/lib/api/resolvers.ts
@@ -15,7 +15,14 @@ import {
import { Construct } from 'constructs'
import * as path from 'path'
import { type ApiProps } from '.'
-import { Effect, Policy, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam'
+import {
+ Effect,
+ Policy,
+ PolicyDocument,
+ PolicyStatement,
+ Role,
+ ServicePrincipal
+} from 'aws-cdk-lib/aws-iam'
interface ApiResolversProps extends ApiProps {
api: GraphqlApi
@@ -24,47 +31,65 @@ interface ApiResolversProps extends ApiProps {
export class ApiResolvers extends Construct {
constructor (scope: Construct, id: string, props: ApiResolversProps) {
super(scope, id)
- const { api, dataFeedTable, newsletterTable, unauthenticatedUserRole } = props
+ const { api, dataFeedTable, newsletterTable, unauthenticatedUserRole } =
+ props
const functionsPath = path.join(__dirname, 'functions')
- const getFunctionPath = (functionName: string, functionType: 'pipeline' | 'resolver'): string => {
- return path.join(functionsPath, 'out', functionType, functionName, 'index.js')
+ const getFunctionPath = (
+ functionName: string,
+ functionType: 'pipeline' | 'resolver'
+ ): string => {
+ return path.join(
+ functionsPath,
+ 'out',
+ functionType,
+ functionName,
+ 'index.js'
+ )
}
/** ****** DATA SOURCES FOR AppSync ******* **/
- const newsletterTableSourceRole = new Role(this, 'NewsletterTableSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- NewsletterTableSourceRolePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'dynamodb:GetItem',
- 'dynamodb:PutItem',
- 'dynamodb:UpdateItem',
- 'dynamodb:DeleteItem',
- 'dynamodb:Query',
- 'dynamodb:Scan',
- 'dynamodb:BatchGetItem'
- ],
- resources: [
- newsletterTable.tableArn,
- `${newsletterTable.tableArn}/index/${props.newsletterTableItemTypeGSI}`
- ]
- })
- ]
- })
+ const newsletterTableSourceRole = new Role(
+ this,
+ 'NewsletterTableSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ NewsletterTableSourceRolePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: [
+ 'dynamodb:GetItem',
+ 'dynamodb:PutItem',
+ 'dynamodb:UpdateItem',
+ 'dynamodb:DeleteItem',
+ 'dynamodb:Query',
+ 'dynamodb:Scan',
+ 'dynamodb:BatchGetItem'
+ ],
+ resources: [
+ newsletterTable.tableArn,
+ `${newsletterTable.tableArn}/index/${props.newsletterTableItemTypeGSI}`
+ ]
+ })
+ ]
+ })
+ }
}
- })
+ )
- const newsletterTableSource = new DynamoDbDataSource(this, 'NewsletterTableSource', {
- api,
- table: newsletterTable,
- serviceRole: newsletterTableSourceRole.withoutPolicyUpdates(),
- name: 'NewsletterTableSource',
- description: 'DynamoDB data source for newsletter table'
- })
+ const newsletterTableSource = new DynamoDbDataSource(
+ this,
+ 'NewsletterTableSource',
+ {
+ api,
+ table: newsletterTable,
+ serviceRole: newsletterTableSourceRole.withoutPolicyUpdates(),
+ name: 'NewsletterTableSource',
+ description: 'DynamoDB data source for newsletter table'
+ }
+ )
const dataFeedTableSourceRole = new Role(this, 'DataFeedTableSourceRole', {
assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
@@ -89,174 +114,209 @@ export class ApiResolvers extends Construct {
]
})
}
- }
- )
-
- const dataFeedTableSource = new DynamoDbDataSource(this, 'DataFeedTableSource', {
- api,
- table: dataFeedTable,
- description: 'DynamoDB data source for Data Feed table',
- serviceRole: dataFeedTableSourceRole.withoutPolicyUpdates(),
- name: 'DataFeedTableSource'
})
- const dataFeedSubscriberLambdaSourceRole = new Role(this, 'DataFeedSubscriberLambdaSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- DataFeedSubscriberLambdaSourceRolePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.feedSubscriberFunction.functionArn
- ]
- })
- ]
- })
+ const dataFeedTableSource = new DynamoDbDataSource(
+ this,
+ 'DataFeedTableSource',
+ {
+ api,
+ table: dataFeedTable,
+ description: 'DynamoDB data source for Data Feed table',
+ serviceRole: dataFeedTableSourceRole.withoutPolicyUpdates(),
+ name: 'DataFeedTableSource'
}
- }
)
- const dataFeedSubscriberLambdaSource = new LambdaDataSource(this, 'DataFeedSubscriberLambdaSource', {
- api,
- lambdaFunction: props.functions.feedSubscriberFunction,
- name: 'DataFeedSubscriberLambdaSource',
- description: 'Lambda data source for feedSubscriber function',
- serviceRole: dataFeedSubscriberLambdaSourceRole.withoutPolicyUpdates()
- })
+ const dataFeedSubscriberLambdaSourceRole = new Role(
+ this,
+ 'DataFeedSubscriberLambdaSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ DataFeedSubscriberLambdaSourceRolePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [props.functions.feedSubscriberFunction.functionArn]
+ })
+ ]
+ })
+ }
+ }
+ )
- const newsletterCreatorLambdaSourceRole = new Role(this, 'NewsletterCreatorLambdaSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- NewsletterCreatorLambdaSourceRolePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.createNewsletterFunction.functionArn
- ]
- })
- ]
- })
+ const dataFeedSubscriberLambdaSource = new LambdaDataSource(
+ this,
+ 'DataFeedSubscriberLambdaSource',
+ {
+ api,
+ lambdaFunction: props.functions.feedSubscriberFunction,
+ name: 'DataFeedSubscriberLambdaSource',
+ description: 'Lambda data source for feedSubscriber function',
+ serviceRole: dataFeedSubscriberLambdaSourceRole.withoutPolicyUpdates()
}
- })
+ )
- const newsletterCreatorLambdaSource = new LambdaDataSource(this, 'NewsletterCreatorLambdaSource', {
- api,
- lambdaFunction: props.functions.createNewsletterFunction,
- name: 'NewsletterCreatorLambdaSource',
- description: 'Lambda data source for createNewsletter function',
- serviceRole: newsletterCreatorLambdaSourceRole.withoutPolicyUpdates()
- })
+ const newsletterCreatorLambdaSourceRole = new Role(
+ this,
+ 'NewsletterCreatorLambdaSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ NewsletterCreatorLambdaSourceRolePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [
+ props.functions.createNewsletterFunction.functionArn
+ ]
+ })
+ ]
+ })
+ }
+ }
+ )
- const userSubscriberLambdaSourceRole = new Role(this, 'UserSubscriberLambdaSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- UserSubscriberLambdaSourceRolePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.userSubscriberFunction.functionArn
- ]
- })
- ]
- })
+ const newsletterCreatorLambdaSource = new LambdaDataSource(
+ this,
+ 'NewsletterCreatorLambdaSource',
+ {
+ api,
+ lambdaFunction: props.functions.createNewsletterFunction,
+ name: 'NewsletterCreatorLambdaSource',
+ description: 'Lambda data source for createNewsletter function',
+ serviceRole: newsletterCreatorLambdaSourceRole.withoutPolicyUpdates()
}
- }
)
- const userSubscriberLambdaSource = new LambdaDataSource(this, 'UserSubscriberLambdaSource', {
- api,
- lambdaFunction: props.functions.userSubscriberFunction,
- name: 'UserSubscriberLambdaSource',
- description: 'Lambda data source for userSubscriber function',
- serviceRole: userSubscriberLambdaSourceRole.withoutPolicyUpdates()
- })
+ const userSubscriberLambdaSourceRole = new Role(
+ this,
+ 'UserSubscriberLambdaSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ UserSubscriberLambdaSourceRolePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [props.functions.userSubscriberFunction.functionArn]
+ })
+ ]
+ })
+ }
+ }
+ )
- const userUnsubscriberLambdaSourceRole = new Role(this, 'UserUnsubscriberLambdaSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- UserUnsubscriberLambdaSourceRolePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.userUnsubscriberFunction.functionArn
- ]
- })
- ]
- })
+ const userSubscriberLambdaSource = new LambdaDataSource(
+ this,
+ 'UserSubscriberLambdaSource',
+ {
+ api,
+ lambdaFunction: props.functions.userSubscriberFunction,
+ name: 'UserSubscriberLambdaSource',
+ description: 'Lambda data source for userSubscriber function',
+ serviceRole: userSubscriberLambdaSourceRole.withoutPolicyUpdates()
}
- })
+ )
- const userUnsubscriberLambdaSource = new LambdaDataSource(this, 'UserUnsubscriberLambdaSource', {
- api,
- lambdaFunction: props.functions.userUnsubscriberFunction,
- name: 'UserUnsubscriberLambdaSource',
- description: 'Lambda data source for userUnsubscriber function',
- serviceRole: userUnsubscriberLambdaSourceRole.withoutPolicyUpdates()
- })
+ const userUnsubscriberLambdaSourceRole = new Role(
+ this,
+ 'UserUnsubscriberLambdaSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ UserUnsubscriberLambdaSourceRolePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [
+ props.functions.userUnsubscriberFunction.functionArn
+ ]
+ })
+ ]
+ })
+ }
+ }
+ )
- const isAuthorizedFunctionSourceRole = new Role(this, 'IsAuthorizedFunctionSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- IsAuthInvokePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.graphqlReadAuthorizerFunction.functionArn
- ]
- })
- ]
- })
+ const userUnsubscriberLambdaSource = new LambdaDataSource(
+ this,
+ 'UserUnsubscriberLambdaSource',
+ {
+ api,
+ lambdaFunction: props.functions.userUnsubscriberFunction,
+ name: 'UserUnsubscriberLambdaSource',
+ description: 'Lambda data source for userUnsubscriber function',
+ serviceRole: userUnsubscriberLambdaSourceRole.withoutPolicyUpdates()
}
- })
+ )
- const isAuthorizedFunctionSource = new LambdaDataSource(this, 'IsAuthorizedFunctionSource', {
- api,
- lambdaFunction: props.functions.graphqlReadAuthorizerFunction,
- name: 'isAuthorizedFunctionSource',
- description: 'Lambda data source for isAuthorized function',
- serviceRole: isAuthorizedFunctionSourceRole.withoutPolicyUpdates()
- })
+ const isAuthorizedFunctionSourceRole = new Role(
+ this,
+ 'IsAuthorizedFunctionSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ IsAuthInvokePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [
+ props.functions.graphqlReadAuthorizerFunction.functionArn
+ ]
+ })
+ ]
+ })
+ }
+ }
+ )
- const filterListByAuthorizationFunctionSourceRole = new Role(this, 'FilterListByAuthFunctionSourceRole', {
- assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
- inlinePolicies: {
- FilterIsAuthInvokePolicy: new PolicyDocument({
- statements: [
- new PolicyStatement({
- actions: [
- 'lambda:InvokeFunction'
- ],
- resources: [
- props.functions.graphqlFilterReadAuthorizerFunction.functionArn
- ]
- })
- ]
- })
+ const isAuthorizedFunctionSource = new LambdaDataSource(
+ this,
+ 'IsAuthorizedFunctionSource',
+ {
+ api,
+ lambdaFunction: props.functions.graphqlReadAuthorizerFunction,
+ name: 'isAuthorizedFunctionSource',
+ description: 'Lambda data source for isAuthorized function',
+ serviceRole: isAuthorizedFunctionSourceRole.withoutPolicyUpdates()
}
- })
+ )
- const filterListByAuthorizationSource = new LambdaDataSource(this, 'FilterIsAuthorizedFunctionSource', {
- api,
- lambdaFunction: props.functions.graphqlFilterReadAuthorizerFunction,
- name: 'filterIsAuthorizedFunctionSource',
- description: 'Lambda data source for isAuthorized function',
- serviceRole: filterListByAuthorizationFunctionSourceRole.withoutPolicyUpdates()
- })
+ const filterListByAuthorizationFunctionSourceRole = new Role(
+ this,
+ 'FilterListByAuthFunctionSourceRole',
+ {
+ assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
+ inlinePolicies: {
+ FilterIsAuthInvokePolicy: new PolicyDocument({
+ statements: [
+ new PolicyStatement({
+ actions: ['lambda:InvokeFunction'],
+ resources: [
+ props.functions.graphqlFilterReadAuthorizerFunction
+ .functionArn
+ ]
+ })
+ ]
+ })
+ }
+ }
+ )
+
+ const filterListByAuthorizationSource = new LambdaDataSource(
+ this,
+ 'FilterIsAuthorizedFunctionSource',
+ {
+ api,
+ lambdaFunction: props.functions.graphqlFilterReadAuthorizerFunction,
+ name: 'filterIsAuthorizedFunctionSource',
+ description: 'Lambda data source for isAuthorized function',
+ serviceRole:
+ filterListByAuthorizationFunctionSourceRole.withoutPolicyUpdates()
+ }
+ )
/** AppSync Resolver Pipeline Functions */
@@ -279,7 +339,9 @@ export class ApiResolvers extends Construct {
name: 'listNewslettersOwned',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listNewslettersOwned', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listNewslettersOwned', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -292,7 +354,9 @@ export class ApiResolvers extends Construct {
api,
dataSource: newsletterTableSource,
runtime: FunctionRuntime.JS_1_0_0,
- code: AssetCode.fromAsset(getFunctionPath('listNewslettersDiscoverable', 'pipeline'))
+ code: AssetCode.fromAsset(
+ getFunctionPath('listNewslettersDiscoverable', 'pipeline')
+ )
}
)
@@ -304,7 +368,9 @@ export class ApiResolvers extends Construct {
api,
dataSource: newsletterTableSource,
runtime: FunctionRuntime.JS_1_0_0,
- code: AssetCode.fromAsset(getFunctionPath('listNewslettersShared', 'pipeline'))
+ code: AssetCode.fromAsset(
+ getFunctionPath('listNewslettersShared', 'pipeline')
+ )
}
)
@@ -329,7 +395,9 @@ export class ApiResolvers extends Construct {
name: 'listPublications',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listPublications', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listPublications', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -340,7 +408,9 @@ export class ApiResolvers extends Construct {
name: 'getPublication',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('getPublication', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('getPublication', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -352,7 +422,9 @@ export class ApiResolvers extends Construct {
name: 'updateNewsletter',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('updateNewsletter', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('updateNewsletter', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -363,7 +435,9 @@ export class ApiResolvers extends Construct {
name: 'subscribeToNewsletter',
api,
dataSource: userSubscriberLambdaSource,
- code: AssetCode.fromAsset(getFunctionPath('subscribeToNewsletter', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('subscribeToNewsletter', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -375,7 +449,9 @@ export class ApiResolvers extends Construct {
name: 'unsubscribeFromNewsletter',
api,
dataSource: userUnsubscriberLambdaSource,
- code: AssetCode.fromAsset(getFunctionPath('unsubscribeFromNewsletter', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('unsubscribeFromNewsletter', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -387,7 +463,9 @@ export class ApiResolvers extends Construct {
name: 'listDataFeedsOwned',
api,
dataSource: dataFeedTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listDataFeedsOwned', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listDataFeedsOwned', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -399,7 +477,9 @@ export class ApiResolvers extends Construct {
name: 'listDataFeedsShared',
api,
dataSource: dataFeedTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listDataFeedsShared', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listDataFeedsShared', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -411,7 +491,9 @@ export class ApiResolvers extends Construct {
name: 'listDataFeedsDiscoverable',
api,
dataSource: dataFeedTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listDataFeedsDiscoverable', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listDataFeedsDiscoverable', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -423,7 +505,9 @@ export class ApiResolvers extends Construct {
name: 'createDataFeed',
api,
dataSource: dataFeedSubscriberLambdaSource,
- code: AssetCode.fromAsset(getFunctionPath('createDataFeed', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('createDataFeed', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -446,7 +530,9 @@ export class ApiResolvers extends Construct {
name: 'updateDataFeed',
api,
dataSource: dataFeedTableSource,
- code: AssetCode.fromAsset(getFunctionPath('updateDataFeed', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('updateDataFeed', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -470,7 +556,9 @@ export class ApiResolvers extends Construct {
name: 'checkSubscriptionToNewsletter',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('checkSubscriptionToNewsletter', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('checkSubscriptionToNewsletter', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -482,7 +570,9 @@ export class ApiResolvers extends Construct {
name: 'getNewsletterSubscriberStats',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('getNewsletterSubscriberStats', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('getNewsletterSubscriberStats', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -506,7 +596,9 @@ export class ApiResolvers extends Construct {
name: 'listUserSubscriptions',
api,
dataSource: newsletterTableSource,
- code: AssetCode.fromAsset(getFunctionPath('listUserSubscriptions', 'pipeline')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listUserSubscriptions', 'pipeline')
+ ),
runtime: FunctionRuntime.JS_1_0_0
}
)
@@ -519,13 +611,19 @@ export class ApiResolvers extends Construct {
code: AssetCode.fromAsset(getFunctionPath('isAuthorized', 'pipeline'))
})
- const filterListByAuthorization = new AppsyncFunction(this, 'filterListByAuthorization', {
- name: 'filterListByAuthorization',
- api,
- dataSource: filterListByAuthorizationSource,
- runtime: FunctionRuntime.JS_1_0_0,
- code: AssetCode.fromAsset(getFunctionPath('filterListByAuthorization', 'pipeline'))
- })
+ const filterListByAuthorization = new AppsyncFunction(
+ this,
+ 'filterListByAuthorization',
+ {
+ name: 'filterListByAuthorization',
+ api,
+ dataSource: filterListByAuthorizationSource,
+ runtime: FunctionRuntime.JS_1_0_0,
+ code: AssetCode.fromAsset(
+ getFunctionPath('filterListByAuthorization', 'pipeline')
+ )
+ }
+ )
/** AppSync GraphQL API Resolvers */
@@ -544,16 +642,27 @@ export class ApiResolvers extends Construct {
fieldName: 'listNewsletters',
code: AssetCode.fromAsset(getFunctionPath('listNewsletters', 'resolver')),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [listNewslettersOwned, listNewslettersDiscoverable, listNewslettersShared, filterListByAuthorization]
+ pipelineConfig: [
+ listNewslettersOwned,
+ listNewslettersDiscoverable,
+ listNewslettersShared,
+ filterListByAuthorization
+ ]
})
new Resolver(this, 'ListPublicationsResolver', {
api,
typeName: 'Query',
fieldName: 'listPublications',
- code: AssetCode.fromAsset(getFunctionPath('listPublications', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listPublications', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [getNewsletterFunction, listPublicationsFunction, filterListByAuthorization]
+ pipelineConfig: [
+ getNewsletterFunction,
+ listPublicationsFunction,
+ filterListByAuthorization
+ ]
})
new Resolver(this, 'getPublicationResolverFunction', {
@@ -569,9 +678,15 @@ export class ApiResolvers extends Construct {
api,
typeName: 'Mutation',
fieldName: 'updateNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('updateNewsletter', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('updateNewsletter', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [getNewsletterFunction, isAuthorized, updateNewsletterResolverFunction]
+ pipelineConfig: [
+ getNewsletterFunction,
+ isAuthorized,
+ updateNewsletterResolverFunction
+ ]
})
new Resolver(this, 'ListDataFeedsResolver', {
@@ -580,7 +695,12 @@ export class ApiResolvers extends Construct {
fieldName: 'listDataFeeds',
code: AssetCode.fromAsset(getFunctionPath('listDataFeeds', 'resolver')),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [listDataFeedsOwnedFunction, listDataFeedsSharedFunction, listDataFeedsDiscoverable, filterListByAuthorization]
+ pipelineConfig: [
+ listDataFeedsOwnedFunction,
+ listDataFeedsSharedFunction,
+ listDataFeedsDiscoverable,
+ filterListByAuthorization
+ ]
})
new Resolver(this, 'GetDataFeedResolver', {
@@ -598,7 +718,11 @@ export class ApiResolvers extends Construct {
fieldName: 'updateDataFeed',
code: AssetCode.fromAsset(getFunctionPath('updateDataFeed', 'resolver')),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [getDataFeedFunction, isAuthorized, updateDataFeedFunction]
+ pipelineConfig: [
+ getDataFeedFunction,
+ isAuthorized,
+ updateDataFeedFunction
+ ]
})
new Resolver(this, 'ListArticlesResolver', {
@@ -637,7 +761,9 @@ export class ApiResolvers extends Construct {
dataSource: newsletterCreatorLambdaSource,
typeName: 'Mutation',
fieldName: 'createNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('createNewsletter', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('createNewsletter', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0
})
@@ -645,8 +771,14 @@ export class ApiResolvers extends Construct {
api,
typeName: 'Mutation',
fieldName: 'subscribeToNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('subscribeToNewsletter', 'resolver')),
- pipelineConfig: [getNewsletterFunction, isAuthorized, subscribeToNewsletterFunction],
+ code: AssetCode.fromAsset(
+ getFunctionPath('subscribeToNewsletter', 'resolver')
+ ),
+ pipelineConfig: [
+ getNewsletterFunction,
+ isAuthorized,
+ subscribeToNewsletterFunction
+ ],
runtime: FunctionRuntime.JS_1_0_0
})
@@ -654,55 +786,72 @@ export class ApiResolvers extends Construct {
api,
typeName: 'Mutation',
fieldName: 'unsubscribeFromNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('unsubscribeFromNewsletter', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('unsubscribeFromNewsletter', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
pipelineConfig: [unsubscribeFromNewsletter]
})
- const externalUnsubscribeResolver = new Resolver(this, 'ExternalUnsubscriberResolver', {
- api,
- typeName: 'Mutation',
- fieldName: 'externalUnsubscribeFromNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('externalUnsubscribeFromNewsletter', 'resolver')),
- runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [unsubscribeFromNewsletter]
- })
- unauthenticatedUserRole.attachInlinePolicy(new Policy(this, 'UnauthRoleUnsubscribe', {
- statements: [
- new PolicyStatement({
- effect: Effect.ALLOW,
- actions: ['appsync:GraphQL'],
- resources: [externalUnsubscribeResolver.arn]
- })
- ]
- }))
+ const externalUnsubscribeResolver = new Resolver(
+ this,
+ 'ExternalUnsubscriberResolver',
+ {
+ api,
+ typeName: 'Mutation',
+ fieldName: 'externalUnsubscribeFromNewsletter',
+ code: AssetCode.fromAsset(
+ getFunctionPath('externalUnsubscribeFromNewsletter', 'resolver')
+ ),
+ runtime: FunctionRuntime.JS_1_0_0,
+ pipelineConfig: [unsubscribeFromNewsletter]
+ }
+ )
+ unauthenticatedUserRole.attachInlinePolicy(
+ new Policy(this, 'UnauthRoleUnsubscribe', {
+ statements: [
+ new PolicyStatement({
+ effect: Effect.ALLOW,
+ actions: ['appsync:GraphQL'],
+ resources: [externalUnsubscribeResolver.arn]
+ })
+ ]
+ })
+ )
new Resolver(this, 'CheckSubscriptionToNewsletterResolver', {
api,
typeName: 'Query',
fieldName: 'checkSubscriptionToNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('checkSubscriptionToNewsletter', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('checkSubscriptionToNewsletter', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [getNewsletterFunction, isAuthorized, checkSubscriptionToNewsletterFunction]
+ pipelineConfig: [
+ getNewsletterFunction,
+ isAuthorized,
+ checkSubscriptionToNewsletterFunction
+ ]
})
new Resolver(this, 'ListUserSubscriptionsResolver', {
api,
typeName: 'Query',
fieldName: 'listUserSubscriptions',
- code: AssetCode.fromAsset(getFunctionPath('listUserSubscriptions', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('listUserSubscriptions', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [
- listUserSubscriptionsFunction,
- filterListByAuthorization
- ]
+ pipelineConfig: [listUserSubscriptionsFunction, filterListByAuthorization]
})
new Resolver(this, 'CanUpdateNewsletterResolver', {
api,
typeName: 'Query',
fieldName: 'canUpdateNewsletter',
- code: AssetCode.fromAsset(getFunctionPath('canUpdateNewsletter', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('canUpdateNewsletter', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
pipelineConfig: [getNewsletterFunction, isAuthorized]
})
@@ -711,7 +860,9 @@ export class ApiResolvers extends Construct {
api,
typeName: 'Query',
fieldName: 'canUpdateDataFeed',
- code: AssetCode.fromAsset(getFunctionPath('canUpdateDataFeed', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('canUpdateDataFeed', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
pipelineConfig: [getDataFeedFunction, isAuthorized]
})
@@ -720,9 +871,15 @@ export class ApiResolvers extends Construct {
api,
typeName: 'Query',
fieldName: 'getNewsletterSubscriberStats',
- code: AssetCode.fromAsset(getFunctionPath('getNewsletterSubscriberStats', 'resolver')),
+ code: AssetCode.fromAsset(
+ getFunctionPath('getNewsletterSubscriberStats', 'resolver')
+ ),
runtime: FunctionRuntime.JS_1_0_0,
- pipelineConfig: [getNewsletterFunction, isAuthorized, getNewsletterSubscriberStatsFunction]
+ pipelineConfig: [
+ getNewsletterFunction,
+ isAuthorized,
+ getNewsletterSubscriberStatsFunction
+ ]
})
}
}
diff --git a/lib/authentication/index.pre-token-generation-hook.ts b/lib/authentication/index.pre-token-generation-hook.ts
index b234580..4324e57 100644
--- a/lib/authentication/index.pre-token-generation-hook.ts
+++ b/lib/authentication/index.pre-token-generation-hook.ts
@@ -11,9 +11,20 @@ import { MetricUnits, Metrics } from '@aws-lambda-powertools/metrics'
import { v4 as uuidv4 } from 'uuid'
import middy from '@middy/core'
import { type PreTokenGenerationAuthenticationTriggerEvent } from 'aws-lambda'
-import { DynamoDBClient, type PutItemCommandInput, PutItemCommand, DynamoDBServiceException, type ScanCommandInput, ScanCommand } from '@aws-sdk/client-dynamodb'
+import {
+ DynamoDBClient,
+ type PutItemCommandInput,
+ PutItemCommand,
+ DynamoDBServiceException,
+ type ScanCommandInput,
+ ScanCommand
+} from '@aws-sdk/client-dynamodb'
import { marshall } from '@aws-sdk/util-dynamodb'
-import { AdminUpdateUserAttributesCommand, CognitoIdentityProviderClient, type AdminUpdateUserAttributesCommandInput } from '@aws-sdk/client-cognito-identity-provider'
+import {
+ AdminUpdateUserAttributesCommand,
+ CognitoIdentityProviderClient,
+ type AdminUpdateUserAttributesCommandInput
+} from '@aws-sdk/client-cognito-identity-provider'
const SERVICE_NAME = 'post-authentication-hook'
const ACCOUNT_TABLE = process.env.ACCOUNT_TABLE
@@ -25,11 +36,17 @@ const metrics = new Metrics({ serviceName: SERVICE_NAME })
const dynamodb = tracer.captureAWSv3Client(new DynamoDBClient())
const cognito = tracer.captureAWSv3Client(new CognitoIdentityProviderClient())
-const lambdaHandler = async (event: PreTokenGenerationAuthenticationTriggerEvent): Promise => {
+const lambdaHandler = async (
+ event: PreTokenGenerationAuthenticationTriggerEvent
+): Promise => {
logger.debug('PostAuthenticationEventTriggered', { event })
metrics.addMetric('PostAuthenticationEventTriggered', MetricUnits.Count, 1)
const { userAttributes } = event.request
- if (userAttributes['custom:Account'] === undefined || userAttributes['custom:Account'] === null || userAttributes['custom:Account'].length < 1) {
+ if (
+ userAttributes['custom:Account'] === undefined ||
+ userAttributes['custom:Account'] === null ||
+ userAttributes['custom:Account'].length < 1
+ ) {
logger.debug('No Account ID found for user! Creating a new one', { event })
metrics.addMetric('NewAccountCreated', MetricUnits.Count, 1)
const userId = userAttributes.sub
@@ -45,7 +62,9 @@ const lambdaHandler = async (event: PreTokenGenerationAuthenticationTriggerEvent
}
const command = new PutItemCommand(input)
await dynamodb.send(command)
- event.response.claimsOverrideDetails.claimsToAddOrOverride = { 'custom:Account': accountId }
+ event.response.claimsOverrideDetails.claimsToAddOrOverride = {
+ 'custom:Account': accountId
+ }
console.log(accountId)
} catch (error) {
if (error instanceof DynamoDBServiceException) {
@@ -61,8 +80,14 @@ const lambdaHandler = async (event: PreTokenGenerationAuthenticationTriggerEvent
}
const command = new ScanCommand(scanInput)
const result = await dynamodb.send(command)
- if (result.Items === undefined || result.Items.length !== 1 || result.Items[0].accountId.S === undefined) {
- throw new Error('Account already exists for user but not found in database')
+ if (
+ result.Items === undefined ||
+ result.Items.length !== 1 ||
+ result.Items[0].accountId.S === undefined
+ ) {
+ throw new Error(
+ 'Account already exists for user but not found in database'
+ )
}
accountId = result.Items[0].accountId.S
}
diff --git a/lib/authentication/index.ts b/lib/authentication/index.ts
index 63b89e7..c26208d 100644
--- a/lib/authentication/index.ts
+++ b/lib/authentication/index.ts
@@ -18,10 +18,25 @@ import {
ClientAttributes
} from 'aws-cdk-lib/aws-cognito'
import { Construct } from 'constructs'
-import { Role, type IRole, PolicyStatement, Effect, Policy, ServicePrincipal, ManagedPolicy } from 'aws-cdk-lib/aws-iam'
+import {
+ Role,
+ type IRole,
+ PolicyStatement,
+ Effect,
+ Policy,
+ ServicePrincipal,
+ ManagedPolicy
+} from 'aws-cdk-lib/aws-iam'
import { AttributeType, BillingMode, Table } from 'aws-cdk-lib/aws-dynamodb'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
-import { ApplicationLogLevel, Architecture, LambdaInsightsVersion, LogFormat, Runtime, Tracing } from 'aws-cdk-lib/aws-lambda'
+import {
+ ApplicationLogLevel,
+ Architecture,
+ LambdaInsightsVersion,
+ LogFormat,
+ Runtime,
+ Tracing
+} from 'aws-cdk-lib/aws-lambda'
import { NagSuppressions } from 'cdk-nag'
interface AuthenticationProps {
@@ -66,28 +81,42 @@ export class Authentication extends Construct {
}
})
this.accountTable = accountTable
- const preTokenGenerationHookFunctionRole = new Role(this, 'pre-token-generation-hook-role', {
- assumedBy: new ServicePrincipal('lambda.amazonaws.com')
- })
- preTokenGenerationHookFunctionRole.addManagedPolicy(ManagedPolicy.fromManagedPolicyArn(this, 'PreTokenGenRoleLambdaExecution', 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'))
- const preTokenGenerationHookFunction = new NodejsFunction(this, 'pre-token-generation-hook', {
- description:
- 'Post Authentication, Pre-Token Generation Hook that creates a user\'s accountId',
- handler: 'handler',
- role: preTokenGenerationHookFunctionRole,
- architecture: Architecture.ARM_64,
- runtime: Runtime.NODEJS_20_X,
- tracing: Tracing.ACTIVE,
- logFormat: LogFormat.JSON,
- applicationLogLevel: ApplicationLogLevel.DEBUG,
- insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
- memorySize: 128,
- timeout: Duration.seconds(5),
- environment: {
- POWERTOOLS_LOG_LEVEL: 'DEBUG',
- ACCOUNT_TABLE: accountTable.tableName
+ const preTokenGenerationHookFunctionRole = new Role(
+ this,
+ 'pre-token-generation-hook-role',
+ {
+ assumedBy: new ServicePrincipal('lambda.amazonaws.com')
}
- })
+ )
+ preTokenGenerationHookFunctionRole.addManagedPolicy(
+ ManagedPolicy.fromManagedPolicyArn(
+ this,
+ 'PreTokenGenRoleLambdaExecution',
+ 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
+ )
+ )
+ const preTokenGenerationHookFunction = new NodejsFunction(
+ this,
+ 'pre-token-generation-hook',
+ {
+ description:
+ "Post Authentication, Pre-Token Generation Hook that creates a user's accountId",
+ handler: 'handler',
+ role: preTokenGenerationHookFunctionRole,
+ architecture: Architecture.ARM_64,
+ runtime: Runtime.NODEJS_20_X,
+ tracing: Tracing.ACTIVE,
+ logFormat: LogFormat.JSON,
+ applicationLogLevel: ApplicationLogLevel.DEBUG,
+ insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
+ memorySize: 128,
+ timeout: Duration.seconds(5),
+ environment: {
+ POWERTOOLS_LOG_LEVEL: 'DEBUG',
+ ACCOUNT_TABLE: accountTable.tableName
+ }
+ }
+ )
if (auth === undefined || auth === null) {
const selfSignUpEnabled =
this.node.tryGetContext('selfSignUpEnabled') ?? false
@@ -117,12 +146,14 @@ export class Authentication extends Construct {
postAuthentication: preTokenGenerationHookFunction
}
})
- const clientWriteAttributes = new ClientAttributes().withStandardAttributes({
- familyName: true,
- givenName: true,
- email: true
- })
- const clientReadAttributes = clientWriteAttributes.withCustomAttributes('Account')
+ const clientWriteAttributes =
+ new ClientAttributes().withStandardAttributes({
+ familyName: true,
+ givenName: true,
+ email: true
+ })
+ const clientReadAttributes =
+ clientWriteAttributes.withCustomAttributes('Account')
const userPoolClient = userPool.addClient('UserPoolClient', {
generateSecret: false,
readAttributes: clientReadAttributes,
@@ -227,28 +258,30 @@ export class Authentication extends Construct {
})
this.identityPool = identityPool
this.authenticatedUserRole = identityPool.authenticatedRole as Role
- this.unauthenticatedUserRole = identityPool.unauthenticatedRole as Role
+ this.unauthenticatedUserRole =
+ identityPool.unauthenticatedRole as Role
}
}
this.userPool = userPool
}
- preTokenGenerationHookFunctionRole.attachInlinePolicy(new Policy(this, 'pre-token-generation-hook-policy', {
- statements: [
- new PolicyStatement({
- actions: ['dynamodb:PutItem', 'dynamodb:Scan'],
- resources: [
- accountTable.tableArn
- ],
- effect: Effect.ALLOW
- }),
- new PolicyStatement({
- actions: ['cognito-idp:AdminUpdateUserAttributes'],
- resources: [this.userPool.userPoolArn]
- })
- ]
- }))
+ preTokenGenerationHookFunctionRole.attachInlinePolicy(
+ new Policy(this, 'pre-token-generation-hook-policy', {
+ statements: [
+ new PolicyStatement({
+ actions: ['dynamodb:PutItem', 'dynamodb:Scan'],
+ resources: [accountTable.tableArn],
+ effect: Effect.ALLOW
+ }),
+ new PolicyStatement({
+ actions: ['cognito-idp:AdminUpdateUserAttributes'],
+ resources: [this.userPool.userPoolArn]
+ })
+ ]
+ })
+ )
preTokenGenerationHookFunctionRole.addManagedPolicy(
- ManagedPolicy.fromAwsManagedPolicyName('AWSXrayWriteOnlyAccess'))
+ ManagedPolicy.fromAwsManagedPolicyName('AWSXrayWriteOnlyAccess')
+ )
new CfnOutput(this, 'UserPoolLink', {
value: `https://${Stack.of(this).region}.console.aws.amazon.com/cognito/v2/idp/user-pools/${this.userPool.userPoolId}/users?region=${Stack.of(this).region}`
@@ -260,28 +293,33 @@ export class Authentication extends Construct {
this.unauthenticatedUserRoleArn = this.unauthenticatedUserRole.roleArn
this.userPoolClientId = this.userPoolClient.userPoolClientId
/**
- * Adding nag suppression to decrease sec requirements for login
- */
+ * Adding nag suppression to decrease sec requirements for login
+ */
NagSuppressions.addResourceSuppressions(this.userPool, [
{
id: 'AwsSolutions-COG1',
- reason: 'Skipping - Sample doesn\'t need advanced security'
+ reason: "Skipping - Sample doesn't need advanced security"
},
{
id: 'AwsSolutions-COG2',
- reason: 'Skipping - Sample doesn\'t need advanced security'
+ reason: "Skipping - Sample doesn't need advanced security"
},
{
id: 'AwsSolutions-COG3',
- reason: 'Skipping - Sample doesn\'t need advanced security'
+ reason: "Skipping - Sample doesn't need advanced security"
}
])
- NagSuppressions.addResourceSuppressions(preTokenGenerationHookFunctionRole, [
- {
- id: 'AwsSolutions-IAM5',
- reason: 'Allowing PreTokenGenerationHookFunctionRole to have * policies'
- }
- ], true)
+ NagSuppressions.addResourceSuppressions(
+ preTokenGenerationHookFunctionRole,
+ [
+ {
+ id: 'AwsSolutions-IAM5',
+ reason:
+ 'Allowing PreTokenGenerationHookFunctionRole to have * policies'
+ }
+ ],
+ true
+ )
}
}
diff --git a/lib/authorization/authorization-helper.ts b/lib/authorization/authorization-helper.ts
index 556101f..175528f 100644
--- a/lib/authorization/authorization-helper.ts
+++ b/lib/authorization/authorization-helper.ts
@@ -7,10 +7,19 @@
import * as schemaMap from '../shared/api/types.json'
import { Kind, type OperationDefinitionNode, parse } from 'graphql'
-import { type EntityItem, type AttributeValue } from '@aws-sdk/client-verifiedpermissions'
+import {
+ type EntityItem,
+ type AttributeValue
+} from '@aws-sdk/client-verifiedpermissions'
import { type Logger } from '@aws-lambda-powertools/logger'
-export const getEntityItem = (schema: Record, entityId: string, entityType: string, entityData?: Record, optionals?: { logger?: Logger }): EntityItem => {
+export const getEntityItem = (
+ schema: Record,
+ entityId: string,
+ entityType: string,
+ entityData?: Record,
+ optionals?: { logger?: Logger }
+): EntityItem => {
const { logger } = optionals ?? {}
if (logger !== undefined) {
logger.debug(`getEntityItem: ${entityId} ${entityType}`)
@@ -27,7 +36,11 @@ export const getEntityItem = (schema: Record, entityId: string, ent
return item
}
-export const getEntityAttributes = (schema: Record, entityType: string, entityData: Record): Record => {
+export const getEntityAttributes = (
+ schema: Record,
+ entityType: string,
+ entityData: Record
+): Record => {
const avpSchema = schema.GenAINewsletter
const entityAttributes: Record = {}
if (avpSchema !== undefined && avpSchema.entityTypes !== undefined) {
@@ -41,7 +54,10 @@ export const getEntityAttributes = (schema: Record, entityType: str
let entityDataForKey
if (value.type === 'Entity') {
Object.keys(entityData).forEach((dataKey) => {
- if (entityData[dataKey].__typename !== undefined && entityData[dataKey].__typename === key) {
+ if (
+ entityData[dataKey].__typename !== undefined &&
+ entityData[dataKey].__typename === key
+ ) {
entityDataForKey = entityData[dataKey]
}
})
@@ -96,14 +112,19 @@ export const lowercaseFirstLetter = (stringVal: string): string => {
export const queryToActionAuth = (query: string): string => {
const ast = parse(query)
- const operationDefinition = ast.definitions.find(value => {
+ const operationDefinition = ast.definitions.find((value) => {
return value.kind === Kind.OPERATION_DEFINITION
}) as OperationDefinitionNode
if (operationDefinition.selectionSet.kind === Kind.SELECTION_SET) {
- const queryFieldSelection = operationDefinition.selectionSet.selections.find((selection) => {
- return selection.kind === Kind.FIELD
- })
- if (queryFieldSelection !== undefined && queryFieldSelection !== null && queryFieldSelection.kind === Kind.FIELD) {
+ const queryFieldSelection =
+ operationDefinition.selectionSet.selections.find((selection) => {
+ return selection.kind === Kind.FIELD
+ })
+ if (
+ queryFieldSelection !== undefined &&
+ queryFieldSelection !== null &&
+ queryFieldSelection.kind === Kind.FIELD
+ ) {
return queryFieldSelection.name.value
}
}
@@ -149,7 +170,12 @@ export const queryToResourcesEntity = (query: string): string => {
const itemObject = queryFieldTypeObject?.fields?.find((fieldItem) => {
return fieldItem.name === 'items'
})
- if (itemObject !== undefined && itemObject.type.kind === 'LIST' && itemObject?.type?.ofType?.name !== undefined && itemObject?.type?.ofType?.name !== null) {
+ if (
+ itemObject !== undefined &&
+ itemObject.type.kind === 'LIST' &&
+ itemObject?.type?.ofType?.name !== undefined &&
+ itemObject?.type?.ofType?.name !== null
+ ) {
return itemObject.type.ofType?.name
}
}
@@ -167,7 +193,12 @@ export const mutationToResourceEntity = (query: string): string => {
const queryField = queries.fields?.find((field) => {
return field.name === action
})
- if (queryField === undefined || queryField === null || queryField.type.kind !== Kind.OBJECT || queryField.type.name === null) {
+ if (
+ queryField === undefined ||
+ queryField === null ||
+ queryField.type.kind !== Kind.OBJECT ||
+ queryField.type.name === null
+ ) {
throw new Error('Unable to locate action')
}
return queryField.type.name
diff --git a/lib/authorization/index.action-authorization.ts b/lib/authorization/index.action-authorization.ts
index e8ca5af..c7e9f9a 100644
--- a/lib/authorization/index.action-authorization.ts
+++ b/lib/authorization/index.action-authorization.ts
@@ -8,9 +8,19 @@ import { captureLambdaHandler } from '@aws-lambda-powertools/tracer/middleware'
import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { MetricUnits, Metrics } from '@aws-lambda-powertools/metrics'
import { CognitoJwtVerifier } from 'aws-jwt-verify'
-import { CognitoIdentityProviderClient, GetUserCommand, type GetUserCommandInput } from '@aws-sdk/client-cognito-identity-provider' // ES Modules import
-import middy from '@middy/core'
-import { GetSchemaCommand, VerifiedPermissionsClient, type IsAuthorizedCommandInput, IsAuthorizedCommand, Decision } from '@aws-sdk/client-verifiedpermissions'
+import {
+ CognitoIdentityProviderClient,
+ GetUserCommand,
+ type GetUserCommandInput
+} from '@aws-sdk/client-cognito-identity-provider' // ES Modules import
+import middy from '@middy/core'
+import {
+ GetSchemaCommand,
+ VerifiedPermissionsClient,
+ type IsAuthorizedCommandInput,
+ IsAuthorizedCommand,
+ Decision
+} from '@aws-sdk/client-verifiedpermissions'
import { queryToActionAuth } from './authorization-helper'
const SERVICE_NAME = 'authorization-check'
@@ -19,7 +29,8 @@ const tracer = new Tracer({ serviceName: SERVICE_NAME })
const logger = new Logger({ serviceName: SERVICE_NAME })
const metrics = new Metrics({ serviceName: SERVICE_NAME })
-const { USER_POOL_ID, USER_POOL_CLIENT_ID, POLICY_STORE_ID, VALIDATION_REGEX } = process.env
+const { USER_POOL_ID, USER_POOL_CLIENT_ID, POLICY_STORE_ID, VALIDATION_REGEX } =
+ process.env
if (VALIDATION_REGEX === undefined || VALIDATION_REGEX === null) {
logger.error('VALIDATION_REGEX is not set')
throw new Error('VALIDATION_REGEX is not set')
@@ -39,17 +50,30 @@ const jwtVerifier = CognitoJwtVerifier.create({
tokenUse: 'access'
})
-const verifiedpermissions = tracer.captureAWSv3Client(new VerifiedPermissionsClient())
-const cognitoIdp = tracer.captureAWSv3Client(new CognitoIdentityProviderClient())
+const verifiedpermissions = tracer.captureAWSv3Client(
+ new VerifiedPermissionsClient()
+)
+const cognitoIdp = tracer.captureAWSv3Client(
+ new CognitoIdentityProviderClient()
+)
let schema: Record
const lambdaHandler = async (event: any): Promise => {
logger.debug('AuthorizationCheckEventTriggered', { event })
- if (schema === undefined || schema === null || Object.keys(schema).length === 0) {
+ if (
+ schema === undefined ||
+ schema === null ||
+ Object.keys(schema).length === 0
+ ) {
logger.debug('AVP Schema not yet cached. Retrieving AVP Schema')
- const schemaResponse = await verifiedpermissions.send(new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID }))
- if (schemaResponse.schema !== undefined && schemaResponse.schema.length > 0) {
+ const schemaResponse = await verifiedpermissions.send(
+ new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID })
+ )
+ if (
+ schemaResponse.schema !== undefined &&
+ schemaResponse.schema.length > 0
+ ) {
schema = JSON.parse(schemaResponse.schema)
} else {
metrics.addMetric('AuthCheckFailed', MetricUnits.Count, 1)
@@ -84,7 +108,9 @@ const lambdaHandler = async (event: any): Promise => {
},
resource: {
entityType: 'GenAINewsletter::Operation',
- entityId: lowercaseFirstLetter(queryToActionAuth(event.requestContext.queryString as string))
+ entityId: lowercaseFirstLetter(
+ queryToActionAuth(event.requestContext.queryString as string)
+ )
},
entities: {
entityList: [
@@ -105,12 +131,13 @@ const lambdaHandler = async (event: any): Promise => {
{
identifier: {
entityType: 'GenAINewsletter::Operation',
- entityId: lowercaseFirstLetter(queryToActionAuth(event.requestContext.queryString as string))
+ entityId: lowercaseFirstLetter(
+ queryToActionAuth(event.requestContext.queryString as string)
+ )
}
}
]
}
-
}
const command = new IsAuthorizedCommand(isAuthInput)
const response = await verifiedpermissions.send(command)
@@ -144,16 +171,24 @@ const lambdaHandler = async (event: any): Promise => {
}
}
-const getUserAccountId = async (authorizationToken: string): Promise => {
+const getUserAccountId = async (
+ authorizationToken: string
+): Promise => {
logger.debug('getting accountId for authToken', { authorizationToken })
const input: GetUserCommandInput = {
AccessToken: authorizationToken
}
const command = new GetUserCommand(input)
const response = await cognitoIdp.send(command)
- if (response.UserAttributes !== undefined && response.UserAttributes.length > 0) {
+ if (
+ response.UserAttributes !== undefined &&
+ response.UserAttributes.length > 0
+ ) {
for (const attribute of response.UserAttributes) {
- if (attribute.Name === 'custom:Account' && attribute.Value !== undefined) {
+ if (
+ attribute.Name === 'custom:Account' &&
+ attribute.Value !== undefined
+ ) {
return attribute.Value
}
}
diff --git a/lib/authorization/index.list-filter-authorization.ts b/lib/authorization/index.list-filter-authorization.ts
index f62932f..bd22d3a 100644
--- a/lib/authorization/index.list-filter-authorization.ts
+++ b/lib/authorization/index.list-filter-authorization.ts
@@ -9,8 +9,19 @@ import { Logger, injectLambdaContext } from '@aws-lambda-powertools/logger'
import { MetricUnits, Metrics } from '@aws-lambda-powertools/metrics'
import middy from '@middy/core'
-import { GetSchemaCommand, VerifiedPermissionsClient, type IsAuthorizedCommandInput, IsAuthorizedCommand, Decision } from '@aws-sdk/client-verifiedpermissions'
-import { getEntityItem, lowercaseFirstLetter, queryToActionAuth, queryToResourcesEntity } from './authorization-helper'
+import {
+ GetSchemaCommand,
+ VerifiedPermissionsClient,
+ type IsAuthorizedCommandInput,
+ IsAuthorizedCommand,
+ Decision
+} from '@aws-sdk/client-verifiedpermissions'
+import {
+ getEntityItem,
+ lowercaseFirstLetter,
+ queryToActionAuth,
+ queryToResourcesEntity
+} from './authorization-helper'
const SERVICE_NAME = 'list-filter-authorization'
@@ -24,17 +35,28 @@ if (POLICY_STORE_ID === undefined || POLICY_STORE_ID === null) {
throw new Error('POLICY_STORE_ID is not set')
}
-const verifiedpermissions = tracer.captureAWSv3Client(new VerifiedPermissionsClient())
+const verifiedpermissions = tracer.captureAWSv3Client(
+ new VerifiedPermissionsClient()
+)
let schema: Record
const lambdaHandler = async (event: any): Promise => {
logger.debug('FilterAuthorizationCheckEventTriggered', { event })
const { userId, accountId } = event
- if (schema === undefined || schema === null || Object.keys(schema).length === 0) {
+ if (
+ schema === undefined ||
+ schema === null ||
+ Object.keys(schema).length === 0
+ ) {
logger.debug('AVP Schema not yet cached. Retrieving AVP Schema')
- const schemaResponse = await verifiedpermissions.send(new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID }))
- if (schemaResponse.schema !== undefined && schemaResponse.schema.length > 0) {
+ const schemaResponse = await verifiedpermissions.send(
+ new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID })
+ )
+ if (
+ schemaResponse.schema !== undefined &&
+ schemaResponse.schema.length > 0
+ ) {
logger.debug('AVP Schema', { schema: schemaResponse.schema })
schema = JSON.parse(schemaResponse.schema)
} else {
@@ -44,13 +66,25 @@ const lambdaHandler = async (event: any): Promise => {
}
}
if (event.result.items !== undefined && event.result.items.length > 0) {
- logger.debug('Checking Item Authorization for Filtering', { itemCount: event.result.items.length })
+ logger.debug('Checking Item Authorization for Filtering', {
+ itemCount: event.result.items.length
+ })
const unfilteredItemPromises: Array> = []
event.result.items.forEach(async (item: any) => {
- unfilteredItemPromises.push(checkItemAuthorization(item, schema, userId as string, accountId as string, event.requestContext))
+ unfilteredItemPromises.push(
+ checkItemAuthorization(
+ item,
+ schema,
+ userId as string,
+ accountId as string,
+ event.requestContext
+ )
+ )
})
const resolvedAuthItems = await Promise.all(unfilteredItemPromises)
- const items = resolvedAuthItems.filter((item) => item.authorization).map((item) => item.item)
+ const items = resolvedAuthItems
+ .filter((item) => item.authorization)
+ .map((item) => item.item)
logger.debug('Filtered Items', { itemCount: items.length })
if (items.length > 0) {
return {
@@ -71,7 +105,13 @@ const lambdaHandler = async (event: any): Promise => {
}
}
-const checkItemAuthorization = async (item: any, schema: Record, userId: string, accountId: string, requestContext: any): Promise<{ item: any, authorization: boolean }> => {
+const checkItemAuthorization = async (
+ item: any,
+ schema: Record,
+ userId: string,
+ accountId: string,
+ requestContext: any
+): Promise<{ item: any; authorization: boolean }> => {
const queryString = requestContext.queryString as string
const isAuthInput: IsAuthorizedCommandInput = {
policyStoreId: POLICY_STORE_ID,
@@ -103,10 +143,15 @@ const checkItemAuthorization = async (item: any, schema: Record, us
}
}
},
- getEntityItem(schema, item.id as string, queryToResourcesEntity(queryString), item as Record, { logger })
+ getEntityItem(
+ schema,
+ item.id as string,
+ queryToResourcesEntity(queryString),
+ item as Record,
+ { logger }
+ )
]
}
-
}
logger.debug('AVP REQUEST', {
isAuthInput
diff --git a/lib/authorization/index.read-authorization.ts b/lib/authorization/index.read-authorization.ts
index 92e542e..7570b2d 100644
--- a/lib/authorization/index.read-authorization.ts
+++ b/lib/authorization/index.read-authorization.ts
@@ -10,8 +10,19 @@ import { MetricUnits, Metrics } from '@aws-lambda-powertools/metrics'
// import { getEntityItem } from '../shared/api/schema-to-avp/permission-map'
import middy from '@middy/core'
-import { GetSchemaCommand, VerifiedPermissionsClient, type IsAuthorizedCommandInput, IsAuthorizedCommand, Decision } from '@aws-sdk/client-verifiedpermissions'
-import { getEntityItem, lowercaseFirstLetter, queryToActionAuth, queryToResourceEntity } from './authorization-helper'
+import {
+ GetSchemaCommand,
+ VerifiedPermissionsClient,
+ type IsAuthorizedCommandInput,
+ IsAuthorizedCommand,
+ Decision
+} from '@aws-sdk/client-verifiedpermissions'
+import {
+ getEntityItem,
+ lowercaseFirstLetter,
+ queryToActionAuth,
+ queryToResourceEntity
+} from './authorization-helper'
const SERVICE_NAME = 'read-authorization'
@@ -25,7 +36,9 @@ if (POLICY_STORE_ID === undefined || POLICY_STORE_ID === null) {
throw new Error('POLICY_STORE_ID is not set')
}
-const verifiedpermissions = tracer.captureAWSv3Client(new VerifiedPermissionsClient())
+const verifiedpermissions = tracer.captureAWSv3Client(
+ new VerifiedPermissionsClient()
+)
let schema: Record
@@ -33,10 +46,19 @@ const lambdaHandler = async (event: any): Promise => {
logger.debug('AuthorizationCheckEventTriggered', { event })
const root = event.root as string | undefined
const contingentAction = event.contingentAction as string | undefined
- if (schema === undefined || schema === null || Object.keys(schema).length === 0) {
+ if (
+ schema === undefined ||
+ schema === null ||
+ Object.keys(schema).length === 0
+ ) {
logger.debug('AVP Schema not yet cached. Retrieving AVP Schema')
- const schemaResponse = await verifiedpermissions.send(new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID }))
- if (schemaResponse.schema !== undefined && schemaResponse.schema.length > 0) {
+ const schemaResponse = await verifiedpermissions.send(
+ new GetSchemaCommand({ policyStoreId: POLICY_STORE_ID })
+ )
+ if (
+ schemaResponse.schema !== undefined &&
+ schemaResponse.schema.length > 0
+ ) {
logger.debug('AVP Schema', { schema: schemaResponse.schema })
schema = JSON.parse(schemaResponse.schema)
} else {
@@ -54,7 +76,9 @@ const lambdaHandler = async (event: any): Promise => {
entityType: 'GenAINewsletter::User'
},
action: {
- actionId: lowercaseFirstLetter(contingentAction ?? queryToActionAuth(queryString)),
+ actionId: lowercaseFirstLetter(
+ contingentAction ?? queryToActionAuth(queryString)
+ ),
actionType: 'GenAINewsletter::Action'
},
resource: {
@@ -77,10 +101,15 @@ const lambdaHandler = async (event: any): Promise => {
}
}
},
- getEntityItem(schema, event.result.id as string, root ?? queryToResourceEntity(queryString), event.result as Record, { logger })
+ getEntityItem(
+ schema,
+ event.result.id as string,
+ root ?? queryToResourceEntity(queryString),
+ event.result as Record,
+ { logger }
+ )
]
}
-
}
logger.debug('AVP REQUEST', {
isAuthInput
diff --git a/lib/authorization/index.ts b/lib/authorization/index.ts
index 5e42912..fbe2b1b 100644
--- a/lib/authorization/index.ts
+++ b/lib/authorization/index.ts
@@ -3,7 +3,11 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: MIT-0
*/
-import { aws_verifiedpermissions as verifiedpermissions, Duration, RemovalPolicy } from 'aws-cdk-lib'
+import {
+ aws_verifiedpermissions as verifiedpermissions,
+ Duration,
+ RemovalPolicy
+} from 'aws-cdk-lib'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
import * as fs from 'fs'
import * as path from 'path'
@@ -16,7 +20,12 @@ import {
Runtime,
Tracing
} from 'aws-cdk-lib/aws-lambda'
-import { PolicyStatement, Effect, Policy, PolicyDocument } from 'aws-cdk-lib/aws-iam'
+import {
+ PolicyStatement,
+ Effect,
+ Policy,
+ PolicyDocument
+} from 'aws-cdk-lib/aws-iam'
import { type CfnPolicy } from 'aws-cdk-lib/aws-verifiedpermissions'
import { NagSuppressions } from 'cdk-nag'
@@ -37,9 +46,10 @@ export class Authorization extends Construct {
const { userPoolId, userPoolClientId, userPoolArn } = props
super(scope, id)
- const validationSettings: verifiedpermissions.CfnPolicyStore.ValidationSettingsProperty = {
- mode: 'STRICT'
- }
+ const validationSettings: verifiedpermissions.CfnPolicyStore.ValidationSettingsProperty =
+ {
+ mode: 'STRICT'
+ }
const policyStore = new verifiedpermissions.CfnPolicyStore(
this,
@@ -67,29 +77,35 @@ export class Authorization extends Construct {
})
const policiesFolder = path.join(__dirname, 'policies')
- this.policyDefinitions = fs.readdirSync(policiesFolder).filter(p => {
- const f = path.join(policiesFolder, p)
- return fs.statSync(f).isFile() && p.endsWith('.cedar')
- }).map((p) => {
- const f = path.join(policiesFolder, p)
- const policy = new verifiedpermissions.CfnPolicy(this, p, {
- policyStoreId: policyStore.ref,
- definition: {
- static: {
- description: p,
- statement: fs.readFileSync(f).toString('utf-8')
+ this.policyDefinitions = fs
+ .readdirSync(policiesFolder)
+ .filter((p) => {
+ const f = path.join(policiesFolder, p)
+ return fs.statSync(f).isFile() && p.endsWith('.cedar')
+ })
+ .map((p) => {
+ const f = path.join(policiesFolder, p)
+ const policy = new verifiedpermissions.CfnPolicy(this, p, {
+ policyStoreId: policyStore.ref,
+ definition: {
+ static: {
+ description: p,
+ statement: fs.readFileSync(f).toString('utf-8')
+ }
}
- }
+ })
+ policy.applyRemovalPolicy(RemovalPolicy.DESTROY)
+ return policy
})
- policy.applyRemovalPolicy(RemovalPolicy.DESTROY)
- return policy
- })
const avpAccessPolicy = new Policy(this, 'AuthCheckAVPAccess', {
document: new PolicyDocument({
statements: [
new PolicyStatement({
- actions: ['verifiedpermissions:IsAuthorized', 'verifiedpermissions:GetSchema'],
+ actions: [
+ 'verifiedpermissions:IsAuthorized',
+ 'verifiedpermissions:GetSchema'
+ ],
resources: [policyStore.attrArn],
effect: Effect.ALLOW
})
@@ -97,77 +113,102 @@ export class Authorization extends Construct {
})
})
- const graphqlActionAuthorizerFunction = new NodejsFunction(this, 'action-authorization', {
- description: 'Function responsible for checking if requests are authorized to create items using Amazon Verified Permissions',
- handler: 'handler',
- architecture: Architecture.ARM_64,
- runtime: Runtime.NODEJS_20_X,
- tracing: Tracing.ACTIVE,
- logFormat: LogFormat.JSON,
- applicationLogLevel: ApplicationLogLevel.DEBUG,
- insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
- timeout: Duration.minutes(5),
- environment: {
- POWERTOOLS_LOG_LEVEL: 'DEBUG',
- USER_POOL_CLIENT_ID: userPoolClientId,
- USER_POOL_ID: userPoolId,
- POLICY_STORE_ID: policyStore.ref,
- VALIDATION_REGEX: this.avpAuthorizerValidationRegex
+ const graphqlActionAuthorizerFunction = new NodejsFunction(
+ this,
+ 'action-authorization',
+ {
+ description:
+ 'Function responsible for checking if requests are authorized to create items using Amazon Verified Permissions',
+ handler: 'handler',
+ architecture: Architecture.ARM_64,
+ runtime: Runtime.NODEJS_20_X,
+ tracing: Tracing.ACTIVE,
+ logFormat: LogFormat.JSON,
+ applicationLogLevel: ApplicationLogLevel.DEBUG,
+ insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
+ timeout: Duration.minutes(5),
+ environment: {
+ POWERTOOLS_LOG_LEVEL: 'DEBUG',
+ USER_POOL_CLIENT_ID: userPoolClientId,
+ USER_POOL_ID: userPoolId,
+ POLICY_STORE_ID: policyStore.ref,
+ VALIDATION_REGEX: this.avpAuthorizerValidationRegex
+ }
}
- })
+ )
graphqlActionAuthorizerFunction.role?.attachInlinePolicy(avpAccessPolicy)
- const graphqlReadAuthorizerFunction = new NodejsFunction(this, 'read-authorization', {
- description: 'Function responsible for checking if requests are authorized to read/view data items using Amazon Verified Permissions',
- handler: 'handler',
- architecture: Architecture.ARM_64,
- runtime: Runtime.NODEJS_20_X,
- tracing: Tracing.ACTIVE,
- logFormat: LogFormat.JSON,
- applicationLogLevel: ApplicationLogLevel.DEBUG,
- insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
- timeout: Duration.minutes(5),
- environment: {
- POWERTOOLS_LOG_LEVEL: 'DEBUG',
- USER_POOL_CLIENT_ID: userPoolClientId,
- USER_POOL_ID: userPoolId,
- POLICY_STORE_ID: policyStore.ref,
- VALIDATION_REGEX: this.avpAuthorizerValidationRegex
+ const graphqlReadAuthorizerFunction = new NodejsFunction(
+ this,
+ 'read-authorization',
+ {
+ description:
+ 'Function responsible for checking if requests are authorized to read/view data items using Amazon Verified Permissions',
+ handler: 'handler',
+ architecture: Architecture.ARM_64,
+ runtime: Runtime.NODEJS_20_X,
+ tracing: Tracing.ACTIVE,
+ logFormat: LogFormat.JSON,
+ applicationLogLevel: ApplicationLogLevel.DEBUG,
+ insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
+ timeout: Duration.minutes(5),
+ environment: {
+ POWERTOOLS_LOG_LEVEL: 'DEBUG',
+ USER_POOL_CLIENT_ID: userPoolClientId,
+ USER_POOL_ID: userPoolId,
+ POLICY_STORE_ID: policyStore.ref,
+ VALIDATION_REGEX: this.avpAuthorizerValidationRegex
+ }
}
- })
+ )
graphqlReadAuthorizerFunction.role?.attachInlinePolicy(avpAccessPolicy)
- const graphqlFilterReadAuthorizerFunction = new NodejsFunction(this, 'list-filter-authorization', {
- description: 'Function responsible for checking if requested resources are authorized for viewing data and filtering out unauthorized data from the list.',
- handler: 'handler',
- architecture: Architecture.ARM_64,
- runtime: Runtime.NODEJS_20_X,
- tracing: Tracing.ACTIVE,
- logFormat: LogFormat.JSON,
- applicationLogLevel: ApplicationLogLevel.DEBUG,
- insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
- timeout: Duration.minutes(5),
- environment: {
- POWERTOOLS_LOG_LEVEL: 'DEBUG',
- USER_POOL_CLIENT_ID: userPoolClientId,
- USER_POOL_ID: userPoolId,
- POLICY_STORE_ID: policyStore.ref
+ const graphqlFilterReadAuthorizerFunction = new NodejsFunction(
+ this,
+ 'list-filter-authorization',
+ {
+ description:
+ 'Function responsible for checking if requested resources are authorized for viewing data and filtering out unauthorized data from the list.',
+ handler: 'handler',
+ architecture: Architecture.ARM_64,
+ runtime: Runtime.NODEJS_20_X,
+ tracing: Tracing.ACTIVE,
+ logFormat: LogFormat.JSON,
+ applicationLogLevel: ApplicationLogLevel.DEBUG,
+ insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
+ timeout: Duration.minutes(5),
+ environment: {
+ POWERTOOLS_LOG_LEVEL: 'DEBUG',
+ USER_POOL_CLIENT_ID: userPoolClientId,
+ USER_POOL_ID: userPoolId,
+ POLICY_STORE_ID: policyStore.ref
+ }
}
- })
- graphqlFilterReadAuthorizerFunction.role?.attachInlinePolicy(avpAccessPolicy)
+ )
+ graphqlFilterReadAuthorizerFunction.role?.attachInlinePolicy(
+ avpAccessPolicy
+ )
this.graphqlActionAuthorizerFunction = graphqlActionAuthorizerFunction
this.graphqlReadAuthorizerFunction = graphqlReadAuthorizerFunction
- this.graphqlFilterReadAuthorizerFunction = graphqlFilterReadAuthorizerFunction
+ this.graphqlFilterReadAuthorizerFunction =
+ graphqlFilterReadAuthorizerFunction
NagSuppressions.addResourceSuppressions(
- [graphqlActionAuthorizerFunction, graphqlReadAuthorizerFunction, graphqlFilterReadAuthorizerFunction], [
+ [
+ graphqlActionAuthorizerFunction,
+ graphqlReadAuthorizerFunction,
+ graphqlFilterReadAuthorizerFunction
+ ],
+ [
{
id: 'AwsSolutions-IAM5',
- reason: 'The policy is restricted to the verifiedpermissions:IsAuthorized and verifiedpermissions:GetSchema actions'
+ reason:
+ 'The policy is restricted to the verifiedpermissions:IsAuthorized and verifiedpermissions:GetSchema actions'
}
- ], true
+ ],
+ true
)
}
}
diff --git a/lib/cdk-nag-supressions.ts b/lib/cdk-nag-supressions.ts
index 6eae32d..23578e0 100644
--- a/lib/cdk-nag-supressions.ts
+++ b/lib/cdk-nag-supressions.ts
@@ -17,7 +17,9 @@ export const addNagSuppressions = (stack: Stack): void => {
},
{
id: 'AwsSolutions-IAM5',
- appliesTo: ['Policy::arn::iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs'],
+ appliesTo: [
+ 'Policy::arn::iam::aws:policy/service-role/AWSAppSyncPushToCloudWatchLogs'
+ ],
reason: 'Allowing managed policy: AWSAppSyncPushToCloudWatchLogs'
}
])
@@ -25,31 +27,38 @@ export const addNagSuppressions = (stack: Stack): void => {
* This is the Stack-Level Log Retention Custom Resource.
* If cdk_nag throws an IAM5 error for LogRetention, confirm the logical ID hasn't changed.
*/
- NagSuppressions.addResourceSuppressionsByPath(stack,
- `/${stack.stackName}/LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8a/ServiceRole/DefaultPolicy/Resource`, [
+ NagSuppressions.addResourceSuppressionsByPath(
+ stack,
+ `/${stack.stackName}/LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8a/ServiceRole/DefaultPolicy/Resource`,
+ [
{
id: 'AwsSolutions-IAM5',
reason: 'Allowing LogRetention to apply to any CloudWatch Resource'
}
- ])
+ ]
+ )
/**
* CDKBucketDeployment Resource must be referenced by Path
* If cdk_nag throws errors for this resource, confirm the logical ID hasn't changed.
- */
- NagSuppressions.addResourceSuppressionsByPath(stack,
- `/${stack.stackName}/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource`,
- [
- {
- id: 'AwsSolutions-IAM5',
- reason: 'Allowing CDKBucketDeployment to have * policies'
- }
- ])
- NagSuppressions.addResourceSuppressionsByPath(stack,
+ */
+ NagSuppressions.addResourceSuppressionsByPath(
+ stack,
+ `/${stack.stackName}/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource`,
+ [
+ {
+ id: 'AwsSolutions-IAM5',
+ reason: 'Allowing CDKBucketDeployment to have * policies'
+ }
+ ]
+ )
+ NagSuppressions.addResourceSuppressionsByPath(
+ stack,
`/${stack.stackName}/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource`,
[
{
id: 'AwsSolutions-L1',
- reason: 'Allowing CDKBucketDeployment Lambda Runtime version to be managed by CDK version'
+ reason:
+ 'Allowing CDKBucketDeployment Lambda Runtime version to be managed by CDK version'
}
]
)
diff --git a/lib/config.ts b/lib/config.ts
index b9d5499..fa7a5be 100644
--- a/lib/config.ts
+++ b/lib/config.ts
@@ -9,9 +9,13 @@ import { type DeployConfig } from '../lib/shared/common/deploy-config'
import { existsSync, readFileSync } from 'fs'
export default function getConfig (pathValue?: string): DeployConfig {
- if (existsSync(pathValue ?? path.join(__dirname, '..', 'bin', 'config.json'))) {
+ if (
+ existsSync(pathValue ?? path.join(__dirname, '..', 'bin', 'config.json'))
+ ) {
return JSON.parse(
- readFileSync(pathValue ?? path.join(__dirname, '..', 'bin', 'config.json')).toString('utf8')
+ readFileSync(
+ pathValue ?? path.join(__dirname, '..', 'bin', 'config.json')
+ ).toString('utf8')
) as DeployConfig
} else {
throw new Error(
diff --git a/lib/data-feed-ingestion/index.ts b/lib/data-feed-ingestion/index.ts
index 1b7cdf5..e1d48e5 100644
--- a/lib/data-feed-ingestion/index.ts
+++ b/lib/data-feed-ingestion/index.ts
@@ -59,17 +59,22 @@ export class NewsSubscriptionIngestion extends Construct {
}
})
- const rssAtomIngestion = new RssAtomFeedConstruct(this, 'RssAtomIngestion', {
- dataFeedTable,
- dataFeedTableTypeIndex: this.dataFeedTableTypeIndex,
- dataFeedTableLSI: this.dataFeedTableLSI,
- loggingBucket
- })
+ const rssAtomIngestion = new RssAtomFeedConstruct(
+ this,
+ 'RssAtomIngestion',
+ {
+ dataFeedTable,
+ dataFeedTableTypeIndex: this.dataFeedTableTypeIndex,
+ dataFeedTableLSI: this.dataFeedTableLSI,
+ loggingBucket
+ }
+ )
this.dataFeedTable = dataFeedTable
this.rssAtomDataBucket = rssAtomIngestion.rssAtomDataBucket
this.feedSubscriberFunction = rssAtomIngestion.feedSubscriberFunction
- this.rssAtomIngestionStepFunctionStateMachine = rssAtomIngestion.ingestionStepFunction.stateMachine
+ this.rssAtomIngestionStepFunctionStateMachine =
+ rssAtomIngestion.ingestionStepFunction.stateMachine
this.dataFeedPollStepFunctionStateMachine =
rssAtomIngestion.dataFeedPollStepFunction.stateMachine
}
diff --git a/lib/data-feed-ingestion/prompts.ts b/lib/data-feed-ingestion/prompts.ts
index 8df81c4..deef6a3 100644
--- a/lib/data-feed-ingestion/prompts.ts
+++ b/lib/data-feed-ingestion/prompts.ts
@@ -3,7 +3,7 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: MIT-0
*/
-
+
export class ArticleIngestorPromptConfiguration {
private static readonly BASE_PROMPT =
'\n\nHuman: ' +
diff --git a/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.get-data-feeds.ts b/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.get-data-feeds.ts
index 751ce9f..828d384 100644
--- a/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.get-data-feeds.ts
+++ b/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.get-data-feeds.ts
@@ -23,8 +23,7 @@ const metrics = new Metrics({ serviceName: SERVICE_NAME })
const dynamodb = tracer.captureAWSv3Client(new DynamoDBClient())
const DATA_FEED_TABLE = process.env.DATA_FEED_TABLE
-const DATA_FEED_TABLE_TYPE_INDEX =
- process.env.DATA_FEED_TABLE_TYPE_INDEX
+const DATA_FEED_TABLE_TYPE_INDEX = process.env.DATA_FEED_TABLE_TYPE_INDEX
interface GetDataFeedsOutput {
dataFeeds: string[]
diff --git a/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.ts b/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.ts
index f95cae4..3a9e74d 100644
--- a/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.ts
+++ b/lib/data-feed-ingestion/rss-atom-ingestion/data-feed-poll-step-function.ts
@@ -48,28 +48,23 @@ export class DataFeedPollStepFunction extends Construct {
) {
super(scope, id)
- const getDataFeedsFunction = new NodejsFunction(
- this,
- 'get-data-feeds',
- {
- description:
- 'Function responsible for getting all enabled data feeds to poll',
- handler: 'handler',
- architecture: Architecture.ARM_64,
- runtime: Runtime.NODEJS_20_X,
- tracing: Tracing.ACTIVE,
- logFormat: LogFormat.JSON,
- applicationLogLevel: ApplicationLogLevel.DEBUG,
- insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
- environment: {
- POWERTOOLS_LOG_LEVEL: 'DEBUG',
- DATA_FEED_TABLE: props.dataFeedTable.tableName,
- DATA_FEED_TABLE_TYPE_INDEX:
- props.dataFeedTableTypeIndex
- },
- timeout: cdk.Duration.seconds(30)
- }
- )
+ const getDataFeedsFunction = new NodejsFunction(this, 'get-data-feeds', {
+ description:
+ 'Function responsible for getting all enabled data feeds to poll',
+ handler: 'handler',
+ architecture: Architecture.ARM_64,
+ runtime: Runtime.NODEJS_20_X,
+ tracing: Tracing.ACTIVE,
+ logFormat: LogFormat.JSON,
+ applicationLogLevel: ApplicationLogLevel.DEBUG,
+ insightsVersion: LambdaInsightsVersion.VERSION_1_0_229_0,
+ environment: {
+ POWERTOOLS_LOG_LEVEL: 'DEBUG',
+ DATA_FEED_TABLE: props.dataFeedTable.tableName,
+ DATA_FEED_TABLE_TYPE_INDEX: props.dataFeedTableTypeIndex
+ },
+ timeout: cdk.Duration.seconds(30)
+ })
// Step Function Tasks
// Get Data Feeds from Data Feed Table
@@ -128,10 +123,13 @@ export class DataFeedPollStepFunction extends Construct {
*/
NagSuppressions.addResourceSuppressions(
[stateMachine, getDataFeedsFunction],
- [{
- id: 'AwsSolutions-IAM5',
- reason: 'Allowing CloudWatch & XRay'
- }], true
+ [
+ {
+ id: 'AwsSolutions-IAM5',
+ reason: 'Allowing CloudWatch & XRay'
+ }
+ ],
+ true
)
}
}
diff --git a/lib/data-feed-ingestion/rss-atom-ingestion/index.feed-subscriber.ts b/lib/data-feed-ingestion/rss-atom-ingestion/index.feed-subscriber.ts
index d456745..a0ebe58 100644
--- a/lib/data-feed-ingestion/rss-atom-ingestion/index.feed-subscriber.ts
+++ b/lib/data-feed-ingestion/rss-atom-ingestion/index.feed-subscriber.ts
@@ -47,7 +47,9 @@ const lambdaHander = async (event: {
metrics.addMetric('SubscriberInvocations', MetricUnits.Count, 1)
const { url, summarizationPrompt, title, description, enabled } = event.input
const isPrivate: boolean = event.input.isPrivate ?? true
- if (url === undefined) { throw new Error('URL is required') }
+ if (url === undefined) {
+ throw new Error('URL is required')
+ }
const { accountId } = event
try {
const response = await axios.get(url)
@@ -60,7 +62,8 @@ const lambdaHander = async (event: {
logger.debug('Found RSS feed')
feedType = DataFeedType.RSS
} else if (
- $('feed').length > 0 && $('feed').attr('xmlns') === 'http://www.w3.org/2005/Atom'
+ $('feed').length > 0 &&
+ $('feed').attr('xmlns') === 'http://www.w3.org/2005/Atom'
) {
metrics.addMetric('ATOMFeeds', MetricUnits.Count, 1)
logger.debug('Found ATOM feed')
@@ -98,9 +101,7 @@ const lambdaHander = async (event: {
}
}
-const storeDataFeed = async (
- dataFeed: DataFeed
-): Promise => {
+const storeDataFeed = async (dataFeed: DataFeed): Promise => {
const {
id: dataFeedId,
url,
diff --git a/lib/data-feed-ingestion/rss-atom-ingestion/index.ts b/lib/data-feed-ingestion/rss-atom-ingestion/index.ts
index d6f3f69..55f1853 100644
--- a/lib/data-feed-ingestion/rss-atom-ingestion/index.ts
+++ b/lib/data-feed-ingestion/rss-atom-ingestion/index.ts
@@ -10,7 +10,14 @@ import { Construct } from 'constructs'
import { IngestionStepFunction } from './ingestion-step-function'
import { DataFeedPollStepFunction } from './data-feed-poll-step-function'
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'
-import { ApplicationLogLevel, Architecture, LambdaInsightsVersion, LogFormat, Runtime, Tracing } from 'aws-cdk-lib/aws-lambda'
+import {
+ ApplicationLogLevel,
+ Architecture,
+ LambdaInsightsVersion,
+ LogFormat,
+ Runtime,
+ Tracing
+} from 'aws-cdk-lib/aws-lambda'
import { NagSuppressions } from 'cdk-nag'
interface RssAtomFeedProps {
@@ -42,7 +49,7 @@ export class RssAtomFeedConstruct extends Construct {
'IngestionStepFunction',
{
description:
-'Step Function Responsible for ingesting data from RSS/ATOM feeds, generating summarizations and storing the information.',
+ 'Step Function Responsible for ingesting data from RSS/ATOM feeds, generating summarizations and storing the information.',
dataFeedTable,
rssAtomDataBucket
}
@@ -53,7 +60,7 @@ export class RssAtomFeedConstruct extends Construct {
'DataFeedPollStepFunction',
{
description:
-'Step Function Responsible for getting enabled data feeds and starting ingestion for each one.',
+ 'Step Function Responsible for getting enabled data feeds and starting ingestion for each one.',
dataFeedIngestionStateMachine: ingestionStepFunction.stateMachine,
dataFeedTable,
dataFeedTableTypeIndex
@@ -62,7 +69,7 @@ export class RssAtomFeedConstruct extends Construct {
const feedSubscriberFunction = new NodejsFunction(this, 'feed-subscriber', {
description:
-'Function responsible for subscribing to a specified RSS/ATOM feed',
+ 'Function responsible for subscribing to a specified RSS/ATOM feed',
handler: 'handler',
architecture: Architecture.ARM_64,
runtime: Runtime.NODEJS_20_X,
@@ -74,7 +81,7 @@ export class RssAtomFeedConstruct extends Construct {
POWERTOOLS_LOG_LEVEL: 'DEBUG',
DATA_FEED_TABLE: dataFeedTable.tableName,
INGESTION_STEP_FUNCTION:
-ingestionStepFunction.stateMachine.stateMachineArn
+ ingestionStepFunction.stateMachine.stateMachineArn
},
timeout: Duration.minutes(1)
})
@@ -97,10 +104,13 @@ ingestionStepFunction.stateMachine.stateMachineArn
*/
NagSuppressions.addResourceSuppressions(
[feedSubscriberFunction],
- [{
- id: 'AwsSolutions-IAM5',
- reason: 'Allowing CloudWatch & XRay'
- }], true
+ [
+ {
+ id: 'AwsSolutions-IAM5',
+ reason: 'Allowing CloudWatch & XRay'
+ }
+ ],
+ true
)
}
}
diff --git a/lib/data-feed-ingestion/rss-atom-ingestion/ingestion-step-function.article-ingestor.ts b/lib/data-feed-ingestion/rss-atom-ingestion/ingestion-step-function.article-ingestor.ts
index 6ef172c..81b8aa8 100644
--- a/lib/data-feed-ingestion/rss-atom-ingestion/ingestion-step-function.article-ingestor.ts
+++ b/lib/data-feed-ingestion/rss-atom-ingestion/ingestion-step-function.article-ingestor.ts
@@ -226,7 +226,13 @@ const generateArticleSummarization = async (
messages: [{ role: 'user', content: prompt }]
})
logger.debug('GenAI Output', { response })
- const processedResponse = summaryBuilder.getProcessedResponse(response.content.map((item) => { return item.type === 'text' ? item.text : '' }).join('\n'))
+ const processedResponse = summaryBuilder.getProcessedResponse(
+ response.content
+ .map((item) => {
+ return item.type === 'text' ? item.text : ''
+ })
+ .join('\n')
+ )
logger.debug('Formatted response from Model:', { processedResponse })
if (processedResponse.error.response !== null) {
logger.error('Error in processed response from LLM', {
@@ -282,7 +288,9 @@ const saveArticleData = async (
const checkForRedirectFallback = ($: cheerio.Root): string | null => {
logger.debug('Checking for redirect fallback in