bippy 0.6.1-dev.fe75557 → 0.7.0-dev.07e6032

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 (67) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +223 -461
  3. package/dist/core.cjs +1 -1
  4. package/dist/core.js +1 -1
  5. package/dist/errors.d.cts +410 -0
  6. package/dist/errors.d.ts +410 -0
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.d.cts +154 -3
  9. package/dist/index.d.ts +154 -3
  10. package/dist/index.js +1 -1
  11. package/dist/install-hook-only.cjs +1 -1
  12. package/dist/install-hook-only.d.cts +9 -1
  13. package/dist/install-hook-only.d.ts +9 -1
  14. package/dist/install-hook-only.js +1 -1
  15. package/dist/rdt-hook.cjs +1 -1
  16. package/dist/rdt-hook.js +1 -1
  17. package/dist/source.cjs +14 -5
  18. package/dist/source.d.cts +86 -69
  19. package/dist/source.d.ts +86 -69
  20. package/dist/source.js +14 -5
  21. package/package.json +26 -27
  22. package/src/core.ts +367 -685
  23. package/src/errors.ts +34 -0
  24. package/src/index.ts +1 -0
  25. package/src/install-hook-only.ts +6 -2
  26. package/src/rdt-hook.ts +177 -156
  27. package/src/react-internals/generated/react-work-tags.ts +318 -0
  28. package/src/react-internals/index.ts +73 -0
  29. package/src/react-internals/semver.ts +80 -0
  30. package/src/react-internals/types.ts +186 -0
  31. package/src/react.ts +76 -0
  32. package/src/source/constants.ts +1 -1
  33. package/src/source/error-stack.ts +11 -0
  34. package/src/source/get-display-name-from-source.ts +44 -40
  35. package/src/source/get-source.ts +43 -26
  36. package/src/source/index.ts +11 -1
  37. package/src/source/inspect-hooks.ts +220 -207
  38. package/src/source/owner-stack.ts +121 -174
  39. package/src/source/parse-debug-stack.ts +4 -4
  40. package/src/source/parse-hook-names.ts +14 -53
  41. package/src/source/parse-stack.ts +14 -31
  42. package/src/source/renderer-dispatchers.ts +30 -0
  43. package/src/source/symbolication.ts +709 -120
  44. package/dist/core.d.cts +0 -214
  45. package/dist/core.d.ts +0 -214
  46. package/dist/core2.d.cts +0 -3
  47. package/dist/core2.d.ts +0 -3
  48. package/dist/get-source.cjs +0 -19
  49. package/dist/get-source.js +0 -19
  50. package/dist/index.iife.js +0 -9
  51. package/dist/install-hook-only.iife.js +0 -9
  52. package/dist/react-refresh.cjs +0 -9
  53. package/dist/react-refresh.d.cts +0 -66
  54. package/dist/react-refresh.d.ts +0 -66
  55. package/dist/react-refresh.js +0 -9
  56. package/dist/unsubscribe.d.cts +0 -298
  57. package/dist/unsubscribe.d.ts +0 -298
  58. package/src/react-refresh/constants.ts +0 -9
  59. package/src/react-refresh/detect-hmr-transport.ts +0 -33
  60. package/src/react-refresh/index.ts +0 -173
  61. package/src/react-refresh/metro-hmr-transport.ts +0 -188
  62. package/src/react-refresh/next-webpack-hmr-transport.ts +0 -72
  63. package/src/react-refresh/normalize-hmr-file-path.ts +0 -24
  64. package/src/react-refresh/types.ts +0 -7
  65. package/src/react-refresh/vite-hmr-transport.ts +0 -116
  66. package/src/types.ts +0 -438
  67. package/src/unsubscribe.ts +0 -17
@@ -1,188 +0,0 @@
1
- import { HMR_RECONNECT_DELAY_MS } from "./constants.js";
2
- import { HmrTransport, HmrUpdateHandler } from "./types.js";
3
-
4
- declare global {
5
- var __turboModuleProxy: ((moduleName: string) => unknown) | undefined;
6
- var nativeModuleProxy: Record<string, unknown> | undefined;
7
- }
8
-
9
- const getScriptUrlFromSourceCodeModule = (sourceCodeModule: unknown): string | null => {
10
- if (typeof sourceCodeModule !== "object" || sourceCodeModule === null) return null;
11
- if (!("getConstants" in sourceCodeModule)) return null;
12
- const getConstants = sourceCodeModule.getConstants;
13
- if (typeof getConstants !== "function") return null;
14
- let constants: unknown;
15
- try {
16
- constants = getConstants.call(sourceCodeModule);
17
- } catch {
18
- return null;
19
- }
20
- if (typeof constants !== "object" || constants === null) return null;
21
- if (!("scriptURL" in constants)) return null;
22
- const scriptUrl = constants.scriptURL;
23
- return typeof scriptUrl === "string" ? scriptUrl : null;
24
- };
25
-
26
- /**
27
- * Resolves the URL the running React Native bundle was loaded from, using
28
- * the same `SourceCode` native module React Native's own dev tooling reads
29
- * (via the TurboModule proxy globals, so react-native is not imported).
30
- * Returns `null` outside a Metro-served React Native runtime.
31
- *
32
- * @example
33
- * ```ts
34
- * getMetroBundleUrl();
35
- * // "http://localhost:8081/index.bundle?platform=ios&dev=true"
36
- * ```
37
- */
38
- export const getMetroBundleUrl = (): string | null => {
39
- if (typeof globalThis.__turboModuleProxy === "function") {
40
- let sourceCodeModule: unknown;
41
- try {
42
- sourceCodeModule = globalThis.__turboModuleProxy("SourceCode");
43
- } catch {
44
- sourceCodeModule = null;
45
- }
46
- const scriptUrl = getScriptUrlFromSourceCodeModule(sourceCodeModule);
47
- if (scriptUrl) return scriptUrl;
48
- }
49
- const legacySourceCodeModule = globalThis.nativeModuleProxy?.SourceCode;
50
- return getScriptUrlFromSourceCodeModule(legacySourceCodeModule);
51
- };
52
-
53
- // HACK: module sourceURLs may be JSC-safe URLs where "//&" stands in for
54
- // "?" (iOS 16.4 stack traces strip query strings), so the query separator
55
- // must be normalized before URL parsing.
56
- const normalizeJscSafeUrl = (jscSafeUrl: string): string => jscSafeUrl.replace("//&", "?");
57
-
58
- const getSourcePathFromSourceUrl = (sourceUrl: string): string | null => {
59
- let parsedUrl: URL;
60
- try {
61
- parsedUrl = new URL(normalizeJscSafeUrl(sourceUrl));
62
- } catch {
63
- return null;
64
- }
65
- let sourcePath = decodeURIComponent(parsedUrl.pathname);
66
- if (sourcePath.startsWith("/")) sourcePath = sourcePath.slice(1);
67
- // Metro rewrites each module's real extension to ".bundle" when building
68
- // hot-update sourceURLs, so the original extension is unrecoverable.
69
- if (sourcePath.endsWith(".bundle")) sourcePath = sourcePath.slice(0, -".bundle".length);
70
- return sourcePath.length > 0 ? sourcePath : null;
71
- };
72
-
73
- const collectModuleSourcePaths = (hmrModules: unknown, filePaths: string[]) => {
74
- if (!Array.isArray(hmrModules)) return;
75
- for (const hmrModule of hmrModules) {
76
- if (typeof hmrModule !== "object" || hmrModule === null) continue;
77
- if (!("sourceURL" in hmrModule) || typeof hmrModule.sourceURL !== "string") continue;
78
- const sourcePath = getSourcePathFromSourceUrl(hmrModule.sourceURL);
79
- if (!sourcePath || sourcePath.includes("node_modules")) continue;
80
- filePaths.push(sourcePath);
81
- }
82
- };
83
-
84
- /**
85
- * Extracts the updated source file paths from a raw Metro HMR WebSocket
86
- * message. Paths are project-relative but extension-less (`src/app`, not
87
- * `src/app.tsx`) because Metro rewrites module extensions to `.bundle`.
88
- * The initial update replayed on connect is skipped. Returns an empty
89
- * array for any other message shape.
90
- *
91
- * @example
92
- * ```ts
93
- * parseMetroUpdatePaths(rawMessageData);
94
- * // ["src/app"]
95
- * ```
96
- */
97
- export const parseMetroUpdatePaths = (rawMessageData: string): string[] => {
98
- let message: unknown;
99
- try {
100
- message = JSON.parse(rawMessageData);
101
- } catch {
102
- return [];
103
- }
104
- if (typeof message !== "object" || message === null) return [];
105
- if (!("type" in message) || message.type !== "update") return [];
106
- if (!("body" in message) || typeof message.body !== "object" || message.body === null) return [];
107
- const updateBody = message.body;
108
- if ("isInitialUpdate" in updateBody && updateBody.isInitialUpdate === true) return [];
109
- const filePaths: string[] = [];
110
- if ("added" in updateBody) collectModuleSourcePaths(updateBody.added, filePaths);
111
- if ("modified" in updateBody) collectModuleSourcePaths(updateBody.modified, filePaths);
112
- return filePaths;
113
- };
114
-
115
- export interface MetroHmrTransportOptions {
116
- bundleUrl?: string;
117
- }
118
-
119
- /**
120
- * Subscribes to the Metro dev server's `/hot` HMR WebSocket (as a second
121
- * client alongside React Native's own) and invokes `onHmrUpdate` with the
122
- * updated file paths on every hot update. Reconnects automatically when
123
- * the dev server restarts. Returns `null` when no Metro bundle URL can be
124
- * resolved (production builds, non-Metro runtimes).
125
- *
126
- * @example
127
- * ```ts
128
- * const transport = createMetroHmrTransport((filePaths) => {
129
- * console.log("hot updated:", filePaths);
130
- * });
131
- * transport?.dispose();
132
- * ```
133
- */
134
- export const createMetroHmrTransport = (
135
- onHmrUpdate: HmrUpdateHandler,
136
- options: MetroHmrTransportOptions = {},
137
- ): HmrTransport | null => {
138
- if (typeof WebSocket === "undefined") return null;
139
- const bundleUrl = options.bundleUrl ?? getMetroBundleUrl();
140
- if (!bundleUrl) return null;
141
-
142
- let hotSocketUrl: string;
143
- try {
144
- const parsedBundleUrl = new URL(bundleUrl);
145
- const socketProtocol = parsedBundleUrl.protocol === "https:" ? "wss" : "ws";
146
- hotSocketUrl = `${socketProtocol}://${parsedBundleUrl.host}/hot`;
147
- } catch {
148
- return null;
149
- }
150
-
151
- let isDisposed = false;
152
- let socket: WebSocket | null = null;
153
- let reconnectTimerId: ReturnType<typeof setTimeout> | undefined;
154
-
155
- const scheduleReconnect = () => {
156
- if (isDisposed) return;
157
- reconnectTimerId = setTimeout(connect, HMR_RECONNECT_DELAY_MS);
158
- };
159
-
160
- const connect = () => {
161
- if (isDisposed) return;
162
- const connectedSocket = new WebSocket(hotSocketUrl);
163
- socket = connectedSocket;
164
- connectedSocket.onopen = () => {
165
- connectedSocket.send(
166
- JSON.stringify({ type: "register-entrypoints", entryPoints: [bundleUrl] }),
167
- );
168
- };
169
- connectedSocket.onmessage = (event) => {
170
- const filePaths = parseMetroUpdatePaths(String(event.data));
171
- if (filePaths.length > 0) onHmrUpdate(filePaths);
172
- };
173
- connectedSocket.onclose = scheduleReconnect;
174
- };
175
-
176
- connect();
177
-
178
- return {
179
- dispose: () => {
180
- isDisposed = true;
181
- clearTimeout(reconnectTimerId);
182
- if (socket) {
183
- socket.onclose = null;
184
- socket.close();
185
- }
186
- },
187
- };
188
- };
@@ -1,72 +0,0 @@
1
- import { HMR_SOURCE_FILE_EXTENSION_REGEX } from "./constants.js";
2
- import { normalizeHmrFilePath } from "./normalize-hmr-file-path.js";
3
- import { HmrTransport, HmrUpdateHandler } from "./types.js";
4
-
5
- interface WebpackHotUpdateGlobal {
6
- (chunkId: unknown, updatedModules: Record<string, unknown> | undefined, runtime: unknown): void;
7
- }
8
-
9
- declare global {
10
- interface Window {
11
- webpackHotUpdate_N_E?: WebpackHotUpdateGlobal;
12
- }
13
- }
14
-
15
- /**
16
- * Normalizes webpack hot-update module keys into project-relative source
17
- * file paths, dropping node_modules entries and non-source keys (e.g.
18
- * webpack runtime helpers).
19
- *
20
- * @example
21
- * ```ts
22
- * normalizeWebpackModulePaths(["(app-pages-browser)/./app/page.tsx"]);
23
- * // ["app/page.tsx"]
24
- * ```
25
- */
26
- export const normalizeWebpackModulePaths = (moduleKeys: string[]): string[] => {
27
- const filePaths: string[] = [];
28
- for (const moduleKey of moduleKeys) {
29
- if (moduleKey.includes("node_modules")) continue;
30
- const filePath = normalizeHmrFilePath(moduleKey);
31
- if (!HMR_SOURCE_FILE_EXTENSION_REGEX.test(filePath)) continue;
32
- filePaths.push(filePath);
33
- }
34
- return filePaths;
35
- };
36
-
37
- /**
38
- * Subscribes to Next.js webpack hot updates by wrapping the
39
- * `webpackHotUpdate_N_E` global and invokes `onHmrUpdate` with the updated
40
- * file paths. Returns `null` when the page is not a Next.js webpack dev
41
- * build.
42
- *
43
- * @example
44
- * ```ts
45
- * const transport = createNextWebpackHmrTransport((filePaths) => {
46
- * console.log("hot updated:", filePaths);
47
- * });
48
- * transport?.dispose();
49
- * ```
50
- */
51
- export const createNextWebpackHmrTransport = (
52
- onHmrUpdate: HmrUpdateHandler,
53
- ): HmrTransport | null => {
54
- if (typeof window === "undefined") return null;
55
- const originalHotUpdate = window.webpackHotUpdate_N_E;
56
- if (typeof originalHotUpdate !== "function") return null;
57
-
58
- const wrappedHotUpdate: WebpackHotUpdateGlobal = (chunkId, updatedModules, runtime) => {
59
- const filePaths = normalizeWebpackModulePaths(Object.keys(updatedModules ?? {}));
60
- if (filePaths.length > 0) onHmrUpdate(filePaths);
61
- originalHotUpdate(chunkId, updatedModules, runtime);
62
- };
63
- window.webpackHotUpdate_N_E = wrappedHotUpdate;
64
-
65
- return {
66
- dispose: () => {
67
- if (window.webpackHotUpdate_N_E === wrappedHotUpdate) {
68
- window.webpackHotUpdate_N_E = originalHotUpdate;
69
- }
70
- },
71
- };
72
- };
@@ -1,24 +0,0 @@
1
- import { normalizeFileName } from "../source/get-source.js";
2
-
3
- import { BUNDLER_LAYER_PREFIX_REGEX } from "./constants.js";
4
-
5
- /**
6
- * Normalizes a bundler module key or HMR update path into a plain,
7
- * project-relative file path. Strips URL schemes (via
8
- * {@link normalizeFileName}), bundler layer prefixes like
9
- * `(app-pages-browser)/`, and leading `./` segments.
10
- *
11
- * @example
12
- * ```ts
13
- * normalizeHmrFilePath("(app-pages-browser)/./app/page.tsx");
14
- * // "app/page.tsx"
15
- * ```
16
- */
17
- export const normalizeHmrFilePath = (filePath: string): string => {
18
- let normalizedFilePath = normalizeFileName(filePath);
19
- normalizedFilePath = normalizedFilePath.replace(BUNDLER_LAYER_PREFIX_REGEX, "");
20
- if (normalizedFilePath.startsWith("./")) {
21
- normalizedFilePath = normalizedFilePath.slice(2);
22
- }
23
- return normalizedFilePath;
24
- };
@@ -1,7 +0,0 @@
1
- export interface HmrUpdateHandler {
2
- (filePaths: string[]): void;
3
- }
4
-
5
- export interface HmrTransport {
6
- dispose: () => void;
7
- }
@@ -1,116 +0,0 @@
1
- import { HMR_RECONNECT_DELAY_MS, VITE_WS_TOKEN_REGEX } from "./constants.js";
2
- import { HmrTransport, HmrUpdateHandler } from "./types.js";
3
-
4
- /**
5
- * Extracts the accepted file paths from a raw Vite HMR WebSocket message.
6
- * Only `js-update` entries are kept (a `css-update` swaps a stylesheet link
7
- * without re-running modules). Returns an empty array for any other message
8
- * shape.
9
- *
10
- * @example
11
- * ```ts
12
- * parseViteUpdatePaths(rawMessageData);
13
- * // ["/src/app.tsx"]
14
- * ```
15
- */
16
- export const parseViteUpdatePaths = (rawMessageData: string): string[] => {
17
- let message: unknown;
18
- try {
19
- message = JSON.parse(rawMessageData);
20
- } catch {
21
- return [];
22
- }
23
- if (typeof message !== "object" || message === null) return [];
24
- if (!("type" in message) || message.type !== "update") return [];
25
- if (!("updates" in message) || !Array.isArray(message.updates)) return [];
26
- const filePaths: string[] = [];
27
- for (const update of message.updates) {
28
- if (typeof update !== "object" || update === null) continue;
29
- if (!("type" in update) || update.type !== "js-update") continue;
30
- if (!("acceptedPath" in update) || typeof update.acceptedPath !== "string") continue;
31
- filePaths.push(update.acceptedPath);
32
- }
33
- return filePaths;
34
- };
35
-
36
- // HACK: a standalone script is not a Vite module, so import.meta.hot is
37
- // unavailable; open a second HMR WebSocket using the wsToken scraped from
38
- // the dev server's own /@vite/client source.
39
- const fetchViteWsToken = async (): Promise<string | null> => {
40
- try {
41
- const response = await fetch("/@vite/client");
42
- if (!response.ok) return null;
43
- const clientSource = await response.text();
44
- return VITE_WS_TOKEN_REGEX.exec(clientSource)?.[1] ?? null;
45
- } catch {
46
- return null;
47
- }
48
- };
49
-
50
- /**
51
- * Subscribes to the current page's Vite dev server HMR WebSocket and invokes
52
- * `onHmrUpdate` with the updated file paths on every hot update. Reconnects
53
- * automatically when the dev server restarts. Resolves `null` when the page
54
- * is not served by Vite.
55
- *
56
- * @example
57
- * ```ts
58
- * const transport = await createViteHmrTransport((filePaths) => {
59
- * console.log("hot updated:", filePaths);
60
- * });
61
- * transport?.dispose();
62
- * ```
63
- */
64
- export const createViteHmrTransport = async (
65
- onHmrUpdate: HmrUpdateHandler,
66
- ): Promise<HmrTransport | null> => {
67
- if (typeof window === "undefined" || typeof WebSocket === "undefined") return null;
68
- const initialWsToken = await fetchViteWsToken();
69
- if (!initialWsToken) return null;
70
-
71
- let isDisposed = false;
72
- let socket: WebSocket | null = null;
73
- let reconnectTimerId: number | undefined;
74
-
75
- const scheduleReconnect = () => {
76
- if (isDisposed) return;
77
- reconnectTimerId = window.setTimeout(() => {
78
- void fetchViteWsToken().then((freshWsToken) => {
79
- if (isDisposed) return;
80
- if (freshWsToken) {
81
- connect(freshWsToken);
82
- } else {
83
- scheduleReconnect();
84
- }
85
- });
86
- }, HMR_RECONNECT_DELAY_MS);
87
- };
88
-
89
- const connect = (wsToken: string) => {
90
- if (isDisposed) return;
91
- const socketProtocol = location.protocol === "https:" ? "wss" : "ws";
92
- const connectedSocket = new WebSocket(
93
- `${socketProtocol}://${location.host}/?token=${wsToken}`,
94
- "vite-hmr",
95
- );
96
- socket = connectedSocket;
97
- connectedSocket.onmessage = (event) => {
98
- const filePaths = parseViteUpdatePaths(String(event.data));
99
- if (filePaths.length > 0) onHmrUpdate(filePaths);
100
- };
101
- connectedSocket.onclose = scheduleReconnect;
102
- };
103
-
104
- connect(initialWsToken);
105
-
106
- return {
107
- dispose: () => {
108
- isDisposed = true;
109
- window.clearTimeout(reconnectTimerId);
110
- if (socket) {
111
- socket.onclose = null;
112
- socket.close();
113
- }
114
- },
115
- };
116
- };