jinrai 1.1.0 → 1.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.
package/index.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { ServerKey } from "./src/front/server-state/useServerState"
2
+
1
3
  export { useServerState } from "./src/front/server-state/useServerState"
2
4
  export { real } from "./src/front/server-state/real"
3
5
  export { useParamsIndex } from "./src/front/url/params/useParamsIndex"
package/lib/bin/bin.js CHANGED
@@ -144,7 +144,7 @@ const getRoutesAndTemplates = (pages, normalize = true, templates = true) => {
144
144
  id,
145
145
  content,
146
146
  mask,
147
- requests: template.input,
147
+ state: template.state,
148
148
  });
149
149
  }
150
150
  return {
@@ -194,10 +194,13 @@ class Task {
194
194
 
195
195
  const pageCollector = async (page) => {
196
196
  const state = await page.evaluate(() => {
197
- return window.__page_requests;
197
+ const state = Object.fromEntries(window.$exportServerStates);
198
+ console.log("BROWSER", state);
199
+ return state;
198
200
  });
201
+ console.log("CLIENT", state);
199
202
  const root = await page.locator("#root").innerHTML();
200
- return { state, root };
203
+ return { root, state };
201
204
  };
202
205
 
203
206
  const getRawPageData = async (url, pages, test = false, debug = false) => {
@@ -233,7 +236,7 @@ const getRawPageData = async (url, pages, test = false, debug = false) => {
233
236
  page.close();
234
237
  result.push({
235
238
  id,
236
- input: state,
239
+ state,
237
240
  mask,
238
241
  root,
239
242
  test: testRoot,
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export type { ServerKey } from "./src/front/server-state/useServerState";
1
2
  export { useServerState } from "./src/front/server-state/useServerState";
2
3
  export { real } from "./src/front/server-state/real";
3
4
  export { useParamsIndex } from "./src/front/url/params/useParamsIndex";
@@ -1,5 +1,6 @@
1
1
  import { Page } from "playwright";
2
+ import { ServerStateMap } from "../../front/server-state/useServerState";
2
3
  export declare const pageCollector: (page: Page) => Promise<{
3
- state: any;
4
+ state: ServerStateMap;
4
5
  root: string;
5
6
  }>;
@@ -1,13 +1,9 @@
1
- export type input = {
2
- method: string;
3
- url: string;
4
- input: object;
5
- };
1
+ import { ServerValue } from "../../front/server-state/serverStates";
6
2
  export interface PageData {
7
3
  id: number;
8
4
  mask: string;
9
5
  root: string;
10
- input: input[];
6
+ state: Record<string, ServerValue>;
11
7
  test?: string;
12
8
  }
13
9
  export declare const getRawPageData: (url: string, pages: string[], test?: boolean, debug?: boolean) => Promise<PageData[]>;
@@ -1,9 +1,10 @@
1
- import { input, PageData } from "../playwright/templates";
1
+ import { ServerStateMap } from "../../front/server-state/useServerState";
2
+ import { PageData } from "../playwright/templates";
2
3
  import { Element } from "./Parser";
3
4
  interface Route {
4
5
  id: number;
5
6
  mask: string;
6
- requests: input[];
7
+ state: ServerStateMap;
7
8
  content: Element[];
8
9
  }
9
10
  export declare const getRoutesAndTemplates: (pages: PageData[], normalize?: boolean, templates?: boolean) => {
@@ -1,5 +1,5 @@
1
1
  const ssr = {
2
- current: navigator.userAgent == "____JINRAI_CLIENT____",
2
+ current: true, //navigator.userAgent == "____JINRAI_CLIENT____",
3
3
  exportParams: false,
4
4
  };
5
5
 
@@ -1,9 +1,6 @@
1
- import { ssr } from './SSR.js';
2
1
  import { sources } from './DataProxy.js';
3
2
 
4
3
  function real(value) {
5
- if (!ssr.current)
6
- return value;
7
4
  switch (typeof value) {
8
5
  case "number":
9
6
  return value;
@@ -1,5 +1,18 @@
1
- import { ServerStateOptions } from "./useServerState";
2
- export type ServerValue = any;
3
- export declare const serverStates: Map<string, string>;
4
- export declare const getServerValue: (key: string, def?: ServerValue) => any[];
5
- export declare const setServerValue: (key: string, value: ServerValue, options?: ServerStateOptions) => import("./DataProxy").DataProxy;
1
+ import { ServerKey } from "./useServerState";
2
+ interface Request {
3
+ method: string;
4
+ url: string;
5
+ input: any;
6
+ }
7
+ export type ServerValue = {
8
+ value: any;
9
+ options?: {
10
+ source: {
11
+ request?: Request;
12
+ };
13
+ };
14
+ };
15
+ export declare const serverStates: Map<string, ServerValue>;
16
+ export declare const getServerValue: (key?: ServerKey, def?: ServerValue["value"], options?: ServerValue["options"]) => any[];
17
+ export declare const setServerValue: (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) => import("./DataProxy").DataProxy;
18
+ export {};
@@ -1,29 +1,40 @@
1
+ import { encode } from 'js-base64';
1
2
  import createDataProxy from './DataProxy.js';
2
3
  import { ssr } from './SSR.js';
3
4
 
4
5
  const serverStates = new Map();
5
6
  if (window != undefined) {
7
+ console.log("init $exportServerStates");
6
8
  // @ts-ignore
7
- window.__serverExportStates__ = serverStates;
9
+ window.$exportServerStates = serverStates;
8
10
  }
9
- const getServerValue = (key, def) => {
10
- if (key == "") {
11
+ const getIdent = (key) => {
12
+ {
13
+ ssr.exportParams = true;
14
+ }
15
+ const result = Array.isArray(key) ? JSON.stringify(key) : key.toString();
16
+ {
17
+ ssr.exportParams = false;
18
+ }
19
+ return encode(result);
20
+ };
21
+ const getServerValue = (key, def, options) => {
22
+ if (key == undefined) {
11
23
  return [def, false];
12
24
  }
25
+ const ident = getIdent(key);
26
+ serverStates.set(ident, { options, value: !options?.source ? def : undefined });
13
27
  // @ts-ignore
14
- if (window != undefined && window?.__serverInitialStates__ && key in window.__serverInitialStates__) {
28
+ if (window != undefined && window?.__serverInitialStates__ && ident in window.__serverInitialStates__) {
15
29
  // @ts-ignore
16
- return [window.__serverInitialStates__[key], true];
30
+ return [window.__serverInitialStates__[ident], true];
17
31
  }
18
- return [serverStates.get(key) ?? def, false];
32
+ return [def, false];
19
33
  };
20
34
  const setServerValue = (key, value, options) => {
21
- ssr.exportParams = true;
22
- const json = JSON.stringify({ value, options });
23
- ssr.exportParams = false;
24
- console.log(key, json);
25
- serverStates.set(key, json);
26
- return createDataProxy(value, `${key}@`);
35
+ const ident = getIdent(key);
36
+ serverStates.set(ident, { options, value: !options?.source ? value : undefined });
37
+ return createDataProxy(value, `${ident}@`);
27
38
  };
28
39
 
29
40
  export { getServerValue, serverStates, setServerValue };
@@ -1,14 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from "react";
2
2
  import { ServerValue } from "./serverStates";
3
- interface Request {
4
- method: string;
5
- url: string;
6
- input: any;
7
- }
8
- export interface ServerStateOptions {
9
- source: {
10
- request?: Request;
11
- };
12
- }
13
- export declare const useServerState: <T extends ServerValue>(serverKey: string, initialValue: T, options?: ServerStateOptions) => [T, Dispatch<SetStateAction<T>>, () => boolean];
14
- export {};
3
+ export type ServerStateMap = Record<string, ServerValue>;
4
+ export type ServerKey = string | string[];
5
+ export declare const useServerState: <T extends ServerValue["value"]>(serverKey: ServerKey | undefined, initialValue: T, options?: ServerValue["options"]) => [T, Dispatch<SetStateAction<T>>, () => boolean];
@@ -3,13 +3,13 @@ import { ssr } from './SSR.js';
3
3
  import { getServerValue, setServerValue } from './serverStates.js';
4
4
 
5
5
  const useServerState = (serverKey, initialValue, options) => {
6
- const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue);
6
+ const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue, options);
7
7
  const [value, setStateValue] = useState(serverValue);
8
8
  const [isInit, setIsInit] = useState(isInitOnServer);
9
9
  const setValue = (value) => {
10
10
  setStateValue((prev) => {
11
11
  const result = value instanceof Function ? value(prev) : value;
12
- if (serverKey && ssr.current) {
12
+ if (serverKey != undefined && ssr.current) {
13
13
  return setServerValue(serverKey, result, options);
14
14
  }
15
15
  return result;
@@ -1,13 +1,12 @@
1
1
  import { useContext, useMemo } from 'react';
2
2
  import { getJinraiValue } from '../search/useSearchValue.js';
3
3
  import { JinraiContext } from '../JinraiContext.js';
4
- import { ssr } from '../../server-state/SSR.js';
5
4
 
6
5
  const useParamsIndex = (index, def = "") => {
7
6
  const { deps } = useContext(JinraiContext);
8
7
  const value = useMemo(() => location.pathname.split("/")[index + 1] ?? def, deps ? deps : []);
9
8
  const stableValue = useMemo(() => {
10
- return ssr.current ? value.bindSource(getJinraiValue(index.toString(), "paramsIndex", "", def)) : value;
9
+ return value.bindSource(getJinraiValue(index.toString(), "paramsIndex", "", def)) ;
11
10
  }, [value]);
12
11
  return stableValue;
13
12
  };
@@ -1,13 +1,12 @@
1
1
  import { useContext, useMemo } from 'react';
2
2
  import { JinraiContext } from '../JinraiContext.js';
3
- import { ssr } from '../../server-state/SSR.js';
4
3
  import { getJinraiValue } from './useSearchValue.js';
5
4
 
6
5
  const useSearch = () => {
7
6
  const { deps } = useContext(JinraiContext);
8
7
  const value = useMemo(() => location.search.substring(1), deps ? deps : []);
9
8
  const stableValue = useMemo(() => {
10
- return ssr.current ? value.bindSource(getJinraiValue("", "search", "", "")) : value;
9
+ return value.bindSource(getJinraiValue("", "search", "", "")) ;
11
10
  }, [value]);
12
11
  return stableValue;
13
12
  };
@@ -3,9 +3,12 @@ import { useMemo } from 'react';
3
3
  import { ssr } from '../../server-state/SSR.js';
4
4
 
5
5
  function toJSON() {
6
- // @ts-ignore
7
- if (ssr.exportParams)
8
- return this.source;
6
+ if (ssr.exportParams) {
7
+ // @ts-ignore
8
+ const source = this.source;
9
+ // @ts-ignore
10
+ return source ? source : this;
11
+ }
9
12
  // @ts-ignore
10
13
  return this;
11
14
  }
@@ -30,7 +33,7 @@ function toJSON() {
30
33
  const useSearchValue = (key, defaultValue) => {
31
34
  const [value, setValue] = useQueryState(key, { defaultValue });
32
35
  const stableValue = useMemo(() => {
33
- return ssr.current ? value.bindSource(getJinraiValue(key, "searchString", "", defaultValue)) : value;
36
+ return value.bindSource(getJinraiValue(key, "searchString", "", defaultValue)) ;
34
37
  }, [key, value]);
35
38
  return [stableValue, setValue];
36
39
  };
@@ -38,7 +41,7 @@ const useSearchArray = (key, defaultValue = [], separator = ",") => {
38
41
  const stableDefault = useMemo(() => defaultValue, []);
39
42
  const [value, setValue] = useQueryState(key, parseAsArrayOf(parseAsString, separator).withDefault(stableDefault));
40
43
  const stableValue = useMemo(() => {
41
- return ssr.current ? value.bindSource(getJinraiValue(key, "searchArray", separator, defaultValue)) : value;
44
+ return value.bindSource(getJinraiValue(key, "searchArray", separator, defaultValue)) ;
42
45
  }, [key, value]);
43
46
  return [stableValue, setValue];
44
47
  };
@@ -1,8 +1,4 @@
1
- import { ssr } from '../server-state/SSR.js';
2
-
3
1
  const Custom = ({ name, props, children }) => {
4
- if (!ssr.current)
5
- return children;
6
2
  return `<custom>${JSON.stringify({ name, props })}<custom>`;
7
3
  };
8
4
 
@@ -6,10 +6,13 @@ import { writeFile } from 'fs/promises';
6
6
 
7
7
  const pageCollector = async (page) => {
8
8
  const state = await page.evaluate(() => {
9
- return window.__page_requests;
9
+ const state = Object.fromEntries(window.$exportServerStates);
10
+ console.log("BROWSER", state);
11
+ return state;
10
12
  });
13
+ console.log("CLIENT", state);
11
14
  const root = await page.locator("#root").innerHTML();
12
- return { state, root };
15
+ return { root, state };
13
16
  };
14
17
 
15
18
  const normalizeHtmlWhitespace = (html) => {
@@ -136,7 +139,7 @@ const getRoutesAndTemplates = (pages, normalize = true, templates = true) => {
136
139
  id,
137
140
  content,
138
141
  mask,
139
- requests: template.input,
142
+ state: template.state,
140
143
  });
141
144
  }
142
145
  return {
@@ -190,7 +193,7 @@ function hydration() {
190
193
  await page.goto(debugUrl + currentUrl);
191
194
  await page.waitForLoadState("networkidle");
192
195
  const { root } = await pageCollector(page);
193
- const { routes } = getRoutesAndTemplates([{ id: 1, input: [], mask: currentUrl, root }], true, false);
196
+ const { routes } = getRoutesAndTemplates([{ id: 1, state: {}, mask: currentUrl, root }], true, false);
194
197
  console.log({ routes });
195
198
  writeFile("./routs.json", JSON.stringify(routes, null, 2));
196
199
  const result = html.replace("<!--app-html-->", root);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinrai",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "A powerful library that analyzes your modern web application and automatically generates a perfectly rendered, static snapshot of its pages. Experience unparalleled loading speed and SEO clarity without the complexity of traditional SSR setups. Simply point Jinrai at your SPA and witness divine speed.",
5
5
  "main": "lib/index.ts",
6
6
  "scripts": {
@@ -18,6 +18,7 @@
18
18
  "@rollup/plugin-typescript": "^11.1.6",
19
19
  "@types/node": "^24.5.2",
20
20
  "@types/ora": "^3.1.0",
21
+ "@types/react": "^19.2.7",
21
22
  "@vitest/coverage-v8": "^4.0.8",
22
23
  "dotenv": "^17.2.2",
23
24
  "nodemon": "^3.1.10",
@@ -33,6 +34,8 @@
33
34
  "dependencies": {
34
35
  "@types/prettier": "^2.7.3",
35
36
  "jiti": "^2.6.0",
37
+ "js-base64": "^3.7.8",
38
+ "nuqs": "^2.8.1",
36
39
  "ora": "^9.0.0",
37
40
  "playwright": "^1.55.1",
38
41
  "prettier": "^3.6.2"
@@ -1,11 +1,16 @@
1
1
  import { Page } from "playwright"
2
+ import { ServerStateMap } from "../../front/server-state/useServerState"
2
3
 
3
- export const pageCollector = async (page: Page) => {
4
+ export const pageCollector = async (page: Page): Promise<{ state: ServerStateMap; root: string }> => {
4
5
  const state = await page.evaluate(() => {
5
- return (window as any).__page_requests
6
+ const state = Object.fromEntries((window as any).$exportServerStates)
7
+ console.log("BROWSER", state)
8
+
9
+ return state
6
10
  })
7
11
 
12
+ console.log("CLIENT", state)
8
13
  const root = await page.locator("#root").innerHTML()
9
14
 
10
- return { state, root }
15
+ return { root, state }
11
16
  }
@@ -2,18 +2,13 @@ import { chromium } from "playwright"
2
2
  import Task from "../ui/task"
3
3
  import { spinners } from "ora"
4
4
  import { pageCollector } from "./pageCollector"
5
-
6
- export type input = {
7
- method: string
8
- url: string
9
- input: object
10
- }
5
+ import { ServerValue } from "../../front/server-state/serverStates"
11
6
 
12
7
  export interface PageData {
13
8
  id: number
14
9
  mask: string
15
10
  root: string
16
- input: input[]
11
+ state: Record<string, ServerValue>
17
12
  test?: string
18
13
  }
19
14
 
@@ -70,7 +65,7 @@ export const getRawPageData = async (
70
65
 
71
66
  result.push({
72
67
  id,
73
- input: state,
68
+ state,
74
69
  mask,
75
70
  root,
76
71
  test: testRoot,
@@ -1,10 +1,11 @@
1
- import { input, PageData } from "../playwright/templates"
1
+ import { ServerStateMap } from "../../front/server-state/useServerState"
2
+ import { PageData } from "../playwright/templates"
2
3
  import { Element, Parser } from "./Parser"
3
4
 
4
5
  interface Route {
5
6
  id: number
6
7
  mask: string
7
- requests: input[]
8
+ state: ServerStateMap
8
9
  content: Element[]
9
10
  }
10
11
 
@@ -21,7 +22,7 @@ export const getRoutesAndTemplates = (pages: PageData[], normalize: boolean = tr
21
22
  id,
22
23
  content,
23
24
  mask,
24
- requests: template.input,
25
+ state: template.state,
25
26
  })
26
27
  }
27
28
 
@@ -1,4 +1,4 @@
1
1
  export const ssr = {
2
- current: navigator.userAgent == "____JINRAI_CLIENT____",
2
+ current: true, //navigator.userAgent == "____JINRAI_CLIENT____",
3
3
  exportParams: false,
4
4
  }
@@ -1,36 +1,61 @@
1
+ import { encode } from "js-base64"
1
2
  import createDataProxy from "./DataProxy"
2
3
  import { ssr } from "./SSR"
3
- import { ServerStateOptions } from "./useServerState"
4
+ import { ServerKey } from "./useServerState"
4
5
 
5
- export type ServerValue = any
6
+ interface Request {
7
+ method: string
8
+ url: string
9
+ input: any
10
+ }
11
+
12
+ export type ServerValue = {
13
+ value: any
14
+ options?: {
15
+ source: {
16
+ request?: Request
17
+ }
18
+ }
19
+ }
20
+
21
+ export const serverStates = new Map<string, ServerValue>()
6
22
 
7
- export const serverStates = new Map<string, string>()
8
23
  if (window != undefined) {
24
+ console.log("init $exportServerStates")
9
25
  // @ts-ignore
10
- window.__serverExportStates__ = serverStates
26
+ window.$exportServerStates = serverStates
27
+ }
28
+
29
+ const getIdent = (key: ServerKey): string => {
30
+ if (ssr.current) {
31
+ ssr.exportParams = true
32
+ }
33
+ const result = Array.isArray(key) ? JSON.stringify(key) : key.toString()
34
+ if (ssr.current) {
35
+ ssr.exportParams = false
36
+ }
37
+
38
+ return encode(result)
11
39
  }
12
40
 
13
- export const getServerValue = (key: string, def?: ServerValue) => {
14
- if (key == "") {
41
+ export const getServerValue = (key?: ServerKey, def?: ServerValue["value"], options?: ServerValue["options"]) => {
42
+ if (key == undefined) {
15
43
  return [def, false]
16
44
  }
45
+ const ident = getIdent(key)
46
+ serverStates.set(ident, { options, value: !options?.source ? def : undefined })
17
47
 
18
48
  // @ts-ignore
19
- if (window != undefined && window?.__serverInitialStates__ && key in window.__serverInitialStates__) {
49
+ if (window != undefined && window?.__serverInitialStates__ && ident in window.__serverInitialStates__) {
20
50
  // @ts-ignore
21
- return [window.__serverInitialStates__[key], true]
51
+ return [window.__serverInitialStates__[ident], true]
22
52
  }
23
53
 
24
- return [serverStates.get(key) ?? def, false]
54
+ return [def, false]
25
55
  }
26
56
 
27
- export const setServerValue = (key: string, value: ServerValue, options?: ServerStateOptions) => {
28
- ssr.exportParams = true
29
- const json = JSON.stringify({ value, options })
30
- ssr.exportParams = false
31
-
32
- console.log(key, json)
33
- serverStates.set(key, json)
34
-
35
- return createDataProxy(value, `${key}@`)
57
+ export const setServerValue = (key: ServerKey, value: ServerValue["value"], options?: ServerValue["options"]) => {
58
+ const ident = getIdent(key)
59
+ serverStates.set(ident, { options, value: !options?.source ? value : undefined })
60
+ return createDataProxy(value, `${ident}@`)
36
61
  }
@@ -2,24 +2,15 @@ import { Dispatch, SetStateAction, useState } from "react"
2
2
  import { ssr } from "./SSR"
3
3
  import { getServerValue, ServerValue, setServerValue } from "./serverStates"
4
4
 
5
- interface Request {
6
- method: string
7
- url: string
8
- input: any
9
- }
10
-
11
- export interface ServerStateOptions {
12
- source: {
13
- request?: Request
14
- }
15
- }
5
+ export type ServerStateMap = Record<string, ServerValue>
6
+ export type ServerKey = string | string[]
16
7
 
17
- export const useServerState = <T extends ServerValue>(
18
- serverKey: string,
8
+ export const useServerState = <T extends ServerValue["value"]>(
9
+ serverKey: ServerKey | undefined,
19
10
  initialValue: T,
20
- options?: ServerStateOptions,
11
+ options?: ServerValue["options"],
21
12
  ) => {
22
- const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue)
13
+ const [serverValue, isInitOnServer] = getServerValue(serverKey, initialValue, options)
23
14
  const [value, setStateValue] = useState(serverValue)
24
15
  const [isInit, setIsInit] = useState(isInitOnServer)
25
16
 
@@ -27,7 +18,7 @@ export const useServerState = <T extends ServerValue>(
27
18
  setStateValue((prev: T) => {
28
19
  const result = value instanceof Function ? (value as (prevState: T) => T)(prev) : value
29
20
 
30
- if (serverKey && ssr.current) {
21
+ if (serverKey != undefined && ssr.current) {
31
22
  return setServerValue(serverKey, result, options)
32
23
  }
33
24
 
@@ -16,8 +16,12 @@ declare global {
16
16
  }
17
17
 
18
18
  function toJSON() {
19
- // @ts-ignore
20
- if (ssr.exportParams) return this.source
19
+ if (ssr.exportParams) {
20
+ // @ts-ignore
21
+ const source = this.source
22
+ // @ts-ignore
23
+ return source ? source : this
24
+ }
21
25
  // @ts-ignore
22
26
  return this
23
27
  }
package/vite/plugin.ts CHANGED
@@ -62,7 +62,7 @@ export function hydration(): Plugin {
62
62
  await page.waitForLoadState("networkidle")
63
63
 
64
64
  const { root } = await pageCollector(page)
65
- const { routes } = getRoutesAndTemplates([{ id: 1, input: [], mask: currentUrl, root }], true, false)
65
+ const { routes } = getRoutesAndTemplates([{ id: 1, state: {}, mask: currentUrl, root }], true, false)
66
66
 
67
67
  console.log({ routes })
68
68
  writeFile("./routs.json", JSON.stringify(routes, null, 2))