firebase-tools 9.19.0 → 9.23.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 (101) hide show
  1. package/CHANGELOG.md +1 -3
  2. package/lib/api.js +3 -0
  3. package/lib/apiv2.js +7 -4
  4. package/lib/commands/crashlytics-symbols-upload.js +146 -0
  5. package/lib/commands/deploy.js +9 -1
  6. package/lib/commands/ext-configure.js +3 -1
  7. package/lib/commands/ext-dev-deprecate.js +63 -0
  8. package/lib/commands/ext-dev-undeprecate.js +56 -0
  9. package/lib/commands/ext-dev-unpublish.js +10 -3
  10. package/lib/commands/ext-export.js +44 -0
  11. package/lib/commands/ext-install.js +24 -3
  12. package/lib/commands/ext-uninstall.js +6 -0
  13. package/lib/commands/ext-update.js +10 -3
  14. package/lib/commands/functions-config-export.js +115 -0
  15. package/lib/commands/functions-delete.js +47 -25
  16. package/lib/commands/functions-list.js +12 -12
  17. package/lib/commands/index.js +9 -0
  18. package/lib/commands/init.js +3 -0
  19. package/lib/config.js +3 -2
  20. package/lib/deploy/extensions/args.js +2 -0
  21. package/lib/deploy/extensions/deploy.js +49 -0
  22. package/lib/deploy/extensions/deploymentSummary.js +52 -0
  23. package/lib/deploy/extensions/errors.js +31 -0
  24. package/lib/deploy/extensions/index.js +8 -0
  25. package/lib/deploy/extensions/params.js +39 -0
  26. package/lib/deploy/extensions/planner.js +94 -0
  27. package/lib/deploy/extensions/prepare.js +111 -0
  28. package/lib/deploy/extensions/release.js +43 -0
  29. package/lib/deploy/extensions/secrets.js +150 -0
  30. package/lib/deploy/extensions/tasks.js +98 -0
  31. package/lib/deploy/extensions/validate.js +17 -0
  32. package/lib/deploy/functions/backend.js +93 -115
  33. package/lib/deploy/functions/checkIam.js +8 -8
  34. package/lib/deploy/functions/containerCleaner.js +71 -14
  35. package/lib/deploy/functions/deploy.js +4 -10
  36. package/lib/deploy/functions/functionsDeployHelper.js +3 -68
  37. package/lib/deploy/functions/prepare.js +63 -27
  38. package/lib/deploy/functions/pricing.js +17 -17
  39. package/lib/deploy/functions/prompts.js +22 -21
  40. package/lib/deploy/functions/release/executor.js +39 -0
  41. package/lib/deploy/functions/release/fabricator.js +422 -0
  42. package/lib/deploy/functions/release/index.js +73 -0
  43. package/lib/deploy/functions/release/planner.js +162 -0
  44. package/lib/deploy/functions/release/reporter.js +165 -0
  45. package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
  46. package/lib/deploy/functions/release/timer.js +14 -0
  47. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +129 -126
  48. package/lib/deploy/functions/runtimes/node/parseTriggers.js +41 -45
  49. package/lib/deploy/functions/triggerRegionHelper.js +40 -0
  50. package/lib/deploy/functions/validate.js +1 -24
  51. package/lib/deploy/index.js +10 -1
  52. package/lib/downloadUtils.js +37 -0
  53. package/lib/emulator/auth/apiSpec.js +549 -6
  54. package/lib/emulator/auth/handlers.js +4 -3
  55. package/lib/emulator/auth/operations.js +154 -14
  56. package/lib/emulator/auth/server.js +26 -15
  57. package/lib/emulator/auth/state.js +151 -13
  58. package/lib/emulator/download.js +2 -31
  59. package/lib/emulator/downloadableEmulators.js +7 -7
  60. package/lib/emulator/functionsEmulator.js +18 -4
  61. package/lib/emulator/functionsEmulatorRuntime.js +29 -7
  62. package/lib/emulator/storage/cloudFunctions.js +37 -7
  63. package/lib/extensions/askUserForConsent.js +14 -1
  64. package/lib/extensions/askUserForParam.js +81 -4
  65. package/lib/extensions/checkProjectBilling.js +7 -7
  66. package/lib/extensions/export.js +107 -0
  67. package/lib/extensions/extensionsApi.js +104 -21
  68. package/lib/extensions/extensionsHelper.js +6 -2
  69. package/lib/extensions/listExtensions.js +16 -11
  70. package/lib/extensions/paramHelper.js +9 -6
  71. package/lib/extensions/provisioningHelper.js +16 -3
  72. package/lib/extensions/refs.js +9 -1
  73. package/lib/extensions/secretsUtils.js +59 -0
  74. package/lib/extensions/updateHelper.js +12 -2
  75. package/lib/extensions/versionHelper.js +14 -0
  76. package/lib/extensions/warnings.js +33 -1
  77. package/lib/functional.js +8 -1
  78. package/lib/functions/env.js +10 -4
  79. package/lib/functions/runtimeConfigExport.js +137 -0
  80. package/lib/gcp/artifactregistry.js +16 -0
  81. package/lib/gcp/cloudfunctions.js +20 -74
  82. package/lib/gcp/cloudfunctionsv2.js +12 -90
  83. package/lib/gcp/cloudscheduler.js +22 -16
  84. package/lib/gcp/cloudtasks.js +143 -0
  85. package/lib/gcp/docker.js +7 -1
  86. package/lib/gcp/proto.js +2 -2
  87. package/lib/gcp/pubsub.js +1 -9
  88. package/lib/gcp/secretManager.js +132 -0
  89. package/lib/gcp/storage.js +16 -0
  90. package/lib/projectUtils.js +10 -1
  91. package/lib/requireInteractive.js +12 -0
  92. package/lib/utils.js +30 -1
  93. package/package.json +5 -4
  94. package/schema/firebase-config.json +9 -0
  95. package/lib/deploy/functions/deploymentPlanner.js +0 -113
  96. package/lib/deploy/functions/deploymentTimer.js +0 -23
  97. package/lib/deploy/functions/errorHandler.js +0 -75
  98. package/lib/deploy/functions/release.js +0 -116
  99. package/lib/deploy/functions/tasks.js +0 -324
  100. package/lib/functions/listFunctions.js +0 -10
  101. package/lib/functionsDelete.js +0 -60
@@ -1,12 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.displayWarningPrompts = void 0;
3
+ exports.displayWarningsForDeploy = exports.displayWarningPrompts = void 0;
4
4
  const marked = require("marked");
5
5
  const clc = require("cli-color");
6
6
  const extensionsApi_1 = require("./extensionsApi");
7
7
  const displayExtensionInfo_1 = require("./displayExtensionInfo");
8
8
  const extensionsHelper_1 = require("./extensionsHelper");
9
9
  const resolveSource_1 = require("./resolveSource");
10
+ const deploymentSummary_1 = require("../deploy/extensions/deploymentSummary");
11
+ const planner_1 = require("../deploy/extensions/planner");
12
+ const functional_1 = require("../functional");
10
13
  const utils = require("../utils");
11
14
  function displayEAPWarning({ publisherId, sourceDownloadUri, githubLink, }) {
12
15
  const publisherNameLink = githubLink ? `[${publisherId}](${githubLink})` : publisherId;
@@ -35,3 +38,32 @@ async function displayWarningPrompts(publisherId, launchStage, extensionVersion)
35
38
  }
36
39
  }
37
40
  exports.displayWarningPrompts = displayWarningPrompts;
41
+ const toListEntry = (i) => {
42
+ var _a, _b, _c, _d;
43
+ const idAndRef = deploymentSummary_1.humanReadable(i);
44
+ const sourceCodeLink = `\n\t[Source Code](${(_a = i.extensionVersion) === null || _a === void 0 ? void 0 : _a.sourceDownloadUri})`;
45
+ const githubLink = ((_c = (_b = i.extensionVersion) === null || _b === void 0 ? void 0 : _b.spec) === null || _c === void 0 ? void 0 : _c.sourceUrl) ? `\n\t[Publisher Contact](${(_d = i.extensionVersion) === null || _d === void 0 ? void 0 : _d.spec.sourceUrl})`
46
+ : "";
47
+ return `${idAndRef}${sourceCodeLink}${githubLink}`;
48
+ };
49
+ async function displayWarningsForDeploy(instancesToCreate) {
50
+ const trustedPublishers = await resolveSource_1.getTrustedPublishers();
51
+ for (const i of instancesToCreate) {
52
+ await planner_1.getExtension(i);
53
+ await planner_1.getExtensionVersion(i);
54
+ }
55
+ const [eapExtensions, nonEapExtensions] = functional_1.partition(instancesToCreate, (i) => { var _a, _b; return !trustedPublishers.includes((_b = (_a = i.ref) === null || _a === void 0 ? void 0 : _a.publisherId) !== null && _b !== void 0 ? _b : ""); });
56
+ const experimental = nonEapExtensions.filter((i) => i.extension.registryLaunchStage === extensionsApi_1.RegistryLaunchStage.EXPERIMENTAL);
57
+ if (experimental.length) {
58
+ const humanReadableList = experimental.map((i) => `\t${deploymentSummary_1.humanReadable(i)}`).join("\n");
59
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`The following are instances of ${clc.bold("experimental")} extensions.They may not be production-ready. Their functionality may change in backward-incompatible ways before their official release, or they may be discontinued.\n${humanReadableList}\n`));
60
+ }
61
+ if (eapExtensions.length) {
62
+ const humanReadableList = eapExtensions.map(toListEntry).join("\n");
63
+ utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`These extensions are in preview and are built by a developer in the Extensions Publisher Early Access Program (http://bit.ly/firex-provider. Their functionality might change in backwards-incompatible ways. Since these extensions aren't built by Firebase, reach out to their publisher with questions about them.` +
64
+ ` They are provided “AS IS”, without any warranty, express or implied, from Google.` +
65
+ ` Google disclaims all liability for any damages, direct or indirect, resulting from the use of these extensions\n${humanReadableList}`));
66
+ }
67
+ return experimental.length > 0 || eapExtensions.length > 0;
68
+ }
69
+ exports.displayWarningsForDeploy = displayWarningsForDeploy;
package/lib/functional.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assertExhaustive = exports.zipIn = exports.zip = exports.reduceFlat = exports.flatten = exports.flattenArray = exports.flattenObject = void 0;
3
+ exports.partition = exports.assertExhaustive = exports.zipIn = exports.zip = exports.reduceFlat = exports.flatten = exports.flattenArray = exports.flattenObject = void 0;
4
4
  function* flattenObject(obj) {
5
5
  function* helper(path, obj) {
6
6
  for (const [k, v] of Object.entries(obj)) {
@@ -55,3 +55,10 @@ function assertExhaustive(val) {
55
55
  throw new Error(`Never has a value (${val}). This should be impossible`);
56
56
  }
57
57
  exports.assertExhaustive = assertExhaustive;
58
+ function partition(arr, callbackFn) {
59
+ return arr.reduce((acc, elem) => {
60
+ acc[callbackFn(elem) ? 0 : 1].push(elem);
61
+ return acc;
62
+ }, [[], []]);
63
+ }
64
+ exports.partition = partition;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.validateKey = exports.parse = void 0;
3
+ exports.loadFirebaseEnvs = exports.loadUserEnvs = exports.hasUserEnvs = exports.validateKey = exports.KeyValidationError = exports.parse = void 0;
4
4
  const clc = require("cli-color");
5
5
  const fs = require("fs");
6
6
  const path = require("path");
@@ -72,17 +72,23 @@ function parse(data) {
72
72
  }
73
73
  exports.parse = parse;
74
74
  class KeyValidationError extends Error {
75
+ constructor(key, message) {
76
+ super(`Failed to validate key ${key}: ${message}`);
77
+ this.key = key;
78
+ this.message = message;
79
+ }
75
80
  }
81
+ exports.KeyValidationError = KeyValidationError;
76
82
  function validateKey(key) {
77
83
  if (RESERVED_KEYS.includes(key)) {
78
- throw new KeyValidationError(`Key ${key} is reserved for internal use.`);
84
+ throw new KeyValidationError(key, `Key ${key} is reserved for internal use.`);
79
85
  }
80
86
  if (!/^[A-Z_][A-Z0-9_]*$/.test(key)) {
81
- throw new KeyValidationError(`Key ${key} must start with an uppercase ASCII letter or underscore` +
87
+ throw new KeyValidationError(key, `Key ${key} must start with an uppercase ASCII letter or underscore` +
82
88
  ", and then consist of uppercase ASCII letters, digits, and underscores.");
83
89
  }
84
90
  if (key.startsWith("X_GOOGLE_") || key.startsWith("FIREBASE_")) {
85
- throw new KeyValidationError(`Key ${key} starts with a reserved prefix (X_GOOGLE_ or FIREBASE_)`);
91
+ throw new KeyValidationError(key, `Key ${key} starts with a reserved prefix (X_GOOGLE_ or FIREBASE_)`);
86
92
  }
87
93
  }
88
94
  exports.validateKey = validateKey;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateDotenvFilename = exports.toDotenvFormat = exports.hydrateEnvs = exports.configToEnv = exports.convertKey = exports.hydrateConfigs = exports.getProjectInfos = void 0;
4
+ const clc = require("cli-color");
5
+ const env = require("./env");
6
+ const functionsConfig = require("../functionsConfig");
7
+ const error_1 = require("../error");
8
+ const logger_1 = require("../logger");
9
+ const projectUtils_1 = require("../projectUtils");
10
+ const rc_1 = require("../rc");
11
+ const utils_1 = require("../utils");
12
+ const functional_1 = require("../functional");
13
+ function getProjectInfos(options) {
14
+ const result = {};
15
+ const rc = rc_1.loadRC(options);
16
+ if (rc.projects) {
17
+ for (const [alias, projectId] of Object.entries(rc.projects)) {
18
+ if (Object.keys(result).includes(projectId)) {
19
+ utils_1.logWarning(`Multiple aliases found for ${clc.bold(projectId)}. ` +
20
+ `Preferring alias (${clc.bold(result[projectId])}) over (${clc.bold(alias)}).`);
21
+ continue;
22
+ }
23
+ result[projectId] = alias;
24
+ }
25
+ }
26
+ const projectId = projectUtils_1.getProjectId(options);
27
+ if (projectId && !Object.keys(result).includes(projectId)) {
28
+ result[projectId] = projectId;
29
+ }
30
+ return Object.entries(result).map(([k, v]) => {
31
+ const result = { projectId: k };
32
+ if (k !== v) {
33
+ result.alias = v;
34
+ }
35
+ return result;
36
+ });
37
+ }
38
+ exports.getProjectInfos = getProjectInfos;
39
+ async function hydrateConfigs(pInfos) {
40
+ const hydrate = pInfos.map((info) => {
41
+ return functionsConfig
42
+ .materializeAll(info.projectId)
43
+ .then((config) => {
44
+ info.config = config;
45
+ return;
46
+ })
47
+ .catch((err) => {
48
+ logger_1.logger.debug(`Failed to fetch runtime config for project ${info.projectId}: ${err.message}`);
49
+ });
50
+ });
51
+ await Promise.all(hydrate);
52
+ }
53
+ exports.hydrateConfigs = hydrateConfigs;
54
+ function convertKey(configKey, prefix) {
55
+ const baseKey = configKey
56
+ .toUpperCase()
57
+ .replace(/\./g, "_")
58
+ .replace(/-/g, "_");
59
+ let envKey = baseKey;
60
+ try {
61
+ env.validateKey(envKey);
62
+ }
63
+ catch (err) {
64
+ if (err instanceof env.KeyValidationError) {
65
+ envKey = prefix + envKey;
66
+ env.validateKey(envKey);
67
+ }
68
+ }
69
+ return envKey;
70
+ }
71
+ exports.convertKey = convertKey;
72
+ function configToEnv(configs, prefix) {
73
+ const success = [];
74
+ const errors = [];
75
+ for (const [configKey, value] of functional_1.flatten(configs)) {
76
+ try {
77
+ const envKey = convertKey(configKey, prefix);
78
+ success.push({ origKey: configKey, newKey: envKey, value: value });
79
+ }
80
+ catch (err) {
81
+ if (err instanceof env.KeyValidationError) {
82
+ errors.push({
83
+ origKey: configKey,
84
+ newKey: err.key,
85
+ err: err.message,
86
+ value: value,
87
+ });
88
+ }
89
+ else {
90
+ throw new error_1.FirebaseError("Unexpected error while converting config", {
91
+ exit: 2,
92
+ original: err,
93
+ });
94
+ }
95
+ }
96
+ }
97
+ return { success, errors };
98
+ }
99
+ exports.configToEnv = configToEnv;
100
+ function hydrateEnvs(pInfos, prefix) {
101
+ let errMsg = "";
102
+ for (const pInfo of pInfos) {
103
+ const { success, errors } = configToEnv(pInfo.config, prefix);
104
+ if (errors.length > 0) {
105
+ const msg = `${pInfo.projectId} ` +
106
+ `${pInfo.alias ? "(" + pInfo.alias + ")" : ""}:\n` +
107
+ errors.map((err) => `\t${err.origKey} => ${clc.bold(err.newKey)} (${err.err})`).join("\n") +
108
+ "\n";
109
+ errMsg += msg;
110
+ }
111
+ else {
112
+ pInfo.envs = success;
113
+ }
114
+ }
115
+ return errMsg;
116
+ }
117
+ exports.hydrateEnvs = hydrateEnvs;
118
+ function escape(s) {
119
+ const result = s
120
+ .replace("\n", "\\n")
121
+ .replace("\r", "\\r")
122
+ .replace("\t", "\\t")
123
+ .replace("\v", "\\v");
124
+ return result.replace(/(['"])/g, "\\$1");
125
+ }
126
+ function toDotenvFormat(envs, header = "") {
127
+ const lines = envs.map(({ newKey, value }) => `${newKey}="${escape(value)}"`);
128
+ const maxLineLen = Math.max(...lines.map((l) => l.length));
129
+ return (`${header}\n` +
130
+ lines.map((line, idx) => `${line.padEnd(maxLineLen)} # from ${envs[idx].origKey}`).join("\n"));
131
+ }
132
+ exports.toDotenvFormat = toDotenvFormat;
133
+ function generateDotenvFilename(pInfo) {
134
+ var _a;
135
+ return `.env.${(_a = pInfo.alias) !== null && _a !== void 0 ? _a : pInfo.projectId}`;
136
+ }
137
+ exports.generateDotenvFilename = generateDotenvFilename;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deletePackage = exports.API_VERSION = void 0;
4
+ const apiv2_1 = require("../apiv2");
5
+ const api_1 = require("../api");
6
+ exports.API_VERSION = "v1beta2";
7
+ const client = new apiv2_1.Client({
8
+ urlPrefix: api_1.artifactRegistryDomain,
9
+ auth: true,
10
+ apiVersion: exports.API_VERSION,
11
+ });
12
+ async function deletePackage(name) {
13
+ const res = await client.delete(name);
14
+ return res.body;
15
+ }
16
+ exports.deletePackage = deletePackage;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.functionFromEndpoint = exports.endpointFromFunction = exports.functionFromSpec = exports.specFromFunction = exports.listAllFunctions = exports.listFunctions = exports.deleteFunction = exports.updateFunction = exports.setInvokerUpdate = exports.setInvokerCreate = exports.getIamPolicy = exports.setIamPolicy = exports.createFunction = exports.generateUploadUrl = exports.API_VERSION = void 0;
3
+ exports.functionFromEndpoint = exports.endpointFromFunction = exports.listAllFunctions = exports.listFunctions = exports.deleteFunction = exports.updateFunction = exports.setInvokerUpdate = exports.setInvokerCreate = exports.getIamPolicy = exports.setIamPolicy = exports.createFunction = exports.generateUploadUrl = exports.API_VERSION = void 0;
4
4
  const clc = require("cli-color");
5
5
  const error_1 = require("../error");
6
6
  const logger_1 = require("../logger");
@@ -51,6 +51,7 @@ async function createFunction(cloudFunction) {
51
51
  const endpoint = `/${exports.API_VERSION}/${apiPath}`;
52
52
  try {
53
53
  const res = await api.request("POST", endpoint, {
54
+ headers: { "X-Firebase-Artifact-Registry": "optin" },
54
55
  auth: true,
55
56
  data: cloudFunction,
56
57
  origin: api.functionsOrigin,
@@ -146,6 +147,7 @@ async function updateFunction(cloudFunction) {
146
147
  const fieldMasks = proto.fieldMasks(cloudFunction, "labels", "environmentVariables");
147
148
  try {
148
149
  const res = await api.request("PATCH", endpoint, {
150
+ headers: { "X-Firebase-Artifact-Registry": "optin" },
149
151
  qs: {
150
152
  updateMask: fieldMasks.join(","),
151
153
  },
@@ -198,9 +200,11 @@ async function list(projectId, region) {
198
200
  };
199
201
  }
200
202
  catch (err) {
201
- logger_1.logger.debug("[functions] failed to list functions for " + projectId);
203
+ logger_1.logger.debug(`[functions] failed to list functions for ${projectId}`);
202
204
  logger_1.logger.debug(`[functions] ${err === null || err === void 0 ? void 0 : err.message}`);
203
- return Promise.reject(err === null || err === void 0 ? void 0 : err.message);
205
+ throw new error_1.FirebaseError(`Failed to list functions for ${projectId}`, {
206
+ original: err,
207
+ });
204
208
  }
205
209
  }
206
210
  async function listFunctions(projectId, region) {
@@ -212,87 +216,25 @@ async function listAllFunctions(projectId) {
212
216
  return list(projectId, "-");
213
217
  }
214
218
  exports.listAllFunctions = listAllFunctions;
215
- function specFromFunction(gcfFunction) {
216
- var _a;
219
+ function endpointFromFunction(gcfFunction) {
220
+ var _a, _b, _c;
217
221
  const [, project, , region, , id] = gcfFunction.name.split("/");
218
222
  let trigger;
219
223
  let uri;
220
- if (gcfFunction.httpsTrigger) {
221
- trigger = {};
222
- uri = gcfFunction.httpsTrigger.url;
223
- }
224
- else {
224
+ if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
225
225
  trigger = {
226
- eventType: gcfFunction.eventTrigger.eventType,
227
- eventFilters: {
228
- resource: gcfFunction.eventTrigger.resource,
229
- },
230
- retry: !!((_a = gcfFunction.eventTrigger.failurePolicy) === null || _a === void 0 ? void 0 : _a.retry),
226
+ scheduleTrigger: {},
231
227
  };
232
228
  }
233
- if (!runtimes.isValidRuntime(gcfFunction.runtime)) {
234
- logger_1.logger.debug("GCFv1 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
235
- }
236
- const cloudFunction = {
237
- platform: "gcfv1",
238
- id,
239
- project,
240
- region,
241
- trigger,
242
- entryPoint: gcfFunction.entryPoint,
243
- runtime: gcfFunction.runtime,
244
- };
245
- if (uri) {
246
- cloudFunction.uri = uri;
247
- }
248
- proto.copyIfPresent(cloudFunction, gcfFunction, "serviceAccountEmail", "availableMemoryMb", "timeout", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables", "sourceUploadUrl");
249
- return cloudFunction;
250
- }
251
- exports.specFromFunction = specFromFunction;
252
- function functionFromSpec(cloudFunction, sourceUploadUrl) {
253
- if (cloudFunction.platform != "gcfv1") {
254
- throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
255
- }
256
- if (!runtimes.isValidRuntime(cloudFunction.runtime)) {
257
- throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
258
- " This should never happen");
259
- }
260
- const gcfFunction = {
261
- name: backend.functionName(cloudFunction),
262
- sourceUploadUrl: sourceUploadUrl,
263
- entryPoint: cloudFunction.entryPoint,
264
- runtime: cloudFunction.runtime,
265
- };
266
- if (backend.isEventTrigger(cloudFunction.trigger)) {
267
- gcfFunction.eventTrigger = {
268
- eventType: cloudFunction.trigger.eventType,
269
- resource: cloudFunction.trigger.eventFilters.resource,
229
+ else if ((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) {
230
+ trigger = {
231
+ taskQueueTrigger: {},
270
232
  };
271
- gcfFunction.eventTrigger.failurePolicy = cloudFunction.trigger.retry
272
- ? { retry: {} }
273
- : undefined;
274
233
  }
275
- else {
276
- gcfFunction.httpsTrigger = {};
277
- }
278
- proto.copyIfPresent(gcfFunction, cloudFunction, "serviceAccountEmail", "timeout", "availableMemoryMb", "minInstances", "maxInstances", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "labels", "environmentVariables");
279
- return gcfFunction;
280
- }
281
- exports.functionFromSpec = functionFromSpec;
282
- function endpointFromFunction(gcfFunction) {
283
- var _a, _b;
284
- const [, project, , region, , id] = gcfFunction.name.split("/");
285
- let trigger;
286
- let uri;
287
- if (gcfFunction.httpsTrigger) {
234
+ else if (gcfFunction.httpsTrigger) {
288
235
  trigger = { httpsTrigger: {} };
289
236
  uri = gcfFunction.httpsTrigger.url;
290
237
  }
291
- else if ((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) {
292
- trigger = {
293
- scheduleTrigger: {},
294
- };
295
- }
296
238
  else {
297
239
  trigger = {
298
240
  eventTrigger: {
@@ -300,7 +242,7 @@ function endpointFromFunction(gcfFunction) {
300
242
  eventFilters: {
301
243
  resource: gcfFunction.eventTrigger.resource,
302
244
  },
303
- retry: !!((_b = gcfFunction.eventTrigger.failurePolicy) === null || _b === void 0 ? void 0 : _b.retry),
245
+ retry: !!((_c = gcfFunction.eventTrigger.failurePolicy) === null || _c === void 0 ? void 0 : _c.retry),
304
246
  },
305
247
  };
306
248
  }
@@ -349,6 +291,10 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
349
291
  };
350
292
  gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
351
293
  }
294
+ else if (backend.isTaskQueueTriggered(endpoint)) {
295
+ gcfFunction.httpsTrigger = {};
296
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
297
+ }
352
298
  else {
353
299
  gcfFunction.httpsTrigger = {};
354
300
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.endpointFromFunction = exports.functionFromEndpoint = exports.specFromFunction = exports.functionFromSpec = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.PUBSUB_PUBLISH_EVENT = exports.API_VERSION = void 0;
3
+ exports.endpointFromFunction = exports.functionFromEndpoint = exports.deleteFunction = exports.updateFunction = exports.listAllFunctions = exports.listFunctions = exports.getFunction = exports.createFunction = exports.generateUploadUrl = exports.PUBSUB_PUBLISH_EVENT = exports.API_VERSION = void 0;
4
4
  const clc = require("cli-color");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const error_1 = require("../error");
@@ -115,93 +115,6 @@ async function deleteFunction(cloudFunction) {
115
115
  }
116
116
  }
117
117
  exports.deleteFunction = deleteFunction;
118
- function functionFromSpec(cloudFunction, source) {
119
- if (cloudFunction.platform != "gcfv2") {
120
- throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
121
- }
122
- if (!runtimes.isValidRuntime(cloudFunction.runtime)) {
123
- throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
124
- " This should never happen");
125
- }
126
- const gcfFunction = {
127
- name: backend.functionName(cloudFunction),
128
- buildConfig: {
129
- runtime: cloudFunction.runtime,
130
- entryPoint: cloudFunction.entryPoint,
131
- source: {
132
- storageSource: source,
133
- },
134
- environmentVariables: {},
135
- },
136
- serviceConfig: {},
137
- };
138
- proto.copyIfPresent(gcfFunction.serviceConfig, cloudFunction, "availableMemoryMb", "environmentVariables", "vpcConnector", "vpcConnectorEgressSettings", "serviceAccountEmail", "ingressSettings");
139
- proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "timeoutSeconds", "timeout", proto.secondsFromDuration);
140
- proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "minInstanceCount", "minInstances");
141
- proto.renameIfPresent(gcfFunction.serviceConfig, cloudFunction, "maxInstanceCount", "maxInstances");
142
- if (backend.isEventTrigger(cloudFunction.trigger)) {
143
- gcfFunction.eventTrigger = {
144
- eventType: cloudFunction.trigger.eventType,
145
- };
146
- if (gcfFunction.eventTrigger.eventType === exports.PUBSUB_PUBLISH_EVENT) {
147
- gcfFunction.eventTrigger.pubsubTopic = cloudFunction.trigger.eventFilters.resource;
148
- }
149
- else {
150
- gcfFunction.eventTrigger.eventFilters = [];
151
- for (const [attribute, value] of Object.entries(cloudFunction.trigger.eventFilters)) {
152
- gcfFunction.eventTrigger.eventFilters.push({ attribute, value });
153
- }
154
- }
155
- if (cloudFunction.trigger.retry) {
156
- logger_1.logger.warn("Cannot set a retry policy on Cloud Function", cloudFunction.id);
157
- }
158
- }
159
- proto.copyIfPresent(gcfFunction, cloudFunction, "labels");
160
- return gcfFunction;
161
- }
162
- exports.functionFromSpec = functionFromSpec;
163
- function specFromFunction(gcfFunction) {
164
- const [, project, , region, , id] = gcfFunction.name.split("/");
165
- let trigger;
166
- if (gcfFunction.eventTrigger) {
167
- trigger = {
168
- eventType: gcfFunction.eventTrigger.eventType,
169
- eventFilters: {},
170
- retry: false,
171
- };
172
- if (gcfFunction.eventTrigger.pubsubTopic) {
173
- trigger.eventFilters.resource = gcfFunction.eventTrigger.pubsubTopic;
174
- }
175
- else {
176
- for (const { attribute, value } of gcfFunction.eventTrigger.eventFilters || []) {
177
- trigger.eventFilters[attribute] = value;
178
- }
179
- }
180
- }
181
- else {
182
- trigger = {};
183
- }
184
- if (!runtimes.isValidRuntime(gcfFunction.buildConfig.runtime)) {
185
- logger_1.logger.debug("GCFv2 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
186
- }
187
- const cloudFunction = {
188
- platform: "gcfv2",
189
- id,
190
- project,
191
- region,
192
- trigger,
193
- entryPoint: gcfFunction.buildConfig.entryPoint,
194
- runtime: gcfFunction.buildConfig.runtime,
195
- uri: gcfFunction.serviceConfig.uri,
196
- };
197
- proto.copyIfPresent(cloudFunction, gcfFunction.serviceConfig, "serviceAccountEmail", "availableMemoryMb", "vpcConnector", "vpcConnectorEgressSettings", "ingressSettings", "environmentVariables");
198
- proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "timeout", "timeoutSeconds", proto.durationFromSeconds);
199
- proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "minInstances", "minInstanceCount");
200
- proto.renameIfPresent(cloudFunction, gcfFunction.serviceConfig, "maxInstances", "maxInstanceCount");
201
- proto.copyIfPresent(cloudFunction, gcfFunction, "labels");
202
- return cloudFunction;
203
- }
204
- exports.specFromFunction = specFromFunction;
205
118
  function functionFromEndpoint(endpoint, source) {
206
119
  if (endpoint.platform != "gcfv2") {
207
120
  throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
@@ -245,13 +158,16 @@ function functionFromEndpoint(endpoint, source) {
245
158
  }
246
159
  }
247
160
  else if (backend.isScheduleTriggered(endpoint)) {
248
- gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { ["deployment-scheduled"]: "true" });
161
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-scheduled": "true" });
162
+ }
163
+ else if (backend.isTaskQueueTriggered(endpoint)) {
164
+ gcfFunction.labels = Object.assign(Object.assign({}, gcfFunction.labels), { "deployment-taskqueue": "true" });
249
165
  }
250
166
  return gcfFunction;
251
167
  }
252
168
  exports.functionFromEndpoint = functionFromEndpoint;
253
169
  function endpointFromFunction(gcfFunction) {
254
- var _a;
170
+ var _a, _b;
255
171
  const [, project, , region, , id] = gcfFunction.name.split("/");
256
172
  let trigger;
257
173
  if (((_a = gcfFunction.labels) === null || _a === void 0 ? void 0 : _a["deployment-scheduled"]) === "true") {
@@ -259,6 +175,11 @@ function endpointFromFunction(gcfFunction) {
259
175
  scheduleTrigger: {},
260
176
  };
261
177
  }
178
+ else if (((_b = gcfFunction.labels) === null || _b === void 0 ? void 0 : _b["deployment-taskqueue"]) === "true") {
179
+ trigger = {
180
+ taskQueueTrigger: {},
181
+ };
182
+ }
262
183
  else if (gcfFunction.eventTrigger) {
263
184
  trigger = {
264
185
  eventTrigger: {
@@ -275,6 +196,7 @@ function endpointFromFunction(gcfFunction) {
275
196
  trigger.eventTrigger.eventFilters[attribute] = value;
276
197
  }
277
198
  }
199
+ proto.renameIfPresent(trigger.eventTrigger, gcfFunction.eventTrigger, "region", "triggerRegion");
278
200
  }
279
201
  else {
280
202
  trigger = { httpsTrigger: {} };
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jobFromSpec = exports.createOrReplaceJob = exports.updateJob = exports.getJob = exports.deleteJob = exports.createJob = exports.assertValidJob = void 0;
3
+ exports.jobFromEndpoint = exports.createOrReplaceJob = exports.updateJob = exports.getJob = exports.deleteJob = exports.createJob = exports.assertValidJob = void 0;
4
4
  const _ = require("lodash");
5
5
  const error_1 = require("../error");
6
6
  const logger_1 = require("../logger");
7
7
  const api = require("../api");
8
8
  const backend = require("../deploy/functions/backend");
9
9
  const proto = require("./proto");
10
+ const functional_1 = require("../functional");
10
11
  const VERSION = "v1beta1";
11
12
  const DEFAULT_TIME_ZONE = "America/Los_Angeles";
12
13
  function assertValidJob(job) {
@@ -86,21 +87,26 @@ function isIdentical(job, otherJob) {
86
87
  job.timeZone === otherJob.timeZone &&
87
88
  _.isEqual(job.retryConfig, otherJob.retryConfig));
88
89
  }
89
- function jobFromSpec(schedule, appEngineLocation) {
90
- const job = {
91
- name: backend.scheduleName(schedule, appEngineLocation),
92
- schedule: schedule.schedule,
93
- };
94
- proto.copyIfPresent(job, schedule, "timeZone", "retryConfig");
95
- if (schedule.transport === "https") {
96
- throw new error_1.FirebaseError("HTTPS transport for scheduled functions is not yet supported");
90
+ function jobFromEndpoint(endpoint, appEngineLocation) {
91
+ const job = {};
92
+ if (endpoint.platform === "gcfv1") {
93
+ const id = backend.scheduleIdForFunction(endpoint);
94
+ const region = appEngineLocation;
95
+ job.name = `projects/${endpoint.project}/locations/${region}/jobs/${id}`;
96
+ job.pubsubTarget = {
97
+ topicName: `projects/${endpoint.project}/topics/${id}`,
98
+ attributes: {
99
+ scheduled: "true",
100
+ },
101
+ };
97
102
  }
98
- job.pubsubTarget = {
99
- topicName: backend.topicName(schedule),
100
- attributes: {
101
- scheduled: "true",
102
- },
103
- };
103
+ else if (endpoint.platform === "gcfv2") {
104
+ throw new error_1.FirebaseError("Do not know how to create a scheduled GCFv2 function");
105
+ }
106
+ else {
107
+ functional_1.assertExhaustive(endpoint.platform);
108
+ }
109
+ proto.copyIfPresent(job, endpoint.scheduleTrigger, "schedule", "retryConfig", "timeZone");
104
110
  return job;
105
111
  }
106
- exports.jobFromSpec = jobFromSpec;
112
+ exports.jobFromEndpoint = jobFromEndpoint;