Socket
Socket
Sign inDemoInstall

@google-cloud/functions-framework

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@google-cloud/functions-framework - npm Package Compare versions

Comparing version 3.2.1 to 3.3.0

14

build/src/function_registry.d.ts

@@ -1,6 +0,6 @@

import { HttpFunction, CloudEventFunction, HandlerFunction } from './functions';
import { HttpFunction, CloudEventFunction, HandlerFunction, TypedFunction } from './functions';
import { SignatureType } from './types';
interface RegisteredFunction<T> {
interface RegisteredFunction<T, U> {
signatureType: SignatureType;
userFunction: HandlerFunction<T>;
userFunction: HandlerFunction<T, U>;
}

@@ -23,3 +23,3 @@ /**

*/
export declare const getRegisteredFunction: (functionName: string) => RegisteredFunction<any> | undefined;
export declare const getRegisteredFunction: (functionName: string) => RegisteredFunction<any, any> | undefined;
/**

@@ -39,3 +39,9 @@ * Register a function that responds to HTTP requests.

export declare const cloudEvent: <T = unknown>(functionName: string, handler: CloudEventFunction<T>) => void;
/**
* Register a function that handles strongly typed invocations.
* @param functionName - the name of the function
* @param handler - the function to trigger
*/
export declare const typed: <T, U>(functionName: string, handler: TypedFunction<T, U> | ((req: T) => U | Promise<U>)) => void;
export {};
//# sourceMappingURL=function_registry.d.ts.map

@@ -16,3 +16,4 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.cloudEvent = exports.http = exports.getRegisteredFunction = exports.isValidFunctionName = void 0;
exports.typed = exports.cloudEvent = exports.http = exports.getRegisteredFunction = exports.isValidFunctionName = void 0;
const functions_1 = require("./functions");
/**

@@ -82,2 +83,17 @@ * Singleton map to hold the registered functions

exports.cloudEvent = cloudEvent;
/**
* Register a function that handles strongly typed invocations.
* @param functionName - the name of the function
* @param handler - the function to trigger
*/
const typed = (functionName, handler) => {
if (handler instanceof Function) {
handler = {
handler,
format: new functions_1.JsonInvocationFormat(),
};
}
register(functionName, 'typed', handler);
};
exports.typed = typed;
//# sourceMappingURL=function_registry.js.map

@@ -86,4 +86,3 @@ "use strict";

const d = domain.create();
// Catch unhandled errors originating from this request.
d.on('error', err => {
const errorHandler = (err) => {
if (res.locals.functionExecutionFinished) {

@@ -96,6 +95,12 @@ console.error(`Exception from a finished function: ${err}`);

}
});
};
// Catch unhandled errors originating from this request.
d.on('error', errorHandler);
d.run(() => {
process.nextTick(() => {
execute(req, res);
const ret = execute(req, res);
// Catch rejected promises if the function is async.
if (ret instanceof Promise) {
ret.catch(errorHandler);
}
});

@@ -149,3 +154,3 @@ });

/**
* Wraps an callback style event function in an express RequestHandler.
* Wraps a callback style event function in an express RequestHandler.
* @param userFunction User's function.

@@ -163,2 +168,29 @@ * @return An Express hander function that invokes the user function.

/**
* Wraps a typed function in an express style RequestHandler.
* @param userFunction User's function
* @return An Express handler function that invokes the user function
*/
const wrapTypedFunction = (typedFunction) => {
const typedHandlerWrapper = async (req, res) => {
let reqTyped;
try {
reqTyped = typedFunction.format.deserializeRequest(new InvocationRequestImpl(req));
}
catch (err) {
(0, logger_1.sendCrashResponse)({
err,
res,
statusOverride: 400, // 400 Bad Request
});
return;
}
let resTyped = typedFunction.handler(reqTyped);
if (resTyped instanceof Promise) {
resTyped = await resTyped;
}
typedFunction.format.serializeResponse(new InvocationResponseImpl(res), resTyped);
};
return wrapHttpFunction(typedHandlerWrapper);
};
/**
* Wraps a user function with the provided signature type in an express

@@ -175,3 +207,3 @@ * RequestHandler.

// Callback style if user function has more than 2 arguments.
if (userFunction.length > 2) {
if (userFunction instanceof Function && userFunction.length > 2) {
return wrapEventFunctionWithCallback(userFunction);

@@ -181,3 +213,3 @@ }

case 'cloudevent':
if (userFunction.length > 1) {
if (userFunction instanceof Function && userFunction.length > 1) {
// Callback style if user function has more than 1 argument.

@@ -187,5 +219,38 @@ return wrapCloudEventFunctionWithCallback(userFunction);

return wrapCloudEventFunction(userFunction);
case 'typed':
return wrapTypedFunction(userFunction);
}
};
exports.wrapUserFunction = wrapUserFunction;
/**
* @private
*/
class InvocationRequestImpl {
constructor(req) {
this.req = req;
}
body() {
return this.req.body;
}
header(header) {
return this.req.header(header);
}
}
/**
* @private
*/
class InvocationResponseImpl {
constructor(res) {
this.res = res;
}
setHeader(key, value) {
this.res.set(key, value);
}
write(data) {
this.res.write(data);
}
end(data) {
this.res.end(data);
}
}
//# sourceMappingURL=function_wrappers.js.map

@@ -57,6 +57,14 @@ /// <reference types="node" />

/**
* A Typed function handler that may return a value or a promise.
* @public
*/
export interface TypedFunction<T = unknown, U = unknown> {
handler: (req: T) => U | Promise<U>;
format: InvocationFormat<T, U>;
}
/**
* A function handler.
* @public
*/
export type HandlerFunction<T = unknown> = HttpFunction | EventFunction | EventFunctionWithCallback | CloudEventFunction<T> | CloudEventFunctionWithCallback<T>;
export type HandlerFunction<T = unknown, U = unknown> = HttpFunction | EventFunction | EventFunctionWithCallback | CloudEventFunction<T> | CloudEventFunctionWithCallback<T> | TypedFunction<T, U>;
/**

@@ -115,2 +123,52 @@ * A legacy event.

export type Context = CloudFunctionsContext | CloudEvent<unknown>;
/**
* InvocationRequest represents the properties of an invocation over HTTP.
* @public
*/
export interface InvocationRequest {
/** Returns the request body as either a string or a Buffer if the body is binary. */
body(): string | Buffer;
/** Header returns the value of the specified header */
header(header: string): string | undefined;
}
/**
* InvocationResponse interface describes the properties that can be set on
* an invocation response.
* @public
*/
export interface InvocationResponse {
/** Sets a header on the response. */
setHeader(key: string, value: string): void;
/** Writes a chunk of data to the response. */
write(data: string | Buffer): void;
/** Ends the response, must be called once at the end of writing. */
end(data: string | Buffer): void;
}
/**
* The contract for a request deserializer and response serializer.
* @public
*/
export interface InvocationFormat<T, U> {
/**
* Creates an instance of the request type from an invocation request.
*
* @param request the request body as raw bytes
*/
deserializeRequest(request: InvocationRequest): T | Promise<T>;
/**
* Writes the response type to the invocation result.
*
* @param responseWriter interface for writing to the invocation result
* @param response the response object
*/
serializeResponse(responseWriter: InvocationResponse, response: U): void | Promise<void>;
}
/**
* Default invocation format for JSON requests.
* @public
*/
export declare class JsonInvocationFormat<T, U> implements InvocationFormat<T, U> {
deserializeRequest(request: InvocationRequest): T;
serializeResponse(responseWriter: InvocationResponse, response: U): void;
}
//# sourceMappingURL=functions.d.ts.map

@@ -16,2 +16,27 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.JsonInvocationFormat = void 0;
/**
* Default invocation format for JSON requests.
* @public
*/
class JsonInvocationFormat {
deserializeRequest(request) {
const body = request.body();
if (typeof body !== 'string') {
throw new Error('Unsupported Content-Type, expected application/json');
}
try {
return JSON.parse(body);
}
catch (e) {
throw new Error('Failed to parse malformatted JSON in request: ' +
e.message);
}
}
serializeResponse(responseWriter, response) {
responseWriter.setHeader('content-type', 'application/json');
responseWriter.end(JSON.stringify(response));
}
}
exports.JsonInvocationFormat = JsonInvocationFormat;
//# sourceMappingURL=functions.js.map

@@ -8,3 +8,3 @@ /**

*/
export { http, cloudEvent } from './function_registry';
export { http, cloudEvent, typed } from './function_registry';
//# sourceMappingURL=index.d.ts.map

@@ -30,3 +30,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.cloudEvent = exports.http = void 0;
exports.typed = exports.cloudEvent = exports.http = void 0;
/**

@@ -42,2 +42,3 @@ * @public

Object.defineProperty(exports, "cloudEvent", { enumerable: true, get: function () { return function_registry_1.cloudEvent; } });
Object.defineProperty(exports, "typed", { enumerable: true, get: function () { return function_registry_1.typed; } });
//# sourceMappingURL=index.js.map

@@ -9,3 +9,3 @@ import * as express from 'express';

*/
export declare function sendCrashResponse({ err, res, callback, silent, statusHeader, }: {
export declare function sendCrashResponse({ err, res, callback, silent, statusHeader, statusOverride, }: {
err: Error | any;

@@ -16,3 +16,4 @@ res: express.Response | null;

statusHeader?: string;
statusOverride?: number;
}): void;
//# sourceMappingURL=logger.d.ts.map

@@ -25,3 +25,3 @@ "use strict";

*/
function sendCrashResponse({ err, res, callback, silent = false, statusHeader = 'crash', }) {
function sendCrashResponse({ err, res, callback, silent = false, statusHeader = 'crash', statusOverride = 500, }) {
if (!silent) {

@@ -37,7 +37,7 @@ console.error(err.stack || err);

if (process.env.NODE_ENV !== 'production') {
res.status(500);
res.status(statusOverride);
res.send((err.message || err) + '');
}
else {
res.sendStatus(500);
res.sendStatus(statusOverride);
}

@@ -44,0 +44,0 @@ }

@@ -78,4 +78,14 @@ "use strict";

// Apply middleware
app.use(bodyParser.json(cloudEventsBodySavingOptions));
app.use(bodyParser.json(defaultBodySavingOptions));
if (functionSignatureType !== 'typed') {
// If the function is not typed then JSON parsing can be done automatically, otherwise the
// functions format must determine deserialization.
app.use(bodyParser.json(cloudEventsBodySavingOptions));
app.use(bodyParser.json(defaultBodySavingOptions));
}
else {
const jsonParserOptions = Object.assign({}, defaultBodySavingOptions, {
type: 'application/json',
});
app.use(bodyParser.text(jsonParserOptions));
}
app.use(bodyParser.text(defaultBodySavingOptions));

@@ -82,0 +92,0 @@ app.use(bodyParser.urlencoded(urlEncodedOptions));

@@ -5,3 +5,3 @@ export declare const FUNCTION_STATUS_HEADER_FIELD = "X-Google-Status";

*/
export declare const SignatureType: readonly ["http", "event", "cloudevent"];
export declare const SignatureType: readonly ["http", "event", "cloudevent", "typed"];
/**

@@ -16,3 +16,3 @@ * Union type of all valid function SignatureType values.

*/
export declare const isValidSignatureType: (x: any) => x is "event" | "http" | "cloudevent";
export declare const isValidSignatureType: (x: any) => x is "event" | "http" | "cloudevent" | "typed";
//# sourceMappingURL=types.d.ts.map

@@ -23,3 +23,3 @@ "use strict";

*/
exports.SignatureType = ['http', 'event', 'cloudevent'];
exports.SignatureType = ['http', 'event', 'cloudevent', 'typed'];
/**

@@ -26,0 +26,0 @@ * Type guard to test if a provided value is valid SignatureType

{
"name": "@google-cloud/functions-framework",
"version": "3.2.1",
"version": "3.3.0",
"description": "FaaS (Function as a service) framework for writing portable Node.js functions",

@@ -59,3 +59,3 @@ "engines": {

"@types/mocha": "9.1.1",
"@types/node": "14.18.43",
"@types/node": "14.18.52",
"@types/on-finished": "2.3.1",

@@ -62,0 +62,0 @@ "@types/semver": "^7.3.6",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc