@cedarjs/api-server 4.0.0 → 4.0.1-next.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/bin.js +112 -38
  2. package/dist/cjs/bin.js +122 -48
  3. package/dist/cjs/createServer.d.ts.map +1 -1
  4. package/dist/cjs/createServer.js +6 -5
  5. package/dist/cjs/fastify.d.ts.map +1 -1
  6. package/dist/cjs/fastify.js +5 -0
  7. package/dist/cjs/plugins/api.d.ts.map +1 -1
  8. package/dist/cjs/plugins/graphql.d.ts.map +1 -1
  9. package/dist/cjs/plugins/graphql.js +27 -21
  10. package/dist/cjs/plugins/lambdaLoader.d.ts +16 -6
  11. package/dist/cjs/plugins/lambdaLoader.d.ts.map +1 -1
  12. package/dist/cjs/plugins/lambdaLoader.js +76 -12
  13. package/dist/cjs/requestHandlers/awsLambdaFastify.d.ts.map +1 -1
  14. package/dist/cjs/requestHandlers/awsLambdaFastify.js +6 -2
  15. package/dist/cjs/udDispatcher.d.ts +28 -0
  16. package/dist/cjs/udDispatcher.d.ts.map +1 -0
  17. package/dist/cjs/udDispatcher.js +192 -0
  18. package/dist/cjs/udFetchable.d.ts +12 -0
  19. package/dist/cjs/udFetchable.d.ts.map +1 -0
  20. package/dist/cjs/udFetchable.js +36 -0
  21. package/dist/createServer.d.ts.map +1 -1
  22. package/dist/createServer.js +3 -2
  23. package/dist/fastify.d.ts.map +1 -1
  24. package/dist/fastify.js +5 -0
  25. package/dist/plugins/api.d.ts.map +1 -1
  26. package/dist/plugins/graphql.d.ts.map +1 -1
  27. package/dist/plugins/graphql.js +27 -21
  28. package/dist/plugins/lambdaLoader.d.ts +16 -6
  29. package/dist/plugins/lambdaLoader.d.ts.map +1 -1
  30. package/dist/plugins/lambdaLoader.js +72 -10
  31. package/dist/requestHandlers/awsLambdaFastify.d.ts.map +1 -1
  32. package/dist/requestHandlers/awsLambdaFastify.js +6 -2
  33. package/dist/udDispatcher.d.ts +28 -0
  34. package/dist/udDispatcher.d.ts.map +1 -0
  35. package/dist/udDispatcher.js +158 -0
  36. package/dist/udFetchable.d.ts +12 -0
  37. package/dist/udFetchable.d.ts.map +1 -0
  38. package/dist/udFetchable.js +12 -0
  39. package/package.json +40 -11
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var udFetchable_exports = {};
20
+ __export(udFetchable_exports, {
21
+ createCedarFetchable: () => createCedarFetchable
22
+ });
23
+ module.exports = __toCommonJS(udFetchable_exports);
24
+ var import_runtime = require("@cedarjs/api/runtime");
25
+ function createCedarFetchable(handler) {
26
+ return {
27
+ async fetch(request) {
28
+ const ctx = await (0, import_runtime.buildCedarContext)(request);
29
+ return handler(request, ctx);
30
+ }
31
+ };
32
+ }
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ createCedarFetchable
36
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../src/createServer.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,MAAM,0BAA0B,CAAA;AAsBjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,mBAoHnE"}
1
+ {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../src/createServer.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,MAAM,0BAA0B,CAAA;AAsBjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,mBAoHnE"}
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
- import path from "path";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
3
4
  import ansis from "ansis";
4
5
  import { config } from "dotenv-defaults";
5
6
  import fg from "fast-glob";
@@ -76,7 +77,7 @@ async function createServer(options = {}) {
76
77
  });
77
78
  if (graphqlFunctionPath) {
78
79
  const { redwoodFastifyGraphQLServer } = await import("./plugins/graphql.js");
79
- const { __rw_graphqlOptions } = await import(`file://${graphqlFunctionPath}`);
80
+ const { __rw_graphqlOptions } = await import(pathToFileURL(graphqlFunctionPath).href);
80
81
  await server.register(redwoodFastifyGraphQLServer, {
81
82
  redwood: {
82
83
  apiRootPath,
@@ -1 +1 @@
1
- {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAOpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGrD,eAAO,MAAM,eAAe;;;;CAI3B,CAAA;AAiBD,wBAAsB,iBAAiB;YAb7B,oBAAoB;sBACV,mBAAmB;GAsCtC;AAED,eAAO,MAAM,qBAAqB,GAChC,UAAU,oBAAoB,KAC7B,OAAO,CAAC,eAAe,CAWzB,CAAA"}
1
+ {"version":3,"file":"fastify.d.ts","sourceRoot":"","sources":["../src/fastify.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAOpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGrD,eAAO,MAAM,eAAe;;;;CAI3B,CAAA;AAkBD,wBAAsB,iBAAiB;YAb7B,oBAAoB;sBACV,mBAAmB;GA2CtC;AAED,eAAO,MAAM,qBAAqB,GAChC,UAAU,oBAAoB,KAC7B,OAAO,CAAC,eAAe,CAWzB,CAAA"}
package/dist/fastify.js CHANGED
@@ -10,6 +10,7 @@ const DEFAULT_OPTIONS = {
10
10
  }
11
11
  };
12
12
  let isServerConfigLoaded = false;
13
+ let loadedServerConfigPath;
13
14
  let serverConfigFile = {
14
15
  config: DEFAULT_OPTIONS,
15
16
  configureFastify: async (fastify, options) => {
@@ -28,6 +29,9 @@ async function loadFastifyConfig() {
28
29
  if (!fs.existsSync(serverConfigPath)) {
29
30
  return serverConfigFile;
30
31
  }
32
+ if (loadedServerConfigPath !== serverConfigPath) {
33
+ isServerConfigLoaded = false;
34
+ }
31
35
  if (!isServerConfigLoaded) {
32
36
  console.log(`Loading server config from ${serverConfigPath}`);
33
37
  console.log(`Loading server config from URL file://${serverConfigPath}`);
@@ -36,6 +40,7 @@ async function loadFastifyConfig() {
36
40
  );
37
41
  const config = await import(pathToFileURL(serverConfigPath).href);
38
42
  serverConfigFile = { ...config.default };
43
+ loadedServerConfigPath = serverConfigPath;
39
44
  isServerConfigLoaded = true;
40
45
  }
41
46
  return serverConfigFile;
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/plugins/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAO9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAKvD,MAAM,WAAW,sBAAsB;IAErC,OAAO,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,eAAe,CAAA;QACjC,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;QACzC,cAAc,CAAC,EAAE,OAAO,CAAA;QACxB,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAC3D,CAAA;CACF;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,sBAAsB,iBA4C7B"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/plugins/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAO9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AAKvD,MAAM,WAAW,sBAAsB;IAErC,OAAO,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,eAAe,CAAC,EAAE,eAAe,CAAA;QACjC,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;QACzC,cAAc,CAAC,EAAE,OAAO,CAAA;QACxB,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;KAI3D,CAAA;CACF;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,sBAAsB,iBA4C7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/plugins/graphql.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,SAAS,CAAA;AAO3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAC7B,CAAA;CACF;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,4BAA4B,iBAmGtC"}
1
+ {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/plugins/graphql.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAA+B,MAAM,SAAS,CAAA;AAO3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAC7B,CAAA;CACF;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,4BAA4B,iBAuGtC"}
@@ -1,6 +1,8 @@
1
+ import { pathToFileURL } from "node:url";
1
2
  import fastifyMultiPart from "@fastify/multipart";
2
3
  import fastifyUrlData from "@fastify/url-data";
3
4
  import fg from "fast-glob";
5
+ import { buildCedarContext } from "@cedarjs/api/runtime";
4
6
  import { getAsyncStoreInstance } from "@cedarjs/context/dist/store";
5
7
  import { coerceRootPath } from "@cedarjs/fastify-web/dist/helpers.js";
6
8
  import { createGraphQLYoga } from "@cedarjs/graphql-server";
@@ -22,7 +24,7 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
22
24
  cwd: getPaths().api.base,
23
25
  absolute: true
24
26
  });
25
- const filePath = `file://${graphqlFunctionPath}`;
27
+ const filePath = pathToFileURL(graphqlFunctionPath).href;
26
28
  const { __rw_graphqlOptions } = await import(filePath);
27
29
  if (!__rw_graphqlOptions) {
28
30
  return;
@@ -30,33 +32,28 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
30
32
  redwoodOptions.graphql = __rw_graphqlOptions;
31
33
  }
32
34
  const graphqlOptions = redwoodOptions.graphql;
33
- if (graphqlOptions?.realtime) {
34
- const { useCedarRealtime } = await import("@cedarjs/realtime");
35
- const originalExtraPlugins = graphqlOptions.extraPlugins ?? [];
36
- originalExtraPlugins.push(
37
- // This type cast is needed because useCedarRealtime returns an
38
- // EnvelopPlugin and here we need a YogaPlugin. I can't change the
39
- // return type of `useCedarRealtime` yet, because it'd be a breaking
40
- // change.
41
- useCedarRealtime(graphqlOptions.realtime)
42
- );
43
- graphqlOptions.extraPlugins = originalExtraPlugins;
44
- if (graphqlOptions.realtime.subscriptions) {
45
- method.push("PUT");
46
- }
35
+ if (graphqlOptions?.realtime?.subscriptions) {
36
+ method.push("PUT");
47
37
  }
48
- const { yoga } = createGraphQLYoga(graphqlOptions);
38
+ const { yoga } = await createGraphQLYoga(graphqlOptions);
49
39
  const graphqlEndpoint = trimSlashes(yoga.graphqlEndpoint);
50
40
  const routePaths = ["", "/health", "/readiness", "/stream"];
51
41
  for (const routePath of routePaths) {
52
42
  fastify.route({
53
43
  url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
54
44
  method,
55
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
56
- req,
57
- reply,
58
- event: lambdaEventForFastifyRequest(req)
59
- })
45
+ handler: async (req, _reply) => {
46
+ const request = createFetchRequest(req);
47
+ const cedarContext = await buildCedarContext(request, {
48
+ authDecoder: graphqlOptions.authDecoder
49
+ });
50
+ return yoga.handle(request, {
51
+ request,
52
+ cedarContext,
53
+ event: lambdaEventForFastifyRequest(req),
54
+ requestContext: void 0
55
+ });
56
+ }
60
57
  });
61
58
  }
62
59
  fastify.addHook("onReady", (done) => {
@@ -76,6 +73,15 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
76
73
  function trimSlashes(path) {
77
74
  return path.replace(/^\/|\/$/g, "");
78
75
  }
76
+ function createFetchRequest(req) {
77
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
78
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
79
+ return new Request(href, {
80
+ method: req.method,
81
+ headers: req.headers,
82
+ body: requestBody
83
+ });
84
+ }
79
85
  export {
80
86
  redwoodFastifyGraphQLServer
81
87
  };
@@ -1,8 +1,16 @@
1
1
  import type { Handler } from 'aws-lambda';
2
2
  import type { Options as FastGlobOptions } from 'fast-glob';
3
3
  import type { FastifyReply, FastifyRequest, RequestGenericInterface } from 'fastify';
4
- export type Lambdas = Record<string, Handler>;
5
- export declare const LAMBDA_FUNCTIONS: Lambdas;
4
+ import type { CedarHandler, CedarRouteRecord } from '@cedarjs/api/runtime';
5
+ export declare const LAMBDA_FUNCTIONS: Map<string, Handler>;
6
+ export declare const CEDAR_HANDLERS: Map<string, CedarHandler>;
7
+ /**
8
+ * Exports a copy of the Cedar route manifest.
9
+ *
10
+ * This is intended to be used to later build WinterTC compatible `fetch`
11
+ * exports
12
+ */
13
+ export declare const getCedarRouteManifest: () => CedarRouteRecord[];
6
14
  export declare const setLambdaFunctions: (foundFunctions: string[]) => Promise<void>;
7
15
  type LoadFunctionsFromDistOptions = {
8
16
  fastGlobOptions?: FastGlobOptions;
@@ -15,10 +23,12 @@ interface LambdaHandlerRequest extends RequestGenericInterface {
15
23
  };
16
24
  }
17
25
  /**
18
- This will take a fastify request
19
- Then convert it to a lambdaEvent, and pass it to the the appropriate handler for the routeName
20
- The LAMBDA_FUNCTIONS lookup has been populated already by this point
21
- **/
26
+ * This will take a fastify request
27
+ * Then convert it to a lambdaEvent, and pass it to the the appropriate handler
28
+ * for the routeName
29
+ * The CEDAR_HANDLERS and LAMBDA_FUNCTIONS maps have been populated already by
30
+ * this point
31
+ */
22
32
  export declare const lambdaRequestHandler: (req: FastifyRequest<LambdaHandlerRequest>, reply: FastifyReply) => Promise<void>;
23
33
  export {};
24
34
  //# sourceMappingURL=lambdaLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lambdaLoader.d.ts","sourceRoot":"","sources":["../../src/plugins/lambdaLoader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,uBAAuB,EACxB,MAAM,SAAS,CAAA;AAOhB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAC7C,eAAO,MAAM,gBAAgB,EAAE,OAAY,CAAA;AAI3C,eAAO,MAAM,kBAAkB,GAAU,gBAAgB,MAAM,EAAE,kBAsDhE,CAAA;AAED,KAAK,4BAA4B,GAAG;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1C,CAAA;AAGD,eAAO,MAAM,qBAAqB,GAChC,UAAS,4BAAiC,kBAe3C,CAAA;AA0BD,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAED;;;;IAII;AACJ,eAAO,MAAM,oBAAoB,GAC/B,KAAK,cAAc,CAAC,oBAAoB,CAAC,EACzC,OAAO,YAAY,kBAsBpB,CAAA"}
1
+ {"version":3,"file":"lambdaLoader.d.ts","sourceRoot":"","sources":["../../src/plugins/lambdaLoader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3D,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,uBAAuB,EACxB,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAEjB,MAAM,sBAAsB,CAAA;AAO7B,eAAO,MAAM,gBAAgB,sBAA6B,CAAA;AAC1D,eAAO,MAAM,cAAc,2BAAkC,CAAA;AAG7D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,0BAAgC,CAAA;AAIlE,eAAO,MAAM,kBAAkB,GAAU,gBAAgB,MAAM,EAAE,kBAuGhE,CAAA;AAED,KAAK,4BAA4B,GAAG;IAClC,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAC1C,CAAA;AAGD,eAAO,MAAM,qBAAqB,GAChC,UAAS,4BAAiC,kBAe3C,CAAA;AA0BD,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,MAAM,EAAE;QACN,SAAS,EAAE,MAAM,CAAA;KAClB,CAAA;CACF;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAC/B,KAAK,cAAc,CAAC,oBAAoB,CAAC,EACzC,OAAO,YAAY,kBAqEpB,CAAA"}
@@ -1,17 +1,27 @@
1
- import path from "path";
1
+ import path from "node:path";
2
+ import { pathToFileURL } from "node:url";
2
3
  import ansis from "ansis";
3
4
  import fg from "fast-glob";
5
+ import { terminalLink } from "termi-link";
6
+ import { buildCedarContext, wrapLegacyHandler } from "@cedarjs/api/runtime";
4
7
  import { getPaths } from "@cedarjs/project-config";
5
8
  import { requestHandler } from "../requestHandlers/awsLambdaFastify.js";
6
9
  import { escape } from "../utils.js";
7
- const LAMBDA_FUNCTIONS = {};
10
+ const LAMBDA_FUNCTIONS = /* @__PURE__ */ new Map();
11
+ const CEDAR_HANDLERS = /* @__PURE__ */ new Map();
12
+ const cedarRouteManifest = [];
13
+ const getCedarRouteManifest = () => [...cedarRouteManifest];
8
14
  const setLambdaFunctions = async (foundFunctions) => {
9
15
  const tsImport = Date.now();
10
16
  console.log(ansis.dim.italic("Importing Server Functions... "));
17
+ cedarRouteManifest.length = 0;
18
+ LAMBDA_FUNCTIONS.clear();
19
+ CEDAR_HANDLERS.clear();
11
20
  const imports = foundFunctions.map(async (fnPath) => {
12
21
  const ts = Date.now();
13
22
  const routeName = path.basename(fnPath).replace(".js", "");
14
- const fnImport = await import(`file://${fnPath}`);
23
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
24
+ const fnImport = await import(pathToFileURL(fnPath).href);
15
25
  const handler = (() => {
16
26
  if ("handler" in fnImport) {
17
27
  return fnImport.handler;
@@ -23,17 +33,39 @@ const setLambdaFunctions = async (foundFunctions) => {
23
33
  }
24
34
  return void 0;
25
35
  })();
26
- LAMBDA_FUNCTIONS[routeName] = handler;
27
- if (!handler) {
36
+ const cedarHandler = (() => {
37
+ if ("handleRequest" in fnImport && typeof fnImport.handleRequest === "function") {
38
+ return fnImport.handleRequest;
39
+ }
40
+ if ("default" in fnImport && fnImport.default && "handleRequest" in fnImport.default && typeof fnImport.default.handleRequest === "function") {
41
+ return fnImport.default.handleRequest;
42
+ }
43
+ return void 0;
44
+ })();
45
+ if (handler) {
46
+ LAMBDA_FUNCTIONS.set(routeName, handler);
47
+ }
48
+ if (cedarHandler) {
49
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
50
+ } else if (handler) {
51
+ CEDAR_HANDLERS.set(routeName, wrapLegacyHandler(handler));
52
+ }
53
+ if (!handler && !cedarHandler) {
28
54
  console.warn(
29
55
  routeName,
30
56
  "at",
31
57
  fnPath,
32
- "does not have a function called handler defined."
58
+ "does not have a function called handler or handleRequest defined."
33
59
  );
34
60
  }
61
+ cedarRouteManifest.push({
62
+ path: routePath,
63
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : ["GET", "POST"],
64
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
65
+ entry: fnPath
66
+ });
35
67
  console.log(
36
- ansis.magenta("/" + routeName),
68
+ terminalLink(ansis.magenta("/" + routeName), pathToFileURL(fnPath).href),
37
69
  ansis.dim.italic(Date.now() - ts + " ms")
38
70
  );
39
71
  });
@@ -72,14 +104,43 @@ const findApiDistFunctions = (params) => {
72
104
  };
73
105
  const lambdaRequestHandler = async (req, reply) => {
74
106
  const { routeName } = req.params;
75
- if (!LAMBDA_FUNCTIONS[routeName]) {
107
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
108
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
109
+ if (cedarHandler) {
110
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.rawBody === "string" ? req.rawBody : req.rawBody ? Buffer.from(req.rawBody).toString() : void 0;
111
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
112
+ const request = new Request(href, {
113
+ method: req.method,
114
+ headers: req.headers,
115
+ body: requestBody
116
+ });
117
+ const ctx = await buildCedarContext(request, {
118
+ params: {
119
+ routeName
120
+ }
121
+ });
122
+ const response = await cedarHandler(request, ctx);
123
+ reply.status(response.status);
124
+ response.headers.forEach((value, name) => {
125
+ reply.header(name, value);
126
+ });
127
+ const body = await response.arrayBuffer();
128
+ reply.send(Buffer.from(body));
129
+ return;
130
+ }
131
+ const handler = LAMBDA_FUNCTIONS.get(routeName);
132
+ if (handler) {
133
+ return requestHandler(req, reply, handler);
134
+ } else {
76
135
  const errorMessage = `Function "${routeName}" was not found.`;
77
136
  req.log.error(errorMessage);
78
137
  reply.status(404);
79
138
  if (process.env.NODE_ENV === "development") {
80
139
  const devError = {
81
140
  error: errorMessage,
82
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
141
+ availableFunctions: [
142
+ .../* @__PURE__ */ new Set([...LAMBDA_FUNCTIONS.keys(), ...CEDAR_HANDLERS.keys()])
143
+ ]
83
144
  };
84
145
  reply.send(devError);
85
146
  } else {
@@ -87,10 +148,11 @@ const lambdaRequestHandler = async (req, reply) => {
87
148
  }
88
149
  return;
89
150
  }
90
- return requestHandler(req, reply, LAMBDA_FUNCTIONS[routeName]);
91
151
  };
92
152
  export {
153
+ CEDAR_HANDLERS,
93
154
  LAMBDA_FUNCTIONS,
155
+ getCedarRouteManifest,
94
156
  lambdaRequestHandler,
95
157
  loadFunctionsFromDist,
96
158
  setLambdaFunctions
@@ -1 +1 @@
1
- {"version":3,"file":"awsLambdaFastify.d.ts","sourceRoot":"","sources":["../../src/requestHandlers/awsLambdaFastify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,OAAO,EAER,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3D,eAAO,MAAM,4BAA4B,GACvC,SAAS,cAAc,KACtB,oBAyBF,CAAA;AAoCD,eAAO,MAAM,cAAc,GACzB,KAAK,cAAc,EACnB,OAAO,YAAY,EACnB,SAAS,OAAO,kBAmCjB,CAAA"}
1
+ {"version":3,"file":"awsLambdaFastify.d.ts","sourceRoot":"","sources":["../../src/requestHandlers/awsLambdaFastify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,OAAO,EAGR,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3D,eAAO,MAAM,4BAA4B,GACvC,SAAS,cAAc,KACtB,oBA6BF,CAAA;AAoCD,eAAO,MAAM,cAAc,GACzB,KAAK,cAAc,EACnB,OAAO,YAAY,EACnB,SAAS,OAAO,kBAmCjB,CAAA"}
@@ -11,14 +11,18 @@ const lambdaEventForFastifyRequest = (request) => {
11
11
  );
12
12
  return {
13
13
  httpMethod: request.method,
14
- headers: request.headers,
14
+ headers: {
15
+ "x-forwarded-proto": request.protocol,
16
+ ...request.headers
17
+ },
15
18
  path: request.urlData("path"),
16
19
  queryStringParameters: qsParams,
17
20
  requestContext: {
18
21
  requestId: request.id,
19
22
  identity: {
20
23
  sourceIp: request.ip
21
- }
24
+ },
25
+ domainName: request.hostname
22
26
  },
23
27
  ...parseBody(request.rawBody || "")
24
28
  // adds `body` and `isBase64Encoded`
@@ -0,0 +1,28 @@
1
+ import type { EntryMeta } from '@universal-deploy/store';
2
+ import type { Fetchable } from './udFetchable.js';
3
+ export interface CedarDispatcherOptions {
4
+ apiRootPath?: string;
5
+ discoverFunctionsGlob?: string | string[];
6
+ /**
7
+ * Cache-bust token appended to dynamic ESM imports. Use this in dev to
8
+ * bypass Node.js's ESM module cache after a rebuild. Production builds
9
+ * should omit this.
10
+ */
11
+ cacheBust?: string | number;
12
+ }
13
+ export interface CedarDispatcherResult {
14
+ fetchable: Fetchable;
15
+ registrations: EntryMeta[];
16
+ }
17
+ /**
18
+ * Shared aggregate Cedar API dispatcher used by
19
+ * `cedarUniversalDeployPlugin` (via `virtual:cedar-api`).
20
+ *
21
+ * Discovers Cedar API functions in `api/dist/functions/`, builds a rou3 router
22
+ * and a map of route names to Fetchables, then returns a single Fetchable that
23
+ * routes incoming Fetch-API requests to the correct per-function handler.
24
+ * Also returns the list of `EntryMeta` registrations so callers can forward
25
+ * them to `@universal-deploy/store` via `addEntry()`.
26
+ */
27
+ export declare function buildCedarDispatcher(options?: CedarDispatcherOptions): Promise<CedarDispatcherResult>;
28
+ //# sourceMappingURL=udDispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"udDispatcher.d.ts","sourceRoot":"","sources":["../src/udDispatcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAUxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAgBjD,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACzC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,SAAS,CAAA;IACpB,aAAa,EAAE,SAAS,EAAE,CAAA;CAC3B;AA6BD;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAmNhC"}
@@ -0,0 +1,158 @@
1
+ import path from "node:path";
2
+ import { pathToFileURL } from "node:url";
3
+ import fg from "fast-glob";
4
+ import { addRoute, createRouter, findRoute } from "rou3";
5
+ import { buildCedarContext, requestToLegacyEvent } from "@cedarjs/api/runtime";
6
+ import { getAsyncStoreInstance } from "@cedarjs/context/dist/store";
7
+ import { getPaths } from "@cedarjs/project-config";
8
+ import { createCedarFetchable } from "./udFetchable.js";
9
+ const ALL_HTTP_METHODS = [
10
+ "GET",
11
+ "HEAD",
12
+ "POST",
13
+ "PUT",
14
+ "DELETE",
15
+ "PATCH",
16
+ "OPTIONS",
17
+ "CONNECT",
18
+ "TRACE"
19
+ ];
20
+ const GRAPHQL_METHODS = ["GET", "POST", "OPTIONS"];
21
+ function normalizeApiRootPath(rootPath) {
22
+ let normalized = rootPath;
23
+ if (!normalized.startsWith("/")) {
24
+ normalized = "/" + normalized;
25
+ }
26
+ if (!normalized.endsWith("/")) {
27
+ normalized = normalized + "/";
28
+ }
29
+ return normalized;
30
+ }
31
+ async function buildCedarDispatcher(options) {
32
+ const normalizedApiRootPath = normalizeApiRootPath(
33
+ options?.apiRootPath ?? "/"
34
+ );
35
+ const discoverFunctionsGlob = options?.discoverFunctionsGlob ?? "dist/functions/**/*.{ts,js}";
36
+ const serverFunctions = fg.sync(discoverFunctionsGlob, {
37
+ cwd: getPaths().api.base,
38
+ deep: 2,
39
+ absolute: true
40
+ });
41
+ const graphqlIdx = serverFunctions.findIndex(
42
+ (x) => path.basename(x, path.extname(x)) === "graphql"
43
+ );
44
+ if (graphqlIdx >= 0) {
45
+ const [graphqlFn] = serverFunctions.splice(graphqlIdx, 1);
46
+ serverFunctions.unshift(graphqlFn);
47
+ }
48
+ const fetchableMap = /* @__PURE__ */ new Map();
49
+ const router = createRouter();
50
+ const registrations = [];
51
+ for (const fnPath of serverFunctions) {
52
+ const routeName = path.basename(fnPath, path.extname(fnPath));
53
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
54
+ const importUrl = options?.cacheBust ? `${pathToFileURL(fnPath).href}?t=${options.cacheBust}` : pathToFileURL(fnPath).href;
55
+ const fnImport = await import(importUrl);
56
+ if ("__rw_graphqlOptions" in fnImport && fnImport.__rw_graphqlOptions != null) {
57
+ const { createGraphQLYoga } = await import("@cedarjs/graphql-server");
58
+ const graphqlOptions = fnImport.__rw_graphqlOptions;
59
+ const { yoga } = await createGraphQLYoga(graphqlOptions);
60
+ const graphqlFetchable = {
61
+ async fetch(request) {
62
+ const cedarContext = await buildCedarContext(request, {
63
+ authDecoder: graphqlOptions.authDecoder
64
+ });
65
+ const event = await requestToLegacyEvent(request, cedarContext);
66
+ return yoga.handle(request, {
67
+ request,
68
+ cedarContext,
69
+ event,
70
+ requestContext: void 0
71
+ });
72
+ }
73
+ };
74
+ fetchableMap.set(routeName, graphqlFetchable);
75
+ registrations.push({
76
+ id: routePath,
77
+ route: routePath,
78
+ method: [...GRAPHQL_METHODS]
79
+ });
80
+ for (const method of GRAPHQL_METHODS) {
81
+ addRoute(router, method, routePath, routeName);
82
+ addRoute(router, method, `${routePath}/**`, routeName);
83
+ }
84
+ continue;
85
+ }
86
+ const cedarHandler = (() => {
87
+ if ("handle" in fnImport && typeof fnImport.handle === "function") {
88
+ return fnImport.handle;
89
+ }
90
+ if ("default" in fnImport && fnImport.default != null && "handle" in fnImport.default && typeof fnImport.default.handle === "function") {
91
+ return fnImport.default.handle;
92
+ }
93
+ return void 0;
94
+ })();
95
+ if (!cedarHandler) {
96
+ console.warn(
97
+ routeName,
98
+ "at",
99
+ fnPath,
100
+ "does not export a Fetch-native `handle` function and will not be served by the Universal Deploy server. Migrate to `export async function handle(request, ctx)` or use `yarn cedar serve` for legacy Lambda-shaped handler support."
101
+ );
102
+ continue;
103
+ }
104
+ const handler = cedarHandler;
105
+ fetchableMap.set(routeName, createCedarFetchable(handler));
106
+ registrations.push({
107
+ id: routePath,
108
+ route: routePath
109
+ // method omitted → matches all HTTP methods per @universal-deploy/store docs
110
+ });
111
+ for (const method of ALL_HTTP_METHODS) {
112
+ addRoute(router, method, routePath, routeName);
113
+ addRoute(router, method, `${routePath}/**`, routeName);
114
+ }
115
+ }
116
+ const fetchable = {
117
+ fetch(request) {
118
+ return getAsyncStoreInstance().run(
119
+ /* @__PURE__ */ new Map(),
120
+ async () => {
121
+ const url = new URL(request.url);
122
+ let routePathname = url.pathname;
123
+ if (normalizedApiRootPath !== "/" && routePathname.startsWith(normalizedApiRootPath)) {
124
+ routePathname = routePathname.slice(
125
+ normalizedApiRootPath.length - 1
126
+ );
127
+ }
128
+ if (!routePathname.startsWith("/")) {
129
+ routePathname = "/" + routePathname;
130
+ }
131
+ const match = findRoute(router, request.method, routePathname);
132
+ if (!match) {
133
+ return new Response("Not Found", { status: 404 });
134
+ }
135
+ const matchedRouteName = match.data;
136
+ const fnFetchable = fetchableMap.get(matchedRouteName);
137
+ if (!fnFetchable) {
138
+ return new Response("Not Found", { status: 404 });
139
+ }
140
+ try {
141
+ return await fnFetchable.fetch(request);
142
+ } catch (err) {
143
+ console.error(
144
+ "Unhandled error in fetch handler for route",
145
+ matchedRouteName,
146
+ err
147
+ );
148
+ return new Response("Internal Server Error", { status: 500 });
149
+ }
150
+ }
151
+ );
152
+ }
153
+ };
154
+ return { fetchable, registrations };
155
+ }
156
+ export {
157
+ buildCedarDispatcher
158
+ };
@@ -0,0 +1,12 @@
1
+ import type { CedarHandler } from '@cedarjs/api/runtime';
2
+ export interface Fetchable {
3
+ fetch(request: Request): Response | Promise<Response>;
4
+ }
5
+ /**
6
+ * Wraps a CedarHandler in a WinterTC-compatible Fetchable.
7
+ *
8
+ * The Fetchable calls buildCedarContext to produce a CedarRequestContext,
9
+ * then delegates to the handler.
10
+ */
11
+ export declare function createCedarFetchable(handler: CedarHandler): Fetchable;
12
+ //# sourceMappingURL=udFetchable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"udFetchable.d.ts","sourceRoot":"","sources":["../src/udFetchable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGxD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACtD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAOrE"}
@@ -0,0 +1,12 @@
1
+ import { buildCedarContext } from "@cedarjs/api/runtime";
2
+ function createCedarFetchable(handler) {
3
+ return {
4
+ async fetch(request) {
5
+ const ctx = await buildCedarContext(request);
6
+ return handler(request, ctx);
7
+ }
8
+ };
9
+ }
10
+ export {
11
+ createCedarFetchable
12
+ };