@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.
- package/dist/bin.js +112 -38
- package/dist/cjs/bin.js +122 -48
- package/dist/cjs/createServer.d.ts.map +1 -1
- package/dist/cjs/createServer.js +6 -5
- package/dist/cjs/fastify.d.ts.map +1 -1
- package/dist/cjs/fastify.js +5 -0
- package/dist/cjs/plugins/api.d.ts.map +1 -1
- package/dist/cjs/plugins/graphql.d.ts.map +1 -1
- package/dist/cjs/plugins/graphql.js +27 -21
- package/dist/cjs/plugins/lambdaLoader.d.ts +16 -6
- package/dist/cjs/plugins/lambdaLoader.d.ts.map +1 -1
- package/dist/cjs/plugins/lambdaLoader.js +76 -12
- package/dist/cjs/requestHandlers/awsLambdaFastify.d.ts.map +1 -1
- package/dist/cjs/requestHandlers/awsLambdaFastify.js +6 -2
- package/dist/cjs/udDispatcher.d.ts +28 -0
- package/dist/cjs/udDispatcher.d.ts.map +1 -0
- package/dist/cjs/udDispatcher.js +192 -0
- package/dist/cjs/udFetchable.d.ts +12 -0
- package/dist/cjs/udFetchable.d.ts.map +1 -0
- package/dist/cjs/udFetchable.js +36 -0
- package/dist/createServer.d.ts.map +1 -1
- package/dist/createServer.js +3 -2
- package/dist/fastify.d.ts.map +1 -1
- package/dist/fastify.js +5 -0
- package/dist/plugins/api.d.ts.map +1 -1
- package/dist/plugins/graphql.d.ts.map +1 -1
- package/dist/plugins/graphql.js +27 -21
- package/dist/plugins/lambdaLoader.d.ts +16 -6
- package/dist/plugins/lambdaLoader.d.ts.map +1 -1
- package/dist/plugins/lambdaLoader.js +72 -10
- package/dist/requestHandlers/awsLambdaFastify.d.ts.map +1 -1
- package/dist/requestHandlers/awsLambdaFastify.js +6 -2
- package/dist/udDispatcher.d.ts +28 -0
- package/dist/udDispatcher.d.ts.map +1 -0
- package/dist/udDispatcher.js +158 -0
- package/dist/udFetchable.d.ts +12 -0
- package/dist/udFetchable.d.ts.map +1 -0
- package/dist/udFetchable.js +12 -0
- 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":"
|
|
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"}
|
package/dist/createServer.js
CHANGED
|
@@ -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(
|
|
80
|
+
const { __rw_graphqlOptions } = await import(pathToFileURL(graphqlFunctionPath).href);
|
|
80
81
|
await server.register(redwoodFastifyGraphQLServer, {
|
|
81
82
|
redwood: {
|
|
82
83
|
apiRootPath,
|
package/dist/fastify.d.ts.map
CHANGED
|
@@ -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;
|
|
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;
|
|
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":"
|
|
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"}
|
package/dist/plugins/graphql.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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,
|
|
56
|
-
req
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
5
|
-
export declare const LAMBDA_FUNCTIONS:
|
|
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
|
|
20
|
-
|
|
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":"
|
|
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
|
|
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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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:
|
|
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
|
+
};
|