@cedarjs/api-server 4.0.0-canary.13817 → 4.0.0-canary.13821

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 CHANGED
@@ -141,6 +141,9 @@ async function loadFastifyConfig() {
141
141
  if (!fs.existsSync(serverConfigPath)) {
142
142
  return serverConfigFile;
143
143
  }
144
+ if (loadedServerConfigPath !== serverConfigPath) {
145
+ isServerConfigLoaded = false;
146
+ }
144
147
  if (!isServerConfigLoaded) {
145
148
  console.log(`Loading server config from ${serverConfigPath}`);
146
149
  console.log(`Loading server config from URL file://${serverConfigPath}`);
@@ -149,11 +152,12 @@ async function loadFastifyConfig() {
149
152
  );
150
153
  const config3 = await import(pathToFileURL(serverConfigPath).href);
151
154
  serverConfigFile = { ...config3.default };
155
+ loadedServerConfigPath = serverConfigPath;
152
156
  isServerConfigLoaded = true;
153
157
  }
154
158
  return serverConfigFile;
155
159
  }
156
- var DEFAULT_OPTIONS, isServerConfigLoaded, serverConfigFile, createFastifyInstance;
160
+ var DEFAULT_OPTIONS, isServerConfigLoaded, loadedServerConfigPath, serverConfigFile, createFastifyInstance;
157
161
  var init_fastify = __esm({
158
162
  "src/fastify.ts"() {
159
163
  "use strict";
@@ -320,20 +324,26 @@ import path2 from "node:path";
320
324
  import { pathToFileURL as pathToFileURL2 } from "node:url";
321
325
  import ansis from "ansis";
322
326
  import fg from "fast-glob";
327
+ import { buildCedarContext, wrapLegacyHandler } from "@cedarjs/api/runtime";
323
328
  import { getPaths as getPaths2 } from "@cedarjs/project-config";
324
- var LAMBDA_FUNCTIONS, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
329
+ var LAMBDA_FUNCTIONS, CEDAR_HANDLERS, cedarRouteManifest, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
325
330
  var init_lambdaLoader = __esm({
326
331
  "src/plugins/lambdaLoader.ts"() {
327
332
  "use strict";
328
333
  init_awsLambdaFastify();
329
334
  init_utils2();
330
335
  LAMBDA_FUNCTIONS = {};
336
+ CEDAR_HANDLERS = /* @__PURE__ */ new Map();
337
+ cedarRouteManifest = [];
331
338
  setLambdaFunctions = async (foundFunctions) => {
332
339
  const tsImport = Date.now();
333
340
  console.log(ansis.dim.italic("Importing Server Functions... "));
341
+ cedarRouteManifest.length = 0;
342
+ CEDAR_HANDLERS.clear();
334
343
  const imports = foundFunctions.map(async (fnPath) => {
335
344
  const ts = Date.now();
336
345
  const routeName = path2.basename(fnPath).replace(".js", "");
346
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
337
347
  const fnImport = await import(pathToFileURL2(fnPath).href);
338
348
  const handler3 = (() => {
339
349
  if ("handler" in fnImport) {
@@ -346,15 +356,35 @@ var init_lambdaLoader = __esm({
346
356
  }
347
357
  return void 0;
348
358
  })();
359
+ const cedarHandler = (() => {
360
+ if ("handle" in fnImport && typeof fnImport.handle === "function") {
361
+ return fnImport.handle;
362
+ }
363
+ if ("default" in fnImport && fnImport.default && "handle" in fnImport.default && typeof fnImport.default.handle === "function") {
364
+ return fnImport.default.handle;
365
+ }
366
+ return void 0;
367
+ })();
349
368
  LAMBDA_FUNCTIONS[routeName] = handler3;
350
- if (!handler3) {
369
+ if (cedarHandler) {
370
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
371
+ } else if (handler3) {
372
+ CEDAR_HANDLERS.set(routeName, wrapLegacyHandler(handler3));
373
+ }
374
+ if (!handler3 && !cedarHandler) {
351
375
  console.warn(
352
376
  routeName,
353
377
  "at",
354
378
  fnPath,
355
- "does not have a function called handler defined."
379
+ "does not have a function called handler or handle defined."
356
380
  );
357
381
  }
382
+ cedarRouteManifest.push({
383
+ path: routePath,
384
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : ["GET", "POST"],
385
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
386
+ entry: fnPath
387
+ });
358
388
  console.log(
359
389
  ansis.magenta("/" + routeName),
360
390
  ansis.dim.italic(Date.now() - ts + " ms")
@@ -395,6 +425,30 @@ var init_lambdaLoader = __esm({
395
425
  };
396
426
  lambdaRequestHandler = async (req, reply) => {
397
427
  const { routeName } = req.params;
428
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
429
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
430
+ if (cedarHandler) {
431
+ 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;
432
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
433
+ const request = new Request(href, {
434
+ method: req.method,
435
+ headers: req.headers,
436
+ body: requestBody
437
+ });
438
+ const ctx = await buildCedarContext(request, {
439
+ params: {
440
+ routeName
441
+ }
442
+ });
443
+ const response = await cedarHandler(request, ctx);
444
+ reply.status(response.status);
445
+ response.headers.forEach((value, name) => {
446
+ reply.header(name, value);
447
+ });
448
+ const body = await response.arrayBuffer();
449
+ reply.send(Buffer.from(body));
450
+ return;
451
+ }
398
452
  if (!LAMBDA_FUNCTIONS[routeName]) {
399
453
  const errorMessage = `Function "${routeName}" was not found.`;
400
454
  req.log.error(errorMessage);
@@ -402,7 +456,12 @@ var init_lambdaLoader = __esm({
402
456
  if (process.env.NODE_ENV === "development") {
403
457
  const devError = {
404
458
  error: errorMessage,
405
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
459
+ availableFunctions: [
460
+ .../* @__PURE__ */ new Set([
461
+ ...Object.keys(LAMBDA_FUNCTIONS),
462
+ ...CEDAR_HANDLERS.keys()
463
+ ])
464
+ ]
406
465
  };
407
466
  reply.send(devError);
408
467
  } else {
@@ -472,6 +531,7 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
472
531
  import fastifyMultiPart from "@fastify/multipart";
473
532
  import fastifyUrlData2 from "@fastify/url-data";
474
533
  import fg2 from "fast-glob";
534
+ import { buildCedarContext as buildCedarContext2 } from "@cedarjs/api/runtime";
475
535
  import { getAsyncStoreInstance as getAsyncStoreInstance3 } from "@cedarjs/context/dist/store";
476
536
  import { coerceRootPath as coerceRootPath3 } from "@cedarjs/fastify-web/dist/helpers.js";
477
537
  import { createGraphQLYoga } from "@cedarjs/graphql-server";
@@ -522,11 +582,18 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
522
582
  fastify2.route({
523
583
  url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
524
584
  method,
525
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
526
- req,
527
- reply,
528
- event: lambdaEventForFastifyRequest(req)
529
- })
585
+ handler: async (req, _reply) => {
586
+ const request = createFetchRequest(req);
587
+ const cedarContext = await buildCedarContext2(request, {
588
+ authDecoder: graphqlOptions.authDecoder
589
+ });
590
+ return yoga.handle(request, {
591
+ request,
592
+ cedarContext,
593
+ event: lambdaEventForFastifyRequest(req),
594
+ requestContext: void 0
595
+ });
596
+ }
530
597
  });
531
598
  }
532
599
  fastify2.addHook("onReady", (done) => {
@@ -546,6 +613,15 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
546
613
  function trimSlashes(path5) {
547
614
  return path5.replace(/^\/|\/$/g, "");
548
615
  }
616
+ function createFetchRequest(req) {
617
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
618
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
619
+ return new Request(href, {
620
+ method: req.method,
621
+ headers: req.headers,
622
+ body: requestBody
623
+ });
624
+ }
549
625
  var init_graphql = __esm({
550
626
  "src/plugins/graphql.ts"() {
551
627
  "use strict";
package/dist/cjs/bin.js CHANGED
@@ -157,6 +157,9 @@ async function loadFastifyConfig() {
157
157
  if (!import_node_fs.default.existsSync(serverConfigPath)) {
158
158
  return serverConfigFile;
159
159
  }
160
+ if (loadedServerConfigPath !== serverConfigPath) {
161
+ isServerConfigLoaded = false;
162
+ }
160
163
  if (!isServerConfigLoaded) {
161
164
  console.log(`Loading server config from ${serverConfigPath}`);
162
165
  console.log(`Loading server config from URL file://${serverConfigPath}`);
@@ -165,11 +168,12 @@ async function loadFastifyConfig() {
165
168
  );
166
169
  const config3 = await import((0, import_url.pathToFileURL)(serverConfigPath).href);
167
170
  serverConfigFile = { ...config3.default };
171
+ loadedServerConfigPath = serverConfigPath;
168
172
  isServerConfigLoaded = true;
169
173
  }
170
174
  return serverConfigFile;
171
175
  }
172
- var import_node_fs, import_path, import_url, import_fastify, import_store, import_project_config2, DEFAULT_OPTIONS, isServerConfigLoaded, serverConfigFile, createFastifyInstance;
176
+ var import_node_fs, import_path, import_url, import_fastify, import_store, import_project_config2, DEFAULT_OPTIONS, isServerConfigLoaded, loadedServerConfigPath, serverConfigFile, createFastifyInstance;
173
177
  var init_fastify = __esm({
174
178
  "src/fastify.ts"() {
175
179
  "use strict";
@@ -338,7 +342,7 @@ var init_utils2 = __esm({
338
342
  });
339
343
 
340
344
  // src/plugins/lambdaLoader.ts
341
- var import_node_path, import_node_url, import_ansis, import_fast_glob, import_project_config3, LAMBDA_FUNCTIONS, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
345
+ var import_node_path, import_node_url, import_ansis, import_fast_glob, import_runtime, import_project_config3, LAMBDA_FUNCTIONS, CEDAR_HANDLERS, cedarRouteManifest, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
342
346
  var init_lambdaLoader = __esm({
343
347
  "src/plugins/lambdaLoader.ts"() {
344
348
  "use strict";
@@ -346,16 +350,22 @@ var init_lambdaLoader = __esm({
346
350
  import_node_url = require("node:url");
347
351
  import_ansis = __toESM(require("ansis"), 1);
348
352
  import_fast_glob = __toESM(require("fast-glob"), 1);
353
+ import_runtime = require("@cedarjs/api/runtime");
349
354
  import_project_config3 = require("@cedarjs/project-config");
350
355
  init_awsLambdaFastify();
351
356
  init_utils2();
352
357
  LAMBDA_FUNCTIONS = {};
358
+ CEDAR_HANDLERS = /* @__PURE__ */ new Map();
359
+ cedarRouteManifest = [];
353
360
  setLambdaFunctions = async (foundFunctions) => {
354
361
  const tsImport = Date.now();
355
362
  console.log(import_ansis.default.dim.italic("Importing Server Functions... "));
363
+ cedarRouteManifest.length = 0;
364
+ CEDAR_HANDLERS.clear();
356
365
  const imports = foundFunctions.map(async (fnPath) => {
357
366
  const ts = Date.now();
358
367
  const routeName = import_node_path.default.basename(fnPath).replace(".js", "");
368
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
359
369
  const fnImport = await import((0, import_node_url.pathToFileURL)(fnPath).href);
360
370
  const handler3 = (() => {
361
371
  if ("handler" in fnImport) {
@@ -368,15 +378,35 @@ var init_lambdaLoader = __esm({
368
378
  }
369
379
  return void 0;
370
380
  })();
381
+ const cedarHandler = (() => {
382
+ if ("handle" in fnImport && typeof fnImport.handle === "function") {
383
+ return fnImport.handle;
384
+ }
385
+ if ("default" in fnImport && fnImport.default && "handle" in fnImport.default && typeof fnImport.default.handle === "function") {
386
+ return fnImport.default.handle;
387
+ }
388
+ return void 0;
389
+ })();
371
390
  LAMBDA_FUNCTIONS[routeName] = handler3;
372
- if (!handler3) {
391
+ if (cedarHandler) {
392
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
393
+ } else if (handler3) {
394
+ CEDAR_HANDLERS.set(routeName, (0, import_runtime.wrapLegacyHandler)(handler3));
395
+ }
396
+ if (!handler3 && !cedarHandler) {
373
397
  console.warn(
374
398
  routeName,
375
399
  "at",
376
400
  fnPath,
377
- "does not have a function called handler defined."
401
+ "does not have a function called handler or handle defined."
378
402
  );
379
403
  }
404
+ cedarRouteManifest.push({
405
+ path: routePath,
406
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : ["GET", "POST"],
407
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
408
+ entry: fnPath
409
+ });
380
410
  console.log(
381
411
  import_ansis.default.magenta("/" + routeName),
382
412
  import_ansis.default.dim.italic(Date.now() - ts + " ms")
@@ -417,6 +447,30 @@ var init_lambdaLoader = __esm({
417
447
  };
418
448
  lambdaRequestHandler = async (req, reply) => {
419
449
  const { routeName } = req.params;
450
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
451
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
452
+ if (cedarHandler) {
453
+ 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;
454
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
455
+ const request = new Request(href, {
456
+ method: req.method,
457
+ headers: req.headers,
458
+ body: requestBody
459
+ });
460
+ const ctx = await (0, import_runtime.buildCedarContext)(request, {
461
+ params: {
462
+ routeName
463
+ }
464
+ });
465
+ const response = await cedarHandler(request, ctx);
466
+ reply.status(response.status);
467
+ response.headers.forEach((value, name) => {
468
+ reply.header(name, value);
469
+ });
470
+ const body = await response.arrayBuffer();
471
+ reply.send(Buffer.from(body));
472
+ return;
473
+ }
420
474
  if (!LAMBDA_FUNCTIONS[routeName]) {
421
475
  const errorMessage = `Function "${routeName}" was not found.`;
422
476
  req.log.error(errorMessage);
@@ -424,7 +478,12 @@ var init_lambdaLoader = __esm({
424
478
  if (process.env.NODE_ENV === "development") {
425
479
  const devError = {
426
480
  error: errorMessage,
427
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
481
+ availableFunctions: [
482
+ .../* @__PURE__ */ new Set([
483
+ ...Object.keys(LAMBDA_FUNCTIONS),
484
+ ...CEDAR_HANDLERS.keys()
485
+ ])
486
+ ]
428
487
  };
429
488
  reply.send(devError);
430
489
  } else {
@@ -537,11 +596,18 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
537
596
  fastify2.route({
538
597
  url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
539
598
  method,
540
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
541
- req,
542
- reply,
543
- event: lambdaEventForFastifyRequest(req)
544
- })
599
+ handler: async (req, _reply) => {
600
+ const request = createFetchRequest(req);
601
+ const cedarContext = await (0, import_runtime2.buildCedarContext)(request, {
602
+ authDecoder: graphqlOptions.authDecoder
603
+ });
604
+ return yoga.handle(request, {
605
+ request,
606
+ cedarContext,
607
+ event: lambdaEventForFastifyRequest(req),
608
+ requestContext: void 0
609
+ });
610
+ }
545
611
  });
546
612
  }
547
613
  fastify2.addHook("onReady", (done) => {
@@ -561,7 +627,16 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
561
627
  function trimSlashes(path5) {
562
628
  return path5.replace(/^\/|\/$/g, "");
563
629
  }
564
- var import_node_url2, import_multipart, import_url_data2, import_fast_glob2, import_store3, import_helpers3, import_graphql_server, import_project_config4;
630
+ function createFetchRequest(req) {
631
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
632
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
633
+ return new Request(href, {
634
+ method: req.method,
635
+ headers: req.headers,
636
+ body: requestBody
637
+ });
638
+ }
639
+ var import_node_url2, import_multipart, import_url_data2, import_fast_glob2, import_runtime2, import_store3, import_helpers3, import_graphql_server, import_project_config4;
565
640
  var init_graphql = __esm({
566
641
  "src/plugins/graphql.ts"() {
567
642
  "use strict";
@@ -569,6 +644,7 @@ var init_graphql = __esm({
569
644
  import_multipart = __toESM(require("@fastify/multipart"), 1);
570
645
  import_url_data2 = __toESM(require("@fastify/url-data"), 1);
571
646
  import_fast_glob2 = __toESM(require("fast-glob"), 1);
647
+ import_runtime2 = require("@cedarjs/api/runtime");
572
648
  import_store3 = require("@cedarjs/context/dist/store");
573
649
  import_helpers3 = require("@cedarjs/fastify-web/dist/helpers.js");
574
650
  import_graphql_server = require("@cedarjs/graphql-server");
@@ -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"}
@@ -45,6 +45,7 @@ const DEFAULT_OPTIONS = {
45
45
  }
46
46
  };
47
47
  let isServerConfigLoaded = false;
48
+ let loadedServerConfigPath;
48
49
  let serverConfigFile = {
49
50
  config: DEFAULT_OPTIONS,
50
51
  configureFastify: async (fastify, options) => {
@@ -63,6 +64,9 @@ async function loadFastifyConfig() {
63
64
  if (!import_node_fs.default.existsSync(serverConfigPath)) {
64
65
  return serverConfigFile;
65
66
  }
67
+ if (loadedServerConfigPath !== serverConfigPath) {
68
+ isServerConfigLoaded = false;
69
+ }
66
70
  if (!isServerConfigLoaded) {
67
71
  console.log(`Loading server config from ${serverConfigPath}`);
68
72
  console.log(`Loading server config from URL file://${serverConfigPath}`);
@@ -71,6 +75,7 @@ async function loadFastifyConfig() {
71
75
  );
72
76
  const config = await import((0, import_url.pathToFileURL)(serverConfigPath).href);
73
77
  serverConfigFile = { ...config.default };
78
+ loadedServerConfigPath = serverConfigPath;
74
79
  isServerConfigLoaded = true;
75
80
  }
76
81
  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":"AAKA,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;AAQ3E,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,iBA0HtC"}
@@ -35,6 +35,7 @@ var import_node_url = require("node:url");
35
35
  var import_multipart = __toESM(require("@fastify/multipart"), 1);
36
36
  var import_url_data = __toESM(require("@fastify/url-data"), 1);
37
37
  var import_fast_glob = __toESM(require("fast-glob"), 1);
38
+ var import_runtime = require("@cedarjs/api/runtime");
38
39
  var import_store = require("@cedarjs/context/dist/store");
39
40
  var import_helpers = require("@cedarjs/fastify-web/dist/helpers.js");
40
41
  var import_graphql_server = require("@cedarjs/graphql-server");
@@ -86,11 +87,18 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
86
87
  fastify.route({
87
88
  url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
88
89
  method,
89
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
90
- req,
91
- reply,
92
- event: (0, import_awsLambdaFastify.lambdaEventForFastifyRequest)(req)
93
- })
90
+ handler: async (req, _reply) => {
91
+ const request = createFetchRequest(req);
92
+ const cedarContext = await (0, import_runtime.buildCedarContext)(request, {
93
+ authDecoder: graphqlOptions.authDecoder
94
+ });
95
+ return yoga.handle(request, {
96
+ request,
97
+ cedarContext,
98
+ event: (0, import_awsLambdaFastify.lambdaEventForFastifyRequest)(req),
99
+ requestContext: void 0
100
+ });
101
+ }
94
102
  });
95
103
  }
96
104
  fastify.addHook("onReady", (done) => {
@@ -110,6 +118,15 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
110
118
  function trimSlashes(path) {
111
119
  return path.replace(/^\/|\/$/g, "");
112
120
  }
121
+ function createFetchRequest(req) {
122
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
123
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
124
+ return new Request(href, {
125
+ method: req.method,
126
+ headers: req.headers,
127
+ body: requestBody
128
+ });
129
+ }
113
130
  // Annotate the CommonJS export names for ESM import in node:
114
131
  0 && (module.exports = {
115
132
  redwoodFastifyGraphQLServer
@@ -1,8 +1,17 @@
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
+ import type { CedarHandler, CedarRouteRecord } from '@cedarjs/api/runtime';
4
5
  export type Lambdas = Record<string, Handler>;
5
6
  export declare const LAMBDA_FUNCTIONS: Lambdas;
7
+ export declare const CEDAR_HANDLERS: Map<string, CedarHandler>;
8
+ /**
9
+ * Exports a copy of the Cedar route manifest.
10
+ *
11
+ * This is intended to be used to later build WinterTC compatible `fetch`
12
+ * exports
13
+ */
14
+ export declare const getCedarRouteManifest: () => CedarRouteRecord[];
6
15
  export declare const setLambdaFunctions: (foundFunctions: string[]) => Promise<void>;
7
16
  type LoadFunctionsFromDistOptions = {
8
17
  fastGlobOptions?: FastGlobOptions;
@@ -1 +1 @@
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;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;AAEhB,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAEjB,MAAM,sBAAsB,CAAA;AAO7B,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAC7C,eAAO,MAAM,gBAAgB,EAAE,OAAY,CAAA;AAC3C,eAAO,MAAM,cAAc,2BAAkC,CAAA;AAG7D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,0BAAgC,CAAA;AAIlE,eAAO,MAAM,kBAAkB,GAAU,gBAAgB,MAAM,EAAE,kBAkGhE,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,kBAsEpB,CAAA"}
@@ -28,7 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var lambdaLoader_exports = {};
30
30
  __export(lambdaLoader_exports, {
31
+ CEDAR_HANDLERS: () => CEDAR_HANDLERS,
31
32
  LAMBDA_FUNCTIONS: () => LAMBDA_FUNCTIONS,
33
+ getCedarRouteManifest: () => getCedarRouteManifest,
32
34
  lambdaRequestHandler: () => lambdaRequestHandler,
33
35
  loadFunctionsFromDist: () => loadFunctionsFromDist,
34
36
  setLambdaFunctions: () => setLambdaFunctions
@@ -38,16 +40,23 @@ var import_node_path = __toESM(require("node:path"), 1);
38
40
  var import_node_url = require("node:url");
39
41
  var import_ansis = __toESM(require("ansis"), 1);
40
42
  var import_fast_glob = __toESM(require("fast-glob"), 1);
43
+ var import_runtime = require("@cedarjs/api/runtime");
41
44
  var import_project_config = require("@cedarjs/project-config");
42
45
  var import_awsLambdaFastify = require("../requestHandlers/awsLambdaFastify.js");
43
46
  var import_utils = require("../utils.js");
44
47
  const LAMBDA_FUNCTIONS = {};
48
+ const CEDAR_HANDLERS = /* @__PURE__ */ new Map();
49
+ const cedarRouteManifest = [];
50
+ const getCedarRouteManifest = () => [...cedarRouteManifest];
45
51
  const setLambdaFunctions = async (foundFunctions) => {
46
52
  const tsImport = Date.now();
47
53
  console.log(import_ansis.default.dim.italic("Importing Server Functions... "));
54
+ cedarRouteManifest.length = 0;
55
+ CEDAR_HANDLERS.clear();
48
56
  const imports = foundFunctions.map(async (fnPath) => {
49
57
  const ts = Date.now();
50
58
  const routeName = import_node_path.default.basename(fnPath).replace(".js", "");
59
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
51
60
  const fnImport = await import((0, import_node_url.pathToFileURL)(fnPath).href);
52
61
  const handler = (() => {
53
62
  if ("handler" in fnImport) {
@@ -60,15 +69,35 @@ const setLambdaFunctions = async (foundFunctions) => {
60
69
  }
61
70
  return void 0;
62
71
  })();
72
+ const cedarHandler = (() => {
73
+ if ("handle" in fnImport && typeof fnImport.handle === "function") {
74
+ return fnImport.handle;
75
+ }
76
+ if ("default" in fnImport && fnImport.default && "handle" in fnImport.default && typeof fnImport.default.handle === "function") {
77
+ return fnImport.default.handle;
78
+ }
79
+ return void 0;
80
+ })();
63
81
  LAMBDA_FUNCTIONS[routeName] = handler;
64
- if (!handler) {
82
+ if (cedarHandler) {
83
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
84
+ } else if (handler) {
85
+ CEDAR_HANDLERS.set(routeName, (0, import_runtime.wrapLegacyHandler)(handler));
86
+ }
87
+ if (!handler && !cedarHandler) {
65
88
  console.warn(
66
89
  routeName,
67
90
  "at",
68
91
  fnPath,
69
- "does not have a function called handler defined."
92
+ "does not have a function called handler or handle defined."
70
93
  );
71
94
  }
95
+ cedarRouteManifest.push({
96
+ path: routePath,
97
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : ["GET", "POST"],
98
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
99
+ entry: fnPath
100
+ });
72
101
  console.log(
73
102
  import_ansis.default.magenta("/" + routeName),
74
103
  import_ansis.default.dim.italic(Date.now() - ts + " ms")
@@ -109,6 +138,30 @@ const findApiDistFunctions = (params) => {
109
138
  };
110
139
  const lambdaRequestHandler = async (req, reply) => {
111
140
  const { routeName } = req.params;
141
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
142
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
143
+ if (cedarHandler) {
144
+ 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;
145
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
146
+ const request = new Request(href, {
147
+ method: req.method,
148
+ headers: req.headers,
149
+ body: requestBody
150
+ });
151
+ const ctx = await (0, import_runtime.buildCedarContext)(request, {
152
+ params: {
153
+ routeName
154
+ }
155
+ });
156
+ const response = await cedarHandler(request, ctx);
157
+ reply.status(response.status);
158
+ response.headers.forEach((value, name) => {
159
+ reply.header(name, value);
160
+ });
161
+ const body = await response.arrayBuffer();
162
+ reply.send(Buffer.from(body));
163
+ return;
164
+ }
112
165
  if (!LAMBDA_FUNCTIONS[routeName]) {
113
166
  const errorMessage = `Function "${routeName}" was not found.`;
114
167
  req.log.error(errorMessage);
@@ -116,7 +169,12 @@ const lambdaRequestHandler = async (req, reply) => {
116
169
  if (process.env.NODE_ENV === "development") {
117
170
  const devError = {
118
171
  error: errorMessage,
119
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
172
+ availableFunctions: [
173
+ .../* @__PURE__ */ new Set([
174
+ ...Object.keys(LAMBDA_FUNCTIONS),
175
+ ...CEDAR_HANDLERS.keys()
176
+ ])
177
+ ]
120
178
  };
121
179
  reply.send(devError);
122
180
  } else {
@@ -128,7 +186,9 @@ const lambdaRequestHandler = async (req, reply) => {
128
186
  };
129
187
  // Annotate the CommonJS export names for ESM import in node:
130
188
  0 && (module.exports = {
189
+ CEDAR_HANDLERS,
131
190
  LAMBDA_FUNCTIONS,
191
+ getCedarRouteManifest,
132
192
  lambdaRequestHandler,
133
193
  loadFunctionsFromDist,
134
194
  setLambdaFunctions
@@ -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":"AAKA,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;AAQ3E,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,iBA0HtC"}
@@ -2,6 +2,7 @@ import { pathToFileURL } from "node:url";
2
2
  import fastifyMultiPart from "@fastify/multipart";
3
3
  import fastifyUrlData from "@fastify/url-data";
4
4
  import fg from "fast-glob";
5
+ import { buildCedarContext } from "@cedarjs/api/runtime";
5
6
  import { getAsyncStoreInstance } from "@cedarjs/context/dist/store";
6
7
  import { coerceRootPath } from "@cedarjs/fastify-web/dist/helpers.js";
7
8
  import { createGraphQLYoga } from "@cedarjs/graphql-server";
@@ -53,11 +54,18 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
53
54
  fastify.route({
54
55
  url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
55
56
  method,
56
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
57
- req,
58
- reply,
59
- event: lambdaEventForFastifyRequest(req)
60
- })
57
+ handler: async (req, _reply) => {
58
+ const request = createFetchRequest(req);
59
+ const cedarContext = await buildCedarContext(request, {
60
+ authDecoder: graphqlOptions.authDecoder
61
+ });
62
+ return yoga.handle(request, {
63
+ request,
64
+ cedarContext,
65
+ event: lambdaEventForFastifyRequest(req),
66
+ requestContext: void 0
67
+ });
68
+ }
61
69
  });
62
70
  }
63
71
  fastify.addHook("onReady", (done) => {
@@ -77,6 +85,15 @@ async function redwoodFastifyGraphQLServer(fastify, options) {
77
85
  function trimSlashes(path) {
78
86
  return path.replace(/^\/|\/$/g, "");
79
87
  }
88
+ function createFetchRequest(req) {
89
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
90
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
91
+ return new Request(href, {
92
+ method: req.method,
93
+ headers: req.headers,
94
+ body: requestBody
95
+ });
96
+ }
80
97
  export {
81
98
  redwoodFastifyGraphQLServer
82
99
  };
@@ -1,8 +1,17 @@
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
+ import type { CedarHandler, CedarRouteRecord } from '@cedarjs/api/runtime';
4
5
  export type Lambdas = Record<string, Handler>;
5
6
  export declare const LAMBDA_FUNCTIONS: Lambdas;
7
+ export declare const CEDAR_HANDLERS: Map<string, CedarHandler>;
8
+ /**
9
+ * Exports a copy of the Cedar route manifest.
10
+ *
11
+ * This is intended to be used to later build WinterTC compatible `fetch`
12
+ * exports
13
+ */
14
+ export declare const getCedarRouteManifest: () => CedarRouteRecord[];
6
15
  export declare const setLambdaFunctions: (foundFunctions: string[]) => Promise<void>;
7
16
  type LoadFunctionsFromDistOptions = {
8
17
  fastGlobOptions?: FastGlobOptions;
@@ -1 +1 @@
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;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;AAEhB,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAEjB,MAAM,sBAAsB,CAAA;AAO7B,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAC7C,eAAO,MAAM,gBAAgB,EAAE,OAAY,CAAA;AAC3C,eAAO,MAAM,cAAc,2BAAkC,CAAA;AAG7D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,0BAAgC,CAAA;AAIlE,eAAO,MAAM,kBAAkB,GAAU,gBAAgB,MAAM,EAAE,kBAkGhE,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,kBAsEpB,CAAA"}
@@ -2,16 +2,23 @@ import path from "node:path";
2
2
  import { pathToFileURL } from "node:url";
3
3
  import ansis from "ansis";
4
4
  import fg from "fast-glob";
5
+ import { buildCedarContext, wrapLegacyHandler } from "@cedarjs/api/runtime";
5
6
  import { getPaths } from "@cedarjs/project-config";
6
7
  import { requestHandler } from "../requestHandlers/awsLambdaFastify.js";
7
8
  import { escape } from "../utils.js";
8
9
  const LAMBDA_FUNCTIONS = {};
10
+ const CEDAR_HANDLERS = /* @__PURE__ */ new Map();
11
+ const cedarRouteManifest = [];
12
+ const getCedarRouteManifest = () => [...cedarRouteManifest];
9
13
  const setLambdaFunctions = async (foundFunctions) => {
10
14
  const tsImport = Date.now();
11
15
  console.log(ansis.dim.italic("Importing Server Functions... "));
16
+ cedarRouteManifest.length = 0;
17
+ CEDAR_HANDLERS.clear();
12
18
  const imports = foundFunctions.map(async (fnPath) => {
13
19
  const ts = Date.now();
14
20
  const routeName = path.basename(fnPath).replace(".js", "");
21
+ const routePath = routeName === "graphql" ? "/graphql" : `/${routeName}`;
15
22
  const fnImport = await import(pathToFileURL(fnPath).href);
16
23
  const handler = (() => {
17
24
  if ("handler" in fnImport) {
@@ -24,15 +31,35 @@ const setLambdaFunctions = async (foundFunctions) => {
24
31
  }
25
32
  return void 0;
26
33
  })();
34
+ const cedarHandler = (() => {
35
+ if ("handle" in fnImport && typeof fnImport.handle === "function") {
36
+ return fnImport.handle;
37
+ }
38
+ if ("default" in fnImport && fnImport.default && "handle" in fnImport.default && typeof fnImport.default.handle === "function") {
39
+ return fnImport.default.handle;
40
+ }
41
+ return void 0;
42
+ })();
27
43
  LAMBDA_FUNCTIONS[routeName] = handler;
28
- if (!handler) {
44
+ if (cedarHandler) {
45
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
46
+ } else if (handler) {
47
+ CEDAR_HANDLERS.set(routeName, wrapLegacyHandler(handler));
48
+ }
49
+ if (!handler && !cedarHandler) {
29
50
  console.warn(
30
51
  routeName,
31
52
  "at",
32
53
  fnPath,
33
- "does not have a function called handler defined."
54
+ "does not have a function called handler or handle defined."
34
55
  );
35
56
  }
57
+ cedarRouteManifest.push({
58
+ path: routePath,
59
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : ["GET", "POST"],
60
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
61
+ entry: fnPath
62
+ });
36
63
  console.log(
37
64
  ansis.magenta("/" + routeName),
38
65
  ansis.dim.italic(Date.now() - ts + " ms")
@@ -73,6 +100,30 @@ const findApiDistFunctions = (params) => {
73
100
  };
74
101
  const lambdaRequestHandler = async (req, reply) => {
75
102
  const { routeName } = req.params;
103
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
104
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
105
+ if (cedarHandler) {
106
+ 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;
107
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
108
+ const request = new Request(href, {
109
+ method: req.method,
110
+ headers: req.headers,
111
+ body: requestBody
112
+ });
113
+ const ctx = await buildCedarContext(request, {
114
+ params: {
115
+ routeName
116
+ }
117
+ });
118
+ const response = await cedarHandler(request, ctx);
119
+ reply.status(response.status);
120
+ response.headers.forEach((value, name) => {
121
+ reply.header(name, value);
122
+ });
123
+ const body = await response.arrayBuffer();
124
+ reply.send(Buffer.from(body));
125
+ return;
126
+ }
76
127
  if (!LAMBDA_FUNCTIONS[routeName]) {
77
128
  const errorMessage = `Function "${routeName}" was not found.`;
78
129
  req.log.error(errorMessage);
@@ -80,7 +131,12 @@ const lambdaRequestHandler = async (req, reply) => {
80
131
  if (process.env.NODE_ENV === "development") {
81
132
  const devError = {
82
133
  error: errorMessage,
83
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
134
+ availableFunctions: [
135
+ .../* @__PURE__ */ new Set([
136
+ ...Object.keys(LAMBDA_FUNCTIONS),
137
+ ...CEDAR_HANDLERS.keys()
138
+ ])
139
+ ]
84
140
  };
85
141
  reply.send(devError);
86
142
  } else {
@@ -91,7 +147,9 @@ const lambdaRequestHandler = async (req, reply) => {
91
147
  return requestHandler(req, reply, LAMBDA_FUNCTIONS[routeName]);
92
148
  };
93
149
  export {
150
+ CEDAR_HANDLERS,
94
151
  LAMBDA_FUNCTIONS,
152
+ getCedarRouteManifest,
95
153
  lambdaRequestHandler,
96
154
  loadFunctionsFromDist,
97
155
  setLambdaFunctions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedarjs/api-server",
3
- "version": "4.0.0-canary.13817+443ccf6432",
3
+ "version": "4.0.0-canary.13821+c50dad5fb2",
4
4
  "description": "CedarJS's HTTP server for Serverless Functions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -111,11 +111,11 @@
111
111
  "test:watch": "vitest watch"
112
112
  },
113
113
  "dependencies": {
114
- "@cedarjs/context": "4.0.0-canary.13817",
115
- "@cedarjs/fastify-web": "4.0.0-canary.13817",
116
- "@cedarjs/internal": "4.0.0-canary.13817",
117
- "@cedarjs/project-config": "4.0.0-canary.13817",
118
- "@cedarjs/web-server": "4.0.0-canary.13817",
114
+ "@cedarjs/context": "4.0.0-canary.13821",
115
+ "@cedarjs/fastify-web": "4.0.0-canary.13821",
116
+ "@cedarjs/internal": "4.0.0-canary.13821",
117
+ "@cedarjs/project-config": "4.0.0-canary.13821",
118
+ "@cedarjs/web-server": "4.0.0-canary.13821",
119
119
  "@fastify/multipart": "9.4.0",
120
120
  "@fastify/url-data": "6.0.3",
121
121
  "ansis": "4.2.0",
@@ -132,7 +132,7 @@
132
132
  "yargs": "17.7.2"
133
133
  },
134
134
  "devDependencies": {
135
- "@cedarjs/framework-tools": "4.0.0-canary.13817",
135
+ "@cedarjs/framework-tools": "4.0.0-canary.13821",
136
136
  "@types/aws-lambda": "8.10.161",
137
137
  "@types/dotenv-defaults": "^5.0.0",
138
138
  "@types/split2": "4.2.3",
@@ -145,7 +145,7 @@
145
145
  "vitest": "3.2.4"
146
146
  },
147
147
  "peerDependencies": {
148
- "@cedarjs/graphql-server": "4.0.0-canary.13817"
148
+ "@cedarjs/graphql-server": "4.0.0-canary.13821"
149
149
  },
150
150
  "peerDependenciesMeta": {
151
151
  "@cedarjs/graphql-server": {
@@ -155,5 +155,5 @@
155
155
  "publishConfig": {
156
156
  "access": "public"
157
157
  },
158
- "gitHead": "443ccf6432c587392e3cd2ef01e9732ee47f65fa"
158
+ "gitHead": "c50dad5fb2c3d3571a8151f7a5af200a5a077104"
159
159
  }