UNPKG

genkitx-azure-openai

Version:
431 lines (428 loc) 12.8 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var azure_functions_exports = {}; __export(azure_functions_exports, { allOf: () => allOf, allowAll: () => allowAll, anyOf: () => anyOf, default: () => azure_functions_default, onCallGenkit: () => onCallGenkit, requireApiKey: () => requireApiKey, requireBearerToken: () => requireBearerToken, requireHeader: () => requireHeader }); module.exports = __toCommonJS(azure_functions_exports); var import_functions = require("@azure/functions"); var import_genkit = require("genkit"); var import_context = require("genkit/context"); function buildCorsHeaders(corsOptions, requestOrigin) { if (corsOptions === false) { return {}; } const opts = corsOptions === true || corsOptions === void 0 ? {} : corsOptions; const headers = { "Content-Type": "application/json" }; const origin = opts.origin ?? "*"; if (Array.isArray(origin)) { if (requestOrigin && origin.includes(requestOrigin)) { headers["Access-Control-Allow-Origin"] = requestOrigin; } } else { headers["Access-Control-Allow-Origin"] = origin; } const methods = opts.methods ?? ["POST", "OPTIONS"]; headers["Access-Control-Allow-Methods"] = methods.join(", "); const allowedHeaders = opts.allowedHeaders ?? [ "Content-Type", "Authorization" ]; headers["Access-Control-Allow-Headers"] = allowedHeaders.join(", "); if (opts.exposedHeaders && opts.exposedHeaders.length > 0) { headers["Access-Control-Expose-Headers"] = opts.exposedHeaders.join(", "); } if (opts.credentials) { headers["Access-Control-Allow-Credentials"] = "true"; } const maxAge = opts.maxAge ?? 86400; headers["Access-Control-Max-Age"] = String(maxAge); return headers; } async function parseRequestBody(request) { let bodyText; try { bodyText = await request.text(); } catch { return {}; } if (!bodyText) { return {}; } try { const parsed = JSON.parse(bodyText); if (parsed && typeof parsed === "object" && "data" in parsed) { return parsed.data; } return parsed; } catch { throw new import_genkit.UserFacingError( "INVALID_ARGUMENT", "Invalid JSON in request body" ); } } function getRequestOrigin(request) { return request.headers.get("origin") || void 0; } function normalizeHeaders(request) { const result = {}; request.headers.forEach((value, key) => { result[key.toLowerCase()] = value; }); return result; } function getQueryParams(request) { const result = {}; const url = new URL(request.url); url.searchParams.forEach((value, key) => { result[key] = value; }); return result; } function toRequestData(request, input) { return { method: request.method, headers: normalizeHeaders(request), input }; } function onCallGenkit(optsOrFlow, flowArg) { let opts; let flow; if (arguments.length === 1) { opts = {}; flow = optsOrFlow; } else { opts = optsOrFlow; flow = flowArg; } const flowName = flow.__action?.name || "unknown"; function buildAzureFunctionsContext(request, azureContext) { return { azureFunctions: { request: { url: request.url, headers: normalizeHeaders(request), query: getQueryParams(request), params: request.params }, context: { functionName: azureContext.functionName, invocationId: azureContext.invocationId } } }; } async function resolveActionContext(request, azureContext, input) { const azureFunctionsContext = buildAzureFunctionsContext( request, azureContext ); if (opts.contextProvider) { const requestData = toRequestData(request, input); const providerContext = await opts.contextProvider(requestData); return { ...azureFunctionsContext, ...providerContext }; } return azureFunctionsContext; } async function buildErrorResponse(error, corsHeaders) { if (opts.onError) { const customError = await opts.onError( error instanceof Error ? error : new Error(String(error)) ); return { status: customError.statusCode, headers: corsHeaders, jsonBody: { error: { status: "INTERNAL", message: customError.message } } }; } return { status: (0, import_context.getHttpStatus)(error), headers: corsHeaders, jsonBody: (0, import_context.getCallableJSON)(error) }; } async function standardHandler(request, azureContext) { const requestOrigin = getRequestOrigin(request); const corsHeaders = buildCorsHeaders(opts.cors, requestOrigin); if (request.method === "OPTIONS") { return { status: 204, headers: corsHeaders }; } if (opts.debug) { azureContext.log( `[${flowName}] Request: ${request.method} ${request.url}` ); azureContext.log( `[${flowName}] Headers:`, JSON.stringify(normalizeHeaders(request), null, 2) ); } try { const input = await parseRequestBody(request); const actionContext = await resolveActionContext( request, azureContext, input ); if (opts.debug) { azureContext.log(`[${flowName}] Running flow with input:`, input); } const runResult = await flow.run(input, { context: actionContext }); const result = runResult.result; if (opts.debug) { azureContext.log(`[${flowName}] Flow completed successfully`); } return { status: 200, headers: corsHeaders, jsonBody: { result } }; } catch (error) { azureContext.error(`[${flowName}] Error:`, error); return buildErrorResponse(error, corsHeaders); } } async function streamingHandler(request, azureContext) { const requestOrigin = getRequestOrigin(request); const corsHeaders = buildCorsHeaders(opts.cors, requestOrigin); if (request.method === "OPTIONS") { return { status: 204, headers: corsHeaders }; } if (opts.debug) { azureContext.log( `[${flowName}] Stream request: ${request.method} ${request.url}` ); } try { const input = await parseRequestBody(request); const actionContext = await resolveActionContext( request, azureContext, input ); const acceptHeader = request.headers.get("accept") || ""; const clientWantsStreaming = acceptHeader.includes("text/event-stream"); if (clientWantsStreaming) { const encoder = new TextEncoder(); const readableStream = new ReadableStream({ async start(controller) { try { const { stream, output } = flow.stream(input, { context: actionContext }); for await (const chunk of stream) { const sseData = `data: ${JSON.stringify({ message: chunk })} `; controller.enqueue(encoder.encode(sseData)); } const result = await output; const sseFinal = `data: ${JSON.stringify({ result })} `; controller.enqueue(encoder.encode(sseFinal)); controller.close(); if (opts.debug) { azureContext.log( `[${flowName}] Streaming flow completed successfully` ); } } catch (error) { azureContext.error(`[${flowName}] Stream error:`, error); const errorData = `data: ${JSON.stringify((0, import_context.getCallableJSON)(error))} `; controller.enqueue(encoder.encode(errorData)); controller.close(); } } }); return { status: 200, headers: { ...corsHeaders, "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }, body: readableStream }; } else { const runResult = await flow.run(input, { context: actionContext }); const result = runResult.result; return { status: 200, headers: corsHeaders, jsonBody: { result } }; } } catch (error) { azureContext.error(`[${flowName}] Stream error:`, error); return buildErrorResponse(error, corsHeaders); } } const handler = opts.streaming ? streamingHandler : standardHandler; const callableFunction = { handler, flow, flowName, run: async (input, options) => { const runResult = await flow.run(input, { context: options?.context }); return runResult.result; }, stream: (input, options) => { return flow.stream(input, { context: options?.context }); } }; const methods = opts.httpMethods ?? ["POST", "OPTIONS"]; const authLevel = opts.authLevel ?? "anonymous"; import_functions.app.http(flowName, { methods, authLevel, ...opts.route ? { route: opts.route } : {}, handler }); return callableFunction; } function requireApiKey(headerName, expectedValueOrValidator) { const lowerHeaderName = headerName.toLowerCase(); return async (request) => { const apiKey = request.headers[lowerHeaderName]; if (!apiKey) { throw new import_genkit.UserFacingError( "UNAUTHENTICATED", `Missing required header: ${headerName}` ); } if (typeof expectedValueOrValidator === "string") { if (apiKey !== expectedValueOrValidator) { throw new import_genkit.UserFacingError("PERMISSION_DENIED", "Invalid API key"); } } else { await expectedValueOrValidator(apiKey); } return { auth: { apiKey } }; }; } function requireBearerToken(validateToken) { return async (request) => { const authHeader = request.headers["authorization"]; if (!authHeader) { throw new import_genkit.UserFacingError( "UNAUTHENTICATED", "Missing Authorization header" ); } const match = authHeader.match(/^Bearer\s+(.+)$/i); if (!match) { throw new import_genkit.UserFacingError( "UNAUTHENTICATED", "Invalid Authorization header format. Expected: Bearer <token>" ); } const token = match[1]; return await validateToken(token); }; } function requireHeader(headerName, expectedValue) { const lowerHeaderName = headerName.toLowerCase(); return async (request) => { const value = request.headers[lowerHeaderName]; if (!value) { throw new import_genkit.UserFacingError( "UNAUTHENTICATED", `Missing required header: ${headerName}` ); } if (expectedValue !== void 0 && value !== expectedValue) { throw new import_genkit.UserFacingError( "PERMISSION_DENIED", `Invalid value for header: ${headerName}` ); } return {}; }; } function allowAll() { return async () => ({}); } function allOf(...providers) { return async (request) => { let mergedContext = {}; for (const provider of providers) { const context = await provider(request); mergedContext = { ...mergedContext, ...context }; } return mergedContext; }; } function anyOf(...providers) { return async (request) => { let lastError; for (const provider of providers) { try { const context = await provider(request); return context; } catch (error) { lastError = error instanceof Error ? error : new Error(String(error)); } } throw lastError || new import_genkit.UserFacingError("UNAUTHENTICATED", "Unauthorized"); }; } var azure_functions_default = onCallGenkit; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { allOf, allowAll, anyOf, onCallGenkit, requireApiKey, requireBearerToken, requireHeader }); //# sourceMappingURL=azure_functions.js.map