Skip to content

Commit

Permalink
feat: validate edge function signature at build time (#200)
Browse files Browse the repository at this point in the history
* feat: validate edge function signature at build time
  • Loading branch information
jackiewmacharia committed Nov 18, 2022
1 parent 311ab7c commit 2f81b01
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 0 deletions.
4 changes: 4 additions & 0 deletions deno/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ try {
Deno.exit(exitCodes.ImportError)
}

if (typeof func.default !== 'function') {
Deno.exit(exitCodes.InvalidDefaultExport)
}

if (func.config === undefined) {
Deno.exit(exitCodes.NoConfig)
}
Expand Down
113 changes: 113 additions & 0 deletions node/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const importMapFile = {
},
}

const invalidDefaultExportErr = (path: string) =>
`Default export in '${path}' must be a function. More on the Edge Functions API at https://ntl.fyi/edge-api.`

test('`getFunctionConfig` extracts configuration properties from function file', async () => {
const { path: tmpDir } = await tmp.dir()
const deno = new DenoBridge({
Expand Down Expand Up @@ -219,3 +222,113 @@ test('Loads function paths from the in-source `config` function', async () => {

await fs.rmdir(tmpDir.path, { recursive: true })
})

test('Passes validation if default export exists and is a function', async () => {
const { path: tmpDir } = await tmp.dir()
const deno = new DenoBridge({
cacheDirectory: tmpDir,
})

const func = {
name: 'func1',
source: `
const func = () => new Response("Hello world!")
export default func
`,
}

const logger = {
user: vi.fn().mockResolvedValue(null),
system: vi.fn().mockResolvedValue(null),
}
const path = join(tmpDir, `${func.name}.ts`)

await fs.writeFile(path, func.source)

expect(async () => {
await getFunctionConfig(
{
name: func.name,
path,
},
new ImportMap([importMapFile]),
deno,
logger,
)
}).not.toThrow()

await deleteAsync(tmpDir, { force: true })
})

test('Fails validation if default export is not function', async () => {
const { path: tmpDir } = await tmp.dir()
const deno = new DenoBridge({
cacheDirectory: tmpDir,
})

const func = {
name: 'func2',
source: `
const func = new Response("Hello world!")
export default func
`,
}

const logger = {
user: vi.fn().mockResolvedValue(null),
system: vi.fn().mockResolvedValue(null),
}
const path = join(tmpDir, `${func.name}.ts`)

await fs.writeFile(path, func.source)

const config = getFunctionConfig(
{
name: func.name,
path,
},
new ImportMap([importMapFile]),
deno,
logger,
)

await expect(config).rejects.toThrowError(invalidDefaultExportErr(path))

await deleteAsync(tmpDir, { force: true })
})

test('Fails validation if default export is not present', async () => {
const { path: tmpDir } = await tmp.dir()
const deno = new DenoBridge({
cacheDirectory: tmpDir,
})

const func = {
name: 'func3',
source: `
export const func = () => new Response("Hello world!")
`,
}

const logger = {
user: vi.fn().mockResolvedValue(null),
system: vi.fn().mockResolvedValue(null),
}
const path = join(tmpDir, `${func.name}.ts`)

await fs.writeFile(path, func.source)

const config = getFunctionConfig(
{
name: func.name,
path,
},
new ImportMap([importMapFile]),
deno,
logger,
)

await expect(config).rejects.toThrowError(invalidDefaultExportErr(path))

await deleteAsync(tmpDir, { force: true })
})
6 changes: 6 additions & 0 deletions node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum ConfigExitCode {
InvalidExport,
RuntimeError,
SerializationError,
InvalidDefaultExport,
}

export const enum Cache {
Expand Down Expand Up @@ -121,6 +122,11 @@ const logConfigError = (func: EdgeFunction, exitCode: number, stderr: string, lo

break

case ConfigExitCode.InvalidDefaultExport:
throw new Error(
`Default export in '${func.path}' must be a function. More on the Edge Functions API at https://ntl.fyi/edge-api.`,
)

default:
log.user(`Could not load configuration for edge function at '${func.path}'`)
log.user(stderr)
Expand Down

0 comments on commit 2f81b01

Please sign in to comment.