diff --git a/build.fsx b/build.fsx
index 0f4e64dfd..9464d94c2 100644
--- a/build.fsx
+++ b/build.fsx
@@ -161,6 +161,7 @@ Target "GenerateZipToSign" (fun _ ->
!! (buildDir @@ "/**/Microsoft.Azure.*.dll")
++ (buildDir @@ "func.exe")
+ ++ (buildDir @@ "azurefunctions/functions.js")
++ (buildDir @@ "azurefunctions/http/request.js")
++ (buildDir @@ "azurefunctions/http/response.js")
|> notSigned
@@ -246,6 +247,7 @@ Target "WaitForSigning" (fun _ ->
match signed with
| Success file ->
Unzip buildDir file
+ MoveFile (buildDir @@ "azurefunctions/") (buildDir @@ "functions.js")
MoveFile (buildDir @@ "azurefunctions/http/") (buildDir @@ "request.js")
MoveFile (buildDir @@ "azurefunctions/http/") (buildDir @@ "response.js")
| Failure e -> targetError e null |> ignore
diff --git a/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj b/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj
index 27c487bb5..12a26162d 100644
--- a/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj
+++ b/src/Azure.Functions.Cli/Azure.Functions.Cli.csproj
@@ -828,6 +828,9 @@
edge\edge.js
PreserveNewest
+
+ PreserveNewest
+
Always
diff --git a/src/Azure.Functions.Cli/azurefunctions/functions.js b/src/Azure.Functions.Cli/azurefunctions/functions.js
new file mode 100644
index 000000000..b9b320508
--- /dev/null
+++ b/src/Azure.Functions.Cli/azurefunctions/functions.js
@@ -0,0 +1,142 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+var util = require('util');
+var process = require('process');
+var request = require('./http/request');
+var response = require('./http/response');
+
+module.exports = {
+ globalInitialization: globalInitialization,
+ clearRequireCache: clearRequireCache,
+ createFunction: createFunction
+};
+
+function globalInitialization(context, callback) {
+ process.on('uncaughtException', function (err) {
+ context.handleUncaughtException(err.stack);
+ });
+ callback();
+}
+
+function clearRequireCache(context, callback) {
+ Object.keys(require.cache).forEach(function (key) {
+ delete require.cache[key];
+ });
+ callback();
+}
+
+function createFunction(f) {
+ return function (context, callback) {
+ // TEMP HACK: workaround for https://github.com/tjanczuk/edge/issues/325
+ setImmediate(() => { });
+
+ f = getEntryPoint(f, context);
+
+ // configure loggers
+ var origLog = context.log;
+ var logLevel = function (traceLevel) {
+ return function () {
+ var message = util.format.apply(null, arguments);
+ origLog({ lvl: traceLevel, msg: message });
+ };
+ };
+ // set default log to 'info'
+ var log = logLevel(3);
+ ['error', 'warn', 'info', 'verbose'].forEach((level, index) => {
+ var traceLevel = index + 1;
+ log[level] = logLevel(traceLevel);
+ });
+ context.log = log;
+
+ var origMetric = context._metric;
+ delete context._metric;
+ context.log.metric = function (name, value, properties) {
+ origMetric({ name: name, value: value, properties: properties});
+ };
+
+ context.done = function (err, returnValue) {
+ if (context._done) {
+ if (context._promise) {
+ context.log("Error: Choose either to return a promise or call 'done'. Do not use both in your script.");
+ } else {
+ context.log("Error: 'done' has already been called. Please check your script for extraneous calls to 'done'.");
+ }
+ return;
+ }
+ context._done = true;
+
+ if (err) {
+ callback(err);
+ }
+ else {
+ if (context.res && context.bindings.res === undefined) {
+ context.bindings.res = context.res;
+ }
+
+ // because Edge.JS interop doesn't flow new values added to objects,
+ // we capture the binding values and pass them back as part of the
+ // result
+ var bindingValues = {};
+ for (var name in context.bindings) {
+ bindingValues[name] = context.bindings[name];
+ }
+
+ var result = {
+ returnValue: returnValue,
+ bindingValues: bindingValues
+ };
+ callback(null, result);
+ }
+ };
+
+ var inputs = context._inputs;
+ inputs.unshift(context);
+ delete context._inputs;
+
+ var lowercaseTrigger = context._triggerType && context._triggerType.toLowerCase();
+ switch (lowercaseTrigger) {
+ case "httptrigger":
+ context.req = request(context);
+ context.res = response(context);
+ break;
+ }
+ delete context._triggerType;
+
+ var result = f.apply(null, inputs);
+ if (result && util.isFunction(result.then)) {
+ context._promise = true;
+ result.then((result) => context.done(null, result))
+ .catch((err) => context.done(err));
+ }
+ };
+}
+
+function getEntryPoint(f, context) {
+ if (util.isObject(f)) {
+ if (context._entryPoint) {
+ // the module exports multiple functions
+ // and an explicit entry point was named
+ f = f[context._entryPoint];
+ delete context._entryPoint;
+ }
+ else if (Object.keys(f).length === 1) {
+ // a single named function was exported
+ var name = Object.keys(f)[0];
+ f = f[name];
+ }
+ else {
+ // finally, see if there is an exported function named
+ // 'run' or 'index' by convention
+ f = f.run || f.index;
+ }
+ }
+
+ if (!util.isFunction(f)) {
+ throw "Unable to determine function entry point. If multiple functions are exported, " +
+ "you must indicate the entry point, either by naming it 'run' or 'index', or by naming it " +
+ "explicitly via the 'entryPoint' metadata property.";
+ }
+
+ return f;
+}
\ No newline at end of file