request-iframe 0.0.2 → 0.0.4

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 (84) hide show
  1. package/QUICKSTART.CN.md +35 -8
  2. package/QUICKSTART.md +35 -8
  3. package/README.CN.md +439 -36
  4. package/README.md +496 -30
  5. package/library/__tests__/channel.test.ts +420 -0
  6. package/library/__tests__/coverage-branches.test.ts +356 -0
  7. package/library/__tests__/debug.test.ts +588 -0
  8. package/library/__tests__/dispatcher.test.ts +481 -0
  9. package/library/__tests__/requestIframe.test.ts +3163 -185
  10. package/library/__tests__/server.test.ts +738 -0
  11. package/library/__tests__/stream.test.ts +46 -15
  12. package/library/api/client.d.ts.map +1 -1
  13. package/library/api/client.js +12 -6
  14. package/library/api/server.d.ts +4 -3
  15. package/library/api/server.d.ts.map +1 -1
  16. package/library/api/server.js +25 -7
  17. package/library/constants/index.d.ts +14 -4
  18. package/library/constants/index.d.ts.map +1 -1
  19. package/library/constants/index.js +15 -7
  20. package/library/constants/messages.d.ts +37 -0
  21. package/library/constants/messages.d.ts.map +1 -1
  22. package/library/constants/messages.js +38 -1
  23. package/library/core/client-server.d.ts +105 -0
  24. package/library/core/client-server.d.ts.map +1 -0
  25. package/library/core/client-server.js +289 -0
  26. package/library/core/client.d.ts +53 -10
  27. package/library/core/client.d.ts.map +1 -1
  28. package/library/core/client.js +529 -207
  29. package/library/core/request.d.ts +3 -1
  30. package/library/core/request.d.ts.map +1 -1
  31. package/library/core/request.js +2 -1
  32. package/library/core/response.d.ts +30 -4
  33. package/library/core/response.d.ts.map +1 -1
  34. package/library/core/response.js +176 -100
  35. package/library/core/server-client.d.ts +3 -1
  36. package/library/core/server-client.d.ts.map +1 -1
  37. package/library/core/server-client.js +19 -9
  38. package/library/core/server.d.ts +22 -1
  39. package/library/core/server.d.ts.map +1 -1
  40. package/library/core/server.js +304 -55
  41. package/library/index.d.ts +3 -2
  42. package/library/index.d.ts.map +1 -1
  43. package/library/index.js +34 -5
  44. package/library/interceptors/index.d.ts.map +1 -1
  45. package/library/message/channel.d.ts +3 -1
  46. package/library/message/channel.d.ts.map +1 -1
  47. package/library/message/dispatcher.d.ts +7 -2
  48. package/library/message/dispatcher.d.ts.map +1 -1
  49. package/library/message/dispatcher.js +48 -2
  50. package/library/message/index.d.ts.map +1 -1
  51. package/library/stream/file-stream.d.ts +5 -0
  52. package/library/stream/file-stream.d.ts.map +1 -1
  53. package/library/stream/file-stream.js +41 -12
  54. package/library/stream/index.d.ts +11 -1
  55. package/library/stream/index.d.ts.map +1 -1
  56. package/library/stream/index.js +21 -3
  57. package/library/stream/readable-stream.d.ts.map +1 -1
  58. package/library/stream/readable-stream.js +32 -30
  59. package/library/stream/types.d.ts +20 -2
  60. package/library/stream/types.d.ts.map +1 -1
  61. package/library/stream/writable-stream.d.ts +2 -1
  62. package/library/stream/writable-stream.d.ts.map +1 -1
  63. package/library/stream/writable-stream.js +13 -10
  64. package/library/types/index.d.ts +106 -32
  65. package/library/types/index.d.ts.map +1 -1
  66. package/library/utils/cache.d.ts +24 -0
  67. package/library/utils/cache.d.ts.map +1 -1
  68. package/library/utils/cache.js +76 -0
  69. package/library/utils/cookie.d.ts.map +1 -1
  70. package/library/utils/debug.d.ts.map +1 -1
  71. package/library/utils/debug.js +382 -20
  72. package/library/utils/index.d.ts +19 -0
  73. package/library/utils/index.d.ts.map +1 -1
  74. package/library/utils/index.js +113 -2
  75. package/library/utils/path-match.d.ts +16 -0
  76. package/library/utils/path-match.d.ts.map +1 -1
  77. package/library/utils/path-match.js +65 -0
  78. package/library/utils/protocol.d.ts.map +1 -1
  79. package/package.json +4 -1
  80. package/react/library/__tests__/index.test.tsx +274 -281
  81. package/react/library/index.d.ts +4 -3
  82. package/react/library/index.d.ts.map +1 -1
  83. package/react/library/index.js +225 -158
  84. package/react/package.json +7 -0
@@ -52,9 +52,10 @@ export declare function useClient(targetFnOrRef: (() => HTMLIFrameElement | Wind
52
52
  * const server = useServer({ secretKey: 'my-app' });
53
53
  *
54
54
  * useEffect(() => {
55
- * server.on('/api/data', (req, res) => {
55
+ * const off = server.on('/api/data', (req, res) => {
56
56
  * res.send({ data: 'Hello' });
57
57
  * });
58
+ * return off;
58
59
  * }, [server]);
59
60
  *
60
61
  * return <div>Server Component</div>;
@@ -85,7 +86,7 @@ export declare function useServer(options?: RequestIframeServerOptions, deps?: r
85
86
  * };
86
87
  * ```
87
88
  */
88
- export declare function useServerHandler(server: RequestIframeServer | null, path: string, handler: ServerHandler, deps?: readonly unknown[]): void;
89
+ export declare function useServerHandler(server: RequestIframeServer | null, path: string, handler: ServerHandler, deps: readonly unknown[]): void;
89
90
  /**
90
91
  * React hook for registering server handlers map
91
92
  *
@@ -113,5 +114,5 @@ export declare function useServerHandler(server: RequestIframeServer | null, pat
113
114
  * };
114
115
  * ```
115
116
  */
116
- export declare function useServerHandlerMap(server: RequestIframeServer | null, map: Record<string, ServerHandler>, deps?: readonly unknown[]): void;
117
+ export declare function useServerHandlerMap(server: RequestIframeServer | null, map: Record<string, ServerHandler>, deps: readonly unknown[]): void;
117
118
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,CAAC,MAAM,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAAC,EACvG,OAAO,CAAC,EAAE,0BAA0B,EACpC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,mBAAmB,GAAG,IAAI,CA8C5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,SAAS,CACvB,OAAO,CAAC,EAAE,0BAA0B,EACpC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,mBAAmB,GAAG,IAAI,CAwB5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,IAAI,CAcN;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,IAAI,CAaN"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1F,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,CAAC,MAAM,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAAC,EACvG,OAAO,CAAC,EAAE,0BAA0B,EACpC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,mBAAmB,GAAG,IAAI,CA2E5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CACvB,OAAO,CAAC,EAAE,0BAA0B,EACpC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,GACxB,mBAAmB,GAAG,IAAI,CA2C5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,SAAS,OAAO,EAAE,GACvB,IAAI,CAmBN;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,EAClC,IAAI,EAAE,SAAS,OAAO,EAAE,GACvB,IAAI,CA2BN"}
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
@@ -9,215 +10,281 @@ exports.useServerHandler = useServerHandler;
9
10
  exports.useServerHandlerMap = useServerHandlerMap;
10
11
  require("core-js/modules/es.array.iterator.js");
11
12
  require("core-js/modules/es.array.map.js");
13
+ require("core-js/modules/es.array.reduce.js");
14
+ require("core-js/modules/es.array.sort.js");
12
15
  require("core-js/modules/web.dom-collections.iterator.js");
16
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
13
17
  var _react = require("react");
14
18
  var _ = require("../..");
15
- /**
16
- * React hook for using request-iframe client
17
- *
18
- * @param targetFnOrRef - function that returns iframe element or Window object, or a React ref object
19
- * @param options - client options
20
- * @param deps - dependency array (optional, for re-creating client when dependencies change)
21
- * @returns client instance
22
- *
23
- * @example
24
- * ```tsx
25
- * // Using function
26
- * const MyComponent = () => {
27
- * const iframeRef = useRef<HTMLIFrameElement>(null);
28
- * const client = useClient(() => iframeRef.current, { secretKey: 'my-app' });
29
- *
30
- * const handleClick = async () => {
31
- * if (client) {
32
- * const response = await client.send('/api/data', { id: 1 });
33
- * console.log(response.data);
34
- * }
35
- * };
36
- *
37
- * return (
38
- * <div>
39
- * <iframe ref={iframeRef} src="/iframe.html" />
40
- * <button onClick={handleClick}>Send Request</button>
41
- * </div>
42
- * );
43
- * };
44
- *
45
- * // Using ref directly
46
- * const MyComponent2 = () => {
47
- * const iframeRef = useRef<HTMLIFrameElement>(null);
48
- * const client = useClient(iframeRef, { secretKey: 'my-app' });
49
- * // ...
50
- * };
51
- * ```
19
+ /**
20
+ * React hook for using request-iframe client
21
+ *
22
+ * @param targetFnOrRef - function that returns iframe element or Window object, or a React ref object
23
+ * @param options - client options
24
+ * @param deps - dependency array (optional, for re-creating client when dependencies change)
25
+ * @returns client instance
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * // Using function
30
+ * const MyComponent = () => {
31
+ * const iframeRef = useRef<HTMLIFrameElement>(null);
32
+ * const client = useClient(() => iframeRef.current, { secretKey: 'my-app' });
33
+ *
34
+ * const handleClick = async () => {
35
+ * if (client) {
36
+ * const response = await client.send('/api/data', { id: 1 });
37
+ * console.log(response.data);
38
+ * }
39
+ * };
40
+ *
41
+ * return (
42
+ * <div>
43
+ * <iframe ref={iframeRef} src="/iframe.html" />
44
+ * <button onClick={handleClick}>Send Request</button>
45
+ * </div>
46
+ * );
47
+ * };
48
+ *
49
+ * // Using ref directly
50
+ * const MyComponent2 = () => {
51
+ * const iframeRef = useRef<HTMLIFrameElement>(null);
52
+ * const client = useClient(iframeRef, { secretKey: 'my-app' });
53
+ * // ...
54
+ * };
55
+ * ```
52
56
  */
53
57
  function useClient(targetFnOrRef, options, deps) {
54
58
  var clientRef = (0, _react.useRef)(null);
55
- var optionsRef = (0, _react.useRef)(options);
59
+ var _useState = (0, _react.useState)(null),
60
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
61
+ client = _useState2[0],
62
+ setClient = _useState2[1];
63
+ var lastTargetRef = (0, _react.useRef)(null);
56
64
  var targetFnOrRefRef = (0, _react.useRef)(targetFnOrRef);
65
+ var optionsRef = (0, _react.useRef)(options);
57
66
 
58
- // Update refs when they change
59
- (0, _react.useEffect)(() => {
60
- optionsRef.current = options;
61
- targetFnOrRefRef.current = targetFnOrRef;
62
- }, [options, targetFnOrRef]);
63
- (0, _react.useEffect)(() => {
64
- // Get current target
65
- var target = typeof targetFnOrRefRef.current === 'function' ? targetFnOrRefRef.current() : targetFnOrRefRef.current.current;
67
+ /** Keep latest inputs without re-creating effect deps */
68
+ targetFnOrRefRef.current = targetFnOrRef;
69
+ optionsRef.current = options;
70
+ var getTarget = (0, _react.useCallback)(() => {
71
+ return typeof targetFnOrRefRef.current === 'function' ? targetFnOrRefRef.current() : targetFnOrRefRef.current.current;
72
+ }, []);
66
73
 
67
- // Only create client if target is available
68
- if (!target) {
69
- if (clientRef.current) {
70
- clientRef.current.destroy();
71
- clientRef.current = null;
72
- }
73
- return;
74
- }
75
-
76
- // Destroy previous client if exists
74
+ /**
75
+ * Snapshot the current target during render (pure read).
76
+ * We use this value as an effect dependency so the effect only runs when
77
+ * the target actually changes (avoids StrictMode update-depth loops).
78
+ */
79
+ var target = getTarget();
80
+ var destroy = (0, _react.useCallback)(() => {
77
81
  if (clientRef.current) {
78
82
  clientRef.current.destroy();
79
83
  clientRef.current = null;
80
84
  }
85
+ lastTargetRef.current = null;
86
+ }, []);
81
87
 
82
- // Create new client instance
83
- var client = (0, _.requestIframeClient)(target, optionsRef.current);
84
- clientRef.current = client;
88
+ /**
89
+ * Create/destroy client in effect to be compatible with React 18 StrictMode
90
+ * and concurrent rendering (avoid render-phase side effects).
91
+ */
92
+ (0, _react.useEffect)(() => {
93
+ /** If target unchanged, keep current client */
94
+ if (target === lastTargetRef.current) return;
85
95
 
86
- // Cleanup: destroy client on unmount
96
+ /** Target changed: destroy old client and maybe create a new one */
97
+ if (clientRef.current) {
98
+ clientRef.current.destroy();
99
+ clientRef.current = null;
100
+ }
101
+ lastTargetRef.current = target;
102
+ if (!target) {
103
+ setClient(null);
104
+ return;
105
+ }
106
+ var newClient = (0, _.requestIframeClient)(target, optionsRef.current);
107
+ clientRef.current = newClient;
108
+ setClient(newClient);
87
109
  return () => {
88
- if (clientRef.current) {
89
- clientRef.current.destroy();
110
+ /** Cleanup only if it's still the current client */
111
+ if (clientRef.current === newClient) {
112
+ newClient.destroy();
90
113
  clientRef.current = null;
114
+ lastTargetRef.current = null;
91
115
  }
92
116
  };
93
- }, deps !== undefined ? deps : [targetFnOrRef, options]);
94
- return clientRef.current;
117
+ }, deps ? [...deps, target] : [target]);
118
+
119
+ // Cleanup on unmount
120
+ (0, _react.useEffect)(() => {
121
+ return () => {
122
+ destroy();
123
+ };
124
+ }, []);
125
+ return client;
95
126
  }
96
127
 
97
- /**
98
- * React hook for using request-iframe server
99
- *
100
- * @param options - server options
101
- * @param deps - dependency array (optional, for re-creating server when dependencies change)
102
- * @returns server instance
103
- *
104
- * @example
105
- * ```tsx
106
- * const MyComponent = () => {
107
- * const server = useServer({ secretKey: 'my-app' });
108
- *
109
- * useEffect(() => {
110
- * server.on('/api/data', (req, res) => {
111
- * res.send({ data: 'Hello' });
112
- * });
113
- * }, [server]);
114
- *
115
- * return <div>Server Component</div>;
116
- * };
117
- * ```
128
+ /**
129
+ * React hook for using request-iframe server
130
+ *
131
+ * @param options - server options
132
+ * @param deps - dependency array (optional, for re-creating server when dependencies change)
133
+ * @returns server instance
134
+ *
135
+ * @example
136
+ * ```tsx
137
+ * const MyComponent = () => {
138
+ * const server = useServer({ secretKey: 'my-app' });
139
+ *
140
+ * useEffect(() => {
141
+ * const off = server.on('/api/data', (req, res) => {
142
+ * res.send({ data: 'Hello' });
143
+ * });
144
+ * return off;
145
+ * }, [server]);
146
+ *
147
+ * return <div>Server Component</div>;
148
+ * };
149
+ * ```
118
150
  */
119
151
  function useServer(options, deps) {
120
152
  var serverRef = (0, _react.useRef)(null);
153
+ var _useState3 = (0, _react.useState)(null),
154
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
155
+ server = _useState4[0],
156
+ setServer = _useState4[1];
121
157
  var optionsRef = (0, _react.useRef)(options);
158
+ optionsRef.current = options;
159
+ var destroy = (0, _react.useCallback)(() => {
160
+ if (serverRef.current) {
161
+ serverRef.current.destroy();
162
+ serverRef.current = null;
163
+ }
164
+ }, []);
122
165
 
123
- // Update options ref when options change
166
+ /**
167
+ * Create/destroy server in effect to be compatible with React 18 StrictMode
168
+ * and concurrent rendering (avoid render-phase side effects).
169
+ */
124
170
  (0, _react.useEffect)(() => {
125
- optionsRef.current = options;
126
- }, [options]);
127
- (0, _react.useEffect)(() => {
128
- // Create server instance
129
- var server = (0, _.requestIframeServer)(optionsRef.current);
130
- serverRef.current = server;
131
-
132
- // Cleanup: destroy server on unmount
171
+ if (serverRef.current) {
172
+ serverRef.current.destroy();
173
+ serverRef.current = null;
174
+ }
175
+ var newServer = (0, _.requestIframeServer)(optionsRef.current);
176
+ serverRef.current = newServer;
177
+ setServer(newServer);
133
178
  return () => {
134
- if (serverRef.current) {
135
- serverRef.current.destroy();
179
+ if (serverRef.current === newServer) {
180
+ newServer.destroy();
136
181
  serverRef.current = null;
137
182
  }
138
183
  };
139
- }, deps !== undefined ? deps : []); // Only create once on mount by default
184
+ }, deps !== null && deps !== void 0 ? deps : []);
140
185
 
141
- return serverRef.current;
186
+ // Cleanup on unmount
187
+ (0, _react.useEffect)(() => {
188
+ return () => {
189
+ destroy();
190
+ };
191
+ }, []);
192
+ return server;
142
193
  }
143
194
 
144
- /**
145
- * React hook for registering server handlers
146
- *
147
- * @param server - server instance (from useServer)
148
- * @param path - route path
149
- * @param handler - handler function
150
- * @param deps - dependency array (optional, for re-registering when dependencies change)
151
- *
152
- * @example
153
- * ```tsx
154
- * const MyComponent = () => {
155
- * const server = useServer();
156
- * const [userId, setUserId] = useState(1);
157
- *
158
- * // Register handler that depends on userId
159
- * useServerHandler(server, '/api/user', (req, res) => {
160
- * res.send({ userId, data: 'Hello' });
161
- * }, [userId]);
162
- *
163
- * return <div>Server Component</div>;
164
- * };
165
- * ```
195
+ /**
196
+ * React hook for registering server handlers
197
+ *
198
+ * @param server - server instance (from useServer)
199
+ * @param path - route path
200
+ * @param handler - handler function
201
+ * @param deps - dependency array (optional, for re-registering when dependencies change)
202
+ *
203
+ * @example
204
+ * ```tsx
205
+ * const MyComponent = () => {
206
+ * const server = useServer();
207
+ * const [userId, setUserId] = useState(1);
208
+ *
209
+ * // Register handler that depends on userId
210
+ * useServerHandler(server, '/api/user', (req, res) => {
211
+ * res.send({ userId, data: 'Hello' });
212
+ * }, [userId]);
213
+ *
214
+ * return <div>Server Component</div>;
215
+ * };
216
+ * ```
166
217
  */
167
218
  function useServerHandler(server, path, handler, deps) {
219
+ var handlerRef = (0, _react.useRef)(handler);
220
+ handlerRef.current = handler;
221
+ var handlerWrapper = (0, _react.useCallback)((req, res) => {
222
+ var _handlerRef$current;
223
+ return (_handlerRef$current = handlerRef.current) === null || _handlerRef$current === void 0 ? void 0 : _handlerRef$current.call(handlerRef, req, res);
224
+ }, []);
168
225
  (0, _react.useEffect)(() => {
169
226
  if (!server) {
170
227
  return;
171
228
  }
172
229
 
173
- // Register handler and get unregister function
174
- var unregister = server.on(path, handler);
230
+ // Register handler with stable wrapper
231
+ var off = server.on(path, handlerWrapper);
175
232
 
176
233
  // Cleanup: unregister handler on unmount or when deps change
177
- return () => {
178
- unregister();
179
- };
180
- }, [server, path, handler, ...(deps || [])]);
234
+ return off;
235
+ }, [server, path, handlerWrapper, ...(deps || [])]);
181
236
  }
182
237
 
183
- /**
184
- * React hook for registering server handlers map
185
- *
186
- * @param server - server instance (from useServer)
187
- * @param map - map of route paths and handler functions
188
- * @param deps - dependency array (optional, for re-registering when dependencies change)
189
- *
190
- * @example
191
- * ```tsx
192
- * const MyComponent = () => {
193
- * const server = useServer();
194
- * const [userId, setUserId] = useState(1);
195
- *
196
- * // Register handlers using map
197
- * useServerHandlerMap(server, {
198
- * '/api/user': (req, res) => {
199
- * res.send({ userId, data: 'Hello' });
200
- * },
201
- * '/api/user2': (req, res) => {
202
- * res.send({ userId, data: 'Hello' });
203
- * }
204
- * }, [userId]);
205
- *
206
- * return <div>Server Component</div>;
207
- * };
208
- * ```
238
+ /**
239
+ * React hook for registering server handlers map
240
+ *
241
+ * @param server - server instance (from useServer)
242
+ * @param map - map of route paths and handler functions
243
+ * @param deps - dependency array (optional, for re-registering when dependencies change)
244
+ *
245
+ * @example
246
+ * ```tsx
247
+ * const MyComponent = () => {
248
+ * const server = useServer();
249
+ * const [userId, setUserId] = useState(1);
250
+ *
251
+ * // Register handlers using map
252
+ * useServerHandlerMap(server, {
253
+ * '/api/user': (req, res) => {
254
+ * res.send({ userId, data: 'Hello' });
255
+ * },
256
+ * '/api/user2': (req, res) => {
257
+ * res.send({ userId, data: 'Hello' });
258
+ * }
259
+ * }, [userId]);
260
+ *
261
+ * return <div>Server Component</div>;
262
+ * };
263
+ * ```
209
264
  */
210
265
  function useServerHandlerMap(server, map, deps) {
266
+ var mapRef = (0, _react.useRef)(map);
267
+ mapRef.current = map;
268
+ var keys = (0, _react.useMemo)(() => {
269
+ return Object.keys(map).sort();
270
+ }, [map]);
271
+ var mapWrapper = (0, _react.useMemo)(() => {
272
+ return keys.reduce((acc, key) => {
273
+ acc[key] = function (req, res) {
274
+ var _mapRef$current;
275
+ return (_mapRef$current = mapRef.current) === null || _mapRef$current === void 0 || (_mapRef$current = _mapRef$current[key]) === null || _mapRef$current === void 0 ? void 0 : _mapRef$current.call(this, req, res);
276
+ };
277
+ return acc;
278
+ }, {});
279
+ }, [keys]);
211
280
  (0, _react.useEffect)(() => {
212
281
  if (!server) {
213
282
  return;
214
283
  }
215
- // Register handlers using map
216
- server.map(map);
284
+ // Register handlers using map with stable wrappers
285
+ var off = server.map(mapWrapper);
217
286
 
218
287
  // Cleanup: unregister all handlers on unmount or when deps change
219
- return () => {
220
- server.off(Object.keys(map));
221
- };
222
- }, [server, map, ...(deps || [])]);
288
+ return off;
289
+ }, [server, mapWrapper, ...(deps || [])]);
223
290
  }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@request-iframe/react",
3
+ "version": "0.0.1",
4
+ "main": "./library/index.js",
5
+ "module": "./library/index.js",
6
+ "typings": "./library/index.d.ts"
7
+ }