UNPKG

@genkit-ai/next

Version:
1 lines 7.32 kB
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Copyright 2025 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { z, type Action, type ActionContext } from 'genkit';\nimport {\n getCallableJSON,\n getHttpStatus,\n type ContextProvider,\n type RequestData,\n} from 'genkit/context';\nimport { NextRequest, NextResponse } from 'next/server.js';\nexport { NextRequest, NextResponse, z, type Action, type ActionContext };\n\nconst delimiter = '\\n\\n';\nasync function getContext<C extends ActionContext, T>(\n request: NextRequest,\n input: T,\n provider: ContextProvider<C, T> | undefined\n): Promise<C> {\n // Type cast is necessary because there is no runtime way to generate a context if C is provided to appRoute\n // but contextProvider is missing. When I'm less sleepy/busy I'll see if I can make this a type error.\n const context = {} as C;\n if (!provider) {\n return context;\n }\n\n const r: RequestData = {\n method: request.method as RequestData['method'],\n headers: {},\n input,\n };\n request.headers.forEach((val, key) => {\n r.headers[key.toLowerCase()] = val;\n });\n return await provider(r);\n}\n\nfunction appRoute<\n C extends ActionContext = ActionContext,\n I extends z.ZodTypeAny = z.ZodTypeAny,\n O extends z.ZodTypeAny = z.ZodTypeAny,\n S extends z.ZodTypeAny = z.ZodTypeAny,\n>(\n action: Action<I, O, S>,\n opts?: {\n contextProvider?: ContextProvider<C, I>;\n }\n) {\n return async (req: NextRequest): Promise<NextResponse> => {\n let context: C = {} as C;\n const { data: input } = await req.json();\n if (req.headers.get('accept') !== 'text/event-stream') {\n try {\n context = await getContext(req, input, opts?.contextProvider);\n } catch (e) {\n console.error('Error gathering context for running action:', e);\n return NextResponse.json(\n { error: getCallableJSON(e) },\n { status: getHttpStatus(e) }\n );\n }\n try {\n const resp = await action.run(input, {\n context,\n abortSignal: req.signal,\n });\n return NextResponse.json({ result: resp.result });\n } catch (e) {\n // For security reasons, log the error rather than responding with it.\n console.error('Error calling action:', e);\n return NextResponse.json(\n { error: getCallableJSON(e) },\n { status: getHttpStatus(e) }\n );\n }\n }\n\n try {\n context = await getContext(req, input, opts?.contextProvider);\n } catch (e) {\n console.error('Error gathering context for streaming action:', e);\n return new NextResponse(\n `error: ${JSON.stringify(getCallableJSON(e))}${delimiter}END`,\n { status: getHttpStatus(e) }\n );\n }\n const { output, stream } = action.stream(input, {\n context,\n abortSignal: req.signal,\n });\n const encoder = new TextEncoder();\n const { readable, writable } = new TransformStream();\n\n // Not using a dangling promise causes this closure to block on the stream being drained,\n // which doesn't happen until the NextResponse is consumed later in the cosure.\n // TODO: Add ping comments at regular intervals between streaming responses to mitigate\n // timeouts.\n (async (): Promise<void> => {\n const writer = writable.getWriter();\n try {\n for await (const chunk of stream) {\n await writer.write(\n encoder.encode(\n `data: ${JSON.stringify({ message: chunk })}${delimiter}`\n )\n );\n }\n await writer.write(\n encoder.encode(\n `data: ${JSON.stringify({ result: await output })}${delimiter}`\n )\n );\n await writer.write(encoder.encode('END'));\n } catch (err) {\n console.error('Error streaming action:', err);\n await writer.write(\n encoder.encode(\n `error: ${JSON.stringify(getCallableJSON(err))}` + '\\n\\n'\n )\n );\n await writer.write(encoder.encode('END'));\n } finally {\n await writer.close();\n }\n })();\n\n return new NextResponse(readable, {\n status: 200,\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'Transfer-Encoding': 'chunked',\n },\n });\n };\n}\n\nexport default appRoute;\nexport { appRoute };\n"],"mappings":"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","names":[]}