UNPKG

@rivetkit/next-js

Version:

Next.js integration for RivetKit actors and client

160 lines (156 loc) 5.15 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/mod.ts var _fs = require('fs'); var _path = require('path'); var _utils = require('rivetkit/utils'); // src/log.ts var _log = require('rivetkit/log'); function logger() { return _log.getLogger.call(void 0, "driver-next-js"); } // src/mod.ts var toNextHandler = (registry, inputConfig = {}) => { inputConfig.disableDefaultServer = true; inputConfig.runnerKind = "serverless"; if (process.env.NODE_ENV !== "production") { logger().debug( "detected development environment, auto-starting engine and auto-configuring serverless" ); const publicUrl = _nullishCoalesce(_nullishCoalesce(process.env.NEXT_PUBLIC_SITE_URL, () => ( process.env.NEXT_PUBLIC_VERCEL_URL)), () => ( `http://127.0.0.1:${_nullishCoalesce(process.env.PORT, () => ( 3e3))}`)); inputConfig.runEngine = true; inputConfig.autoConfigureServerless = { url: `${publicUrl}/api/rivet`, minRunners: 0, maxRunners: 1e5, requestLifespan: 300, slotsPerRunner: 1, metadata: { provider: "next-js" } }; } else { logger().debug( "detected production environment, will not auto-start engine and auto-configure serverless" ); } inputConfig.noWelcome = true; const { fetch } = registry.start(inputConfig); const fetchWrapper = async (request, { params }) => { const { all } = await params; const newUrl = new URL(request.url); newUrl.pathname = all.join("/"); if (process.env.NODE_ENV !== "development") { const newReq = new Request(newUrl, request); return await fetch(newReq); } else { return await handleRequestWithFileWatcher(request, newUrl, fetch); } }; return { GET: fetchWrapper, POST: fetchWrapper, PUT: fetchWrapper, PATCH: fetchWrapper, HEAD: fetchWrapper, OPTIONS: fetchWrapper }; }; async function handleRequestWithFileWatcher(request, newUrl, fetch) { var _a; const mergedController = new AbortController(); const abortMerged = () => mergedController.abort(); (_a = request.signal) == null ? void 0 : _a.addEventListener("abort", abortMerged); const watchIntervalId = watchRouteFile(mergedController); request.signal.addEventListener("abort", () => { logger().debug("clearing file watcher interval: request aborted"); clearInterval(watchIntervalId); }); const newReq = new Request(newUrl, { // Copy old request properties method: request.method, headers: request.headers, body: request.body, credentials: request.credentials, cache: request.cache, redirect: request.redirect, referrer: request.referrer, integrity: request.integrity, // Override with new signal signal: mergedController.signal, // Required for streaming body duplex: "half" }); const response = await fetch(newReq); if (response.body) { const wrappedStream = waitForStreamFinish(response.body, () => { logger().debug("clearing file watcher interval: stream finished"); clearInterval(watchIntervalId); }); return new Response(wrappedStream, { status: response.status, statusText: response.statusText, headers: response.headers }); } else { logger().debug("clearing file watcher interval: no response body"); clearInterval(watchIntervalId); return response; } } function watchRouteFile(abortController) { logger().debug("starting file watcher"); const routePath = _path.join.call(void 0, process.cwd(), ".next/server/app/api/rivet/[...all]/route.js" ); let lastMtime = null; const checkFile = () => { logger().debug({ msg: "checking for file changes", routePath }); try { if (!_fs.existsSync.call(void 0, routePath)) { return; } const stats = _fs.statSync.call(void 0, routePath); const mtime = stats.mtimeMs; if (lastMtime !== null && mtime !== lastMtime) { logger().info({ msg: "route file changed", routePath }); abortController.abort(); } lastMtime = mtime; } catch (err) { logger().info({ msg: "failed to check for route file change", err: _utils.stringifyError.call(void 0, err) }); } }; checkFile(); return setInterval(checkFile, 1e3); } function waitForStreamFinish(body, onFinish) { const reader = body.getReader(); return new ReadableStream({ async start(controller) { try { while (true) { const { done, value } = await reader.read(); if (done) { logger().debug("stream completed"); onFinish(); controller.close(); break; } controller.enqueue(value); } } catch (err) { logger().debug("stream errored"); onFinish(); controller.error(err); } }, cancel() { logger().debug("stream cancelled"); onFinish(); reader.cancel(); } }); } exports.toNextHandler = toNextHandler; //# sourceMappingURL=mod.js.map