firebase-tools-with-isolate
Advanced tools
Comparing version 13.9.0 to 13.11.2
@@ -23,12 +23,18 @@ "use strict"; | ||
const serviceInfo = await (0, load_1.load)(projectId, service.location, configDir); | ||
const args = { | ||
projectId, | ||
configDir, | ||
auto_download: true, | ||
rc: options.rc, | ||
locationId: service.location, | ||
}; | ||
const dataconnectEmulator = new dataconnectEmulator_1.DataConnectEmulator(args); | ||
const hasGeneratables = serviceInfo.connectorInfo.some((c) => { | ||
return (c.connectorYaml.generate?.javascriptSdk || | ||
c.connectorYaml.generate?.kotlinSdk || | ||
c.connectorYaml.generate?.swiftSdk); | ||
}); | ||
if (!hasGeneratables) { | ||
logger_1.logger.warn("No generated SDKs have been declared in connector.yaml files."); | ||
logger_1.logger.warn("See https://firebase.google.com/docs/data-connect/quickstart#configure-sdk-outputs for examples of how to configure generated SDKs."); | ||
return; | ||
} | ||
for (const conn of serviceInfo.connectorInfo) { | ||
const output = await dataconnectEmulator.generate(conn.connectorYaml.connectorId); | ||
const output = await dataconnectEmulator_1.DataConnectEmulator.generate({ | ||
configDir, | ||
locationId: service.location, | ||
connectorId: conn.connectorYaml.connectorId, | ||
}); | ||
logger_1.logger.info(output); | ||
@@ -35,0 +41,0 @@ logger_1.logger.info(`Generated SDKs for ${conn.connectorYaml.connectorId}`); |
@@ -36,3 +36,3 @@ "use strict"; | ||
for (const service of services) { | ||
let schema = { | ||
const schema = (await client.getSchema(service.name)) ?? { | ||
name: "", | ||
@@ -42,8 +42,2 @@ primaryDatasource: {}, | ||
}; | ||
try { | ||
schema = await client.getSchema(service.name); | ||
} | ||
catch (err) { | ||
logger_1.logger.debug(`Error fetching schema: ${err}`); | ||
} | ||
const connectors = await client.listConnectors(service.name); | ||
@@ -50,0 +44,0 @@ const serviceName = names.parseServiceName(service.name); |
@@ -35,3 +35,2 @@ "use strict"; | ||
schema: serviceInfo.schema, | ||
allowNonInteractiveMigration: true, | ||
validateOnly: true, | ||
@@ -38,0 +37,0 @@ }); |
@@ -15,6 +15,7 @@ "use strict"; | ||
path.join(os.homedir(), ".cache", "firebase", "crashlytics", "buildtools"); | ||
const JAR_VERSION = "2.9.2"; | ||
const JAR_VERSION = "3.0.0"; | ||
const JAR_URL = `https://dl.google.com/android/maven2/com/google/firebase/firebase-crashlytics-buildtools/${JAR_VERSION}/firebase-crashlytics-buildtools-${JAR_VERSION}.jar`; | ||
async function fetchBuildtoolsJar() { | ||
if (process.env.CRASHLYTICS_LOCAL_JAR) { | ||
logger_1.logger.debug(`Using local Crashlytics Jar override at ${process.env.CRASHLYTICS_LOCAL_JAR}`); | ||
return process.env.CRASHLYTICS_LOCAL_JAR; | ||
@@ -21,0 +22,0 @@ } |
@@ -8,11 +8,3 @@ "use strict"; | ||
async function build(options, configDir) { | ||
const projectId = options.project ?? "demo-test"; | ||
const args = { | ||
projectId, | ||
configDir, | ||
auto_download: true, | ||
rc: options.rc, | ||
}; | ||
const dataconnectEmulator = new dataconnectEmulator_1.DataConnectEmulator(args); | ||
const buildResult = await dataconnectEmulator.build(); | ||
const buildResult = await dataconnectEmulator_1.DataConnectEmulator.build({ configDir }); | ||
if (buildResult?.errors?.length) { | ||
@@ -19,0 +11,0 @@ throw new error_1.FirebaseError(`There are errors in your schema and connector files:\n${buildResult.errors.map(graphqlError_1.prettify).join("\n")}`); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.upsertSchema = exports.getSchema = exports.deleteService = exports.createService = exports.listServices = exports.listAllServices = exports.listLocations = void 0; | ||
exports.upsertConnector = exports.listConnectors = exports.deleteConnector = exports.getConnector = exports.upsertSchema = exports.getSchema = exports.deleteService = exports.createService = exports.listAllServices = exports.listLocations = void 0; | ||
const api_1 = require("../api"); | ||
@@ -8,3 +8,2 @@ const apiv2_1 = require("../apiv2"); | ||
const types = require("./types"); | ||
const logger_1 = require("../logger"); | ||
const DATACONNECT_API_VERSION = "v1alpha"; | ||
@@ -22,21 +21,6 @@ const dataconnectClient = () => new apiv2_1.Client({ | ||
async function listAllServices(projectId) { | ||
const locations = await listLocations(projectId); | ||
let services = []; | ||
await Promise.all(locations.map(async (l) => { | ||
try { | ||
const locationServices = await listServices(projectId, l); | ||
services = services.concat(locationServices); | ||
} | ||
catch (err) { | ||
logger_1.logger.debug(`Unable to listServices in ${l}: ${err}`); | ||
} | ||
})); | ||
return services; | ||
const res = await dataconnectClient().get(`/projects/${projectId}/locations/-/services`); | ||
return res.body.services ?? []; | ||
} | ||
exports.listAllServices = listAllServices; | ||
async function listServices(projectId, locationId) { | ||
const res = await dataconnectClient().get(`/projects/${projectId}/locations/${locationId}/services`); | ||
return res.body.services ?? []; | ||
} | ||
exports.listServices = listServices; | ||
async function createService(projectId, locationId, serviceId) { | ||
@@ -59,3 +43,3 @@ const op = await dataconnectClient().post(`/projects/${projectId}/locations/${locationId}/services`, { | ||
async function deleteService(projectId, locationId, serviceId) { | ||
const op = await dataconnectClient().delete(`projects/${projectId}/locations/${locationId}/services/${serviceId}?force=true`); | ||
const op = await dataconnectClient().delete(`projects/${projectId}/locations/${locationId}/services/${serviceId}`); | ||
const pollRes = await operationPoller.pollOperation({ | ||
@@ -70,4 +54,12 @@ apiOrigin: (0, api_1.dataconnectOrigin)(), | ||
async function getSchema(serviceName) { | ||
const res = await dataconnectClient().get(`${serviceName}/schemas/${types.SCHEMA_ID}`); | ||
return res.body; | ||
try { | ||
const res = await dataconnectClient().get(`${serviceName}/schemas/${types.SCHEMA_ID}`); | ||
return res.body; | ||
} | ||
catch (err) { | ||
if (err.status !== 404) { | ||
throw err; | ||
} | ||
return undefined; | ||
} | ||
} | ||
@@ -74,0 +66,0 @@ exports.getSchema = getSchema; |
@@ -8,16 +8,19 @@ "use strict"; | ||
function getIncompatibleSchemaError(err) { | ||
const original = err.context?.body?.error || err.orignal; | ||
if (!original) { | ||
throw err; | ||
const incompatibles = errorDetails(err, INCOMPATIBLE_SCHEMA_ERROR_TYPESTRING); | ||
if (incompatibles.length === 0) { | ||
return undefined; | ||
} | ||
const details = original.details; | ||
const incompatibles = details.filter((d) => d["@type"]?.includes(INCOMPATIBLE_SCHEMA_ERROR_TYPESTRING)); | ||
return incompatibles[0]; | ||
const incompatible = incompatibles[0]; | ||
const preconditionErrs = errorDetails(err, PRECONDITION_ERROR_TYPESTRING); | ||
const violationTypes = (incompatible.violationType = preconditionErrs | ||
.flatMap((preCondErr) => preCondErr.violations) | ||
.flatMap((viol) => viol.type) | ||
.filter((type) => type === "INACCESSIBLE_SCHEMA" || type === "INCOMPATIBLE_SCHEMA")); | ||
incompatible.violationType = violationTypes[0]; | ||
return incompatible; | ||
} | ||
exports.getIncompatibleSchemaError = getIncompatibleSchemaError; | ||
function getInvalidConnectors(err) { | ||
const preconditionErrs = errorDetails(err, PRECONDITION_ERROR_TYPESTRING); | ||
const invalidConns = []; | ||
const original = err.context?.body?.error || err?.orignal; | ||
const details = original?.details; | ||
const preconditionErrs = details?.filter((d) => d["@type"]?.includes(PRECONDITION_ERROR_TYPESTRING)); | ||
for (const preconditionErr of preconditionErrs) { | ||
@@ -31,1 +34,6 @@ const incompatibleConnViolation = preconditionErr?.violations?.filter((v) => v.type === INCOMPATIBLE_CONNECTOR_TYPE); | ||
exports.getInvalidConnectors = getInvalidConnectors; | ||
function errorDetails(err, ofType) { | ||
const original = err.context?.body?.error || err?.original; | ||
const details = original?.details; | ||
return details?.filter((d) => d["@type"]?.includes(ofType)) || []; | ||
} |
@@ -6,5 +6,8 @@ "use strict"; | ||
const message = err.message; | ||
let header = err.extensions.file ?? ""; | ||
if (err.locations) { | ||
header += `:${err.locations[0].line}`; | ||
let header = err.extensions?.file ?? ""; | ||
if (err.locations && err.locations.length) { | ||
const line = err.locations[0]?.line ?? ""; | ||
if (line) { | ||
header += `:${line}`; | ||
} | ||
} | ||
@@ -11,0 +14,0 @@ return header.length ? `${header}: ${message}` : message; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.parseConnectorName = exports.parseServiceName = void 0; | ||
exports.parseCloudSQLInstanceName = exports.parseConnectorName = exports.parseServiceName = void 0; | ||
const error_1 = require("../error"); | ||
@@ -47,1 +47,21 @@ const serviceNameRegex = /projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/services\/(?<serviceId>[^\/]+)/; | ||
exports.parseConnectorName = parseConnectorName; | ||
const cloudSQLInstanceNameRegex = /projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/instances\/(?<instanceId>[^\/]+)/; | ||
function parseCloudSQLInstanceName(cloudSQLInstanceName) { | ||
const res = cloudSQLInstanceNameRegex.exec(cloudSQLInstanceName); | ||
const projectId = res?.groups?.projectId; | ||
const location = res?.groups?.location; | ||
const instanceId = res?.groups?.instanceId; | ||
if (!projectId || !location || !instanceId) { | ||
throw new error_1.FirebaseError(`${cloudSQLInstanceName} is not a valid cloudSQL instance name`); | ||
} | ||
const toString = () => { | ||
return `projects/${projectId}/locations/${location}/services/${instanceId}`; | ||
}; | ||
return { | ||
projectId, | ||
location, | ||
instanceId, | ||
toString, | ||
}; | ||
} | ||
exports.parseCloudSQLInstanceName = parseCloudSQLInstanceName; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.checkInstanceConfig = exports.provisionCloudSql = void 0; | ||
exports.getUpdateReason = exports.provisionCloudSql = void 0; | ||
const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin"); | ||
@@ -12,4 +12,4 @@ const utils = require("../utils"); | ||
async function provisionCloudSql(args) { | ||
let connectionName; | ||
const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, silent } = args; | ||
let connectionName = ""; | ||
const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, waitForCreation, silent, } = args; | ||
try { | ||
@@ -19,6 +19,8 @@ const existingInstance = await cloudSqlAdminClient.getInstance(projectId, instanceId); | ||
connectionName = existingInstance?.connectionName || ""; | ||
if (!checkInstanceConfig(existingInstance, enableGoogleMlIntegration)) { | ||
const why = getUpdateReason(existingInstance, enableGoogleMlIntegration); | ||
if (why) { | ||
silent || | ||
utils.logLabeledBullet("dataconnect", `Instance ${instanceId} settings not compatible with Firebase Data Connect. ` + | ||
`Updating instance to enable Cloud IAM authentication and public IP. This may take a few minutes...`); | ||
`Updating instance. This may take a few minutes...` + | ||
why); | ||
await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.updateInstanceForDataConnect(existingInstance, enableGoogleMlIntegration), "Updating your instance..."); | ||
@@ -38,7 +40,13 @@ silent || utils.logLabeledBullet("dataconnect", "Instance updated"); | ||
silent || | ||
utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found, creating it. This instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}`); | ||
silent || utils.logLabeledBullet("dataconnect", `This may take while...`); | ||
const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration), "Creating your instance..."); | ||
silent || utils.logLabeledBullet("dataconnect", "Instance created"); | ||
connectionName = newInstance?.connectionName || ""; | ||
utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found, creating it.` + | ||
`\nThis instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}` + | ||
`\nMonitor the progress at ${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}`); | ||
const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance..."); | ||
if (newInstance) { | ||
silent || utils.logLabeledBullet("dataconnect", "Instance created"); | ||
connectionName = newInstance?.connectionName || ""; | ||
} | ||
else { | ||
silent || utils.logLabeledBullet("dataconnect", "Instance creation process started"); | ||
} | ||
} | ||
@@ -50,6 +58,11 @@ try { | ||
catch (err) { | ||
silent || | ||
utils.logLabeledBullet("dataconnect", `Database ${databaseId} not found, creating it now...`); | ||
await cloudSqlAdminClient.createDatabase(projectId, instanceId, databaseId); | ||
silent || utils.logLabeledBullet("dataconnect", `Database ${databaseId} created.`); | ||
if (err.status === 404) { | ||
silent || | ||
utils.logLabeledBullet("dataconnect", `Database ${databaseId} not found, creating it now...`); | ||
await cloudSqlAdminClient.createDatabase(projectId, instanceId, databaseId); | ||
silent || utils.logLabeledBullet("dataconnect", `Database ${databaseId} created.`); | ||
} | ||
else { | ||
silent || utils.logLabeledWarning("dataconnect", `Database ${databaseId} is not accessible.`); | ||
} | ||
} | ||
@@ -62,18 +75,22 @@ if (enableGoogleMlIntegration) { | ||
exports.provisionCloudSql = provisionCloudSql; | ||
function checkInstanceConfig(instance, requireGoogleMlIntegration) { | ||
function getUpdateReason(instance, requireGoogleMlIntegration) { | ||
let reason = ""; | ||
const settings = instance.settings; | ||
if (!settings.ipConfiguration?.ipv4Enabled) { | ||
return false; | ||
reason += "\n - to enable public IP."; | ||
} | ||
if (requireGoogleMlIntegration) { | ||
if (!settings.enableGoogleMlIntegration) { | ||
return false; | ||
reason += "\n - to enable Google ML integration."; | ||
} | ||
if (!settings.databaseFlags?.some((f) => f.name === "cloudsql.enable_google_ml_integration" && f.value === "on")) { | ||
return false; | ||
reason += "\n - to enable Google ML integration database flag."; | ||
} | ||
} | ||
const isIamEnabled = settings.databaseFlags?.some((f) => f.name === "cloudsql.iam_authentication" && f.value === "on") ?? false; | ||
return isIamEnabled; | ||
if (!isIamEnabled) { | ||
reason += "\n - to enable IAM authentication database flag."; | ||
} | ||
return reason; | ||
} | ||
exports.checkInstanceConfig = checkInstanceConfig; | ||
exports.getUpdateReason = getUpdateReason; |
@@ -17,12 +17,19 @@ "use strict"; | ||
const { serviceName, instanceName, databaseId } = getIdentifiers(schema); | ||
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId); | ||
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, false); | ||
try { | ||
await (0, client_1.upsertSchema)(schema, true); | ||
(0, utils_1.logLabeledSuccess)("dataconnect", `Database schema is up to date.`); | ||
} | ||
catch (err) { | ||
if (err.status !== 400) { | ||
throw err; | ||
} | ||
const invalidConnectors = errors.getInvalidConnectors(err); | ||
const incompatible = errors.getIncompatibleSchemaError(err); | ||
if (!incompatible && !invalidConnectors.length) { | ||
throw err; | ||
} | ||
if (invalidConnectors.length) { | ||
displayInvalidConnectors(invalidConnectors); | ||
} | ||
const incompatible = errors.getIncompatibleSchemaError(err); | ||
if (incompatible) { | ||
@@ -33,3 +40,2 @@ displaySchemaChanges(incompatible); | ||
} | ||
(0, utils_1.logLabeledSuccess)("dataconnect", `Database schema is up to date.`); | ||
return []; | ||
@@ -39,5 +45,5 @@ } | ||
async function migrateSchema(args) { | ||
const { options, schema, allowNonInteractiveMigration, validateOnly } = args; | ||
const { options, schema, validateOnly } = args; | ||
const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema); | ||
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId); | ||
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, true); | ||
try { | ||
@@ -48,2 +54,5 @@ await (0, client_1.upsertSchema)(schema, validateOnly); | ||
catch (err) { | ||
if (err.status !== 400) { | ||
throw err; | ||
} | ||
const incompatible = errors.getIncompatibleSchemaError(err); | ||
@@ -54,13 +63,4 @@ const invalidConnectors = errors.getInvalidConnectors(err); | ||
} | ||
const shouldDeleteInvalidConnectors = await promptForInvalidConnectorError(options, invalidConnectors, validateOnly); | ||
if (!shouldDeleteInvalidConnectors && invalidConnectors.length) { | ||
const cmd = suggestedCommand(serviceName, invalidConnectors); | ||
throw new error_1.FirebaseError(`Command aborted. Try deploying compatible connectors first with ${clc.bold(cmd)}`); | ||
} | ||
const migrationMode = incompatible | ||
? await promptForSchemaMigration(options, databaseId, incompatible, allowNonInteractiveMigration) | ||
: "none"; | ||
if (migrationMode === "none" && incompatible) { | ||
throw new error_1.FirebaseError("Command aborted."); | ||
} | ||
const migrationMode = await promptForSchemaMigration(options, databaseId, incompatible, validateOnly); | ||
const shouldDeleteInvalidConnectors = await promptForInvalidConnectorError(options, serviceName, invalidConnectors, validateOnly); | ||
let diffs = []; | ||
@@ -76,6 +76,8 @@ if (incompatible) { | ||
} | ||
if (invalidConnectors.length) { | ||
if (shouldDeleteInvalidConnectors) { | ||
await deleteInvalidConnectors(invalidConnectors); | ||
} | ||
await (0, client_1.upsertSchema)(schema, validateOnly); | ||
if (!validateOnly) { | ||
await (0, client_1.upsertSchema)(schema, validateOnly); | ||
} | ||
return diffs; | ||
@@ -144,5 +146,11 @@ } | ||
} | ||
async function promptForSchemaMigration(options, databaseName, err, allowNonInteractiveMigration) { | ||
async function promptForSchemaMigration(options, databaseName, err, validateOnly) { | ||
if (!err) { | ||
return "none"; | ||
} | ||
displaySchemaChanges(err); | ||
if (!options.nonInteractive) { | ||
if (validateOnly && options.force) { | ||
return "all"; | ||
} | ||
const choices = err.destructive | ||
@@ -154,3 +162,3 @@ ? [ | ||
: [ | ||
{ name: "Execute changes", value: "safe" }, | ||
{ name: "Execute changes", value: "all" }, | ||
{ name: "Abort changes", value: "none" }, | ||
@@ -164,5 +172,4 @@ ]; | ||
} | ||
else if (!allowNonInteractiveMigration) { | ||
logger_1.logger.error("Your database schema is incompatible with your Data Connect schema. Run `firebase dataconnect:sql:migrate` to migrate your database schema"); | ||
return "none"; | ||
if (!validateOnly) { | ||
throw new error_1.FirebaseError("Command aborted. Your database schema is incompatible with your Data Connect schema. Run `firebase dataconnect:sql:migrate` to migrate your database schema"); | ||
} | ||
@@ -173,10 +180,9 @@ else if (options.force) { | ||
else if (!err.destructive) { | ||
return "safe"; | ||
return "all"; | ||
} | ||
else { | ||
logger_1.logger.error("This schema migration includes potentially destructive changes. If you'd like to execute it anyway, rerun this command with --force"); | ||
return "none"; | ||
throw new error_1.FirebaseError("Command aborted. This schema migration includes potentially destructive changes. If you'd like to execute it anyway, rerun this command with --force"); | ||
} | ||
} | ||
async function promptForInvalidConnectorError(options, invalidConnectors, validateOnly) { | ||
async function promptForInvalidConnectorError(options, serviceName, invalidConnectors, validateOnly) { | ||
if (!invalidConnectors.length) { | ||
@@ -187,13 +193,19 @@ return false; | ||
if (validateOnly) { | ||
return false; | ||
if (options.force) { | ||
return false; | ||
} | ||
throw new error_1.FirebaseError(`Command aborted. If you'd like to migrate it anyway, you may override with --force.`); | ||
} | ||
else if (options.force || | ||
(!options.nonInteractive && | ||
(await (0, prompt_1.confirm)({ | ||
...options, | ||
message: "Would you like to delete and recreate these connectors?", | ||
})))) { | ||
if (options.force) { | ||
return true; | ||
} | ||
return false; | ||
if (!options.nonInteractive && | ||
(await (0, prompt_1.confirm)({ | ||
...options, | ||
message: `Would you like to delete and recreate these connectors? This will cause ${clc.red(`downtime.`)}.`, | ||
}))) { | ||
return true; | ||
} | ||
const cmd = suggestedCommand(serviceName, invalidConnectors); | ||
throw new error_1.FirebaseError(`Command aborted. Try deploying those connectors first with ${clc.bold(cmd)}`); | ||
} | ||
@@ -206,35 +218,38 @@ async function deleteInvalidConnectors(invalidConnectors) { | ||
(0, utils_1.logLabeledWarning)("dataconnect", `The schema you are deploying is incompatible with the following existing connectors: ${connectorIds}.`); | ||
(0, utils_1.logLabeledWarning)("dataconnect", `This is a ${clc.red("breaking")} change and will cause a brief downtime.`); | ||
(0, utils_1.logLabeledWarning)("dataconnect", `This is a ${clc.red("breaking")} change and may break existing apps.`); | ||
} | ||
async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, databaseId) { | ||
let currentSchema; | ||
try { | ||
currentSchema = await (0, client_1.getSchema)(serviceName); | ||
} | ||
catch (err) { | ||
if (err.status === 404) { | ||
currentSchema = { | ||
name: `${serviceName}/schemas/${types_1.SCHEMA_ID}`, | ||
source: { | ||
files: [], | ||
}, | ||
primaryDatasource: { | ||
postgresql: { | ||
database: databaseId, | ||
cloudSql: { | ||
instance: instanceId, | ||
}, | ||
async function ensureServiceIsConnectedToCloudSql(serviceName, instanceId, databaseId, linkIfNotConnected) { | ||
let currentSchema = await (0, client_1.getSchema)(serviceName); | ||
if (!currentSchema) { | ||
if (!linkIfNotConnected) { | ||
(0, utils_1.logLabeledWarning)("dataconnect", `Not yet linked to the Cloud SQL instance.`); | ||
return; | ||
} | ||
(0, utils_1.logLabeledBullet)("dataconnect", `Linking the Cloud SQL instance...`); | ||
currentSchema = { | ||
name: `${serviceName}/schemas/${types_1.SCHEMA_ID}`, | ||
source: { | ||
files: [], | ||
}, | ||
primaryDatasource: { | ||
postgresql: { | ||
database: databaseId, | ||
cloudSql: { | ||
instance: instanceId, | ||
}, | ||
}, | ||
}; | ||
} | ||
else { | ||
throw err; | ||
} | ||
}, | ||
}; | ||
} | ||
if (!currentSchema.primaryDatasource.postgresql || | ||
currentSchema.primaryDatasource.postgresql.schemaValidation === "STRICT") { | ||
const postgresql = currentSchema.primaryDatasource.postgresql; | ||
if (postgresql?.cloudSql.instance !== instanceId) { | ||
(0, utils_1.logLabeledWarning)("dataconnect", `Switching connected Cloud SQL instance\nFrom ${postgresql?.cloudSql.instance}\nTo ${instanceId}`); | ||
} | ||
if (postgresql?.database !== databaseId) { | ||
(0, utils_1.logLabeledWarning)("dataconnect", `Switching connected Postgres database from ${postgresql?.database} to ${databaseId}`); | ||
} | ||
if (!postgresql || postgresql.schemaValidation === "STRICT") { | ||
return; | ||
} | ||
currentSchema.primaryDatasource.postgresql.schemaValidation = "STRICT"; | ||
postgresql.schemaValidation = "STRICT"; | ||
try { | ||
@@ -251,6 +266,23 @@ await (0, client_1.upsertSchema)(currentSchema, false); | ||
function displaySchemaChanges(error) { | ||
const message = "Your new schema is incompatible with the schema of your CloudSQL database. " + | ||
"The following SQL statements will migrate your database schema to match your new Data Connect schema.\n" + | ||
error.diffs.map(toString).join("\n"); | ||
(0, utils_1.logLabeledWarning)("dataconnect", message); | ||
switch (error.violationType) { | ||
case "INCOMPATIBLE_SCHEMA": | ||
{ | ||
const message = "Your new schema is incompatible with the schema of your CloudSQL database. " + | ||
"The following SQL statements will migrate your database schema to match your new Data Connect schema.\n" + | ||
error.diffs.map(toString).join("\n"); | ||
(0, utils_1.logLabeledWarning)("dataconnect", message); | ||
} | ||
break; | ||
case "INACCESSIBLE_SCHEMA": | ||
{ | ||
const message = "Cannot access your CloudSQL database to validate schema. " + | ||
"The following SQL statements can setup a new database schema.\n" + | ||
error.diffs.map(toString).join("\n"); | ||
(0, utils_1.logLabeledWarning)("dataconnect", message); | ||
(0, utils_1.logLabeledWarning)("dataconnect", "Some SQL resources may already exist."); | ||
} | ||
break; | ||
default: | ||
throw new error_1.FirebaseError(`Unknown schema violation type: ${error.violationType}, IncompatibleSqlSchemaError: ${error}`); | ||
} | ||
} | ||
@@ -257,0 +289,0 @@ function toString(diff) { |
@@ -60,2 +60,3 @@ "use strict"; | ||
enableGoogleMlIntegration, | ||
waitForCreation: true, | ||
}); | ||
@@ -62,0 +63,0 @@ })); |
@@ -24,3 +24,2 @@ "use strict"; | ||
schema: s, | ||
allowNonInteractiveMigration: false, | ||
validateOnly: false, | ||
@@ -27,0 +26,0 @@ }); |
@@ -293,3 +293,3 @@ "use strict"; | ||
throw new error_1.FirebaseError(`Functions codebase ${codebase} has invalid runtime ` + | ||
`${firebaseJsonRuntime} specified in firebase.json. Valid values are: ` + | ||
`${firebaseJsonRuntime} specified in firebase.json. Valid values are: \n` + | ||
Object.keys(supported.RUNTIMES) | ||
@@ -296,0 +296,0 @@ .map((s) => `- ${s}`) |
@@ -14,2 +14,3 @@ "use strict"; | ||
exports.readFileAsync = (0, util_1.promisify)(fs.readFile); | ||
const TIMEOUT_OVERRIDE_ENV_VAR = "FUNCTIONS_DISCOVERY_TIMEOUT"; | ||
function yamlToBuild(yaml, project, region, runtime) { | ||
@@ -54,3 +55,3 @@ try { | ||
reject(new error_1.FirebaseError("User code failed to load. Cannot determine backend specification")); | ||
}, timeout); | ||
}, +(process.env[TIMEOUT_OVERRIDE_ENV_VAR] || 0) * 1000 || timeout); | ||
}); | ||
@@ -57,0 +58,0 @@ while (true) { |
@@ -56,2 +56,8 @@ "use strict"; | ||
}, | ||
nodejs22: { | ||
friendly: "Node.js 22", | ||
status: "beta", | ||
deprecationDate: "2027-04-30", | ||
decommissionDate: "2027-10-31", | ||
}, | ||
python310: { | ||
@@ -58,0 +64,0 @@ friendly: "Python 3.10", |
@@ -525,3 +525,2 @@ "use strict"; | ||
if (listenForEmulator.dataconnect) { | ||
const dataConnectAddr = legacyGetFirstAddr(types_1.Emulators.DATACONNECT); | ||
const config = (0, fileUtils_1.readFirebaseJson)(options.config); | ||
@@ -540,4 +539,3 @@ if (!config.length) { | ||
const dataConnectEmulator = new dataconnectEmulator_1.DataConnectEmulator({ | ||
host: dataConnectAddr.host, | ||
port: dataConnectAddr.port, | ||
listen: listenForEmulator.dataconnect, | ||
projectId, | ||
@@ -550,2 +548,5 @@ auto_download: true, | ||
await startEmulator(dataConnectEmulator); | ||
if (!utils.isVSCodeExtension()) { | ||
await dataConnectEmulator.connectToPostgres(); | ||
} | ||
} | ||
@@ -552,0 +553,0 @@ if (listenForEmulator.storage) { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.DataConnectEmulator = void 0; | ||
exports.DataConnectEmulatorClient = exports.DataConnectEmulator = void 0; | ||
const childProcess = require("child_process"); | ||
@@ -12,3 +12,4 @@ const api_1 = require("../api"); | ||
const types_2 = require("../dataconnect/types"); | ||
const grpcDefaultPort = 9510; | ||
const portUtils_1 = require("./portUtils"); | ||
const registry_1 = require("./registry"); | ||
class DataConnectEmulator { | ||
@@ -18,21 +19,23 @@ constructor(args) { | ||
this.logger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT); | ||
this.emulatorClient = new DataConnectEmulatorClient(); | ||
} | ||
async start() { | ||
const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.DATACONNECT); | ||
this.logger.log("DEBUG", `Using Postgres connection string: ${this.getLocalConectionString()}`); | ||
const info = await this.build(); | ||
if ((0, types_2.requiresVector)(info.metadata)) { | ||
if (constants_1.Constants.isDemoProject(this.args.projectId)) { | ||
this.logger.logLabeled("WARN", "Data Connect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail."); | ||
try { | ||
const info = await DataConnectEmulator.build({ configDir: this.args.configDir }); | ||
if ((0, types_2.requiresVector)(info.metadata)) { | ||
if (constants_1.Constants.isDemoProject(this.args.projectId)) { | ||
this.logger.logLabeled("WARN", "Data Connect", "Detected a 'demo-' project, but vector embeddings require a real project. Operations that use vector_embed will fail."); | ||
} | ||
else { | ||
this.logger.logLabeled("WARN", "Data Connect", "Operations that use vector_embed will make calls to production Vertex AI"); | ||
} | ||
} | ||
else { | ||
this.logger.logLabeled("WARN", "Data Connect", "Operations that use vector_embed will make calls to production Vertex AI"); | ||
} | ||
} | ||
catch (err) { | ||
this.logger.log("DEBUG", `'fdc build' failed with error: ${err.message}`); | ||
} | ||
return (0, downloadableEmulators_1.start)(types_1.Emulators.DATACONNECT, { | ||
...this.args, | ||
http_port: port, | ||
grpc_port: grpcDefaultPort, | ||
auto_download: this.args.auto_download, | ||
listen: (0, portUtils_1.listenSpecsToString)(this.args.listen), | ||
config_dir: this.args.configDir, | ||
local_connection_string: this.getLocalConectionString(), | ||
project_id: this.args.projectId, | ||
@@ -49,8 +52,7 @@ service_location: this.args.locationId, | ||
getInfo() { | ||
const host = this.args.host || constants_1.Constants.getDefaultHost(); | ||
const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.DATACONNECT); | ||
return { | ||
name: this.getName(), | ||
host, | ||
port, | ||
listen: this.args.listen, | ||
host: this.args.listen[0].address, | ||
port: this.args.listen[0].port, | ||
pid: (0, downloadableEmulators_1.getPID)(types_1.Emulators.DATACONNECT), | ||
@@ -63,22 +65,32 @@ timeout: 10000, | ||
} | ||
async generate(connectorId) { | ||
static async generate(args) { | ||
const commandInfo = await (0, downloadableEmulators_1.downloadIfNecessary)(types_1.Emulators.DATACONNECT); | ||
const cmd = [ | ||
"generate", | ||
`--service_location=${this.args.locationId}`, | ||
`--config_dir=${this.args.configDir}`, | ||
`--connector_id=${connectorId}`, | ||
`--service_location=${args.locationId}`, | ||
`--config_dir=${args.configDir}`, | ||
`--connector_id=${args.connectorId}`, | ||
]; | ||
const res = childProcess.spawnSync(commandInfo.binary, cmd, { encoding: "utf-8" }); | ||
if (res.error) { | ||
throw new error_1.FirebaseError(`Error starting up Data Connect emulator: ${res.error}`); | ||
throw new error_1.FirebaseError(`Error starting up Data Connect generate: ${res.error.message}`, { | ||
original: res.error, | ||
}); | ||
} | ||
return res.stdout; | ||
} | ||
async build() { | ||
static async build(args) { | ||
const commandInfo = await (0, downloadableEmulators_1.downloadIfNecessary)(types_1.Emulators.DATACONNECT); | ||
const cmd = ["build", `--config_dir=${this.args.configDir}`]; | ||
const cmd = ["build", `--config_dir=${args.configDir}`]; | ||
const res = childProcess.spawnSync(commandInfo.binary, cmd, { encoding: "utf-8" }); | ||
if (res.error) { | ||
throw new error_1.FirebaseError(`Error starting up Data Connect build: ${res.error.message}`, { | ||
original: res.error, | ||
}); | ||
} | ||
if (res.status !== 0) { | ||
throw new error_1.FirebaseError(`Unable to build your Data Connect schema and connectors (exit code ${res.status}): ${res.stderr}`); | ||
} | ||
if (res.stderr) { | ||
throw new error_1.FirebaseError(`Unable to build your Data Connect schema and connectors: ${res.stderr}`); | ||
emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.DATACONNECT).log("DEBUG", res.stderr); | ||
} | ||
@@ -98,3 +110,33 @@ try { | ||
} | ||
async connectToPostgres(localConnectionString, database, serviceId) { | ||
const connectionString = localConnectionString ?? this.getLocalConectionString(); | ||
if (!connectionString) { | ||
this.logger.log("DEBUG", "No Postgres connection string found, not connecting to Postgres"); | ||
return false; | ||
} | ||
await this.emulatorClient.configureEmulator({ connectionString, database, serviceId }); | ||
return true; | ||
} | ||
} | ||
exports.DataConnectEmulator = DataConnectEmulator; | ||
class DataConnectEmulatorClient { | ||
constructor() { | ||
this.client = undefined; | ||
} | ||
async configureEmulator(body) { | ||
if (!this.client) { | ||
this.client = registry_1.EmulatorRegistry.client(types_1.Emulators.DATACONNECT); | ||
} | ||
try { | ||
const res = await this.client.post("emulator/configure", body); | ||
return res; | ||
} | ||
catch (err) { | ||
if (err.status === 500) { | ||
throw new error_1.FirebaseError(`Data Connect emulator: ${err.context.body.message}`); | ||
} | ||
throw err; | ||
} | ||
} | ||
} | ||
exports.DataConnectEmulatorClient = DataConnectEmulatorClient; |
@@ -16,2 +16,6 @@ "use strict"; | ||
const emulator = downloadableEmulators.getDownloadDetails(name); | ||
if (emulator.localOnly) { | ||
emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("WARN", name, `Env variable override detected, skipping download. Using ${emulator} emulator at ${emulator.binaryPath}`); | ||
return; | ||
} | ||
emulatorLogger_1.EmulatorLogger.forEmulator(name).logLabeled("BULLET", name, `downloading ${path.basename(emulator.downloadPath)}...`); | ||
@@ -18,0 +22,0 @@ fs.ensureDirSync(emulator.opts.cacheDir); |
@@ -26,5 +26,5 @@ "use strict"; | ||
firestore: { | ||
version: "1.19.6", | ||
expectedSize: 66349770, | ||
expectedChecksum: "2eaabbe3cdb4867df585b7ec5505bad7", | ||
version: "1.19.7", | ||
expectedSize: 66438992, | ||
expectedChecksum: "aec233bea95c5cfab03881574ec16d6c", | ||
}, | ||
@@ -39,22 +39,28 @@ storage: { | ||
: { | ||
version: "1.11.8", | ||
expectedSize: 3523907, | ||
expectedChecksum: "49f6dc1911dda9d10df62a6c09aaf9a0", | ||
version: "1.12.1", | ||
expectedSize: 3498269, | ||
expectedChecksum: "a7f4398a00e5ca22abdcd78dc3877d00", | ||
}, | ||
pubsub: { | ||
version: "0.8.2", | ||
expectedSize: 65611398, | ||
expectedChecksum: "70bb840321423e6ae621a3ae2f314903", | ||
version: "0.8.14", | ||
expectedSize: 66786933, | ||
expectedChecksum: "a9025b3e53fdeafd2969ccb3ba1e1d38", | ||
}, | ||
dataconnect: process.platform === "darwin" | ||
? { | ||
version: "1.1.17", | ||
expectedSize: 25602224, | ||
expectedChecksum: "1f9e3dd040a0ac4d1cb4d9dde4a3c0b0", | ||
version: "1.2.0", | ||
expectedSize: 23954240, | ||
expectedChecksum: "0f250761959519bb5a28fed76ceab2cb", | ||
} | ||
: { | ||
version: "1.1.17", | ||
expectedSize: 23036912, | ||
expectedChecksum: "a0ec0517108f842ed06fea14fe7c7e56", | ||
}, | ||
: process.platform === "win32" | ||
? { | ||
version: "1.2.0", | ||
expectedSize: 24360960, | ||
expectedChecksum: "168ce32c742e1d26037c52bdbb7d871c", | ||
} | ||
: { | ||
version: "1.2.0", | ||
expectedSize: 23970052, | ||
expectedChecksum: "2ca17e4009a9ebae0f7c983bafff2ee6", | ||
}, | ||
}; | ||
@@ -124,5 +130,5 @@ exports.DownloadDetails = { | ||
dataconnect: { | ||
downloadPath: path.join(CACHE_DIR, `dataconnect-emulator-${EMULATOR_UPDATE_DETAILS.dataconnect.version}`), | ||
downloadPath: path.join(CACHE_DIR, `dataconnect-emulator-${EMULATOR_UPDATE_DETAILS.dataconnect.version}${process.platform === "win32" ? ".exe" : ""}`), | ||
version: EMULATOR_UPDATE_DETAILS.dataconnect.version, | ||
binaryPath: path.join(CACHE_DIR, `dataconnect-emulator-${EMULATOR_UPDATE_DETAILS.dataconnect.version}`), | ||
binaryPath: path.join(CACHE_DIR, `dataconnect-emulator-${EMULATOR_UPDATE_DETAILS.dataconnect.version}${process.platform === "win32" ? ".exe" : ""}`), | ||
opts: { | ||
@@ -132,3 +138,5 @@ cacheDir: CACHE_DIR, | ||
? `https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-v${EMULATOR_UPDATE_DETAILS.dataconnect.version}` | ||
: `https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v${EMULATOR_UPDATE_DETAILS.dataconnect.version}`, | ||
: process.platform === "win32" | ||
? `https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-v${EMULATOR_UPDATE_DETAILS.dataconnect.version}` | ||
: `https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-v${EMULATOR_UPDATE_DETAILS.dataconnect.version}`, | ||
expectedSize: EMULATOR_UPDATE_DETAILS.dataconnect.expectedSize, | ||
@@ -239,5 +247,14 @@ expectedChecksum: EMULATOR_UPDATE_DETAILS.dataconnect.expectedChecksum, | ||
args: ["dev"], | ||
optionalArgs: ["http_port", "grpc_port", "config_dir", "local_connection_string", "project_id"], | ||
optionalArgs: [ | ||
"listen", | ||
"config_dir", | ||
"project_id", | ||
"service_location", | ||
"disable_sdk_generation", | ||
"resolvers_emulator", | ||
"vertex_location", | ||
"rpc_retry_count", | ||
], | ||
joinArgs: true, | ||
shell: true, | ||
shell: false, | ||
}, | ||
@@ -373,3 +390,13 @@ }; | ||
function getDownloadDetails(emulator) { | ||
return exports.DownloadDetails[emulator]; | ||
const details = exports.DownloadDetails[emulator]; | ||
const pathOverride = process.env[`${emulator.toUpperCase()}_EMULATOR_BINARY_PATH`]; | ||
if (pathOverride) { | ||
const logger = emulatorLogger_1.EmulatorLogger.forEmulator(emulator); | ||
logger.logLabeled("WARN", emulator, `Env variable override detected. Using ${emulator} emulator at ${pathOverride}`); | ||
details.downloadPath = pathOverride; | ||
details.binaryPath = pathOverride; | ||
details.localOnly = true; | ||
fs.chmodSync(pathOverride, 0o755); | ||
} | ||
return details; | ||
} | ||
@@ -418,3 +445,3 @@ exports.getDownloadDetails = getDownloadDetails; | ||
async function start(targetName, args, extraEnv = {}) { | ||
const downloadDetails = exports.DownloadDetails[targetName]; | ||
const downloadDetails = getDownloadDetails(targetName); | ||
const emulator = get(targetName); | ||
@@ -421,0 +448,0 @@ const hasEmulator = fs.existsSync(getExecPath(targetName)); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.resolveHostAndAssignPorts = exports.waitForPortUsed = exports.checkListenable = void 0; | ||
exports.listenSpecsToString = exports.resolveHostAndAssignPorts = exports.waitForPortUsed = exports.checkListenable = void 0; | ||
const clc = require("colorette"); | ||
@@ -149,3 +149,3 @@ const tcpport = require("tcp-port-used"); | ||
pubsub: true, | ||
dataconnect: true, | ||
dataconnect: false, | ||
hub: false, | ||
@@ -325,1 +325,10 @@ ui: false, | ||
} | ||
function listenSpecsToString(specs) { | ||
return specs | ||
.map((spec) => { | ||
const host = spec.family === "IPv4" ? spec.address : `[${spec.address}]`; | ||
return `${host}:${spec.port}`; | ||
}) | ||
.join(","); | ||
} | ||
exports.listenSpecsToString = listenSpecsToString; |
@@ -76,3 +76,3 @@ "use strict"; | ||
} | ||
const downloadDetails = downloadableEmulators_1.DownloadDetails[types_2.Emulators.STORAGE]; | ||
const downloadDetails = (0, downloadableEmulators_1.getDownloadDetails)(types_2.Emulators.STORAGE); | ||
const hasEmulator = fs.existsSync(downloadDetails.downloadPath); | ||
@@ -79,0 +79,0 @@ if (!hasEmulator) { |
@@ -312,2 +312,4 @@ "use strict"; | ||
continue; | ||
if (target === buildTarget && builder === "@angular-devkit/build-angular:browser") | ||
continue; | ||
if (target === browserTarget && builder === "@angular-devkit/build-angular:browser-esbuild") | ||
@@ -367,6 +369,9 @@ continue; | ||
} | ||
const { locales, defaultLocale } = await localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject); | ||
const targetOptions = await architectHost.getOptionsForTarget(buildOrBrowserTarget); | ||
const [{ locales, defaultLocale }, targetOptions, builderName] = await Promise.all([ | ||
localesForTarget(sourceDir, architectHost, buildOrBrowserTarget, workspaceProject), | ||
architectHost.getOptionsForTarget(buildOrBrowserTarget), | ||
architectHost.getBuilderNameForTarget(buildOrBrowserTarget), | ||
]); | ||
(0, utils_2.assertIsString)(targetOptions?.outputPath); | ||
const outputPath = (0, path_1.join)(targetOptions.outputPath, buildTarget ? "browser" : ""); | ||
const outputPath = (0, path_1.join)(targetOptions.outputPath, buildTarget && builderName === "@angular-devkit/build-angular:application" ? "browser" : ""); | ||
return { locales, baseHref, outputPath, defaultLocale }; | ||
@@ -373,0 +378,0 @@ } |
@@ -237,3 +237,2 @@ "use strict"; | ||
absolute: false, | ||
realpath: utils_2.IS_WINDOWS, | ||
}, (err, matches) => { | ||
@@ -240,0 +239,0 @@ if (err) |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.listUsers = exports.deleteUser = exports.getUser = exports.createUser = exports.createDatabase = exports.getDatabase = exports.listDatabases = exports.updateInstanceForDataConnect = exports.createInstance = exports.getInstance = exports.listInstances = void 0; | ||
exports.listUsers = exports.deleteUser = exports.getUser = exports.createUser = exports.createDatabase = exports.getDatabase = exports.listDatabases = exports.updateInstanceForDataConnect = exports.createInstance = exports.instanceConsoleLink = exports.getInstance = exports.listInstances = void 0; | ||
const apiv2_1 = require("../../apiv2"); | ||
const api_1 = require("../../api"); | ||
const operationPoller = require("../../operation-poller"); | ||
const error_1 = require("../../error"); | ||
const API_VERSION = "v1"; | ||
@@ -20,6 +21,13 @@ const client = new apiv2_1.Client({ | ||
const res = await client.get(`projects/${projectId}/instances/${instanceId}`); | ||
if (res.body.state === "FAILED") { | ||
throw new error_1.FirebaseError(`Cloud SQL instance ${instanceId} is in a failed state.\nGo to ${instanceConsoleLink(projectId, instanceId)} to repair or delete it.`); | ||
} | ||
return res.body; | ||
} | ||
exports.getInstance = getInstance; | ||
async function createInstance(projectId, location, instanceId, enableGoogleMlIntegration) { | ||
function instanceConsoleLink(projectId, instanceId) { | ||
return `https://console.cloud.google.com/sql/instances/${instanceId}/overview?project=${projectId}`; | ||
} | ||
exports.instanceConsoleLink = instanceConsoleLink; | ||
async function createInstance(projectId, location, instanceId, enableGoogleMlIntegration, waitForCreation) { | ||
const databaseFlags = [{ name: "cloudsql.iam_authentication", value: "on" }]; | ||
@@ -45,5 +53,10 @@ if (enableGoogleMlIntegration) { | ||
queryInsightsEnabled: true, | ||
queryPlansPerMinute: 5, | ||
queryStringLength: 1024, | ||
}, | ||
}, | ||
}); | ||
if (!waitForCreation) { | ||
return; | ||
} | ||
const opName = `projects/${projectId}/operations/${op.body.name}`; | ||
@@ -50,0 +63,0 @@ const pollRes = await operationPoller.pollOperation({ |
@@ -19,3 +19,3 @@ "use strict"; | ||
if (!connectionName) { | ||
throw new error_1.FirebaseError(`Could not get instance conection string for ${opts.instanceId}:${opts.databaseId}`); | ||
throw new error_1.FirebaseError(`Could not get instance connection string for ${opts.instanceId}:${opts.databaseId}`); | ||
} | ||
@@ -38,3 +38,2 @@ let connector; | ||
database: opts.databaseId, | ||
max: 1, | ||
}); | ||
@@ -54,3 +53,2 @@ break; | ||
database: opts.databaseId, | ||
max: 1, | ||
}); | ||
@@ -75,3 +73,2 @@ break; | ||
database: opts.databaseId, | ||
max: 1, | ||
}); | ||
@@ -81,6 +78,8 @@ break; | ||
} | ||
const conn = await pool.connect(); | ||
logFn(`Logged in as ${opts.username}`); | ||
for (const s of sqlStatements) { | ||
logFn(`Executing: '${s}' as ${opts.username}`); | ||
logFn(`Executing: '${s}'`); | ||
try { | ||
await pool.query(s); | ||
await conn.query(s); | ||
} | ||
@@ -91,2 +90,3 @@ catch (err) { | ||
} | ||
conn.release(); | ||
await pool.end(); | ||
@@ -93,0 +93,0 @@ connector.close(); |
@@ -13,2 +13,4 @@ "use strict"; | ||
const emulators_1 = require("../emulators"); | ||
const names_1 = require("../../../dataconnect/names"); | ||
const logger_1 = require("../../../logger"); | ||
const TEMPLATE_ROOT = (0, path_1.resolve)(__dirname, "../../../../templates/init/dataconnect/"); | ||
@@ -21,94 +23,18 @@ const DATACONNECT_YAML_TEMPLATE = (0, fs_1.readFileSync)((0, path_1.join)(TEMPLATE_ROOT, "dataconnect.yaml"), "utf8"); | ||
async function doSetup(setup, config) { | ||
if (setup.projectId) { | ||
await (0, ensureApis_1.ensureApis)(setup.projectId); | ||
let info = { | ||
serviceId: "", | ||
locationId: "", | ||
cloudSqlInstanceId: "", | ||
isNewInstance: false, | ||
cloudSqlDatabase: "", | ||
isNewDatabase: false, | ||
connectorId: "default-connector", | ||
}; | ||
info = await promptForService(setup, info); | ||
if (info.cloudSqlInstanceId === "") { | ||
info = await promptForCloudSQLInstance(setup, info); | ||
} | ||
const serviceId = await (0, prompt_1.promptOnce)({ | ||
message: "What ID would you like to use for this service?", | ||
type: "input", | ||
default: "dataconnect", | ||
}); | ||
const connectorId = await (0, prompt_1.promptOnce)({ | ||
message: "What ID would you like to use for your connector?", | ||
type: "input", | ||
default: "my-connector", | ||
}); | ||
let cloudSqlInstanceId = ""; | ||
let newInstance = false; | ||
let locationId = ""; | ||
if (setup.projectId) { | ||
const instances = await cloudsql.listInstances(setup.projectId); | ||
const choices = instances.map((i) => { | ||
return { name: i.name, value: i.name, location: i.region }; | ||
}); | ||
const freeTrialInstanceId = await (0, freeTrial_1.checkForFreeTrialInstance)(setup.projectId); | ||
if (!freeTrialInstanceId) { | ||
choices.push({ name: "Create a new instance", value: "", location: "" }); | ||
} | ||
if (instances.length) { | ||
cloudSqlInstanceId = await (0, prompt_1.promptOnce)({ | ||
message: `Which CloudSSQL instance would you like to use?`, | ||
type: "list", | ||
choices, | ||
}); | ||
} | ||
locationId = choices.find((c) => c.value === cloudSqlInstanceId).location; | ||
if (info.cloudSqlDatabase === "") { | ||
info = await promptForDatabase(setup, config, info); | ||
} | ||
if (cloudSqlInstanceId === "") { | ||
let locationOptions = [ | ||
{ name: "us-central1", value: "us-central1" }, | ||
{ name: "europe-north1", value: "europe-north1" }, | ||
{ name: "europe-central2", value: "europe-central2" }, | ||
{ name: "europe-west1", value: "europe-west1" }, | ||
{ name: "southamerica-west1", value: "southamerica-west1" }, | ||
{ name: "us-east4", value: "us-east4" }, | ||
{ name: "us-west1", value: "us-west1" }, | ||
{ name: "asia-southeast1", value: "asia-southeast1" }, | ||
]; | ||
if (setup.projectId) { | ||
const locations = await (0, client_1.listLocations)(setup.projectId); | ||
locationOptions = locations.map((l) => { | ||
return { name: l, value: l }; | ||
}); | ||
} | ||
newInstance = true; | ||
cloudSqlInstanceId = await (0, prompt_1.promptOnce)({ | ||
message: `What ID would you like to use for your new CloudSQL instance?`, | ||
type: "input", | ||
default: `dataconnect-test`, | ||
}); | ||
locationId = await (0, prompt_1.promptOnce)({ | ||
message: "What location would you use for this instance?", | ||
type: "list", | ||
choices: locationOptions, | ||
}); | ||
} | ||
const dir = config.get("dataconnect.source") || "dataconnect"; | ||
if (!config.has("dataconnect")) { | ||
config.set("dataconnect.source", dir); | ||
config.set("dataconnect.location", locationId); | ||
} | ||
let cloudSqlDatabase = ""; | ||
let newDB = false; | ||
if (!newInstance && setup.projectId) { | ||
const dbs = await cloudsql.listDatabases(setup.projectId, cloudSqlInstanceId); | ||
const choices = dbs.map((d) => { | ||
return { name: d.name, value: d.name }; | ||
}); | ||
choices.push({ name: "Create a new database", value: "" }); | ||
if (dbs.length) { | ||
cloudSqlDatabase = await (0, prompt_1.promptOnce)({ | ||
message: `Which database in ${cloudSqlInstanceId} would you like to use?`, | ||
type: "list", | ||
choices, | ||
}); | ||
} | ||
} | ||
if (cloudSqlDatabase === "") { | ||
newDB = true; | ||
cloudSqlDatabase = await (0, prompt_1.promptOnce)({ | ||
message: `What ID would you like to use for your new database in ${cloudSqlInstanceId}?`, | ||
type: "input", | ||
default: `dataconnect`, | ||
}); | ||
} | ||
const defaultConnectionString = setup.rcfile.dataconnectEmulatorConfig?.postgres?.localConnectionString ?? | ||
@@ -123,21 +49,16 @@ emulators_1.DEFAULT_POSTGRES_CONNECTION; | ||
setup.rcfile.dataconnectEmulatorConfig = { postgres: { localConnectionString } }; | ||
const subbedDataconnectYaml = subValues(DATACONNECT_YAML_TEMPLATE, { | ||
serviceId, | ||
cloudSqlInstanceId, | ||
cloudSqlDatabase, | ||
connectorId, | ||
}); | ||
const subbedConnectorYaml = subValues(CONNECTOR_YAML_TEMPLATE, { | ||
serviceId, | ||
cloudSqlInstanceId, | ||
cloudSqlDatabase, | ||
connectorId, | ||
}); | ||
const dir = config.get("dataconnect.source") || "dataconnect"; | ||
const subbedDataconnectYaml = subValues(DATACONNECT_YAML_TEMPLATE, info); | ||
const subbedConnectorYaml = subValues(CONNECTOR_YAML_TEMPLATE, info); | ||
if (!config.has("dataconnect")) { | ||
config.set("dataconnect.source", dir); | ||
config.set("dataconnect.location", info.locationId); | ||
} | ||
await config.askWriteProjectFile((0, path_1.join)(dir, "dataconnect.yaml"), subbedDataconnectYaml); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "connector.yaml"), subbedConnectorYaml); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, "schema", "schema.gql"), SCHEMA_TEMPLATE); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "queries.gql"), QUERIES_TEMPLATE); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, "connector", "mutations.gql"), MUTATIONS_TEMPLATE); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "connector.yaml"), subbedConnectorYaml); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "queries.gql"), QUERIES_TEMPLATE); | ||
await config.askWriteProjectFile((0, path_1.join)(dir, info.connectorId, "mutations.gql"), MUTATIONS_TEMPLATE); | ||
if (setup.projectId && | ||
(newInstance || newDB) && | ||
(info.isNewInstance || info.isNewDatabase) && | ||
(await (0, prompt_1.confirm)({ | ||
@@ -149,6 +70,7 @@ message: "Would you like to provision your CloudSQL instance and database now? This will take a few minutes.", | ||
projectId: setup.projectId, | ||
locationId, | ||
instanceId: cloudSqlInstanceId, | ||
databaseId: cloudSqlDatabase, | ||
locationId: info.locationId, | ||
instanceId: info.cloudSqlInstanceId, | ||
databaseId: info.cloudSqlDatabase, | ||
enableGoogleMlIntegration: false, | ||
waitForCreation: false, | ||
}); | ||
@@ -171,1 +93,141 @@ } | ||
} | ||
async function promptForService(setup, info) { | ||
if (setup.projectId) { | ||
await (0, ensureApis_1.ensureApis)(setup.projectId); | ||
const existingServices = await (0, client_1.listAllServices)(setup.projectId); | ||
const existingServicesAndSchemas = await Promise.all(existingServices.map(async (s) => { | ||
return { | ||
service: s, | ||
schema: await (0, client_1.getSchema)(s.name), | ||
}; | ||
})); | ||
const existingFreshServicesAndSchemas = existingServicesAndSchemas.filter((s) => { | ||
return !s.schema?.source.files?.length; | ||
}); | ||
if (existingFreshServicesAndSchemas.length) { | ||
const choices = existingFreshServicesAndSchemas.map((s) => { | ||
const serviceName = (0, names_1.parseServiceName)(s.service.name); | ||
return { | ||
name: `${serviceName.location}/${serviceName.serviceId}`, | ||
value: s, | ||
}; | ||
}); | ||
choices.push({ name: "Create a new service", value: undefined }); | ||
const choice = await (0, prompt_1.promptOnce)({ | ||
message: "Your project already has existing services. Which would you like to set up local files for?", | ||
type: "list", | ||
choices, | ||
}); | ||
if (choice) { | ||
const serviceName = (0, names_1.parseServiceName)(choice.service.name); | ||
info.serviceId = serviceName.serviceId; | ||
info.locationId = serviceName.location; | ||
if (choice.schema) { | ||
if (choice.schema.primaryDatasource.postgresql?.cloudSql.instance) { | ||
const instanceName = (0, names_1.parseCloudSQLInstanceName)(choice.schema.primaryDatasource.postgresql?.cloudSql.instance); | ||
info.cloudSqlInstanceId = instanceName.instanceId; | ||
} | ||
info.cloudSqlDatabase = choice.schema.primaryDatasource.postgresql?.database ?? ""; | ||
} | ||
} | ||
} | ||
} | ||
if (info.serviceId === "") { | ||
info.serviceId = await (0, prompt_1.promptOnce)({ | ||
message: "What ID would you like to use for this service?", | ||
type: "input", | ||
default: "my-service", | ||
}); | ||
} | ||
return info; | ||
} | ||
async function promptForCloudSQLInstance(setup, info) { | ||
if (setup.projectId) { | ||
const instances = await cloudsql.listInstances(setup.projectId); | ||
let choices = instances.map((i) => { | ||
return { name: i.name, value: i.name, location: i.region }; | ||
}); | ||
choices = choices.filter((c) => info.locationId === "" || info.locationId === c.location); | ||
if (choices.length) { | ||
const freeTrialInstanceId = await (0, freeTrial_1.checkForFreeTrialInstance)(setup.projectId); | ||
if (!freeTrialInstanceId) { | ||
choices.push({ name: "Create a new instance", value: "", location: "" }); | ||
} | ||
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({ | ||
message: `Which CloudSQL instance would you like to use?`, | ||
type: "list", | ||
choices, | ||
}); | ||
if (info.cloudSqlInstanceId !== "") { | ||
info.locationId = choices.find((c) => c.value === info.cloudSqlInstanceId).location; | ||
} | ||
} | ||
} | ||
if (info.cloudSqlInstanceId === "") { | ||
info.isNewInstance = true; | ||
info.cloudSqlInstanceId = await (0, prompt_1.promptOnce)({ | ||
message: `What ID would you like to use for your new CloudSQL instance?`, | ||
type: "input", | ||
default: `fdc-sql`, | ||
}); | ||
} | ||
if (info.locationId === "") { | ||
const choices = await locationChoices(setup); | ||
info.locationId = await (0, prompt_1.promptOnce)({ | ||
message: "What location would like to use?", | ||
type: "list", | ||
choices, | ||
}); | ||
} | ||
return info; | ||
} | ||
async function locationChoices(setup) { | ||
if (setup.projectId) { | ||
const locations = await (0, client_1.listLocations)(setup.projectId); | ||
return locations.map((l) => { | ||
return { name: l, value: l }; | ||
}); | ||
} | ||
else { | ||
return [ | ||
{ name: "us-central1", value: "us-central1" }, | ||
{ name: "europe-north1", value: "europe-north1" }, | ||
{ name: "europe-central2", value: "europe-central2" }, | ||
{ name: "europe-west1", value: "europe-west1" }, | ||
{ name: "southamerica-west1", value: "southamerica-west1" }, | ||
{ name: "us-east4", value: "us-east4" }, | ||
{ name: "us-west1", value: "us-west1" }, | ||
{ name: "asia-southeast1", value: "asia-southeast1" }, | ||
]; | ||
} | ||
} | ||
async function promptForDatabase(setup, config, info) { | ||
if (!info.isNewInstance && setup.projectId) { | ||
try { | ||
const dbs = await cloudsql.listDatabases(setup.projectId, info.cloudSqlInstanceId); | ||
const choices = dbs.map((d) => { | ||
return { name: d.name, value: d.name }; | ||
}); | ||
choices.push({ name: "Create a new database", value: "" }); | ||
if (dbs.length) { | ||
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({ | ||
message: `Which database in ${info.cloudSqlInstanceId} would you like to use?`, | ||
type: "list", | ||
choices, | ||
}); | ||
} | ||
} | ||
catch (err) { | ||
logger_1.logger.debug(`[dataconnect] Cannot list databases during init: ${err}`); | ||
} | ||
} | ||
if (info.cloudSqlDatabase === "") { | ||
info.isNewDatabase = true; | ||
info.cloudSqlDatabase = await (0, prompt_1.promptOnce)({ | ||
message: `What ID would you like to use for your new database in ${info.cloudSqlInstanceId}?`, | ||
type: "input", | ||
default: `fdcdb`, | ||
}); | ||
} | ||
return info; | ||
} |
@@ -157,5 +157,3 @@ "use strict"; | ||
setDataconnect(localConnectionString) { | ||
if (!this.data.dataconnectEmulatorConfig) { | ||
this.data.dataconnectEmulatorConfig = { postgres: { localConnectionString } }; | ||
} | ||
this.data.dataconnectEmulatorConfig = { postgres: { localConnectionString } }; | ||
} | ||
@@ -162,0 +160,0 @@ save() { |
@@ -23,2 +23,5 @@ "use strict"; | ||
async function autoAuth(options, authScopes) { | ||
if (process.env.MONOSPACE_ENV) { | ||
throw new error_1.FirebaseError("autoAuth not yet implemented for IDX. Please run 'firebase login'"); | ||
} | ||
const client = getAuthClient({ scopes: authScopes, projectId: options.project }); | ||
@@ -25,0 +28,0 @@ const token = await client.getAccessToken(); |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.track = exports.cliSession = exports.emulatorSession = exports.trackEmulator = exports.trackGA4 = exports.usageEnabled = exports.GA4_PROPERTIES = void 0; | ||
exports.track = exports.cliSession = exports.vscodeSession = exports.emulatorSession = exports.trackVSCode = exports.trackEmulator = exports.trackGA4 = exports.usageEnabled = exports.GA4_PROPERTIES = void 0; | ||
const node_fetch_1 = require("node-fetch"); | ||
@@ -22,2 +22,7 @@ const ua = require("universal-analytics"); | ||
}, | ||
vscode: { | ||
measurementId: process.env.FIREBASE_VSCODE_GA4_MEASUREMENT_ID || "G-FYJ489XM2T", | ||
apiSecret: process.env.FIREBASE_VSCODE_GA4_API_SECRET || "XAEWKHe7RM-ygCK44N52Ww", | ||
clientIdKey: "vscode-analytics-clientId", | ||
}, | ||
}; | ||
@@ -73,2 +78,20 @@ function usageEnabled() { | ||
exports.trackEmulator = trackEmulator; | ||
async function trackVSCode(eventName, params) { | ||
const session = vscodeSession(); | ||
if (!session) { | ||
return; | ||
} | ||
session.debugMode = process.env.VSCODE_DEBUG_MODE === "true"; | ||
const oldTotalEngagementSeconds = session.totalEngagementSeconds; | ||
session.totalEngagementSeconds = process.uptime(); | ||
const duration = session.totalEngagementSeconds - oldTotalEngagementSeconds; | ||
return _ga4Track({ | ||
session, | ||
apiSecret: exports.GA4_PROPERTIES.vscode.apiSecret, | ||
eventName, | ||
params, | ||
duration, | ||
}); | ||
} | ||
exports.trackVSCode = trackVSCode; | ||
async function _ga4Track(args) { | ||
@@ -133,2 +156,6 @@ const { session, apiSecret, eventName, params, duration } = args; | ||
exports.emulatorSession = emulatorSession; | ||
function vscodeSession() { | ||
return session("vscode"); | ||
} | ||
exports.vscodeSession = vscodeSession; | ||
function cliSession() { | ||
@@ -140,3 +167,3 @@ return session("cli"); | ||
const validateOnly = !!process.env.FIREBASE_CLI_MP_VALIDATE; | ||
if (!usageEnabled()) { | ||
if (!usageEnabled() && propertyName !== "vscode") { | ||
if (validateOnly) { | ||
@@ -143,0 +170,0 @@ logger_1.logger.warn("Google Analytics is DISABLED. To enable, (re)login and opt in to collection."); |
{ | ||
"name": "firebase-tools-with-isolate", | ||
"version": "13.9.0", | ||
"description": "Command-Line Interface for Firebase with monorepo support", | ||
"version": "13.11.2", | ||
"main": "./lib/index.js", | ||
@@ -98,3 +98,3 @@ "bin": { | ||
"@google-cloud/cloud-sql-connector": "^1.2.3", | ||
"@google-cloud/pubsub": "^3.0.1", | ||
"@google-cloud/pubsub": "^4.4.0", | ||
"abort-controller": "^3.0.0", | ||
@@ -128,3 +128,3 @@ "ajv": "^6.12.6", | ||
"inquirer-autocomplete-prompt": "^2.0.1", | ||
"isolate-package": "^1.16.0", | ||
"isolate-package": "^1.18.0", | ||
"jsonwebtoken": "^9.0.0", | ||
@@ -131,0 +131,0 @@ "leven": "^3.1.0", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 6 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3466940
80105
260
+ Added@google-cloud/paginator@5.0.2(transitive)
+ Added@google-cloud/precise-date@4.0.0(transitive)
+ Added@google-cloud/projectify@4.0.0(transitive)
+ Added@google-cloud/promisify@4.0.0(transitive)
+ Added@google-cloud/pubsub@4.9.0(transitive)
+ Added@grpc/grpc-js@1.12.5(transitive)
+ Added@js-sdsl/ordered-map@4.4.2(transitive)
+ Added@opentelemetry/semantic-conventions@1.26.0(transitive)
+ Added@types/caseless@0.12.5(transitive)
+ Added@types/request@2.48.12(transitive)
+ Added@types/tough-cookie@4.0.5(transitive)
+ Addedform-data@2.5.2(transitive)
+ Addedgoogle-gax@4.4.1(transitive)
+ Addedproto3-json-serializer@2.0.2(transitive)
+ Addedretry-request@7.0.2(transitive)
+ Addedstream-events@1.0.5(transitive)
+ Addedstubs@3.0.0(transitive)
+ Addedteeny-request@9.0.0(transitive)
- Removed@babel/helper-string-parser@7.25.9(transitive)
- Removed@babel/helper-validator-identifier@7.25.9(transitive)
- Removed@babel/parser@7.26.3(transitive)
- Removed@babel/types@7.26.3(transitive)
- Removed@google-cloud/paginator@4.0.1(transitive)
- Removed@google-cloud/precise-date@3.0.1(transitive)
- Removed@google-cloud/projectify@3.0.0(transitive)
- Removed@google-cloud/promisify@2.0.4(transitive)
- Removed@google-cloud/pubsub@3.7.5(transitive)
- Removed@grpc/grpc-js@1.8.22(transitive)
- Removed@jsdoc/salty@0.2.9(transitive)
- Removed@opentelemetry/semantic-conventions@1.3.1(transitive)
- Removed@types/duplexify@3.6.4(transitive)
- Removed@types/glob@8.1.0(transitive)
- Removed@types/linkify-it@5.0.0(transitive)
- Removed@types/markdown-it@14.1.2(transitive)
- Removed@types/mdurl@2.0.0(transitive)
- Removed@types/minimatch@5.1.2(transitive)
- Removed@types/rimraf@3.0.2(transitive)
- Removedacorn@8.14.0(transitive)
- Removedacorn-jsx@5.3.2(transitive)
- Removedbluebird@3.7.2(transitive)
- Removedcatharsis@0.9.0(transitive)
- Removedentities@4.5.0(transitive)
- Removedescape-string-regexp@2.0.0(transitive)
- Removedescodegen@1.14.3(transitive)
- Removedeslint-visitor-keys@3.4.3(transitive)
- Removedespree@9.6.1(transitive)
- Removedestraverse@4.3.0(transitive)
- Removedfast-levenshtein@2.0.6(transitive)
- Removedfast-text-encoding@1.0.6(transitive)
- Removedgaxios@5.1.3(transitive)
- Removedgcp-metadata@5.3.0(transitive)
- Removedglob@8.1.0(transitive)
- Removedgoogle-auth-library@8.9.0(transitive)
- Removedgoogle-gax@3.6.1(transitive)
- Removedgoogle-p12-pem@4.0.1(transitive)
- Removedgtoken@6.1.2(transitive)
- Removedjs2xmlparser@4.0.2(transitive)
- Removedjsdoc@4.0.4(transitive)
- Removedklaw@3.0.0(transitive)
- Removedlevn@0.3.0(transitive)
- Removedlinkify-it@5.0.0(transitive)
- Removedmarkdown-it@14.1.0(transitive)
- Removedmarkdown-it-anchor@8.6.7(transitive)
- Removedmdurl@2.0.0(transitive)
- Removednode-forge@1.3.1(transitive)
- Removedoptionator@0.8.3(transitive)
- Removedprelude-ls@1.1.2(transitive)
- Removedproto3-json-serializer@1.1.1(transitive)
- Removedprotobufjs@7.2.4(transitive)
- Removedprotobufjs-cli@1.1.1(transitive)
- Removedpunycode.js@2.3.1(transitive)
- Removedrequizzle@0.2.4(transitive)
- Removedretry-request@5.0.2(transitive)
- Removedstrip-json-comments@3.1.1(transitive)
- Removedtype-check@0.3.2(transitive)
- Removeduc.micro@2.1.0(transitive)
- Removeduglify-js@3.19.3(transitive)
- Removedunderscore@1.13.7(transitive)
- Removedword-wrap@1.2.5(transitive)
- Removedxmlcreate@2.0.4(transitive)
Updated@google-cloud/pubsub@^4.4.0
Updatedisolate-package@^1.18.0