Skip to content

Commit 9ecb93e

Browse files
committed
feat: add TypeScript type definitions
This commit adds type definitions for the following: * `Invokable`: The user provided function * `Context`: The invocation context * `CloudEventResponse`: Convenience class for constructing events * `Logger`: The logging interface * `LogLevel`: Logging enumeration * `start`: A function to start the invoker * `InvokerOptions`: Options for `start` The definitions are statically tested with `tsd`. These type definitions are not actually used by the JS files. This does not convert the module to TypeScript; it just adds these type definitions to our exports. This will allow us to create TypeScript function templates without a full conversion of this code base to TypeScript. Ultimately, I think it's probably best to make the change. This change also bumps to `[email protected]` which does have a breaking change. See: cloudevents/sdk-javascript#332 As a result, we accept all versions of CloudEvents. Actually, I think this is probably a fine change in the long run. Loose validation upon receipt of an event allows functions to handle event sources that may be producing malformed events. I've commented out the test for now. If we decide it makes sense to leave this as-is instead of waiting for a fix from upstream, then we should remove the test and the existing logic for dealing with this, since it's no longer necessary. Finally, I've really simplified the `start` funtion interface. It now just takes a function and a bag of options. It doesn't deal with callbacks anymore. Promises are used to deal with async server startup. Signed-off-by: Lance Ball <[email protected]>
1 parent 4ea93d6 commit 9ecb93e

12 files changed

+2139
-390
lines changed

.eslintrc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
{
2-
"extends": "eslint:recommended",
2+
"parser": "@typescript-eslint/parser",
3+
"parserOptions": {
4+
"ecmaVersion": 2020,
5+
"sourceType": "module"
6+
},
7+
"extends": [
8+
"prettier"
9+
],
310
"env": {
411
"es2020": true,
512
"node": true
613
},
7-
"parser": "babel-eslint",
814
"rules": {
915
"standard/no-callback-literal": "off",
1016
"arrow-spacing": "error",

index.d.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Server } from 'http';
2+
import { Context } from './lib/context';
3+
4+
export declare const start: {
5+
(func: Invokable, options: InvokerOptions): Promise<Server>
6+
}
7+
8+
export type InvokerOptions = {
9+
'logLevel': LogLevel,
10+
'port': Number
11+
}
12+
13+
export enum LogLevel {
14+
'debug', 'info', 'warn', 'error'
15+
}
16+
17+
export interface Invokable {
18+
(context: Context, data?:string|Record<string, any>): any
19+
}
20+
21+
// re-export
22+
export { Context, Logger, CloudEventResponse } from './lib/context';

index.js

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,9 @@ const fastify = require('fastify');
1010

1111
const DEFAULT_PORT = 8080;
1212

13-
function start(func, port, cb, options) {
14-
switch (typeof port) {
15-
case 'function':
16-
options = cb;
17-
cb = port;
18-
port = DEFAULT_PORT;
19-
break;
20-
case 'undefined':
21-
port = DEFAULT_PORT;
22-
break;
23-
}
24-
const { logLevel = 'info' } = { ...options };
13+
// Invoker
14+
function start(func, options) {
15+
const { logLevel = 'warn', port = DEFAULT_PORT } = { ...options };
2516

2617
const server = fastify({ logger: { level: logLevel } });
2718

@@ -56,7 +47,6 @@ function start(func, port, cb, options) {
5647
return new Promise((resolve, reject) => {
5748
server.listen(port, '0.0.0.0', err => {
5849
if (err) return reject(err);
59-
if (cb) cb(server.server);
6050
resolve(server.server);
6151
});
6252
});

lib/context.d.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { IncomingHttpHeaders, IncomingMessage } from 'http';
2+
import { CloudEvent } from 'cloudevents';
3+
4+
export interface Logger {
5+
debug: (msg: any) => void,
6+
info: (msg: any) => void,
7+
warn: (msg: any) => void,
8+
error: (msg: any) => void,
9+
fatal: (msg: any) => void,
10+
trace: (msg: any) => void,
11+
}
12+
13+
export interface Context {
14+
log: Logger;
15+
req: IncomingMessage;
16+
query?: Record<string, any>;
17+
body?: Record<string, any>|string;
18+
method: string;
19+
headers: IncomingHttpHeaders;
20+
httpVersion: string;
21+
httpVersionMajor: number;
22+
httpVersionMinor: number;
23+
cloudEventResponse(data: string|object): CloudEventResponse;
24+
}
25+
26+
export interface CloudEventResponse {
27+
id(id: string): CloudEventResponse;
28+
source(source: string): CloudEventResponse;
29+
type(type: string): CloudEventResponse;
30+
version(version: string): CloudEventResponse;
31+
response(): CloudEvent;
32+
}

lib/event-handler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ function use(fastify, opts, done) {
1515
if (request.isCloudEvent()) {
1616
try {
1717
request.fcontext.cloudevent = HTTP.toEvent(request);
18+
request.fcontext.cloudevent.validate();
1819
} catch (err) {
1920
if (err.message.startsWith('invalid spec version')) {
2021
reply.code(406);

0 commit comments

Comments
 (0)