@taujs/react 0.1.1 → 0.1.3

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 CHANGED
@@ -11,3 +11,7 @@
11
11
  React Renderer: CSR, SSR, Streaming SSR
12
12
 
13
13
  https://taujs.dev/
14
+
15
+ A lightweight, production-ready React SSR library with streaming capabilities, built for modern TypeScript applications. Designed as part of the taujs (τjs) ecosystem but fully standalone and runtime-agnostic.
16
+
17
+ https://taujs.dev/renderers/react/
package/dist/index.d.ts CHANGED
@@ -22,10 +22,10 @@ type UILogger = {
22
22
  error: (...args: unknown[]) => void;
23
23
  };
24
24
  type ServerLogs = {
25
- info: (message: string, meta?: unknown) => void;
26
- warn: (message: string, meta?: unknown) => void;
27
- error: (message: string, meta?: unknown) => void;
28
- debug?: (category: string, message: string, meta?: unknown) => void;
25
+ info: (meta?: unknown, message?: string) => void;
26
+ warn: (meta?: unknown, message?: string) => void;
27
+ error: (meta?: unknown, message?: string) => void;
28
+ debug?: (category: string, meta?: unknown, message?: string) => void;
29
29
  child?: (ctx: Record<string, unknown>) => ServerLogs;
30
30
  isDebugEnabled?: (category: string) => boolean;
31
31
  };
@@ -56,6 +56,10 @@ type StreamOptions = {
56
56
  /** Whether to use cork/uncork for batched writes (default: true) */
57
57
  useCork?: boolean;
58
58
  };
59
+ type HeadContext<T extends Record<string, unknown> = Record<string, unknown>> = {
60
+ data: T;
61
+ meta: Record<string, unknown>;
62
+ };
59
63
  type SSRResult = {
60
64
  headContent: string;
61
65
  appHtml: string;
@@ -68,10 +72,7 @@ declare function createRenderer<T extends Record<string, unknown>>({ appComponen
68
72
  appComponent: (props: {
69
73
  location: string;
70
74
  }) => React.ReactElement;
71
- headContent: (ctx: {
72
- data: T;
73
- meta: Record<string, unknown>;
74
- }) => string;
75
+ headContent: (ctx: HeadContext<T>) => string;
75
76
  enableDebug?: boolean;
76
77
  logger?: LoggerLike;
77
78
  streamOptions?: StreamOptions;
@@ -85,4 +86,70 @@ declare function createRenderer<T extends Record<string, unknown>>({ appComponen
85
86
  };
86
87
  };
87
88
 
88
- export { type HydrateAppOptions, type RenderCallbacks, type SSRStore, SSRStoreProvider, type ServerLogs, type StreamOptions, createRenderer, createSSRStore, hydrateApp, useSSRStore };
89
+ /**
90
+ * τjs Client Data Bridge
91
+ *
92
+ * Provides framework-agnostic primitives for accessing route data:
93
+ * - SSR hydration (window.__INITIAL_DATA__)
94
+ * - Client-side fetch (/__taujs/data endpoint)
95
+ *
96
+ * This is a transport layer only. For data orchestration (caching, refetch, etc.),
97
+ * use TanStack Query or similar.
98
+ */
99
+ type RouteData = Record<string, unknown>;
100
+ /**
101
+ * Error thrown when fetchRouteData receives a non-2xx response.
102
+ * Contains structured error information from the server.
103
+ */
104
+ declare class RouteDataError extends Error {
105
+ readonly status: number;
106
+ readonly statusText: string;
107
+ readonly code?: string;
108
+ readonly body?: unknown;
109
+ constructor(message: string, opts: {
110
+ status: number;
111
+ statusText: string;
112
+ code?: string;
113
+ body?: unknown;
114
+ });
115
+ }
116
+ /**
117
+ * Read SSR boot data from window.__INITIAL_DATA__ exactly once.
118
+ * Subsequent calls return null (forces client-side fetch).
119
+ *
120
+ * Returns null on server (typeof window === 'undefined').
121
+ */
122
+ declare function readInitialDataOnce<T extends RouteData = RouteData>(): T | null;
123
+ /**
124
+ * Fetch route data from the τjs data endpoint.
125
+ *
126
+ * Calls: GET /__taujs/data?url=<pathname>
127
+ * Returns: { data: T }
128
+ *
129
+ * Throws RouteDataError on non-2xx responses with structured error info.
130
+ *
131
+ * @example
132
+ * const data = await fetchRouteData('/app/dashboard');
133
+ *
134
+ * @example
135
+ * try {
136
+ * const data = await fetchRouteData('/app/dashboard');
137
+ * } catch (err) {
138
+ * if (err instanceof RouteDataError && err.status === 404) {
139
+ * // Handle not found
140
+ * }
141
+ * }
142
+ */
143
+ declare function fetchRouteData<T extends RouteData = RouteData>(pathname: string, init?: RequestInit): Promise<T>;
144
+ /**
145
+ * Get the current browser path (pathname + search).
146
+ * Does not include hash.
147
+ *
148
+ * Returns null on server (typeof window === 'undefined').
149
+ *
150
+ * @example
151
+ * const path = getCurrentPath(); // "/app/dashboard?tab=overview"
152
+ */
153
+ declare function getCurrentPath(): string | null;
154
+
155
+ export { type HeadContext, type HydrateAppOptions, type RenderCallbacks, type RouteData, RouteDataError, type SSRStore, SSRStoreProvider, type ServerLogs, type StreamOptions, createRenderer, createSSRStore, fetchRouteData, getCurrentPath, hydrateApp, readInitialDataOnce, useSSRStore };
package/dist/index.js CHANGED
@@ -90,10 +90,16 @@ var splitMsgAndMeta = (args) => {
90
90
  };
91
91
  function createUILogger(logger, opts = {}) {
92
92
  const { debugCategory = "ssr", context, preferDebug = false, enableDebug = false } = opts;
93
- if (!enableDebug) return { log: () => {
94
- }, warn: () => {
95
- }, error: () => {
96
- } };
93
+ if (!enableDebug) {
94
+ return {
95
+ log: () => {
96
+ },
97
+ warn: () => {
98
+ },
99
+ error: () => {
100
+ }
101
+ };
102
+ }
97
103
  const looksServer = !!logger && ("info" in logger || "debug" in logger || "child" in logger || "isDebugEnabled" in logger);
98
104
  if (looksServer) {
99
105
  let s = logger;
@@ -103,11 +109,11 @@ function createUILogger(logger, opts = {}) {
103
109
  } catch {
104
110
  }
105
111
  }
106
- const info = s.info ? s.info.bind(s) : (m, meta) => meta ? console.log(m, meta) : console.log(m);
107
- const warn = s.warn ? s.warn.bind(s) : (m, meta) => meta ? console.warn(m, meta) : console.warn(m);
108
- const error = s.error ? s.error.bind(s) : (m, meta) => meta ? console.error(m, meta) : console.error(m);
109
- const debug = s.debug ? s.debug.bind(s) : void 0;
110
- const isDebugEnabled = s.isDebugEnabled ? s.isDebugEnabled.bind(s) : void 0;
112
+ const info = s.info ? (msg, meta) => s.info(meta, msg) : (msg, meta) => meta ? console.log(msg, meta) : console.log(msg);
113
+ const warn = s.warn ? (msg, meta) => s.warn(meta, msg) : (msg, meta) => meta ? console.warn(msg, meta) : console.warn(msg);
114
+ const error = s.error ? (msg, meta) => s.error(meta, msg) : (msg, meta) => meta ? console.error(msg, meta) : console.error(msg);
115
+ const debug = s.debug ? (category, msg, meta) => s.debug(category, meta, msg) : void 0;
116
+ const isDebugEnabled = s.isDebugEnabled ? (category) => s.isDebugEnabled(category) : void 0;
111
117
  return {
112
118
  log: (...args) => {
113
119
  const { msg, meta } = splitMsgAndMeta(args);
@@ -151,10 +157,13 @@ function hydrateApp({
151
157
  onSuccess
152
158
  }) {
153
159
  const { log, warn, error } = createUILogger(logger, { debugCategory: "ssr", context: { scope: "react-hydration" }, enableDebug });
154
- const mountCSR = (rootEl) => {
160
+ const mountCSR = (rootEl, initialData) => {
155
161
  rootEl.innerHTML = "";
162
+ const store = createSSRStore(initialData);
156
163
  const root = createRoot(rootEl);
157
- root.render(/* @__PURE__ */ jsx2(React2.StrictMode, { children: appComponent }));
164
+ root.render(
165
+ /* @__PURE__ */ jsx2(React2.StrictMode, { children: /* @__PURE__ */ jsx2(SSRStoreProvider, { store, children: appComponent }) })
166
+ );
158
167
  };
159
168
  const startHydration = (rootEl, initialData) => {
160
169
  if (enableDebug) log("Hydration started");
@@ -187,8 +196,9 @@ function hydrateApp({
187
196
  }
188
197
  const data = window[dataKey];
189
198
  if (data === void 0) {
199
+ const data2 = {};
190
200
  if (enableDebug) warn(`No initial SSR data at window["${dataKey}"]. Mounting CSR.`);
191
- mountCSR(rootEl);
201
+ mountCSR(rootEl, data2);
192
202
  return;
193
203
  }
194
204
  startHydration(rootEl, data);
@@ -559,10 +569,73 @@ function createRenderer({
559
569
  };
560
570
  return { renderSSR, renderStream };
561
571
  }
572
+
573
+ // src/RouteData.ts
574
+ var RouteDataError = class _RouteDataError extends Error {
575
+ status;
576
+ statusText;
577
+ code;
578
+ body;
579
+ constructor(message, opts) {
580
+ super(message);
581
+ this.name = "RouteDataError";
582
+ this.status = opts.status;
583
+ this.statusText = opts.statusText;
584
+ this.code = opts.code;
585
+ this.body = opts.body;
586
+ Object.setPrototypeOf(this, _RouteDataError.prototype);
587
+ }
588
+ };
589
+ var INITIAL_DATA_KEY = "__INITIAL_DATA__";
590
+ function readInitialDataOnce() {
591
+ if (typeof window === "undefined") return null;
592
+ const w = window;
593
+ const data = w[INITIAL_DATA_KEY];
594
+ if (!data) return null;
595
+ delete w[INITIAL_DATA_KEY];
596
+ return data;
597
+ }
598
+ async function fetchRouteData(pathname, init) {
599
+ if (!pathname) {
600
+ throw new Error("fetchRouteData: pathname is required");
601
+ }
602
+ const url = `/__taujs/data?url=${encodeURIComponent(pathname)}`;
603
+ const res = await fetch(url, {
604
+ credentials: "include",
605
+ ...init
606
+ });
607
+ if (!res.ok) {
608
+ let body2;
609
+ try {
610
+ body2 = await res.json();
611
+ } catch {
612
+ const text = await res.text().catch(() => "");
613
+ body2 = { error: text };
614
+ }
615
+ const json = body2;
616
+ throw new RouteDataError(json.error ?? `Request failed: ${res.status}`, {
617
+ status: res.status,
618
+ statusText: json.statusText ?? res.statusText,
619
+ code: json.code,
620
+ body: body2
621
+ });
622
+ }
623
+ const body = await res.json();
624
+ return body.data ?? {};
625
+ }
626
+ function getCurrentPath() {
627
+ if (typeof window === "undefined") return null;
628
+ const { pathname, search } = window.location;
629
+ return `${pathname}${search}`;
630
+ }
562
631
  export {
632
+ RouteDataError,
563
633
  SSRStoreProvider,
564
634
  createRenderer,
565
635
  createSSRStore,
636
+ fetchRouteData,
637
+ getCurrentPath,
566
638
  hydrateApp,
639
+ readInitialDataOnce,
567
640
  useSSRStore
568
641
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taujs/react",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "taujs | τjs",
5
5
  "author": "Aoede <taujs@aoede.uk.net> (https://www.aoede.uk.net)",
6
6
  "license": "MIT",