firebase-tools 10.9.2 → 11.1.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 (181) hide show
  1. package/README.md +15 -9
  2. package/lib/accountImporter.js +92 -93
  3. package/lib/api.js +77 -218
  4. package/lib/apiv2.js +5 -4
  5. package/lib/appdistribution/client.js +16 -25
  6. package/lib/auth.js +69 -47
  7. package/lib/bin/firebase.js +42 -47
  8. package/lib/checkValidTargetFilters.js +13 -12
  9. package/lib/commands/appdistribution-distribute.js +2 -1
  10. package/lib/commands/appdistribution-testers-add.js +2 -1
  11. package/lib/commands/appdistribution-testers-remove.js +2 -1
  12. package/lib/commands/apps-android-sha-create.js +2 -1
  13. package/lib/commands/apps-android-sha-delete.js +2 -1
  14. package/lib/commands/apps-android-sha-list.js +2 -1
  15. package/lib/commands/apps-create.js +2 -1
  16. package/lib/commands/apps-list.js +2 -1
  17. package/lib/commands/apps-sdkconfig.js +8 -3
  18. package/lib/commands/auth-export.js +2 -1
  19. package/lib/commands/auth-import.js +7 -10
  20. package/lib/commands/crashlytics-symbols-upload.js +2 -1
  21. package/lib/commands/database-get.js +4 -3
  22. package/lib/commands/database-instances-create.js +2 -1
  23. package/lib/commands/database-instances-list.js +3 -3
  24. package/lib/commands/database-profile.js +2 -1
  25. package/lib/commands/database-push.js +2 -1
  26. package/lib/commands/database-remove.js +2 -1
  27. package/lib/commands/database-rules-canary.js +2 -1
  28. package/lib/commands/database-rules-get.js +2 -1
  29. package/lib/commands/database-rules-list.js +2 -1
  30. package/lib/commands/database-rules-release.js +2 -1
  31. package/lib/commands/database-rules-stage.js +2 -1
  32. package/lib/commands/database-set.js +2 -1
  33. package/lib/commands/database-settings-get.js +2 -1
  34. package/lib/commands/database-settings-set.js +2 -1
  35. package/lib/commands/database-update.js +2 -1
  36. package/lib/commands/deploy.js +23 -21
  37. package/lib/commands/emulators-exec.js +2 -1
  38. package/lib/commands/emulators-export.js +2 -1
  39. package/lib/commands/emulators-start.js +2 -1
  40. package/lib/commands/experimental-functions-shell.js +10 -8
  41. package/lib/commands/ext-configure.js +56 -120
  42. package/lib/commands/ext-dev-deprecate.js +2 -1
  43. package/lib/commands/ext-dev-emulators-exec.js +13 -7
  44. package/lib/commands/ext-dev-emulators-start.js +12 -27
  45. package/lib/commands/ext-dev-extension-delete.js +2 -1
  46. package/lib/commands/ext-dev-init.js +2 -1
  47. package/lib/commands/ext-dev-list.js +2 -1
  48. package/lib/commands/ext-dev-publish.js +2 -1
  49. package/lib/commands/ext-dev-register.js +2 -1
  50. package/lib/commands/ext-dev-undeprecate.js +2 -1
  51. package/lib/commands/ext-dev-unpublish.js +2 -1
  52. package/lib/commands/ext-dev-usage.js +2 -1
  53. package/lib/commands/ext-export.js +2 -1
  54. package/lib/commands/ext-info.js +2 -1
  55. package/lib/commands/ext-install.js +14 -198
  56. package/lib/commands/ext-list.js +2 -1
  57. package/lib/commands/ext-sources-create.js +2 -1
  58. package/lib/commands/ext-uninstall.js +9 -92
  59. package/lib/commands/ext-update.js +67 -225
  60. package/lib/commands/ext.js +2 -1
  61. package/lib/commands/firestore-delete.js +2 -1
  62. package/lib/commands/firestore-indexes-list.js +2 -1
  63. package/lib/commands/functions-config-clone.js +4 -3
  64. package/lib/commands/functions-config-export.js +2 -1
  65. package/lib/commands/functions-config-get.js +2 -1
  66. package/lib/commands/functions-config-set.js +2 -1
  67. package/lib/commands/functions-config-unset.js +2 -1
  68. package/lib/commands/functions-delete.js +2 -1
  69. package/lib/commands/functions-deletegcfartifacts.js +2 -1
  70. package/lib/commands/functions-list.js +2 -1
  71. package/lib/commands/functions-log.js +2 -1
  72. package/lib/commands/functions-secrets-access.js +2 -1
  73. package/lib/commands/functions-secrets-destroy.js +2 -1
  74. package/lib/commands/functions-secrets-get.js +2 -1
  75. package/lib/commands/functions-secrets-prune.js +2 -1
  76. package/lib/commands/functions-secrets-set.js +2 -1
  77. package/lib/commands/functions-shell.js +12 -10
  78. package/lib/commands/help.js +2 -1
  79. package/lib/commands/hosting-channel-create.js +2 -1
  80. package/lib/commands/hosting-channel-delete.js +2 -1
  81. package/lib/commands/hosting-channel-deploy.js +2 -1
  82. package/lib/commands/hosting-channel-list.js +2 -1
  83. package/lib/commands/hosting-channel-open.js +2 -1
  84. package/lib/commands/hosting-clone.js +2 -1
  85. package/lib/commands/hosting-disable.js +2 -1
  86. package/lib/commands/hosting-sites-create.js +2 -1
  87. package/lib/commands/hosting-sites-delete.js +2 -1
  88. package/lib/commands/hosting-sites-get.js +2 -1
  89. package/lib/commands/hosting-sites-list.js +2 -1
  90. package/lib/commands/index.js +23 -13
  91. package/lib/commands/init.js +47 -43
  92. package/lib/commands/login-add.js +2 -1
  93. package/lib/commands/login-ci.js +2 -1
  94. package/lib/commands/login-list.js +2 -1
  95. package/lib/commands/login-use.js +2 -1
  96. package/lib/commands/login.js +2 -1
  97. package/lib/commands/logout.js +2 -1
  98. package/lib/commands/open.js +2 -1
  99. package/lib/commands/projects-addfirebase.js +2 -1
  100. package/lib/commands/projects-create.js +2 -1
  101. package/lib/commands/projects-list.js +2 -1
  102. package/lib/commands/remoteconfig-get.js +2 -1
  103. package/lib/commands/remoteconfig-rollback.js +2 -1
  104. package/lib/commands/remoteconfig-versions-list.js +2 -1
  105. package/lib/commands/serve.js +29 -27
  106. package/lib/commands/setup-emulators-database.js +2 -1
  107. package/lib/commands/setup-emulators-firestore.js +2 -1
  108. package/lib/commands/setup-emulators-pubsub.js +2 -1
  109. package/lib/commands/setup-emulators-storage.js +2 -1
  110. package/lib/commands/setup-emulators-ui.js +2 -1
  111. package/lib/commands/target-apply.js +2 -1
  112. package/lib/commands/target-clear.js +2 -1
  113. package/lib/commands/target-remove.js +2 -1
  114. package/lib/commands/target.js +2 -1
  115. package/lib/commands/use.js +54 -52
  116. package/lib/config.js +3 -3
  117. package/lib/deploy/database/deploy.js +3 -2
  118. package/lib/deploy/database/index.js +8 -5
  119. package/lib/deploy/database/prepare.js +22 -19
  120. package/lib/deploy/database/release.js +12 -9
  121. package/lib/deploy/firestore/prepare.js +2 -2
  122. package/lib/deploy/functions/build.js +32 -20
  123. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +187 -54
  124. package/lib/deploy/functions/runtimes/node/parseTriggers.js +14 -2
  125. package/lib/deploy/functions/services/database.js +14 -0
  126. package/lib/deploy/functions/services/index.js +14 -0
  127. package/lib/deploy/index.js +3 -3
  128. package/lib/deploy/lifecycleHooks.js +23 -20
  129. package/lib/deploy/remoteconfig/functions.js +18 -14
  130. package/lib/deploy/remoteconfig/prepare.js +2 -2
  131. package/lib/emulator/auth/apiSpec.js +14 -46
  132. package/lib/emulator/auth/operations.js +6 -29
  133. package/lib/emulator/auth/state.js +2 -25
  134. package/lib/emulator/commandUtils.js +1 -1
  135. package/lib/emulator/controller.js +3 -3
  136. package/lib/emulator/databaseEmulator.js +9 -7
  137. package/lib/emulator/downloadableEmulators.js +6 -6
  138. package/lib/emulator/extensionsEmulator.js +7 -3
  139. package/lib/emulator/firestoreEmulator.js +10 -12
  140. package/lib/emulator/functionsEmulator.js +39 -42
  141. package/lib/emulator/hubClient.js +11 -22
  142. package/lib/emulator/hubExport.js +26 -16
  143. package/lib/emulator/portUtils.js +2 -0
  144. package/lib/emulator/storage/crc.js +3 -0
  145. package/lib/emulator/storage/rules/runtime.js +1 -1
  146. package/lib/errorOut.js +2 -2
  147. package/lib/extensions/extensionsHelper.js +4 -5
  148. package/lib/extensions/manifest.js +5 -11
  149. package/lib/firebaseConfigValidate.js +1 -1
  150. package/lib/firestore/checkDatabaseType.js +4 -5
  151. package/lib/firestore/indexes.js +17 -34
  152. package/lib/functions/events/v2.js +7 -1
  153. package/lib/functionsConfigClone.js +43 -41
  154. package/lib/gcp/cloudfunctionsv2.js +17 -2
  155. package/lib/gcp/iam.js +1 -1
  156. package/lib/gcp/index.js +10 -10
  157. package/lib/gcp/runtimeconfig.js +45 -47
  158. package/lib/gcp/storage.js +2 -4
  159. package/lib/hosting/cloudRunProxy.js +19 -15
  160. package/lib/index.js +29 -28
  161. package/lib/init/features/database.js +11 -5
  162. package/lib/init/features/functions/index.js +1 -1
  163. package/lib/init/features/functions/javascript.js +23 -20
  164. package/lib/init/features/functions/npm-dependencies.js +17 -14
  165. package/lib/init/features/functions/typescript.js +27 -24
  166. package/lib/init/features/hosting/github.js +5 -4
  167. package/lib/loadCJSON.js +9 -6
  168. package/lib/logError.js +15 -12
  169. package/lib/management/apps.js +47 -43
  170. package/lib/management/database.js +33 -31
  171. package/lib/management/projects.js +13 -7
  172. package/lib/parseBoltRules.js +15 -14
  173. package/lib/profileReport.js +503 -511
  174. package/lib/profiler.js +4 -4
  175. package/lib/requireAuth.js +0 -1
  176. package/lib/responseToError.js +8 -5
  177. package/lib/rtdb.js +31 -29
  178. package/lib/scopes.js +9 -9
  179. package/npm-shrinkwrap.json +1485 -670
  180. package/package.json +21 -22
  181. package/standalone/package.json +1 -1
@@ -56,44 +56,45 @@ function resolveBackend(build, userEnvs) {
56
56
  if (!userEnvs.hasOwnProperty(expectedEnv)) {
57
57
  throw new error_1.FirebaseError("Build specified parameter " +
58
58
  expectedEnv +
59
- " but it was not present in the user dotenv files");
59
+ " but it was not present in the user dotenv files or Cloud Secret Manager");
60
60
  }
61
61
  }
62
62
  const bkEndpoints = [];
63
63
  for (const endpointId of Object.keys(build.endpoints)) {
64
- const endpoint = build.endpoints[endpointId];
65
- let regions = endpoint.region;
64
+ const bdEndpoint = build.endpoints[endpointId];
65
+ let regions = bdEndpoint.region;
66
66
  if (typeof regions === "undefined") {
67
67
  regions = [api.functionsDefaultRegion];
68
68
  }
69
69
  for (const region of regions) {
70
- const trigger = discoverTrigger(endpoint);
71
- if (typeof endpoint.platform === "undefined") {
70
+ const trigger = discoverTrigger(bdEndpoint);
71
+ if (typeof bdEndpoint.platform === "undefined") {
72
72
  throw new error_1.FirebaseError("platform can't be undefined");
73
73
  }
74
- if (!isMemoryOption(endpoint.availableMemoryMb)) {
74
+ if (!isMemoryOption(bdEndpoint.availableMemoryMb)) {
75
75
  throw new error_1.FirebaseError("available memory must be a supported value, if present");
76
76
  }
77
77
  let timeout;
78
- if (endpoint.timeoutSeconds) {
79
- timeout = resolveInt(endpoint.timeoutSeconds);
78
+ if (bdEndpoint.timeoutSeconds) {
79
+ timeout = resolveInt(bdEndpoint.timeoutSeconds);
80
80
  }
81
81
  else {
82
82
  timeout = 60;
83
83
  }
84
- const bkEndpoint = Object.assign({ id: endpointId, project: endpoint.project, region: region, entryPoint: endpoint.entryPoint, platform: endpoint.platform, runtime: endpoint.runtime, timeoutSeconds: timeout }, trigger);
85
- proto.renameIfPresent(bkEndpoint, endpoint, "maxInstances", "maxInstances", resolveInt);
86
- proto.renameIfPresent(bkEndpoint, endpoint, "minInstances", "minInstances", resolveInt);
87
- proto.renameIfPresent(bkEndpoint, endpoint, "concurrency", "concurrency", resolveInt);
88
- proto.copyIfPresent(bkEndpoint, endpoint, "ingressSettings", "availableMemoryMb", "environmentVariables", "labels");
89
- if (endpoint.vpc) {
84
+ const bkEndpoint = Object.assign({ id: endpointId, project: bdEndpoint.project, region: region, entryPoint: bdEndpoint.entryPoint, platform: bdEndpoint.platform, runtime: bdEndpoint.runtime, timeoutSeconds: timeout }, trigger);
85
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "maxInstances", "maxInstances", resolveInt);
86
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "minInstances", "minInstances", resolveInt);
87
+ proto.renameIfPresent(bkEndpoint, bdEndpoint, "concurrency", "concurrency", resolveInt);
88
+ proto.copyIfPresent(bkEndpoint, bdEndpoint, "ingressSettings", "availableMemoryMb", "environmentVariables", "labels");
89
+ proto.copyIfPresent(bkEndpoint, bdEndpoint, "secretEnvironmentVariables");
90
+ if (bdEndpoint.vpc) {
90
91
  bkEndpoint.vpc = {
91
- connector: resolveString(endpoint.vpc.connector).replace("$REGION", region),
92
+ connector: resolveString(bdEndpoint.vpc.connector).replace("$REGION", region),
92
93
  };
93
- proto.copyIfPresent(bkEndpoint.vpc, endpoint.vpc, "egressSettings");
94
+ proto.copyIfPresent(bkEndpoint.vpc, bdEndpoint.vpc, "egressSettings");
94
95
  }
95
- if (endpoint.serviceAccount) {
96
- bkEndpoint.serviceAccountEmail = endpoint.serviceAccount;
96
+ if (bdEndpoint.serviceAccount) {
97
+ bkEndpoint.serviceAccountEmail = bdEndpoint.serviceAccount;
97
98
  }
98
99
  bkEndpoints.push(bkEndpoint);
99
100
  }
@@ -116,7 +117,7 @@ function discoverTrigger(endpoint) {
116
117
  trigger = { callableTrigger: {} };
117
118
  }
118
119
  else if ("blockingTrigger" in endpoint) {
119
- throw new error_1.FirebaseError("blocking triggers not supported");
120
+ trigger = { blockingTrigger: endpoint.blockingTrigger };
120
121
  }
121
122
  else if ("eventTrigger" in endpoint) {
122
123
  const bkEventFilters = {};
@@ -143,7 +144,18 @@ function discoverTrigger(endpoint) {
143
144
  schedule: resolveString(endpoint.scheduleTrigger.schedule),
144
145
  timeZone: resolveString(endpoint.scheduleTrigger.timeZone),
145
146
  };
146
- proto.renameIfPresent(bkSchedule, endpoint.scheduleTrigger, "retryConfig", "retryConfig", resolveInt);
147
+ const bkRetry = {};
148
+ if (endpoint.scheduleTrigger.retryConfig.maxBackoffSeconds) {
149
+ bkRetry.maxBackoffDuration = proto.durationFromSeconds(resolveInt(endpoint.scheduleTrigger.retryConfig.maxBackoffSeconds));
150
+ }
151
+ if (endpoint.scheduleTrigger.retryConfig.minBackoffSeconds) {
152
+ bkRetry.minBackoffDuration = proto.durationFromSeconds(resolveInt(endpoint.scheduleTrigger.retryConfig.minBackoffSeconds));
153
+ }
154
+ if (endpoint.scheduleTrigger.retryConfig.maxRetrySeconds) {
155
+ bkRetry.maxRetryDuration = proto.durationFromSeconds(resolveInt(endpoint.scheduleTrigger.retryConfig.maxRetrySeconds));
156
+ }
157
+ proto.copyIfPresent(bkRetry, endpoint.scheduleTrigger.retryConfig, "retryCount", "maxDoublings");
158
+ bkSchedule.retryConfig = bkRetry;
147
159
  trigger = { scheduleTrigger: bkSchedule };
148
160
  }
149
161
  else if ("taskQueueTrigger" in endpoint) {
@@ -1,7 +1,19 @@
1
1
  "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
2
13
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.backendFromV1Alpha1 = void 0;
14
+ exports.backendFromV1Alpha1 = exports.buildFromV1Alpha1 = void 0;
4
15
  const backend = require("../../backend");
16
+ const build = require("../../build");
5
17
  const proto_1 = require("../../../../gcp/proto");
6
18
  const parsing_1 = require("./parsing");
7
19
  const error_1 = require("../../../../error");
@@ -11,6 +23,25 @@ const CHANNEL_NAME_REGEX = new RegExp("(projects\\/" +
11
23
  "(?<location>[A-Za-z\\d\\-_]+)\\/" +
12
24
  "channels\\/" +
13
25
  "(?<channel>[A-Za-z\\d\\-_]+)");
26
+ function buildFromV1Alpha1(yaml, project, region, runtime) {
27
+ const manifest = JSON.parse(JSON.stringify(yaml));
28
+ (0, parsing_1.requireKeys)("", manifest, "endpoints");
29
+ (0, parsing_1.assertKeyTypes)("", manifest, {
30
+ specVersion: "string",
31
+ requiredAPIs: "array",
32
+ endpoints: "object",
33
+ });
34
+ const bd = build.empty();
35
+ bd.requiredAPIs = parseRequiredAPIs(manifest);
36
+ for (const id of Object.keys(manifest.endpoints)) {
37
+ const me = manifest.endpoints[id];
38
+ assertManifestEndpoint(me, id);
39
+ const be = parseEndpointForBuild(id, me, project, region, runtime);
40
+ bd.endpoints[id] = be;
41
+ }
42
+ return bd;
43
+ }
44
+ exports.buildFromV1Alpha1 = buildFromV1Alpha1;
14
45
  function backendFromV1Alpha1(yaml, project, region, runtime) {
15
46
  const manifest = JSON.parse(JSON.stringify(yaml));
16
47
  const bkend = backend.empty();
@@ -42,10 +73,8 @@ function parseRequiredAPIs(manifest) {
42
73
  }
43
74
  return requiredAPIs;
44
75
  }
45
- function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
46
- const allParsed = [];
76
+ function assertManifestEndpoint(ep, id) {
47
77
  const prefix = `endpoints[${id}]`;
48
- const ep = manifest.endpoints[id];
49
78
  (0, parsing_1.assertKeyTypes)(prefix, ep, {
50
79
  region: "array",
51
80
  platform: (platform) => backend.AllFunctionsPlatforms.includes(platform),
@@ -101,19 +130,163 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
101
130
  if (triggerCount > 1) {
102
131
  throw new error_1.FirebaseError("Multiple triggers defined for endpoint" + id);
103
132
  }
133
+ if (backend.isEventTriggered(ep)) {
134
+ (0, parsing_1.requireKeys)(prefix + ".eventTrigger", ep.eventTrigger, "eventType", "eventFilters");
135
+ (0, parsing_1.assertKeyTypes)(prefix + ".eventTrigger", ep.eventTrigger, {
136
+ eventFilters: "object",
137
+ eventFilterPathPatterns: "object",
138
+ eventType: "string",
139
+ retry: "boolean",
140
+ region: "string",
141
+ serviceAccountEmail: "string",
142
+ channel: "string",
143
+ });
144
+ }
145
+ else if (backend.isHttpsTriggered(ep)) {
146
+ (0, parsing_1.assertKeyTypes)(prefix + ".httpsTrigger", ep.httpsTrigger, {
147
+ invoker: "array",
148
+ });
149
+ }
150
+ else if (backend.isCallableTriggered(ep)) {
151
+ }
152
+ else if (backend.isScheduleTriggered(ep)) {
153
+ (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
154
+ schedule: "string",
155
+ timeZone: "string",
156
+ retryConfig: "object",
157
+ });
158
+ (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger.retryConfig", ep.scheduleTrigger.retryConfig, {
159
+ retryCount: "number",
160
+ maxDoublings: "number",
161
+ minBackoffDuration: "string",
162
+ maxBackoffDuration: "string",
163
+ maxRetryDuration: "string",
164
+ });
165
+ }
166
+ else if (backend.isTaskQueueTriggered(ep)) {
167
+ (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger", ep.taskQueueTrigger, {
168
+ rateLimits: "object",
169
+ retryConfig: "object",
170
+ invoker: "array",
171
+ });
172
+ if (ep.taskQueueTrigger.rateLimits) {
173
+ (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.rateLimits", ep.taskQueueTrigger.rateLimits, {
174
+ maxConcurrentDispatches: "number",
175
+ maxDispatchesPerSecond: "number",
176
+ });
177
+ }
178
+ if (ep.taskQueueTrigger.retryConfig) {
179
+ (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.retryConfig", ep.taskQueueTrigger.retryConfig, {
180
+ maxAttempts: "number",
181
+ maxRetrySeconds: "number",
182
+ minBackoffSeconds: "number",
183
+ maxBackoffSeconds: "number",
184
+ maxDoublings: "number",
185
+ });
186
+ }
187
+ }
188
+ else if (backend.isBlockingTriggered(ep)) {
189
+ (0, parsing_1.requireKeys)(prefix + ".blockingTrigger", ep.blockingTrigger, "eventType");
190
+ (0, parsing_1.assertKeyTypes)(prefix + ".blockingTrigger", ep.blockingTrigger, {
191
+ eventType: "string",
192
+ options: "object",
193
+ });
194
+ }
195
+ else {
196
+ throw new error_1.FirebaseError(`Do not recognize trigger type for endpoint ${id}. Try upgrading ` +
197
+ "firebase-tools with npm install -g firebase-tools@latest");
198
+ }
199
+ }
200
+ function parseEndpointForBuild(id, ep, project, defaultRegion, runtime) {
201
+ let triggered;
202
+ if (backend.isEventTriggered(ep)) {
203
+ const _a = ep.eventTrigger, { serviceAccountEmail } = _a, newTrigger = __rest(_a, ["serviceAccountEmail"]);
204
+ triggered = { eventTrigger: newTrigger };
205
+ triggered.eventTrigger.serviceAccount = ep.eventTrigger.serviceAccountEmail;
206
+ (0, proto_1.renameIfPresent)(triggered.eventTrigger, ep.eventTrigger, "channel", "channel", (c) => resolveChannelName(project, c, defaultRegion));
207
+ for (const [k, v] of Object.entries(triggered.eventTrigger.eventFilters)) {
208
+ if (k === "topic" && !v.startsWith("projects/")) {
209
+ triggered.eventTrigger.eventFilters[k] = `projects/${project}/topics/${v}`;
210
+ }
211
+ }
212
+ }
213
+ else if (backend.isHttpsTriggered(ep)) {
214
+ triggered = { httpsTrigger: {} };
215
+ (0, proto_1.copyIfPresent)(triggered.httpsTrigger, ep.httpsTrigger, "invoker");
216
+ }
217
+ else if (backend.isCallableTriggered(ep)) {
218
+ triggered = { callableTrigger: {} };
219
+ }
220
+ else if (backend.isScheduleTriggered(ep)) {
221
+ const st = {
222
+ schedule: ep.scheduleTrigger.schedule || "",
223
+ timeZone: ep.scheduleTrigger.timeZone || "",
224
+ retryConfig: {},
225
+ };
226
+ if (ep.scheduleTrigger.retryConfig) {
227
+ st.retryConfig = {
228
+ retryCount: ep.scheduleTrigger.retryConfig.retryCount,
229
+ maxDoublings: ep.scheduleTrigger.retryConfig.maxDoublings,
230
+ };
231
+ if (ep.scheduleTrigger.retryConfig.maxRetryDuration) {
232
+ st.retryConfig.maxRetrySeconds = (0, proto_1.secondsFromDuration)(ep.scheduleTrigger.retryConfig.maxRetryDuration);
233
+ }
234
+ if (ep.scheduleTrigger.retryConfig.maxBackoffDuration) {
235
+ st.retryConfig.maxBackoffSeconds = (0, proto_1.secondsFromDuration)(ep.scheduleTrigger.retryConfig.maxBackoffDuration);
236
+ }
237
+ if (ep.scheduleTrigger.retryConfig.minBackoffDuration) {
238
+ st.retryConfig.minBackoffSeconds = (0, proto_1.secondsFromDuration)(ep.scheduleTrigger.retryConfig.minBackoffDuration);
239
+ }
240
+ }
241
+ triggered = { scheduleTrigger: st };
242
+ }
243
+ else if (backend.isTaskQueueTriggered(ep)) {
244
+ const tq = {
245
+ invoker: ep.taskQueueTrigger.invoker,
246
+ rateLimits: ep.taskQueueTrigger.rateLimits,
247
+ };
248
+ if (ep.taskQueueTrigger.retryConfig) {
249
+ tq.retryConfig = {
250
+ maxRetryDurationSeconds: ep.taskQueueTrigger.retryConfig.maxRetrySeconds,
251
+ maxBackoffSeconds: ep.taskQueueTrigger.retryConfig.maxBackoffSeconds,
252
+ minBackoffSeconds: ep.taskQueueTrigger.retryConfig.minBackoffSeconds,
253
+ maxDoublings: ep.taskQueueTrigger.retryConfig.maxDoublings,
254
+ maxAttempts: ep.taskQueueTrigger.retryConfig.maxAttempts,
255
+ };
256
+ }
257
+ triggered = { taskQueueTrigger: tq };
258
+ }
259
+ else if (backend.isBlockingTriggered(ep)) {
260
+ triggered = { blockingTrigger: ep.blockingTrigger };
261
+ }
262
+ else {
263
+ throw new error_1.FirebaseError(`Do not recognize trigger type for endpoint ${id}. Try upgrading ` +
264
+ "firebase-tools with npm install -g firebase-tools@latest");
265
+ }
266
+ const parsed = Object.assign({ platform: ep.platform || "gcfv2", region: ep.region || [defaultRegion], project,
267
+ runtime, entryPoint: ep.entryPoint, serviceAccount: ep.serviceAccountEmail || "default" }, triggered);
268
+ (0, proto_1.copyIfPresent)(parsed, ep, "availableMemoryMb", "maxInstances", "minInstances", "concurrency", "timeoutSeconds", "vpc", "labels", "ingressSettings", "environmentVariables");
269
+ (0, proto_1.renameIfPresent)(parsed, ep, "secretEnvironmentVariables", "secretEnvironmentVariables", (senvs) => {
270
+ const secretEnvironmentVariables = [];
271
+ for (const { key, secret } of senvs) {
272
+ secretEnvironmentVariables.push({
273
+ key,
274
+ secret: secret || key,
275
+ projectId: project,
276
+ });
277
+ }
278
+ return secretEnvironmentVariables;
279
+ });
280
+ return parsed;
281
+ }
282
+ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
283
+ const allParsed = [];
284
+ const prefix = `endpoints[${id}]`;
285
+ const ep = manifest.endpoints[id];
286
+ assertManifestEndpoint(ep, prefix);
104
287
  for (const region of ep.region || [defaultRegion]) {
105
288
  let triggered;
106
289
  if (backend.isEventTriggered(ep)) {
107
- (0, parsing_1.requireKeys)(prefix + ".eventTrigger", ep.eventTrigger, "eventType", "eventFilters");
108
- (0, parsing_1.assertKeyTypes)(prefix + ".eventTrigger", ep.eventTrigger, {
109
- eventFilters: "object",
110
- eventFilterPathPatterns: "object",
111
- eventType: "string",
112
- retry: "boolean",
113
- region: "string",
114
- serviceAccountEmail: "string",
115
- channel: "string",
116
- });
117
290
  triggered = { eventTrigger: ep.eventTrigger };
118
291
  (0, proto_1.renameIfPresent)(triggered.eventTrigger, ep.eventTrigger, "channel", "channel", (c) => resolveChannelName(project, c, defaultRegion));
119
292
  for (const [k, v] of Object.entries(triggered.eventTrigger.eventFilters)) {
@@ -123,9 +296,6 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
123
296
  }
124
297
  }
125
298
  else if (backend.isHttpsTriggered(ep)) {
126
- (0, parsing_1.assertKeyTypes)(prefix + ".httpsTrigger", ep.httpsTrigger, {
127
- invoker: "array",
128
- });
129
299
  triggered = { httpsTrigger: {} };
130
300
  (0, proto_1.copyIfPresent)(triggered.httpsTrigger, ep.httpsTrigger, "invoker");
131
301
  }
@@ -133,49 +303,12 @@ function parseEndpoints(manifest, id, project, defaultRegion, runtime) {
133
303
  triggered = { callableTrigger: {} };
134
304
  }
135
305
  else if (backend.isScheduleTriggered(ep)) {
136
- (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger", ep.scheduleTrigger, {
137
- schedule: "string",
138
- timeZone: "string",
139
- retryConfig: "object",
140
- });
141
- (0, parsing_1.assertKeyTypes)(prefix + ".scheduleTrigger.retryConfig", ep.scheduleTrigger.retryConfig, {
142
- retryCount: "number",
143
- maxDoublings: "number",
144
- minBackoffDuration: "string",
145
- maxBackoffDuration: "string",
146
- maxRetryDuration: "string",
147
- });
148
306
  triggered = { scheduleTrigger: ep.scheduleTrigger };
149
307
  }
150
308
  else if (backend.isTaskQueueTriggered(ep)) {
151
- (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger", ep.taskQueueTrigger, {
152
- rateLimits: "object",
153
- retryConfig: "object",
154
- invoker: "array",
155
- });
156
- if (ep.taskQueueTrigger.rateLimits) {
157
- (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.rateLimits", ep.taskQueueTrigger.rateLimits, {
158
- maxConcurrentDispatches: "number",
159
- maxDispatchesPerSecond: "number",
160
- });
161
- }
162
- if (ep.taskQueueTrigger.retryConfig) {
163
- (0, parsing_1.assertKeyTypes)(prefix + ".taskQueueTrigger.retryConfig", ep.taskQueueTrigger.retryConfig, {
164
- maxAttempts: "number",
165
- maxRetrySeconds: "number",
166
- minBackoffSeconds: "number",
167
- maxBackoffSeconds: "number",
168
- maxDoublings: "number",
169
- });
170
- }
171
309
  triggered = { taskQueueTrigger: ep.taskQueueTrigger };
172
310
  }
173
311
  else if (backend.isBlockingTriggered(ep)) {
174
- (0, parsing_1.requireKeys)(prefix + ".blockingTrigger", ep.blockingTrigger, "eventType");
175
- (0, parsing_1.assertKeyTypes)(prefix + ".blockingTrigger", ep.blockingTrigger, {
176
- eventType: "string",
177
- options: "object",
178
- });
179
312
  triggered = { blockingTrigger: ep.blockingTrigger };
180
313
  }
181
314
  else {
@@ -139,10 +139,22 @@ function addResourcesToBuild(projectId, runtime, annotation, want) {
139
139
  triggered = {
140
140
  scheduleTrigger: {
141
141
  schedule: annotation.schedule.schedule,
142
- timeZone: annotation.schedule.timeZone || "what's the default timezone?",
143
- retryConfig: annotation.schedule.retryConfig || {},
142
+ timeZone: annotation.schedule.timeZone || "America/Los_Angeles",
143
+ retryConfig: {},
144
144
  },
145
145
  };
146
+ if (annotation.schedule.retryConfig) {
147
+ if (annotation.schedule.retryConfig.maxBackoffDuration) {
148
+ triggered.scheduleTrigger.retryConfig.maxBackoffSeconds = proto.secondsFromDuration(annotation.schedule.retryConfig.maxBackoffDuration);
149
+ }
150
+ if (annotation.schedule.retryConfig.minBackoffDuration) {
151
+ triggered.scheduleTrigger.retryConfig.minBackoffSeconds = proto.secondsFromDuration(annotation.schedule.retryConfig.minBackoffDuration);
152
+ }
153
+ if (annotation.schedule.retryConfig.maxRetryDuration) {
154
+ triggered.scheduleTrigger.retryConfig.maxRetrySeconds = proto.secondsFromDuration(annotation.schedule.retryConfig.maxRetryDuration);
155
+ }
156
+ proto.copyIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxDoublings", "retryCount");
157
+ }
146
158
  }
147
159
  else if (annotation.blockingTrigger) {
148
160
  if (events.v1.AUTH_BLOCKING_EVENTS.includes(annotation.blockingTrigger.eventType)) {
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureDatabaseTriggerRegion = void 0;
4
+ const error_1 = require("../../../error");
5
+ function ensureDatabaseTriggerRegion(endpoint) {
6
+ if (!endpoint.eventTrigger.region) {
7
+ endpoint.eventTrigger.region = endpoint.region;
8
+ }
9
+ if (endpoint.eventTrigger.region !== endpoint.region) {
10
+ throw new error_1.FirebaseError("A database trigger location must match the function region.");
11
+ }
12
+ return Promise.resolve();
13
+ }
14
+ exports.ensureDatabaseTriggerRegion = ensureDatabaseTriggerRegion;
@@ -5,6 +5,7 @@ const backend = require("../backend");
5
5
  const auth_1 = require("./auth");
6
6
  const storage_1 = require("./storage");
7
7
  const firebaseAlerts_1 = require("./firebaseAlerts");
8
+ const database_1 = require("./database");
8
9
  const noop = () => Promise.resolve();
9
10
  exports.noop = noop;
10
11
  const noopProjectBindings = () => Promise.resolve([]);
@@ -45,6 +46,15 @@ const firebaseAlertsService = {
45
46
  unregisterTrigger: exports.noop,
46
47
  };
47
48
  const authBlockingService = new auth_1.AuthBlockingService();
49
+ const databaseService = {
50
+ name: "database",
51
+ api: "firebasedatabase.googleapis.com",
52
+ requiredProjectBindings: exports.noopProjectBindings,
53
+ ensureTriggerRegion: database_1.ensureDatabaseTriggerRegion,
54
+ validateTrigger: exports.noop,
55
+ registerTrigger: exports.noop,
56
+ unregisterTrigger: exports.noop,
57
+ };
48
58
  const EVENT_SERVICE_MAPPING = {
49
59
  "google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
50
60
  "google.cloud.storage.object.v1.finalized": storageService,
@@ -54,6 +64,10 @@ const EVENT_SERVICE_MAPPING = {
54
64
  "google.firebase.firebasealerts.alerts.v1.published": firebaseAlertsService,
55
65
  "providers/cloud.auth/eventTypes/user.beforeCreate": authBlockingService,
56
66
  "providers/cloud.auth/eventTypes/user.beforeSignIn": authBlockingService,
67
+ "google.firebase.database.ref.v1.written": databaseService,
68
+ "google.firebase.database.ref.v1.created": databaseService,
69
+ "google.firebase.database.ref.v1.updated": databaseService,
70
+ "google.firebase.database.ref.v1.deleted": databaseService,
57
71
  };
58
72
  function serviceForEndpoint(endpoint) {
59
73
  if (backend.isEventTriggered(endpoint)) {
@@ -9,7 +9,7 @@ const projectUtils_1 = require("../projectUtils");
9
9
  const utils_1 = require("../utils");
10
10
  const error_1 = require("../error");
11
11
  const track_1 = require("../track");
12
- const lifecycleHooks = require("./lifecycleHooks");
12
+ const lifecycleHooks_1 = require("./lifecycleHooks");
13
13
  const previews_1 = require("../previews");
14
14
  const HostingTarget = require("./hosting");
15
15
  const DatabaseTarget = require("./database");
@@ -54,11 +54,11 @@ const deploy = async function (targetNames, options, customContext = {}) {
54
54
  if (!target) {
55
55
  return Promise.reject(new error_1.FirebaseError((0, cli_color_1.bold)(targetName) + " is not a valid deploy target", { exit: 1 }));
56
56
  }
57
- predeploys.push(lifecycleHooks(targetName, "predeploy"));
57
+ predeploys.push((0, lifecycleHooks_1.lifecycleHooks)(targetName, "predeploy"));
58
58
  prepares.push(target.prepare);
59
59
  deploys.push(target.deploy);
60
60
  releases.push(target.release);
61
- postdeploys.push(lifecycleHooks(targetName, "postdeploy"));
61
+ postdeploys.push((0, lifecycleHooks_1.lifecycleHooks)(targetName, "postdeploy"));
62
62
  }
63
63
  logger_1.logger.info();
64
64
  logger_1.logger.info((0, cli_color_1.bold)((0, cli_color_1.white)("===") + " Deploying to '" + projectId + "'..."));
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lifecycleHooks = void 0;
2
4
  const _ = require("lodash");
3
5
  const utils = require("../utils");
4
6
  const clc = require("cli-color");
5
7
  const childProcess = require("child_process");
6
- const { FirebaseError } = require("../error");
8
+ const error_1 = require("../error");
7
9
  const needProjectId = require("../projectUtils").needProjectId;
8
- const { logger } = require("../logger");
10
+ const logger_1 = require("../logger");
9
11
  const path = require("path");
10
12
  function runCommand(command, childOptions) {
11
13
  const escapedCommand = command.replace(/\"/g, '\\"');
@@ -16,16 +18,16 @@ function runCommand(command, childOptions) {
16
18
  '" "' +
17
19
  escapedCommand +
18
20
  '"';
19
- return new Promise(function (resolve, reject) {
20
- logger.info("Running command: " + command);
21
+ return new Promise((resolve, reject) => {
22
+ logger_1.logger.info("Running command: " + command);
21
23
  if (translatedCommand === "") {
22
- resolve();
24
+ return resolve();
23
25
  }
24
26
  const child = childProcess.spawn(translatedCommand, [], childOptions);
25
- child.on("error", function (err) {
27
+ child.on("error", (err) => {
26
28
  reject(err);
27
29
  });
28
- child.on("exit", function (code, signal) {
30
+ child.on("exit", (code, signal) => {
29
31
  if (signal) {
30
32
  reject(new Error("Command terminated with signal " + signal));
31
33
  }
@@ -72,8 +74,8 @@ function runTargetCommands(target, hook, overallOptions, config) {
72
74
  shell: true,
73
75
  stdio: [0, 1, 2],
74
76
  };
75
- const runAllCommands = _.reduce(commands, function (soFar, command) {
76
- return soFar.then(function () {
77
+ const runAllCommands = _.reduce(commands, (soFar, command) => {
78
+ return soFar.then(() => {
77
79
  return runCommand(command, childOptions);
78
80
  });
79
81
  }, Promise.resolve());
@@ -82,11 +84,11 @@ function runTargetCommands(target, hook, overallOptions, config) {
82
84
  logIdentifier += `[${config.target}]`;
83
85
  }
84
86
  return runAllCommands
85
- .then(function () {
87
+ .then(() => {
86
88
  utils.logSuccess(clc.green.bold(logIdentifier + ":") + " Finished running " + clc.bold(hook) + " script.");
87
89
  })
88
- .catch(function (err) {
89
- throw new FirebaseError(logIdentifier + " " + hook + " error: " + err.message);
90
+ .catch((err) => {
91
+ throw new error_1.FirebaseError(logIdentifier + " " + hook + " error: " + err.message);
90
92
  });
91
93
  }
92
94
  function getReleventConfigs(target, options) {
@@ -100,27 +102,28 @@ function getReleventConfigs(target, options) {
100
102
  if (!options.only) {
101
103
  return targetConfigs;
102
104
  }
103
- var onlyTargets = options.only.split(",");
105
+ let onlyTargets = options.only.split(",");
104
106
  if (_.includes(onlyTargets, target)) {
105
107
  return targetConfigs;
106
108
  }
107
109
  onlyTargets = onlyTargets
108
- .filter(function (individualOnly) {
110
+ .filter((individualOnly) => {
109
111
  return individualOnly.indexOf(`${target}:`) === 0;
110
112
  })
111
- .map(function (individualOnly) {
113
+ .map((individualOnly) => {
112
114
  return individualOnly.replace(`${target}:`, "");
113
115
  });
114
- return targetConfigs.filter(function (config) {
116
+ return targetConfigs.filter((config) => {
115
117
  return !config.target || _.includes(onlyTargets, config.target);
116
118
  });
117
119
  }
118
- module.exports = function (target, hook) {
120
+ function lifecycleHooks(target, hook) {
119
121
  return function (context, options) {
120
- return _.reduce(getReleventConfigs(target, options), function (previousCommands, individualConfig) {
121
- return previousCommands.then(function () {
122
+ return _.reduce(getReleventConfigs(target, options), (previousCommands, individualConfig) => {
123
+ return previousCommands.then(() => {
122
124
  return runTargetCommands(target, hook, options, individualConfig);
123
125
  });
124
126
  }, Promise.resolve());
125
127
  };
126
- };
128
+ }
129
+ exports.lifecycleHooks = lifecycleHooks;
@@ -1,21 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.publishTemplate = exports.deployTemplate = exports.validateInputRemoteConfigTemplate = exports.getEtag = void 0;
4
+ const api_1 = require("../../api");
5
+ const apiv2_1 = require("../../apiv2");
4
6
  const error_1 = require("../../error");
5
- const api = require("../../api");
6
7
  const TIMEOUT = 30000;
8
+ const client = new apiv2_1.Client({ urlPrefix: api_1.remoteConfigApiOrigin, apiVersion: "v1" });
7
9
  async function getEtag(projectNumber, versionNumber) {
8
- let reqPath = `/v1/projects/${projectNumber}/remoteConfig`;
10
+ const reqPath = `/projects/${projectNumber}/remoteConfig`;
11
+ const queryParams = {};
9
12
  if (versionNumber) {
10
- reqPath = reqPath + "?versionNumber=" + versionNumber;
13
+ queryParams.versionNumber = versionNumber;
11
14
  }
12
- const response = await api.request("GET", reqPath, {
13
- auth: true,
14
- origin: api.remoteConfigApiOrigin,
15
- timeout: TIMEOUT,
15
+ const response = await client.request({
16
+ method: "GET",
17
+ path: reqPath,
18
+ queryParams,
16
19
  headers: { "Accept-Encoding": "gzip" },
20
+ timeout: TIMEOUT,
17
21
  });
18
- return response.response.headers.etag;
22
+ return response.response.headers.get("etag") || "";
19
23
  }
20
24
  exports.getEtag = getEtag;
21
25
  function validateInputRemoteConfigTemplate(template) {
@@ -33,20 +37,20 @@ function validateInputRemoteConfigTemplate(template) {
33
37
  }
34
38
  exports.validateInputRemoteConfigTemplate = validateInputRemoteConfigTemplate;
35
39
  async function deployTemplate(projectNumber, template, etag, options) {
36
- const reqPath = `/v1/projects/${projectNumber}/remoteConfig`;
40
+ const reqPath = `/projects/${projectNumber}/remoteConfig`;
37
41
  if (options === null || options === void 0 ? void 0 : options.force) {
38
42
  etag = "*";
39
43
  }
40
- const response = await api.request("PUT", reqPath, {
41
- auth: true,
42
- origin: api.remoteConfigApiOrigin,
43
- timeout: TIMEOUT,
44
+ const response = await client.request({
45
+ method: "PUT",
46
+ path: reqPath,
44
47
  headers: { "If-Match": etag },
45
- data: {
48
+ body: {
46
49
  conditions: template.conditions,
47
50
  parameters: template.parameters,
48
51
  parameterGroups: template.parameterGroups,
49
52
  },
53
+ timeout: TIMEOUT,
50
54
  });
51
55
  return response.body;
52
56
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const projectUtils_1 = require("../../projectUtils");
4
- const loadCJSON = require("../../loadCJSON");
4
+ const loadCJSON_1 = require("../../loadCJSON");
5
5
  const functions_1 = require("./functions");
6
6
  const functions_2 = require("./functions");
7
7
  async function default_1(context, options) {
@@ -13,7 +13,7 @@ async function default_1(context, options) {
13
13
  if (!filePath) {
14
14
  return;
15
15
  }
16
- const template = loadCJSON(filePath);
16
+ const template = (0, loadCJSON_1.loadCJSON)(filePath);
17
17
  const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
18
18
  template.etag = await (0, functions_1.getEtag)(projectNumber);
19
19
  (0, functions_2.validateInputRemoteConfigTemplate)(template);