@cedarjs/api-server 9.0.0-canary.1784 → 9.0.0-canary.3124

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 (127) hide show
  1. package/README.md +0 -1
  2. package/dist/apiCLIConfig.d.ts.map +1 -1
  3. package/dist/apiCLIConfig.js +1 -1
  4. package/dist/apiCLIConfigHandler.d.ts.map +1 -1
  5. package/dist/apiCLIConfigHandler.js +5 -0
  6. package/dist/bin.js +316 -98
  7. package/dist/bothCLIConfig.d.ts.map +1 -1
  8. package/dist/bothCLIConfig.js +2 -2
  9. package/dist/bothCLIConfigHandler.d.ts.map +1 -1
  10. package/dist/bothCLIConfigHandler.js +8 -2
  11. package/dist/cliHelpers.d.ts +22 -4
  12. package/dist/cliHelpers.d.ts.map +1 -1
  13. package/dist/cliHelpers.js +43 -11
  14. package/dist/createServer.d.ts +19 -3
  15. package/dist/createServer.d.ts.map +1 -1
  16. package/dist/createServer.js +18 -11
  17. package/dist/createServerHelpers.d.ts +15 -2
  18. package/dist/createServerHelpers.d.ts.map +1 -1
  19. package/dist/createServerHelpers.js +14 -4
  20. package/dist/fastify.d.ts.map +1 -1
  21. package/dist/fastify.js +5 -0
  22. package/dist/logFormatter/formatters.d.ts +1 -1
  23. package/dist/logFormatter/formatters.d.ts.map +1 -1
  24. package/dist/logFormatter/index.d.ts.map +1 -1
  25. package/dist/plugins/api.d.ts +4 -5
  26. package/dist/plugins/api.d.ts.map +1 -1
  27. package/dist/plugins/api.js +15 -15
  28. package/dist/plugins/graphql.d.ts +20 -3
  29. package/dist/plugins/graphql.d.ts.map +1 -1
  30. package/dist/plugins/graphql.js +69 -28
  31. package/dist/plugins/lambdaLoader.d.ts +16 -6
  32. package/dist/plugins/lambdaLoader.d.ts.map +1 -1
  33. package/dist/plugins/lambdaLoader.js +73 -10
  34. package/dist/requestHandlers/awsLambdaFastify.d.ts.map +1 -1
  35. package/dist/requestHandlers/awsLambdaFastify.js +16 -4
  36. package/dist/serverFile.d.ts +23 -0
  37. package/dist/serverFile.d.ts.map +1 -0
  38. package/dist/serverFile.js +35 -0
  39. package/dist/types.d.ts +4 -4
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/utils.d.ts +0 -3
  42. package/dist/utils.d.ts.map +1 -1
  43. package/dist/utils.js +0 -20
  44. package/package.json +56 -72
  45. package/LICENSE +0 -21
  46. package/dist/buildManager.d.ts +0 -15
  47. package/dist/buildManager.d.ts.map +0 -1
  48. package/dist/buildManager.js +0 -50
  49. package/dist/cjs/apiCLIConfig.d.ts +0 -6
  50. package/dist/cjs/apiCLIConfig.d.ts.map +0 -1
  51. package/dist/cjs/apiCLIConfig.js +0 -71
  52. package/dist/cjs/apiCLIConfigHandler.d.ts +0 -3
  53. package/dist/cjs/apiCLIConfigHandler.d.ts.map +0 -1
  54. package/dist/cjs/apiCLIConfigHandler.js +0 -67
  55. package/dist/cjs/bin.d.ts +0 -2
  56. package/dist/cjs/bin.d.ts.map +0 -1
  57. package/dist/cjs/bin.js +0 -896
  58. package/dist/cjs/bothCLIConfig.d.ts +0 -6
  59. package/dist/cjs/bothCLIConfig.d.ts.map +0 -1
  60. package/dist/cjs/bothCLIConfig.js +0 -76
  61. package/dist/cjs/bothCLIConfigHandler.d.ts +0 -3
  62. package/dist/cjs/bothCLIConfigHandler.d.ts.map +0 -1
  63. package/dist/cjs/bothCLIConfigHandler.js +0 -107
  64. package/dist/cjs/buildManager.d.ts +0 -15
  65. package/dist/cjs/buildManager.d.ts.map +0 -1
  66. package/dist/cjs/buildManager.js +0 -74
  67. package/dist/cjs/cliHelpers.d.ts +0 -5
  68. package/dist/cjs/cliHelpers.d.ts.map +0 -1
  69. package/dist/cjs/cliHelpers.js +0 -52
  70. package/dist/cjs/createServer.d.ts +0 -30
  71. package/dist/cjs/createServer.d.ts.map +0 -1
  72. package/dist/cjs/createServer.js +0 -144
  73. package/dist/cjs/createServerHelpers.d.ts +0 -38
  74. package/dist/cjs/createServerHelpers.d.ts.map +0 -1
  75. package/dist/cjs/createServerHelpers.js +0 -112
  76. package/dist/cjs/fastify.d.ts +0 -13
  77. package/dist/cjs/fastify.d.ts.map +0 -1
  78. package/dist/cjs/fastify.js +0 -91
  79. package/dist/cjs/logFormatter/ambient.d.js +0 -1
  80. package/dist/cjs/logFormatter/bin.d.ts +0 -2
  81. package/dist/cjs/logFormatter/bin.d.ts.map +0 -1
  82. package/dist/cjs/logFormatter/bin.js +0 -369
  83. package/dist/cjs/logFormatter/formatters.d.ts +0 -30
  84. package/dist/cjs/logFormatter/formatters.d.ts.map +0 -1
  85. package/dist/cjs/logFormatter/formatters.js +0 -275
  86. package/dist/cjs/logFormatter/index.d.ts +0 -2
  87. package/dist/cjs/logFormatter/index.d.ts.map +0 -1
  88. package/dist/cjs/logFormatter/index.js +0 -184
  89. package/dist/cjs/package.json +0 -1
  90. package/dist/cjs/plugins/api.d.ts +0 -14
  91. package/dist/cjs/plugins/api.d.ts.map +0 -1
  92. package/dist/cjs/plugins/api.js +0 -78
  93. package/dist/cjs/plugins/graphql.d.ts +0 -10
  94. package/dist/cjs/plugins/graphql.d.ts.map +0 -1
  95. package/dist/cjs/plugins/graphql.js +0 -109
  96. package/dist/cjs/plugins/lambdaLoader.d.ts +0 -24
  97. package/dist/cjs/plugins/lambdaLoader.d.ts.map +0 -1
  98. package/dist/cjs/plugins/lambdaLoader.js +0 -134
  99. package/dist/cjs/requestHandlers/awsLambdaFastify.d.ts +0 -5
  100. package/dist/cjs/requestHandlers/awsLambdaFastify.d.ts.map +0 -1
  101. package/dist/cjs/requestHandlers/awsLambdaFastify.js +0 -103
  102. package/dist/cjs/requestHandlers/utils.d.ts +0 -26
  103. package/dist/cjs/requestHandlers/utils.d.ts.map +0 -1
  104. package/dist/cjs/requestHandlers/utils.js +0 -55
  105. package/dist/cjs/serverManager.d.ts +0 -8
  106. package/dist/cjs/serverManager.d.ts.map +0 -1
  107. package/dist/cjs/serverManager.js +0 -137
  108. package/dist/cjs/types.d.ts +0 -19
  109. package/dist/cjs/types.d.ts.map +0 -1
  110. package/dist/cjs/utils.d.ts +0 -6
  111. package/dist/cjs/utils.d.ts.map +0 -1
  112. package/dist/cjs/utils.js +0 -58
  113. package/dist/cjs/watch.d.ts +0 -10
  114. package/dist/cjs/watch.d.ts.map +0 -1
  115. package/dist/cjs/watch.js +0 -394
  116. package/dist/cjs/watchPaths.d.ts +0 -3
  117. package/dist/cjs/watchPaths.d.ts.map +0 -1
  118. package/dist/cjs/watchPaths.js +0 -140
  119. package/dist/serverManager.d.ts +0 -8
  120. package/dist/serverManager.d.ts.map +0 -1
  121. package/dist/serverManager.js +0 -102
  122. package/dist/watch.d.ts +0 -10
  123. package/dist/watch.d.ts.map +0 -1
  124. package/dist/watch.js +0 -370
  125. package/dist/watchPaths.d.ts +0 -3
  126. package/dist/watchPaths.d.ts.map +0 -1
  127. package/dist/watchPaths.js +0 -109
package/dist/bin.js CHANGED
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __esm = (fn, res) => function __init() {
5
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ var __esm = (fn, res, err) => function __init() {
5
+ if (err) throw err[0];
6
+ try {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ } catch (e) {
9
+ throw err = [e], e;
10
+ }
6
11
  };
7
12
  var __export = (target, all) => {
8
13
  for (var name in all)
@@ -10,24 +15,55 @@ var __export = (target, all) => {
10
15
  };
11
16
 
12
17
  // src/cliHelpers.ts
13
- import { getConfig } from "@cedarjs/project-config";
14
- function getAPIHost() {
15
- let host = process.env.REDWOOD_API_HOST;
18
+ import { getConfig, parsePort, readEnvVar } from "@cedarjs/project-config";
19
+ function getAPIHost({ isPublicSide = false } = {}) {
20
+ let host = readEnvVar("CEDAR_API_HOST", {
21
+ deprecatedAlias: "REDWOOD_API_HOST"
22
+ });
23
+ if (isPublicSide) {
24
+ host ??= process.env.HOST;
25
+ }
16
26
  host ??= getConfig().api.host;
17
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
27
+ host ??= "::";
18
28
  return host;
19
29
  }
20
- function getAPIPort() {
21
- return process.env.REDWOOD_API_PORT ? parseInt(process.env.REDWOOD_API_PORT) : getConfig().api.port;
30
+ function getAPIPort({ isPublicSide = false } = {}) {
31
+ const apiPort = readEnvVar("CEDAR_API_PORT", {
32
+ deprecatedAlias: "REDWOOD_API_PORT"
33
+ });
34
+ if (apiPort) {
35
+ return parsePort(apiPort, "CEDAR_API_PORT");
36
+ }
37
+ if (isPublicSide && process.env.PORT) {
38
+ return parsePort(process.env.PORT, "PORT");
39
+ }
40
+ return getConfig().api.port;
41
+ }
42
+ function getAPIRootPath() {
43
+ return process.env.CEDAR_API_ROOT_PATH ?? "/";
22
44
  }
23
- function getWebHost() {
24
- let host = process.env.REDWOOD_WEB_HOST;
45
+ function getWebHost({ isPublicSide = false } = {}) {
46
+ let host = readEnvVar("CEDAR_WEB_HOST", {
47
+ deprecatedAlias: "REDWOOD_WEB_HOST"
48
+ });
49
+ if (isPublicSide) {
50
+ host ??= process.env.HOST;
51
+ }
25
52
  host ??= getConfig().web.host;
26
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
53
+ host ??= "::";
27
54
  return host;
28
55
  }
29
- function getWebPort() {
30
- return process.env.REDWOOD_WEB_PORT ? parseInt(process.env.REDWOOD_WEB_PORT) : getConfig().web.port;
56
+ function getWebPort({ isPublicSide = false } = {}) {
57
+ const webPort = readEnvVar("CEDAR_WEB_PORT", {
58
+ deprecatedAlias: "REDWOOD_WEB_PORT"
59
+ });
60
+ if (webPort) {
61
+ return parsePort(webPort, "CEDAR_WEB_PORT");
62
+ }
63
+ if (isPublicSide && process.env.PORT) {
64
+ return parsePort(process.env.PORT, "PORT");
65
+ }
66
+ return getConfig().web.port;
31
67
  }
32
68
  var init_cliHelpers = __esm({
33
69
  "src/cliHelpers.ts"() {
@@ -52,7 +88,9 @@ function resolveOptions(options = {}, args) {
52
88
  bodyLimit: defaults.fastifyServerOptions.bodyLimit
53
89
  },
54
90
  discoverFunctionsGlob: options.discoverFunctionsGlob ?? defaults.discoverFunctionsGlob,
91
+ configureServer: options.configureServer ?? defaults.configureServer,
55
92
  configureApiServer: options.configureApiServer ?? defaults.configureApiServer,
93
+ configureGraphQLServer: options.configureGraphQLServer ?? defaults.configureGraphQLServer,
56
94
  apiHost: options.apiHost ?? defaults.apiHost,
57
95
  apiPort: options.apiPort ?? defaults.apiPort
58
96
  };
@@ -107,7 +145,7 @@ var init_createServerHelpers = __esm({
107
145
  "use strict";
108
146
  init_cliHelpers();
109
147
  getDefaultCreateServerOptions = () => ({
110
- apiRootPath: "/",
148
+ apiRootPath: getAPIRootPath(),
111
149
  logger: {
112
150
  level: process.env.LOG_LEVEL ?? (process.env.NODE_ENV === "development" ? "debug" : "warn")
113
151
  },
@@ -117,11 +155,19 @@ var init_createServerHelpers = __esm({
117
155
  // 100MB
118
156
  },
119
157
  discoverFunctionsGlob: "dist/functions/**/*.{ts,js}",
158
+ configureServer: () => {
159
+ },
120
160
  configureApiServer: () => {
121
161
  },
162
+ configureGraphQLServer: () => {
163
+ },
122
164
  parseArgs: true,
123
- apiHost: getAPIHost(),
124
- apiPort: getAPIPort()
165
+ // `createServer()`'s only callers are `cedarjs-server api` and custom
166
+ // `api/src/server.ts` files — both only ever run with the api side
167
+ // serving public traffic on its own, so they get to use the host's
168
+ // `HOST`/`PORT` env vars.
169
+ apiHost: getAPIHost({ isPublicSide: true }),
170
+ apiPort: getAPIPort({ isPublicSide: true })
125
171
  });
126
172
  }
127
173
  });
@@ -141,6 +187,9 @@ async function loadFastifyConfig() {
141
187
  if (!fs.existsSync(serverConfigPath)) {
142
188
  return serverConfigFile;
143
189
  }
190
+ if (loadedServerConfigPath !== serverConfigPath) {
191
+ isServerConfigLoaded = false;
192
+ }
144
193
  if (!isServerConfigLoaded) {
145
194
  console.log(`Loading server config from ${serverConfigPath}`);
146
195
  console.log(`Loading server config from URL file://${serverConfigPath}`);
@@ -149,11 +198,12 @@ async function loadFastifyConfig() {
149
198
  );
150
199
  const config3 = await import(pathToFileURL(serverConfigPath).href);
151
200
  serverConfigFile = { ...config3.default };
201
+ loadedServerConfigPath = serverConfigPath;
152
202
  isServerConfigLoaded = true;
153
203
  }
154
204
  return serverConfigFile;
155
205
  }
156
- var DEFAULT_OPTIONS, isServerConfigLoaded, serverConfigFile, createFastifyInstance;
206
+ var DEFAULT_OPTIONS, isServerConfigLoaded, loadedServerConfigPath, serverConfigFile, createFastifyInstance;
157
207
  var init_fastify = __esm({
158
208
  "src/fastify.ts"() {
159
209
  "use strict";
@@ -219,23 +269,35 @@ var init_utils = __esm({
219
269
  });
220
270
 
221
271
  // src/requestHandlers/awsLambdaFastify.ts
222
- import qs from "qs";
272
+ import { parse } from "picoquery";
223
273
  var lambdaEventForFastifyRequest, fastifyResponseForLambdaResult, fastifyResponseForLambdaError, requestHandler;
224
274
  var init_awsLambdaFastify = __esm({
225
275
  "src/requestHandlers/awsLambdaFastify.ts"() {
226
276
  "use strict";
227
277
  init_utils();
228
278
  lambdaEventForFastifyRequest = (request) => {
279
+ const qsParams = parse(
280
+ request.url.split(/\?(.+)/)[1],
281
+ {
282
+ nestingSyntax: "index",
283
+ arrayRepeat: true,
284
+ arrayRepeatSyntax: "bracket"
285
+ }
286
+ );
229
287
  return {
230
288
  httpMethod: request.method,
231
- headers: request.headers,
289
+ headers: {
290
+ "x-forwarded-proto": request.protocol,
291
+ ...request.headers
292
+ },
232
293
  path: request.urlData("path"),
233
- queryStringParameters: qs.parse(request.url.split(/\?(.+)/)[1]),
294
+ queryStringParameters: qsParams,
234
295
  requestContext: {
235
296
  requestId: request.id,
236
297
  identity: {
237
298
  sourceIp: request.ip
238
- }
299
+ },
300
+ domainName: request.hostname
239
301
  },
240
302
  ...parseBody(request.rawBody || "")
241
303
  // adds `body` and `isBase64Encoded`
@@ -308,24 +370,33 @@ var init_utils2 = __esm({
308
370
  });
309
371
 
310
372
  // src/plugins/lambdaLoader.ts
311
- import path2 from "path";
373
+ import path2 from "node:path";
374
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
312
375
  import ansis from "ansis";
313
376
  import fg from "fast-glob";
377
+ import { terminalLink } from "termi-link";
378
+ import { buildCedarContext, wrapLegacyHandler } from "@cedarjs/api/runtime";
314
379
  import { getPaths as getPaths2 } from "@cedarjs/project-config";
315
- var LAMBDA_FUNCTIONS, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
380
+ var LAMBDA_FUNCTIONS, CEDAR_HANDLERS, cedarRouteManifest, setLambdaFunctions, loadFunctionsFromDist, findApiDistFunctions, lambdaRequestHandler;
316
381
  var init_lambdaLoader = __esm({
317
382
  "src/plugins/lambdaLoader.ts"() {
318
383
  "use strict";
319
384
  init_awsLambdaFastify();
320
385
  init_utils2();
321
- LAMBDA_FUNCTIONS = {};
386
+ LAMBDA_FUNCTIONS = /* @__PURE__ */ new Map();
387
+ CEDAR_HANDLERS = /* @__PURE__ */ new Map();
388
+ cedarRouteManifest = [];
322
389
  setLambdaFunctions = async (foundFunctions) => {
323
390
  const tsImport = Date.now();
324
391
  console.log(ansis.dim.italic("Importing Server Functions... "));
392
+ cedarRouteManifest.length = 0;
393
+ LAMBDA_FUNCTIONS.clear();
394
+ CEDAR_HANDLERS.clear();
325
395
  const imports = foundFunctions.map(async (fnPath) => {
326
396
  const ts = Date.now();
327
397
  const routeName = path2.basename(fnPath).replace(".js", "");
328
- const fnImport = await import(`file://${fnPath}`);
398
+ const routePath = `/${routeName}`;
399
+ const fnImport = await import(pathToFileURL2(fnPath).href);
329
400
  const handler3 = (() => {
330
401
  if ("handler" in fnImport) {
331
402
  return fnImport.handler;
@@ -337,17 +408,40 @@ var init_lambdaLoader = __esm({
337
408
  }
338
409
  return void 0;
339
410
  })();
340
- LAMBDA_FUNCTIONS[routeName] = handler3;
341
- if (!handler3) {
411
+ const cedarHandler = (() => {
412
+ if ("handleRequest" in fnImport && typeof fnImport.handleRequest === "function") {
413
+ return fnImport.handleRequest;
414
+ }
415
+ if ("default" in fnImport && fnImport.default && "handleRequest" in fnImport.default && typeof fnImport.default.handleRequest === "function") {
416
+ return fnImport.default.handleRequest;
417
+ }
418
+ return void 0;
419
+ })();
420
+ if (handler3) {
421
+ LAMBDA_FUNCTIONS.set(routeName, handler3);
422
+ }
423
+ if (cedarHandler) {
424
+ CEDAR_HANDLERS.set(routeName, cedarHandler);
425
+ } else if (handler3) {
426
+ CEDAR_HANDLERS.set(routeName, wrapLegacyHandler(handler3));
427
+ }
428
+ if (!handler3 && !cedarHandler) {
342
429
  console.warn(
343
430
  routeName,
344
431
  "at",
345
432
  fnPath,
346
- "does not have a function called handler defined."
433
+ "does not have a function called handler or handleRequest defined."
347
434
  );
348
435
  }
436
+ cedarRouteManifest.push({
437
+ id: routePath,
438
+ path: routePath,
439
+ methods: routeName === "graphql" ? ["GET", "POST", "OPTIONS"] : [],
440
+ type: routeName === "graphql" ? "graphql" : routeName === "health" ? "health" : routeName.toLowerCase().includes("auth") ? "auth" : "function",
441
+ entry: fnPath
442
+ });
349
443
  console.log(
350
- ansis.magenta("/" + routeName),
444
+ terminalLink(ansis.magenta("/" + routeName), pathToFileURL2(fnPath).href),
351
445
  ansis.dim.italic(Date.now() - ts + " ms")
352
446
  );
353
447
  });
@@ -386,14 +480,43 @@ var init_lambdaLoader = __esm({
386
480
  };
387
481
  lambdaRequestHandler = async (req, reply) => {
388
482
  const { routeName } = req.params;
389
- if (!LAMBDA_FUNCTIONS[routeName]) {
483
+ const cedarHandlerCandidate = CEDAR_HANDLERS.get(routeName);
484
+ const cedarHandler = typeof cedarHandlerCandidate === "function" ? cedarHandlerCandidate : void 0;
485
+ if (cedarHandler) {
486
+ 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;
487
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
488
+ const request = new Request(href, {
489
+ method: req.method,
490
+ headers: req.headers,
491
+ body: requestBody
492
+ });
493
+ const ctx = await buildCedarContext(request, {
494
+ params: {
495
+ routeName
496
+ }
497
+ });
498
+ const response = await cedarHandler(request, ctx);
499
+ reply.status(response.status);
500
+ response.headers.forEach((value, name) => {
501
+ reply.header(name, value);
502
+ });
503
+ const body = await response.arrayBuffer();
504
+ reply.send(Buffer.from(body));
505
+ return;
506
+ }
507
+ const handler3 = LAMBDA_FUNCTIONS.get(routeName);
508
+ if (handler3) {
509
+ return requestHandler(req, reply, handler3);
510
+ } else {
390
511
  const errorMessage = `Function "${routeName}" was not found.`;
391
512
  req.log.error(errorMessage);
392
513
  reply.status(404);
393
514
  if (process.env.NODE_ENV === "development") {
394
515
  const devError = {
395
516
  error: errorMessage,
396
- availableFunctions: Object.keys(LAMBDA_FUNCTIONS)
517
+ availableFunctions: [
518
+ .../* @__PURE__ */ new Set([...LAMBDA_FUNCTIONS.keys(), ...CEDAR_HANDLERS.keys()])
519
+ ]
397
520
  };
398
521
  reply.send(devError);
399
522
  } else {
@@ -401,7 +524,6 @@ var init_lambdaLoader = __esm({
401
524
  }
402
525
  return;
403
526
  }
404
- return requestHandler(req, reply, LAMBDA_FUNCTIONS[routeName]);
405
527
  };
406
528
  }
407
529
  });
@@ -411,12 +533,12 @@ import fastifyUrlData from "@fastify/url-data";
411
533
  import fastifyRawBody from "fastify-raw-body";
412
534
  import { getAsyncStoreInstance as getAsyncStoreInstance2 } from "@cedarjs/context/dist/store";
413
535
  import { coerceRootPath as coerceRootPath2 } from "@cedarjs/fastify-web/dist/helpers.js";
414
- async function redwoodFastifyAPI(fastify2, opts) {
415
- const redwoodOptions = opts.redwood ?? {};
416
- redwoodOptions.apiRootPath ??= "/";
417
- redwoodOptions.apiRootPath = coerceRootPath2(redwoodOptions.apiRootPath);
418
- redwoodOptions.fastGlobOptions ??= {};
419
- redwoodOptions.loadUserConfig ??= false;
536
+ async function cedarFastifyAPI(fastify2, opts) {
537
+ const cedarOptions = opts.cedar ?? {};
538
+ cedarOptions.apiRootPath ??= "/";
539
+ cedarOptions.apiRootPath = coerceRootPath2(cedarOptions.apiRootPath);
540
+ cedarOptions.fastGlobOptions ??= {};
541
+ cedarOptions.loadUserConfig ??= false;
420
542
  fastify2.register(fastifyUrlData);
421
543
  await fastify2.register(fastifyRawBody);
422
544
  fastify2.addHook("onRequest", (_req, _reply, done) => {
@@ -427,23 +549,23 @@ async function redwoodFastifyAPI(fastify2, opts) {
427
549
  { parseAs: "string" },
428
550
  fastify2.defaultTextParser
429
551
  );
430
- if (redwoodOptions.loadUserConfig) {
552
+ if (cedarOptions.loadUserConfig) {
431
553
  const { configureFastify } = await loadFastifyConfig();
432
554
  if (configureFastify) {
433
555
  await configureFastify(fastify2, {
434
556
  side: "api",
435
- apiRootPath: redwoodOptions.apiRootPath
557
+ apiRootPath: cedarOptions.apiRootPath
436
558
  });
437
559
  }
438
560
  }
439
- if (redwoodOptions.configureServer) {
440
- await redwoodOptions.configureServer(fastify2);
561
+ if (cedarOptions.configureServer) {
562
+ await cedarOptions.configureServer(fastify2);
441
563
  }
442
- fastify2.all(`${redwoodOptions.apiRootPath}:routeName`, lambdaRequestHandler);
443
- fastify2.all(`${redwoodOptions.apiRootPath}:routeName/*`, lambdaRequestHandler);
564
+ fastify2.all(`${cedarOptions.apiRootPath}:routeName`, lambdaRequestHandler);
565
+ fastify2.all(`${cedarOptions.apiRootPath}:routeName/*`, lambdaRequestHandler);
444
566
  await loadFunctionsFromDist({
445
- fastGlobOptions: redwoodOptions.fastGlobOptions,
446
- discoverFunctionsGlob: redwoodOptions.discoverFunctionsGlob
567
+ fastGlobOptions: cedarOptions.fastGlobOptions,
568
+ discoverFunctionsGlob: cedarOptions.discoverFunctionsGlob
447
569
  });
448
570
  }
449
571
  var init_api = __esm({
@@ -457,8 +579,10 @@ var init_api = __esm({
457
579
  // src/plugins/graphql.ts
458
580
  var graphql_exports = {};
459
581
  __export(graphql_exports, {
460
- redwoodFastifyGraphQLServer: () => redwoodFastifyGraphQLServer
582
+ cedarFastifyGraphQLServer: () => cedarFastifyGraphQLServer,
583
+ isClientDisconnectError: () => isClientDisconnectError
461
584
  });
585
+ import { pathToFileURL as pathToFileURL3 } from "node:url";
462
586
  import fastifyMultiPart from "@fastify/multipart";
463
587
  import fastifyUrlData2 from "@fastify/url-data";
464
588
  import fg2 from "fast-glob";
@@ -466,51 +590,60 @@ import { getAsyncStoreInstance as getAsyncStoreInstance3 } from "@cedarjs/contex
466
590
  import { coerceRootPath as coerceRootPath3 } from "@cedarjs/fastify-web/dist/helpers.js";
467
591
  import { createGraphQLYoga } from "@cedarjs/graphql-server";
468
592
  import { getPaths as getPaths3 } from "@cedarjs/project-config";
469
- async function redwoodFastifyGraphQLServer(fastify2, options) {
470
- const redwoodOptions = options.redwood ?? {};
471
- redwoodOptions.apiRootPath ??= "/";
472
- redwoodOptions.apiRootPath = coerceRootPath3(redwoodOptions.apiRootPath);
593
+ async function cedarFastifyGraphQLServer(fastify2, options) {
594
+ const cedarOptions = options.cedar ?? {};
595
+ cedarOptions.apiRootPath ??= "/";
596
+ cedarOptions.apiRootPath = coerceRootPath3(cedarOptions.apiRootPath);
473
597
  fastify2.register(fastifyUrlData2);
474
598
  fastify2.register(fastifyMultiPart);
475
599
  const method = ["GET", "POST", "OPTIONS"];
476
600
  fastify2.addHook("onRequest", (_req, _reply, done) => {
477
601
  getAsyncStoreInstance3().run(/* @__PURE__ */ new Map(), done);
478
602
  });
603
+ if (cedarOptions.configureServer) {
604
+ await cedarOptions.configureServer(fastify2);
605
+ }
479
606
  try {
480
- if (!redwoodOptions.graphql) {
607
+ if (!cedarOptions.graphql) {
481
608
  const [graphqlFunctionPath] = await fg2("dist/functions/graphql.{ts,js}", {
482
609
  cwd: getPaths3().api.base,
483
610
  absolute: true
484
611
  });
485
- const filePath = `file://${graphqlFunctionPath}`;
486
- const { __rw_graphqlOptions } = await import(filePath);
487
- if (!__rw_graphqlOptions) {
612
+ const filePath = pathToFileURL3(graphqlFunctionPath).href;
613
+ const { __cedar_graphqlOptions } = await import(filePath);
614
+ if (!__cedar_graphqlOptions) {
488
615
  return;
489
616
  }
490
- redwoodOptions.graphql = __rw_graphqlOptions;
617
+ cedarOptions.graphql = __cedar_graphqlOptions;
491
618
  }
492
- const graphqlOptions = redwoodOptions.graphql;
493
- if (graphqlOptions?.realtime) {
494
- const { useCedarRealtime } = await import("@cedarjs/realtime");
495
- const originalExtraPlugins = graphqlOptions.extraPlugins ?? [];
496
- originalExtraPlugins.push(useCedarRealtime(graphqlOptions.realtime));
497
- graphqlOptions.extraPlugins = originalExtraPlugins;
498
- if (graphqlOptions.realtime.subscriptions) {
499
- method.push("PUT");
500
- }
619
+ const graphqlOptions = cedarOptions.graphql;
620
+ if (graphqlOptions?.realtime?.subscriptions) {
621
+ method.push("PUT");
501
622
  }
502
- const { yoga } = createGraphQLYoga(graphqlOptions);
503
- const graphqlEndpoint = trimSlashes(yoga.graphqlEndpoint);
623
+ const graphqlServer = await createGraphQLYoga(graphqlOptions);
624
+ const graphqlEndpoint = trimSlashes(graphqlServer.yoga.graphqlEndpoint);
504
625
  const routePaths = ["", "/health", "/readiness", "/stream"];
505
626
  for (const routePath of routePaths) {
506
627
  fastify2.route({
507
- url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
628
+ url: `${cedarOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
508
629
  method,
509
- handler: (req, reply) => yoga.handleNodeRequestAndResponse(req, reply, {
510
- req,
511
- reply,
512
- event: lambdaEventForFastifyRequest(req)
513
- })
630
+ handler: async (req, reply) => {
631
+ const request = createFetchRequest(req, reply);
632
+ const cedarContext = await graphqlServer.buildRequestContext(request);
633
+ try {
634
+ return await graphqlServer.yoga.handle(request, {
635
+ request,
636
+ cedarContext,
637
+ event: lambdaEventForFastifyRequest(req),
638
+ requestContext: void 0
639
+ });
640
+ } catch (e) {
641
+ if (isClientDisconnectError(e)) {
642
+ return new Response(null, { status: 499 });
643
+ }
644
+ throw e;
645
+ }
646
+ }
514
647
  });
515
648
  }
516
649
  fastify2.addHook("onReady", (done) => {
@@ -524,11 +657,41 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
524
657
  done();
525
658
  });
526
659
  } catch (e) {
527
- console.log(e);
660
+ const message = e instanceof Error ? e.message : String(e);
661
+ fastify2.log.error(e, `Failed to set up the GraphQL server: ${message}`);
662
+ throw e;
663
+ }
664
+ }
665
+ function trimSlashes(path6) {
666
+ return path6.replace(/^\/|\/$/g, "");
667
+ }
668
+ function isClientDisconnectError(e) {
669
+ if (!e || typeof e !== "object") {
670
+ return false;
671
+ }
672
+ if ("code" in e && e.code === "ERR_STREAM_PREMATURE_CLOSE") {
673
+ return true;
528
674
  }
675
+ if (e instanceof DOMException && e.name === "AbortError") {
676
+ return true;
677
+ }
678
+ return false;
529
679
  }
530
- function trimSlashes(path5) {
531
- return path5.replace(/^\/|\/$/g, "");
680
+ function createFetchRequest(req, reply) {
681
+ const controller = new AbortController();
682
+ reply.raw.on("close", () => {
683
+ if (!reply.raw.writableFinished) {
684
+ controller.abort();
685
+ }
686
+ });
687
+ const requestBody = req.method === "GET" || req.method === "HEAD" ? void 0 : typeof req.body === "string" ? req.body : req.body ? JSON.stringify(req.body) : void 0;
688
+ const href = `${req.protocol}://${req.hostname}${req.raw.url ?? "/"}`;
689
+ return new Request(href, {
690
+ method: req.method,
691
+ headers: req.headers,
692
+ body: requestBody,
693
+ signal: controller.signal
694
+ });
532
695
  }
533
696
  var init_graphql = __esm({
534
697
  "src/plugins/graphql.ts"() {
@@ -539,7 +702,8 @@ var init_graphql = __esm({
539
702
 
540
703
  // src/createServer.ts
541
704
  import fs2 from "node:fs";
542
- import path3 from "path";
705
+ import path3 from "node:path";
706
+ import { pathToFileURL as pathToFileURL4 } from "node:url";
543
707
  import ansis2 from "ansis";
544
708
  import { config } from "dotenv-defaults";
545
709
  import fg3 from "fast-glob";
@@ -551,7 +715,9 @@ async function createServer(options = {}) {
551
715
  apiRootPath,
552
716
  fastifyServerOptions,
553
717
  discoverFunctionsGlob,
718
+ configureServer,
554
719
  configureApiServer,
720
+ configureGraphQLServer,
555
721
  apiPort,
556
722
  apiHost
557
723
  } = resolveOptions(options);
@@ -590,8 +756,11 @@ async function createServer(options = {}) {
590
756
  server.addHook("onRequest", (_req, _reply, done) => {
591
757
  getAsyncStoreInstance4().run(/* @__PURE__ */ new Map(), done);
592
758
  });
593
- await server.register(redwoodFastifyAPI, {
594
- redwood: {
759
+ if (configureServer) {
760
+ await configureServer(server);
761
+ }
762
+ await server.register(cedarFastifyAPI, {
763
+ cedar: {
595
764
  apiRootPath,
596
765
  fastGlobOptions: {
597
766
  ignore: ["**/dist/functions/graphql.js"]
@@ -605,12 +774,13 @@ async function createServer(options = {}) {
605
774
  absolute: true
606
775
  });
607
776
  if (graphqlFunctionPath) {
608
- const { redwoodFastifyGraphQLServer: redwoodFastifyGraphQLServer2 } = await Promise.resolve().then(() => (init_graphql(), graphql_exports));
609
- const { __rw_graphqlOptions } = await import(`file://${graphqlFunctionPath}`);
610
- await server.register(redwoodFastifyGraphQLServer2, {
611
- redwood: {
777
+ const { cedarFastifyGraphQLServer: cedarFastifyGraphQLServer2 } = await Promise.resolve().then(() => (init_graphql(), graphql_exports));
778
+ const { __cedar_graphqlOptions } = await import(pathToFileURL4(graphqlFunctionPath).href);
779
+ await server.register(cedarFastifyGraphQLServer2, {
780
+ cedar: {
612
781
  apiRootPath,
613
- graphql: __rw_graphqlOptions
782
+ graphql: __cedar_graphqlOptions,
783
+ configureServer: configureGraphQLServer
614
784
  }
615
785
  });
616
786
  }
@@ -640,21 +810,62 @@ var init_createServer = __esm({
640
810
  "use strict";
641
811
  init_createServerHelpers();
642
812
  init_api();
643
- if (!process.env.REDWOOD_ENV_FILES_LOADED) {
813
+ if (!process.env.CEDAR_ENV_FILES_LOADED) {
644
814
  config({
645
815
  path: path3.join(getPaths4().base, ".env"),
646
816
  defaults: path3.join(getPaths4().base, ".env.defaults"),
647
817
  multiline: true
648
818
  });
649
- process.env.REDWOOD_ENV_FILES_LOADED = "true";
819
+ process.env.CEDAR_ENV_FILES_LOADED = "true";
650
820
  }
651
821
  }
652
822
  });
653
823
 
824
+ // src/serverFile.ts
825
+ import { spawn } from "node:child_process";
826
+ import fs3 from "node:fs";
827
+ import path4 from "node:path";
828
+ import { getPaths as getPaths5 } from "@cedarjs/project-config";
829
+ function apiDistServerFilePath() {
830
+ return path4.join(getPaths5().api.dist, "server.js");
831
+ }
832
+ function apiDistServerFileExists() {
833
+ return fs3.existsSync(apiDistServerFilePath());
834
+ }
835
+ async function runApiDistServerFile(options = {}) {
836
+ const args = ["--apiRootPath", options.apiRootPath ?? "/"];
837
+ if (options.port !== void 0) {
838
+ args.push("--apiPort", String(options.port));
839
+ }
840
+ await new Promise((resolve, reject) => {
841
+ const child = spawn(process.execPath, [apiDistServerFilePath(), ...args], {
842
+ cwd: getPaths5().api.dist,
843
+ stdio: "inherit"
844
+ });
845
+ child.on("error", reject);
846
+ child.on("exit", (code, signal) => {
847
+ if (signal || code === 0) {
848
+ resolve();
849
+ return;
850
+ }
851
+ reject(new Error(`api/dist/server.js exited with code ${code}`));
852
+ });
853
+ });
854
+ }
855
+ var init_serverFile = __esm({
856
+ "src/serverFile.ts"() {
857
+ "use strict";
858
+ }
859
+ });
860
+
654
861
  // src/apiCLIConfigHandler.ts
655
862
  import ansis3 from "ansis";
656
863
  import { coerceRootPath as coerceRootPath4 } from "@cedarjs/fastify-web";
657
864
  async function handler(options = {}) {
865
+ if (apiDistServerFileExists()) {
866
+ await runApiDistServerFile(options);
867
+ return;
868
+ }
658
869
  const timeStart = Date.now();
659
870
  console.log(ansis3.dim.italic("Starting API Server..."));
660
871
  options.apiRootPath = coerceRootPath4(options.apiRootPath ?? "/");
@@ -685,6 +896,7 @@ var init_apiCLIConfigHandler = __esm({
685
896
  "src/apiCLIConfigHandler.ts"() {
686
897
  "use strict";
687
898
  init_createServer();
899
+ init_serverFile();
688
900
  }
689
901
  });
690
902
 
@@ -692,10 +904,15 @@ var init_apiCLIConfigHandler = __esm({
692
904
  import ansis4 from "ansis";
693
905
  import { redwoodFastifyWeb, coerceRootPath as coerceRootPath5 } from "@cedarjs/fastify-web";
694
906
  async function handler2(options) {
907
+ if (apiDistServerFileExists()) {
908
+ throw new Error(
909
+ "api/dist/server.js was found, but a custom server file is not supported when serving both sides from one process (`cedarjs-server` / `cedar serve`). It is a Fastify concept. Anything registered there (Realtime, custom plugins, custom middleware) would silently be skipped if this continued.\n\nRun the api and web sides as separate processes instead, so the api side goes through `cedarjs-server api`, which does run your server file:\n\n cedarjs-server api\n cedarjs-server web"
910
+ );
911
+ }
695
912
  const timeStart = Date.now();
696
913
  console.log(ansis4.dim.italic("Starting API and Web Servers..."));
697
- options.webHost ??= getWebHost();
698
- options.webPort ??= getWebPort();
914
+ options.webHost ??= getWebHost({ isPublicSide: true });
915
+ options.webPort ??= getWebPort({ isPublicSide: true });
699
916
  options.apiHost ??= getAPIHost();
700
917
  options.apiPort ??= getAPIPort();
701
918
  options.apiRootPath = coerceRootPath5(options.apiRootPath ?? "/");
@@ -762,15 +979,16 @@ var init_bothCLIConfigHandler = __esm({
762
979
  init_cliHelpers();
763
980
  init_createServer();
764
981
  init_fastify();
982
+ init_serverFile();
765
983
  }
766
984
  });
767
985
 
768
986
  // src/bin.ts
769
- import path4 from "path";
987
+ import path5 from "path";
770
988
  import { config as config2 } from "dotenv-defaults";
771
989
  import { hideBin } from "yargs/helpers";
772
990
  import yargs from "yargs/yargs";
773
- import { getPaths as getPaths5 } from "@cedarjs/project-config";
991
+ import { getPaths as getPaths6 } from "@cedarjs/project-config";
774
992
  import {
775
993
  description as webDescription,
776
994
  builder as webBuilder,
@@ -787,7 +1005,7 @@ function builder(yargs2) {
787
1005
  alias: "p"
788
1006
  },
789
1007
  host: {
790
- description: "The host to listen at. Note that you most likely want this to be '0.0.0.0' in production",
1008
+ description: "The host to listen at",
791
1009
  type: "string"
792
1010
  },
793
1011
  apiRootPath: {
@@ -818,7 +1036,7 @@ function builder2(yargs2) {
818
1036
  alias: ["web-port"]
819
1037
  },
820
1038
  webHost: {
821
- description: "The host for the web server to listen on. Note that you most likely want this to be '0.0.0.0' in production",
1039
+ description: "The host for the web server to listen on",
822
1040
  type: "string",
823
1041
  alias: ["web-host"]
824
1042
  },
@@ -828,7 +1046,7 @@ function builder2(yargs2) {
828
1046
  alias: ["api-port"]
829
1047
  },
830
1048
  apiHost: {
831
- description: "The host for the api server to listen on. Note that you most likely want this to be '0.0.0.0' in production",
1049
+ description: "The host for the api server to listen on",
832
1050
  type: "string",
833
1051
  alias: ["api-host"]
834
1052
  },
@@ -843,16 +1061,16 @@ function builder2(yargs2) {
843
1061
 
844
1062
  // src/bin.ts
845
1063
  init_bothCLIConfigHandler();
846
- if (!process.env.REDWOOD_ENV_FILES_LOADED) {
1064
+ if (!process.env.CEDAR_ENV_FILES_LOADED) {
847
1065
  config2({
848
- path: path4.join(getPaths5().base, ".env"),
849
- defaults: path4.join(getPaths5().base, ".env.defaults"),
1066
+ path: path5.join(getPaths6().base, ".env"),
1067
+ defaults: path5.join(getPaths6().base, ".env.defaults"),
850
1068
  multiline: true
851
1069
  });
852
- process.env.REDWOOD_ENV_FILES_LOADED = "true";
1070
+ process.env.CEDAR_ENV_FILES_LOADED = "true";
853
1071
  }
854
1072
  process.env.NODE_ENV ??= "production";
855
- yargs(hideBin(process.argv)).scriptName("rw-server").strict().alias("h", "help").alias("v", "version").command(
1073
+ yargs(hideBin(process.argv)).scriptName("cedar-server").strict().alias("h", "help").alias("v", "version").command(
856
1074
  "$0",
857
1075
  description2,
858
1076
  // @ts-expect-error The yargs types seem wrong; it's ok for builder to be a function