firebase-functions
Version:
Firebase SDK for Cloud Functions
211 lines (209 loc) • 6.94 kB
JavaScript
import { __export } from "../../_virtual/rolldown_runtime.mjs";
import { initV2Endpoint } from "../../runtime/manifest.mjs";
import { convertIfPresent, convertInvoker } from "../../common/encoding.mjs";
import { withInit } from "../../common/onInit.mjs";
import { withErrorHandler } from "../../common/providers/https.mjs";
import { normalizePath } from "../../common/utilities/path.mjs";
import { wrapTraceContext } from "../trace.mjs";
import { getGlobalOptions, optionsToEndpoint } from "../options.mjs";
import { PathPattern } from "../../common/utilities/path-pattern.mjs";
import express from "express";
import fs from "fs";
//#region src/v2/providers/dataconnect.ts
var dataconnect_exports = /* @__PURE__ */ __export({
initGraphqlServer: () => initGraphqlServer,
mutationExecutedEventType: () => mutationExecutedEventType,
onGraphRequest: () => onGraphRequest,
onMutationExecuted: () => onMutationExecuted
});
/** @internal */
const mutationExecutedEventType = "google.firebase.dataconnect.connector.v1.mutationExecuted";
/**
* Event handler that triggers when a mutation is executed in Firebase Data Connect.
*
* @param mutationOrOpts - Options or string mutation path.
* @param handler - Event handler which is run every time a mutation is executed.
*/
function onMutationExecuted(mutationOrOpts, handler) {
return onOperation(mutationExecutedEventType, mutationOrOpts, handler);
}
function getOpts(mutationOrOpts) {
const operationRegex = new RegExp("services/([^/]+)/connectors/([^/]*)/operations/([^/]+)");
let service;
let connector;
let operation;
let opts;
if (typeof mutationOrOpts === "string") {
const path = normalizePath(mutationOrOpts);
const match = path.match(operationRegex);
if (!match) {
throw new Error(`Invalid operation path: ${path}`);
}
service = match[1];
connector = match[2];
operation = match[3];
opts = {};
} else {
service = mutationOrOpts.service;
connector = mutationOrOpts.connector;
operation = mutationOrOpts.operation;
opts = { ...mutationOrOpts };
delete opts.service;
delete opts.connector;
delete opts.operation;
}
return {
service,
connector,
operation,
opts
};
}
function makeEndpoint(eventType, opts, service, connector, operation) {
const baseOpts = optionsToEndpoint(getGlobalOptions());
const specificOpts = optionsToEndpoint(opts);
const eventFilters = {};
const eventFilterPathPatterns = {};
if (service) {
if (service.hasWildcards()) {
eventFilterPathPatterns.service = service.getValue();
} else {
eventFilters.service = service.getValue();
}
}
if (connector) {
if (connector.hasWildcards()) {
eventFilterPathPatterns.connector = connector.getValue();
} else {
eventFilters.connector = connector.getValue();
}
}
if (operation) {
if (operation.hasWildcards()) {
eventFilterPathPatterns.operation = operation.getValue();
} else {
eventFilters.operation = operation.getValue();
}
}
return {
...initV2Endpoint(getGlobalOptions(), opts),
platform: "gcfv2",
...baseOpts,
...specificOpts,
labels: {
...baseOpts?.labels,
...specificOpts?.labels
},
eventTrigger: {
eventType,
eventFilters,
eventFilterPathPatterns,
retry: opts.retry ?? false
}
};
}
function makeParams(event, service, connector, operation) {
return {
...service?.extractMatches(event.service),
...connector?.extractMatches(event.connector),
...operation?.extractMatches(event.operation)
};
}
function onOperation(eventType, mutationOrOpts, handler) {
const { service, connector, operation, opts } = getOpts(mutationOrOpts);
const servicePattern = service ? new PathPattern(service) : undefined;
const connectorPattern = connector ? new PathPattern(connector) : undefined;
const operationPattern = operation ? new PathPattern(operation) : undefined;
const func = (raw) => {
const event = raw;
const params = makeParams(event, servicePattern, connectorPattern, operationPattern);
const { authtype, authid, service: service$1, connector: connector$1, operation: operation$1,...rest } = event;
const dataConnectEvent = {
...rest,
authType: authtype,
authId: authid,
params
};
return wrapTraceContext(withInit(handler))(dataConnectEvent);
};
func.run = handler;
func.__endpoint = makeEndpoint(eventType, opts, servicePattern, connectorPattern, operationPattern);
return func;
}
/** @hidden */
async function initGraphqlServer(opts) {
if (!opts.schema && !opts.schemaFilePath || opts.schema && opts.schemaFilePath) {
throw new Error("Exactly one of 'schema' or 'schemaFilePath' must be provided.");
}
if (opts.schemaFilePath) {
opts.schema = fs.readFileSync(opts.schemaFilePath, "utf-8");
}
if (!opts.resolvers.query && !opts.resolvers.mutation) {
throw new Error("At least one query or mutation resolver must be provided.");
}
const apolloResolvers = {};
if (opts.resolvers.query) {
apolloResolvers.Query = opts.resolvers.query;
}
if (opts.resolvers.mutation) {
apolloResolvers.Mutation = opts.resolvers.mutation;
}
try {
const { ApolloServer } = await import("@apollo/server");
const { expressMiddleware } = await import("@as-integrations/express4");
const serverPromise$1 = (async () => {
const app = express();
const server = new ApolloServer({
typeDefs: opts.schema,
resolvers: apolloResolvers
});
await server.start();
app.use(`/${opts.path ?? "graphql"}`, express.json(), expressMiddleware(server));
return app;
})();
return serverPromise$1;
} catch (e) {
if (e instanceof Error) {
throw new Error("Error initializing GraphQL server: " + e.message);
} else {
throw e;
}
}
}
let serverPromise = null;
/**
* @hidden
* Handles HTTPS GraphQL requests.
* @param {GraphqlServerOptions} opts - Options for configuring the GraphQL server.
* @returns {HttpsFunction} A function you can export and deploy.
*/
function onGraphRequest(opts) {
const handler = wrapTraceContext(withInit(withErrorHandler(async (req, res) => {
serverPromise = serverPromise ?? initGraphqlServer(opts);
const app = await serverPromise;
app(req, res);
})));
const globalOpts = getGlobalOptions();
const baseOpts = optionsToEndpoint(globalOpts);
const specificOpts = optionsToEndpoint(opts);
const endpoint = {
...initV2Endpoint(globalOpts, opts),
platform: "gcfv2",
...baseOpts,
...specificOpts,
labels: {
...baseOpts?.labels,
...specificOpts?.labels
},
dataConnectGraphqlTrigger: {}
};
convertIfPresent(endpoint.dataConnectGraphqlTrigger, globalOpts, "invoker", "invoker", convertInvoker);
convertIfPresent(endpoint.dataConnectGraphqlTrigger, opts, "invoker", "invoker", convertInvoker);
if (opts.schemaFilePath) {
endpoint.dataConnectGraphqlTrigger.schemaFilePath = opts.schemaFilePath;
}
handler.__endpoint = endpoint;
return handler;
}
//#endregion
export { dataconnect_exports, initGraphqlServer, mutationExecutedEventType, onGraphRequest, onMutationExecuted };