context.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.clearModuleContext = clearModuleContext;
  6. exports.getModuleContext = getModuleContext;
  7. var _middleware = require("next/dist/compiled/@next/react-dev-overlay/dist/middleware");
  8. var _constants = require("../../../shared/lib/constants");
  9. var _edgeRuntime = require("next/dist/compiled/edge-runtime");
  10. var _fs = require("fs");
  11. var _utils = require("../utils");
  12. var _pick = require("../../../lib/pick");
  13. var _fetchInlineAssets = require("./fetch-inline-assets");
  14. const WEBPACK_HASH_REGEX = /__webpack_require__\.h = function\(\) \{ return "[0-9a-f]+"; \}/g;
  15. /**
  16. * A Map of cached module contexts indexed by the module name. It allows
  17. * to have a different cache scoped per module name or depending on the
  18. * provided module key on creation.
  19. */ const moduleContexts = new Map();
  20. function clearModuleContext(path, content) {
  21. for (const [key, cache] of moduleContexts){
  22. var ref;
  23. const prev = (ref = cache == null ? void 0 : cache.paths.get(path)) == null ? void 0 : ref.replace(WEBPACK_HASH_REGEX, "");
  24. if (typeof prev !== "undefined" && prev !== content.toString().replace(WEBPACK_HASH_REGEX, "")) {
  25. moduleContexts.delete(key);
  26. }
  27. }
  28. }
  29. async function loadWasm(wasm) {
  30. const modules = {};
  31. await Promise.all(wasm.map(async (binding)=>{
  32. const module = await WebAssembly.compile(await _fs.promises.readFile(binding.filePath));
  33. modules[binding.name] = module;
  34. }));
  35. return modules;
  36. }
  37. function buildEnvironmentVariablesFrom(keys) {
  38. const pairs = keys.map((key)=>[
  39. key,
  40. process.env[key]
  41. ]);
  42. const env = Object.fromEntries(pairs);
  43. env.NEXT_RUNTIME = "edge";
  44. return env;
  45. }
  46. function throwUnsupportedAPIError(name) {
  47. const error = new Error(`A Node.js API is used (${name}) which is not supported in the Edge Runtime.
  48. Learn more: https://nextjs.org/docs/api-reference/edge-runtime`);
  49. (0, _middleware).decorateServerError(error, _constants.COMPILER_NAMES.edgeServer);
  50. throw error;
  51. }
  52. function createProcessPolyfill(options) {
  53. const env = buildEnvironmentVariablesFrom(options.env);
  54. const processPolyfill = {
  55. env
  56. };
  57. const overridenValue = {};
  58. for (const key of Object.keys(process)){
  59. if (key === "env") continue;
  60. Object.defineProperty(processPolyfill, key, {
  61. get () {
  62. if (overridenValue[key]) {
  63. return overridenValue[key];
  64. }
  65. if (typeof process[key] === "function") {
  66. return ()=>throwUnsupportedAPIError(`process.${key}`);
  67. }
  68. return undefined;
  69. },
  70. set (value) {
  71. overridenValue[key] = value;
  72. },
  73. enumerable: false
  74. });
  75. }
  76. return processPolyfill;
  77. }
  78. function addStub(context, name) {
  79. Object.defineProperty(context, name, {
  80. get () {
  81. return function() {
  82. throwUnsupportedAPIError(name);
  83. };
  84. },
  85. enumerable: false
  86. });
  87. }
  88. function getDecorateUnhandledError(runtime) {
  89. const EdgeRuntimeError = runtime.evaluate(`Error`);
  90. return (error)=>{
  91. if (error instanceof EdgeRuntimeError) {
  92. (0, _middleware).decorateServerError(error, _constants.COMPILER_NAMES.edgeServer);
  93. }
  94. };
  95. }
  96. /**
  97. * Create a module cache specific for the provided parameters. It includes
  98. * a runtime context, require cache and paths cache.
  99. */ async function createModuleContext(options) {
  100. const warnedEvals = new Set();
  101. const warnedWasmCodegens = new Set();
  102. var _wasm;
  103. const wasm = await loadWasm((_wasm = options.edgeFunctionEntry.wasm) != null ? _wasm : []);
  104. const runtime = new _edgeRuntime.EdgeRuntime({
  105. codeGeneration: process.env.NODE_ENV !== "production" ? {
  106. strings: true,
  107. wasm: true
  108. } : undefined,
  109. extend: (context)=>{
  110. context.process = createProcessPolyfill(options);
  111. context.__next_eval__ = function __next_eval__(fn) {
  112. const key = fn.toString();
  113. if (!warnedEvals.has(key)) {
  114. const warning = (0, _middleware).getServerError(new Error(`Dynamic Code Evaluation (e. g. 'eval', 'new Function') not allowed in Edge Runtime
  115. Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), _constants.COMPILER_NAMES.edgeServer);
  116. warning.name = "DynamicCodeEvaluationWarning";
  117. Error.captureStackTrace(warning, __next_eval__);
  118. warnedEvals.add(key);
  119. options.onWarning(warning);
  120. }
  121. return fn();
  122. };
  123. context.__next_webassembly_compile__ = function __next_webassembly_compile__(fn) {
  124. const key = fn.toString();
  125. if (!warnedWasmCodegens.has(key)) {
  126. const warning = (0, _middleware).getServerError(new Error(`Dynamic WASM code generation (e. g. 'WebAssembly.compile') not allowed in Edge Runtime.
  127. Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), _constants.COMPILER_NAMES.edgeServer);
  128. warning.name = "DynamicWasmCodeGenerationWarning";
  129. Error.captureStackTrace(warning, __next_webassembly_compile__);
  130. warnedWasmCodegens.add(key);
  131. options.onWarning(warning);
  132. }
  133. return fn();
  134. };
  135. context.__next_webassembly_instantiate__ = async function __next_webassembly_instantiate__(fn) {
  136. const result = await fn();
  137. // If a buffer is given, WebAssembly.instantiate returns an object
  138. // containing both a module and an instance while it returns only an
  139. // instance if a WASM module is given. Utilize the fact to determine
  140. // if the WASM code generation happens.
  141. //
  142. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate#primary_overload_%E2%80%94_taking_wasm_binary_code
  143. const instantiatedFromBuffer = result.hasOwnProperty("module");
  144. const key = fn.toString();
  145. if (instantiatedFromBuffer && !warnedWasmCodegens.has(key)) {
  146. const warning = (0, _middleware).getServerError(new Error(`Dynamic WASM code generation ('WebAssembly.instantiate' with a buffer parameter) not allowed in Edge Runtime.
  147. Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), _constants.COMPILER_NAMES.edgeServer);
  148. warning.name = "DynamicWasmCodeGenerationWarning";
  149. Error.captureStackTrace(warning, __next_webassembly_instantiate__);
  150. warnedWasmCodegens.add(key);
  151. options.onWarning(warning);
  152. }
  153. return result;
  154. };
  155. const __fetch = context.fetch;
  156. context.fetch = async (input, init = {})=>{
  157. var ref;
  158. const assetResponse = await (0, _fetchInlineAssets).fetchInlineAsset({
  159. input,
  160. assets: options.edgeFunctionEntry.assets,
  161. distDir: options.distDir,
  162. context
  163. });
  164. if (assetResponse) {
  165. return assetResponse;
  166. }
  167. var _headers;
  168. init.headers = new Headers((_headers = init.headers) != null ? _headers : {});
  169. const prevs = ((ref = init.headers.get(`x-middleware-subrequest`)) == null ? void 0 : ref.split(":")) || [];
  170. const value = prevs.concat(options.moduleName).join(":");
  171. init.headers.set("x-middleware-subrequest", value);
  172. if (!init.headers.has("user-agent")) {
  173. init.headers.set(`user-agent`, `Next.js Middleware`);
  174. }
  175. if (typeof input === "object" && "url" in input) {
  176. return __fetch(input.url, {
  177. ...(0, _pick).pick(input, [
  178. "method",
  179. "body",
  180. "cache",
  181. "credentials",
  182. "integrity",
  183. "keepalive",
  184. "mode",
  185. "redirect",
  186. "referrer",
  187. "referrerPolicy",
  188. "signal",
  189. ]),
  190. ...init,
  191. headers: {
  192. ...Object.fromEntries(input.headers),
  193. ...Object.fromEntries(init.headers)
  194. }
  195. });
  196. }
  197. return __fetch(String(input), init);
  198. };
  199. const __Request = context.Request;
  200. context.Request = class extends __Request {
  201. constructor(input, init){
  202. const url = typeof input !== "string" && "url" in input ? input.url : String(input);
  203. (0, _utils).validateURL(url);
  204. super(url, init);
  205. }
  206. };
  207. const __redirect = context.Response.redirect.bind(context.Response);
  208. context.Response.redirect = (...args)=>{
  209. (0, _utils).validateURL(args[0]);
  210. return __redirect(...args);
  211. };
  212. for (const name of _constants.EDGE_UNSUPPORTED_NODE_APIS){
  213. addStub(context, name);
  214. }
  215. Object.assign(context, wasm);
  216. return context;
  217. }
  218. });
  219. const decorateUnhandledError = getDecorateUnhandledError(runtime);
  220. runtime.context.addEventListener("unhandledrejection", decorateUnhandledError);
  221. runtime.context.addEventListener("error", decorateUnhandledError);
  222. return {
  223. runtime,
  224. paths: new Map(),
  225. warnedEvals: new Set()
  226. };
  227. }
  228. const pendingModuleCaches = new Map();
  229. function getModuleContextShared(options) {
  230. let deferredModuleContext = pendingModuleCaches.get(options.moduleName);
  231. if (!deferredModuleContext) {
  232. deferredModuleContext = createModuleContext(options);
  233. pendingModuleCaches.set(options.moduleName, deferredModuleContext);
  234. }
  235. return deferredModuleContext;
  236. }
  237. async function getModuleContext(options) {
  238. let moduleContext = options.useCache ? moduleContexts.get(options.moduleName) : await getModuleContextShared(options);
  239. if (!moduleContext) {
  240. moduleContext = await createModuleContext(options);
  241. moduleContexts.set(options.moduleName, moduleContext);
  242. }
  243. const evaluateInContext = (filepath)=>{
  244. if (!moduleContext.paths.has(filepath)) {
  245. const content = (0, _fs).readFileSync(filepath, "utf-8");
  246. try {
  247. moduleContext == null ? void 0 : moduleContext.runtime.evaluate(content);
  248. moduleContext.paths.set(filepath, content);
  249. } catch (error) {
  250. if (options.useCache) {
  251. moduleContext == null ? void 0 : moduleContext.paths.delete(options.moduleName);
  252. }
  253. throw error;
  254. }
  255. }
  256. };
  257. return {
  258. ...moduleContext,
  259. evaluateInContext
  260. };
  261. }
  262. //# sourceMappingURL=context.js.map