@cedarjs/api-server 6.0.0-rc.189 → 6.0.0-rc.241

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 (44) 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 +135 -40
  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 +21 -4
  12. package/dist/cliHelpers.d.ts.map +1 -1
  13. package/dist/cliHelpers.js +39 -11
  14. package/dist/createServer.d.ts.map +1 -1
  15. package/dist/createServer.js +4 -4
  16. package/dist/createServerHelpers.d.ts.map +1 -1
  17. package/dist/createServerHelpers.js +6 -2
  18. package/dist/plugins/api.d.ts +1 -1
  19. package/dist/plugins/api.d.ts.map +1 -1
  20. package/dist/plugins/api.js +1 -1
  21. package/dist/plugins/graphql.d.ts +19 -3
  22. package/dist/plugins/graphql.d.ts.map +1 -1
  23. package/dist/plugins/graphql.js +26 -11
  24. package/dist/serverFile.d.ts +23 -0
  25. package/dist/serverFile.d.ts.map +1 -0
  26. package/dist/serverFile.js +35 -0
  27. package/dist/types.d.ts +3 -3
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/utils.d.ts +0 -3
  30. package/dist/utils.d.ts.map +1 -1
  31. package/dist/utils.js +0 -20
  32. package/package.json +10 -20
  33. package/dist/buildManager.d.ts +0 -15
  34. package/dist/buildManager.d.ts.map +0 -1
  35. package/dist/buildManager.js +0 -55
  36. package/dist/serverManager.d.ts +0 -8
  37. package/dist/serverManager.d.ts.map +0 -1
  38. package/dist/serverManager.js +0 -102
  39. package/dist/watch.d.ts +0 -10
  40. package/dist/watch.d.ts.map +0 -1
  41. package/dist/watch.js +0 -375
  42. package/dist/watchPaths.d.ts +0 -3
  43. package/dist/watchPaths.d.ts.map +0 -1
  44. package/dist/watchPaths.js +0 -109
package/README.md CHANGED
@@ -16,7 +16,6 @@ From package.json
16
16
 
17
17
  ```
18
18
  "bin": {
19
- "cedarjs-api-server-watch": "./dist/watch.js",
20
19
  "cedarjs-log-formatter": "./dist/logFormatter/bin.js",
21
20
  "cedarjs-server": "./dist/bin.js",
22
21
  },
@@ -1 +1 @@
1
- {"version":3,"file":"apiCLIConfig.d.ts","sourceRoot":"","sources":["../src/apiCLIConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,eAAO,MAAM,WAAW,4CAA4C,CAAA;AAEpE,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,QA0BpD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,gBAAgB,iBAGtD"}
1
+ {"version":3,"file":"apiCLIConfig.d.ts","sourceRoot":"","sources":["../src/apiCLIConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,eAAO,MAAM,WAAW,4CAA4C,CAAA;AAEpE,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,QAwBpD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,gBAAgB,iBAGtD"}
@@ -7,7 +7,7 @@ function builder(yargs) {
7
7
  alias: "p"
8
8
  },
9
9
  host: {
10
- description: "The host to listen at. Note that you most likely want this to be '0.0.0.0' in production",
10
+ description: "The host to listen at",
11
11
  type: "string"
12
12
  },
13
13
  apiRootPath: {
@@ -1 +1 @@
1
- {"version":3,"file":"apiCLIConfigHandler.d.ts","sourceRoot":"","sources":["../src/apiCLIConfigHandler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,wBAAsB,OAAO,CAAC,OAAO,GAAE,gBAAqB,iBAoC3D"}
1
+ {"version":3,"file":"apiCLIConfigHandler.d.ts","sourceRoot":"","sources":["../src/apiCLIConfigHandler.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,wBAAsB,OAAO,CAAC,OAAO,GAAE,gBAAqB,iBA4C3D"}
@@ -1,7 +1,12 @@
1
1
  import ansis from "ansis";
2
2
  import { coerceRootPath } from "@cedarjs/fastify-web";
3
3
  import { createServer } from "./createServer.js";
4
+ import { apiDistServerFileExists, runApiDistServerFile } from "./serverFile.js";
4
5
  async function handler(options = {}) {
6
+ if (apiDistServerFileExists()) {
7
+ await runApiDistServerFile(options);
8
+ return;
9
+ }
5
10
  const timeStart = Date.now();
6
11
  console.log(ansis.dim.italic("Starting API Server..."));
7
12
  options.apiRootPath = coerceRootPath(options.apiRootPath ?? "/");
package/dist/bin.js CHANGED
@@ -15,27 +15,55 @@ var __export = (target, all) => {
15
15
  };
16
16
 
17
17
  // src/cliHelpers.ts
18
- import { getConfig } from "@cedarjs/project-config";
19
- function getAPIHost() {
20
- 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
+ }
21
26
  host ??= getConfig().api.host;
22
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
27
+ host ??= "::";
23
28
  return host;
24
29
  }
25
- function getAPIPort() {
26
- 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;
27
41
  }
28
42
  function getAPIRootPath() {
29
43
  return process.env.CEDAR_API_ROOT_PATH ?? "/";
30
44
  }
31
- function getWebHost() {
32
- 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
+ }
33
52
  host ??= getConfig().web.host;
34
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
53
+ host ??= "::";
35
54
  return host;
36
55
  }
37
- function getWebPort() {
38
- 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;
39
67
  }
40
68
  var init_cliHelpers = __esm({
41
69
  "src/cliHelpers.ts"() {
@@ -128,8 +156,12 @@ var init_createServerHelpers = __esm({
128
156
  configureApiServer: () => {
129
157
  },
130
158
  parseArgs: true,
131
- apiHost: getAPIHost(),
132
- apiPort: getAPIPort()
159
+ // `createServer()`'s only callers are `cedarjs-server api` and custom
160
+ // `api/src/server.ts` files — both only ever run with the api side
161
+ // serving public traffic on its own, so they get to use the host's
162
+ // `HOST`/`PORT` env vars.
163
+ apiHost: getAPIHost({ isPublicSide: true }),
164
+ apiPort: getAPIPort({ isPublicSide: true })
133
165
  });
134
166
  }
135
167
  });
@@ -496,7 +528,7 @@ import fastifyRawBody from "fastify-raw-body";
496
528
  import { getAsyncStoreInstance as getAsyncStoreInstance2 } from "@cedarjs/context/dist/store";
497
529
  import { coerceRootPath as coerceRootPath2 } from "@cedarjs/fastify-web/dist/helpers.js";
498
530
  async function cedarFastifyAPI(fastify2, opts) {
499
- const cedarOptions = opts.redwood ?? {};
531
+ const cedarOptions = opts.cedar ?? {};
500
532
  cedarOptions.apiRootPath ??= "/";
501
533
  cedarOptions.apiRootPath = coerceRootPath2(cedarOptions.apiRootPath);
502
534
  cedarOptions.fastGlobOptions ??= {};
@@ -541,7 +573,8 @@ var init_api = __esm({
541
573
  // src/plugins/graphql.ts
542
574
  var graphql_exports = {};
543
575
  __export(graphql_exports, {
544
- redwoodFastifyGraphQLServer: () => redwoodFastifyGraphQLServer
576
+ cedarFastifyGraphQLServer: () => cedarFastifyGraphQLServer,
577
+ isClientDisconnectError: () => isClientDisconnectError
545
578
  });
546
579
  import { pathToFileURL as pathToFileURL3 } from "node:url";
547
580
  import fastifyMultiPart from "@fastify/multipart";
@@ -552,10 +585,10 @@ import { getAsyncStoreInstance as getAsyncStoreInstance3 } from "@cedarjs/contex
552
585
  import { coerceRootPath as coerceRootPath3 } from "@cedarjs/fastify-web/dist/helpers.js";
553
586
  import { createGraphQLYoga } from "@cedarjs/graphql-server";
554
587
  import { getPaths as getPaths3 } from "@cedarjs/project-config";
555
- async function redwoodFastifyGraphQLServer(fastify2, options) {
556
- const redwoodOptions = options.redwood ?? {};
557
- redwoodOptions.apiRootPath ??= "/";
558
- redwoodOptions.apiRootPath = coerceRootPath3(redwoodOptions.apiRootPath);
588
+ async function cedarFastifyGraphQLServer(fastify2, options) {
589
+ const cedarOptions = options.cedar ?? {};
590
+ cedarOptions.apiRootPath ??= "/";
591
+ cedarOptions.apiRootPath = coerceRootPath3(cedarOptions.apiRootPath);
559
592
  fastify2.register(fastifyUrlData2);
560
593
  fastify2.register(fastifyMultiPart);
561
594
  const method = ["GET", "POST", "OPTIONS"];
@@ -563,7 +596,7 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
563
596
  getAsyncStoreInstance3().run(/* @__PURE__ */ new Map(), done);
564
597
  });
565
598
  try {
566
- if (!redwoodOptions.graphql) {
599
+ if (!cedarOptions.graphql) {
567
600
  const [graphqlFunctionPath] = await fg2("dist/functions/graphql.{ts,js}", {
568
601
  cwd: getPaths3().api.base,
569
602
  absolute: true
@@ -573,9 +606,9 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
573
606
  if (!__cedar_graphqlOptions) {
574
607
  return;
575
608
  }
576
- redwoodOptions.graphql = __cedar_graphqlOptions;
609
+ cedarOptions.graphql = __cedar_graphqlOptions;
577
610
  }
578
- const graphqlOptions = redwoodOptions.graphql;
611
+ const graphqlOptions = cedarOptions.graphql;
579
612
  if (graphqlOptions?.realtime?.subscriptions) {
580
613
  method.push("PUT");
581
614
  }
@@ -584,7 +617,7 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
584
617
  const routePaths = ["", "/health", "/readiness", "/stream"];
585
618
  for (const routePath of routePaths) {
586
619
  fastify2.route({
587
- url: `${redwoodOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
620
+ url: `${cedarOptions.apiRootPath}${graphqlEndpoint}${routePath}`,
588
621
  method,
589
622
  handler: async (req, reply) => {
590
623
  const request = createFetchRequest(req, reply);
@@ -599,7 +632,7 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
599
632
  requestContext: void 0
600
633
  });
601
634
  } catch (e) {
602
- if (!!e && typeof e === "object" && "code" in e && e.code === "ERR_STREAM_PREMATURE_CLOSE") {
635
+ if (isClientDisconnectError(e)) {
603
636
  return new Response(null, { status: 499 });
604
637
  }
605
638
  throw e;
@@ -618,11 +651,25 @@ async function redwoodFastifyGraphQLServer(fastify2, options) {
618
651
  done();
619
652
  });
620
653
  } catch (e) {
621
- console.log(e);
654
+ const message = e instanceof Error ? e.message : String(e);
655
+ fastify2.log.error(e, `Failed to set up the GraphQL server: ${message}`);
656
+ throw e;
622
657
  }
623
658
  }
624
- function trimSlashes(path5) {
625
- return path5.replace(/^\/|\/$/g, "");
659
+ function trimSlashes(path6) {
660
+ return path6.replace(/^\/|\/$/g, "");
661
+ }
662
+ function isClientDisconnectError(e) {
663
+ if (!e || typeof e !== "object") {
664
+ return false;
665
+ }
666
+ if ("code" in e && e.code === "ERR_STREAM_PREMATURE_CLOSE") {
667
+ return true;
668
+ }
669
+ if (e instanceof DOMException && e.name === "AbortError") {
670
+ return true;
671
+ }
672
+ return false;
626
673
  }
627
674
  function createFetchRequest(req, reply) {
628
675
  const controller = new AbortController();
@@ -702,7 +749,7 @@ async function createServer(options = {}) {
702
749
  getAsyncStoreInstance4().run(/* @__PURE__ */ new Map(), done);
703
750
  });
704
751
  await server.register(cedarFastifyAPI, {
705
- redwood: {
752
+ cedar: {
706
753
  apiRootPath,
707
754
  fastGlobOptions: {
708
755
  ignore: ["**/dist/functions/graphql.js"]
@@ -716,10 +763,10 @@ async function createServer(options = {}) {
716
763
  absolute: true
717
764
  });
718
765
  if (graphqlFunctionPath) {
719
- const { redwoodFastifyGraphQLServer: redwoodFastifyGraphQLServer2 } = await Promise.resolve().then(() => (init_graphql(), graphql_exports));
766
+ const { cedarFastifyGraphQLServer: cedarFastifyGraphQLServer2 } = await Promise.resolve().then(() => (init_graphql(), graphql_exports));
720
767
  const { __cedar_graphqlOptions } = await import(pathToFileURL4(graphqlFunctionPath).href);
721
- await server.register(redwoodFastifyGraphQLServer2, {
722
- redwood: {
768
+ await server.register(cedarFastifyGraphQLServer2, {
769
+ cedar: {
723
770
  apiRootPath,
724
771
  graphql: __cedar_graphqlOptions
725
772
  }
@@ -762,10 +809,51 @@ var init_createServer = __esm({
762
809
  }
763
810
  });
764
811
 
812
+ // src/serverFile.ts
813
+ import { spawn } from "node:child_process";
814
+ import fs3 from "node:fs";
815
+ import path4 from "node:path";
816
+ import { getPaths as getPaths5 } from "@cedarjs/project-config";
817
+ function apiDistServerFilePath() {
818
+ return path4.join(getPaths5().api.dist, "server.js");
819
+ }
820
+ function apiDistServerFileExists() {
821
+ return fs3.existsSync(apiDistServerFilePath());
822
+ }
823
+ async function runApiDistServerFile(options = {}) {
824
+ const args = ["--apiRootPath", options.apiRootPath ?? "/"];
825
+ if (options.port !== void 0) {
826
+ args.push("--apiPort", String(options.port));
827
+ }
828
+ await new Promise((resolve, reject) => {
829
+ const child = spawn(process.execPath, [apiDistServerFilePath(), ...args], {
830
+ cwd: getPaths5().api.dist,
831
+ stdio: "inherit"
832
+ });
833
+ child.on("error", reject);
834
+ child.on("exit", (code, signal) => {
835
+ if (signal || code === 0) {
836
+ resolve();
837
+ return;
838
+ }
839
+ reject(new Error(`api/dist/server.js exited with code ${code}`));
840
+ });
841
+ });
842
+ }
843
+ var init_serverFile = __esm({
844
+ "src/serverFile.ts"() {
845
+ "use strict";
846
+ }
847
+ });
848
+
765
849
  // src/apiCLIConfigHandler.ts
766
850
  import ansis3 from "ansis";
767
851
  import { coerceRootPath as coerceRootPath4 } from "@cedarjs/fastify-web";
768
852
  async function handler(options = {}) {
853
+ if (apiDistServerFileExists()) {
854
+ await runApiDistServerFile(options);
855
+ return;
856
+ }
769
857
  const timeStart = Date.now();
770
858
  console.log(ansis3.dim.italic("Starting API Server..."));
771
859
  options.apiRootPath = coerceRootPath4(options.apiRootPath ?? "/");
@@ -796,6 +884,7 @@ var init_apiCLIConfigHandler = __esm({
796
884
  "src/apiCLIConfigHandler.ts"() {
797
885
  "use strict";
798
886
  init_createServer();
887
+ init_serverFile();
799
888
  }
800
889
  });
801
890
 
@@ -803,10 +892,15 @@ var init_apiCLIConfigHandler = __esm({
803
892
  import ansis4 from "ansis";
804
893
  import { redwoodFastifyWeb, coerceRootPath as coerceRootPath5 } from "@cedarjs/fastify-web";
805
894
  async function handler2(options) {
895
+ if (apiDistServerFileExists()) {
896
+ throw new Error(
897
+ "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"
898
+ );
899
+ }
806
900
  const timeStart = Date.now();
807
901
  console.log(ansis4.dim.italic("Starting API and Web Servers..."));
808
- options.webHost ??= getWebHost();
809
- options.webPort ??= getWebPort();
902
+ options.webHost ??= getWebHost({ isPublicSide: true });
903
+ options.webPort ??= getWebPort({ isPublicSide: true });
810
904
  options.apiHost ??= getAPIHost();
811
905
  options.apiPort ??= getAPIPort();
812
906
  options.apiRootPath = coerceRootPath5(options.apiRootPath ?? "/");
@@ -873,15 +967,16 @@ var init_bothCLIConfigHandler = __esm({
873
967
  init_cliHelpers();
874
968
  init_createServer();
875
969
  init_fastify();
970
+ init_serverFile();
876
971
  }
877
972
  });
878
973
 
879
974
  // src/bin.ts
880
- import path4 from "path";
975
+ import path5 from "path";
881
976
  import { config as config2 } from "dotenv-defaults";
882
977
  import { hideBin } from "yargs/helpers";
883
978
  import yargs from "yargs/yargs";
884
- import { getPaths as getPaths5 } from "@cedarjs/project-config";
979
+ import { getPaths as getPaths6 } from "@cedarjs/project-config";
885
980
  import {
886
981
  description as webDescription,
887
982
  builder as webBuilder,
@@ -898,7 +993,7 @@ function builder(yargs2) {
898
993
  alias: "p"
899
994
  },
900
995
  host: {
901
- description: "The host to listen at. Note that you most likely want this to be '0.0.0.0' in production",
996
+ description: "The host to listen at",
902
997
  type: "string"
903
998
  },
904
999
  apiRootPath: {
@@ -929,7 +1024,7 @@ function builder2(yargs2) {
929
1024
  alias: ["web-port"]
930
1025
  },
931
1026
  webHost: {
932
- 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",
1027
+ description: "The host for the web server to listen on",
933
1028
  type: "string",
934
1029
  alias: ["web-host"]
935
1030
  },
@@ -939,7 +1034,7 @@ function builder2(yargs2) {
939
1034
  alias: ["api-port"]
940
1035
  },
941
1036
  apiHost: {
942
- 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",
1037
+ description: "The host for the api server to listen on",
943
1038
  type: "string",
944
1039
  alias: ["api-host"]
945
1040
  },
@@ -956,8 +1051,8 @@ function builder2(yargs2) {
956
1051
  init_bothCLIConfigHandler();
957
1052
  if (!process.env.CEDAR_ENV_FILES_LOADED) {
958
1053
  config2({
959
- path: path4.join(getPaths5().base, ".env"),
960
- defaults: path4.join(getPaths5().base, ".env.defaults"),
1054
+ path: path5.join(getPaths6().base, ".env"),
1055
+ defaults: path5.join(getPaths6().base, ".env.defaults"),
961
1056
  multiline: true
962
1057
  });
963
1058
  process.env.CEDAR_ENV_FILES_LOADED = "true";
@@ -1 +1 @@
1
- {"version":3,"file":"bothCLIConfig.d.ts","sourceRoot":"","sources":["../src/bothCLIConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAO,MAAM,WAAW,qDAAqD,CAAA;AAE7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,QA+BrD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,iBAAiB,iBAGvD"}
1
+ {"version":3,"file":"bothCLIConfig.d.ts","sourceRoot":"","sources":["../src/bothCLIConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,eAAO,MAAM,WAAW,qDAAqD,CAAA;AAE7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,QA6BrD;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,iBAAiB,iBAGvD"}
@@ -7,7 +7,7 @@ function builder(yargs) {
7
7
  alias: ["web-port"]
8
8
  },
9
9
  webHost: {
10
- 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",
10
+ description: "The host for the web server to listen on",
11
11
  type: "string",
12
12
  alias: ["web-host"]
13
13
  },
@@ -17,7 +17,7 @@ function builder(yargs) {
17
17
  alias: ["api-port"]
18
18
  },
19
19
  apiHost: {
20
- 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",
20
+ description: "The host for the api server to listen on",
21
21
  type: "string",
22
22
  alias: ["api-host"]
23
23
  },
@@ -1 +1 @@
1
- {"version":3,"file":"bothCLIConfigHandler.d.ts","sourceRoot":"","sources":["../src/bothCLIConfigHandler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,wBAAsB,OAAO,CAAC,OAAO,EAAE,iBAAiB,iBAmEvD"}
1
+ {"version":3,"file":"bothCLIConfigHandler.d.ts","sourceRoot":"","sources":["../src/bothCLIConfigHandler.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnD,wBAAsB,OAAO,CAAC,OAAO,EAAE,iBAAiB,iBA0FvD"}
@@ -3,11 +3,17 @@ import { redwoodFastifyWeb, coerceRootPath } from "@cedarjs/fastify-web";
3
3
  import { getWebHost, getWebPort, getAPIHost, getAPIPort } from "./cliHelpers.js";
4
4
  import { createServer as createApiServer } from "./createServer.js";
5
5
  import { createFastifyInstance } from "./fastify.js";
6
+ import { apiDistServerFileExists } from "./serverFile.js";
6
7
  async function handler(options) {
8
+ if (apiDistServerFileExists()) {
9
+ throw new Error(
10
+ "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"
11
+ );
12
+ }
7
13
  const timeStart = Date.now();
8
14
  console.log(ansis.dim.italic("Starting API and Web Servers..."));
9
- options.webHost ??= getWebHost();
10
- options.webPort ??= getWebPort();
15
+ options.webHost ??= getWebHost({ isPublicSide: true });
16
+ options.webPort ??= getWebPort({ isPublicSide: true });
11
17
  options.apiHost ??= getAPIHost();
12
18
  options.apiPort ??= getAPIPort();
13
19
  options.apiRootPath = coerceRootPath(options.apiRootPath ?? "/");
@@ -1,6 +1,23 @@
1
- export declare function getAPIHost(): string;
2
- export declare function getAPIPort(): number;
1
+ interface SideOptions {
2
+ /**
3
+ * Whether this side receives the deployment's public traffic.
4
+ *
5
+ * Container hosts (Railway, Render, Fly.io, Cloud Run, Heroku) tell an app
6
+ * which host and port to bind with the `HOST` and `PORT` env vars. Only the
7
+ * side serving public traffic falls back to them — when the api and web
8
+ * servers run in the same deployment they would otherwise both bind to
9
+ * `PORT` and collide.
10
+ *
11
+ * The web side is the public one whenever both sides are served together,
12
+ * because it proxies api requests. The api side is only public when it is
13
+ * served on its own.
14
+ */
15
+ isPublicSide?: boolean;
16
+ }
17
+ export declare function getAPIHost({ isPublicSide }?: SideOptions): string;
18
+ export declare function getAPIPort({ isPublicSide }?: SideOptions): number;
3
19
  export declare function getAPIRootPath(): string;
4
- export declare function getWebHost(): string;
5
- export declare function getWebPort(): number;
20
+ export declare function getWebHost({ isPublicSide }?: SideOptions): string;
21
+ export declare function getWebPort({ isPublicSide }?: SideOptions): number;
22
+ export {};
6
23
  //# sourceMappingURL=cliHelpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cliHelpers.d.ts","sourceRoot":"","sources":["../src/cliHelpers.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,WAKzB;AAED,wBAAgB,UAAU,WAIzB;AAED,wBAAgB,cAAc,WAE7B;AAED,wBAAgB,UAAU,WAKzB;AAED,wBAAgB,UAAU,WAIzB"}
1
+ {"version":3,"file":"cliHelpers.d.ts","sourceRoot":"","sources":["../src/cliHelpers.ts"],"names":[],"mappings":"AAEA,UAAU,WAAW;IACnB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,UAAU,CAAC,EAAE,YAAoB,EAAE,GAAE,WAAgB,UAepE;AAED,wBAAgB,UAAU,CAAC,EAAE,YAAoB,EAAE,GAAE,WAAgB,UAcpE;AAED,wBAAgB,cAAc,WAE7B;AAED,wBAAgB,UAAU,CAAC,EAAE,YAAoB,EAAE,GAAE,WAAgB,UAepE;AAED,wBAAgB,UAAU,CAAC,EAAE,YAAoB,EAAE,GAAE,WAAgB,UAcpE"}
@@ -1,24 +1,52 @@
1
- import { getConfig } from "@cedarjs/project-config";
2
- function getAPIHost() {
3
- let host = process.env.REDWOOD_API_HOST;
1
+ import { getConfig, parsePort, readEnvVar } from "@cedarjs/project-config";
2
+ function getAPIHost({ isPublicSide = false } = {}) {
3
+ let host = readEnvVar("CEDAR_API_HOST", {
4
+ deprecatedAlias: "REDWOOD_API_HOST"
5
+ });
6
+ if (isPublicSide) {
7
+ host ??= process.env.HOST;
8
+ }
4
9
  host ??= getConfig().api.host;
5
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
10
+ host ??= "::";
6
11
  return host;
7
12
  }
8
- function getAPIPort() {
9
- return process.env.REDWOOD_API_PORT ? parseInt(process.env.REDWOOD_API_PORT) : getConfig().api.port;
13
+ function getAPIPort({ isPublicSide = false } = {}) {
14
+ const apiPort = readEnvVar("CEDAR_API_PORT", {
15
+ deprecatedAlias: "REDWOOD_API_PORT"
16
+ });
17
+ if (apiPort) {
18
+ return parsePort(apiPort, "CEDAR_API_PORT");
19
+ }
20
+ if (isPublicSide && process.env.PORT) {
21
+ return parsePort(process.env.PORT, "PORT");
22
+ }
23
+ return getConfig().api.port;
10
24
  }
11
25
  function getAPIRootPath() {
12
26
  return process.env.CEDAR_API_ROOT_PATH ?? "/";
13
27
  }
14
- function getWebHost() {
15
- let host = process.env.REDWOOD_WEB_HOST;
28
+ function getWebHost({ isPublicSide = false } = {}) {
29
+ let host = readEnvVar("CEDAR_WEB_HOST", {
30
+ deprecatedAlias: "REDWOOD_WEB_HOST"
31
+ });
32
+ if (isPublicSide) {
33
+ host ??= process.env.HOST;
34
+ }
16
35
  host ??= getConfig().web.host;
17
- host ??= process.env.NODE_ENV === "production" ? "0.0.0.0" : "::";
36
+ host ??= "::";
18
37
  return host;
19
38
  }
20
- function getWebPort() {
21
- return process.env.REDWOOD_WEB_PORT ? parseInt(process.env.REDWOOD_WEB_PORT) : getConfig().web.port;
39
+ function getWebPort({ isPublicSide = false } = {}) {
40
+ const webPort = readEnvVar("CEDAR_WEB_PORT", {
41
+ deprecatedAlias: "REDWOOD_WEB_PORT"
42
+ });
43
+ if (webPort) {
44
+ return parsePort(webPort, "CEDAR_WEB_PORT");
45
+ }
46
+ if (isPublicSide && process.env.PORT) {
47
+ return parsePort(process.env.PORT, "PORT");
48
+ }
49
+ return getConfig().web.port;
22
50
  }
23
51
  export {
24
52
  getAPIHost,
@@ -1 +1 @@
1
- {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../src/createServer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,MAAM,0BAA0B,CAAA;AAsBjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,mBAoHnE"}
1
+ {"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../src/createServer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,mBAAmB,EACnB,MAAM,EAEP,MAAM,0BAA0B,CAAA;AAsBjC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,mBAqHnE"}
@@ -62,7 +62,7 @@ async function createServer(options = {}) {
62
62
  getAsyncStoreInstance().run(/* @__PURE__ */ new Map(), done);
63
63
  });
64
64
  await server.register(cedarFastifyAPI, {
65
- redwood: {
65
+ cedar: {
66
66
  apiRootPath,
67
67
  fastGlobOptions: {
68
68
  ignore: ["**/dist/functions/graphql.js"]
@@ -76,10 +76,10 @@ async function createServer(options = {}) {
76
76
  absolute: true
77
77
  });
78
78
  if (graphqlFunctionPath) {
79
- const { redwoodFastifyGraphQLServer } = await import("./plugins/graphql.js");
79
+ const { cedarFastifyGraphQLServer } = await import("./plugins/graphql.js");
80
80
  const { __cedar_graphqlOptions } = await import(pathToFileURL(graphqlFunctionPath).href);
81
- await server.register(redwoodFastifyGraphQLServer, {
82
- redwood: {
81
+ await server.register(cedarFastifyGraphQLServer, {
82
+ cedar: {
83
83
  apiRootPath,
84
84
  graphql: __cedar_graphqlOptions
85
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createServerHelpers.d.ts","sourceRoot":"","sources":["../src/createServerHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EAChB,MAAM,SAAS,CAAA;AAMhB,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAEtE,MAAM,WAAW,MAAO,SAAQ,eAAe;IAC7C,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAA;IAGpB,iCAAiC;IACjC,MAAM,CAAC,EACH,oBAAoB,CAAC,QAAQ,CAAC,GAC9B,oBAAoB,CAAC,gBAAgB,CAAC,CAAA;IAE1C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;IAE3D;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAEzC,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7D,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,KAAK,0BAA0B,GAAG,QAAQ,CACxC,IAAI,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG;IAClD,oBAAoB,EAAE,oBAAoB,CAAA;CAC3C,CACF,CAAA;AAID,eAAO,MAAM,6BAA6B,EAAE,MAAM,0BAiB9C,CAAA;AAgBJ,wBAAgB,cAAc,CAC5B,OAAO,GAAE,mBAAwB,EACjC,IAAI,CAAC,EAAE,MAAM,EAAE;0BAdS,oBAAoB;GA4F7C"}
1
+ {"version":3,"file":"createServerHelpers.d.ts","sourceRoot":"","sources":["../src/createServerHelpers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EACpB,eAAe,EAChB,MAAM,SAAS,CAAA;AAMhB,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;AAEtE,MAAM,WAAW,MAAO,SAAQ,eAAe;IAC7C,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAA;IAGpB,iCAAiC;IACjC,MAAM,CAAC,EACH,oBAAoB,CAAC,QAAQ,CAAC,GAC9B,oBAAoB,CAAC,gBAAgB,CAAC,CAAA;IAE1C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;IAE3D;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IAEzC,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7D,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,KAAK,0BAA0B,GAAG,QAAQ,CACxC,IAAI,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG;IAClD,oBAAoB,EAAE,oBAAoB,CAAA;CAC3C,CACF,CAAA;AAID,eAAO,MAAM,6BAA6B,EAAE,MAAM,0BAqB9C,CAAA;AAgBJ,wBAAgB,cAAc,CAC5B,OAAO,GAAE,mBAAwB,EACjC,IAAI,CAAC,EAAE,MAAM,EAAE;0BAdS,oBAAoB;GA4F7C"}
@@ -15,8 +15,12 @@ const getDefaultCreateServerOptions = () => ({
15
15
  configureApiServer: () => {
16
16
  },
17
17
  parseArgs: true,
18
- apiHost: getAPIHost(),
19
- apiPort: getAPIPort()
18
+ // `createServer()`'s only callers are `cedarjs-server api` and custom
19
+ // `api/src/server.ts` files — both only ever run with the api side
20
+ // serving public traffic on its own, so they get to use the host's
21
+ // `HOST`/`PORT` env vars.
22
+ apiHost: getAPIHost({ isPublicSide: true }),
23
+ apiPort: getAPIPort({ isPublicSide: true })
20
24
  });
21
25
  function isCustomLoggerInstance(logger) {
22
26
  return !!logger && typeof logger === "object" && "info" in logger;
@@ -2,7 +2,7 @@ import type { Options as FastGlobOptions } from 'fast-glob';
2
2
  import type { FastifyInstance } from 'fastify';
3
3
  import type { Server } from '../createServerHelpers.js';
4
4
  export interface CedarFastifyAPIOptions {
5
- redwood: {
5
+ cedar: {
6
6
  apiRootPath?: string;
7
7
  fastGlobOptions?: FastGlobOptions;
8
8
  discoverFunctionsGlob?: string | string[];
@@ -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;KAI3D,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;IACrC,KAAK,EAAE;QACL,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"}
@@ -5,7 +5,7 @@ import { coerceRootPath } from "@cedarjs/fastify-web/dist/helpers.js";
5
5
  import { loadFastifyConfig } from "../fastify.js";
6
6
  import { lambdaRequestHandler, loadFunctionsFromDist } from "./lambdaLoader.js";
7
7
  async function cedarFastifyAPI(fastify, opts) {
8
- const cedarOptions = opts.redwood ?? {};
8
+ const cedarOptions = opts.cedar ?? {};
9
9
  cedarOptions.apiRootPath ??= "/";
10
10
  cedarOptions.apiRootPath = coerceRootPath(cedarOptions.apiRootPath);
11
11
  cedarOptions.fastGlobOptions ??= {};
@@ -1,10 +1,26 @@
1
1
  import type { FastifyInstance } from 'fastify';
2
2
  import type { GraphQLYogaOptions } from '@cedarjs/graphql-server';
3
- export interface RedwoodFastifyGraphQLOptions {
4
- redwood: {
3
+ export interface CedarFastifyGraphQLOptions {
4
+ cedar: {
5
5
  apiRootPath?: string;
6
6
  graphql?: GraphQLYogaOptions;
7
7
  };
8
8
  }
9
- export declare function redwoodFastifyGraphQLServer(fastify: FastifyInstance, options: RedwoodFastifyGraphQLOptions): Promise<void>;
9
+ export declare function cedarFastifyGraphQLServer(fastify: FastifyInstance, options: CedarFastifyGraphQLOptions): Promise<void>;
10
+ /**
11
+ * Detects errors that indicate the client disconnected before the response
12
+ * finished, rather than a genuine server-side failure.
13
+ *
14
+ * `ERR_STREAM_PREMATURE_CLOSE` can surface from the underlying Node stream
15
+ * closing early. The `DOMException` named `AbortError` is thrown by Yoga
16
+ * when the AbortSignal wired up in `createFetchRequest`'s
17
+ * `reply.raw.on('close', ...)` handler is aborted, which only happens when
18
+ * the client itself has gone away.
19
+ *
20
+ * The `DOMException` check (rather than just `name === 'AbortError'`) is
21
+ * deliberate: a resolver or hook could throw a plain `Error` renamed to
22
+ * `AbortError`, which would otherwise be misclassified as a benign
23
+ * disconnect and hide a real server-side failure behind a 499.
24
+ */
25
+ export declare function isClientDisconnectError(e: unknown): boolean;
10
26
  //# sourceMappingURL=graphql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/plugins/graphql.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAA;AAOhB,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,iBAuHtC"}
1
+ {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../src/plugins/graphql.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAA;AAOhB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE;QACL,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAC7B,CAAA;CACF;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,0BAA0B,iBA0HpC;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAc3D"}