loader-modules.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // // This loads all middlewares exposed on the middleware object
  2. // // and then starts the invocation chain.
  3. // // The big idea is that we can add these to the middleware export dynamically
  4. // // through wrangler, or we can potentially let users directly add them as a sort
  5. // // of "plugin" system.
  6. import {
  7. Dispatcher,
  8. Middleware,
  9. __facade_invoke__,
  10. __facade_register__,
  11. } from "./common";
  12. import worker from "__ENTRY_POINT__";
  13. // We need to preserve all of the exports from the worker
  14. export * from "__ENTRY_POINT__";
  15. class __Facade_ScheduledController__ implements ScheduledController {
  16. #noRetry: ScheduledController["noRetry"];
  17. constructor(
  18. readonly scheduledTime: number,
  19. readonly cron: string,
  20. noRetry: ScheduledController["noRetry"]
  21. ) {
  22. this.#noRetry = noRetry;
  23. }
  24. noRetry() {
  25. if (!(this instanceof __Facade_ScheduledController__)) {
  26. throw new TypeError("Illegal invocation");
  27. }
  28. // Need to call native method immediately in case uncaught error thrown
  29. this.#noRetry();
  30. }
  31. }
  32. const __facade_modules_fetch__: ExportedHandlerFetchHandler = function (
  33. request,
  34. env,
  35. ctx
  36. ) {
  37. if (worker.fetch === undefined)
  38. throw new Error("Handler does not export a fetch() function.");
  39. return worker.fetch(request, env, ctx);
  40. };
  41. function getMaskedEnv(rawEnv: unknown) {
  42. let env = rawEnv as Record<string, unknown>;
  43. if (worker.envWrappers && worker.envWrappers.length > 0) {
  44. for (const wrapFn of worker.envWrappers) {
  45. env = wrapFn(env);
  46. }
  47. }
  48. return env;
  49. }
  50. /**
  51. * This type is here to cause a type error if a new export handler is added to
  52. * `ExportHandler` without it being included in the `facade` below.
  53. */
  54. type MissingExportHandlers = Omit<
  55. Required<ExportedHandler>,
  56. "tail" | "trace" | "scheduled" | "queue" | "test" | "email" | "fetch"
  57. >;
  58. let registeredMiddleware = false;
  59. const facade: ExportedHandler<unknown> & MissingExportHandlers = {
  60. ...(worker.tail && {
  61. tail: maskHandlerEnv(worker.tail),
  62. }),
  63. ...(worker.trace && {
  64. trace: maskHandlerEnv(worker.trace),
  65. }),
  66. ...(worker.scheduled && {
  67. scheduled: maskHandlerEnv(worker.scheduled),
  68. }),
  69. ...(worker.queue && {
  70. queue: maskHandlerEnv(worker.queue),
  71. }),
  72. ...(worker.test && {
  73. test: maskHandlerEnv(worker.test),
  74. }),
  75. ...(worker.email && {
  76. email: maskHandlerEnv(worker.email),
  77. }),
  78. fetch(request, rawEnv, ctx) {
  79. const env = getMaskedEnv(rawEnv);
  80. // Get the chain of middleware from the worker object
  81. if (worker.middleware && worker.middleware.length > 0) {
  82. // Make sure we only register middleware once:
  83. // https://github.com/cloudflare/workers-sdk/issues/2386#issuecomment-1614715911
  84. if (!registeredMiddleware) {
  85. registeredMiddleware = true;
  86. for (const middleware of worker.middleware) {
  87. __facade_register__(middleware);
  88. }
  89. }
  90. const __facade_modules_dispatch__: Dispatcher = function (type, init) {
  91. if (type === "scheduled" && worker.scheduled !== undefined) {
  92. const controller = new __Facade_ScheduledController__(
  93. Date.now(),
  94. init.cron ?? "",
  95. () => {}
  96. );
  97. return worker.scheduled(controller, env, ctx);
  98. }
  99. };
  100. return __facade_invoke__(
  101. request,
  102. env,
  103. ctx,
  104. __facade_modules_dispatch__,
  105. __facade_modules_fetch__
  106. );
  107. } else {
  108. // We didn't have any middleware so we can skip the invocation chain,
  109. // and just call the fetch handler directly
  110. // We "don't care" if this is undefined as we want to have the same behavior
  111. // as if the worker completely bypassed middleware.
  112. return __facade_modules_fetch__(request, env, ctx);
  113. }
  114. },
  115. };
  116. type HandlerFn<D, R> = (data: D, env: unknown, ctx: ExecutionContext) => R;
  117. function maskHandlerEnv<D, R>(handler: HandlerFn<D, R>): HandlerFn<D, R> {
  118. return (data, env, ctx) => handler(data, getMaskedEnv(env), ctx);
  119. }
  120. export default facade;