gentle-rose-31959
10/22/2025, 3:03 PMgentle-rose-31959
10/22/2025, 3:06 PM.PHONY: build clean deploy
build:
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
SOURCE_DATE_EPOCH=0 \
go build -trimpath -buildvcs=false -ldflags="-buildid= -s -w" -tags=lambda.norpc -o bootstrap .
clean:
rm -f bootstrap
deploy: clean build
this is my make commandmodern-zebra-45309
10/22/2025, 3:20 PMstocky-restaurant-98004
10/22/2025, 3:33 PMaws.lambda.Function resource as well?gentle-rose-31959
10/22/2025, 3:41 PM// biome-ignore lint/performance/noNamespaceImport: node convention
import * as path from 'node:path'
// biome-ignore lint/performance/noNamespaceImport: pulumi convention
import * as aws from '@pulumi/aws'
// biome-ignore lint/performance/noNamespaceImport: pulumi convention
import * as pulumi from '@pulumi/pulumi'
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'
const DEFAULT_MEMORY_SIZE_MB = 256
const DEFAULT_TIMEOUT_SECONDS = 10
const MB_TO_KB = 1024
export interface LambdaHttpRouteArgs {
httpApi: aws.apigatewayv2.Api
routePath: string
methods: HttpMethod[]
handlerPath: string
runtime: aws.lambda.Runtime
handler: string
architecture?: 'x86_64' | 'arm64'
subnetIds: pulumi.Input<string[]>
securityGroupIds: pulumi.Input<string[]>
memorySizeMb?: number
timeoutSeconds?: number
existingRoleArn: pulumi.Input<string>
authorizerId?: pulumi.Input<string>
environment?: Record<string, pulumi.Input<string>>
layers?: pulumi.Input<string[]>
ephemeralStorageGb?: number
// Image package type options (alternative to Zip)
packageType?: 'Zip' | 'Image'
imageUri?: pulumi.Input<string>
}
export class LambdaHttpRoute extends pulumi.ComponentResource {
readonly function: aws.lambda.Function
readonly routes: aws.apigatewayv2.Route[]
constructor(name: string, args: LambdaHttpRouteArgs, opts?: pulumi.ComponentResourceOptions) {
super('pkg:foundation:api:LambdaHttpRoute', name, {}, opts)
const packageType = args.packageType ?? 'Zip'
if (packageType === 'Image' && !args.imageUri) {
throw new Error('imageUri is required when packageType is Image')
}
const baseFunctionArgs = {
role: args.existingRoleArn,
architectures: args.architecture ? [args.architecture] : undefined,
memorySize: args.memorySizeMb ?? DEFAULT_MEMORY_SIZE_MB,
timeout: args.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS,
environment: args.environment ? { variables: args.environment } : undefined,
vpcConfig: {
subnetIds: args.subnetIds,
securityGroupIds: args.securityGroupIds,
},
ephemeralStorage: args.ephemeralStorageGb
? { size: args.ephemeralStorageGb * MB_TO_KB }
: undefined,
}
const functionArgs =
packageType === 'Image'
? {
...baseFunctionArgs,
packageType: 'Image' as const,
imageUri: args.imageUri,
}
: {
...baseFunctionArgs,
packageType: 'Zip' as const,
runtime: args.runtime,
handler: args.handler,
code: new pulumi.asset.AssetArchive({
// The key becomes the filename inside the Zip uploaded to Lambda
bootstrap: new pulumi.asset.FileAsset(path.join(args.handlerPath, 'bootstrap')),
}),
layers: args.layers,
}
this.function = new aws.lambda.Function(`${name}-fn`, functionArgs, {
parent: this,
})
const integration = new aws.apigatewayv2.Integration(
`${name}-int`,
{
apiId: args.httpApi.id,
integrationType: 'AWS_PROXY',
integrationUri: this.function.arn,
payloadFormatVersion: '2.0',
},
{ parent: this }
)
this.routes = args.methods.map(
(method) =>
new aws.apigatewayv2.Route(
`${name}-route-${method.toLowerCase()}`,
{
apiId: args.httpApi.id,
routeKey: `${method} /${args.routePath}`,
target: pulumi.interpolate`integrations/${integration.id}`,
authorizationType: args.authorizerId ? 'JWT' : 'NONE',
authorizerId: args.authorizerId,
},
{ parent: this }
)
)
const accountId = pulumi.output(aws.getCallerIdentity()).apply((i) => i.accountId)
new aws.lambda.Permission(
`${name}-invoke`,
{
action: 'lambda:InvokeFunction',
function: this.function.name,
principal: '<http://apigateway.amazonaws.com|apigateway.amazonaws.com>',
sourceArn: pulumi.interpolate`arn:aws:execute-api:${aws.config.region}:${accountId}:${args.httpApi.id}/*/*/${args.routePath}`,
},
{ parent: this }
)
this.registerOutputs({
function: this.function,
routes: this.routes,
})
}
}gentle-rose-31959
10/22/2025, 3:42 PM/** biome-ignore-all lint/performance/noNamespaceImport: pulumi said so */
import type * as aws from '@pulumi/aws'
import type * as pulumi from '@pulumi/pulumi'
import type { SharedHttpApi } from '../../constructs/foundation/api'
import { LambdaHttpRoute } from '../../constructs/foundation/api'
export type RoleType =
| 'adminDbRead'
| 'appDbRead'
| 'appDbReadSqsSend'
| 'adminS3List'
| 'fileUpload'
| 'fileProcessor'
export interface RouteDef {
name: string
path: string
methods: ('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH')[]
handlerPath: string
role: RoleType
timeoutSeconds?: number
memorySizeMb?: number
env?: Record<string, pulumi.Input<string>>
}
interface RouteContext {
api: SharedHttpApi
authorizerId: pulumi.Input<string> | undefined
vpc: {
subnetIds: pulumi.Input<string[]>
}
securityGroupIds: pulumi.Input<string[]>
roles: Partial<Record<RoleType, aws.iam.Role>>
baseEnv: Record<string, pulumi.Input<string>>
}
const DEFAULT_TIMEOUT_SECONDS = 30
export function createRoutes(defs: RouteDef[], ctx: RouteContext) {
return defs.map((d) => {
const role = ctx.roles[d.role]
if (!role) {
throw new Error(`Role '${d.role}' not found in context for route '${d.name}'`)
}
return new LambdaHttpRoute(d.name, {
httpApi: ctx.api.api,
routePath: d.path,
methods: d.methods,
handlerPath: d.handlerPath,
runtime: 'provided.al2023',
architecture: 'arm64',
handler: 'bootstrap',
subnetIds: ctx.vpc.subnetIds,
authorizerId: ctx.authorizerId,
existingRoleArn: role.arn,
environment: { ...ctx.baseEnv, ...(d.env ?? {}) },
securityGroupIds: ctx.securityGroupIds,
timeoutSeconds: d.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS,
memorySizeMb: d.memorySizeMb,
})
})
}gentle-rose-31959
10/22/2025, 3:42 PMexport const appRoutes: RouteDef[] = [
{
name: 'app-projects-get',
path: 'projects',
methods: ['GET'],
handlerPath: '../app/lambda/app/projects/get',
role: 'appDbRead',
},......gentle-rose-31959
10/22/2025, 3:42 PMstocky-restaurant-98004
10/22/2025, 3:45 PMpulumi preview --diffgentle-rose-31959
10/22/2025, 4:51 PM}
- lastModified: "2025-10-22T02:32:45.000+0000"
~ aws:lambda/function:Function: (update)
[id=app-parcels-autocomplete-get-fn-c23fa10]
[urn=urn:pulumi:development::backend::pkg:foundation:api:LambdaHttpRoute$aws:lambda/function:Function::app-parcels-autocomplete-get-fn]
[provider=urn:pulumi:development::backend::pulumi:providers:aws::default_7_8_0::4bd3c38a-dae2-4ba1-b341-71f829fdb3d5]
~ code : archive(assets:c550b59->544514b) {
~ "bootstrap": asset(file:9534128->2058616) { ../app/lambda/app/parcels/autocomplete/get/bootstrap }
}
- lastModified: "2025-10-22T02:32:36.000+0000"
~ aws:lambda/function:Function: (update)
[id=admin-data-parcels-id-coordinates-get-fn-b13c58c]
[urn=urn:pulumi:development::backend::pkg:foundation:api:LambdaHttpRoute$aws:lambda/function:Function::admin-data-parcels-id-coordinates-get-fn]
[provider=urn:pulumi:development::backend::pulumi:providers:aws::default_7_8_0::4bd3c38a-dae2-4ba1-b341-71f829fdb3d5]
~ code : archive(assets:d9790c1->3614bc2) {
~ "bootstrap": asset(file:6164dd5->d44a053) { ../app/lambda/admin/data/parcels/$parcel_id/coordinates/get/bootstrap }
}
- lastModified: "2025-10-22T02:32:35.000+0000"
~ aws:lambda/function:Function: (update)
[id=app-users-recent-projects-get-fn-32dbe31]
[urn=urn:pulumi:development::backend::pkg:foundation:api:LambdaHttpRoute$aws:lambda/function:Function::app-users-recent-projects-get-fn]
[provider=urn:pulumi:development::backend::pulumi:providers:aws::default_7_8_0::4bd3c38a-dae2-4ba1-b341-71f829fdb3d5]
~ code : archive(assets:0085a6a->cab8fb0) {
~ "bootstrap": asset(file:2fbe49c->1902c19) { ../app/lambda/app/users/recent-projects/get/bootstrap }
}
- lastModified: "2025-10-22T02:32:48.000+0000"
~ aws:lambda/function:Function: (update)
[id=app-projects-id-reports-id-get-fn-883be31]
[urn=urn:pulumi:development::backend::pkg:foundation:api:LambdaHttpRoute$aws:lambda/function:Function::app-projects-id-reports-id-get-fn]
[provider=urn:pulumi:development::backend::pulumi:providers:aws::default_7_8_0::4bd3c38a-dae2-4ba1-b341-71f829fdb3d5]
~ code : archive(assets:e93ab7e->58da86c) {
~ "bootstrap": asset(file:008f72d->f8b3be1) { ../app/lambda/app/projects/{project_id}/reports/$report_id/get/bootstrap }
}
- lastModified: "2025-10-22T02:32:37.000+0000"
here is a snippet of it (its just this like 200 timesstocky-restaurant-98004
10/22/2025, 6:19 PMmodern-zebra-45309
10/22/2025, 6:19 PMbootstrap or update only specific resources using the --target option of the Pulumi CLI.modern-zebra-45309
10/22/2025, 6:19 PMgentle-rose-31959
10/22/2025, 6:20 PMmodern-zebra-45309
10/22/2025, 6:21 PMmodern-zebra-45309
10/22/2025, 6:23 PMcalm-intern-65863
10/23/2025, 1:30 PMmodern-zebra-45309
10/23/2025, 1:47 PMcalm-intern-65863
10/23/2025, 2:54 PMcalm-intern-65863
10/23/2025, 2:59 PMmodern-zebra-45309
10/23/2025, 3:02 PMcalm-intern-65863
10/23/2025, 3:03 PMcalm-intern-65863
10/23/2025, 3:03 PMmodern-zebra-45309
10/23/2025, 3:03 PMcalm-intern-65863
10/23/2025, 3:03 PMcalm-intern-65863
10/23/2025, 3:04 PMcalm-intern-65863
10/30/2025, 4:30 PMmodern-zebra-45309
10/30/2025, 4:39 PM