Skip to content

Commit

Permalink
feat(aws-lambda): add streaming support to main preset (#2786)
Browse files Browse the repository at this point in the history
Co-authored-by: Pooya Parsa <[email protected]>
  • Loading branch information
thdxr and pi0 authored Oct 21, 2024
1 parent 8840d72 commit 9655ca6
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 45 deletions.
6 changes: 4 additions & 2 deletions src/presets/_types.gen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Auto-generated using gen-presets script

import type { PresetOptions as AwsAmplifyOptions } from "./aws-amplify/preset";
import type { PresetOptions as AwsLambdaOptions } from "./aws-lambda/preset";
import type { PresetOptions as AzureOptions } from "./azure/preset";
import type { PresetOptions as CloudflareOptions } from "./cloudflare/preset";
import type { PresetOptions as FirebaseOptions } from "./firebase/preset";
Expand All @@ -9,13 +10,14 @@ import type { PresetOptions as VercelOptions } from "./vercel/preset";

export interface PresetOptions {
awsAmplify: AwsAmplifyOptions;
awsLambda: AwsLambdaOptions;
azure: AzureOptions;
cloudflare: CloudflareOptions;
firebase: FirebaseOptions;
netlify: NetlifyOptions;
vercel: VercelOptions;
}

export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "aws-lambda-streaming" | "azure" | "azure-functions" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-module-legacy" | "cloudflare-pages" | "cloudflare-pages-static" | "cloudflare-worker" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "edgio" | "firebase" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis" | "iis-handler" | "iis-node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlify-edge" | "netlify-legacy" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-listener" | "node-server" | "platform-sh" | "render-com" | "service-worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";
export type PresetName = "alwaysdata" | "aws-amplify" | "aws-lambda" | "azure" | "azure-functions" | "azure-swa" | "base-worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflare-module" | "cloudflare-module-legacy" | "cloudflare-pages" | "cloudflare-pages-static" | "cloudflare-worker" | "deno" | "deno-deploy" | "deno-server" | "digital-ocean" | "edgio" | "firebase" | "flight-control" | "genezio" | "github-pages" | "gitlab-pages" | "heroku" | "iis" | "iis-handler" | "iis-node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlify-edge" | "netlify-legacy" | "netlify-static" | "nitro-dev" | "nitro-prerender" | "node" | "node-cluster" | "node-listener" | "node-server" | "platform-sh" | "render-com" | "service-worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercel-static" | "winterjs" | "zeabur" | "zeabur-static" | "zerops" | "zerops-static";

export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "aws-lambda-streaming" | "awsLambdaStreaming" | "aws_lambda_streaming" | "azure" | "azure-functions" | "azureFunctions" | "azure_functions" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-module-legacy" | "cloudflareModuleLegacy" | "cloudflare_module_legacy" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "cloudflare-worker" | "cloudflareWorker" | "cloudflare_worker" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "edgio" | "firebase" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlifyBuilder" | "netlify_builder" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-legacy" | "netlifyLegacy" | "netlify_legacy" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-listener" | "nodeListener" | "node_listener" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "service-worker" | "serviceWorker" | "service_worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercelEdge" | "vercel_edge" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
export type PresetNameInput = "alwaysdata" | "aws-amplify" | "awsAmplify" | "aws_amplify" | "aws-lambda" | "awsLambda" | "aws_lambda" | "azure" | "azure-functions" | "azureFunctions" | "azure_functions" | "azure-swa" | "azureSwa" | "azure_swa" | "base-worker" | "baseWorker" | "base_worker" | "bun" | "cleavr" | "cli" | "cloudflare" | "cloudflare-durable" | "cloudflareDurable" | "cloudflare_durable" | "cloudflare-module" | "cloudflareModule" | "cloudflare_module" | "cloudflare-module-legacy" | "cloudflareModuleLegacy" | "cloudflare_module_legacy" | "cloudflare-pages" | "cloudflarePages" | "cloudflare_pages" | "cloudflare-pages-static" | "cloudflarePagesStatic" | "cloudflare_pages_static" | "cloudflare-worker" | "cloudflareWorker" | "cloudflare_worker" | "deno" | "deno-deploy" | "denoDeploy" | "deno_deploy" | "deno-server" | "denoServer" | "deno_server" | "digital-ocean" | "digitalOcean" | "digital_ocean" | "edgio" | "firebase" | "flight-control" | "flightControl" | "flight_control" | "genezio" | "github-pages" | "githubPages" | "github_pages" | "gitlab-pages" | "gitlabPages" | "gitlab_pages" | "heroku" | "iis" | "iis-handler" | "iisHandler" | "iis_handler" | "iis-node" | "iisNode" | "iis_node" | "koyeb" | "layer0" | "netlify" | "netlify-builder" | "netlifyBuilder" | "netlify_builder" | "netlify-edge" | "netlifyEdge" | "netlify_edge" | "netlify-legacy" | "netlifyLegacy" | "netlify_legacy" | "netlify-static" | "netlifyStatic" | "netlify_static" | "nitro-dev" | "nitroDev" | "nitro_dev" | "nitro-prerender" | "nitroPrerender" | "nitro_prerender" | "node" | "node-cluster" | "nodeCluster" | "node_cluster" | "node-listener" | "nodeListener" | "node_listener" | "node-server" | "nodeServer" | "node_server" | "platform-sh" | "platformSh" | "platform_sh" | "render-com" | "renderCom" | "render_com" | "service-worker" | "serviceWorker" | "service_worker" | "static" | "stormkit" | "vercel" | "vercel-edge" | "vercelEdge" | "vercel_edge" | "vercel-static" | "vercelStatic" | "vercel_static" | "winterjs" | "zeabur" | "zeabur-static" | "zeaburStatic" | "zeabur_static" | "zerops" | "zerops-static" | "zeropsStatic" | "zerops_static" | (string & {});
24 changes: 12 additions & 12 deletions src/presets/aws-lambda/preset.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { defineNitroPreset } from "nitropack/kit";
export type { AwsLambdaOptions as PresetOptions } from "./types";

const awsLambda = defineNitroPreset(
{
entry: "./runtime/aws-lambda",
awsLambda: {
streaming: false,
},
hooks: {
"rollup:before": (nitro, rollupConfig) => {
if (nitro.options.awsLambda.streaming) {
(rollupConfig.input as string) += "-streaming";
}
},
},
},
{
name: "aws-lambda" as const,
url: import.meta.url,
}
);

const awsLambdaStreaming = defineNitroPreset(
{
extends: "aws-lambda",
entry: "./runtime/aws-lambda-streaming",
},
{
name: "aws-lambda-streaming" as const,
url: import.meta.url,
}
);

export default [awsLambda, awsLambdaStreaming] as const;
export default [awsLambda] as const;
68 changes: 37 additions & 31 deletions src/presets/aws-lambda/runtime/aws-lambda-streaming.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Readable } from "node:stream";
import type {
APIGatewayProxyEventV2,
APIGatewayProxyStructuredResultV2,
Expand All @@ -11,31 +12,6 @@ import {
} from "nitropack/runtime/internal";
import { withQuery } from "ufo";

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace awslambda {
// https://docs.aws.amazon.com/lambda/latest/dg/configuration-response-streaming.html
function streamifyResponse(
handler: (
event: APIGatewayProxyEventV2,
responseStream: NodeJS.WritableStream,
context: Context
) => Promise<void>
): any;

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace HttpResponseStream {
function from(
stream: NodeJS.WritableStream,
metadata: {
statusCode: APIGatewayProxyStructuredResultV2["statusCode"];
headers: APIGatewayProxyStructuredResultV2["headers"];
}
): NodeJS.WritableStream;
}
}
}

const nitroApp = useNitroApp();

export const handler = awslambda.streamifyResponse(
Expand Down Expand Up @@ -72,25 +48,55 @@ export const handler = awslambda.streamifyResponse(
},
};
if (r.body) {
const reader = r.body as ReadableStream;
const writer = awslambda.HttpResponseStream.from(
responseStream,
httpResponseMetadata
);
await streamToNodeStream(reader.getReader(), responseStream);
if (!(r.body as ReadableStream).getReader) {
writer.write(r.body as any /* TODO */);
writer.end();
return;
}
const reader = (r.body as ReadableStream).getReader();
await streamToNodeStream(reader, responseStream);
writer.end();
}
}
);

const streamToNodeStream = async (
reader: ReadableStreamDefaultReader<Uint8Array>,
async function streamToNodeStream(
reader: Readable | ReadableStreamDefaultReader,
writer: NodeJS.WritableStream
) => {
) {
let readResult = await reader.read();
while (!readResult.done) {
writer.write(readResult.value);
readResult = await reader.read();
}
writer.end();
};
}

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace awslambda {
// https://docs.aws.amazon.com/lambda/latest/dg/configuration-response-streaming.html
function streamifyResponse(
handler: (
event: APIGatewayProxyEventV2,
responseStream: NodeJS.WritableStream,
context: Context
) => Promise<void>
): any;

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace HttpResponseStream {
function from(
stream: NodeJS.WritableStream,
metadata: {
statusCode: APIGatewayProxyStructuredResultV2["statusCode"];
headers: APIGatewayProxyStructuredResultV2["headers"];
}
): NodeJS.WritableStream;
}
}
}
3 changes: 3 additions & 0 deletions src/presets/aws-lambda/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface AwsLambdaOptions {
streaming?: boolean;
}

0 comments on commit 9655ca6

Please sign in to comment.