From 8de20a36fa5d623d372a0840caaaf88d2c58bcfd Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 15 Jan 2024 16:24:23 -0500 Subject: [PATCH] Nextjs: support linking --- internal/components/src/components/bucket.ts | 1 - .../components/src/components/function.ts | 29 ++++- .../components/src/components/ssr-site.ts | 111 +++++++----------- 3 files changed, 63 insertions(+), 78 deletions(-) diff --git a/internal/components/src/components/bucket.ts b/internal/components/src/components/bucket.ts index a926e54ec..095071c41 100644 --- a/internal/components/src/components/bucket.ts +++ b/internal/components/src/components/bucket.ts @@ -12,7 +12,6 @@ import { prefixName, hashNumberToString } from "./helpers/naming"; import { Component } from "./component"; import { AWSLinkable, Link, Linkable } from "./link"; import { FunctionPermissionArgs } from "."; -import { create } from "domain"; /** * Properties to create a DNS validated certificate managed by AWS Certificate Manager. diff --git a/internal/components/src/components/function.ts b/internal/components/src/components/function.ts index 04505a114..e7b7f2c8d 100644 --- a/internal/components/src/components/function.ts +++ b/internal/components/src/components/function.ts @@ -23,6 +23,7 @@ import { Duration, toSeconds } from "./util/duration.js"; import { Size, toMBs } from "./util/size.js"; import { Component } from "./component.js"; import { + AWSLinkable, Linkable, isAWSLinkable, isLinkable, @@ -58,7 +59,7 @@ const RETENTION = { export interface FunctionPermissionArgs { actions: string[]; - resources: Output[]; + resources: Input[]; } export interface FunctionCopyFilesArgs { @@ -334,9 +335,8 @@ export interface FunctionArgs { * { * permissions: [ * { - * Effect: "Allow", - * Action: ["s3:*"], - * Resource: ["arn:aws:s3:::*"], + * actions: ["s3:*"], + * resources: ["arn:aws:s3:::*"], * }, * ] * } @@ -344,7 +344,8 @@ export interface FunctionArgs { */ permissions?: Input; /** - * Link resources for the function + * Link resources to the function. + * This will grant the function permissions to access the linked resources at runtime. * * @example * ```js @@ -427,7 +428,7 @@ export interface FunctionArgs { }; } -export class Function extends Component { +export class Function extends Component implements Linkable, AWSLinkable { private function: Output; private role: Output; private logGroup: LogGroup; @@ -859,6 +860,22 @@ export class Function extends Component { return this.fnUrl.apply((url) => url?.functionUrl ?? output(undefined)); } + public getSSTLink(): Link { + return { + type: `{ functionName: string }`, + value: { + functionName: this.function.name, + }, + }; + } + + public getSSTAWSPermissions(): FunctionPermissionArgs { + return { + actions: ["lambda:InvokeFunction"], + resources: [this.function.arn], + }; + } + /** @internal */ public getConstructMetadata() { return { diff --git a/internal/components/src/components/ssr-site.ts b/internal/components/src/components/ssr-site.ts index fb0e4377b..6c3456cde 100644 --- a/internal/components/src/components/ssr-site.ts +++ b/internal/components/src/components/ssr-site.ts @@ -15,7 +15,12 @@ import { } from "@pulumi/pulumi"; import * as aws from "@pulumi/aws"; import { Cdn, CdnDomainArgs } from "./cdn.js"; -import { Function, FunctionArgs, FunctionNodeJSArgs } from "./function.js"; +import { + Function, + FunctionArgs, + FunctionNodeJSArgs, + FunctionPermissionArgs, +} from "./function.js"; import { Duration, toSeconds } from "./util/duration.js"; import { DistributionInvalidation } from "./providers/distribution-invalidation.js"; import { useProvider } from "./helpers/aws/provider.js"; @@ -102,14 +107,31 @@ export interface SsrSiteArgs { */ domain?: Input; /** - * Attaches the given list of permissions to the SSR function. Configuring this property is equivalent to calling `attachPermissions()` after the site is created. + * Attaches the given list of permissions to the SSR function. + * @default No permissions + * @example + * ```js + * permissions: [ + * { + * actions: ["s3:*"], + * resources: ["arn:aws:s3:::*"], + * }, + * ] + * ``` + */ + permissions?: Input; + /** + * Link resources to the SSR function. + * This will grant the site permissions to access the linked resources at runtime. + * * @example * ```js - * permissions: ["ses"] + * { + * link: [myBucket, stripeKey], + * } * ``` */ - // TODO implement permissions - //permissions?: Input; + link?: Input; /** * An object with the key being the environment variable name. * @@ -605,23 +627,10 @@ function handler(event) { ...environment, ...props.environment, })), - policies: output(props.policies).apply((policies) => [ - { - name: "assets", - policy: bucket.arn.apply((arn) => - aws.iam - .getPolicyDocument({ - statements: [ - { - actions: ["s3:*"], - resources: [arn, `${arn}/*`], - }, - ], - }) - .then((doc) => doc.json) - ), - }, - ...(policies || []), + link: output(args.link).apply((link) => [ + bucket, + ...(props.link ?? []), + ...(link ?? []), ]), nodes: { function: { publish: true }, @@ -715,24 +724,11 @@ function handler(event) { ...(args.warm ? [useServerFunctionWarmingInjection()] : []), ...(injections || []), ]), - policies: [ - { - name: "assets", - policy: bucket.arn.apply((arn) => - aws.iam - .getPolicyDocument({ - statements: [ - { - actions: ["s3:*"], - resources: [arn, `${arn}/*`], - }, - ], - }) - .then((doc) => doc.json) - ), - }, - ...(props.function.policies || []), - ], + link: output(args.link).apply((link) => [ + bucket, + ...(props.function.link ?? []), + ...(link ?? []), + ]), url: true, }, { parent } @@ -763,21 +759,10 @@ function handler(event) { logging: { retention: "3 days", }, - policies: [ + permissions: [ { - name: "s3", - policy: bucket.arn.apply((arn) => - aws.iam - .getPolicyDocument({ - statements: [ - { - actions: ["s3:GetObject"], - resources: [`${arn}/*`], - }, - ], - }) - .then((doc) => doc.json) - ), + actions: ["s3:GetObject"], + resources: [interpolate`${bucket.arn}/*`], }, ], ...props.function, @@ -1031,23 +1016,7 @@ if (event.type === "warmer") { FUNCTION_NAME: ssrFunctions[0].nodes.function.name, CONCURRENCY: output(args.warm).apply((warm) => warm.toString()), }, - policies: [ - { - name: "invoke-server", - policy: ssrFunctions[0].nodes.function.arn.apply((arn) => - aws.iam - .getPolicyDocument({ - statements: [ - { - actions: ["lambda:InvokeFunction"], - resources: [arn], - }, - ], - }) - .then((doc) => doc.json) - ), - }, - ], + link: [ssrFunctions[0]], }, { parent } );