@rpcbase/client 0.288.0 → 0.289.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.
@@ -0,0 +1,94 @@
1
+ const getServerApiClient = async (app) => {
2
+ const callRoute = async (app2, method, path, req, res) => {
3
+ return new Promise((resolve, reject) => {
4
+ let isEnded = false;
5
+ const mockReq = {
6
+ ...req,
7
+ method: method.toUpperCase(),
8
+ url: path
9
+ };
10
+ const mockRes = {
11
+ ...res,
12
+ json: (data) => {
13
+ if (!isEnded) {
14
+ isEnded = true;
15
+ resolve(data);
16
+ }
17
+ },
18
+ status: (statusCode) => {
19
+ console.log("Status:", statusCode);
20
+ return mockRes;
21
+ }
22
+ };
23
+ const routerStack = app2.router.stack;
24
+ const firstApiMiddlewareIndex = routerStack.findIndex((layer) => layer.name === "__FIRST_API_MIDDLEWARE__");
25
+ if (!(firstApiMiddlewareIndex > -1)) {
26
+ throw new Error("middleware: __FIRST_API_MIDDLEWARE__ was not found in stack");
27
+ }
28
+ const apiStack = routerStack.slice(firstApiMiddlewareIndex + 1);
29
+ const processLayer = async (index) => {
30
+ if (index >= apiStack.length || isEnded) return;
31
+ const layer = apiStack[index];
32
+ const isNonMatchingLayer = !layer.match(path);
33
+ if (isNonMatchingLayer) {
34
+ await processLayer(index + 1);
35
+ return;
36
+ }
37
+ const runHandler = async (handler) => new Promise((resolveMiddleware, rejectMiddleware) => {
38
+ handler(mockReq, mockRes, (err) => {
39
+ if (err) {
40
+ console.error("Middleware error:", err);
41
+ if (!isEnded) {
42
+ isEnded = true;
43
+ rejectMiddleware(err);
44
+ }
45
+ return;
46
+ }
47
+ resolveMiddleware();
48
+ });
49
+ });
50
+ if (layer.route) {
51
+ if (!layer.route.methods[method.toLowerCase()]) {
52
+ await processLayer(index + 1);
53
+ return;
54
+ }
55
+ if (layer.route.stack.length !== 1) {
56
+ throw new Error(`expected only one handler per route for route: ${layer.route.path}`);
57
+ }
58
+ await runHandler(layer.route.stack[0].handle);
59
+ } else {
60
+ await runHandler(layer.handle);
61
+ }
62
+ if (!isEnded) {
63
+ await processLayer(index + 1);
64
+ }
65
+ };
66
+ processLayer(0);
67
+ setTimeout(() => {
68
+ if (!isEnded) {
69
+ reject("Route handler timed out");
70
+ }
71
+ }, 3e4);
72
+ });
73
+ };
74
+ const createMethod = (method) => {
75
+ return async (path, payload, ctx) => {
76
+ if (!ctx) {
77
+ throw new Error("Context must be provided in SSR mode");
78
+ }
79
+ ctx.req.body = payload;
80
+ return callRoute(app, method, path, ctx.req, ctx.res);
81
+ };
82
+ };
83
+ const apiClient = {
84
+ get: createMethod("get"),
85
+ post: createMethod("post"),
86
+ put: createMethod("put"),
87
+ delete: createMethod("delete")
88
+ };
89
+ return apiClient;
90
+ };
91
+ export {
92
+ getServerApiClient as default,
93
+ getServerApiClient
94
+ };
@@ -1,4 +1,4 @@
1
- export declare const useThrottledMeasure: (throttleDuration?: number) => (import('react-use/lib/useMeasure.js').UseMeasureRef<Element> | {
1
+ export declare const useThrottledMeasure: (throttleDuration?: number) => (import('react-use/esm/useMeasure.js').UseMeasureRef<Element> | {
2
2
  x: number;
3
3
  y: number;
4
4
  width: number;
package/dist/index.js CHANGED
@@ -4,10 +4,16 @@ import posthog from "posthog-js";
4
4
  import { createRoutesFromElements, createBrowserRouter, RouterProvider, useLocation } from "@rpcbase/router";
5
5
  import { hydrateRoot } from "react-dom/client";
6
6
  import { PostHogProvider } from "posthog-js/react/dist/esm/index.js";
7
- import useMeasure from "react-use/lib/useMeasure.js";
7
+ import useMeasure from "react-use/esm/useMeasure.js";
8
8
  let apiClient;
9
9
  const initApiClient = async (args) => {
10
- {
10
+ if (globalThis.__rb_env__.SSR) {
11
+ if (!args) {
12
+ throw new Error("Server args must be provided in SSR mode");
13
+ }
14
+ const { getServerApiClient } = await import("./getServerApiClient-CHA4nyjq.js");
15
+ apiClient = await getServerApiClient(args.app);
16
+ } else {
11
17
  const axios = (await import("axios")).default;
12
18
  const axiosClient = axios.create({
13
19
  baseURL: "/",
@@ -48,6 +54,9 @@ const initApiClient = async (args) => {
48
54
  };
49
55
  const CLEANUP_WAIT_DELAY = 1e3;
50
56
  const cleanupURL = () => {
57
+ if (globalThis.__rb_env__.SSR) {
58
+ return;
59
+ }
51
60
  const runCleanup = () => {
52
61
  setTimeout(() => {
53
62
  const url = new URL(window.location.href);
@@ -68,6 +77,7 @@ const cleanupURL = () => {
68
77
  document.addEventListener("DOMContentLoaded", runCleanup, { once: true });
69
78
  }
70
79
  };
80
+ const isProduction = globalThis.__rb_env__.MODE === "production";
71
81
  const showErrorOverlay = (err) => {
72
82
  const ErrorOverlay = customElements.get("vite-error-overlay");
73
83
  if (!ErrorOverlay) {
@@ -95,6 +105,20 @@ const initWithRoutes = async (routesElement, opts) => {
95
105
  const routes = createRoutesFromElements(routesElement);
96
106
  const router = createBrowserRouter(routes);
97
107
  const toError = (error) => error instanceof Error ? error : new Error(String(error));
108
+ const mentionsHydration = (value, depth = 0) => {
109
+ if (depth > 5) {
110
+ return false;
111
+ }
112
+ if (typeof value === "string") {
113
+ return value.toLowerCase().includes("hydrat");
114
+ }
115
+ if (value instanceof Error) {
116
+ const digest = value.digest;
117
+ const cause = value.cause;
118
+ return mentionsHydration(value.message, depth + 1) || mentionsHydration(digest, depth + 1) || mentionsHydration(cause, depth + 1);
119
+ }
120
+ return false;
121
+ };
98
122
  const phReactHandler = (react_context) => (error, errorInfo) => {
99
123
  const err = toError(error);
100
124
  posthog.captureException(err, {
@@ -105,11 +129,19 @@ const initWithRoutes = async (routesElement, opts) => {
105
129
  console.warn("Uncaught error", err, errorInfo?.componentStack);
106
130
  }
107
131
  };
108
- const hydrationOptions = {
132
+ const hydrationOptions = isProduction ? {
109
133
  onUncaughtError: phReactHandler("uncaught"),
110
134
  onCaughtError: phReactHandler("caught"),
111
135
  onRecoverableError: phReactHandler("recoverable")
112
- };
136
+ } : opts?.devThrowsOnHydrationErrors ? {
137
+ onRecoverableError(error, errorInfo) {
138
+ const err = toError(error);
139
+ if (mentionsHydration(err) || mentionsHydration(errorInfo?.componentStack)) {
140
+ throw err;
141
+ }
142
+ console.error(err, errorInfo?.componentStack);
143
+ }
144
+ } : void 0;
113
145
  hydrateRoot(
114
146
  document.getElementById("root"),
115
147
  /* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(RouterProvider, { router }) }),
@@ -643,7 +675,23 @@ const _snakeCase = /* @__PURE__ */ getDefaultExportFromCjs(snakeCaseExports);
643
675
  const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
644
676
  const getFeatureFlag = async (flag) => {
645
677
  const envKey = `RB_PUBLIC_FLAG_${_snakeCase(flag).toUpperCase()}`;
646
- {
678
+ if (globalThis.__rb_env__.SSR) {
679
+ if (process.env[envKey] !== void 0) {
680
+ return process.env[envKey];
681
+ }
682
+ const startTime = performance.now();
683
+ const { PostHog } = await import("./index.node-f83KBCsj.js");
684
+ const client = new PostHog(
685
+ process.env.RB_PUBLIC_POSTHOG_KEY,
686
+ { host: "https://eu.i.posthog.com" }
687
+ );
688
+ const distinctId = "server";
689
+ console.log("TODO: NYI server side feature flags client distinctId");
690
+ const value = await client.getFeatureFlag(flag, distinctId);
691
+ const endTime = performance.now();
692
+ console.log(`SSR: Feature flag "${flag}" loaded in ${(endTime - startTime).toFixed(2)}ms`);
693
+ return value;
694
+ } else {
647
695
  let waitForFeatureFlags = function() {
648
696
  return new Promise((resolve) => {
649
697
  if (hasLoadedFeatureFlags) {