From 267ceeb82f65ba30ca93241909f92ff71e45c8b5 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Mon, 22 Apr 2024 17:12:03 -0400 Subject: [PATCH 01/12] Parse Firebase extensions out of code --- package.json | 3 +- src/runtime/loader.ts | 100 ++++++++++++++++++++++++++++++++++++++-- src/runtime/manifest.ts | 20 ++++++-- 3 files changed, 115 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 258be26ff..940ca9f87 100644 --- a/package.json +++ b/package.json @@ -247,7 +247,8 @@ "yargs": "^15.3.1" }, "peerDependencies": { - "firebase-admin": "^11.10.0 || ^12.0.0" + "firebase-admin": "^11.10.0 || ^12.0.0", + "firebase-tools": "^13.15.1" }, "engines": { "node": ">=14.10.0" diff --git a/src/runtime/loader.ts b/src/runtime/loader.ts index d1f9f2f32..ddbd23302 100644 --- a/src/runtime/loader.ts +++ b/src/runtime/loader.ts @@ -22,7 +22,12 @@ import * as path from "path"; import * as url from "url"; -import { ManifestEndpoint, ManifestRequiredAPI, ManifestStack } from "./manifest"; +import { + ManifestEndpoint, + ManifestExtension, + ManifestRequiredAPI, + ManifestStack, +} from "./manifest"; import * as params from "../params"; @@ -59,6 +64,7 @@ export function extractStack( module, endpoints: Record, requiredAPIs: ManifestRequiredAPI[], + extensions: Record, prefix = "" ) { for (const [name, valAsUnknown] of Object.entries(module)) { @@ -73,12 +79,96 @@ export function extractStack( if (val.__requiredAPIs && Array.isArray(val.__requiredAPIs)) { requiredAPIs.push(...val.__requiredAPIs); } - } else if (typeof val === "object" && val !== null) { - extractStack(val, endpoints, requiredAPIs, prefix + name + "-"); + } else if (isFirebaseRefExtension(val)) { + extensions[val.instanceId] = { + params: convertExtensionParams(val.params), + ref: val.FIREBASE_EXTENSION_REFERENCE, + events: val.events, + }; + } else if (isFirebaseLocalExtension(val)) { + extensions[val.instanceId] = { + params: convertExtensionParams(val.params), + localPath: val.FIREBASE_EXTENSION_LOCAL_PATH, + events: val.events, + }; + } else if (isObject(val)) { + extractStack(val, endpoints, requiredAPIs, extensions, prefix + name + "-"); + } + } +} + +function toTitleCase(txt: string): string { + return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase(); +} + +function snakeToCamelCase(txt: string): string { + let ret = txt.toLowerCase(); + ret = ret.replace(/_/g, " "); + ret = ret.replace(/\w\S*/g, toTitleCase); + ret = ret.charAt(0).toLowerCase() + ret.substring(1); + return ret; +} + +function convertExtensionParams(params: object): Record { + const systemPrefixes: Record = { + FUNCTION: "firebaseextensions.v1beta.function", + V2FUNCTION: "firebaseextensions.v1beta.v2function", + }; + const converted: Record = {}; + for (const [rawKey, paramVal] of Object.entries(params)) { + let key = rawKey; + if (rawKey.startsWith("_") && rawKey !== "_EVENT_ARC_REGION") { + const prefix = rawKey.substring(1).split("_")[0]; + const suffix = rawKey.substring(2 + prefix.length); // 2 for underscores + key = `${systemPrefixes[prefix]}/${snakeToCamelCase(suffix)}`; + } + if (Array.isArray(paramVal)) { + converted[key] = paramVal.join(","); + } else { + converted[key] = paramVal as string; } } + return converted; +} + +function isObject(value: unknown): value is Record { + return typeof value === "object" && value !== null; +} + +interface FirebaseLocalExtension { + FIREBASE_EXTENSION_LOCAL_PATH: string; + instanceId: string; + params: Record; + events: string[]; } +const isFirebaseLocalExtension = (val: unknown): val is FirebaseLocalExtension => { + return ( + isObject(val) && + typeof val.FIREBASE_EXTENSION_LOCAL_PATH === "string" && + typeof val.instanceId === "string" && + isObject(val.params) && + Array.isArray(val.events) + ); +}; + +interface FirebaseRefExtension { + FIREBASE_EXTENSION_REFERENCE: string; + instanceId: string; + params: Record; + events: string[]; +} + +const isFirebaseRefExtension = (val: unknown): val is FirebaseRefExtension => { + return ( + isObject(val) && + typeof val.FIREBASE_EXTENSION_REFERENCE === "string" && + typeof val.instanceId === "string" && + isObject(val.params) && + Array.isArray(val.events) + ); +}; + /* @internal */ export function mergeRequiredAPIs(requiredAPIs: ManifestRequiredAPI[]): ManifestRequiredAPI[] { const apiToReasons: Record> = {}; @@ -99,14 +189,16 @@ export function mergeRequiredAPIs(requiredAPIs: ManifestRequiredAPI[]): Manifest export async function loadStack(functionsDir: string): Promise { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; const mod = await loadModule(functionsDir); - extractStack(mod, endpoints, requiredAPIs); + extractStack(mod, endpoints, requiredAPIs, extensions); const stack: ManifestStack = { endpoints, specVersion: "v1alpha1", requiredAPIs: mergeRequiredAPIs(requiredAPIs), + extensions, }; if (params.declaredParams.length > 0) { stack.params = params.declaredParams.map((p) => p.toSpec()); diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 6ff5fe0f9..87369c1af 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -22,10 +22,22 @@ import { RESET_VALUE, ResettableKeys, ResetValue } from "../common/options"; import { Expression } from "../params"; -import { WireParamSpec } from "../params/types"; +import { WireParamSpec, SecretParam } from "../params/types"; /** - * An definition of a function as appears in the Manifest. + * A definition of an extension as appears in the Manifest. + * + * @alpha + */ +export interface ManifestExtension { + params: Record; + ref?: string; + localPath?: string; + events: string[]; +} + +/** + * A definition of a function as appears in the Manifest. * * @alpha */ @@ -113,7 +125,8 @@ export interface ManifestRequiredAPI { } /** - * An definition of a function deployment as appears in the Manifest. + * A definition of a function/extension deployment as appears in the Manifest. + * * @alpha */ export interface ManifestStack { @@ -121,6 +134,7 @@ export interface ManifestStack { params?: WireParamSpec[]; requiredAPIs: ManifestRequiredAPI[]; endpoints: Record; + extensions: Record; } /** From d48abf063ebd9b0b49b3fe38302cb32d5bbcc991 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Fri, 9 Aug 2024 15:18:10 -0400 Subject: [PATCH 02/12] removing peer dep --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 940ca9f87..258be26ff 100644 --- a/package.json +++ b/package.json @@ -247,8 +247,7 @@ "yargs": "^15.3.1" }, "peerDependencies": { - "firebase-admin": "^11.10.0 || ^12.0.0", - "firebase-tools": "^13.15.1" + "firebase-admin": "^11.10.0 || ^12.0.0" }, "engines": { "node": ">=14.10.0" From e6bbcd32997829b71964354517856547e2904c27 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Tue, 13 Aug 2024 20:08:08 -0400 Subject: [PATCH 03/12] fixed tests --- spec/fixtures/extsdk/local/index.d.ts | 37 ++++++ spec/fixtures/extsdk/local/index.js | 30 +++++ spec/fixtures/extsdk/local/package.json | 4 + spec/fixtures/extsdk/translate/index.d.ts | 123 ++++++++++++++++++ spec/fixtures/extsdk/translate/index.js | 61 +++++++++ spec/fixtures/extsdk/translate/package.json | 4 + .../sources/commonjs-grouped/index.js | 27 ++++ .../sources/commonjs-main/functions.js | 26 ++++ .../commonjs-parametrized-fields/index.js | 26 ++++ .../fixtures/sources/commonjs-params/index.js | 26 ++++ spec/fixtures/sources/commonjs/index.js | 26 ++++ spec/runtime/loader.spec.ts | 77 ++++++++++- spec/runtime/manifest.spec.ts | 44 +++++++ src/runtime/loader.ts | 12 +- src/runtime/manifest.ts | 3 +- 15 files changed, 511 insertions(+), 15 deletions(-) create mode 100644 spec/fixtures/extsdk/local/index.d.ts create mode 100644 spec/fixtures/extsdk/local/index.js create mode 100644 spec/fixtures/extsdk/local/package.json create mode 100644 spec/fixtures/extsdk/translate/index.d.ts create mode 100644 spec/fixtures/extsdk/translate/index.js create mode 100644 spec/fixtures/extsdk/translate/package.json diff --git a/spec/fixtures/extsdk/local/index.d.ts b/spec/fixtures/extsdk/local/index.d.ts new file mode 100644 index 000000000..ed3a39c74 --- /dev/null +++ b/spec/fixtures/extsdk/local/index.d.ts @@ -0,0 +1,37 @@ +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester SDK for backfill@0.0.2 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for Local extension. + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +export type DoBackfillParam = "True" | "False"; +export type LocationParam = "us-central1" | "us-east1" | "us-east4" | "europe-west1" | "europe-west2" | "europe-west3" | "asia-east2" | "asia-northeast1"; +/** + * Parameters for backfill@0.0.2 extension + */ +export interface BackfillParams { + /** + * Do a backfill + */ + DO_BACKFILL: DoBackfillParam; + /** + * Cloud Functions location + */ + LOCATION: LocationParam; +} +export declare function backfill(instanceId: string, params: BackfillParams): Backfill; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester + * A tester for the TaskQueue/LCE/RuntimeStatus project + */ +export declare class Backfill { + private instanceId; + private params; + readonly FIREBASE_EXTENSION_LOCAL_PATH = "./functions/generated/extensions/local/backfill/0.0.2/src"; + constructor(instanceId: string, params: BackfillParams); + getInstanceId(): string; + getParams(): BackfillParams; +} \ No newline at end of file diff --git a/spec/fixtures/extsdk/local/index.js b/spec/fixtures/extsdk/local/index.js new file mode 100644 index 000000000..f1f9cce55 --- /dev/null +++ b/spec/fixtures/extsdk/local/index.js @@ -0,0 +1,30 @@ +"use strict"; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester SDK for extensions-try-backfill3@0.0.2 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for Local extension. + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.backfill = exports.backfill = void 0; +function backfill(instanceId, params) { + return new Backfill(instanceId, params); +} +exports.backfill = backfill; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester + * A tester for the TaskQueue/LCE/RuntimeStatus project + */ +class Backfill { + constructor(instanceId, params) { + this.instanceId = instanceId; + this.params = params; + this.FIREBASE_EXTENSION_LOCAL_PATH = "./functions/generated/extensions/local/backfill/0.0.2/src"; + } + getInstanceId() { return this.instanceId; } + getParams() { return this.params; } +} +exports.Backfill = Backfill; diff --git a/spec/fixtures/extsdk/local/package.json b/spec/fixtures/extsdk/local/package.json new file mode 100644 index 000000000..700806b3e --- /dev/null +++ b/spec/fixtures/extsdk/local/package.json @@ -0,0 +1,4 @@ +{ + "name": "@firebase-extensions/local-backfill-sdk", + "main": "./index.js" + } \ No newline at end of file diff --git a/spec/fixtures/extsdk/translate/index.d.ts b/spec/fixtures/extsdk/translate/index.d.ts new file mode 100644 index 000000000..96b86dcc3 --- /dev/null +++ b/spec/fixtures/extsdk/translate/index.d.ts @@ -0,0 +1,123 @@ +/** + * Translate Text in Firestore SDK for firestore-translate-text@0.1.18 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for firestore-translate-text@0.1.18" + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +import { CloudEvent } from "../../../../v2"; +import { EventarcTriggerOptions } from "../../../../v2/eventarc"; +export type EventCallback = (event: CloudEvent) => unknown | Promise; +export type SimpleEventarcTriggerOptions = Omit; +export type EventArcRegionType = "us-central1" | "us-west1" | "europe-west4" | "asia-northeast1"; +export type SystemFunctionVpcConnectorEgressSettingsParam = "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED" | "PRIVATE_RANGES_ONLY" | "ALL_TRAFFIC"; +export type SystemFunctionIngressSettingsParam = "ALLOW_ALL" | "ALLOW_INTERNAL_ONLY" | "ALLOW_INTERNAL_AND_GCLB"; +export type SystemFunctionLocationParam = "us-central1" | "us-east1" | "us-east4" | "us-west1" | "us-west2" | "us-west3" | "us-west4" | "europe-central2" | "europe-west1" | "europe-west2" | "europe-west3" | "europe-west6" | "asia-east1" | "asia-east2" | "asia-northeast1" | "asia-northeast2" | "asia-northeast3" | "asia-south1" | "asia-southeast1" | "asia-southeast2" | "northamerica-northeast1" | "southamerica-east1" | "australia-southeast1"; +export type SystemFunctionMemoryParam = "128" | "256" | "512" | "1024" | "2048" | "4096" | "8192"; +/** + * Parameters for firestore-translate-text@0.1.18 extension + */ +export interface FirestoreTranslateTextParams { + /** + * Target languages for translations, as a comma-separated list + */ + LANGUAGES: string; + /** + * Collection path + */ + COLLECTION_PATH: string; + /** + * Input field name + */ + INPUT_FIELD_NAME: string; + /** + * Translations output field name + */ + OUTPUT_FIELD_NAME: string; + /** + * Languages field name + */ + LANGUAGES_FIELD_NAME?: string; + /** + * Event Arc Region + */ + _EVENT_ARC_REGION?: EventArcRegionType; + /** + * Function timeout seconds + */ + _FUNCTION_TIMEOUT_SECONDS?: string; + /** + * VPC Connector + */ + _FUNCTION_VPC_CONNECTOR?: string; + /** + * VPC Connector Egress settings + */ + _FUNCTION_VPC_CONNECTOR_EGRESS_SETTINGS?: SystemFunctionVpcConnectorEgressSettingsParam; + /** + * Minimum function instances + */ + _FUNCTION_MIN_INSTANCES?: string; + /** + * Maximum function instances + */ + _FUNCTION_MAX_INSTANCES?: string; + /** + * Function ingress settings + */ + _FUNCTION_INGRESS_SETTINGS?: SystemFunctionIngressSettingsParam; + /** + * Function labels + */ + _FUNCTION_LABELS?: string; + /** + * KMS key name + */ + _FUNCTION_KMS_KEY_NAME?: string; + /** + * Docker repository + */ + _FUNCTION_DOCKER_REPOSITORY?: string; + /** + * Cloud Functions location + */ + _FUNCTION_LOCATION: SystemFunctionLocationParam; + /** + * Function memory + */ + _FUNCTION_MEMORY?: SystemFunctionMemoryParam; +} +export declare function firestoreTranslateText(instanceId: string, params: FirestoreTranslateTextParams): FirestoreTranslateText; +/** + * Translate Text in Firestore + * Translates strings written to a Cloud Firestore collection into multiple languages (uses Cloud Translation API). + */ +export declare class FirestoreTranslateText { + private instanceId; + private params; + events: string[]; + readonly FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; + readonly EXTENSION_VERSION = "0.1.18"; + constructor(instanceId: string, params: FirestoreTranslateTextParams); + getInstanceId(): string; + getParams(): FirestoreTranslateTextParams; + /** + * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. + */ + onStart(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. + */ + onSuccess(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. + */ + onError(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when the function is settled. Provides no customized data other than the context. + */ + onCompletion(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/spec/fixtures/extsdk/translate/index.js b/spec/fixtures/extsdk/translate/index.js new file mode 100644 index 000000000..e263f582f --- /dev/null +++ b/spec/fixtures/extsdk/translate/index.js @@ -0,0 +1,61 @@ +"use strict"; +/** + * Translate Text in Firestore SDK for firestore-translate-text@0.1.18 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for firestore-translate-text@0.1.18" + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FirestoreTranslateText = exports.firestoreTranslateText = void 0; +const eventarc_1 = require("../../../../src/v2/providers/eventarc"); +function firestoreTranslateText(instanceId, params) { + return new FirestoreTranslateText(instanceId, params); +} +exports.firestoreTranslateText = firestoreTranslateText; +/** + * Translate Text in Firestore + * Translates strings written to a Cloud Firestore collection into multiple languages (uses Cloud Translation API). + */ +class FirestoreTranslateText { + constructor(instanceId, params) { + this.instanceId = instanceId; + this.params = params; + this.events = []; + this.FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; + this.EXTENSION_VERSION = "0.1.18"; + } + getInstanceId() { return this.instanceId; } + getParams() { return this.params; } + /** + * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. + */ + onStart(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onStart"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onStart", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. + */ + onSuccess(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onSuccess"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onSuccess", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. + */ + onError(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onError"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onError", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when the function is settled. Provides no customized data other than the context. + */ + onCompletion(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onCompletion"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onCompletion", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } +} +exports.FirestoreTranslateText = FirestoreTranslateText; diff --git a/spec/fixtures/extsdk/translate/package.json b/spec/fixtures/extsdk/translate/package.json new file mode 100644 index 000000000..964287a7e --- /dev/null +++ b/spec/fixtures/extsdk/translate/package.json @@ -0,0 +1,4 @@ +{ + "name": "@firebase-extensions/firebase-firestore-translate-text-sdk", + "main": "./index.js" +} \ No newline at end of file diff --git a/spec/fixtures/sources/commonjs-grouped/index.js b/spec/fixtures/sources/commonjs-grouped/index.js index 385f8ea79..15f04e2a0 100644 --- a/spec/fixtures/sources/commonjs-grouped/index.js +++ b/spec/fixtures/sources/commonjs-grouped/index.js @@ -1,5 +1,8 @@ const functions = require("../../../../src/v1"); const functionsv2 = require("../../../../src/v2"); +const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; +const backfill = require("../../extsdk/local").backfill; + exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -17,4 +20,28 @@ exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; + exports.g1 = require("./g1"); diff --git a/spec/fixtures/sources/commonjs-main/functions.js b/spec/fixtures/sources/commonjs-main/functions.js index 31b0ae2fa..6e29f9d16 100644 --- a/spec/fixtures/sources/commonjs-main/functions.js +++ b/spec/fixtures/sources/commonjs-main/functions.js @@ -1,5 +1,7 @@ const functions = require("../../../../src/v1"); const functionsv2 = require("../../../../src/v2"); +const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; +const backfill = require("../../extsdk/local").backfill; exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,27 @@ exports.v2http = functionsv2.https.onRequest((req, resp) => { exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; \ No newline at end of file diff --git a/spec/fixtures/sources/commonjs-parametrized-fields/index.js b/spec/fixtures/sources/commonjs-parametrized-fields/index.js index c6f37a309..d153fc034 100644 --- a/spec/fixtures/sources/commonjs-parametrized-fields/index.js +++ b/spec/fixtures/sources/commonjs-parametrized-fields/index.js @@ -1,5 +1,7 @@ const functions = require("../../../../src/v1/index"); const functionsv2 = require("../../../../src/v2/index"); +const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; +const backfill = require("../../extsdk/local").backfill; const params = require("../../../../src/params"); params.clearParams(); @@ -28,3 +30,27 @@ exports.v2http = functionsv2.https.onRequest({ }, (req, resp) => { resp.status(200).send("Hello world!"); }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; diff --git a/spec/fixtures/sources/commonjs-params/index.js b/spec/fixtures/sources/commonjs-params/index.js index 447990730..4049a1478 100644 --- a/spec/fixtures/sources/commonjs-params/index.js +++ b/spec/fixtures/sources/commonjs-params/index.js @@ -1,5 +1,7 @@ const functions = require("../../../../src/v1/index"); const functionsv2 = require("../../../../src/v2/index"); +const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; +const backfill = require("../../extsdk/local").backfill; const params = require("../../../../src/params"); params.defineString("BORING"); @@ -40,3 +42,27 @@ exports.v2http = functionsv2.https.onRequest((req, resp) => { exports.v2callable = functionsv2.https.onCall(() => { return params.databaseURL; }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; diff --git a/spec/fixtures/sources/commonjs/index.js b/spec/fixtures/sources/commonjs/index.js index 31b0ae2fa..6e29f9d16 100644 --- a/spec/fixtures/sources/commonjs/index.js +++ b/spec/fixtures/sources/commonjs/index.js @@ -1,5 +1,7 @@ const functions = require("../../../../src/v1"); const functionsv2 = require("../../../../src/v2"); +const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; +const backfill = require("../../extsdk/local").backfill; exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,27 @@ exports.v2http = functionsv2.https.onRequest((req, resp) => { exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; \ No newline at end of file diff --git a/spec/runtime/loader.spec.ts b/spec/runtime/loader.spec.ts index f405b3cb9..a3c8c559c 100644 --- a/spec/runtime/loader.spec.ts +++ b/spec/runtime/loader.spec.ts @@ -3,7 +3,12 @@ import * as path from "path"; import * as functions from "../../src/v1"; import * as loader from "../../src/runtime/loader"; -import { ManifestEndpoint, ManifestRequiredAPI, ManifestStack } from "../../src/runtime/manifest"; +import { + ManifestEndpoint, + ManifestExtension, + ManifestRequiredAPI, + ManifestStack, +} from "../../src/runtime/manifest"; import { clearParams } from "../../src/params"; import { MINIMAL_V1_ENDPOINT, MINIMAL_V2_ENDPOINT } from "../fixtures"; import { MINIMAL_SCHEDULE_TRIGGER, MINIMIAL_TASK_QUEUE_TRIGGER } from "../v1/providers/fixtures"; @@ -31,8 +36,9 @@ describe("extractStack", () => { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; - loader.extractStack(module, endpoints, requiredAPIs); + loader.extractStack(module, endpoints, requiredAPIs, extensions); expect(endpoints).to.be.deep.equal({ http: { @@ -57,8 +63,9 @@ describe("extractStack", () => { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; - loader.extractStack(module, endpoints, requiredAPIs); + loader.extractStack(module, endpoints, requiredAPIs, extensions); expect(endpoints).to.be.deep.equal({ taskq: { @@ -87,8 +94,9 @@ describe("extractStack", () => { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; - loader.extractStack(module, endpoints, requiredAPIs); + loader.extractStack(module, endpoints, requiredAPIs, extensions); expect(endpoints).to.be.deep.equal({ fn1: { @@ -125,8 +133,9 @@ describe("extractStack", () => { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; - loader.extractStack(module, endpoints, requiredAPIs); + loader.extractStack(module, endpoints, requiredAPIs, extensions); expect(endpoints).to.be.deep.equal({ fn: { @@ -152,8 +161,9 @@ describe("extractStack", () => { const endpoints: Record = {}; const requiredAPIs: ManifestRequiredAPI[] = []; + const extensions: Record = {}; - loader.extractStack(module, endpoints, requiredAPIs); + loader.extractStack(module, endpoints, requiredAPIs, extensions); expect(endpoints).to.be.deep.equal({ scheduled: { @@ -259,8 +269,48 @@ describe("loadStack", () => { labels: {}, callableTrigger: {}, }, + ttOnStart: { + ...MINIMAL_V2_ENDPOINT, + entryPoint: "ttOnStart", + eventTrigger: { + channel: "projects/locations/us-central1/channels/firebase", + eventFilters: {}, + eventType: "firebase.extensions.firestore-translate-text.v1.onStart", + retry: false, + }, + labels: {}, + platform: "gcfv2", + region: ["us-central1"], + }, + }, + requiredAPIs: [ + { + api: "eventarcpublishing.googleapis.com", + reason: "Needed for custom event functions", + }, + ], + extensions: { + extRef1: { + params: { + COLLECTION_PATH: "collection1", + INPUT_FIELD_NAME: "input1", + LANGUAGES: "de,es", + OUTPUT_FIELD_NAME: "translated", + "firebaseextensions.v1beta.function/location": "us-central1", + _EVENT_ARC_REGION: "us-central1", + }, + ref: "firebase/firestore-translate-text@0.1.18", + events: ["firebase.extensions.firestore-translate-text.v1.onStart"], + }, + extLocal2: { + params: { + DO_BACKFILL: "False", + LOCATION: "us-central1", + }, + localPath: "./functions/generated/extensions/local/backfill/0.0.2/src", + events: [], + }, }, - requiredAPIs: [], specVersion: "v1alpha1", }; @@ -413,6 +463,19 @@ describe("loadStack", () => { labels: {}, httpsTrigger: {}, }, + ttOnStart: { + ...MINIMAL_V2_ENDPOINT, + entryPoint: "ttOnStart", + eventTrigger: { + channel: "projects/locations/us-central1/channels/firebase", + eventFilters: {}, + eventType: "firebase.extensions.firestore-translate-text.v1.onStart", + retry: false, + }, + labels: {}, + platform: "gcfv2", + region: ["us-central1"], + }, }, }, }, diff --git a/spec/runtime/manifest.spec.ts b/spec/runtime/manifest.spec.ts index eb553643b..7534ba2ee 100644 --- a/spec/runtime/manifest.spec.ts +++ b/spec/runtime/manifest.spec.ts @@ -27,6 +27,7 @@ describe("stackToWire", () => { requiredAPIs: [], params: [regExpParam.toSpec()], specVersion: "v1alpha1", + extensions: {}, }; const expected = { endpoints: {}, @@ -43,6 +44,7 @@ describe("stackToWire", () => { }, ], specVersion: "v1alpha1", + extensions: {}, }; expect(stackToWire(stack)).to.deep.equal(expected); }); @@ -60,6 +62,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; const expected = { endpoints: { @@ -73,6 +82,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; expect(stackToWire(stack)).to.deep.equal(expected); }); @@ -97,6 +113,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; const expected = { endpoints: { @@ -117,6 +140,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; expect(stackToWire(stack)).to.deep.equal(expected); }); @@ -149,6 +179,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; const expected = { endpoints: { @@ -172,6 +209,13 @@ describe("stackToWire", () => { }, requiredAPIs: [], specVersion: "v1alpha1", + extensions: { + ext1: { + params: {}, + localPath: "localPath", + events: [], + }, + }, }; expect(stackToWire(stack)).to.deep.equal(expected); }); diff --git a/src/runtime/loader.ts b/src/runtime/loader.ts index ddbd23302..953444e35 100644 --- a/src/runtime/loader.ts +++ b/src/runtime/loader.ts @@ -83,13 +83,13 @@ export function extractStack( extensions[val.instanceId] = { params: convertExtensionParams(val.params), ref: val.FIREBASE_EXTENSION_REFERENCE, - events: val.events, + events: val.events || [], }; } else if (isFirebaseLocalExtension(val)) { extensions[val.instanceId] = { params: convertExtensionParams(val.params), localPath: val.FIREBASE_EXTENSION_LOCAL_PATH, - events: val.events, + events: val.events || [], }; } else if (isObject(val)) { extractStack(val, endpoints, requiredAPIs, extensions, prefix + name + "-"); @@ -139,7 +139,7 @@ interface FirebaseLocalExtension { FIREBASE_EXTENSION_LOCAL_PATH: string; instanceId: string; params: Record; - events: string[]; + events?: string[]; } const isFirebaseLocalExtension = (val: unknown): val is FirebaseLocalExtension => { @@ -148,7 +148,7 @@ const isFirebaseLocalExtension = (val: unknown): val is FirebaseLocalExtension = typeof val.FIREBASE_EXTENSION_LOCAL_PATH === "string" && typeof val.instanceId === "string" && isObject(val.params) && - Array.isArray(val.events) + (!val.events || Array.isArray(val.events)) ); }; @@ -156,7 +156,7 @@ interface FirebaseRefExtension { FIREBASE_EXTENSION_REFERENCE: string; instanceId: string; params: Record; - events: string[]; + events?: string[]; } const isFirebaseRefExtension = (val: unknown): val is FirebaseRefExtension => { @@ -165,7 +165,7 @@ const isFirebaseRefExtension = (val: unknown): val is FirebaseRefExtension => { typeof val.FIREBASE_EXTENSION_REFERENCE === "string" && typeof val.instanceId === "string" && isObject(val.params) && - Array.isArray(val.events) + (!val.events || Array.isArray(val.events)) ); }; diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 87369c1af..b27b65127 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -26,8 +26,7 @@ import { WireParamSpec, SecretParam } from "../params/types"; /** * A definition of an extension as appears in the Manifest. - * - * @alpha + * Exactly one of ref or localPath must be present. */ export interface ManifestExtension { params: Record; From e84745c13290278cc74b599b8f0767b0b87ee393 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 15:36:03 -0400 Subject: [PATCH 04/12] fixed more tests --- .../sources/commonjs-grouped/index.js | 27 ++++++++ .../sources/commonjs-main/functions.js | 26 +++++++ .../sources/commonjs-preserve/index.js | 26 +++++++ scripts/bin-test/sources/commonjs/index.js | 26 +++++++ scripts/bin-test/sources/esm-ext/index.mjs | 23 +++++++ .../bin-test/sources/esm-main/functions.js | 23 +++++++ scripts/bin-test/sources/esm/index.js | 23 +++++++ scripts/bin-test/test.ts | 69 ++++++++++++++++++- 8 files changed, 240 insertions(+), 3 deletions(-) diff --git a/scripts/bin-test/sources/commonjs-grouped/index.js b/scripts/bin-test/sources/commonjs-grouped/index.js index b00828de0..00ce31928 100644 --- a/scripts/bin-test/sources/commonjs-grouped/index.js +++ b/scripts/bin-test/sources/commonjs-grouped/index.js @@ -1,5 +1,8 @@ const functions = require("firebase-functions"); const functionsv2 = require("firebase-functions/v2"); +const firestoreTranslateText = require("@firebase-extensions/firebase-firestore-translate-text-sdk").firestoreTranslateText; +const backfill = require("@firebase-extensions/local-backfill-sdk").backfill; + exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -17,4 +20,28 @@ exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; + exports.g1 = require("./g1"); diff --git a/scripts/bin-test/sources/commonjs-main/functions.js b/scripts/bin-test/sources/commonjs-main/functions.js index 9122f9223..4994aca2f 100644 --- a/scripts/bin-test/sources/commonjs-main/functions.js +++ b/scripts/bin-test/sources/commonjs-main/functions.js @@ -1,5 +1,7 @@ const functions = require("firebase-functions"); const functionsv2 = require("firebase-functions/v2"); +const firestoreTranslateText = require("@firebase-extensions/firebase-firestore-translate-text-sdk").firestoreTranslateText; +const backfill = require("@firebase-extensions/local-backfill-sdk").backfill; exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,27 @@ exports.v2http = functionsv2.https.onRequest((req, resp) => { exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; diff --git a/scripts/bin-test/sources/commonjs-preserve/index.js b/scripts/bin-test/sources/commonjs-preserve/index.js index 7c953dec8..cacdd8e10 100644 --- a/scripts/bin-test/sources/commonjs-preserve/index.js +++ b/scripts/bin-test/sources/commonjs-preserve/index.js @@ -1,5 +1,7 @@ const functions = require("firebase-functions"); const functionsv2 = require("firebase-functions/v2"); +const firestoreTranslateText = require("@firebase-extensions/firebase-firestore-translate-text-sdk").firestoreTranslateText; +const backfill = require("@firebase-extensions/local-backfill-sdk").backfill; exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,27 @@ functionsv2.setGlobalOptions({ preserveExternalChanges: true }); exports.v2http = functionsv2.https.onRequest((req, resp) => { resp.status(200).send("PASS"); }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; \ No newline at end of file diff --git a/scripts/bin-test/sources/commonjs/index.js b/scripts/bin-test/sources/commonjs/index.js index 9122f9223..4994aca2f 100644 --- a/scripts/bin-test/sources/commonjs/index.js +++ b/scripts/bin-test/sources/commonjs/index.js @@ -1,5 +1,7 @@ const functions = require("firebase-functions"); const functionsv2 = require("firebase-functions/v2"); +const firestoreTranslateText = require("@firebase-extensions/firebase-firestore-translate-text-sdk").firestoreTranslateText; +const backfill = require("@firebase-extensions/local-backfill-sdk").backfill; exports.v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,27 @@ exports.v2http = functionsv2.https.onRequest((req, resp) => { exports.v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); +exports.extRef1 = extRef1; + +// A Firebase function defined by extension event +const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); +exports.ttOnStart = ttOnStart; + +// A Firebase extension by localPath +const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); +exports.extLocal2 = extLocal2; diff --git a/scripts/bin-test/sources/esm-ext/index.mjs b/scripts/bin-test/sources/esm-ext/index.mjs index 91e974d93..5413b5fa2 100644 --- a/scripts/bin-test/sources/esm-ext/index.mjs +++ b/scripts/bin-test/sources/esm-ext/index.mjs @@ -1,5 +1,7 @@ import * as functions from "firebase-functions"; import * as functionsv2 from "firebase-functions/v2"; +import { firestoreTranslateText } from "@firebase-extensions/firebase-firestore-translate-text-sdk"; +import { backfill } from "@firebase-extensions/local-backfill-sdk"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,24 @@ export const v2http = functionsv2.https.onRequest((req, resp) => { export const v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +export const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); + +// A Firebase function defined by extension event +export const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); + +// A Firebase extension by localPath +export const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); \ No newline at end of file diff --git a/scripts/bin-test/sources/esm-main/functions.js b/scripts/bin-test/sources/esm-main/functions.js index b09186731..3515c2124 100644 --- a/scripts/bin-test/sources/esm-main/functions.js +++ b/scripts/bin-test/sources/esm-main/functions.js @@ -1,5 +1,7 @@ import * as functions from "firebase-functions"; import * as functionsv2 from "firebase-functions/v2"; +import { firestoreTranslateText } from "@firebase-extensions/firebase-firestore-translate-text-sdk"; +import { backfill } from "@firebase-extensions/local-backfill-sdk"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,24 @@ export const v2http = functionsv2.https.onRequest((req, resp) => { export const v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +export const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); + +// A Firebase function defined by extension event +export const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); + +// A Firebase extension by localPath +export const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); \ No newline at end of file diff --git a/scripts/bin-test/sources/esm/index.js b/scripts/bin-test/sources/esm/index.js index b09186731..3515c2124 100644 --- a/scripts/bin-test/sources/esm/index.js +++ b/scripts/bin-test/sources/esm/index.js @@ -1,5 +1,7 @@ import * as functions from "firebase-functions"; import * as functionsv2 from "firebase-functions/v2"; +import { firestoreTranslateText } from "@firebase-extensions/firebase-firestore-translate-text-sdk"; +import { backfill } from "@firebase-extensions/local-backfill-sdk"; export const v1http = functions.https.onRequest((req, resp) => { resp.status(200).send("PASS"); @@ -16,3 +18,24 @@ export const v2http = functionsv2.https.onRequest((req, resp) => { export const v2callable = functionsv2.https.onCall(() => { return "PASS"; }); + +// A Firebase extension by ref +export const extRef1 = firestoreTranslateText("extRef1", { + "COLLECTION_PATH": "collection1", + "INPUT_FIELD_NAME": "input1", + "LANGUAGES": "de,es", + "OUTPUT_FIELD_NAME": "translated", + "_EVENT_ARC_REGION": "us-central1", + "_FUNCTION_LOCATION": "us-central1", +}); + +// A Firebase function defined by extension event +export const ttOnStart = extRef1.onStart((event) => { + console.log("onStart got event: " + JSON.stringify(event, null, 2)); +}); + +// A Firebase extension by localPath +export const extLocal2 = backfill("extLocal2", { + DO_BACKFILL: "False", + LOCATION: "us-central1", +}); \ No newline at end of file diff --git a/scripts/bin-test/test.ts b/scripts/bin-test/test.ts index efc5a5127..744e98a85 100644 --- a/scripts/bin-test/test.ts +++ b/scripts/bin-test/test.ts @@ -26,6 +26,29 @@ const DEFAULT_V1_OPTIONS = { ...DEFAULT_OPTIONS }; const DEFAULT_V2_OPTIONS = { ...DEFAULT_OPTIONS, concurrency: null }; +const BASE_EXTENSIONS = { + extRef1: { + params: { + COLLECTION_PATH: "collection1", + INPUT_FIELD_NAME: "input1", + LANGUAGES: "de,es", + OUTPUT_FIELD_NAME: "translated", + _EVENT_ARC_REGION: "us-central1", + "firebaseextensions.v1beta.function/location": "us-central1", + }, + ref: "firebase/firestore-translate-text@0.1.18", + events: ["firebase.extensions.firestore-translate-text.v1.onStart"], + }, + extLocal2: { + params: { + DO_BACKFILL: "False", + LOCATION: "us-central1", + }, + localPath: "./functions/generated/extensions/local/backfill0.0.2/src", + events: [], + }, +}; + const BASE_STACK = { endpoints: { v1http: { @@ -55,9 +78,28 @@ const BASE_STACK = { labels: {}, callableTrigger: {}, }, + ttOnStart: { + ...DEFAULT_V2_OPTIONS, + platform: "gcfv2", + entryPoint: "ttOnStart", + labels: {}, + region: ["us-central1"], + eventTrigger: { + eventType: "firebase.extensions.firestore-translate-text.v1.onStart", + eventFilters: {}, + retry: false, + channel: "projects/locations/us-central1/channels/firebase", + }, + }, }, - requiredAPIs: [], + requiredAPIs: [ + { + api: "eventarcpublishing.googleapis.com", + reason: "Needed for custom event functions", + }, + ], specVersion: "v1alpha1", + extensions: BASE_EXTENSIONS, }; interface Testcase { @@ -108,10 +150,15 @@ async function startBin( FUNCTIONS_CONTROL_API: "true", }, }); - if (!proc) { throw new Error("Failed to start firebase functions"); } + proc.stdout?.on("data", (chunk: Buffer) => { + console.log(chunk.toString("utf8")); + }); + proc.stderr?.on("data", (chunk: Buffer) => { + console.log(chunk.toString("utf8")); + }); await retryUntil(async () => { try { @@ -246,9 +293,25 @@ describe("functions.yaml", function () { labels: {}, httpsTrigger: {}, }, + ttOnStart: { + platform: "gcfv2", + entryPoint: "ttOnStart", + labels: {}, + region: ["us-central1"], + eventTrigger: { + eventType: "firebase.extensions.firestore-translate-text.v1.onStart", + eventFilters: {}, + retry: false, + channel: "projects/locations/us-central1/channels/firebase", + }, + }, }, - requiredAPIs: [], + requiredAPIs: [{ + api: "eventarcpublishing.googleapis.com", + reason: "Needed for custom event functions", + },], specVersion: "v1alpha1", + extensions: BASE_EXTENSIONS, }, }, ]; From 97d8ce31414b91791357b31c484e620e293ffb50 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 17:04:00 -0400 Subject: [PATCH 05/12] more testing fixes --- scripts/bin-test/run.sh | 9 ++++++++- scripts/bin-test/test.ts | 12 +++++++----- spec/fixtures/extsdk/translate/index.d.ts | 3 +-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/scripts/bin-test/run.sh b/scripts/bin-test/run.sh index aa10b4286..8998ad6f1 100755 --- a/scripts/bin-test/run.sh +++ b/scripts/bin-test/run.sh @@ -5,10 +5,17 @@ set -ex # Immediately exit on failure npm run build npm link -# Link local SDK to all test sources. +# Link the extensions SDKs for the testing environment. +(cd scripts/bin-test/extsdks/local && npm link) +(cd scripts/bin-test/extsdks/translate && npm link) +(cd scripts/bin-test/extsdks/translate && npm link firebase-functions) + +# Link SDKs to all test sources. for f in scripts/bin-test/sources/*; do if [ -d "$f" ]; then (cd "$f" && npm link firebase-functions) + (cd "$f" && npm link @firebase-extensions/firebase-firestore-translate-text-sdk) + (cd "$f" && npm link @firebase-extensions/local-backfill-sdk) fi done diff --git a/scripts/bin-test/test.ts b/scripts/bin-test/test.ts index 744e98a85..85b2eb249 100644 --- a/scripts/bin-test/test.ts +++ b/scripts/bin-test/test.ts @@ -44,7 +44,7 @@ const BASE_EXTENSIONS = { DO_BACKFILL: "False", LOCATION: "us-central1", }, - localPath: "./functions/generated/extensions/local/backfill0.0.2/src", + localPath: "./functions/generated/extensions/local/backfill/0.0.2/src", events: [], }, }; @@ -306,10 +306,12 @@ describe("functions.yaml", function () { }, }, }, - requiredAPIs: [{ - api: "eventarcpublishing.googleapis.com", - reason: "Needed for custom event functions", - },], + requiredAPIs: [ + { + api: "eventarcpublishing.googleapis.com", + reason: "Needed for custom event functions", + }, + ], specVersion: "v1alpha1", extensions: BASE_EXTENSIONS, }, diff --git a/spec/fixtures/extsdk/translate/index.d.ts b/spec/fixtures/extsdk/translate/index.d.ts index 96b86dcc3..8e5cee195 100644 --- a/spec/fixtures/extsdk/translate/index.d.ts +++ b/spec/fixtures/extsdk/translate/index.d.ts @@ -119,5 +119,4 @@ export declare class FirestoreTranslateText { * Occurs when the function is settled. Provides no customized data other than the context. */ onCompletion(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; -} -//# sourceMappingURL=index.d.ts.map \ No newline at end of file +} \ No newline at end of file From 19e320c20b6899d5c6d0720d8d6c327d9a6480d0 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 17:07:27 -0400 Subject: [PATCH 06/12] added extsdks for tests --- scripts/bin-test/extsdks/local/index.d.ts | 37 ++++++ scripts/bin-test/extsdks/local/index.js | 30 +++++ scripts/bin-test/extsdks/local/package.json | 4 + scripts/bin-test/extsdks/translate/index.d.ts | 122 ++++++++++++++++++ scripts/bin-test/extsdks/translate/index.js | 61 +++++++++ .../bin-test/extsdks/translate/package.json | 4 + 6 files changed, 258 insertions(+) create mode 100644 scripts/bin-test/extsdks/local/index.d.ts create mode 100644 scripts/bin-test/extsdks/local/index.js create mode 100644 scripts/bin-test/extsdks/local/package.json create mode 100644 scripts/bin-test/extsdks/translate/index.d.ts create mode 100644 scripts/bin-test/extsdks/translate/index.js create mode 100644 scripts/bin-test/extsdks/translate/package.json diff --git a/scripts/bin-test/extsdks/local/index.d.ts b/scripts/bin-test/extsdks/local/index.d.ts new file mode 100644 index 000000000..ed3a39c74 --- /dev/null +++ b/scripts/bin-test/extsdks/local/index.d.ts @@ -0,0 +1,37 @@ +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester SDK for backfill@0.0.2 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for Local extension. + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +export type DoBackfillParam = "True" | "False"; +export type LocationParam = "us-central1" | "us-east1" | "us-east4" | "europe-west1" | "europe-west2" | "europe-west3" | "asia-east2" | "asia-northeast1"; +/** + * Parameters for backfill@0.0.2 extension + */ +export interface BackfillParams { + /** + * Do a backfill + */ + DO_BACKFILL: DoBackfillParam; + /** + * Cloud Functions location + */ + LOCATION: LocationParam; +} +export declare function backfill(instanceId: string, params: BackfillParams): Backfill; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester + * A tester for the TaskQueue/LCE/RuntimeStatus project + */ +export declare class Backfill { + private instanceId; + private params; + readonly FIREBASE_EXTENSION_LOCAL_PATH = "./functions/generated/extensions/local/backfill/0.0.2/src"; + constructor(instanceId: string, params: BackfillParams); + getInstanceId(): string; + getParams(): BackfillParams; +} \ No newline at end of file diff --git a/scripts/bin-test/extsdks/local/index.js b/scripts/bin-test/extsdks/local/index.js new file mode 100644 index 000000000..f1f9cce55 --- /dev/null +++ b/scripts/bin-test/extsdks/local/index.js @@ -0,0 +1,30 @@ +"use strict"; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester SDK for extensions-try-backfill3@0.0.2 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for Local extension. + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.backfill = exports.backfill = void 0; +function backfill(instanceId, params) { + return new Backfill(instanceId, params); +} +exports.backfill = backfill; +/** + * TaskQueue/LifecycleEvent/RuntimeStatus Tester + * A tester for the TaskQueue/LCE/RuntimeStatus project + */ +class Backfill { + constructor(instanceId, params) { + this.instanceId = instanceId; + this.params = params; + this.FIREBASE_EXTENSION_LOCAL_PATH = "./functions/generated/extensions/local/backfill/0.0.2/src"; + } + getInstanceId() { return this.instanceId; } + getParams() { return this.params; } +} +exports.Backfill = Backfill; diff --git a/scripts/bin-test/extsdks/local/package.json b/scripts/bin-test/extsdks/local/package.json new file mode 100644 index 000000000..700806b3e --- /dev/null +++ b/scripts/bin-test/extsdks/local/package.json @@ -0,0 +1,4 @@ +{ + "name": "@firebase-extensions/local-backfill-sdk", + "main": "./index.js" + } \ No newline at end of file diff --git a/scripts/bin-test/extsdks/translate/index.d.ts b/scripts/bin-test/extsdks/translate/index.d.ts new file mode 100644 index 000000000..8e5cee195 --- /dev/null +++ b/scripts/bin-test/extsdks/translate/index.d.ts @@ -0,0 +1,122 @@ +/** + * Translate Text in Firestore SDK for firestore-translate-text@0.1.18 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for firestore-translate-text@0.1.18" + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +import { CloudEvent } from "../../../../v2"; +import { EventarcTriggerOptions } from "../../../../v2/eventarc"; +export type EventCallback = (event: CloudEvent) => unknown | Promise; +export type SimpleEventarcTriggerOptions = Omit; +export type EventArcRegionType = "us-central1" | "us-west1" | "europe-west4" | "asia-northeast1"; +export type SystemFunctionVpcConnectorEgressSettingsParam = "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED" | "PRIVATE_RANGES_ONLY" | "ALL_TRAFFIC"; +export type SystemFunctionIngressSettingsParam = "ALLOW_ALL" | "ALLOW_INTERNAL_ONLY" | "ALLOW_INTERNAL_AND_GCLB"; +export type SystemFunctionLocationParam = "us-central1" | "us-east1" | "us-east4" | "us-west1" | "us-west2" | "us-west3" | "us-west4" | "europe-central2" | "europe-west1" | "europe-west2" | "europe-west3" | "europe-west6" | "asia-east1" | "asia-east2" | "asia-northeast1" | "asia-northeast2" | "asia-northeast3" | "asia-south1" | "asia-southeast1" | "asia-southeast2" | "northamerica-northeast1" | "southamerica-east1" | "australia-southeast1"; +export type SystemFunctionMemoryParam = "128" | "256" | "512" | "1024" | "2048" | "4096" | "8192"; +/** + * Parameters for firestore-translate-text@0.1.18 extension + */ +export interface FirestoreTranslateTextParams { + /** + * Target languages for translations, as a comma-separated list + */ + LANGUAGES: string; + /** + * Collection path + */ + COLLECTION_PATH: string; + /** + * Input field name + */ + INPUT_FIELD_NAME: string; + /** + * Translations output field name + */ + OUTPUT_FIELD_NAME: string; + /** + * Languages field name + */ + LANGUAGES_FIELD_NAME?: string; + /** + * Event Arc Region + */ + _EVENT_ARC_REGION?: EventArcRegionType; + /** + * Function timeout seconds + */ + _FUNCTION_TIMEOUT_SECONDS?: string; + /** + * VPC Connector + */ + _FUNCTION_VPC_CONNECTOR?: string; + /** + * VPC Connector Egress settings + */ + _FUNCTION_VPC_CONNECTOR_EGRESS_SETTINGS?: SystemFunctionVpcConnectorEgressSettingsParam; + /** + * Minimum function instances + */ + _FUNCTION_MIN_INSTANCES?: string; + /** + * Maximum function instances + */ + _FUNCTION_MAX_INSTANCES?: string; + /** + * Function ingress settings + */ + _FUNCTION_INGRESS_SETTINGS?: SystemFunctionIngressSettingsParam; + /** + * Function labels + */ + _FUNCTION_LABELS?: string; + /** + * KMS key name + */ + _FUNCTION_KMS_KEY_NAME?: string; + /** + * Docker repository + */ + _FUNCTION_DOCKER_REPOSITORY?: string; + /** + * Cloud Functions location + */ + _FUNCTION_LOCATION: SystemFunctionLocationParam; + /** + * Function memory + */ + _FUNCTION_MEMORY?: SystemFunctionMemoryParam; +} +export declare function firestoreTranslateText(instanceId: string, params: FirestoreTranslateTextParams): FirestoreTranslateText; +/** + * Translate Text in Firestore + * Translates strings written to a Cloud Firestore collection into multiple languages (uses Cloud Translation API). + */ +export declare class FirestoreTranslateText { + private instanceId; + private params; + events: string[]; + readonly FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; + readonly EXTENSION_VERSION = "0.1.18"; + constructor(instanceId: string, params: FirestoreTranslateTextParams); + getInstanceId(): string; + getParams(): FirestoreTranslateTextParams; + /** + * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. + */ + onStart(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. + */ + onSuccess(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. + */ + onError(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when the function is settled. Provides no customized data other than the context. + */ + onCompletion(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; +} \ No newline at end of file diff --git a/scripts/bin-test/extsdks/translate/index.js b/scripts/bin-test/extsdks/translate/index.js new file mode 100644 index 000000000..6721d13d6 --- /dev/null +++ b/scripts/bin-test/extsdks/translate/index.js @@ -0,0 +1,61 @@ +"use strict"; +/** + * Translate Text in Firestore SDK for firestore-translate-text@0.1.18 + * + * When filing bugs or feature requests please specify: + * "Extensions SDK v1.0.0 for firestore-translate-text@0.1.18" + * https://github.com/firebase/firebase-tools/issues/new/choose + * + * GENERATED FILE. DO NOT EDIT. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FirestoreTranslateText = exports.firestoreTranslateText = void 0; +const eventarc_1 = require("firebase-functions/v2/eventarc"); +function firestoreTranslateText(instanceId, params) { + return new FirestoreTranslateText(instanceId, params); +} +exports.firestoreTranslateText = firestoreTranslateText; +/** + * Translate Text in Firestore + * Translates strings written to a Cloud Firestore collection into multiple languages (uses Cloud Translation API). + */ +class FirestoreTranslateText { + constructor(instanceId, params) { + this.instanceId = instanceId; + this.params = params; + this.events = []; + this.FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; + this.EXTENSION_VERSION = "0.1.18"; + } + getInstanceId() { return this.instanceId; } + getParams() { return this.params; } + /** + * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. + */ + onStart(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onStart"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onStart", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. + */ + onSuccess(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onSuccess"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onSuccess", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. + */ + onError(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onError"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onError", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } + /** + * Occurs when the function is settled. Provides no customized data other than the context. + */ + onCompletion(callback, options) { + this.events.push("firebase.extensions.firestore-translate-text.v1.onCompletion"); + return (0, eventarc_1.onCustomEventPublished)(Object.assign(Object.assign({}, options), { "eventType": "firebase.extensions.firestore-translate-text.v1.onCompletion", "channel": `projects/locations/${this.params._EVENT_ARC_REGION}/channels/firebase`, "region": `${this.params._EVENT_ARC_REGION}` }), callback); + } +} +exports.FirestoreTranslateText = FirestoreTranslateText; diff --git a/scripts/bin-test/extsdks/translate/package.json b/scripts/bin-test/extsdks/translate/package.json new file mode 100644 index 000000000..964287a7e --- /dev/null +++ b/scripts/bin-test/extsdks/translate/package.json @@ -0,0 +1,4 @@ +{ + "name": "@firebase-extensions/firebase-firestore-translate-text-sdk", + "main": "./index.js" +} \ No newline at end of file From f0755905c429cea7481be1a8a7716dc11a9d911a Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 17:14:12 -0400 Subject: [PATCH 07/12] fixed lint --- scripts/bin-test/extsdks/local/index.d.ts | 41 +-- scripts/bin-test/extsdks/translate/index.d.ts | 243 +++++++++++------- 2 files changed, 170 insertions(+), 114 deletions(-) diff --git a/scripts/bin-test/extsdks/local/index.d.ts b/scripts/bin-test/extsdks/local/index.d.ts index ed3a39c74..620621e2e 100644 --- a/scripts/bin-test/extsdks/local/index.d.ts +++ b/scripts/bin-test/extsdks/local/index.d.ts @@ -8,19 +8,27 @@ * GENERATED FILE. DO NOT EDIT. */ export type DoBackfillParam = "True" | "False"; -export type LocationParam = "us-central1" | "us-east1" | "us-east4" | "europe-west1" | "europe-west2" | "europe-west3" | "asia-east2" | "asia-northeast1"; +export type LocationParam = + | "us-central1" + | "us-east1" + | "us-east4" + | "europe-west1" + | "europe-west2" + | "europe-west3" + | "asia-east2" + | "asia-northeast1"; /** * Parameters for backfill@0.0.2 extension */ export interface BackfillParams { - /** - * Do a backfill - */ - DO_BACKFILL: DoBackfillParam; - /** - * Cloud Functions location - */ - LOCATION: LocationParam; + /** + * Do a backfill + */ + DO_BACKFILL: DoBackfillParam; + /** + * Cloud Functions location + */ + LOCATION: LocationParam; } export declare function backfill(instanceId: string, params: BackfillParams): Backfill; /** @@ -28,10 +36,11 @@ export declare function backfill(instanceId: string, params: BackfillParams): Ba * A tester for the TaskQueue/LCE/RuntimeStatus project */ export declare class Backfill { - private instanceId; - private params; - readonly FIREBASE_EXTENSION_LOCAL_PATH = "./functions/generated/extensions/local/backfill/0.0.2/src"; - constructor(instanceId: string, params: BackfillParams); - getInstanceId(): string; - getParams(): BackfillParams; -} \ No newline at end of file + private instanceId; + private params; + readonly FIREBASE_EXTENSION_LOCAL_PATH = + "./functions/generated/extensions/local/backfill/0.0.2/src"; + constructor(instanceId: string, params: BackfillParams); + getInstanceId(): string; + getParams(): BackfillParams; +} diff --git a/scripts/bin-test/extsdks/translate/index.d.ts b/scripts/bin-test/extsdks/translate/index.d.ts index 8e5cee195..ba706712c 100644 --- a/scripts/bin-test/extsdks/translate/index.d.ts +++ b/scripts/bin-test/extsdks/translate/index.d.ts @@ -10,113 +10,160 @@ import { CloudEvent } from "../../../../v2"; import { EventarcTriggerOptions } from "../../../../v2/eventarc"; export type EventCallback = (event: CloudEvent) => unknown | Promise; -export type SimpleEventarcTriggerOptions = Omit; +export type SimpleEventarcTriggerOptions = Omit< + EventarcTriggerOptions, + "eventType" | "channel" | "region" +>; export type EventArcRegionType = "us-central1" | "us-west1" | "europe-west4" | "asia-northeast1"; -export type SystemFunctionVpcConnectorEgressSettingsParam = "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED" | "PRIVATE_RANGES_ONLY" | "ALL_TRAFFIC"; -export type SystemFunctionIngressSettingsParam = "ALLOW_ALL" | "ALLOW_INTERNAL_ONLY" | "ALLOW_INTERNAL_AND_GCLB"; -export type SystemFunctionLocationParam = "us-central1" | "us-east1" | "us-east4" | "us-west1" | "us-west2" | "us-west3" | "us-west4" | "europe-central2" | "europe-west1" | "europe-west2" | "europe-west3" | "europe-west6" | "asia-east1" | "asia-east2" | "asia-northeast1" | "asia-northeast2" | "asia-northeast3" | "asia-south1" | "asia-southeast1" | "asia-southeast2" | "northamerica-northeast1" | "southamerica-east1" | "australia-southeast1"; +export type SystemFunctionVpcConnectorEgressSettingsParam = + | "VPC_CONNECTOR_EGRESS_SETTINGS_UNSPECIFIED" + | "PRIVATE_RANGES_ONLY" + | "ALL_TRAFFIC"; +export type SystemFunctionIngressSettingsParam = + | "ALLOW_ALL" + | "ALLOW_INTERNAL_ONLY" + | "ALLOW_INTERNAL_AND_GCLB"; +export type SystemFunctionLocationParam = + | "us-central1" + | "us-east1" + | "us-east4" + | "us-west1" + | "us-west2" + | "us-west3" + | "us-west4" + | "europe-central2" + | "europe-west1" + | "europe-west2" + | "europe-west3" + | "europe-west6" + | "asia-east1" + | "asia-east2" + | "asia-northeast1" + | "asia-northeast2" + | "asia-northeast3" + | "asia-south1" + | "asia-southeast1" + | "asia-southeast2" + | "northamerica-northeast1" + | "southamerica-east1" + | "australia-southeast1"; export type SystemFunctionMemoryParam = "128" | "256" | "512" | "1024" | "2048" | "4096" | "8192"; /** * Parameters for firestore-translate-text@0.1.18 extension */ export interface FirestoreTranslateTextParams { - /** - * Target languages for translations, as a comma-separated list - */ - LANGUAGES: string; - /** - * Collection path - */ - COLLECTION_PATH: string; - /** - * Input field name - */ - INPUT_FIELD_NAME: string; - /** - * Translations output field name - */ - OUTPUT_FIELD_NAME: string; - /** - * Languages field name - */ - LANGUAGES_FIELD_NAME?: string; - /** - * Event Arc Region - */ - _EVENT_ARC_REGION?: EventArcRegionType; - /** - * Function timeout seconds - */ - _FUNCTION_TIMEOUT_SECONDS?: string; - /** - * VPC Connector - */ - _FUNCTION_VPC_CONNECTOR?: string; - /** - * VPC Connector Egress settings - */ - _FUNCTION_VPC_CONNECTOR_EGRESS_SETTINGS?: SystemFunctionVpcConnectorEgressSettingsParam; - /** - * Minimum function instances - */ - _FUNCTION_MIN_INSTANCES?: string; - /** - * Maximum function instances - */ - _FUNCTION_MAX_INSTANCES?: string; - /** - * Function ingress settings - */ - _FUNCTION_INGRESS_SETTINGS?: SystemFunctionIngressSettingsParam; - /** - * Function labels - */ - _FUNCTION_LABELS?: string; - /** - * KMS key name - */ - _FUNCTION_KMS_KEY_NAME?: string; - /** - * Docker repository - */ - _FUNCTION_DOCKER_REPOSITORY?: string; - /** - * Cloud Functions location - */ - _FUNCTION_LOCATION: SystemFunctionLocationParam; - /** - * Function memory - */ - _FUNCTION_MEMORY?: SystemFunctionMemoryParam; + /** + * Target languages for translations, as a comma-separated list + */ + LANGUAGES: string; + /** + * Collection path + */ + COLLECTION_PATH: string; + /** + * Input field name + */ + INPUT_FIELD_NAME: string; + /** + * Translations output field name + */ + OUTPUT_FIELD_NAME: string; + /** + * Languages field name + */ + LANGUAGES_FIELD_NAME?: string; + /** + * Event Arc Region + */ + _EVENT_ARC_REGION?: EventArcRegionType; + /** + * Function timeout seconds + */ + _FUNCTION_TIMEOUT_SECONDS?: string; + /** + * VPC Connector + */ + _FUNCTION_VPC_CONNECTOR?: string; + /** + * VPC Connector Egress settings + */ + _FUNCTION_VPC_CONNECTOR_EGRESS_SETTINGS?: SystemFunctionVpcConnectorEgressSettingsParam; + /** + * Minimum function instances + */ + _FUNCTION_MIN_INSTANCES?: string; + /** + * Maximum function instances + */ + _FUNCTION_MAX_INSTANCES?: string; + /** + * Function ingress settings + */ + _FUNCTION_INGRESS_SETTINGS?: SystemFunctionIngressSettingsParam; + /** + * Function labels + */ + _FUNCTION_LABELS?: string; + /** + * KMS key name + */ + _FUNCTION_KMS_KEY_NAME?: string; + /** + * Docker repository + */ + _FUNCTION_DOCKER_REPOSITORY?: string; + /** + * Cloud Functions location + */ + _FUNCTION_LOCATION: SystemFunctionLocationParam; + /** + * Function memory + */ + _FUNCTION_MEMORY?: SystemFunctionMemoryParam; } -export declare function firestoreTranslateText(instanceId: string, params: FirestoreTranslateTextParams): FirestoreTranslateText; +export declare function firestoreTranslateText( + instanceId: string, + params: FirestoreTranslateTextParams +): FirestoreTranslateText; /** * Translate Text in Firestore * Translates strings written to a Cloud Firestore collection into multiple languages (uses Cloud Translation API). */ export declare class FirestoreTranslateText { - private instanceId; - private params; - events: string[]; - readonly FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; - readonly EXTENSION_VERSION = "0.1.18"; - constructor(instanceId: string, params: FirestoreTranslateTextParams); - getInstanceId(): string; - getParams(): FirestoreTranslateTextParams; - /** - * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. - */ - onStart(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; - /** - * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. - */ - onSuccess(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; - /** - * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. - */ - onError(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; - /** - * Occurs when the function is settled. Provides no customized data other than the context. - */ - onCompletion(callback: EventCallback, options?: SimpleEventarcTriggerOptions): import("firebase-functions/v2").CloudFunction>; -} \ No newline at end of file + private instanceId; + private params; + events: string[]; + readonly FIREBASE_EXTENSION_REFERENCE = "firebase/firestore-translate-text@0.1.18"; + readonly EXTENSION_VERSION = "0.1.18"; + constructor(instanceId: string, params: FirestoreTranslateTextParams); + getInstanceId(): string; + getParams(): FirestoreTranslateTextParams; + /** + * Occurs when a trigger has been called within the Extension, and will include data such as the context of the trigger request. + */ + onStart( + callback: EventCallback, + options?: SimpleEventarcTriggerOptions + ): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when image resizing completes successfully. The event will contain further details about specific formats and sizes. + */ + onSuccess( + callback: EventCallback, + options?: SimpleEventarcTriggerOptions + ): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when an issue has been experienced in the Extension. This will include any error data that has been included within the Error Exception. + */ + onError( + callback: EventCallback, + options?: SimpleEventarcTriggerOptions + ): import("firebase-functions/v2").CloudFunction>; + /** + * Occurs when the function is settled. Provides no customized data other than the context. + */ + onCompletion( + callback: EventCallback, + options?: SimpleEventarcTriggerOptions + ): import("firebase-functions/v2").CloudFunction>; +} From 65f4218ccfdc3a8e9257bf8ebf92a1839edf4aa5 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 17:34:32 -0400 Subject: [PATCH 08/12] added changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29bb..0615875c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1 @@ +- Future Extensions support \ No newline at end of file From b71ae6ddeb36e519431004caea2a185112908e09 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Wed, 14 Aug 2024 17:48:32 -0400 Subject: [PATCH 09/12] more lint --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0615875c0..51ac4ebb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -- Future Extensions support \ No newline at end of file +- Future Extensions support From 84f073c9b1f6907755e6ba619ce153c46662a91d Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Thu, 15 Aug 2024 13:21:11 -0400 Subject: [PATCH 10/12] added PR number to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51ac4ebb0..6b6b1028a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1 @@ -- Future Extensions support +- Future Extensions support (#1590) From 1a45154c9e7081d8b57d5fe669c1b050f3b3cfd9 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Thu, 15 Aug 2024 15:34:04 -0400 Subject: [PATCH 11/12] make extensions optional --- src/runtime/manifest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index b27b65127..47b948825 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -133,7 +133,7 @@ export interface ManifestStack { params?: WireParamSpec[]; requiredAPIs: ManifestRequiredAPI[]; endpoints: Record; - extensions: Record; + extensions?: Record; } /** From a56adbd6bd448187ebc177a72665456daa55a183 Mon Sep 17 00:00:00 2001 From: Ingrid Fielker Date: Fri, 16 Aug 2024 13:55:47 -0400 Subject: [PATCH 12/12] fixing nits --- .../sources/commonjs-grouped/index.js | 3 +-- .../sources/commonjs-main/functions.js | 3 +-- .../sources/commonjs-preserve/index.js | 5 ++-- scripts/bin-test/sources/commonjs/index.js | 3 +-- .../sources/commonjs-grouped/index.js | 3 +-- .../sources/commonjs-main/functions.js | 5 ++-- .../commonjs-parametrized-fields/index.js | 26 ------------------- .../fixtures/sources/commonjs-params/index.js | 3 +-- spec/fixtures/sources/commonjs/index.js | 5 ++-- spec/runtime/loader.spec.ts | 15 ++--------- 10 files changed, 13 insertions(+), 58 deletions(-) diff --git a/scripts/bin-test/sources/commonjs-grouped/index.js b/scripts/bin-test/sources/commonjs-grouped/index.js index 00ce31928..022374a65 100644 --- a/scripts/bin-test/sources/commonjs-grouped/index.js +++ b/scripts/bin-test/sources/commonjs-grouped/index.js @@ -38,10 +38,9 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", }); -exports.extLocal2 = extLocal2; exports.g1 = require("./g1"); diff --git a/scripts/bin-test/sources/commonjs-main/functions.js b/scripts/bin-test/sources/commonjs-main/functions.js index 4994aca2f..031e109d7 100644 --- a/scripts/bin-test/sources/commonjs-main/functions.js +++ b/scripts/bin-test/sources/commonjs-main/functions.js @@ -37,8 +37,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", }); -exports.extLocal2 = extLocal2; diff --git a/scripts/bin-test/sources/commonjs-preserve/index.js b/scripts/bin-test/sources/commonjs-preserve/index.js index cacdd8e10..768fb6c4e 100644 --- a/scripts/bin-test/sources/commonjs-preserve/index.js +++ b/scripts/bin-test/sources/commonjs-preserve/index.js @@ -37,8 +37,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", -}); -exports.extLocal2 = extLocal2; \ No newline at end of file +}); \ No newline at end of file diff --git a/scripts/bin-test/sources/commonjs/index.js b/scripts/bin-test/sources/commonjs/index.js index 4994aca2f..031e109d7 100644 --- a/scripts/bin-test/sources/commonjs/index.js +++ b/scripts/bin-test/sources/commonjs/index.js @@ -37,8 +37,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", }); -exports.extLocal2 = extLocal2; diff --git a/spec/fixtures/sources/commonjs-grouped/index.js b/spec/fixtures/sources/commonjs-grouped/index.js index 15f04e2a0..06c976a71 100644 --- a/spec/fixtures/sources/commonjs-grouped/index.js +++ b/spec/fixtures/sources/commonjs-grouped/index.js @@ -38,10 +38,9 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", }); -exports.extLocal2 = extLocal2; exports.g1 = require("./g1"); diff --git a/spec/fixtures/sources/commonjs-main/functions.js b/spec/fixtures/sources/commonjs-main/functions.js index 6e29f9d16..b33e0cb71 100644 --- a/spec/fixtures/sources/commonjs-main/functions.js +++ b/spec/fixtures/sources/commonjs-main/functions.js @@ -37,8 +37,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", -}); -exports.extLocal2 = extLocal2; \ No newline at end of file +}); \ No newline at end of file diff --git a/spec/fixtures/sources/commonjs-parametrized-fields/index.js b/spec/fixtures/sources/commonjs-parametrized-fields/index.js index d153fc034..c6f37a309 100644 --- a/spec/fixtures/sources/commonjs-parametrized-fields/index.js +++ b/spec/fixtures/sources/commonjs-parametrized-fields/index.js @@ -1,7 +1,5 @@ const functions = require("../../../../src/v1/index"); const functionsv2 = require("../../../../src/v2/index"); -const firestoreTranslateText = require("../../extsdk/translate").firestoreTranslateText; -const backfill = require("../../extsdk/local").backfill; const params = require("../../../../src/params"); params.clearParams(); @@ -30,27 +28,3 @@ exports.v2http = functionsv2.https.onRequest({ }, (req, resp) => { resp.status(200).send("Hello world!"); }); - -// A Firebase extension by ref -const extRef1 = firestoreTranslateText("extRef1", { - "COLLECTION_PATH": "collection1", - "INPUT_FIELD_NAME": "input1", - "LANGUAGES": "de,es", - "OUTPUT_FIELD_NAME": "translated", - "_EVENT_ARC_REGION": "us-central1", - "_FUNCTION_LOCATION": "us-central1", -}); -exports.extRef1 = extRef1; - -// A Firebase function defined by extension event -const ttOnStart = extRef1.onStart((event) => { - console.log("onStart got event: " + JSON.stringify(event, null, 2)); -}); -exports.ttOnStart = ttOnStart; - -// A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { - DO_BACKFILL: "False", - LOCATION: "us-central1", -}); -exports.extLocal2 = extLocal2; diff --git a/spec/fixtures/sources/commonjs-params/index.js b/spec/fixtures/sources/commonjs-params/index.js index 4049a1478..76d07559c 100644 --- a/spec/fixtures/sources/commonjs-params/index.js +++ b/spec/fixtures/sources/commonjs-params/index.js @@ -61,8 +61,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", }); -exports.extLocal2 = extLocal2; diff --git a/spec/fixtures/sources/commonjs/index.js b/spec/fixtures/sources/commonjs/index.js index 6e29f9d16..b33e0cb71 100644 --- a/spec/fixtures/sources/commonjs/index.js +++ b/spec/fixtures/sources/commonjs/index.js @@ -37,8 +37,7 @@ const ttOnStart = extRef1.onStart((event) => { exports.ttOnStart = ttOnStart; // A Firebase extension by localPath -const extLocal2 = backfill("extLocal2", { +exports.extLocal2 = backfill("extLocal2", { DO_BACKFILL: "False", LOCATION: "us-central1", -}); -exports.extLocal2 = extLocal2; \ No newline at end of file +}); \ No newline at end of file diff --git a/spec/runtime/loader.spec.ts b/spec/runtime/loader.spec.ts index a3c8c559c..e67140c1b 100644 --- a/spec/runtime/loader.spec.ts +++ b/spec/runtime/loader.spec.ts @@ -437,6 +437,8 @@ describe("loadStack", () => { { name: "INT_PARAM", type: "int" }, { name: "BOOLEAN_PARAM", type: "boolean" }, ], + requiredAPIs: [], + extensions: {}, endpoints: { v1http: { ...MINIMAL_V1_ENDPOINT, @@ -463,19 +465,6 @@ describe("loadStack", () => { labels: {}, httpsTrigger: {}, }, - ttOnStart: { - ...MINIMAL_V2_ENDPOINT, - entryPoint: "ttOnStart", - eventTrigger: { - channel: "projects/locations/us-central1/channels/firebase", - eventFilters: {}, - eventType: "firebase.extensions.firestore-translate-text.v1.onStart", - retry: false, - }, - labels: {}, - platform: "gcfv2", - region: ["us-central1"], - }, }, }, },