"use strict";
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.stopAllServers = exports.getServer = void 0;
exports.expressApp = expressApp;
/**
 * @azure/functions-extensions-express — Express integration for Azure Functions.
 *
 * Runs Express as a real HTTP server inside the Functions worker.
 * Each Express route is automatically discovered and registered as
 * a separate Azure Function with full streaming and middleware support.
 *
 * @example
 * ```typescript
 * import express from 'express';
 * import { expressApp } from '@azure/functions-extensions-express';
 *
 * const app = express();
 * app.get('/items', (req, res) => res.json(items));
 * app.get('/items/:id', (req, res) => res.json(item));
 * expressApp('api', app);
 * ```
 */
const functions_1 = require("@azure/functions");
const routeExtractor_1 = require("./routeExtractor");
const server_1 = require("./server");
var server_2 = require("./server");
Object.defineProperty(exports, "getServer", { enumerable: true, get: function () { return server_2.getServer; } });
Object.defineProperty(exports, "stopAllServers", { enumerable: true, get: function () { return server_2.stopAllServers; } });
const NULL_BODY_CODES = new Set([204, 304]);
function createHandler(sidecar, opts) {
    return async (request, context) => {
        const url = new URL(request.url);
        let path = url.pathname + url.search;
        // Strip Azure Functions route prefix so Express sees its own paths
        if (opts.routePrefix && path.startsWith(opts.routePrefix)) {
            path = path.slice(opts.routePrefix.length) || '/';
            if (!path.startsWith('/'))
                path = '/' + path;
        }
        const headers = {};
        request.headers.forEach((v, k) => {
            headers[k] = v;
        });
        let body = null;
        if (request.body)
            body = Buffer.from(await request.arrayBuffer());
        const res = await sidecar.proxy(request.method, path, headers, body, context.invocationId);
        const noBody = NULL_BODY_CODES.has(res.status) || (res.status >= 100 && res.status < 200);
        return {
            status: res.status,
            headers: res.headers,
            body: noBody ? undefined : res.body ?? undefined,
        };
    };
}
/**
 * Register an Express app as Azure Functions.
 *
 * Discovers all routes and creates one Azure Function per route.
 * Falls back to a catch-all if no routes are found.
 */
function expressApp(name, expressApplication, options = {}) {
    const routePrefix = options.routePrefix ?? '';
    const opts = {
        port: options.port ?? 0,
        basePath: options.basePath ?? '',
        timeout: options.timeout ?? 30000,
        enableStreaming: options.enableStreaming ?? true,
        routePrefix: routePrefix ? '/' + routePrefix.replace(/^\//, '') : '',
    };
    const sidecar = (0, server_1.getOrCreateServer)(name, expressApplication, opts);
    const handler = createHandler(sidecar, opts);
    const routes = (0, routeExtractor_1.extractRoutes)(expressApplication, opts.basePath);
    if (routes.length === 0) {
        console.warn('[functions-express] No routes found, using catch-all.');
        functions_1.app.http(name, {
            route: options.route || '{*path}',
            methods: options.methods || ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'],
            authLevel: options.authLevel || 'anonymous',
            handler,
        });
    }
    else {
        console.log(`[functions-express] Discovered ${routes.length} route(s):`);
        for (const r of routes) {
            const fn = `${name}-${r.functionName}`;
            console.log(`  ${fn} -> [${r.methods.join(', ')}] /${r.azureFunctionsRoute}`);
            functions_1.app.http(fn, {
                route: r.azureFunctionsRoute,
                methods: r.methods,
                authLevel: options.authLevel || 'anonymous',
                handler,
            });
        }
    }
    return sidecar;
}
//# sourceMappingURL=index.js.map