firebase-functions 7.2.5 → 7.3.0-rc.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.
Files changed (76) hide show
  1. package/lib/common/api.d.ts +7 -0
  2. package/lib/common/api.js +34 -0
  3. package/lib/common/providers/https.d.ts +7 -0
  4. package/lib/common/providers/https.js +40 -1
  5. package/lib/esm/common/api.mjs +31 -0
  6. package/lib/esm/common/providers/https.mjs +40 -2
  7. package/lib/esm/lifecycle/index.mjs +55 -0
  8. package/lib/esm/runtime/loader.mjs +12 -2
  9. package/lib/esm/runtime/manifest.mjs +0 -1
  10. package/lib/esm/security/roles.mjs +17 -0
  11. package/lib/esm/v1/cloud-functions.mjs +2 -1
  12. package/lib/esm/v1/function-builder.mjs +15 -1
  13. package/lib/esm/v1/index.mjs +2 -1
  14. package/lib/esm/v1/providers/https.mjs +28 -4
  15. package/lib/esm/v2/index.doc.mjs +4 -1
  16. package/lib/esm/v2/index.mjs +4 -1
  17. package/lib/esm/v2/options.mjs +79 -3
  18. package/lib/esm/v2/providers/ai/index.mjs +2 -2
  19. package/lib/esm/v2/providers/alerts/alerts.mjs +1 -1
  20. package/lib/esm/v2/providers/database.mjs +19 -6
  21. package/lib/esm/v2/providers/dataconnect/graphql.mjs +1 -1
  22. package/lib/esm/v2/providers/dataconnect/index.mjs +1 -1
  23. package/lib/esm/v2/providers/eventarc.mjs +1 -1
  24. package/lib/esm/v2/providers/firestore.mjs +1 -1
  25. package/lib/esm/v2/providers/https.mjs +9 -23
  26. package/lib/esm/v2/providers/identity.mjs +89 -4
  27. package/lib/esm/v2/providers/pubsub.mjs +4 -4
  28. package/lib/esm/v2/providers/remoteConfig.mjs +1 -1
  29. package/lib/esm/v2/providers/scheduler.mjs +1 -1
  30. package/lib/esm/v2/providers/storage.mjs +2 -2
  31. package/lib/esm/v2/providers/tasks.mjs +2 -2
  32. package/lib/esm/v2/providers/testLab.mjs +1 -1
  33. package/lib/esm/v2/security.mjs +19 -0
  34. package/lib/lifecycle/index.d.ts +44 -0
  35. package/lib/lifecycle/index.js +59 -0
  36. package/lib/logger/common.d.ts +20 -5
  37. package/lib/params/types.d.ts +9 -3
  38. package/lib/runtime/loader.js +12 -2
  39. package/lib/runtime/manifest.d.ts +24 -3
  40. package/lib/runtime/manifest.js +0 -1
  41. package/lib/security/roles.d.ts +5 -0
  42. package/lib/security/roles.js +19 -0
  43. package/lib/v1/cloud-functions.d.ts +8 -5
  44. package/lib/v1/cloud-functions.js +2 -1
  45. package/lib/v1/function-builder.d.ts +2 -2
  46. package/lib/v1/function-builder.js +15 -1
  47. package/lib/v1/index.d.ts +1 -0
  48. package/lib/v1/index.js +2 -0
  49. package/lib/v1/providers/https.d.ts +11 -3
  50. package/lib/v1/providers/https.js +28 -3
  51. package/lib/v2/index.d.ts +4 -2
  52. package/lib/v2/index.doc.js +7 -0
  53. package/lib/v2/index.js +7 -0
  54. package/lib/v2/options.d.ts +6 -2
  55. package/lib/v2/options.js +84 -2
  56. package/lib/v2/providers/ai/index.js +2 -2
  57. package/lib/v2/providers/alerts/alerts.js +1 -1
  58. package/lib/v2/providers/database.d.ts +1 -1
  59. package/lib/v2/providers/database.js +19 -6
  60. package/lib/v2/providers/dataconnect/graphql.js +1 -1
  61. package/lib/v2/providers/dataconnect/index.js +1 -1
  62. package/lib/v2/providers/eventarc.js +1 -1
  63. package/lib/v2/providers/firestore.js +1 -1
  64. package/lib/v2/providers/https.js +8 -22
  65. package/lib/v2/providers/identity.d.ts +71 -1
  66. package/lib/v2/providers/identity.js +91 -3
  67. package/lib/v2/providers/pubsub.d.ts +3 -3
  68. package/lib/v2/providers/pubsub.js +4 -4
  69. package/lib/v2/providers/remoteConfig.js +1 -1
  70. package/lib/v2/providers/scheduler.js +1 -1
  71. package/lib/v2/providers/storage.js +2 -2
  72. package/lib/v2/providers/tasks.js +2 -2
  73. package/lib/v2/providers/testLab.js +1 -1
  74. package/lib/v2/security.d.ts +11 -0
  75. package/lib/v2/security.js +19 -0
  76. package/package.json +17 -13
@@ -1,4 +1,6 @@
1
1
  import { __export } from "../../_virtual/rolldown_runtime.mjs";
2
+ import { Expression } from "../../params/types.mjs";
3
+ import "../../params/index.mjs";
2
4
  import { initV2Endpoint } from "../../runtime/manifest.mjs";
3
5
  import { getApp } from "../../common/app.mjs";
4
6
  import { withInit } from "../../common/onInit.mjs";
@@ -163,10 +165,12 @@ function makeV1Context(eventType, databaseEvent) {
163
165
  /** @internal */
164
166
  function makeEndpoint(eventType, opts, path, instance) {
165
167
  const baseOpts = optionsToEndpoint(getGlobalOptions());
166
- const specificOpts = optionsToEndpoint(opts);
168
+ const specificOpts = optionsToEndpoint(opts, "event");
167
169
  const eventFilters = {};
168
170
  const eventFilterPathPatterns = { ref: path.getValue() };
169
- if (instance.hasWildcards()) {
171
+ if (instance instanceof Expression) {
172
+ eventFilterPathPatterns.instance = instance;
173
+ } else if (instance.hasWildcards()) {
170
174
  eventFilterPathPatterns.instance = instance.getValue();
171
175
  } else {
172
176
  eventFilters.instance = instance.getValue();
@@ -188,15 +192,24 @@ function makeEndpoint(eventType, opts, path, instance) {
188
192
  }
189
193
  };
190
194
  }
195
+ function resolveInstancePattern(instance) {
196
+ return instance instanceof Expression ? new PathPattern(instance.value()) : instance;
197
+ }
198
+ function makeInstancePattern(instance) {
199
+ return instance instanceof Expression ? instance : new PathPattern(instance);
200
+ }
201
+ function makeTypedParams(event, pathPattern, instancePattern) {
202
+ return makeParams(event, pathPattern, resolveInstancePattern(instancePattern));
203
+ }
191
204
  /** @internal */
192
205
  function onChangedOperation(eventType, referenceOrOpts, handler) {
193
206
  const { path, instance, opts } = getOpts(referenceOrOpts);
194
207
  const pathPattern = new PathPattern(path);
195
- const instancePattern = new PathPattern(instance);
208
+ const instancePattern = makeInstancePattern(instance);
196
209
  const func = (raw) => {
197
210
  const event = raw;
198
211
  const instanceUrl = getInstance(event);
199
- const params = makeParams(event, pathPattern, instancePattern);
212
+ const params = makeTypedParams(event, pathPattern, instancePattern);
200
213
  const databaseEvent = makeChangedDatabaseEvent(event, instanceUrl, params);
201
214
  const compatEvent = addV1Compat(databaseEvent, {
202
215
  context: () => makeV1Context(eventType, databaseEvent),
@@ -212,11 +225,11 @@ function onChangedOperation(eventType, referenceOrOpts, handler) {
212
225
  function onOperation(eventType, referenceOrOpts, handler) {
213
226
  const { path, instance, opts } = getOpts(referenceOrOpts);
214
227
  const pathPattern = new PathPattern(path);
215
- const instancePattern = new PathPattern(instance);
228
+ const instancePattern = makeInstancePattern(instance);
216
229
  const func = (raw) => {
217
230
  const event = raw;
218
231
  const instanceUrl = getInstance(event);
219
- const params = makeParams(event, pathPattern, instancePattern);
232
+ const params = makeTypedParams(event, pathPattern, instancePattern);
220
233
  const data = eventType === deletedEventType ? event.data.data : event.data.delta;
221
234
  const databaseEvent = makeDatabaseEvent(event, data, instanceUrl, params);
222
235
  const compatEvent = addV1Compat(databaseEvent, {
@@ -78,7 +78,7 @@ function onGraphRequest(opts) {
78
78
  })));
79
79
  const globalOpts = getGlobalOptions();
80
80
  const baseOpts = optionsToEndpoint(globalOpts);
81
- const specificOpts = optionsToEndpoint(opts);
81
+ const specificOpts = optionsToEndpoint(opts, "https");
82
82
  const endpoint = {
83
83
  ...initV2Endpoint(globalOpts, opts),
84
84
  platform: "gcfv2",
@@ -56,7 +56,7 @@ function getOpts(mutationOrOpts) {
56
56
  }
57
57
  function makeEndpoint(eventType, opts, service, connector, operation) {
58
58
  const baseOpts = optionsToEndpoint(getGlobalOptions());
59
- const specificOpts = optionsToEndpoint(opts);
59
+ const specificOpts = optionsToEndpoint(opts, "event");
60
60
  const eventFilters = {};
61
61
  const eventFilterPathPatterns = {};
62
62
  if (service) {
@@ -20,7 +20,7 @@ function onCustomEventPublished(eventTypeOrOpts, handler) {
20
20
  func.run = handler;
21
21
  const channel = opts.channel ?? "locations/us-central1/channels/firebase";
22
22
  const baseOpts = optionsToEndpoint(getGlobalOptions());
23
- const specificOpts = optionsToEndpoint(opts);
23
+ const specificOpts = optionsToEndpoint(opts, "event");
24
24
  const endpoint = {
25
25
  ...initV2Endpoint(getGlobalOptions(), opts),
26
26
  platform: "gcfv2",
@@ -234,7 +234,7 @@ function makeChangedFirestoreEvent(event, params) {
234
234
  /** @internal */
235
235
  function makeEndpoint(eventType, opts, document, database, namespace) {
236
236
  const baseOpts = optionsToEndpoint(getGlobalOptions());
237
- const specificOpts = optionsToEndpoint(opts);
237
+ const specificOpts = optionsToEndpoint(opts, "event");
238
238
  const eventFilters = {
239
239
  database,
240
240
  namespace
@@ -6,7 +6,7 @@ import { initV2Endpoint } from "../../runtime/manifest.mjs";
6
6
  import { isDebugFeatureEnabled } from "../../common/debug.mjs";
7
7
  import { convertIfPresent, convertInvoker, copyIfPresent } from "../../common/encoding.mjs";
8
8
  import { withInit } from "../../common/onInit.mjs";
9
- import { HttpsError, onCallHandler, withErrorHandler } from "../../common/providers/https.mjs";
9
+ import { HttpsError, onCallHandler, resolveCorsOrigin, withErrorHandler } from "../../common/providers/https.mjs";
10
10
  import { wrapTraceContext } from "../trace.mjs";
11
11
  import { getGlobalOptions, optionsToEndpoint, optionsToTriggerAnnotations } from "../options.mjs";
12
12
  import cors from "cors";
@@ -50,18 +50,12 @@ function onRequest(optsOrHandler, handler) {
50
50
  }
51
51
  handler = withErrorHandler(handler);
52
52
  if (isDebugFeatureEnabled("enableCors") || "cors" in opts) {
53
- let origin = opts.cors instanceof Expression ? opts.cors.value() : opts.cors;
54
- if (isDebugFeatureEnabled("enableCors")) {
55
- origin = opts.cors === false ? false : true;
56
- }
57
- if (Array.isArray(origin) && origin.length === 1) {
58
- origin = origin[0];
59
- }
60
- const middleware = cors({ origin });
61
53
  const userProvidedHandler = handler;
62
54
  handler = (req, res) => {
63
55
  return new Promise((resolve) => {
64
56
  res.on("finish", resolve);
57
+ const origin = resolveCorsOrigin(opts.cors);
58
+ const middleware = cors({ origin });
65
59
  middleware(req, res, () => {
66
60
  resolve(userProvidedHandler(req, res));
67
61
  });
@@ -71,7 +65,7 @@ function onRequest(optsOrHandler, handler) {
71
65
  handler = wrapTraceContext(withInit(handler));
72
66
  Object.defineProperty(handler, "__trigger", { get: () => {
73
67
  const baseOpts$1 = optionsToTriggerAnnotations(getGlobalOptions());
74
- const specificOpts$1 = optionsToTriggerAnnotations(opts);
68
+ const specificOpts$1 = optionsToTriggerAnnotations(opts, "https");
75
69
  const trigger = {
76
70
  platform: "gcfv2",
77
71
  ...baseOpts$1,
@@ -88,7 +82,7 @@ function onRequest(optsOrHandler, handler) {
88
82
  } });
89
83
  const globalOpts = getGlobalOptions();
90
84
  const baseOpts = optionsToEndpoint(globalOpts);
91
- const specificOpts = optionsToEndpoint(opts);
85
+ const specificOpts = optionsToEndpoint(opts, "https");
92
86
  const endpoint = {
93
87
  ...initV2Endpoint(globalOpts, opts),
94
88
  platform: "gcfv2",
@@ -115,18 +109,10 @@ function onCall(optsOrHandler, handler) {
115
109
  }
116
110
  let cors$1;
117
111
  if ("cors" in opts) {
118
- if (opts.cors instanceof Expression) {
119
- cors$1 = opts.cors.value();
120
- } else {
121
- cors$1 = opts.cors;
122
- }
112
+ cors$1 = opts.cors;
123
113
  } else {
124
114
  cors$1 = true;
125
115
  }
126
- let origin = isDebugFeatureEnabled("enableCors") ? true : cors$1;
127
- if (Array.isArray(origin) && origin.length === 1) {
128
- origin = origin[0];
129
- }
130
116
  const fixedLen = (req, resp) => handler(req, resp);
131
117
  let enforceAppCheck = opts.enforceAppCheck ?? getGlobalOptions().enforceAppCheck;
132
118
  if (enforceAppCheck instanceof Expression) {
@@ -138,7 +124,7 @@ function onCall(optsOrHandler, handler) {
138
124
  }
139
125
  let func = onCallHandler({
140
126
  cors: {
141
- origin,
127
+ origin: cors$1,
142
128
  methods: "POST"
143
129
  },
144
130
  enforceAppCheck,
@@ -149,7 +135,7 @@ function onCall(optsOrHandler, handler) {
149
135
  func = wrapTraceContext(withInit(func));
150
136
  Object.defineProperty(func, "__trigger", { get: () => {
151
137
  const baseOpts$1 = optionsToTriggerAnnotations(getGlobalOptions());
152
- const specificOpts$1 = optionsToTriggerAnnotations(opts);
138
+ const specificOpts$1 = optionsToTriggerAnnotations(opts, "https");
153
139
  return {
154
140
  platform: "gcfv2",
155
141
  ...baseOpts$1,
@@ -163,7 +149,7 @@ function onCall(optsOrHandler, handler) {
163
149
  };
164
150
  } });
165
151
  const baseOpts = optionsToEndpoint(getGlobalOptions());
166
- const specificOpts = optionsToEndpoint(opts);
152
+ const specificOpts = optionsToEndpoint(opts, "https");
167
153
  func.__endpoint = {
168
154
  ...initV2Endpoint(getGlobalOptions(), opts),
169
155
  platform: "gcfv2",
@@ -1,20 +1,24 @@
1
1
  import { __export } from "../../_virtual/rolldown_runtime.mjs";
2
+ import { RESET_VALUE } from "../../common/options.mjs";
2
3
  import { initV2Endpoint } from "../../runtime/manifest.mjs";
3
4
  import { withInit } from "../../common/onInit.mjs";
4
5
  import { HttpsError } from "../../common/providers/https.mjs";
5
- import { wrapHandler } from "../../common/providers/identity.mjs";
6
+ import { userRecordConstructor, wrapHandler } from "../../common/providers/identity.mjs";
6
7
  import { wrapTraceContext } from "../trace.mjs";
7
8
  import { getGlobalOptions, optionsToEndpoint } from "../options.mjs";
8
9
 
9
10
  //#region src/v2/providers/identity.ts
10
11
  var identity_exports = /* @__PURE__ */ __export({
11
12
  HttpsError: () => HttpsError,
13
+ IS_NOT_TENANT: () => IS_NOT_TENANT,
12
14
  beforeEmailSent: () => beforeEmailSent,
13
15
  beforeOperation: () => beforeOperation,
14
16
  beforeSmsSent: () => beforeSmsSent,
15
17
  beforeUserCreated: () => beforeUserCreated,
16
18
  beforeUserSignedIn: () => beforeUserSignedIn,
17
- getOpts: () => getOpts
19
+ getOpts: () => getOpts,
20
+ onUserCreated: () => onUserCreated,
21
+ onUserDeleted: () => onUserDeleted
18
22
  });
19
23
  /**
20
24
  * Handles an event that is triggered before a user is created.
@@ -60,7 +64,7 @@ function beforeOperation(eventType, optsOrHandler, handler) {
60
64
  const legacyEventType = `providers/cloud.auth/eventTypes/user.${eventType}`;
61
65
  /** Endpoint */
62
66
  const baseOptsEndpoint = optionsToEndpoint(getGlobalOptions());
63
- const specificOptsEndpoint = optionsToEndpoint(opts);
67
+ const specificOptsEndpoint = optionsToEndpoint(opts, "identity");
64
68
  func.__endpoint = {
65
69
  ...initV2Endpoint(getGlobalOptions(), opts),
66
70
  platform: "gcfv2",
@@ -98,6 +102,87 @@ function getOpts(blockingOptions) {
98
102
  refreshToken
99
103
  };
100
104
  }
105
+ const IS_NOT_TENANT = RESET_VALUE;
106
+ function getOptsAndHandler(optsOrHandler, handler) {
107
+ if (typeof optsOrHandler === "function") {
108
+ return {
109
+ opts: {},
110
+ handler: optsOrHandler
111
+ };
112
+ }
113
+ return {
114
+ opts: optsOrHandler,
115
+ handler
116
+ };
117
+ }
118
+ const PROJECT_ID_REGEX = /(?:^|\/)projects\/([^\/]+)/;
119
+ /** @hidden */
120
+ function getAuthEvent(raw) {
121
+ const event = { ...raw };
122
+ if (raw.data) {
123
+ event.data = userRecordConstructor(raw.data);
124
+ }
125
+ const rawAny = raw;
126
+ const tenantId = rawAny.tenantid || rawAny.tenantId;
127
+ if (tenantId) {
128
+ event.tenantId = tenantId;
129
+ }
130
+ if (raw.source) {
131
+ const match = raw.source.match(PROJECT_ID_REGEX);
132
+ if (match) {
133
+ event.project = match[1];
134
+ }
135
+ }
136
+ return event;
137
+ }
138
+ /** @hidden */
139
+ function makeAuthTrigger(eventType, optsOrHandler, handler) {
140
+ const { opts, handler: handlerFunc } = getOptsAndHandler(optsOrHandler, handler);
141
+ if (typeof handlerFunc !== "function") {
142
+ throw new Error("The handler must be a function.");
143
+ }
144
+ const wrappedHandler = wrapTraceContext(withInit(handlerFunc));
145
+ const func = ((raw) => {
146
+ const event = getAuthEvent(raw);
147
+ return wrappedHandler(event);
148
+ });
149
+ func.run = handlerFunc;
150
+ const baseOptsEndpoint = optionsToEndpoint(getGlobalOptions());
151
+ const specificOptsEndpoint = optionsToEndpoint(opts);
152
+ const endpoint = {
153
+ ...initV2Endpoint(getGlobalOptions(), opts),
154
+ platform: "gcfv2",
155
+ ...baseOptsEndpoint,
156
+ ...specificOptsEndpoint,
157
+ labels: {
158
+ ...baseOptsEndpoint?.labels,
159
+ ...specificOptsEndpoint?.labels
160
+ },
161
+ eventTrigger: {
162
+ eventType,
163
+ eventFilters: {},
164
+ retry: opts.retry ?? false,
165
+ region: "global"
166
+ }
167
+ };
168
+ if (opts.tenantId !== undefined) {
169
+ if (opts.tenantId === IS_NOT_TENANT) {
170
+ endpoint.eventTrigger.eventFilters["tenantid"] = "";
171
+ } else {
172
+ endpoint.eventTrigger.eventFilters["tenantid"] = opts.tenantId;
173
+ }
174
+ }
175
+ func.__endpoint = endpoint;
176
+ return func;
177
+ }
178
+ const USER_CREATED_EVENT = "google.firebase.auth.user.v2.created";
179
+ function onUserCreated(optsOrHandler, handler) {
180
+ return makeAuthTrigger(USER_CREATED_EVENT, optsOrHandler, handler);
181
+ }
182
+ const USER_DELETED_EVENT = "google.firebase.auth.user.v2.deleted";
183
+ function onUserDeleted(optsOrHandler, handler) {
184
+ return makeAuthTrigger(USER_DELETED_EVENT, optsOrHandler, handler);
185
+ }
101
186
 
102
187
  //#endregion
103
- export { HttpsError, beforeEmailSent, beforeOperation, beforeSmsSent, beforeUserCreated, beforeUserSignedIn, getOpts, identity_exports };
188
+ export { HttpsError, IS_NOT_TENANT, beforeEmailSent, beforeOperation, beforeSmsSent, beforeUserCreated, beforeUserSignedIn, getOpts, identity_exports, onUserCreated, onUserDeleted };
@@ -90,7 +90,7 @@ var Message = class {
90
90
  function onMessagePublished(topicOrOptions, handler) {
91
91
  let topic;
92
92
  let opts;
93
- if (typeof topicOrOptions === "string") {
93
+ if (typeof topicOrOptions === "string" || "value" in topicOrOptions) {
94
94
  topic = topicOrOptions;
95
95
  opts = {};
96
96
  } else {
@@ -145,7 +145,7 @@ function onMessagePublished(topicOrOptions, handler) {
145
145
  func.run = handler;
146
146
  Object.defineProperty(func, "__trigger", { get: () => {
147
147
  const baseOpts$1 = optionsToTriggerAnnotations(getGlobalOptions());
148
- const specificOpts$1 = optionsToTriggerAnnotations(opts);
148
+ const specificOpts$1 = optionsToTriggerAnnotations(opts, "event");
149
149
  return {
150
150
  platform: "gcfv2",
151
151
  ...baseOpts$1,
@@ -156,12 +156,12 @@ function onMessagePublished(topicOrOptions, handler) {
156
156
  },
157
157
  eventTrigger: {
158
158
  eventType: "google.cloud.pubsub.topic.v1.messagePublished",
159
- resource: `projects/${process.env.GCLOUD_PROJECT}/topics/${topic}`
159
+ ...typeof topic === "string" && { resource: `projects/${process.env.GCLOUD_PROJECT}/topics/${topic}` }
160
160
  }
161
161
  };
162
162
  } });
163
163
  const baseOpts = optionsToEndpoint(getGlobalOptions());
164
- const specificOpts = optionsToEndpoint(opts);
164
+ const specificOpts = optionsToEndpoint(opts, "event");
165
165
  const endpoint = {
166
166
  ...initV2Endpoint(getGlobalOptions(), opts),
167
167
  platform: "gcfv2",
@@ -25,7 +25,7 @@ function onConfigUpdated(optsOrHandler, handler) {
25
25
  optsOrHandler = {};
26
26
  }
27
27
  const baseOpts = optionsToEndpoint(getGlobalOptions());
28
- const specificOpts = optionsToEndpoint(optsOrHandler);
28
+ const specificOpts = optionsToEndpoint(optsOrHandler, "event");
29
29
  const func = wrapTraceContext(withInit((raw) => {
30
30
  const event = raw;
31
31
  const patchedEvent = addV1Compat(event, {
@@ -70,7 +70,7 @@ function onSchedule(args, handler) {
70
70
  func.run = handler;
71
71
  const globalOpts = getGlobalOptions();
72
72
  const baseOptsEndpoint = optionsToEndpoint(globalOpts);
73
- const specificOptsEndpoint = optionsToEndpoint(separatedOpts.opts);
73
+ const specificOptsEndpoint = optionsToEndpoint(separatedOpts.opts, "event");
74
74
  const ep = {
75
75
  ...initV2Endpoint(globalOpts, separatedOpts.opts),
76
76
  platform: "gcfv2",
@@ -114,7 +114,7 @@ function onOperation(eventType, bucketOrOptsOrHandler, handler) {
114
114
  func.run = handler;
115
115
  Object.defineProperty(func, "__trigger", { get: () => {
116
116
  const baseOpts = optionsToTriggerAnnotations(getGlobalOptions());
117
- const specificOpts = optionsToTriggerAnnotations(opts);
117
+ const specificOpts = optionsToTriggerAnnotations(opts, "event");
118
118
  return {
119
119
  platform: "gcfv2",
120
120
  ...baseOpts,
@@ -132,7 +132,7 @@ function onOperation(eventType, bucketOrOptsOrHandler, handler) {
132
132
  func.__endpoint = {};
133
133
  Object.defineProperty(func, "__endpoint", { get: () => {
134
134
  const baseOpts = optionsToEndpoint(getGlobalOptions());
135
- const specificOpts = optionsToEndpoint(opts);
135
+ const specificOpts = optionsToEndpoint(opts, "event");
136
136
  const endpoint = {
137
137
  platform: "gcfv2",
138
138
  ...initV2Endpoint(getGlobalOptions(), opts),
@@ -20,7 +20,7 @@ function onTaskDispatched(optsOrHandler, handler) {
20
20
  const func = wrapTraceContext(withInit(onDispatchHandler(fixedLen)));
21
21
  Object.defineProperty(func, "__trigger", { get: () => {
22
22
  const baseOpts$1 = optionsToTriggerAnnotations(getGlobalOptions());
23
- const specificOpts$1 = optionsToTriggerAnnotations(opts);
23
+ const specificOpts$1 = optionsToTriggerAnnotations(opts, "task");
24
24
  const taskQueueTrigger = {};
25
25
  copyIfPresent(taskQueueTrigger, opts, "retryConfig", "rateLimits");
26
26
  convertIfPresent(taskQueueTrigger, getGlobalOptions(), "invoker", "invoker", convertInvoker);
@@ -37,7 +37,7 @@ function onTaskDispatched(optsOrHandler, handler) {
37
37
  };
38
38
  } });
39
39
  const baseOpts = optionsToEndpoint(getGlobalOptions());
40
- const specificOpts = optionsToEndpoint(opts);
40
+ const specificOpts = optionsToEndpoint(opts, "task");
41
41
  func.__endpoint = {
42
42
  platform: "gcfv2",
43
43
  ...initV2Endpoint(getGlobalOptions(), opts),
@@ -25,7 +25,7 @@ function onTestMatrixCompleted(optsOrHandler, handler) {
25
25
  optsOrHandler = {};
26
26
  }
27
27
  const baseOpts = optionsToEndpoint(getGlobalOptions());
28
- const specificOpts = optionsToEndpoint(optsOrHandler);
28
+ const specificOpts = optionsToEndpoint(optsOrHandler, "event");
29
29
  const func = (raw) => {
30
30
  return wrapTraceContext(withInit(handler))(raw);
31
31
  };
@@ -0,0 +1,19 @@
1
+ import { registerRole } from "../security/roles.mjs";
2
+
3
+ //#region src/v2/security.ts
4
+ /**
5
+ * Declares that this codebase requires the specified IAM role to operate.
6
+ * When deployed, the Firebase CLI will automatically provision a managed service account
7
+ * with this role and attach it to all functions in this codebase.
8
+ * @param role The IAM role required (e.g. "roles/bigquery.dataEditor")
9
+ */
10
+ function requiresRole(role) {
11
+ const roleRegex = /^(roles\/[a-zA-Z0-9_.-]+|projects\/[a-zA-Z0-9_-]+\/roles\/[a-zA-Z0-9_.-]+|organizations\/[a-zA-Z0-9_-]+\/roles\/[a-zA-Z0-9_.-]+)$/;
12
+ if (!roleRegex.test(role)) {
13
+ throw new Error(`Invalid role: "${role}". Role must be a valid GCP IAM role format (e.g., "roles/viewer", "projects/<project-id>/roles/<custom-role>", or "organizations/<org-id>/roles/<custom-role>").`);
14
+ }
15
+ registerRole(role);
16
+ }
17
+
18
+ //#endregion
19
+ export { requiresRole };
@@ -0,0 +1,44 @@
1
+ export interface TaskAction {
2
+ function: string;
3
+ body?: Record<string, unknown>;
4
+ }
5
+ export interface CallAction {
6
+ function: string;
7
+ params?: Record<string, unknown>;
8
+ }
9
+ export type HttpAction = ({
10
+ function: string;
11
+ } | {
12
+ url: string;
13
+ }) & {
14
+ method?: "GET" | "POST" | "PUT" | "DELETE";
15
+ headers?: Record<string, string>;
16
+ body?: unknown;
17
+ };
18
+ export type LifecycleAction = {
19
+ task: TaskAction;
20
+ call?: never;
21
+ http?: never;
22
+ } | {
23
+ call: CallAction;
24
+ task?: never;
25
+ http?: never;
26
+ } | {
27
+ http: HttpAction;
28
+ task?: never;
29
+ call?: never;
30
+ };
31
+ /**
32
+ * Registers an action to be executed automatically post-deployment when resources in this codebase
33
+ * are deployed for the first time.
34
+ *
35
+ * @param action The lifecycle action to execute.
36
+ */
37
+ export declare function afterFirstDeploy(action: LifecycleAction): void;
38
+ /**
39
+ * Registers an action to be executed automatically post-deployment when resources in this codebase
40
+ * are updated.
41
+ *
42
+ * @param action The lifecycle action to execute.
43
+ */
44
+ export declare function afterRedeploy(action: LifecycleAction): void;
@@ -0,0 +1,59 @@
1
+
2
+ //#region src/lifecycle/index.ts
3
+ /**
4
+ * Use a global singleton to manage the list of declared lifecycle hooks.
5
+ *
6
+ * This ensures that lifecycle hooks are shared between CJS and ESM builds,
7
+ * avoiding the "dual-package hazard" where the src/bin/firebase-functions.ts (CJS) sees
8
+ * an empty list while the user's code (ESM) populates a different list.
9
+ */
10
+ const majorVersion = typeof "7" !== "undefined" ? "7" : "0";
11
+ const GLOBAL_SYMBOL = Symbol.for(`firebase-functions:lifecycle:declaredHooks:v${majorVersion}`);
12
+ const globalSymbols = globalThis;
13
+ if (!globalSymbols[GLOBAL_SYMBOL]) {
14
+ globalSymbols[GLOBAL_SYMBOL] = {};
15
+ }
16
+ /**
17
+ * Singleton dictionary of declared lifecycle hooks.
18
+ * @internal
19
+ */
20
+ const declaredLifecycleHooks = globalSymbols[GLOBAL_SYMBOL];
21
+ /**
22
+ * Registers an action to be executed automatically post-deployment when resources in this codebase
23
+ * are deployed for the first time.
24
+ *
25
+ * @param action The lifecycle action to execute.
26
+ */
27
+ function afterFirstDeploy(action) {
28
+ if (declaredLifecycleHooks.afterFirstDeploy) {
29
+ throw new Error("Only one afterFirstDeploy lifecycle hook is allowed per codebase.");
30
+ }
31
+ declaredLifecycleHooks.afterFirstDeploy = action;
32
+ }
33
+ /**
34
+ * Registers an action to be executed automatically post-deployment when resources in this codebase
35
+ * are updated.
36
+ *
37
+ * @param action The lifecycle action to execute.
38
+ */
39
+ function afterRedeploy(action) {
40
+ if (declaredLifecycleHooks.afterRedeploy) {
41
+ throw new Error("Only one afterRedeploy lifecycle hook is allowed per codebase.");
42
+ }
43
+ declaredLifecycleHooks.afterRedeploy = action;
44
+ }
45
+ /**
46
+ * Helper to clear declared lifecycle hooks.
47
+ * @internal
48
+ */
49
+ function clearDeclaredLifecycleHooks() {
50
+ for (const key of Object.keys(declaredLifecycleHooks)) {
51
+ delete declaredLifecycleHooks[key];
52
+ }
53
+ }
54
+
55
+ //#endregion
56
+ exports.afterFirstDeploy = afterFirstDeploy;
57
+ exports.afterRedeploy = afterRedeploy;
58
+ exports.clearDeclaredLifecycleHooks = clearDeclaredLifecycleHooks;
59
+ exports.declaredLifecycleHooks = declaredLifecycleHooks;
@@ -4,9 +4,24 @@ export declare const CONSOLE_SEVERITY: {
4
4
  };
5
5
  /** @hidden */
6
6
  export declare const UNPATCHED_CONSOLE: {
7
- debug: (message?: any, ...optionalParams: any[]) => void;
8
- info: (message?: any, ...optionalParams: any[]) => void;
9
- log: (message?: any, ...optionalParams: any[]) => void;
10
- warn: (message?: any, ...optionalParams: any[]) => void;
11
- error: (message?: any, ...optionalParams: any[]) => void;
7
+ debug: {
8
+ (...data: any[]): void;
9
+ (message?: any, ...optionalParams: any[]): void;
10
+ };
11
+ info: {
12
+ (...data: any[]): void;
13
+ (message?: any, ...optionalParams: any[]): void;
14
+ };
15
+ log: {
16
+ (...data: any[]): void;
17
+ (message?: any, ...optionalParams: any[]): void;
18
+ };
19
+ warn: {
20
+ (...data: any[]): void;
21
+ (message?: any, ...optionalParams: any[]): void;
22
+ };
23
+ error: {
24
+ (...data: any[]): void;
25
+ (message?: any, ...optionalParams: any[]): void;
26
+ };
12
27
  };
@@ -84,7 +84,9 @@ export interface TextInput<T = unknown> {
84
84
  * failing to conform to the validationRegex,
85
85
  */
86
86
  validationErrorMessage?: string;
87
- };
87
+ } & (T extends string | string[] ? {
88
+ nonEmpty?: boolean;
89
+ } : {});
88
90
  }
89
91
  /**
90
92
  * Specifies that a parameter's value should be determined by having the user
@@ -117,6 +119,12 @@ export interface SelectInput<T = unknown> {
117
119
  export interface MultiSelectInput {
118
120
  multiSelect: {
119
121
  options: Array<SelectOptions<string>>;
122
+ /**
123
+ * If set on an input for a string or string list param, nonEmpty prevents
124
+ * the prompt from accepting the empty string or empty list as valid input.
125
+ * Syntactic sugar over setting validationRegex to /.+/
126
+ */
127
+ nonEmpty?: boolean;
120
128
  };
121
129
  }
122
130
  /**
@@ -144,10 +152,8 @@ export type ParamSpec<T extends string | number | boolean | string[]> = {
144
152
  };
145
153
  /**
146
154
  * Representation of parameters for the stack over the wire.
147
- *
148
155
  * @remarks
149
156
  * N.B: a WireParamSpec is just a ParamSpec with default expressions converted into a CEL literal
150
- *
151
157
  * @alpha
152
158
  */
153
159
  export type WireParamSpec<T extends string | number | boolean | string[]> = {
@@ -1,5 +1,8 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
2
2
  const require_params_index = require('../params/index.js');
3
+ const require_security_roles = require('../security/roles.js');
4
+ const require_common_api = require('../common/api.js');
5
+ const require_lifecycle_index = require('../lifecycle/index.js');
3
6
  let path = require("path");
4
7
  path = require_rolldown_runtime.__toESM(path);
5
8
  let url = require("url");
@@ -9,9 +12,7 @@ url = require_rolldown_runtime.__toESM(url);
9
12
  /**
10
13
  * Dynamically load import function to prevent TypeScript from
11
14
  * transpiling into a require.
12
- *
13
15
  * See https://github.com/microsoft/TypeScript/issues/43329.
14
- *
15
16
  */
16
17
  const dynamicImport = new Function("modulePath", "return import(modulePath)");
17
18
  async function loadModule(functionsDir) {
@@ -118,6 +119,8 @@ async function loadStack(functionsDir) {
118
119
  const extensions = {};
119
120
  const mod = await loadModule(functionsDir);
120
121
  extractStack(mod, endpoints, requiredAPIs, extensions);
122
+ requiredAPIs.push(...require_common_api.getGlobalRequiredAPIs());
123
+ require_common_api.clearGlobalRequiredAPIs();
121
124
  const stack = {
122
125
  endpoints,
123
126
  specVersion: "v1alpha1",
@@ -127,6 +130,13 @@ async function loadStack(functionsDir) {
127
130
  if (require_params_index.declaredParams.length > 0) {
128
131
  stack.params = require_params_index.declaredParams.map((p) => p.toSpec());
129
132
  }
133
+ if (require_security_roles.declaredRoles.size > 0) {
134
+ stack.requiredRoles = Array.from(require_security_roles.declaredRoles);
135
+ }
136
+ if (Object.keys(require_lifecycle_index.declaredLifecycleHooks).length > 0) {
137
+ stack.lifecycleHooks = { ...require_lifecycle_index.declaredLifecycleHooks };
138
+ }
139
+ require_lifecycle_index.clearDeclaredLifecycleHooks();
130
140
  return stack;
131
141
  }
132
142