@absolutejs/absolute 0.20.0-beta.122 → 0.20.0-beta.124

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/CHANGELOG.md CHANGED
@@ -6,6 +6,37 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.20.0-beta.124 — 2026-09-28
10
+
11
+ ### Fixed
12
+
13
+ - **Projects on a current `@absolutejs/auth` no longer get a second, older copy**
14
+ AbsoluteJS accepted `@absolutejs/auth` only below 0.77, so a project that added a current auth (0.77 to 0.96) got two copies: its own, plus 0.76.3 nested under AbsoluteJS for the mobile shell. The duplicate also doubled the auth type declarations TypeScript loads. AbsoluteJS now accepts auth up to 0.96. The `@absolutejs/auth/client/mobile` API it uses is byte-identical from 0.76.3 to 0.96.0, in both its declarations and its runtime.
15
+ - **`/hmr-status` no longer counts closed or duplicate HMR clients** (`HMRWebSocket`)
16
+ Elysia 2 hands every open, message and close event of a WebSocket a new wrapper object. The dev server tracked HMR clients by that wrapper, so a closed browser tab was never removed (it stayed until a broadcast send threw) and each `ready` message counted the same tab again under `connectedTargets`, so `/hmr-status` reported clients that were gone and more web targets than open sockets. Clients are now tracked by the underlying socket.
17
+
18
+ ## 0.20.0-beta.123 — 2026-09-28
19
+
20
+ ### Added
21
+
22
+ - **React Fast Refresh keeps component state: `absolute dev` can run on AbsoluteJS's patched Bun**
23
+ Stock Bun ignores `reactFastRefresh` on `Bun.Transpiler` (oven-sh/bun#32919), so React edits in `absolute dev` remounted the page and lost component state. AbsoluteJS now publishes Bun 1.4.0 with just that fix for every platform Bun ships (github.com/absolutejs/patched-bun). In React projects on stock Bun, `absolute dev` offers it once (Install now / Ask me later / Don't ask again); it installs to ~/.absolutejs/bun, is checked against a pinned SHA-256, and only the dev server uses it, so your `bun` is unchanged. `absolute bun-patch [status|install|remove|reset]` manages it; `ABSOLUTE_PATCHED_BUN=0` opts out.
24
+
25
+ ### Fixed
26
+
27
+ - **`absolute dev` keeps rebuilding after a syntax error in a React component or an unhandled rejection**
28
+ Under `bun --hot`, Bun counts unhandled rejections that no listener claims and never resets the count; while it is non-zero Bun parks the process in a loop that still serves requests and delivers file-watch events but never runs timers. The server entry imports React pages, so saving a React component with a syntax error made Bun's hot reload reject, and from then on the HMR debounce never fired: every edit was detected and queued, including the one that fixed the error, and nothing rebuilt until the dev server restarted. An unhandled rejection in app code did the same. The dev server now claims unhandled rejections and prints them as before, so its timers keep running.
29
+ - **The patched Bun is now a release build, not a canary build**
30
+ `absolute bun-patch install` and the `absolute dev` offer now install `bun-v1.4.0-absolute.2`. The first release was built as a Bun canary build (Bun's build default): it reported `1.4.0-canary.1`, enabled Bun's experimental "bake" server features and made `bun upgrade` track canary. absolute.2 is built with `--canary=off`, as Bun's own releases are; the React Fast Refresh fix is unchanged. Run `absolute bun-patch install` to replace an absolute.1 install.
31
+ - **Removed a React HMR CSS branch that only matched the example app**
32
+ The React HMR client had a CSS-only branch that looked up the example app's `ReactExampleCSS` manifest key, so it could never work in another app; the server never sends a CSS-only React update, so it was also unreachable. Removed. Stylesheet edits on React pages go through the general stylesheet swap, now covered by a browser test (the rule applies, component state and the document are kept).
33
+ - **React edits that add a component, touch a hook or utility, or create a folder now update the page in place**
34
+ The React fast path told the browser to re-import a single module: the first non-page file in the batch. A new component added to the page re-imported only the new file, so the page never rendered it; a folder created alongside a file became the target and its URL failed to load; and an edited hook or utility whose importer had not been fetched through the module server re-imported just itself, which updates nothing on screen. Every edited file now gets a target (hooks and utilities resolve to the nearest importing component, falling back to the dependents the dependency graph found), directories and deleted paths are skipped, and the client imports them all before refreshing. On stock Bun the remount fallback rendered the changed child in place of the whole page; it now re-imports the page module for the page on screen and ignores edits that do not reach it.
35
+ - **React Fast Refresh is used when Bun supports it, instead of always falling back to a remount**
36
+ The dev server decides between React Fast Refresh and the stock-Bun remount fallback by transpiling a probe component. The probe was named `__AbsoluteRefreshProbe`; React Fast Refresh registers only capitalized components, so it reported "unsupported" even on a Bun with the reactFastRefresh fix, and React edits always remounted with a warning. It now uses a capitalized name.
37
+ - **A syntax error in a React component shows the error overlay instead of reloading the page**
38
+ A React edit that failed to compile was still broadcast as an update. The browser imported a module that answered 500 and fell back to a full reload, which showed the last good page and no error. The dev server now checks the edited modules compile first and sends the error overlay (file, line and source line) instead; the save that fixes it applies as a normal in-place update. The module server handler and its transform errors also moved to globalThis: after a `bun --hot` reload failed part-way, later imports of the module server got a fresh instance that was never configured, so pre-transforming the changed module silently did nothing.
39
+
9
40
  ## 0.20.0-beta.122 — 2026-09-27
10
41
 
11
42
  ### Fixed
package/changelog.json CHANGED
@@ -2,6 +2,66 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/absolute",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "detail": "AbsoluteJS accepted `@absolutejs/auth` only below 0.77, so a project that added a current auth (0.77 to 0.96) got two copies: its own, plus 0.76.3 nested under AbsoluteJS for the mobile shell. The duplicate also doubled the auth type declarations TypeScript loads. AbsoluteJS now accepts auth up to 0.96. The `@absolutejs/auth/client/mobile` API it uses is byte-identical from 0.76.3 to 0.96.0, in both its declarations and its runtime.",
9
+ "kind": "fixed",
10
+ "summary": "Projects on a current `@absolutejs/auth` no longer get a second, older copy"
11
+ },
12
+ {
13
+ "detail": "Elysia 2 hands every open, message and close event of a WebSocket a new wrapper object. The dev server tracked HMR clients by that wrapper, so a closed browser tab was never removed (it stayed until a broadcast send threw) and each `ready` message counted the same tab again under `connectedTargets`, so `/hmr-status` reported clients that were gone and more web targets than open sockets. Clients are now tracked by the underlying socket.",
14
+ "kind": "fixed",
15
+ "summary": "`/hmr-status` no longer counts closed or duplicate HMR clients",
16
+ "symbols": [
17
+ "HMRWebSocket"
18
+ ]
19
+ }
20
+ ],
21
+ "date": "2026-09-28",
22
+ "version": "0.20.0-beta.124"
23
+ },
24
+ {
25
+ "changes": [
26
+ {
27
+ "detail": "Under `bun --hot`, Bun counts unhandled rejections that no listener claims and never resets the count; while it is non-zero Bun parks the process in a loop that still serves requests and delivers file-watch events but never runs timers. The server entry imports React pages, so saving a React component with a syntax error made Bun's hot reload reject, and from then on the HMR debounce never fired: every edit was detected and queued, including the one that fixed the error, and nothing rebuilt until the dev server restarted. An unhandled rejection in app code did the same. The dev server now claims unhandled rejections and prints them as before, so its timers keep running.",
28
+ "kind": "fixed",
29
+ "summary": "`absolute dev` keeps rebuilding after a syntax error in a React component or an unhandled rejection"
30
+ },
31
+ {
32
+ "detail": "`absolute bun-patch install` and the `absolute dev` offer now install `bun-v1.4.0-absolute.2`. The first release was built as a Bun canary build (Bun's build default): it reported `1.4.0-canary.1`, enabled Bun's experimental \"bake\" server features and made `bun upgrade` track canary. absolute.2 is built with `--canary=off`, as Bun's own releases are; the React Fast Refresh fix is unchanged. Run `absolute bun-patch install` to replace an absolute.1 install.",
33
+ "kind": "fixed",
34
+ "summary": "The patched Bun is now a release build, not a canary build"
35
+ },
36
+ {
37
+ "detail": "Stock Bun ignores `reactFastRefresh` on `Bun.Transpiler` (oven-sh/bun#32919), so React edits in `absolute dev` remounted the page and lost component state. AbsoluteJS now publishes Bun 1.4.0 with just that fix for every platform Bun ships (github.com/absolutejs/patched-bun). In React projects on stock Bun, `absolute dev` offers it once (Install now / Ask me later / Don't ask again); it installs to ~/.absolutejs/bun, is checked against a pinned SHA-256, and only the dev server uses it, so your `bun` is unchanged. `absolute bun-patch [status|install|remove|reset]` manages it; `ABSOLUTE_PATCHED_BUN=0` opts out.",
38
+ "kind": "added",
39
+ "summary": "React Fast Refresh keeps component state: `absolute dev` can run on AbsoluteJS's patched Bun"
40
+ },
41
+ {
42
+ "detail": "The React HMR client had a CSS-only branch that looked up the example app's `ReactExampleCSS` manifest key, so it could never work in another app; the server never sends a CSS-only React update, so it was also unreachable. Removed. Stylesheet edits on React pages go through the general stylesheet swap, now covered by a browser test (the rule applies, component state and the document are kept).",
43
+ "kind": "fixed",
44
+ "summary": "Removed a React HMR CSS branch that only matched the example app"
45
+ },
46
+ {
47
+ "detail": "The React fast path told the browser to re-import a single module: the first non-page file in the batch. A new component added to the page re-imported only the new file, so the page never rendered it; a folder created alongside a file became the target and its URL failed to load; and an edited hook or utility whose importer had not been fetched through the module server re-imported just itself, which updates nothing on screen. Every edited file now gets a target (hooks and utilities resolve to the nearest importing component, falling back to the dependents the dependency graph found), directories and deleted paths are skipped, and the client imports them all before refreshing. On stock Bun the remount fallback rendered the changed child in place of the whole page; it now re-imports the page module for the page on screen and ignores edits that do not reach it.",
48
+ "kind": "fixed",
49
+ "summary": "React edits that add a component, touch a hook or utility, or create a folder now update the page in place"
50
+ },
51
+ {
52
+ "detail": "The dev server decides between React Fast Refresh and the stock-Bun remount fallback by transpiling a probe component. The probe was named `__AbsoluteRefreshProbe`; React Fast Refresh registers only capitalized components, so it reported \"unsupported\" even on a Bun with the reactFastRefresh fix, and React edits always remounted with a warning. It now uses a capitalized name.",
53
+ "kind": "fixed",
54
+ "summary": "React Fast Refresh is used when Bun supports it, instead of always falling back to a remount"
55
+ },
56
+ {
57
+ "detail": "A React edit that failed to compile was still broadcast as an update. The browser imported a module that answered 500 and fell back to a full reload, which showed the last good page and no error. The dev server now checks the edited modules compile first and sends the error overlay (file, line and source line) instead; the save that fixes it applies as a normal in-place update. The module server handler and its transform errors also moved to globalThis: after a `bun --hot` reload failed part-way, later imports of the module server got a fresh instance that was never configured, so pre-transforming the changed module silently did nothing.",
58
+ "kind": "fixed",
59
+ "summary": "A syntax error in a React component shows the error overlay instead of reloading the page"
60
+ }
61
+ ],
62
+ "date": "2026-09-28",
63
+ "version": "0.20.0-beta.123"
64
+ },
5
65
  {
6
66
  "changes": [
7
67
  {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-LiuoUM/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-VA5kAM/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-LiuoUM/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-VA5kAM/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-LiuoUM/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-VA5kAM/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
package/dist/build.js CHANGED
@@ -21873,7 +21873,7 @@ var init_compileAngular = __esm(() => {
21873
21873
 
21874
21874
  // node_modules/content-tag/pkg/node/content_tag.cjs
21875
21875
  var require_content_tag = __commonJS(function(exports, module) {
21876
- var __dirname = "/tmp/abs-translation-fix/node_modules/content-tag/pkg/node";
21876
+ var __dirname = "/home/alexkahn/abs/absolutejs/.claude/worktrees/release/node_modules/content-tag/pkg/node";
21877
21877
  var imports = {};
21878
21878
  imports["__wbindgen_placeholder__"] = exports;
21879
21879
  var wasm;
@@ -26173,15 +26173,6 @@ var init_fileHashTracker = __esm(() => {
26173
26173
  });
26174
26174
 
26175
26175
  // src/dev/transformCache.ts
26176
- var exports_transformCache = {};
26177
- __export(exports_transformCache, {
26178
- findNearestComponent: () => findNearestComponent,
26179
- getInvalidationVersion: () => getInvalidationVersion,
26180
- getTransformed: () => getTransformed,
26181
- invalidate: () => invalidate,
26182
- invalidateAll: () => invalidateAll,
26183
- setTransformed: () => setTransformed
26184
- });
26185
26176
  var cache, importers, getTransformed = (filePath) => cache.get(filePath)?.content, setTransformed = (filePath, content, mtime, imports) => {
26186
26177
  const resolvedImports = imports ?? [];
26187
26178
  cache.set(filePath, { content, imports: resolvedImports, mtime });
@@ -26233,10 +26224,6 @@ var cache, importers, getTransformed = (filePath) => cache.get(filePath)?.conten
26233
26224
  queue.push(parent);
26234
26225
  }
26235
26226
  }
26236
- }, invalidateAll = () => {
26237
- cache.clear();
26238
- importers.clear();
26239
- invalidationVersions.clear();
26240
26227
  };
26241
26228
  var init_transformCache = __esm(() => {
26242
26229
  cache = globalThis.__transformCache ?? new Map;
@@ -26816,6 +26803,15 @@ var MAX_RETAINED_HMR_UPDATES = 100, normalizedHmrTarget = (value) => {
26816
26803
  const oldest = state.hmrUpdates.keys().next().value;
26817
26804
  if (typeof oldest === "number")
26818
26805
  state.hmrUpdates.delete(oldest);
26806
+ }, canonicalClients, canonicalClient = (client) => {
26807
+ const { raw } = client;
26808
+ if (!raw)
26809
+ return client;
26810
+ const known = canonicalClients.get(raw);
26811
+ if (known)
26812
+ return known;
26813
+ canonicalClients.set(raw, client);
26814
+ return client;
26819
26815
  }, trySendMessage = (client, messageStr) => {
26820
26816
  try {
26821
26817
  client.send(messageStr);
@@ -26842,7 +26838,7 @@ var MAX_RETAINED_HMR_UPDATES = 100, normalizedHmrTarget = (value) => {
26842
26838
  state.clientTargets.delete(client);
26843
26839
  });
26844
26840
  }, handleClientConnect = (state, client, manifest) => {
26845
- state.connectedClients.add(client);
26841
+ state.connectedClients.add(canonicalClient(client));
26846
26842
  const serverVersions = serializeModuleVersions(state.moduleVersions);
26847
26843
  client.send(JSON.stringify({
26848
26844
  data: {
@@ -26879,8 +26875,11 @@ var MAX_RETAINED_HMR_UPDATES = 100, normalizedHmrTarget = (value) => {
26879
26875
  }));
26880
26876
  }
26881
26877
  }, handleClientDisconnect = (state, client) => {
26882
- state.connectedClients.delete(client);
26883
- state.clientTargets.delete(client);
26878
+ const known = canonicalClient(client);
26879
+ state.connectedClients.delete(known);
26880
+ state.clientTargets.delete(known);
26881
+ if (client.raw)
26882
+ canonicalClients.delete(client.raw);
26884
26883
  }, parseJsonSafe = (raw) => JSON.parse(raw), parseMessage = (message) => {
26885
26884
  if (typeof message === "string") {
26886
26885
  return parseJsonSafe(message);
@@ -26956,12 +26955,13 @@ var MAX_RETAINED_HMR_UPDATES = 100, normalizedHmrTarget = (value) => {
26956
26955
  if (!isValidHMRClientMessage(parsedData)) {
26957
26956
  return;
26958
26957
  }
26959
- handleParsedMessage(state, client, parsedData);
26958
+ handleParsedMessage(state, canonicalClient(client), parsedData);
26960
26959
  } catch {}
26961
26960
  };
26962
26961
  var init_webSocket = __esm(() => {
26963
26962
  init_telemetryEvent();
26964
26963
  init_logger();
26964
+ canonicalClients = new WeakMap;
26965
26965
  });
26966
26966
 
26967
26967
  // src/utils/loadConfig.ts
@@ -33053,6 +33053,7 @@ __export(exports_moduleServer, {
33053
33053
  SRC_URL_PREFIX: () => SRC_URL_PREFIX2,
33054
33054
  createDevPageWarmer: () => createDevPageWarmer,
33055
33055
  createModuleServer: () => createModuleServer,
33056
+ getTransformError: () => getTransformError,
33056
33057
  importedBindingNames: () => importedBindingNames,
33057
33058
  invalidateModule: () => invalidateModule,
33058
33059
  isReactFastRefreshSupported: () => isReactFastRefreshSupported,
@@ -33253,7 +33254,7 @@ ${code2}`;
33253
33254
  reactFastRefresh: true
33254
33255
  };
33255
33256
  const probe = new Bun.Transpiler(probeOptions);
33256
- const out = probe.transformSync("export function __AbsoluteRefreshProbe(){return null;}");
33257
+ const out = probe.transformSync("export function AbsoluteRefreshProbe(){return null;}");
33257
33258
  return out.includes("$RefreshReg$");
33258
33259
  } catch {
33259
33260
  return false;
@@ -33262,7 +33263,7 @@ ${code2}`;
33262
33263
  if (reactFastRefreshSupported || reactFastRefreshWarningEmitted)
33263
33264
  return;
33264
33265
  reactFastRefreshWarningEmitted = true;
33265
- logWarn("React HMR is blocked: this Bun build ignores " + "`reactFastRefresh` on Bun.Transpiler, so component state " + "cannot be preserved across edits. Tracking " + "https://github.com/oven-sh/bun/pull/28312 \u2014 if it still has " + "not merged, leave a \uD83D\uDC4D on the PR so the Bun team knows it " + "is blocking you. Until then, React edits trigger a targeted " + "page remount instead of a state-preserving fast refresh.");
33266
+ logWarn("React edits remount the page instead of keeping component state: " + "this Bun ignores `reactFastRefresh` on Bun.Transpiler " + "(https://github.com/oven-sh/bun/issues/32919). Run " + "`absolute bun-patch install` to use AbsoluteJS's patched Bun, " + "which has the fix; `absolute dev` then uses it automatically.");
33266
33267
  }, transformReactFile = (filePath, projectRoot, rewriter) => {
33267
33268
  const raw = readFileSync40(filePath, "utf-8");
33268
33269
  const valueExports = tsxTranspiler.scan(raw).exports;
@@ -33812,7 +33813,27 @@ export default {};
33812
33813
  const content = await transformVueFile(filePath, projectRoot, rewriter, vueDir, stylePreprocessors);
33813
33814
  setTransformed(filePath, content, stat4.mtimeMs, extractImportedFiles(content, projectRoot));
33814
33815
  return jsResponse(content);
33815
- }, transformErrorResponse = (err) => {
33816
+ }, transformErrors, readPosition = (value) => {
33817
+ if (!value || typeof value !== "object")
33818
+ return;
33819
+ const position = Reflect.get(value, "position");
33820
+ if (!position || typeof position !== "object")
33821
+ return;
33822
+ const line = Reflect.get(position, "line");
33823
+ const column = Reflect.get(position, "column");
33824
+ const lineText = Reflect.get(position, "lineText");
33825
+ return {
33826
+ column: typeof column === "number" ? column : undefined,
33827
+ line: typeof line === "number" ? line : undefined,
33828
+ lineText: typeof lineText === "string" ? lineText : undefined
33829
+ };
33830
+ }, describeTransformError = (err) => {
33831
+ const [first] = err instanceof AggregateError && Array.isArray(err.errors) ? err.errors : [err];
33832
+ const source = first ?? err;
33833
+ const ownMessage = source && typeof source === "object" ? Reflect.get(source, "message") : undefined;
33834
+ const message = typeof ownMessage === "string" ? ownMessage : String(source);
33835
+ return { message, ...readPosition(first) };
33836
+ }, getTransformError = (filePath) => transformErrors.get(resolve51(filePath)), transformErrorResponse = (err) => {
33816
33837
  const errMsg = err instanceof Error ? err.message : String(err);
33817
33838
  return new Response(`console.error('[ModuleServer] Transform error:', ${JSON.stringify(errMsg)});`, {
33818
33839
  headers: { "Content-Type": "application/javascript" },
@@ -33840,8 +33861,11 @@ export default {};
33840
33861
  return virtualCssResponse;
33841
33862
  const { filePath, ext } = resolveSourcePath2(relPath, projectRoot);
33842
33863
  try {
33843
- return await transformAndCache(filePath, ext, projectRoot, rewriter, frameworkDirs?.vue, stylePreprocessors);
33864
+ const response = await transformAndCache(filePath, ext, projectRoot, rewriter, frameworkDirs?.vue, stylePreprocessors);
33865
+ transformErrors.delete(resolve51(filePath));
33866
+ return response;
33844
33867
  } catch (err) {
33868
+ transformErrors.set(resolve51(filePath), describeTransformError(err));
33845
33869
  return transformErrorResponse(err);
33846
33870
  }
33847
33871
  };
@@ -33854,21 +33878,23 @@ export default {};
33854
33878
  files.push(resolve51(projectRoot, match[1]));
33855
33879
  }
33856
33880
  return files;
33857
- }, invalidateModule = (filePath) => {
33881
+ }, SRC_URL_PREFIX2, invalidateModule = (filePath) => {
33858
33882
  const resolved = resolve51(filePath);
33883
+ transformErrors.delete(resolved);
33859
33884
  invalidate(filePath);
33860
33885
  if (resolved !== filePath)
33861
33886
  invalidate(resolved);
33862
33887
  mtimeCache.delete(filePath);
33863
33888
  mtimeCache.delete(resolved);
33889
+ }, setGlobalModuleServer = (handler) => {
33890
+ globalThis.__absoluteModuleServer = handler ?? undefined;
33864
33891
  }, warmCache = async (pathname) => {
33865
33892
  if (!pathname.startsWith(SRC_PREFIX))
33866
33893
  return;
33867
- if (!globalModuleServer)
33894
+ const handler = globalThis.__absoluteModuleServer;
33895
+ if (!handler)
33868
33896
  return;
33869
- await globalModuleServer(pathname);
33870
- }, globalModuleServer = null, SRC_URL_PREFIX2, setGlobalModuleServer = (handler) => {
33871
- globalModuleServer = handler;
33897
+ await handler(pathname);
33872
33898
  }, REBUILD_IDLE_POLL_MS = 10, getDevResult = () => globalThis.__hmrDevResult, resolveDevPageEntry = (keyOrPath) => {
33873
33899
  const cached = getDevResult();
33874
33900
  const lazy = cached?.hmrState.lazyPages;
@@ -34039,6 +34065,8 @@ export function __legacyDecorateParamTS(paramIndex, decorator) {
34039
34065
  return function (target, key) { decorator(target, key, paramIndex); };
34040
34066
  }
34041
34067
  `.trim();
34068
+ transformErrors = globalThis.__absoluteTransformErrors ?? new Map;
34069
+ globalThis.__absoluteTransformErrors = transformErrors;
34042
34070
  SRC_IMPORT_RE = /\/@src\/([^"'?\s]+)/g;
34043
34071
  SRC_URL_PREFIX2 = SRC_PREFIX;
34044
34072
  });
@@ -34343,7 +34371,7 @@ __export(exports_rebuildTrigger, {
34343
34371
  queueFileChange: () => queueFileChange,
34344
34372
  triggerRebuild: () => triggerRebuild
34345
34373
  });
34346
- import { existsSync as existsSync47, readdirSync as readdirSync13, rmSync as rmSync4 } from "fs";
34374
+ import { existsSync as existsSync47, readdirSync as readdirSync13, rmSync as rmSync4, statSync as statSync8 } from "fs";
34347
34375
  import {
34348
34376
  basename as basename21,
34349
34377
  dirname as dirname36,
@@ -35488,28 +35516,76 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
35488
35516
  const url = `${SRC_URL_PREFIX3}${rel}`;
35489
35517
  await warmCache2(url);
35490
35518
  return url;
35491
- }, getReactModuleUrl, resolveBroadcastTarget = async (primaryFile) => {
35492
- const isComponentFile2 = primaryFile.endsWith(".tsx") || primaryFile.endsWith(".jsx");
35493
- if (isComponentFile2)
35494
- return primaryFile;
35495
- const { findNearestComponent: findNearestComponent2 } = await Promise.resolve().then(() => (init_transformCache(), exports_transformCache));
35496
- const nearest = findNearestComponent2(resolvePath4(primaryFile));
35497
- return nearest ?? primaryFile;
35519
+ }, getReactModuleUrl, isReactComponentPath = (file5) => file5.endsWith(".tsx") || file5.endsWith(".jsx"), isReactPagePath = (file5) => file5.replace(/\\/g, "/").includes("/pages/"), isImportableModule = (file5) => {
35520
+ try {
35521
+ return statSync8(file5).isFile();
35522
+ } catch {
35523
+ return false;
35524
+ }
35525
+ }, resolveComponentTarget = (file5, reactFiles, edited) => {
35526
+ if (isReactComponentPath(file5))
35527
+ return file5;
35528
+ const nearest = findNearestComponent(resolvePath4(file5));
35529
+ if (nearest && isImportableModule(nearest))
35530
+ return nearest;
35531
+ const dependents = reactFiles.filter((candidate) => !edited.has(candidate) && isReactComponentPath(candidate) && isImportableModule(candidate));
35532
+ return dependents.find((candidate) => !isReactPagePath(candidate)) ?? dependents[0] ?? file5;
35533
+ }, resolveReactUpdateTargets = (state, reactFiles) => {
35534
+ const importable = reactFiles.filter(isImportableModule);
35535
+ const userEdited = importable.filter((file5) => state.lastUserEditedFiles?.has(resolvePath4(file5)));
35536
+ const editedFiles = userEdited.length > 0 ? userEdited : importable;
35537
+ const edited = new Set(editedFiles);
35538
+ const ordered = [
35539
+ ...editedFiles.filter((file5) => !isReactPagePath(file5)),
35540
+ ...editedFiles.filter(isReactPagePath)
35541
+ ];
35542
+ const targets = ordered.map((file5) => resolveComponentTarget(file5, reactFiles, edited));
35543
+ return { editedFiles, targets: [...new Set(targets)] };
35544
+ }, resolveAffectedPageModules = async (reactFiles) => {
35545
+ const pages = reactFiles.filter((file5) => isReactPagePath(file5) && isReactComponentPath(file5) && isImportableModule(file5));
35546
+ const entries = await Promise.all(pages.map(async (page) => [
35547
+ `${basename21(page).replace(/\.[jt]sx$/, "")}Index`,
35548
+ await getReactModuleUrl(page)
35549
+ ]));
35550
+ return Object.fromEntries(entries);
35498
35551
  }, handleReactModuleServerPath = async (state, reactFiles, startTime, fastRefreshSupported, onRebuildComplete) => {
35499
- const primaryFile = reactFiles.find((file5) => !file5.replace(/\\/g, "/").includes("/pages/")) ?? reactFiles[0];
35500
- if (!primaryFile) {
35552
+ const { invalidateModule: invalidateModule2 } = await getModuleServer();
35553
+ for (const file5 of reactFiles) {
35554
+ invalidateModule2(file5);
35555
+ }
35556
+ const { editedFiles, targets } = resolveReactUpdateTargets(state, reactFiles);
35557
+ const [primaryTarget] = targets;
35558
+ if (!primaryTarget) {
35501
35559
  onRebuildComplete({
35502
35560
  hmrState: state,
35503
35561
  manifest: state.manifest
35504
35562
  });
35505
35563
  return state.manifest;
35506
35564
  }
35507
- const { invalidateModule: invalidateModule2 } = await getModuleServer();
35508
- for (const file5 of reactFiles) {
35509
- invalidateModule2(file5);
35565
+ const moduleUrls = await Promise.all(targets.map(getReactModuleUrl));
35566
+ await Promise.all(editedFiles.filter((file5) => !targets.includes(file5)).map(getReactModuleUrl));
35567
+ const { getTransformError: getTransformError2 } = await getModuleServer();
35568
+ const failed = [...new Set([...editedFiles, ...targets])].map((file5) => ({ error: getTransformError2(file5), file: file5 })).find((entry) => entry.error !== undefined);
35569
+ if (failed?.error) {
35570
+ broadcastToClients(state, {
35571
+ data: {
35572
+ affectedFrameworks: ["react"],
35573
+ column: failed.error.column,
35574
+ error: failed.error.message,
35575
+ file: failed.file,
35576
+ framework: "react",
35577
+ line: failed.error.line,
35578
+ lineText: failed.error.lineText
35579
+ },
35580
+ message: "React module failed to compile",
35581
+ type: "rebuild-error"
35582
+ });
35583
+ onRebuildComplete({ hmrState: state, manifest: state.manifest });
35584
+ return state.manifest;
35510
35585
  }
35511
- const broadcastTarget = await resolveBroadcastTarget(primaryFile);
35512
- const pageModuleUrl = await getReactModuleUrl(broadcastTarget);
35586
+ const pageModuleUrls = fastRefreshSupported ? undefined : await resolveAffectedPageModules(reactFiles);
35587
+ const [pageModuleUrl] = moduleUrls;
35588
+ const primaryFile = reactFiles.find((file5) => isImportableModule(file5) && !isReactPagePath(file5)) ?? primaryTarget;
35513
35589
  if (pageModuleUrl) {
35514
35590
  const serverDuration = Date.now() - startTime;
35515
35591
  state.lastHmrPath = relative24(process.cwd(), primaryFile).replace(/\\/g, "/");
@@ -35521,7 +35597,9 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
35521
35597
  hasComponentChanges: true,
35522
35598
  hasCSSChanges: false,
35523
35599
  manifest: state.manifest,
35600
+ moduleUrls,
35524
35601
  pageModuleUrl,
35602
+ pageModuleUrls,
35525
35603
  primarySource: primaryFile,
35526
35604
  serverDuration,
35527
35605
  sourceFiles: reactFiles
@@ -37532,7 +37610,7 @@ __export(exports_devBuild, {
37532
37610
  devBuild: () => devBuild
37533
37611
  });
37534
37612
  import { readdir as readdir6 } from "fs/promises";
37535
- import { existsSync as existsSync49, statSync as statSync8 } from "fs";
37613
+ import { existsSync as existsSync49, statSync as statSync9 } from "fs";
37536
37614
  import { resolve as resolve55 } from "path";
37537
37615
  var FRAMEWORK_DIR_KEYS, devClientVendorSourceDir = () => resolve55(import.meta.dir, "../dev/client"), collectDepVendorSourceDirs = (config) => {
37538
37616
  const configuredDirs = [
@@ -37672,7 +37750,7 @@ var FRAMEWORK_DIR_KEYS, devClientVendorSourceDir = () => resolve55(import.meta.d
37672
37750
  });
37673
37751
  }
37674
37752
  }, handleCachedReload = async () => {
37675
- const serverMtime = statSync8(resolve55(Bun.main)).mtimeMs;
37753
+ const serverMtime = statSync9(resolve55(Bun.main)).mtimeMs;
37676
37754
  const lastMtime = globalThis.__hmrServerMtime;
37677
37755
  globalThis.__hmrServerMtime = serverMtime;
37678
37756
  const cached = globalThis.__hmrDevResult;
@@ -38053,7 +38131,7 @@ var FRAMEWORK_DIR_KEYS, devClientVendorSourceDir = () => resolve55(import.meta.d
38053
38131
  manifest
38054
38132
  };
38055
38133
  globalThis.__hmrDevResult = result;
38056
- globalThis.__hmrServerMtime = statSync8(resolve55(Bun.main)).mtimeMs;
38134
+ globalThis.__hmrServerMtime = statSync9(resolve55(Bun.main)).mtimeMs;
38057
38135
  return result;
38058
38136
  };
38059
38137
  var init_devBuild = __esm(() => {
@@ -38094,5 +38172,5 @@ export {
38094
38172
  devBuild
38095
38173
  };
38096
38174
 
38097
- //# debugId=F8C17F2264022D4D64756E2164756E21
38175
+ //# debugId=CE51F4C6C3DEBBDF64756E2164756E21
38098
38176
  //# sourceMappingURL=build.js.map