-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathlambdaLoader.ts
126 lines (107 loc) · 3.44 KB
/
lambdaLoader.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import path from 'path'
import type { Handler } from 'aws-lambda'
import chalk from 'chalk'
import fg from 'fast-glob'
import type { Options as FastGlobOptions } from 'fast-glob'
import type {
FastifyReply,
FastifyRequest,
RequestGenericInterface,
} from 'fastify'
import { escape } from 'lodash'
import { getPaths } from '@redwoodjs/project-config'
import { requestHandler } from '../requestHandlers/awsLambdaFastify'
export type Lambdas = Record<string, Handler>
export const LAMBDA_FUNCTIONS: Lambdas = {}
// Import the API functions and add them to the LAMBDA_FUNCTIONS object
export const setLambdaFunctions = async (foundFunctions: string[]) => {
const tsImport = Date.now()
console.log(chalk.dim.italic('Importing Server Functions... '))
const imports = foundFunctions.map(async (fnPath) => {
const ts = Date.now()
const routeName = path.basename(fnPath).replace('.js', '')
const { handler } = await import(`file://${fnPath}`)
LAMBDA_FUNCTIONS[routeName] = handler
if (!handler) {
console.warn(
routeName,
'at',
fnPath,
'does not have a function called handler defined.',
)
}
// TODO: Use terminal link.
console.log(
chalk.magenta('/' + routeName),
chalk.dim.italic(Date.now() - ts + ' ms'),
)
})
await Promise.all(imports)
console.log(
chalk.dim.italic('...Done importing in ' + (Date.now() - tsImport) + ' ms'),
)
}
type LoadFunctionsFromDistOptions = {
fastGlobOptions?: FastGlobOptions
}
// TODO: Use v8 caching to load these crazy fast.
export const loadFunctionsFromDist = async (
options: LoadFunctionsFromDistOptions = {},
) => {
const serverFunctions = findApiDistFunctions(
getPaths().api.base,
options?.fastGlobOptions,
)
// Place `GraphQL` serverless function at the start.
const i = serverFunctions.findIndex((x) => x.includes('graphql'))
if (i >= 0) {
const graphQLFn = serverFunctions.splice(i, 1)[0]
serverFunctions.unshift(graphQLFn)
}
await setLambdaFunctions(serverFunctions)
}
// NOTE: Copied from @redwoodjs/internal/dist/files to avoid depending on @redwoodjs/internal.
// import { findApiDistFunctions } from '@redwoodjs/internal/dist/files'
function findApiDistFunctions(
cwd: string = getPaths().api.base,
options: FastGlobOptions = {},
) {
return fg.sync('dist/functions/**/*.{ts,js}', {
cwd,
deep: 2, // We don't support deeply nested api functions, to maximise compatibility with deployment providers
absolute: true,
...options,
})
}
interface LambdaHandlerRequest extends RequestGenericInterface {
Params: {
routeName: string
}
}
/**
This will take a fastify request
Then convert it to a lambdaEvent, and pass it to the the appropriate handler for the routeName
The LAMBDA_FUNCTIONS lookup has been populated already by this point
**/
export const lambdaRequestHandler = async (
req: FastifyRequest<LambdaHandlerRequest>,
reply: FastifyReply,
) => {
const { routeName } = req.params
if (!LAMBDA_FUNCTIONS[routeName]) {
const errorMessage = `Function "${routeName}" was not found.`
req.log.error(errorMessage)
reply.status(404)
if (process.env.NODE_ENV === 'development') {
const devError = {
error: errorMessage,
availableFunctions: Object.keys(LAMBDA_FUNCTIONS),
}
reply.send(devError)
} else {
reply.send(escape(errorMessage))
}
return
}
return requestHandler(req, reply, LAMBDA_FUNCTIONS[routeName])
}