@jxsuite/server 0.28.2 → 0.28.4

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/src/server.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  * proxying, and studio filesystem integration as a single createDevServer() call.
14
14
  */
15
15
 
16
- import { resolve, join } from "node:path";
16
+ import { join, resolve } from "node:path";
17
17
  import { buildAll } from "./build.ts";
18
18
  import { createWatcher, injectSSE } from "./watch.ts";
19
19
  import { handleResolve, handleServerFunction } from "./resolve.ts";
@@ -30,15 +30,18 @@ import { existsSync, readFileSync } from "node:fs";
30
30
  * @param {string} urlPath - URL pathname (e.g. "/pages/@jxsuite/parser/Foo.class.json")
31
31
  * @returns {string | null} Absolute file path or null
32
32
  */
33
- function resolveNpmPath(root: string, urlPath: string) {
33
+ function resolveNpmPath(rootDir: string, urlPath: string) {
34
+ let root = rootDir;
34
35
  let segments = urlPath.split("/").filter(Boolean);
35
36
 
36
37
  // If "node_modules" appears in the path, use everything before it as a subdirectory
37
- // prefix and everything after as the package specifier.
38
- // e.g. /examples/demo/node_modules/@scope/pkg → root=root/examples/demo, pkg=@scope/pkg
38
+ // Prefix and everything after as the package specifier.
39
+ // E.g. /examples/demo/node_modules/@scope/pkg → root=root/examples/demo, pkg=@scope/pkg
39
40
  const nmIdx = segments.indexOf("node_modules");
40
- if (nmIdx >= 0) {
41
- if (nmIdx > 0) root = join(root, ...segments.slice(0, nmIdx));
41
+ if (nmIdx !== -1) {
42
+ if (nmIdx > 0) {
43
+ root = join(root, ...segments.slice(0, nmIdx));
44
+ }
42
45
  segments = segments.slice(nmIdx + 1);
43
46
  }
44
47
 
@@ -53,11 +56,13 @@ function resolveNpmPath(root: string, urlPath: string) {
53
56
  }
54
57
  }
55
58
 
56
- let pkgDir: string = "";
57
- let subpath: string = "";
59
+ let pkgDir = "";
60
+ let subpath = "";
58
61
 
59
62
  if (isScoped) {
60
- if (start < 0 || start + 1 >= segments.length) return null;
63
+ if (start < 0 || start + 1 >= segments.length) {
64
+ return null;
65
+ }
61
66
  const scope = segments[start];
62
67
  const pkg = segments[start + 1];
63
68
  subpath = segments.slice(start + 2).join("/");
@@ -73,11 +78,15 @@ function resolveNpmPath(root: string, urlPath: string) {
73
78
  break;
74
79
  }
75
80
  }
76
- if (start < 0) return null;
81
+ if (start < 0) {
82
+ return null;
83
+ }
77
84
  }
78
85
 
79
86
  const pkgJsonPath = join(pkgDir, "package.json");
80
- if (!existsSync(pkgJsonPath)) return null;
87
+ if (!existsSync(pkgJsonPath)) {
88
+ return null;
89
+ }
81
90
 
82
91
  // If there's a subpath, check package.json exports first
83
92
  if (subpath) {
@@ -86,19 +95,25 @@ function resolveNpmPath(root: string, urlPath: string) {
86
95
  const exportKey = `./${subpath}`;
87
96
  if (pkgJson.exports && pkgJson.exports[exportKey]) {
88
97
  const mapped = join(pkgDir, pkgJson.exports[exportKey]);
89
- if (existsSync(mapped)) return mapped;
98
+ if (existsSync(mapped)) {
99
+ return mapped;
100
+ }
90
101
  }
91
102
  } catch {}
92
103
  // Fall back to direct path
93
104
  const direct = join(pkgDir, subpath);
94
- if (existsSync(direct)) return direct;
105
+ if (existsSync(direct)) {
106
+ return direct;
107
+ }
95
108
  // CEM-relative: subpath may be relative to the custom elements manifest directory
96
109
  try {
97
110
  const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf8"));
98
111
  if (pkgJson.customElements) {
99
112
  const cemDir = pkgJson.customElements.replace(/\/[^/]+$/, "");
100
113
  const cemRelative = join(pkgDir, cemDir, subpath);
101
- if (existsSync(cemRelative)) return cemRelative;
114
+ if (existsSync(cemRelative)) {
115
+ return cemRelative;
116
+ }
102
117
  }
103
118
  } catch {}
104
119
  }
@@ -113,7 +128,9 @@ function resolveNpmPath(root: string, urlPath: string) {
113
128
  pkgJson.main;
114
129
  if (entry && typeof entry === "string") {
115
130
  const resolved = join(pkgDir, entry);
116
- if (existsSync(resolved)) return resolved;
131
+ if (existsSync(resolved)) {
132
+ return resolved;
133
+ }
117
134
  }
118
135
  } catch {}
119
136
 
@@ -162,7 +179,9 @@ export async function createDevServer(options: {
162
179
  middleware,
163
180
  } = options;
164
181
 
165
- if (!root) throw new Error("@jxsuite/server: root is required");
182
+ if (!root) {
183
+ throw new Error("@jxsuite/server: root is required");
184
+ }
166
185
  const absRoot = resolve(root);
167
186
 
168
187
  // ─── Build pipeline ─────────────────────────────────────────────────────────
@@ -177,11 +196,11 @@ export async function createDevServer(options: {
177
196
  if (watch !== false) {
178
197
  const watchOpts = typeof watch === "object" ? watch : {};
179
198
  const watcher = createWatcher(absRoot, builds, watchOpts);
180
- handleSSE = watcher.handleSSE;
199
+ ({ handleSSE } = watcher);
181
200
  }
182
201
 
183
202
  // Bundle cache for npm packages (bare specifier → bundled JS)
184
- const bundleCache: Map<string, string> = new Map();
203
+ const bundleCache = new Map<string, string>();
185
204
 
186
205
  // Active studio project root (set via /__studio/activate, used for static file fallback)
187
206
  let activeProjectRoot: string | null = null;
@@ -189,13 +208,14 @@ export async function createDevServer(options: {
189
208
  // ─── HTTP server ────────────────────────────────────────────────────────────
190
209
 
191
210
  const server = Bun.serve({
192
- port,
193
-
194
211
  async fetch(req) {
195
212
  const url = new URL(req.url);
196
213
  let path = decodeURIComponent(url.pathname);
197
- if (path.endsWith("/")) path += "index.html";
198
- else if (path === "") path = "/index.html";
214
+ if (path.endsWith("/")) {
215
+ path += "index.html";
216
+ } else if (path === "") {
217
+ path = "/index.html";
218
+ }
199
219
 
200
220
  // SSE live reload
201
221
  if (handleSSE && path === "/__reload") {
@@ -207,7 +227,7 @@ export async function createDevServer(options: {
207
227
  return handleResolve(req, absRoot, activeProjectRoot);
208
228
  }
209
229
 
210
- // timing: "server" function proxy
230
+ // Timing: "server" function proxy
211
231
  if (path === "/__jx_server__" && req.method === "POST") {
212
232
  return handleServerFunction(req, absRoot);
213
233
  }
@@ -224,16 +244,22 @@ export async function createDevServer(options: {
224
244
  }
225
245
 
226
246
  const codeRes = await handleCodeApi(req, url);
227
- if (codeRes) return codeRes;
247
+ if (codeRes) {
248
+ return codeRes;
249
+ }
228
250
 
229
251
  const res = await handleStudioApi(req, url, absRoot, activeProjectRoot);
230
- if (res) return res;
252
+ if (res) {
253
+ return res;
254
+ }
231
255
  }
232
256
 
233
257
  // Custom middleware
234
258
  if (middleware) {
235
259
  const res = await middleware(req, url);
236
- if (res) return res;
260
+ if (res) {
261
+ return res;
262
+ }
237
263
  }
238
264
 
239
265
  // Static files
@@ -248,16 +274,16 @@ export async function createDevServer(options: {
248
274
  }
249
275
  }
250
276
 
251
- const file = Bun.file(resolve(absRoot, "." + path));
277
+ const file = Bun.file(resolve(absRoot, `.${path}`));
252
278
  if (!(await file.exists())) {
253
279
  // Try resolving relative to active studio project root
254
280
  if (activeProjectRoot) {
255
- const projectFile = Bun.file(resolve(activeProjectRoot, "." + path));
281
+ const projectFile = Bun.file(resolve(activeProjectRoot, `.${path}`));
256
282
  if (await projectFile.exists()) {
257
283
  return new Response(projectFile);
258
284
  }
259
285
  // Mirror production: public/ contents are served at root
260
- const publicFile = Bun.file(resolve(activeProjectRoot, "public", "." + path));
286
+ const publicFile = Bun.file(resolve(activeProjectRoot, "public", `.${path}`));
261
287
  if (await publicFile.exists()) {
262
288
  return new Response(publicFile);
263
289
  }
@@ -278,8 +304,8 @@ export async function createDevServer(options: {
278
304
  if (result.success && result.outputs.length > 0) {
279
305
  bundleCache.set(cacheKey, await result.outputs[0].text());
280
306
  }
281
- } catch (e) {
282
- console.error("Bundle failed for", resolved, e);
307
+ } catch (error) {
308
+ console.error("Bundle failed for", resolved, error);
283
309
  }
284
310
  }
285
311
  const bundled = bundleCache.get(cacheKey);
@@ -303,6 +329,8 @@ export async function createDevServer(options: {
303
329
 
304
330
  return new Response(file);
305
331
  },
332
+
333
+ port,
306
334
  });
307
335
 
308
336
  console.log(`\n@jxsuite/server listening on http://localhost:${server.port}`);