@jxsuite/server 0.10.2 → 0.11.0

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/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # `@jxsuite/server`
2
+
3
+ > Bun-native development server for Jx projects with live reload, proxy resolution, and Studio API.
4
+
5
+ ## Overview
6
+
7
+ `@jxsuite/server` provides a single `createDevServer()` call that covers live reload, `$src`/`$prototype` proxy resolution (Node.js-side), `timing: "server"` function execution, a Studio filesystem API, and OXC-powered code services.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ bun add @jxsuite/server
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```js
18
+ import { createDevServer } from "@jxsuite/server";
19
+
20
+ await createDevServer({
21
+ root: "./my-project",
22
+ port: 3000,
23
+ builds: [{ entrypoints: ["./index.html"], outdir: "./dist", label: "app" }],
24
+ });
25
+ ```
26
+
27
+ ## Endpoints
28
+
29
+ ### Live reload — `GET /__reload`
30
+
31
+ SSE endpoint. `chokidar` watches the project root and pushes change events to connected browsers, triggering automatic page reload.
32
+
33
+ ### `$prototype`/`$src` proxy — `POST /__jx_resolve__`
34
+
35
+ Resolves external `$prototype` data sources server-side. Supports `.js` modules and `.class.json` schemas. Avoids browser CORS issues and enables Node.js-only dependencies (`fs`, `glob`, etc.).
36
+
37
+ ### Server functions — `POST /__jx_server__`
38
+
39
+ Executes `timing: "server"` function entries during development. The runtime sends `{ $src, $export, arguments }` and receives the return value as JSON.
40
+
41
+ ### Studio filesystem API — `/__studio/*`
42
+
43
+ REST API for the Studio visual builder:
44
+
45
+ | Method | Path | Description |
46
+ | -------------- | ----------------------- | -------------------------- |
47
+ | GET | `/__studio/project` | Project metadata |
48
+ | GET | `/__studio/files` | Directory listing |
49
+ | GET/PUT/DELETE | `/__studio/file` | Read / write / delete file |
50
+ | POST | `/__studio/file/rename` | Rename or move file |
51
+ | GET | `/__studio/components` | Discover custom elements |
52
+ | GET | `/__studio/search` | Search file contents |
53
+
54
+ All file operations are constrained to the project root (path traversal is rejected).
55
+
56
+ ### Code services — `/__studio/code/*`
57
+
58
+ OXC-powered tools for the Studio function body editor:
59
+
60
+ | Endpoint | Tool | Description |
61
+ | ---------------------------- | ---------------- | ------------------- |
62
+ | `POST /__studio/code/format` | oxfmt | Format a JS snippet |
63
+ | `POST /__studio/code/minify` | `Bun.Transpiler` | Minify a JS snippet |
64
+ | `POST /__studio/code/lint` | oxlint | Lint a JS snippet |
65
+
66
+ ## Build pipeline
67
+
68
+ `buildAll(options)` uses `Bun.build` to bundle entrypoints. Incremental rebuilds (`rebuild(changedPath)`) are triggered by the file watcher and reprocess only affected entrypoints.
69
+
70
+ ## Dependencies
71
+
72
+ | Package | Purpose |
73
+ | ---------- | ----------------------------- |
74
+ | `chokidar` | File watching for live reload |
75
+
76
+ Bun built-ins used: `Bun.serve`, `Bun.build`, `Bun.Transpiler`.
77
+
78
+ ## License
79
+
80
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxsuite/server",
3
- "version": "0.10.2",
3
+ "version": "0.11.0",
4
4
  "description": "Jx development server with live reload, server-side proxy, and studio integration",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/server.js CHANGED
@@ -113,6 +113,8 @@ function resolveNpmPath(root, urlPath) {
113
113
  return null;
114
114
  }
115
115
 
116
+ export { resolveNpmPath };
117
+
116
118
  /**
117
119
  * Create and start a Jx development server.
118
120
  *
package/src/studio-api.js CHANGED
@@ -10,6 +10,7 @@
10
10
  import { resolve, relative, basename, dirname, isAbsolute } from "node:path";
11
11
  import { readdir, stat, readFile, writeFile, rename, unlink, mkdir } from "node:fs/promises";
12
12
  import { readFileSync, existsSync } from "node:fs";
13
+ import { transpileJxMarkdown } from "@jxsuite/parser/transpile";
13
14
 
14
15
  /** Normalise a path to forward slashes (Windows `path` module returns backslashes). */
15
16
  const fwd = (/** @type {string} */ p) => p.replaceAll("\\", "/");
@@ -325,13 +326,10 @@ export async function handleStudioApi(req, url, root, activeProjectRoot = null)
325
326
  /** @type {any} */
326
327
  let content;
327
328
  if (match.endsWith(".md")) {
328
- // Parse YAML frontmatter to check for Jx component
329
329
  const source = await readFile(fp, "utf8");
330
330
  const fmMatch = source.match(/^---\r?\n([\s\S]*?)\r?\n---/);
331
331
  if (!fmMatch) continue;
332
- // Quick check: must have tagName with hyphen
333
332
  if (!/^tagName:\s*.+-.+/m.test(fmMatch[1])) continue;
334
- const { transpileJxMarkdown } = await import("@jxsuite/parser/transpile");
335
333
  content = transpileJxMarkdown(source);
336
334
  } else {
337
335
  content = JSON.parse(await readFile(fp, "utf8"));
package/src/watch.js CHANGED
@@ -40,6 +40,8 @@ function shouldIgnore(pathname, ignore) {
40
40
  });
41
41
  }
42
42
 
43
+ export { shouldIgnore };
44
+
43
45
  export const SSE_SCRIPT = `\n<script>new EventSource('/__reload').onmessage=()=>location.reload()</script>`;
44
46
 
45
47
  /** @param {string} html */
@@ -55,7 +57,11 @@ export function injectSSE(html) {
55
57
  * @param {string} root - Absolute path to watch
56
58
  * @param {any[]} builds - Build entries (for selective rebuild)
57
59
  * @param {{ ignore?: string[]; debounce?: number; reloadOnAnyChange?: boolean }} [opts]
58
- * @returns {{ broadcast: () => void; handleSSE: () => Response }}
60
+ * @returns {{
61
+ * broadcast: () => void;
62
+ * handleSSE: () => Response;
63
+ * watcher: import("chokidar").FSWatcher;
64
+ * }}
59
65
  */
60
66
  export function createWatcher(root, builds, opts = {}) {
61
67
  const ignore = opts.ignore ?? DEFAULT_IGNORE;
@@ -132,5 +138,5 @@ export function createWatcher(root, builds, opts = {}) {
132
138
  }, debounceMs);
133
139
  });
134
140
 
135
- return { broadcast, handleSSE };
141
+ return { broadcast, handleSSE, watcher };
136
142
  }