firebase-functions 6.3.2 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,8 @@
23
23
  // SOFTWARE.
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  const express = require("express");
26
+ const fs = require("fs/promises");
27
+ const path = require("path");
26
28
  const loader_1 = require("../runtime/loader");
27
29
  const manifest_1 = require("../runtime/manifest");
28
30
  function printUsageAndExit() {
@@ -42,30 +44,76 @@ if (args.length > 1) {
42
44
  }
43
45
  functionsDir = args[0];
44
46
  }
45
- let server = undefined;
46
- const app = express();
47
- function handleQuitquitquit(req, res) {
47
+ function handleQuitquitquit(req, res, server) {
48
48
  res.send("ok");
49
49
  server.close();
50
50
  }
51
- app.get("/__/quitquitquit", handleQuitquitquit);
52
- app.post("/__/quitquitquit", handleQuitquitquit);
53
- if (process.env.FUNCTIONS_CONTROL_API === "true") {
54
- app.get("/__/functions.yaml", async (req, res) => {
51
+ if (process.env.FUNCTIONS_MANIFEST_OUTPUT_PATH) {
52
+ void (async () => {
53
+ var _a;
54
+ const outputPath = process.env.FUNCTIONS_MANIFEST_OUTPUT_PATH;
55
55
  try {
56
+ // Validate the output path
57
+ const dir = path.dirname(outputPath);
58
+ try {
59
+ await fs.access(dir, fs.constants.W_OK);
60
+ }
61
+ catch (e) {
62
+ console.error(`Error: Cannot write to directory '${dir}': ${e instanceof Error ? e.message : String(e)}`);
63
+ console.error("Please ensure the directory exists and you have write permissions.");
64
+ process.exit(1);
65
+ }
56
66
  const stack = await (0, loader_1.loadStack)(functionsDir);
57
- res.setHeader("content-type", "text/yaml");
58
- res.send(JSON.stringify((0, manifest_1.stackToWire)(stack)));
67
+ const wireFormat = (0, manifest_1.stackToWire)(stack);
68
+ await fs.writeFile(outputPath, JSON.stringify(wireFormat, null, 2));
69
+ process.exit(0);
59
70
  }
60
71
  catch (e) {
61
- console.error(e);
62
- res.status(400).send(`Failed to generate manifest from function source: ${e}`);
72
+ if (e.code === "ENOENT") {
73
+ console.error(`Error: Directory '${path.dirname(outputPath)}' does not exist.`);
74
+ console.error("Please create the directory or specify a valid path.");
75
+ }
76
+ else if (e.code === "EACCES") {
77
+ console.error(`Error: Permission denied writing to '${outputPath}'.`);
78
+ console.error("Please check file permissions or choose a different location.");
79
+ }
80
+ else if ((_a = e.message) === null || _a === void 0 ? void 0 : _a.includes("Failed to generate manifest")) {
81
+ console.error(e.message);
82
+ }
83
+ else {
84
+ console.error(`Failed to generate manifest from function source: ${e instanceof Error ? e.message : String(e)}`);
85
+ }
86
+ if (e instanceof Error && e.stack) {
87
+ console.error(e.stack);
88
+ }
89
+ process.exit(1);
63
90
  }
64
- });
91
+ })();
65
92
  }
66
- let port = 8080;
67
- if (process.env.PORT) {
68
- port = Number.parseInt(process.env.PORT);
93
+ else {
94
+ let server = undefined;
95
+ const app = express();
96
+ app.get("/__/quitquitquit", (req, res) => handleQuitquitquit(req, res, server));
97
+ app.post("/__/quitquitquit", (req, res) => handleQuitquitquit(req, res, server));
98
+ if (process.env.FUNCTIONS_CONTROL_API === "true") {
99
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
100
+ app.get("/__/functions.yaml", async (req, res) => {
101
+ try {
102
+ const stack = await (0, loader_1.loadStack)(functionsDir);
103
+ res.setHeader("content-type", "text/yaml");
104
+ res.send(JSON.stringify((0, manifest_1.stackToWire)(stack)));
105
+ }
106
+ catch (e) {
107
+ console.error(e);
108
+ const errorMessage = e instanceof Error ? e.message : String(e);
109
+ res.status(400).send(`Failed to generate manifest from function source: ${errorMessage}`);
110
+ }
111
+ });
112
+ }
113
+ let port = 8080;
114
+ if (process.env.PORT) {
115
+ port = Number.parseInt(process.env.PORT);
116
+ }
117
+ console.log("Serving at port", port);
118
+ server = app.listen(port);
69
119
  }
70
- console.log("Serving at port", port);
71
- server = app.listen(port);
@@ -99,6 +99,9 @@ class DataSnapshot {
99
99
  val() {
100
100
  const parts = (0, path_1.pathParts)(this._childPath);
101
101
  let source = this._data;
102
+ if (source === null) {
103
+ return null;
104
+ }
102
105
  if (parts.length) {
103
106
  for (const part of parts) {
104
107
  if (source[part] === undefined) {
@@ -1,3 +1,6 @@
1
+ /// <reference types="node" />
2
+ import { AsyncLocalStorage } from "async_hooks";
3
+ export declare const traceContext: AsyncLocalStorage<TraceContext>;
1
4
  export interface TraceContext {
2
5
  version: string;
3
6
  traceId: string;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.extractTraceContext = exports.traceContext = void 0;
4
4
  const async_hooks_1 = require("async_hooks");
5
- /* @internal */
6
5
  exports.traceContext = new async_hooks_1.AsyncLocalStorage();
7
6
  /**
8
7
  * A regex to match the Cloud Trace header.
@@ -55,6 +55,7 @@ function removeCircular(obj, refs = []) {
55
55
  returnObj[k] = removeCircular(obj[k], refs);
56
56
  }
57
57
  }
58
+ refs.pop();
58
59
  return returnObj;
59
60
  }
60
61
  /**
@@ -55,8 +55,8 @@ export interface EventContext<Params = Record<string, string>> {
55
55
  * does not exist.
56
56
  */
57
57
  auth?: {
58
- token: object;
59
58
  uid: string;
59
+ token: EventContextAuthToken;
60
60
  };
61
61
  /**
62
62
  * The level of permissions for a user.
@@ -152,6 +152,28 @@ export interface EventContext<Params = Record<string, string>> {
152
152
  */
153
153
  timestamp: string;
154
154
  }
155
+ /**
156
+ * https://firebase.google.com/docs/reference/security/database#authtoken
157
+ */
158
+ export interface EventContextAuthToken {
159
+ iss: string;
160
+ aud: string;
161
+ auth_time: number;
162
+ iat: number;
163
+ exp: number;
164
+ sub: string;
165
+ email?: string;
166
+ email_verified?: boolean;
167
+ phone_number?: string;
168
+ name?: string;
169
+ firebase?: {
170
+ identities?: {
171
+ [key: string]: string[];
172
+ };
173
+ sign_in_provider?: string;
174
+ tenant?: string;
175
+ };
176
+ }
155
177
  /**
156
178
  * Resource is a standard format for defining a resource
157
179
  * (google.rpc.context.AttributeContext.Resource). In Cloud Functions, it is the
package/lib/v2/index.d.ts CHANGED
@@ -22,6 +22,7 @@ export { alerts, database, storage, https, identity, pubsub, logger, tasks, even
22
22
  export { setGlobalOptions, GlobalOptions, SupportedRegion, MemoryOption, VpcEgressSetting, IngressSetting, EventHandlerOptions, } from "./options";
23
23
  export { CloudFunction, CloudEvent, ParamsOf, onInit } from "./core";
24
24
  export { Change } from "../common/change";
25
+ export { traceContext } from "../common/trace";
25
26
  import * as params from "../params";
26
27
  export { params };
27
28
  export { config } from "../v1/config";
package/lib/v2/index.js CHANGED
@@ -21,7 +21,7 @@
21
21
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  // SOFTWARE.
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.app = exports.config = exports.params = exports.Change = exports.onInit = exports.setGlobalOptions = exports.firestore = exports.testLab = exports.remoteConfig = exports.scheduler = exports.eventarc = exports.tasks = exports.logger = exports.pubsub = exports.identity = exports.https = exports.storage = exports.database = exports.alerts = void 0;
24
+ exports.app = exports.config = exports.params = exports.traceContext = exports.Change = exports.onInit = exports.setGlobalOptions = exports.firestore = exports.testLab = exports.remoteConfig = exports.scheduler = exports.eventarc = exports.tasks = exports.logger = exports.pubsub = exports.identity = exports.https = exports.storage = exports.database = exports.alerts = void 0;
25
25
  /**
26
26
  * The 2nd gen API for Cloud Functions for Firebase.
27
27
  * This SDK supports deep imports. For example, the namespace
@@ -61,6 +61,8 @@ var core_1 = require("./core");
61
61
  Object.defineProperty(exports, "onInit", { enumerable: true, get: function () { return core_1.onInit; } });
62
62
  var change_1 = require("../common/change");
63
63
  Object.defineProperty(exports, "Change", { enumerable: true, get: function () { return change_1.Change; } });
64
+ var trace_1 = require("../common/trace");
65
+ Object.defineProperty(exports, "traceContext", { enumerable: true, get: function () { return trace_1.traceContext; } });
64
66
  // NOTE: Equivalent to `export * as params from "../params"` but api-extractor doesn't support that syntax.
65
67
  const params = require("../params");
66
68
  exports.params = params;
@@ -134,11 +134,22 @@ export declare function setGlobalOptions(options: GlobalOptions): void;
134
134
  * Additional fields that can be set on any event-handling function.
135
135
  */
136
136
  export interface EventHandlerOptions extends Omit<GlobalOptions, "enforceAppCheck"> {
137
- /** Type of the event. Valid values are TODO */
137
+ /** Type of the event. */
138
138
  eventType?: string;
139
- /** TODO */
139
+ /**
140
+ * Filters events based on exact matches on the CloudEvents attributes.
141
+ *
142
+ * Each key-value pair represents an attribute name and its required value for exact matching.
143
+ * Events must match all specified filters to trigger the function.
144
+ */
140
145
  eventFilters?: Record<string, string | Expression<string>>;
141
- /** TODO */
146
+ /**
147
+ * Filters events based on path pattern matching on the CloudEvents attributes.
148
+ *
149
+ * Similar to eventFilters, but supports wildcard patterns for flexible matching where `*` matches
150
+ * any single path segment, `**` matches zero or more path segments, and `{param}` captures a path segment
151
+ * as a parameter
152
+ */
142
153
  eventFilterPathPatterns?: Record<string, string | Expression<string>>;
143
154
  /** Whether failed executions should be delivered again. */
144
155
  retry?: boolean | Expression<boolean> | ResetValue;
@@ -22,7 +22,7 @@ export interface HttpsOptions extends Omit<GlobalOptions, "region" | "enforceApp
22
22
  * If this is an `Array`, allows requests from domains matching at least one entry of the array.
23
23
  * Defaults to true for {@link https.CallableFunction} and false otherwise.
24
24
  */
25
- cors?: string | boolean | RegExp | Array<string | RegExp>;
25
+ cors?: string | Expression<string> | Expression<string[]> | boolean | RegExp | Array<string | RegExp>;
26
26
  /**
27
27
  * Amount of memory to allocate to a function.
28
28
  */
@@ -140,12 +140,12 @@ export interface CallableOptions<T = any> extends HttpsOptions {
140
140
  */
141
141
  heartbeatSeconds?: number | null;
142
142
  /**
143
- * @deprecated
144
- *
145
- * Callback for whether a request is authorized.
143
+ * (Deprecated) Callback for whether a request is authorized.
146
144
  *
147
145
  * Designed to allow reusable auth policies to be passed as an options object. Two built-in reusable policies exist:
148
146
  * isSignedIn and hasClaim.
147
+ *
148
+ * @deprecated
149
149
  */
150
150
  authPolicy?: (auth: AuthData | null, data: T) => boolean | Promise<boolean>;
151
151
  }
@@ -33,6 +33,7 @@ const debug_1 = require("../../common/debug");
33
33
  const https_1 = require("../../common/providers/https");
34
34
  Object.defineProperty(exports, "HttpsError", { enumerable: true, get: function () { return https_1.HttpsError; } });
35
35
  const manifest_1 = require("../../runtime/manifest");
36
+ const params_1 = require("../../params");
36
37
  const options = require("../options");
37
38
  const onInit_1 = require("../../common/onInit");
38
39
  const logger = require("../../logger");
@@ -68,7 +69,7 @@ function onRequest(optsOrHandler, handler) {
68
69
  opts = optsOrHandler;
69
70
  }
70
71
  if ((0, debug_1.isDebugFeatureEnabled)("enableCors") || "cors" in opts) {
71
- let origin = opts.cors;
72
+ let origin = opts.cors instanceof params_1.Expression ? opts.cors.value() : opts.cors;
72
73
  if ((0, debug_1.isDebugFeatureEnabled)("enableCors")) {
73
74
  // Respect `cors: false` to turn off cors even if debug feature is enabled.
74
75
  origin = opts.cors === false ? false : true;
@@ -146,7 +147,19 @@ function onCall(optsOrHandler, handler) {
146
147
  else {
147
148
  opts = optsOrHandler;
148
149
  }
149
- let origin = (0, debug_1.isDebugFeatureEnabled)("enableCors") ? true : "cors" in opts ? opts.cors : true;
150
+ let cors;
151
+ if ("cors" in opts) {
152
+ if (opts.cors instanceof params_1.Expression) {
153
+ cors = opts.cors.value();
154
+ }
155
+ else {
156
+ cors = opts.cors;
157
+ }
158
+ }
159
+ else {
160
+ cors = true;
161
+ }
162
+ let origin = (0, debug_1.isDebugFeatureEnabled)("enableCors") ? true : cors;
150
163
  // Arrays cause the access-control-allow-origin header to be dynamic based
151
164
  // on the origin header of the request. If there is only one element in the
152
165
  // array, this is unnecessary.
@@ -86,7 +86,6 @@ function onTaskDispatched(optsOrHandler, handler) {
86
86
  (0, encoding_1.copyIfPresent)(func.__endpoint.taskQueueTrigger.rateLimits, opts.rateLimits, "maxConcurrentDispatches", "maxDispatchesPerSecond");
87
87
  (0, encoding_1.convertIfPresent)(func.__endpoint.taskQueueTrigger, options.getGlobalOptions(), "invoker", "invoker", encoding_1.convertInvoker);
88
88
  (0, encoding_1.convertIfPresent)(func.__endpoint.taskQueueTrigger, opts, "invoker", "invoker", encoding_1.convertInvoker);
89
- (0, encoding_1.copyIfPresent)(func.__endpoint.taskQueueTrigger, opts, "retry", "retry");
90
89
  func.__requiredAPIs = [
91
90
  {
92
91
  api: "cloudtasks.googleapis.com",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-functions",
3
- "version": "6.3.2",
3
+ "version": "6.4.0",
4
4
  "description": "Firebase SDK for Cloud Functions",
5
5
  "keywords": [
6
6
  "firebase",