@cytario/web 2.1.1 → 2.1.2

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.
@@ -76,9 +76,11 @@ async function runReactRouterPipeline(subcommand, forwardedArgs) {
76
76
  }
77
77
 
78
78
  function runStart(forwardedArgs) {
79
- const serverEntry = resolve(PACKAGE_ROOT, "server.ts");
79
+ // Node 24 won't type-strip under `node_modules/`, so we spawn the
80
+ // precompiled `server.js` (emitted by `npm run build:server`).
81
+ const serverEntry = resolve(PACKAGE_ROOT, "server.js");
80
82
  if (!existsSync(serverEntry)) {
81
- fail(`missing server entry at ${serverEntry}`);
83
+ fail(`missing server entry at ${serverEntry} — run \`npm run build:server\``);
82
84
  }
83
85
  const child = spawn(process.execPath, [serverEntry, ...forwardedArgs], {
84
86
  cwd: PACKAGE_ROOT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cytario/web",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Cytario Web — scientific imaging data browser and viewer for OME-TIFF, OME-Zarr, Parquet and GeoTIFF on S3-compatible storage.",
5
5
  "license": "AGPL-3.0",
6
6
  "sideEffects": false,
@@ -29,7 +29,8 @@
29
29
  "vite-plugins",
30
30
  "prisma.config.ts",
31
31
  "react-router.config.ts",
32
- "server.ts",
32
+ "server.js",
33
+ "server.js.map",
33
34
  "tsconfig.json",
34
35
  "vite.config.ts",
35
36
  "!**/__tests__",
@@ -47,14 +48,17 @@
47
48
  },
48
49
  "scripts": {
49
50
  "prepare": "husky || true",
51
+ "prepublishOnly": "npm run build:server",
50
52
  "prebuild": "node scripts/prebuild.mjs",
51
53
  "build": "node bin/cytario-web.mjs build",
54
+ "build:server": "tsup --config tsup.server.config.ts",
52
55
  "codegen:check": "tsx scripts/codegen-check.ts",
53
56
  "dev": "node bin/cytario-web.mjs dev",
54
57
  "predev": "if [ -L node_modules/@cytario/design ]; then npm unlink @cytario/design --no-save 2>/dev/null && npm install @cytario/design --quiet; fi",
55
58
  "predev:design": "cd ../cytario-design && npm link --quiet && cd - > /dev/null && npm link @cytario/design --quiet && for p in react react-dom react-aria-components; do rm -rf ../cytario-design/node_modules/$p && ln -s \"$(pwd)/node_modules/$p\" ../cytario-design/node_modules/$p; done",
56
59
  "dev:design": "concurrently -n tsup,storybook,web -c blue,magenta,green \"cd ../cytario-design && npx tsup --watch\" \"cd ../cytario-design && npm run dev\" \"node bin/cytario-web.mjs dev\"",
57
60
  "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
61
+ "prestart": "npm run build:server",
58
62
  "start": "node bin/cytario-web.mjs start",
59
63
  "typecheck": "react-router typegen && tsc",
60
64
  "test": "vitest",
@@ -1,28 +1,17 @@
1
+ // server.ts
1
2
  import "dotenv/config";
2
3
  import { createRequestHandler } from "@react-router/express";
3
4
  import compression from "compression";
4
5
  import express from "express";
5
6
  import morgan from "morgan";
6
- import path from "node:path";
7
- import url from "node:url";
8
-
9
- const BUILD_PATH = path.resolve("build/server/index.js");
10
-
11
- const buildModule = await import(url.pathToFileURL(BUILD_PATH).href);
12
-
13
- const app = express();
14
-
15
- // Trust the first proxy (Traefik) so req.protocol reflects X-Forwarded-Proto
16
- // and req.ip reflects X-Forwarded-For. This is critical for secure cookie
17
- // handling when TLS is terminated at the reverse proxy.
7
+ import path from "path";
8
+ import url from "url";
9
+ var BUILD_PATH = path.resolve("build/server/index.js");
10
+ var buildModule = await import(url.pathToFileURL(BUILD_PATH).href);
11
+ var app = express();
18
12
  app.set("trust proxy", 1);
19
-
20
13
  app.disable("x-powered-by");
21
-
22
- let isShuttingDown = false;
23
-
24
- // Kubernetes readiness/liveness probe — before all middleware so it's fast and
25
- // never blocked by compression, static-file serving, or request logging.
14
+ var isShuttingDown = false;
26
15
  app.get("/healthz", (_req, res) => {
27
16
  if (isShuttingDown) {
28
17
  res.status(503).send("shutting down");
@@ -30,54 +19,38 @@ app.get("/healthz", (_req, res) => {
30
19
  res.status(200).send("ok");
31
20
  }
32
21
  });
33
-
34
22
  app.use(compression());
35
-
36
- // Vite-fingerprinted assets — immutable, cache forever
37
23
  app.use(
38
24
  path.posix.join(buildModule.publicPath, "assets"),
39
25
  express.static(path.join(buildModule.assetsBuildDirectory, "assets"), {
40
26
  immutable: true,
41
- maxAge: "1y",
42
- }),
27
+ maxAge: "1y"
28
+ })
43
29
  );
44
-
45
- // Other build assets — short cache
46
30
  app.use(
47
31
  buildModule.publicPath,
48
- express.static(buildModule.assetsBuildDirectory, { maxAge: "1h" }),
32
+ express.static(buildModule.assetsBuildDirectory, { maxAge: "1h" })
49
33
  );
50
-
51
- // Public static files (fonts, logos, etc.)
52
34
  app.use(express.static("public", { maxAge: "1h" }));
53
-
54
35
  app.use(morgan("tiny"));
55
-
56
36
  app.all(
57
37
  "*",
58
38
  createRequestHandler({
59
39
  build: buildModule,
60
- mode: process.env.NODE_ENV,
61
- }),
40
+ mode: process.env.NODE_ENV
41
+ })
62
42
  );
63
-
64
- const port = Number.parseInt(process.env.PORT || "3000", 10);
65
- const host = process.env.HOST || "0.0.0.0";
66
-
67
- const server = app.listen(port, host, () => {
43
+ var port = Number.parseInt(process.env.PORT || "3000", 10);
44
+ var host = process.env.HOST || "0.0.0.0";
45
+ var server = app.listen(port, host, () => {
68
46
  console.log(`[cytario-web] http://${host}:${port}`);
69
47
  });
70
-
71
- // Graceful shutdown on SIGTERM/SIGINT
72
- const SHUTDOWN_DELAY_MS = 5_000;
73
- const DRAIN_TIMEOUT_MS = 15_000;
74
-
48
+ var SHUTDOWN_DELAY_MS = 5e3;
49
+ var DRAIN_TIMEOUT_MS = 15e3;
75
50
  for (const signal of ["SIGTERM", "SIGINT"]) {
76
51
  process.once(signal, () => {
77
52
  console.log(`[cytario-web] ${signal} received, shutting down gracefully`);
78
53
  isShuttingDown = true;
79
-
80
- // Wait for load balancer to deregister the pod before closing connections
81
54
  setTimeout(() => {
82
55
  console.log("[cytario-web] closing server to new connections");
83
56
  server.close((err) => {
@@ -88,8 +61,6 @@ for (const signal of ["SIGTERM", "SIGINT"]) {
88
61
  }
89
62
  process.exit(err ? 1 : 0);
90
63
  });
91
-
92
- // Force exit if connections don't drain in time
93
64
  setTimeout(() => {
94
65
  console.error("[cytario-web] drain timeout, forcing exit");
95
66
  process.exit(1);
@@ -97,3 +68,4 @@ for (const signal of ["SIGTERM", "SIGINT"]) {
97
68
  }, SHUTDOWN_DELAY_MS);
98
69
  });
99
70
  }
71
+ //# sourceMappingURL=server.js.map
package/server.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["server.ts"],"sourcesContent":["import \"dotenv/config\";\nimport { createRequestHandler } from \"@react-router/express\";\nimport compression from \"compression\";\nimport express from \"express\";\nimport morgan from \"morgan\";\nimport path from \"node:path\";\nimport url from \"node:url\";\n\nconst BUILD_PATH = path.resolve(\"build/server/index.js\");\n\nconst buildModule = await import(url.pathToFileURL(BUILD_PATH).href);\n\nconst app = express();\n\n// Trust the first proxy (Traefik) so req.protocol reflects X-Forwarded-Proto\n// and req.ip reflects X-Forwarded-For. This is critical for secure cookie\n// handling when TLS is terminated at the reverse proxy.\napp.set(\"trust proxy\", 1);\n\napp.disable(\"x-powered-by\");\n\nlet isShuttingDown = false;\n\n// Kubernetes readiness/liveness probe — before all middleware so it's fast and\n// never blocked by compression, static-file serving, or request logging.\napp.get(\"/healthz\", (_req, res) => {\n if (isShuttingDown) {\n res.status(503).send(\"shutting down\");\n } else {\n res.status(200).send(\"ok\");\n }\n});\n\napp.use(compression());\n\n// Vite-fingerprinted assets — immutable, cache forever\napp.use(\n path.posix.join(buildModule.publicPath, \"assets\"),\n express.static(path.join(buildModule.assetsBuildDirectory, \"assets\"), {\n immutable: true,\n maxAge: \"1y\",\n }),\n);\n\n// Other build assets — short cache\napp.use(\n buildModule.publicPath,\n express.static(buildModule.assetsBuildDirectory, { maxAge: \"1h\" }),\n);\n\n// Public static files (fonts, logos, etc.)\napp.use(express.static(\"public\", { maxAge: \"1h\" }));\n\napp.use(morgan(\"tiny\"));\n\napp.all(\n \"*\",\n createRequestHandler({\n build: buildModule,\n mode: process.env.NODE_ENV,\n }),\n);\n\nconst port = Number.parseInt(process.env.PORT || \"3000\", 10);\nconst host = process.env.HOST || \"0.0.0.0\";\n\nconst server = app.listen(port, host, () => {\n console.log(`[cytario-web] http://${host}:${port}`);\n});\n\n// Graceful shutdown on SIGTERM/SIGINT\nconst SHUTDOWN_DELAY_MS = 5_000;\nconst DRAIN_TIMEOUT_MS = 15_000;\n\nfor (const signal of [\"SIGTERM\", \"SIGINT\"]) {\n process.once(signal, () => {\n console.log(`[cytario-web] ${signal} received, shutting down gracefully`);\n isShuttingDown = true;\n\n // Wait for load balancer to deregister the pod before closing connections\n setTimeout(() => {\n console.log(\"[cytario-web] closing server to new connections\");\n server.close((err) => {\n if (err) {\n console.error(\"[cytario-web] error during close:\", err);\n } else {\n console.log(\"[cytario-web] all connections drained, exiting\");\n }\n process.exit(err ? 1 : 0);\n });\n\n // Force exit if connections don't drain in time\n setTimeout(() => {\n console.error(\"[cytario-web] drain timeout, forcing exit\");\n process.exit(1);\n }, DRAIN_TIMEOUT_MS).unref();\n }, SHUTDOWN_DELAY_MS);\n });\n}\n"],"mappings":";AAAA,OAAO;AACP,SAAS,4BAA4B;AACrC,OAAO,iBAAiB;AACxB,OAAO,aAAa;AACpB,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB,OAAO,SAAS;AAEhB,IAAM,aAAa,KAAK,QAAQ,uBAAuB;AAEvD,IAAM,cAAc,MAAM,OAAO,IAAI,cAAc,UAAU,EAAE;AAE/D,IAAM,MAAM,QAAQ;AAKpB,IAAI,IAAI,eAAe,CAAC;AAExB,IAAI,QAAQ,cAAc;AAE1B,IAAI,iBAAiB;AAIrB,IAAI,IAAI,YAAY,CAAC,MAAM,QAAQ;AACjC,MAAI,gBAAgB;AAClB,QAAI,OAAO,GAAG,EAAE,KAAK,eAAe;AAAA,EACtC,OAAO;AACL,QAAI,OAAO,GAAG,EAAE,KAAK,IAAI;AAAA,EAC3B;AACF,CAAC;AAED,IAAI,IAAI,YAAY,CAAC;AAGrB,IAAI;AAAA,EACF,KAAK,MAAM,KAAK,YAAY,YAAY,QAAQ;AAAA,EAChD,QAAQ,OAAO,KAAK,KAAK,YAAY,sBAAsB,QAAQ,GAAG;AAAA,IACpE,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,CAAC;AACH;AAGA,IAAI;AAAA,EACF,YAAY;AAAA,EACZ,QAAQ,OAAO,YAAY,sBAAsB,EAAE,QAAQ,KAAK,CAAC;AACnE;AAGA,IAAI,IAAI,QAAQ,OAAO,UAAU,EAAE,QAAQ,KAAK,CAAC,CAAC;AAElD,IAAI,IAAI,OAAO,MAAM,CAAC;AAEtB,IAAI;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB,OAAO;AAAA,IACP,MAAM,QAAQ,IAAI;AAAA,EACpB,CAAC;AACH;AAEA,IAAM,OAAO,OAAO,SAAS,QAAQ,IAAI,QAAQ,QAAQ,EAAE;AAC3D,IAAM,OAAO,QAAQ,IAAI,QAAQ;AAEjC,IAAM,SAAS,IAAI,OAAO,MAAM,MAAM,MAAM;AAC1C,UAAQ,IAAI,wBAAwB,IAAI,IAAI,IAAI,EAAE;AACpD,CAAC;AAGD,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AAEzB,WAAW,UAAU,CAAC,WAAW,QAAQ,GAAG;AAC1C,UAAQ,KAAK,QAAQ,MAAM;AACzB,YAAQ,IAAI,iBAAiB,MAAM,qCAAqC;AACxE,qBAAiB;AAGjB,eAAW,MAAM;AACf,cAAQ,IAAI,iDAAiD;AAC7D,aAAO,MAAM,CAAC,QAAQ;AACpB,YAAI,KAAK;AACP,kBAAQ,MAAM,qCAAqC,GAAG;AAAA,QACxD,OAAO;AACL,kBAAQ,IAAI,gDAAgD;AAAA,QAC9D;AACA,gBAAQ,KAAK,MAAM,IAAI,CAAC;AAAA,MAC1B,CAAC;AAGD,iBAAW,MAAM;AACf,gBAAQ,MAAM,2CAA2C;AACzD,gBAAQ,KAAK,CAAC;AAAA,MAChB,GAAG,gBAAgB,EAAE,MAAM;AAAA,IAC7B,GAAG,iBAAiB;AAAA,EACtB,CAAC;AACH;","names":[]}