xanix 1.0.16 → 1.0.18

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 (40) hide show
  1. package/dist/bin/browser.d.ts +0 -0
  2. package/dist/bin/browser.js +1 -0
  3. package/dist/bin/bundler/generateClientEntries.js +1 -1
  4. package/dist/bin/bundler/plugins/XanixDocument/index.js +8 -8
  5. package/dist/bin/bundler/plugins/XanixReactRefresh.js +30 -30
  6. package/dist/bin/bundler/watchServer.js +1 -5
  7. package/dist/bin/cli/browser.d.ts +1 -0
  8. package/dist/bin/cli/browser.js +97 -0
  9. package/dist/bin/cli/build.js +19 -7
  10. package/dist/bin/cli/dev.js +25 -19
  11. package/dist/bin/cli/start.js +17 -2
  12. package/dist/bin/include/logger.d.ts +3 -6
  13. package/dist/bin/include/logger.js +4 -7
  14. package/dist/bin/include/spinner.d.ts +9 -0
  15. package/dist/bin/include/spinner.js +27 -0
  16. package/dist/bin/index.js +0 -0
  17. package/dist/components/Head.js +1 -1
  18. package/dist/hooks/useData.js +7 -6
  19. package/dist/hooks/useRequest copy.d.ts +2 -0
  20. package/dist/hooks/useRequest copy.js +8 -0
  21. package/dist/hooks/useServer/registry.d.ts +0 -7
  22. package/dist/hooks/useServer/registry.js +1 -12
  23. package/dist/hooks/useServer/resource.d.ts +11 -0
  24. package/dist/hooks/useServer/resource.js +49 -0
  25. package/dist/server/index.d.ts +0 -0
  26. package/dist/server/index.js +1 -0
  27. package/dist/server/runtime/createServer.js +11 -12
  28. package/dist/types/assets.d.ts +34 -34
  29. package/dist/types/express.d.ts +7 -7
  30. package/dist/types/globals.d.ts +26 -26
  31. package/dist/types/xanix-virtual.d.ts +41 -41
  32. package/package.json +72 -72
  33. package/dist/db/index.d.ts +0 -2
  34. package/dist/db/index.js +0 -1
  35. package/dist/db/test.d.ts +0 -2
  36. package/dist/db/test.js +0 -1
  37. package/dist/hooks/useServer/context.d.ts +0 -7
  38. package/dist/hooks/useServer/context.js +0 -19
  39. package/dist/hooks/useServer/registerUseServer.d.ts +0 -3
  40. package/dist/hooks/useServer/registerUseServer.js +0 -5
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -1,6 +1,6 @@
1
1
  import { rollup } from "rollup";
2
2
  import path from "node:path";
3
- import { xanixGenerateClientEntryPlugins, } from "./plugins/plugins.js";
3
+ import { xanixGenerateClientEntryPlugins } from "./plugins/plugins.js";
4
4
  import external from "./config/external.js";
5
5
  const root = process.cwd();
6
6
  const generateClientEntries = async ({ rootEntry, }) => {
@@ -27,16 +27,16 @@ export default function xanixDocument() {
27
27
  // Detect common metadata export forms.
28
28
  const hasMetadata = /\bexport\s+(?:const|let|var|function|class)\s+metadata\b/.test(source) || /\bexport\s*\{\s*[^}]*\bmetadata\b[^}]*\}/.test(source);
29
29
  if (hasMetadata) {
30
- return `
31
- import Document, * as DocumentModule from ${JSON.stringify(document)};
32
- export const metadata = DocumentModule.metadata;
33
- export default Document;
30
+ return `
31
+ import Document, * as DocumentModule from ${JSON.stringify(document)};
32
+ export const metadata = DocumentModule.metadata;
33
+ export default Document;
34
34
  `;
35
35
  }
36
- return `
37
- import Document from ${JSON.stringify(document)};
38
- export const metadata = async () => ({});
39
- export default Document;
36
+ return `
37
+ import Document from ${JSON.stringify(document)};
38
+ export const metadata = async () => ({});
39
+ export default Document;
40
40
  `;
41
41
  },
42
42
  };
@@ -14,36 +14,36 @@ export default function xanixReactRefresh(WebSocketPort) {
14
14
  return null;
15
15
  }
16
16
  const code = fs.readFileSync(id, "utf8");
17
- const refreshCode = `
18
- import * as RefreshRuntime from "react-refresh/runtime";
19
-
20
- ${code}
21
-
22
- RefreshRuntime.injectIntoGlobalHook(window);
23
- window.$RefreshReg$ = RefreshRuntime.register;
24
- window.$RefreshSig$ = () => (type) => type;
25
- const ws = new WebSocket("ws://localhost:" + ${WebSocketPort});
26
-
27
-
28
- ws.onmessage = async (event) => {
29
- const files = JSON.parse(event.data);
30
-
31
- for (const file of files) {
32
- if (!file.endsWith(".js")) {
33
- continue;
34
- }
35
-
36
- const url =
37
- getImportUrl(file.replace(/\\.js$/, "")) +
38
- "?t=" +
39
- Date.now();
40
-
41
- await import(url);
42
- }
43
-
44
- RefreshRuntime.performReactRefresh();
45
- ws.send("reload")
46
- };
17
+ const refreshCode = `
18
+ import * as RefreshRuntime from "react-refresh/runtime";
19
+
20
+ ${code}
21
+
22
+ RefreshRuntime.injectIntoGlobalHook(window);
23
+ window.$RefreshReg$ = RefreshRuntime.register;
24
+ window.$RefreshSig$ = () => (type) => type;
25
+ const ws = new WebSocket("ws://localhost:" + ${WebSocketPort});
26
+
27
+
28
+ ws.onmessage = async (event) => {
29
+ const files = JSON.parse(event.data);
30
+
31
+ for (const file of files) {
32
+ if (!file.endsWith(".js")) {
33
+ continue;
34
+ }
35
+
36
+ const url =
37
+ getImportUrl(file.replace(/\\.js$/, "")) +
38
+ "?t=" +
39
+ Date.now();
40
+
41
+ await import(url);
42
+ }
43
+
44
+ RefreshRuntime.performReactRefresh();
45
+ ws.send("reload")
46
+ };
47
47
  `;
48
48
  return {
49
49
  code: refreshCode,
@@ -20,7 +20,6 @@ const watchServer = async ({ rootEntry, onChange, onBuildEnd, onClientEntryChang
20
20
  const input = {
21
21
  index: path.resolve(root, rootEntry),
22
22
  };
23
- // const changedFiles = new Set<string>();
24
23
  const watcher = watch({
25
24
  input,
26
25
  treeshake: true,
@@ -29,9 +28,6 @@ const watchServer = async ({ rootEntry, onChange, onBuildEnd, onClientEntryChang
29
28
  target: "server",
30
29
  development: true,
31
30
  assetExternal: false,
32
- // onChange: (entry) => {
33
- // changedFiles.add(entry);
34
- // },
35
31
  }),
36
32
  ],
37
33
  external(id) {
@@ -53,7 +49,7 @@ const watchServer = async ({ rootEntry, onChange, onBuildEnd, onClientEntryChang
53
49
  watcher.on("event", async (event) => {
54
50
  switch (event.code) {
55
51
  case "BUNDLE_END":
56
- await onBuildEnd?.(event.duration);
52
+ onBuildEnd?.(event.duration);
57
53
  break;
58
54
  case "END":
59
55
  const entries = await getEntries();
@@ -0,0 +1 @@
1
+ export declare function openOrFocusXanix(url?: string): Promise<void>;
@@ -0,0 +1,97 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { spawn } from "node:child_process";
4
+ const CDP_PORT = 9222;
5
+ const XANIX_URL = "http://localhost:3000";
6
+ // Keep a separate profile so Xanix can control its own Chrome instance.
7
+ const XANIX_CHROME_PROFILE = path.join(process.env.LOCALAPPDATA ?? process.cwd(), "Xanix", "Chrome");
8
+ function getChromePath() {
9
+ const paths = [
10
+ path.join(process.env.PROGRAMFILES ?? "", "Google", "Chrome", "Application", "chrome.exe"),
11
+ path.join(process.env["PROGRAMFILES(X86)"] ?? "", "Google", "Chrome", "Application", "chrome.exe"),
12
+ path.join(process.env.LOCALAPPDATA ?? "", "Google", "Chrome", "Application", "chrome.exe"),
13
+ ];
14
+ return paths.find(existsSync);
15
+ }
16
+ async function isCdpRunning() {
17
+ try {
18
+ const response = await fetch(`http://127.0.0.1:${CDP_PORT}/json/version`);
19
+ return response.ok;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ function startChrome(chromePath) {
26
+ spawn(chromePath, [
27
+ `--remote-debugging-port=${CDP_PORT}`,
28
+ `--user-data-dir=${XANIX_CHROME_PROFILE}`,
29
+ "--no-first-run",
30
+ "--no-default-browser-check",
31
+ ], {
32
+ detached: true,
33
+ stdio: "ignore",
34
+ }).unref();
35
+ }
36
+ async function waitForCdp(timeout = 5000) {
37
+ const start = Date.now();
38
+ while (Date.now() - start < timeout) {
39
+ if (await isCdpRunning()) {
40
+ return;
41
+ }
42
+ await new Promise((resolve) => setTimeout(resolve, 100));
43
+ }
44
+ throw new Error("Chrome DevTools Protocol did not start.");
45
+ }
46
+ async function getTabs() {
47
+ const response = await fetch(`http://127.0.0.1:${CDP_PORT}/json/list`);
48
+ if (!response.ok) {
49
+ throw new Error("Unable to get Chrome tabs.");
50
+ }
51
+ return response.json();
52
+ }
53
+ async function activateTab(targetId) {
54
+ const response = await fetch(`http://127.0.0.1:${CDP_PORT}/json/activate/${targetId}`);
55
+ if (!response.ok) {
56
+ throw new Error(`Unable to activate Chrome tab: ${targetId}`);
57
+ }
58
+ }
59
+ async function openNewTab(url) {
60
+ const response = await fetch(`http://127.0.0.1:${CDP_PORT}/json/new?${encodeURIComponent(url)}`, {
61
+ method: "PUT",
62
+ });
63
+ if (!response.ok) {
64
+ throw new Error(`Unable to open Chrome tab: ${url}`);
65
+ }
66
+ }
67
+ function sameUrl(tabUrl, targetUrl) {
68
+ try {
69
+ const a = new URL(tabUrl);
70
+ const b = new URL(targetUrl);
71
+ return (a.protocol === b.protocol &&
72
+ a.hostname === b.hostname &&
73
+ a.port === b.port &&
74
+ a.pathname === b.pathname);
75
+ }
76
+ catch {
77
+ return tabUrl === targetUrl;
78
+ }
79
+ }
80
+ export async function openOrFocusXanix(url = XANIX_URL) {
81
+ const chromePath = getChromePath();
82
+ if (!chromePath) {
83
+ throw new Error("Google Chrome was not found on this computer.");
84
+ }
85
+ // Start Xanix's Chrome instance only if it isn't already running.
86
+ if (!(await isCdpRunning())) {
87
+ startChrome(chromePath);
88
+ await waitForCdp();
89
+ }
90
+ const tabs = await getTabs();
91
+ const existingTab = tabs.find((tab) => tab.type === "page" && sameUrl(tab.url, url));
92
+ if (existingTab) {
93
+ await activateTab(existingTab.id);
94
+ return;
95
+ }
96
+ await openNewTab(url);
97
+ }
@@ -1,19 +1,31 @@
1
1
  import buildServer from "../bundler/buildServer.js";
2
2
  import buildClient from "../bundler/buildClient.js";
3
3
  import pc from "picocolors";
4
- import logger from "../include/logger.js";
4
+ import spinner from "../include/spinner.js";
5
+ import { readFile } from "fs/promises";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const packageJson = JSON.parse(await readFile(path.join(__dirname, "../../../package.json"), "utf8"));
5
10
  const build = async (rootEntry) => {
6
- logger.info(pc.green("Building server..."), "server");
11
+ console.log("");
12
+ console.log(pc.bold(`Xanix ${packageJson.version}`));
13
+ console.log("");
14
+ spinner.start(`Building server...`);
7
15
  const st = Date.now();
8
16
  await buildServer({
9
17
  rootEntry,
10
18
  onBuildEnd: async (entries) => {
11
- logger.info(pc.green("Building client..."), "client");
19
+ spinner.stop(`${pc.green("✓")} Server built in ${pc.dim(Date.now() - st + "ms")}`);
20
+ spinner.start(`Building client...`);
12
21
  const duration = Date.now() - st;
13
- if (entries.length) {
14
- await buildClient(entries);
15
- }
16
- logger.info(pc.green(`Build completed in ${duration}ms`), "complete");
22
+ await buildClient(entries);
23
+ spinner.stop(`${pc.green("✓")} Client built in ${pc.dim(duration + "ms")}`);
24
+ console.log("");
25
+ console.log(pc.bold(pc.green(`Build completed in ${duration}ms`)));
26
+ console.log("");
27
+ console.log(`${pc.dim("Run")} ${pc.cyan("xanix start")} ${pc.dim("to start the server")}`);
28
+ console.log("");
17
29
  },
18
30
  });
19
31
  };
@@ -9,15 +9,17 @@ import outdirs from "../../outdirs.js";
9
9
  import { getWebSocketPort } from "../include/utils.js";
10
10
  import { readFile } from "node:fs/promises";
11
11
  import { fileURLToPath } from "node:url";
12
+ import spinner from "../include/spinner.js";
12
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
14
  const packageJson = JSON.parse(await readFile(path.join(__dirname, "../../../package.json"), "utf8"));
14
- let host;
15
+ const serverInfo = {};
15
16
  let child;
16
17
  let firstStart = false;
17
- let startDuration = 0;
18
+ let serverDuration = 0;
19
+ let clientDuration = 0;
18
20
  const curl = () => {
19
21
  return new Promise((resolve, reject) => {
20
- const child = spawn("curl", [host], {
22
+ const child = spawn("curl", [serverInfo.url], {
21
23
  stdio: "pipe",
22
24
  });
23
25
  child.on("error", reject);
@@ -31,17 +33,16 @@ function runStart() {
31
33
  child = spawn(process.execPath, [filePath], {
32
34
  stdio: ["inherit", "inherit", "inherit", "ipc"],
33
35
  });
34
- child.on("message", (message) => {
35
- if (message.type === "xanix:server:info") {
36
- host = message.host;
36
+ child.on("message", async (message) => {
37
+ if (message.type === "xanix:ready") {
38
+ serverInfo.port = message.port;
39
+ serverInfo.url = message.url;
37
40
  if (!firstStart) {
38
41
  firstStart = true;
39
42
  console.log("");
40
- console.log(pc.blue(`Xanix ${packageJson.version}`));
43
+ console.log(` ${pc.blue("➜ Local:")} ${pc.yellow(serverInfo.url)}`);
41
44
  console.log("");
42
- console.log(`${pc.blue("- Local:")} ${pc.yellow(host)}`);
43
- console.log("");
44
- console.log(pc.green(`✓ Ready in ${startDuration}ms`));
45
+ console.log(pc.green(`Ready in ${serverDuration + clientDuration}ms`));
45
46
  console.log("");
46
47
  }
47
48
  resolve();
@@ -76,40 +77,45 @@ const dev = async (rootEntry) => {
76
77
  let clientChangeFiles = [];
77
78
  let _clientWatcher = null;
78
79
  const clientWatcher = async (entries) => {
80
+ spinner.start("Compiling Client...");
79
81
  _clientWatcher?.close();
80
82
  _clientWatcher = await watchClient(entries, {
81
83
  WebSocketPort,
82
84
  onReady: async () => {
85
+ spinner.stop(`${pc.green("✓")} Client compiled in ${pc.dim(clientDuration + "ms")}`);
83
86
  await startServer();
84
87
  },
85
88
  onChange: async (files) => {
86
89
  clientChangeFiles = files;
87
- await startServer();
88
- broadcast(JSON.stringify(files));
89
- logger.info(`Client ${pc.yellow(files.join(", "))}`, "update");
90
90
  },
91
91
  onBuildEnd(duration) {
92
- startDuration += duration;
92
+ clientDuration += duration;
93
93
  },
94
94
  });
95
95
  };
96
+ console.log("");
97
+ console.log(pc.bold(`Xanix ${packageJson.version}`));
98
+ console.log("");
99
+ spinner.start("Compiling Server...");
96
100
  const watch = await watchServer({
97
101
  rootEntry,
98
102
  onReady: async (entries) => {
103
+ spinner.stop(`${pc.green("✓")} Server compiled in ${pc.dim(serverDuration + "ms")}`);
99
104
  await clientWatcher(entries);
100
105
  },
101
- onChange: async (files, entries) => {
102
- if (!clientChangeFiles.length) {
103
- await startServer();
104
- logger.info(`Server ${pc.yellow(files.join(", "))}`, "update");
106
+ onChange: async (files) => {
107
+ await startServer();
108
+ if (clientChangeFiles.length) {
109
+ broadcast(JSON.stringify(clientChangeFiles));
105
110
  }
111
+ logger.info(`${pc.yellow(files.join(", "))}`, "[update]");
106
112
  clientChangeFiles = [];
107
113
  },
108
114
  onClientEntryChange: async (_entry, entries) => {
109
115
  await clientWatcher(entries);
110
116
  },
111
117
  onBuildEnd(duration) {
112
- startDuration += duration;
118
+ serverDuration += duration;
113
119
  },
114
120
  });
115
121
  process.on("SIGINT", () => {
@@ -1,11 +1,26 @@
1
- import path from "node:path";
2
1
  import { spawn } from "child_process";
2
+ import pc from "picocolors";
3
+ import { readFile } from "fs/promises";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const packageJson = JSON.parse(await readFile(path.join(__dirname, "../../../package.json"), "utf8"));
3
8
  import outdirs from "../../outdirs.js";
4
9
  let child;
5
10
  const start = async () => {
11
+ console.log("");
12
+ console.log(pc.bold(`Xanix ${packageJson.version}`));
13
+ console.log("");
6
14
  const filePath = path.join(outdirs.server, "index.js");
7
15
  child = spawn(process.execPath, [filePath], {
8
- stdio: "inherit",
16
+ stdio: ["inherit", "inherit", "inherit", "ipc"],
17
+ });
18
+ child.on("message", async (message) => {
19
+ if (message.type === "xanix:ready") {
20
+ const url = message.url;
21
+ console.log(` ${pc.blue("➜ Local:")} ${pc.yellow(url)}`);
22
+ console.log("");
23
+ }
9
24
  });
10
25
  process.on("SIGINT", () => {
11
26
  child?.kill();
@@ -1,10 +1,7 @@
1
1
  declare const logger: {
2
2
  info: (msg: string, title?: string) => void;
3
- warn: (msg: string) => void;
4
- error: (msg: string) => void;
5
- warnOnce: (msg: string) => void;
6
- clearScreen: () => void;
7
- hasErrorLogged: () => boolean;
8
- hasWarned: boolean;
3
+ warn: (msg: string, title?: string) => void;
4
+ error: (msg: string, title?: string) => void;
5
+ success: (msg: string, title?: string) => void;
9
6
  };
10
7
  export default logger;
@@ -1,11 +1,8 @@
1
1
  import pc from "picocolors";
2
2
  const logger = {
3
- info: (msg, title = "xanix") => console.log(`${pc.blue(`[${title}]`)} ${msg}`),
4
- warn: (msg) => console.log(`${pc.yellow("[xanix:warn]")} ${pc.yellow(msg)}`),
5
- error: (msg) => console.log(`${pc.red("[xanix:error]")} ${pc.red(msg)}`),
6
- warnOnce: (msg) => console.log(`${pc.yellow("[xanix:warn]")} ${pc.yellow(msg)}`),
7
- clearScreen: () => { },
8
- hasErrorLogged: () => false,
9
- hasWarned: false,
3
+ info: (msg, title = "xanix") => console.log(`${pc.blue(`${title}`)} ${msg}`),
4
+ warn: (msg, title = "xanix:warning") => console.log(`${pc.yellow(`${title}`)} ${pc.yellow(msg)}`),
5
+ error: (msg, title = "xanix:error") => console.log(`${pc.red(`${title}`)} ${pc.red(msg)}`),
6
+ success: (msg, title = "xanix:success") => console.log(`${pc.green(`${title}`)} ${msg}`),
10
7
  };
11
8
  export default logger;
@@ -0,0 +1,9 @@
1
+ declare function startSpinner(message: string): void;
2
+ declare function updateSpinner(message: string): void;
3
+ declare function stopSpinner(message: string): void;
4
+ declare const spinner: {
5
+ start: typeof startSpinner;
6
+ stop: typeof stopSpinner;
7
+ update: typeof updateSpinner;
8
+ };
9
+ export default spinner;
@@ -0,0 +1,27 @@
1
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
2
+ let spinnerTimer;
3
+ let spinnerIndex = 0;
4
+ function startSpinner(message) {
5
+ spinnerIndex = 0;
6
+ process.stdout.write(`${frames[0]} ${message}`);
7
+ spinnerTimer = setInterval(() => {
8
+ spinnerIndex = (spinnerIndex + 1) % frames.length;
9
+ process.stdout.write(`\r${frames[spinnerIndex]} ${message}`);
10
+ }, 80);
11
+ }
12
+ function updateSpinner(message) {
13
+ process.stdout.write(`\r\x1b[K${frames[spinnerIndex]} ${message}`);
14
+ }
15
+ function stopSpinner(message) {
16
+ if (spinnerTimer) {
17
+ clearInterval(spinnerTimer);
18
+ spinnerTimer = undefined;
19
+ }
20
+ process.stdout.write(`\r\x1b[K ${message}\n`);
21
+ }
22
+ const spinner = {
23
+ start: startSpinner,
24
+ stop: stopSpinner,
25
+ update: updateSpinner,
26
+ };
27
+ export default spinner;
package/dist/bin/index.js CHANGED
File without changes
@@ -26,7 +26,7 @@ const Head = ({ children }) => {
26
26
  path,
27
27
  metadata,
28
28
  usedata,
29
- })};
29
+ })};
30
30
  `,
31
31
  } }), _jsx("script", { type: "module", src: `/${outdirs.client}/${__XANIX_CLIENT_RUNTIME_FILE_NAME__}.js` })] }));
32
32
  }
@@ -16,7 +16,7 @@ useData.register = (xanixId, callback) => {
16
16
  const usedata = doc.usedata || {};
17
17
  const itemData = usedata[xanixId];
18
18
  return {
19
- data: `data_${xanixId}`,
19
+ data: itemData,
20
20
  loading: false,
21
21
  reload: async () => { },
22
22
  };
@@ -49,11 +49,12 @@ useData.register = (xanixId, callback) => {
49
49
  setLoading(false);
50
50
  };
51
51
  useEffect(() => {
52
- // if (init.current) {
53
- // reload();
54
- // } else if (!itemData) {
55
- // reload();
56
- // }
52
+ if (init.current) {
53
+ reload();
54
+ }
55
+ else if (!itemData) {
56
+ reload();
57
+ }
57
58
  init.current = true;
58
59
  }, [JSON.stringify(args)]);
59
60
  return {
@@ -0,0 +1,2 @@
1
+ declare const useRequest: () => import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>> | undefined;
2
+ export default useRequest;
@@ -0,0 +1,8 @@
1
+ import useDocument from "./useDocument.js";
2
+ const useRequest = () => {
3
+ const { request } = useDocument();
4
+ if (__XANIX_SERVER__) {
5
+ return request;
6
+ }
7
+ };
8
+ export default useRequest;
@@ -1,7 +0,0 @@
1
- type Uid = string;
2
- export declare const state: Map<string, Function>;
3
- declare const registry: {
4
- set: (uid: Uid, fn: Function) => void;
5
- get: (uid: Uid) => Function | undefined;
6
- };
7
- export default registry;
@@ -1,12 +1 @@
1
- export const state = new Map();
2
- const set = (uid, fn) => {
3
- state.set(uid, fn);
4
- };
5
- const get = (uid) => {
6
- return state.get(uid);
7
- };
8
- const registry = {
9
- set,
10
- get,
11
- };
12
- export default registry;
1
+ "use strict";
@@ -0,0 +1,11 @@
1
+ type ResourceStatus = "pending" | "success" | "error";
2
+ type ServerResource<T = any> = {
3
+ uid: string;
4
+ status: ResourceStatus;
5
+ promise: Promise<T>;
6
+ value?: T;
7
+ error?: unknown;
8
+ read: () => T;
9
+ };
10
+ export declare function getServerResource<T>(pageId: string, uid: string, args: Record<string, any>): ServerResource<T>;
11
+ export {};
@@ -0,0 +1,49 @@
1
+ import { ServerRegistry } from "./registry.js";
2
+ const serverResources = new Map();
3
+ const createResourceKey = (uid, args) => {
4
+ return `${uid}:${JSON.stringify(args ?? {})}`;
5
+ };
6
+ function createResource(promise) {
7
+ const resource = {
8
+ uid: "",
9
+ status: "pending",
10
+ promise,
11
+ read() {
12
+ if (resource.status === "pending") {
13
+ throw resource.promise;
14
+ }
15
+ if (resource.status === "error") {
16
+ throw resource.error;
17
+ }
18
+ return resource.value;
19
+ },
20
+ };
21
+ promise.then((value) => {
22
+ resource.status = "success";
23
+ resource.value = value;
24
+ }, (error) => {
25
+ resource.status = "error";
26
+ resource.error = error;
27
+ });
28
+ return resource;
29
+ }
30
+ export function getServerResource(pageId, uid, args) {
31
+ let resources = serverResources.get(pageId);
32
+ if (!resources) {
33
+ resources = new Map();
34
+ serverResources.set(pageId, resources);
35
+ }
36
+ const key = createResourceKey(uid, args);
37
+ const existing = resources.get(key);
38
+ if (existing) {
39
+ return existing;
40
+ }
41
+ const callback = ServerRegistry.get(uid);
42
+ if (typeof callback !== "function") {
43
+ throw new Error(`useServer(): No server callback registered for uid "${uid}".`);
44
+ }
45
+ const promise = Promise.resolve(callback(args));
46
+ const resource = createResource(promise);
47
+ resources.set(key, resource);
48
+ return resource;
49
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -6,18 +6,17 @@ function createXanixServer({ mode }) {
6
6
  const originalListener = app.listen;
7
7
  app.listen = (...args) => {
8
8
  const server = originalListener.apply(app, args);
9
- if (__XANIX_DEV__) {
10
- const address = server.address();
11
- if (typeof address === "object" && address) {
12
- const host = address.address === "::" || address.address === "0.0.0.0"
13
- ? "localhost"
14
- : address.address;
15
- const port = address.port;
16
- process.send?.({
17
- type: "xanix:server:info",
18
- host: `http://${host}:${port}`,
19
- });
20
- }
9
+ const address = server.address();
10
+ if (typeof address === "object" && address) {
11
+ const host = address.address === "::" || address.address === "0.0.0.0"
12
+ ? "localhost"
13
+ : address.address;
14
+ const port = address.port;
15
+ process.send?.({
16
+ type: "xanix:ready",
17
+ port,
18
+ url: `http://${host}:${port}`,
19
+ });
21
20
  }
22
21
  return server;
23
22
  };
@@ -1,34 +1,34 @@
1
- declare module "*.png" {
2
- const src: string;
3
- export default src;
4
- }
5
-
6
- declare module "*.jpg" {
7
- const src: string;
8
- export default src;
9
- }
10
-
11
- declare module "*.jpeg" {
12
- const src: string;
13
- export default src;
14
- }
15
-
16
- declare module "*.gif" {
17
- const src: string;
18
- export default src;
19
- }
20
-
21
- declare module "*.webp" {
22
- const src: string;
23
- export default src;
24
- }
25
-
26
- declare module "*.svg" {
27
- const src: string;
28
- export default src;
29
- }
30
-
31
- declare module "*.css" {
32
- const src: string;
33
- export default src;
34
- }
1
+ declare module "*.png" {
2
+ const src: string;
3
+ export default src;
4
+ }
5
+
6
+ declare module "*.jpg" {
7
+ const src: string;
8
+ export default src;
9
+ }
10
+
11
+ declare module "*.jpeg" {
12
+ const src: string;
13
+ export default src;
14
+ }
15
+
16
+ declare module "*.gif" {
17
+ const src: string;
18
+ export default src;
19
+ }
20
+
21
+ declare module "*.webp" {
22
+ const src: string;
23
+ export default src;
24
+ }
25
+
26
+ declare module "*.svg" {
27
+ const src: string;
28
+ export default src;
29
+ }
30
+
31
+ declare module "*.css" {
32
+ const src: string;
33
+ export default src;
34
+ }
@@ -1,7 +1,7 @@
1
- import "express-serve-static-core";
2
-
3
- declare module "express-serve-static-core" {
4
- interface Request {}
5
- }
6
-
7
- export {};
1
+ import "express-serve-static-core";
2
+
3
+ declare module "express-serve-static-core" {
4
+ interface Request {}
5
+ }
6
+
7
+ export {};
@@ -1,26 +1,26 @@
1
- declare global {
2
- const __XANIX_CLIENT_RUNTIME_FILE_NAME__: string;
3
- const __XANIX_PAGE_NAVIGATION_HEADER_VALUE__: string;
4
- const __XANIX_CLIENT__: boolean;
5
- const __XANIX_SERVER__: boolean;
6
- const __XANIX_DEV__: boolean;
7
- const __XANIX_PROD__: boolean;
8
-
9
- // XANIX Data
10
- const XANIXDT: {
11
- handlers: Record<string, () => Promise<any>>;
12
- pages: Record<string, string[]>;
13
- initialed: Record<string, boolean>;
14
- };
15
-
16
- // navigation events
17
- const XANIX_NAVIGATE: string;
18
- const XANIX_NAVIGATE_START: string;
19
- const XANIX_NAVIGATE_END: string;
20
- const XANIX_PRELOAD: string;
21
- const XANIX_PRELOAD_START: string;
22
- const XANIX_PRELOAD_END: string;
23
- const XANIX_NAVIGATE_RELOAD: string;
24
- }
25
-
26
- export {};
1
+ declare global {
2
+ const __XANIX_CLIENT_RUNTIME_FILE_NAME__: string;
3
+ const __XANIX_PAGE_NAVIGATION_HEADER_VALUE__: string;
4
+ const __XANIX_CLIENT__: boolean;
5
+ const __XANIX_SERVER__: boolean;
6
+ const __XANIX_DEV__: boolean;
7
+ const __XANIX_PROD__: boolean;
8
+
9
+ // XANIX Data
10
+ const XANIXDT: {
11
+ handlers: Record<string, () => Promise<any>>;
12
+ pages: Record<string, string[]>;
13
+ initialed: Record<string, boolean>;
14
+ };
15
+
16
+ // navigation events
17
+ const XANIX_NAVIGATE: string;
18
+ const XANIX_NAVIGATE_START: string;
19
+ const XANIX_NAVIGATE_END: string;
20
+ const XANIX_PRELOAD: string;
21
+ const XANIX_PRELOAD_START: string;
22
+ const XANIX_PRELOAD_END: string;
23
+ const XANIX_NAVIGATE_RELOAD: string;
24
+ }
25
+
26
+ export {};
@@ -1,41 +1,41 @@
1
- declare module "virtual:xanix-document" {
2
- import type { ComponentType, ReactNode } from "react";
3
- import type { Request, Response } from "express";
4
-
5
- export type XanixDocumentData = {
6
- pageId: string;
7
- props: Record<string, any>;
8
- params: Record<string, string>;
9
- path: string;
10
- metadata: Record<string, any>;
11
- request?: Request;
12
- response?: Response;
13
- };
14
-
15
- export type XanixDocumentProps = {
16
- document: XanixDocumentData;
17
- children?: ReactNode;
18
- page: {
19
- id: string;
20
- props: Record<string, any>;
21
- };
22
- metadata: Record<string, any>;
23
- request?: Request;
24
- response?: Response;
25
- };
26
-
27
- /**
28
- * User-defined document component.
29
- */
30
- const Document: ComponentType<XanixDocumentProps>;
31
-
32
- /**
33
- * Generates document metadata for the current request.
34
- */
35
- export const metadata: (
36
- request: Request,
37
- context: { pageId: string; name: string },
38
- ) => Promise<Record<string, any>>;
39
-
40
- export default Document;
41
- }
1
+ declare module "virtual:xanix-document" {
2
+ import type { ComponentType, ReactNode } from "react";
3
+ import type { Request, Response } from "express";
4
+
5
+ export type XanixDocumentData = {
6
+ pageId: string;
7
+ props: Record<string, any>;
8
+ params: Record<string, string>;
9
+ path: string;
10
+ metadata: Record<string, any>;
11
+ request?: Request;
12
+ response?: Response;
13
+ };
14
+
15
+ export type XanixDocumentProps = {
16
+ document: XanixDocumentData;
17
+ children?: ReactNode;
18
+ page: {
19
+ id: string;
20
+ props: Record<string, any>;
21
+ };
22
+ metadata: Record<string, any>;
23
+ request?: Request;
24
+ response?: Response;
25
+ };
26
+
27
+ /**
28
+ * User-defined document component.
29
+ */
30
+ const Document: ComponentType<XanixDocumentProps>;
31
+
32
+ /**
33
+ * Generates document metadata for the current request.
34
+ */
35
+ export const metadata: (
36
+ request: Request,
37
+ context: { pageId: string; name: string },
38
+ ) => Promise<Record<string, any>>;
39
+
40
+ export default Document;
41
+ }
package/package.json CHANGED
@@ -1,72 +1,72 @@
1
- {
2
- "name": "xanix",
3
- "version": "1.0.16",
4
- "description": "",
5
- "main": "dist/index.js",
6
- "module": "dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "bin": {
9
- "xanix": "dist/bin/index.js"
10
- },
11
- "type": "module",
12
- "files": [
13
- "dist"
14
- ],
15
- "exports": {
16
- ".": {
17
- "import": "./dist/index.js",
18
- "require": "./dist/index.js"
19
- },
20
- "./page": {
21
- "import": "./dist/server/page.js",
22
- "require": "./dist/server/page.js"
23
- },
24
- "./runtime": {
25
- "import": "./dist/server/runtime/index.js",
26
- "require": "./dist/server/runtime/index.js"
27
- }
28
- },
29
- "scripts": {
30
- "dev": "tsc --watch --preserveWatchOutput",
31
- "build": "tsc && node scripts/build-types.js"
32
- },
33
- "keywords": [],
34
- "author": "Naxrul Ahmed",
35
- "license": "ISC",
36
- "dependencies": {
37
- "@babel/generator": "^8.0.0",
38
- "@babel/parser": "^8.0.4",
39
- "@babel/traverse": "^8.0.4",
40
- "@rollup/plugin-commonjs": "^29.0.3",
41
- "@rollup/plugin-json": "^6.1.0",
42
- "@rollup/plugin-node-resolve": "^16.0.3",
43
- "@rollup/plugin-replace": "^6.0.3",
44
- "@rollup/plugin-url": "^8.0.2",
45
- "commander": "^15.0.0",
46
- "dotenv": "^17.4.2",
47
- "esbuild": "^0.28.2",
48
- "express": "^5.2.1",
49
- "picocolors": "^1.1.1",
50
- "react-refresh": "^0.18.0",
51
- "rollup": "^4.62.5",
52
- "rollup-plugin-esbuild": "^6.2.1",
53
- "tslib": "^2.8.1",
54
- "ws": "^8.21.3",
55
- "typescript": "^5.9.3"
56
- },
57
- "devDependencies": {
58
- "@types/babel__core": "^7.20.5",
59
- "@types/express": "^5.0.6",
60
- "@types/node": "^26.2.0",
61
- "@types/prompts": "^2.4.9",
62
- "@types/react": "^19.2.17",
63
- "@types/react-dom": "^19.2.3",
64
- "@types/react-refresh": "^0.14.7",
65
- "@types/ws": "^8.18.1",
66
- "@xanui/core": "^1.3.38",
67
- "@xanui/icons": "^1.1.14",
68
- "@xanui/ui": "^1.2.24",
69
- "react": "^19.2.8",
70
- "react-dom": "^19.2.8"
71
- }
72
- }
1
+ {
2
+ "name": "xanix",
3
+ "version": "1.0.18",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "xanix": "dist/bin/index.js"
10
+ },
11
+ "type": "module",
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.js"
19
+ },
20
+ "./page": {
21
+ "import": "./dist/server/page.js",
22
+ "require": "./dist/server/page.js"
23
+ },
24
+ "./runtime": {
25
+ "import": "./dist/server/runtime/index.js",
26
+ "require": "./dist/server/runtime/index.js"
27
+ }
28
+ },
29
+ "scripts": {
30
+ "dev": "tsc --watch --preserveWatchOutput",
31
+ "build": "tsc && node scripts/build-types.js"
32
+ },
33
+ "keywords": [],
34
+ "author": "Naxrul Ahmed",
35
+ "license": "ISC",
36
+ "dependencies": {
37
+ "@babel/generator": "^8.0.0",
38
+ "@babel/parser": "^8.0.4",
39
+ "@babel/traverse": "^8.0.4",
40
+ "@rollup/plugin-commonjs": "^29.0.3",
41
+ "@rollup/plugin-json": "^6.1.0",
42
+ "@rollup/plugin-node-resolve": "^16.0.3",
43
+ "@rollup/plugin-replace": "^6.0.3",
44
+ "@rollup/plugin-url": "^8.0.2",
45
+ "commander": "^15.0.0",
46
+ "dotenv": "^17.4.2",
47
+ "esbuild": "^0.28.2",
48
+ "express": "^5.2.1",
49
+ "picocolors": "^1.1.1",
50
+ "react-refresh": "^0.18.0",
51
+ "rollup": "^4.62.5",
52
+ "rollup-plugin-esbuild": "^6.2.1",
53
+ "tslib": "^2.8.1",
54
+ "typescript": "^5.9.3",
55
+ "ws": "^8.21.3"
56
+ },
57
+ "devDependencies": {
58
+ "@types/babel__core": "^7.20.5",
59
+ "@types/express": "^5.0.6",
60
+ "@types/node": "^26.2.0",
61
+ "@types/prompts": "^2.4.9",
62
+ "@types/react": "^19.2.17",
63
+ "@types/react-dom": "^19.2.3",
64
+ "@types/react-refresh": "^0.14.7",
65
+ "@types/ws": "^8.18.1",
66
+ "@xanui/core": "^1.3.38",
67
+ "@xanui/icons": "^1.1.14",
68
+ "@xanui/ui": "^1.2.24",
69
+ "react": "^19.2.8",
70
+ "react-dom": "^19.2.8"
71
+ }
72
+ }
@@ -1,2 +0,0 @@
1
- declare const _default: {};
2
- export default _default;
package/dist/db/index.js DELETED
@@ -1 +0,0 @@
1
- export default {};
package/dist/db/test.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare const _default: {};
2
- export default _default;
package/dist/db/test.js DELETED
@@ -1 +0,0 @@
1
- export default {};
@@ -1,7 +0,0 @@
1
- export declare const state: Map<string, Map<string, any>>;
2
- declare const UseServerRegistry: {
3
- getHandlers: (pageId: string) => Map<string, any>;
4
- setData: (pageId: string, uid: string, data: any) => void;
5
- getData: (pageId: string, uid: string) => any;
6
- };
7
- export default UseServerRegistry;
@@ -1,19 +0,0 @@
1
- export const state = new Map();
2
- const getHandlers = (pageId) => {
3
- return state.get(pageId) || new Map();
4
- };
5
- const setData = (pageId, uid, data) => {
6
- const handlers = getHandlers(pageId);
7
- handlers.set(uid, data);
8
- state.set(pageId, handlers);
9
- };
10
- const getData = (pageId, uid) => {
11
- const handlers = getHandlers(pageId);
12
- return handlers.get(uid);
13
- };
14
- const UseServerRegistry = {
15
- getHandlers,
16
- setData,
17
- getData,
18
- };
19
- export default UseServerRegistry;
@@ -1,3 +0,0 @@
1
- import { type UseServerCallback } from "./context.js";
2
- declare const registerUseServer: (uid: string, callback: UseServerCallback) => void;
3
- export default registerUseServer;
@@ -1,5 +0,0 @@
1
- import useServerState from "./context.js";
2
- const registerUseServer = (uid, callback) => {
3
- useServerState.set(uid, callback);
4
- };
5
- export default registerUseServer;