firebase-functions 6.3.1 → 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,18 +140,24 @@ export interface CallableOptions<T = any> extends HttpsOptions {
140
140
  */
141
141
  heartbeatSeconds?: number | null;
142
142
  /**
143
- * Callback for whether a request is authorized.
143
+ * (Deprecated) Callback for whether a request is authorized.
144
144
  *
145
145
  * Designed to allow reusable auth policies to be passed as an options object. Two built-in reusable policies exist:
146
146
  * isSignedIn and hasClaim.
147
+ *
148
+ * @deprecated
147
149
  */
148
150
  authPolicy?: (auth: AuthData | null, data: T) => boolean | Promise<boolean>;
149
151
  }
150
152
  /**
153
+ * @deprecated
154
+ *
151
155
  * An auth policy that requires a user to be signed in.
152
156
  */
153
157
  export declare const isSignedIn: () => (auth: AuthData | null) => boolean;
154
158
  /**
159
+ * @deprecated
160
+ *
155
161
  * An auth policy that requires a user to be both signed in and have a specific claim (optionally with a specific value)
156
162
  */
157
163
  export declare const hasClaim: (claim: string, value?: string) => (auth: AuthData | null) => boolean;
@@ -33,15 +33,20 @@ 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");
39
40
  /**
41
+ * @deprecated
42
+ *
40
43
  * An auth policy that requires a user to be signed in.
41
44
  */
42
45
  const isSignedIn = () => (auth) => !!auth;
43
46
  exports.isSignedIn = isSignedIn;
44
47
  /**
48
+ * @deprecated
49
+ *
45
50
  * An auth policy that requires a user to be both signed in and have a specific claim (optionally with a specific value)
46
51
  */
47
52
  const hasClaim = (claim, value) => (auth) => {
@@ -64,7 +69,7 @@ function onRequest(optsOrHandler, handler) {
64
69
  opts = optsOrHandler;
65
70
  }
66
71
  if ((0, debug_1.isDebugFeatureEnabled)("enableCors") || "cors" in opts) {
67
- let origin = opts.cors;
72
+ let origin = opts.cors instanceof params_1.Expression ? opts.cors.value() : opts.cors;
68
73
  if ((0, debug_1.isDebugFeatureEnabled)("enableCors")) {
69
74
  // Respect `cors: false` to turn off cors even if debug feature is enabled.
70
75
  origin = opts.cors === false ? false : true;
@@ -142,7 +147,19 @@ function onCall(optsOrHandler, handler) {
142
147
  else {
143
148
  opts = optsOrHandler;
144
149
  }
145
- 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;
146
163
  // Arrays cause the access-control-allow-origin header to be dynamic based
147
164
  // on the origin header of the request. If there is only one element in the
148
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.1",
3
+ "version": "6.4.0",
4
4
  "description": "Firebase SDK for Cloud Functions",
5
5
  "keywords": [
6
6
  "firebase",