Skip to content

Commit

Permalink
fix(runtime-handler): add warning for optional context vars (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
dkundel authored Jul 19, 2021
1 parent 6b5bcf4 commit 47051de
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { ServerlessCallback } from '@twilio-labs/serverless-runtime-types/types';
import { serializeError } from 'serialize-error';
import { constructContext, constructGlobalScope, isTwiml } from '../route';
import {
augmentContextWithOptionals,
constructContext,
constructGlobalScope,
isTwiml,
} from '../route';
import { ServerConfig } from '../types';
import { Response } from './response';
import { setRoutes } from './route-cache';
Expand Down Expand Up @@ -62,8 +67,9 @@ process.on(
try {
setRoutes(config.routes);
constructGlobalScope(config);
const context = constructContext(config, path);
let context = constructContext(config, path);
sendDebugMessage('Context for %s: %p', path, context);
context = augmentContextWithOptionals(config, context);
sendDebugMessage('Event for %s: %o', path, event);
let run_timings: { start: [number, number]; end: [number, number] } = {
start: [0, 0],
Expand Down
66 changes: 65 additions & 1 deletion packages/runtime-handler/src/dev-runtime/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TwilioClientOptions,
TwilioPackage,
} from '@twilio-labs/serverless-runtime-types/types';
import chalk from 'chalk';
import { fork } from 'child_process';
import {
NextFunction,
Expand All @@ -23,6 +24,7 @@ import * as Runtime from './internal/runtime';
import { ServerConfig } from './types';
import debug from './utils/debug';
import { wrapErrorInHtml } from './utils/error-html';
import { getCodeLocation } from './utils/getCodeLocation';
import { requireFromProject } from './utils/requireFromProject';
import { cleanUpStackTrace } from './utils/stack-trace/clean-up';

Expand All @@ -39,6 +41,60 @@ export function constructEvent<T extends {} = {}>(req: ExpressRequest): T {
return { ...req.query, ...req.body };
}

export function augmentContextWithOptionals(
config: ServerConfig,
context: Context
): Context<{
ACCOUNT_SID?: string;
AUTH_TOKEN?: string;
DOMAIN_NAME: string;
PATH: string;
SERVICE_SID: string | undefined;
ENVIRONMENT_SID: string | undefined;
[key: string]: string | undefined | Function;
}> {
log('Adding getters with warnings to optional properties');
if (typeof context.SERVICE_SID === 'undefined') {
let _serviceSid: string | undefined = undefined;
Object.defineProperty(context, 'SERVICE_SID', {
get: () => {
if (_serviceSid === undefined) {
console.warn(
chalk`{bold.yellow WARNING} at ${getCodeLocation({
relativeFrom: config.baseDir,
offset: 1,
})} The SERVICE_SID variable is undefined by default in local development. This variable will be autopopulated when your Functions get deployed. Learn more at: https://twil.io/toolkit-variables`
);
}
return _serviceSid;
},
set: (value: string) => {
_serviceSid = value;
},
});
}
if (typeof context.ENVIRONMENT_SID === 'undefined') {
let _environmentSid: string | undefined = undefined;
Object.defineProperty(context, 'ENVIRONMENT_SID', {
get: () => {
if (_environmentSid === undefined) {
console.warn(
chalk`{bold.yellow WARNING} at ${getCodeLocation({
relativeFrom: config.baseDir,
offset: 1,
})}: The ENVIRONMENT_SID variable is undefined by default in local development. This variable will be autopopulated when your Functions get deployed. Learn more at: https://twil.io/toolkit-variables`
);
}
return _environmentSid;
},
set: (value: string) => {
_environmentSid = value;
},
});
}
return context;
}

export function constructContext<T extends {} = {}>(
{ url, env, logger, baseDir }: ServerConfig,
functionPath: string
Expand Down Expand Up @@ -74,7 +130,15 @@ export function constructContext<T extends {} = {}>(
}
const DOMAIN_NAME = url.replace(/^https?:\/\//, '');
const PATH = functionPath;
return { PATH, DOMAIN_NAME, ...env, getTwilioClient };
const context = {
PATH,
DOMAIN_NAME,
SERVICE_SID: undefined,
ENVIRONMENT_SID: undefined,
...env,
getTwilioClient,
};
return context;
}

export function constructGlobalScope(config: ServerConfig): void {
Expand Down
67 changes: 67 additions & 0 deletions packages/runtime-handler/src/dev-runtime/utils/getCodeLocation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os from 'os';
import path from 'path';

export type CodeLocation =
| {
line: null;
filePath: null;
column: null;
toString(): 'unknown';
}
| {
line: number;
column: number;
filePath: string;
toString(): string;
};

export const UNKNOWN_LOCATION = {
line: null,
filePath: null,
column: null,
toString: (): 'unknown' => {
return 'unknown';
},
};

const STACK_TRACE_REGEX = /.*\((?<fullFilePath>.*):(?<line>\d+):(?<column>\d+)\)$/i;

export function getCodeLocation(
options: { relativeFrom?: string; offset?: number } = {}
): CodeLocation {
options = { relativeFrom: undefined, offset: 0, ...options };
const fullStackTrace = new Error().stack;
if (typeof fullStackTrace !== 'string') {
return UNKNOWN_LOCATION;
}

const stackLines = fullStackTrace.split(os.EOL);
// add two to the offset because the first line is "Error" and the next is the location of this function.
const locationLine = stackLines[(options.offset || 0) + 2];

if (!locationLine) {
return UNKNOWN_LOCATION;
}

const match = STACK_TRACE_REGEX.exec(locationLine);
if (match === null) {
return UNKNOWN_LOCATION;
}

const line = parseInt(match.groups?.line || '0', 0);
const column = parseInt(match.groups?.column || '0', 0);
let filePath = match.groups?.fullFilePath || 'unknown';

if (options.relativeFrom) {
filePath = path.relative(options.relativeFrom, filePath);
}

const stringVersion = `${filePath}:${line}:${column}`;

return {
line,
column,
filePath,
toString: () => stringVersion,
};
}
3 changes: 3 additions & 0 deletions packages/serverless-runtime-types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export type RuntimeInstance = {
export type Context<T = {}> = {
getTwilioClient(options?: TwilioClientOptions): twilio.Twilio;
DOMAIN_NAME: string;
PATH: string;
SERVICE_SID: string | undefined;
ENVIRONMENT_SID: string | undefined;
} & T;

export type ServerlessCallback = (
Expand Down
2 changes: 1 addition & 1 deletion packages/twilio-run/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"license": "MIT",
"dependencies": {
"@twilio-labs/serverless-api": "^5.2.0",
"@twilio-labs/serverless-runtime-types": "^2.1.0",
"@twilio-labs/serverless-runtime-types": "2.1.0-rc.0",
"@types/express": "4.17.7",
"@types/inquirer": "^6.0.3",
"@types/is-ci": "^2.0.0",
Expand Down

0 comments on commit 47051de

Please sign in to comment.