rari 0.1.3 → 0.2.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent, Routes, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, router_default, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CC4YQweh.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-BvGV8m79.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-CpI87WFQ.js";
3
3
  import "./server-build-DaBgiV55.js";
4
4
 
5
5
  export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };
@@ -5683,14 +5683,33 @@ function rari(options = {}) {
5683
5683
  }
5684
5684
  if (node.specifiers) for (const specifier of node.specifiers) exportedNames.push(specifier.exported.name);
5685
5685
  break;
5686
+ case "ExportAllDeclaration":
5687
+ if (node.exported && node.exported.type === "Identifier") exportedNames.push(node.exported.name);
5688
+ break;
5686
5689
  }
5687
5690
  return exportedNames;
5688
5691
  } catch {
5689
5692
  return [];
5690
5693
  }
5691
5694
  }
5695
+ function hasTopLevelDirective(code, directive) {
5696
+ try {
5697
+ const ast = acorn.parse(code, {
5698
+ ecmaVersion: 2024,
5699
+ sourceType: "module",
5700
+ locations: false
5701
+ });
5702
+ for (const node of ast.body) {
5703
+ if (node.type !== "ExpressionStatement" || !node.directive) break;
5704
+ if (node.directive === directive) return true;
5705
+ }
5706
+ return false;
5707
+ } catch {
5708
+ return false;
5709
+ }
5710
+ }
5692
5711
  function transformServerModule(code, id) {
5693
- if (!code.includes("use server")) return code;
5712
+ if (!hasTopLevelDirective(code, "use server")) return code;
5694
5713
  const exportedNames = parseExportedNames(code);
5695
5714
  if (exportedNames.length === 0) return code;
5696
5715
  let newCode = code;
@@ -5732,7 +5751,7 @@ if (import.meta.hot) {
5732
5751
  return newCode;
5733
5752
  }
5734
5753
  function transformClientModule(code, id) {
5735
- if (code.includes("use server")) {
5754
+ if (hasTopLevelDirective(code, "use server")) {
5736
5755
  const exportedNames$1 = parseExportedNames(code);
5737
5756
  if (exportedNames$1.length === 0) return "";
5738
5757
  const relativePath = path.relative(process$1.cwd(), id);
@@ -5742,7 +5761,7 @@ if (import.meta.hot) {
5742
5761
  else newCode$1 += `export const ${name} = createServerComponentWrapper("${componentId}_${name}", ${JSON.stringify(id)});\n`;
5743
5762
  return newCode$1;
5744
5763
  }
5745
- if (!code.includes("use client")) return code;
5764
+ if (!hasTopLevelDirective(code, "use client")) return code;
5746
5765
  const exportedNames = parseExportedNames(code);
5747
5766
  if (exportedNames.length === 0) return "";
5748
5767
  let newCode = "import {registerClientReference} from \"react-server-dom-rari/server\";\n";
@@ -5763,7 +5782,7 @@ if (import.meta.hot) {
5763
5782
  return newCode;
5764
5783
  }
5765
5784
  function transformClientModuleForClient(code, id) {
5766
- if (!code.includes("use client")) return code;
5785
+ if (!hasTopLevelDirective(code, "use client")) return code;
5767
5786
  const exportedNames = parseExportedNames(code);
5768
5787
  if (exportedNames.length === 0) return code;
5769
5788
  let newCode = code.replace(/^['"]use client['"];?\s*$/gm, "");
@@ -5809,6 +5828,38 @@ if (import.meta.hot) {
5809
5828
  const mainPlugin = {
5810
5829
  name: "rari",
5811
5830
  config(config, { command }) {
5831
+ config.resolve = config.resolve || {};
5832
+ const existingDedupe = Array.isArray(config.resolve.dedupe) ? config.resolve.dedupe : [];
5833
+ const toAdd = ["react", "react-dom"];
5834
+ config.resolve.dedupe = Array.from(new Set([...existingDedupe || [], ...toAdd]));
5835
+ const existingAlias = Array.isArray(config.resolve.alias) ? config.resolve.alias : [];
5836
+ const aliasFinds = new Set(existingAlias.map((a) => String(a.find)));
5837
+ try {
5838
+ const reactPath = __require.resolve("react");
5839
+ const reactDomClientPath = __require.resolve("react-dom/client");
5840
+ const reactJsxRuntimePath = __require.resolve("react/jsx-runtime");
5841
+ const aliasesToAppend = [];
5842
+ if (!aliasFinds.has("react/jsx-runtime")) aliasesToAppend.push({
5843
+ find: "react/jsx-runtime",
5844
+ replacement: reactJsxRuntimePath
5845
+ });
5846
+ try {
5847
+ const reactJsxDevRuntimePath = __require.resolve("react/jsx-dev-runtime");
5848
+ if (!aliasFinds.has("react/jsx-dev-runtime")) aliasesToAppend.push({
5849
+ find: "react/jsx-dev-runtime",
5850
+ replacement: reactJsxDevRuntimePath
5851
+ });
5852
+ } catch {}
5853
+ if (!aliasFinds.has("react")) aliasesToAppend.push({
5854
+ find: "react",
5855
+ replacement: reactPath
5856
+ });
5857
+ if (!aliasFinds.has("react-dom/client")) aliasesToAppend.push({
5858
+ find: "react-dom/client",
5859
+ replacement: reactDomClientPath
5860
+ });
5861
+ if (aliasesToAppend.length > 0) config.resolve.alias = [...existingAlias, ...aliasesToAppend];
5862
+ } catch {}
5812
5863
  config.environments = config.environments || {};
5813
5864
  config.environments.rsc = {
5814
5865
  resolve: { conditions: [
@@ -5875,19 +5926,19 @@ if (import.meta.hot) {
5875
5926
  transform(code, id) {
5876
5927
  if (!/\.(?:tsx?|jsx?)$/.test(id)) return null;
5877
5928
  const environment = this.environment;
5878
- if (code.includes("'use client'") || code.includes("\"use client\"")) {
5929
+ if (hasTopLevelDirective(code, "use client")) {
5879
5930
  componentTypeCache.set(id, "client");
5880
5931
  clientComponents.add(id);
5881
5932
  if (environment && (environment.name === "rsc" || environment.name === "ssr")) return transformClientModule(code, id);
5882
5933
  else return transformClientModuleForClient(code, id);
5883
5934
  }
5884
- if (code.includes("'use server'") || code.includes("\"use server\"")) {
5935
+ if (hasTopLevelDirective(code, "use server")) {
5885
5936
  componentTypeCache.set(id, "server");
5886
5937
  serverComponents.add(id);
5887
5938
  if (environment && (environment.name === "rsc" || environment.name === "ssr")) return transformServerModule(code, id);
5888
5939
  else {
5889
5940
  let clientTransformedCode = transformClientModule(code, id);
5890
- if (code.includes("'use server'") || code.includes("\"use server\"")) clientTransformedCode = `// HMR acceptance for server component
5941
+ if (hasTopLevelDirective(code, "use server")) clientTransformedCode = `// HMR acceptance for server component
5891
5942
  if (import.meta.hot) {
5892
5943
  import.meta.hot.accept();
5893
5944
  }
@@ -6455,11 +6506,24 @@ async function loadRscClient() {
6455
6506
 
6456
6507
  rscClientLoadPromise = (async () => {
6457
6508
  try {
6458
- const rscModule = await import('react-dom/server');
6509
+ const rscModule = await import('react-dom/client');
6459
6510
  createFromFetch = rscModule.createFromFetch;
6460
6511
  createFromReadableStream = rscModule.createFromReadableStream;
6512
+
6513
+ if (typeof createFromReadableStream !== 'function') {
6514
+ console.warn('createFromReadableStream is not available in react-dom/client');
6515
+ createFromReadableStream = null;
6516
+ }
6517
+ if (typeof createFromFetch !== 'function') {
6518
+ console.warn('createFromFetch is not available in react-dom/client');
6519
+ createFromFetch = null;
6520
+ }
6521
+
6461
6522
  return rscModule;
6462
6523
  } catch (error) {
6524
+ console.warn('Failed to load react-dom/client RSC functions:', error);
6525
+ createFromFetch = null;
6526
+ createFromReadableStream = null;
6463
6527
  return null;
6464
6528
  }
6465
6529
  })()
@@ -6471,8 +6535,9 @@ class RscClient {
6471
6535
  constructor() {
6472
6536
  this.componentCache = new Map();
6473
6537
  this.moduleCache = new Map();
6538
+ this.inflightRequests = new Map();
6474
6539
  this.config = {
6475
- enableStreaming: false,
6540
+ enableStreaming: true,
6476
6541
  maxRetries: 5,
6477
6542
  retryDelay: 500,
6478
6543
  timeout: 10000,
@@ -6495,48 +6560,394 @@ class RscClient {
6495
6560
  return this.componentCache.get(cacheKey);
6496
6561
  }
6497
6562
 
6498
- const encodedProps = encodeURIComponent(JSON.stringify(props));
6499
- // Add cache-busting parameter to prevent browser caching issues
6500
- const cacheBuster = Date.now();
6501
- const fetchUrl = '/rsc/render/' + componentId + '?props=' + encodedProps + '&_t=' + cacheBuster;
6563
+ if (this.inflightRequests.has(cacheKey)) {
6564
+ return this.inflightRequests.get(cacheKey);
6565
+ }
6502
6566
 
6567
+ let requestPromise;
6568
+ if (this.config.enableStreaming) {
6569
+ requestPromise = this.fetchServerComponentStreamV2(componentId, props);
6570
+ } else {
6571
+ requestPromise = (async () => {
6572
+ const encodedProps = encodeURIComponent(JSON.stringify(props));
6573
+ const cacheBuster = Date.now();
6574
+ const fetchUrl = '/rsc/render/' + componentId + '?props=' + encodedProps + '&_t=' + cacheBuster;
6575
+ await this.waitForServerReady();
6576
+ const response = await this.fetchWithTimeout(fetchUrl, {
6577
+ method: 'GET',
6578
+ headers: {
6579
+ ...this.buildRequestHeaders(),
6580
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
6581
+ 'Pragma': 'no-cache',
6582
+ 'Expires': '0'
6583
+ },
6584
+ });
6585
+ if (!response.ok) {
6586
+ throw new Error('Server responded with ' + response.status + ': ' + response.statusText);
6587
+ }
6588
+ try {
6589
+ return await this.processRscResponseManually(response);
6590
+ } catch (manualError) {
6591
+ const fallback = await this.processRscResponse(response);
6592
+ return fallback;
6593
+ }
6594
+ })();
6595
+ }
6596
+
6597
+ this.inflightRequests.set(cacheKey, requestPromise);
6503
6598
  try {
6504
- await this.waitForServerReady();
6505
-
6506
- const response = await this.fetchWithTimeout(fetchUrl, {
6507
- method: 'GET',
6508
- headers: {
6509
- ...this.buildRequestHeaders(),
6510
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
6511
- 'Pragma': 'no-cache',
6512
- 'Expires': '0'
6513
- },
6514
- });
6599
+ const result = await requestPromise;
6600
+ this.componentCache.set(cacheKey, result);
6601
+ return result;
6602
+ } finally {
6603
+ this.inflightRequests.delete(cacheKey);
6604
+ }
6515
6605
 
6516
- if (!response.ok) {
6517
- throw new Error('Server responded with ' + response.status + ': ' + response.statusText);
6518
- }
6606
+ }
6519
6607
 
6520
- let result;
6608
+ async fetchServerComponentStreamV2(componentId, props = {}) {
6609
+ await loadRscClient();
6521
6610
 
6522
- try {
6523
- result = await this.processRscResponseManually(response);
6524
- } catch (manualError) {
6611
+ const endpoints = (() => {
6612
+ const list = [
6613
+ 'http://127.0.0.1:3000/api/rsc/stream',
6614
+ 'http://localhost:3000/api/rsc/stream',
6615
+ '/api/rsc/stream',
6616
+ ];
6617
+ return list;
6618
+ })();
6619
+ let response = null;
6620
+ let lastError = null;
6621
+ const attempt = async () => {
6622
+ for (const url of endpoints) {
6525
6623
  try {
6526
- result = await this.processRscResponse(response);
6527
- } catch (error) {
6528
- console.error('Both RSC parsing methods failed:', { manualError, error });
6529
- throw new Error('Failed to parse RSC response: ' + manualError.message);
6624
+ const r = await this.fetchWithTimeout(url, {
6625
+ method: 'POST',
6626
+ headers: {
6627
+ 'Content-Type': 'application/json',
6628
+ ...this.buildRequestHeaders(),
6629
+ },
6630
+ body: JSON.stringify({ component_id: componentId, props }),
6631
+ });
6632
+ if (r.ok) {
6633
+ return r;
6634
+ }
6635
+ lastError = new Error('HTTP ' + r.status + ': ' + (await r.text()));
6636
+ } catch (e) {
6637
+ lastError = e;
6530
6638
  }
6531
6639
  }
6640
+ return null;
6641
+ };
6532
6642
 
6533
- this.componentCache.set(cacheKey, result);
6534
- return result;
6535
- } catch (error) {
6536
- throw new Error('Failed to fetch server component ' + componentId + ': ' + error.message);
6643
+ const abortController = new AbortController();
6644
+ const abortTimeout = setTimeout(() => abortController.abort(), this.config.timeout);
6645
+
6646
+ response = await attempt();
6647
+ if (!response) {
6648
+ await new Promise(r => setTimeout(r, 150));
6649
+ response = await attempt();
6650
+ }
6651
+ if (!response) {
6652
+ throw lastError || new Error('Failed to reach stream endpoint');
6653
+ }
6654
+
6655
+ if (!response.ok) {
6656
+ const errorText = await response.text();
6657
+ throw new Error('Server responded with ' + response.status + ': ' + errorText);
6537
6658
  }
6659
+
6660
+ const stream = response.body;
6661
+ if (!stream) {
6662
+ throw new Error('No ReadableStream from stream response');
6663
+ }
6664
+
6665
+ if (false && createFromReadableStream) {
6666
+ try {
6667
+ const rscPromise = createFromReadableStream(stream);
6668
+ return {
6669
+ _isRscResponse: true,
6670
+ _rscPromise: rscPromise,
6671
+ readRoot() {
6672
+ return rscPromise;
6673
+ }
6674
+ };
6675
+ } catch (error) {
6676
+ console.warn('Failed to use createFromReadableStream:', error);
6677
+ }
6678
+ }
6679
+
6680
+ const reader = stream.getReader();
6681
+ const decoder = new TextDecoder();
6682
+ let content = '';
6683
+ const modules = new Map();
6684
+ const boundaryRowMap = new Map();
6685
+
6686
+ const convertRscToReact = (element) => {
6687
+ if (!React) {
6688
+ console.warn('React not available for RSC conversion');
6689
+ return null;
6690
+ }
6691
+
6692
+ if (!element) {
6693
+ return null;
6694
+ }
6695
+
6696
+ if (typeof element === 'string' || typeof element === 'number' || typeof element === 'boolean') {
6697
+ return element;
6698
+ }
6699
+
6700
+ if (Array.isArray(element)) {
6701
+ if (element.length >= 3 && element[0] === '$') {
6702
+ const [, type, key, props] = element;
6703
+
6704
+ if (type === 'react.suspense' || type === 'suspense') {
6705
+
6706
+ const suspenseWrapper = React.createElement('div',
6707
+ {
6708
+ 'data-boundary-id': props?.boundaryId,
6709
+ boundaryId: props?.boundaryId,
6710
+ 'data-suspense-boundary': true
6711
+ },
6712
+ convertRscToReact(props?.fallback || props?.children)
6713
+ );
6714
+
6715
+ return suspenseWrapper;
6716
+ }
6717
+
6718
+ let processedProps = props ? { ...props } : {};
6719
+ if (props?.children) {
6720
+ const child = convertRscToReact(props.children);
6721
+ if (Array.isArray(child)) {
6722
+ processedProps.children = child.map((c, i) => React.isValidElement(c) ? React.cloneElement(c, { key: (c.key ?? i) }) : c);
6723
+ } else {
6724
+ processedProps.children = child;
6725
+ }
6726
+ }
6727
+
6728
+ if (typeof type === 'string') {
6729
+ if (type.startsWith('$L')) {
6730
+ const mod = modules.get(type);
6731
+ if (mod) {
6732
+ const clientKey = mod.id + '#' + (mod.name || 'default');
6733
+ const clientComponent = getClientComponent(clientKey);
6734
+ if (clientComponent) {
6735
+ const reactElement = React.createElement(clientComponent, key ? { ...processedProps, key } : processedProps);
6736
+ return reactElement;
6737
+ }
6738
+ }
6739
+ return processedProps && processedProps.children ? processedProps.children : null;
6740
+ }
6741
+ if (type.includes('.tsx#') || type.includes('.jsx#')) {
6742
+ const clientComponent = getClientComponent(type);
6743
+ if (clientComponent) {
6744
+ const reactElement = React.createElement(clientComponent, key ? { ...processedProps, key } : processedProps);
6745
+ return reactElement;
6746
+ } else {
6747
+ console.warn('Failed to resolve client component:', type);
6748
+ return null;
6749
+ }
6750
+ } else {
6751
+ if (processedProps && Object.prototype.hasOwnProperty.call(processedProps, 'boundaryId')) {
6752
+ const { boundaryId, ...rest } = processedProps;
6753
+ processedProps = rest;
6754
+ }
6755
+ const reactElement = React.createElement(type, key ? { ...processedProps, key } : processedProps);
6756
+ return reactElement;
6757
+ }
6758
+ } else {
6759
+ console.warn('Unknown RSC element type:', type);
6760
+ }
6761
+ }
6762
+
6763
+ return element.map((child, index) => {
6764
+ const converted = convertRscToReact(child);
6765
+ return converted;
6766
+ });
6767
+ }
6768
+
6769
+ if (typeof element === 'object') {
6770
+ console.warn('Unexpected object in RSC conversion:', element);
6771
+ return null;
6772
+ }
6773
+
6774
+ return element;
6775
+ };
6776
+
6777
+ let initialContent = null;
6778
+ let boundaryUpdates = new Map();
6779
+ let isComplete = false;
6780
+ let buffered = '';
6781
+
6782
+ const processStream = async () => {
6783
+ const newlineChar = String.fromCharCode(10);
6784
+
6785
+ try {
6786
+ while (true) {
6787
+ const { value, done } = await reader.read();
6788
+ if (done) {
6789
+ isComplete = true;
6790
+ break;
6791
+ }
6792
+
6793
+ const chunk = decoder.decode(value, { stream: true });
6794
+ buffered += chunk;
6795
+
6796
+ const lines = buffered.split(newlineChar);
6797
+ const completeLines = lines.slice(0, -1);
6798
+ buffered = lines[lines.length - 1];
6799
+
6800
+ for (const line of completeLines) {
6801
+ if (!line.trim()) continue;
6802
+
6803
+ try {
6804
+ const colonIndex = line.indexOf(':');
6805
+ if (colonIndex === -1) continue;
6806
+
6807
+ const rowId = line.substring(0, colonIndex);
6808
+ const content = line.substring(colonIndex + 1);
6809
+
6810
+ if (content.includes('STREAM_COMPLETE')) {
6811
+ isComplete = true;
6812
+ } else if (content.startsWith('I[')) {
6813
+ try {
6814
+ const importData = JSON.parse(content.substring(1));
6815
+ if (Array.isArray(importData) && importData.length >= 3) {
6816
+ const [path, chunks, exportName] = importData;
6817
+ modules.set('$L' + rowId, {
6818
+ id: path,
6819
+ chunks: Array.isArray(chunks) ? chunks : [chunks],
6820
+ name: exportName || 'default'
6821
+ });
6822
+ }
6823
+ } catch (e) {
6824
+ console.warn('Failed to parse import row:', content, e);
6825
+ }
6826
+ } else if (content.startsWith('E{')) {
6827
+ try {
6828
+ const err = JSON.parse(content.substring(1));
6829
+ console.error('RSC stream error:', err);
6830
+ } catch (e) {
6831
+ console.error('Failed to parse error row:', content, e);
6832
+ }
6833
+ } else if (content.startsWith('Symbol.for(')) {
6834
+ continue;
6835
+ } else if (content.startsWith('[')) {
6836
+ const parsed = JSON.parse(content);
6837
+ if (Array.isArray(parsed) && parsed.length >= 4) {
6838
+ const [marker, selector, key, props] = parsed;
6839
+ if (marker === '$' && (selector === 'react.suspense' || selector === 'suspense') && props && props.boundaryId) {
6840
+ boundaryRowMap.set('$L' + rowId, props.boundaryId);
6841
+ }
6842
+ if (marker === '$' && props && Object.prototype.hasOwnProperty.call(props, 'children')) {
6843
+ if (typeof selector === 'string' && selector.startsWith('$L')) {
6844
+ const target = boundaryRowMap.get(selector) || null;
6845
+ if (target) {
6846
+ const resolvedContent = convertRscToReact(props.children);
6847
+ boundaryUpdates.set(target, resolvedContent);
6848
+ if (streamingComponent) {
6849
+ streamingComponent.updateBoundary(target, resolvedContent);
6850
+ }
6851
+ continue;
6852
+ }
6853
+ }
6854
+ }
6855
+ }
6856
+ if (!initialContent) {
6857
+ let canUseAsRoot = true;
6858
+ if (Array.isArray(parsed) && parsed.length >= 4 && parsed[0] === '$') {
6859
+ const sel = parsed[1];
6860
+ const p = parsed[3];
6861
+ if (typeof sel === 'string' && (sel === 'react.suspense' || sel === 'suspense') && p && p.boundaryId) {
6862
+ canUseAsRoot = false;
6863
+ }
6864
+ }
6865
+ if (canUseAsRoot) {
6866
+ initialContent = convertRscToReact(parsed);
6867
+ if (streamingComponent && typeof streamingComponent.updateRoot === 'function') {
6868
+ streamingComponent.updateRoot();
6869
+ }
6870
+ }
6871
+ }
6872
+ }
6873
+ } catch (e) {
6874
+ console.warn('Failed to parse stream line:', line, e);
6875
+ }
6876
+ }
6877
+ }
6878
+ } catch (error) {
6879
+ console.error('Error processing stream:', error);
6880
+ isComplete = true;
6881
+ }
6882
+ };
6883
+
6884
+ let streamingComponent = null;
6885
+
6886
+ const StreamingWrapper = () => {
6887
+ const [renderTrigger, setRenderTrigger] = React.useState(0);
6888
+
6889
+ React.useEffect(() => {
6890
+ streamingComponent = {
6891
+ updateBoundary: (boundaryId, resolvedContent) => {
6892
+ boundaryUpdates.set(boundaryId, resolvedContent);
6893
+ setRenderTrigger(prev => prev + 1);
6894
+ },
6895
+ updateRoot: () => {
6896
+ setRenderTrigger(prev => prev + 1);
6897
+ }
6898
+ };
6899
+
6900
+ return () => {
6901
+ streamingComponent = null;
6902
+ };
6903
+ }, []);
6904
+
6905
+ const renderWithBoundaryUpdates = (element) => {
6906
+ if (!element) return null;
6907
+
6908
+ if (React.isValidElement(element)) {
6909
+ if (element.props && element.props.boundaryId) {
6910
+ const boundaryId = element.props.boundaryId;
6911
+ const resolvedContent = boundaryUpdates.get(boundaryId);
6912
+ if (resolvedContent) {
6913
+ return resolvedContent;
6914
+ }
6915
+ }
6916
+
6917
+ if (element.props && element.props.children) {
6918
+ const updatedChildren = renderWithBoundaryUpdates(element.props.children);
6919
+ if (updatedChildren !== element.props.children) {
6920
+ return React.cloneElement(element, { ...element.props, children: updatedChildren });
6921
+ }
6922
+ }
6923
+
6924
+ return element;
6925
+ }
6926
+
6927
+ if (Array.isArray(element)) {
6928
+ return element.map((child, index) => renderWithBoundaryUpdates(child));
6929
+ }
6930
+
6931
+ return element;
6932
+ };
6933
+
6934
+ const renderedContent = renderWithBoundaryUpdates(initialContent);
6935
+ return renderedContent;
6936
+ };
6937
+
6938
+ processStream();
6939
+
6940
+ return {
6941
+ _isRscResponse: true,
6942
+ _rscPromise: Promise.resolve(React.createElement(StreamingWrapper)),
6943
+ readRoot() {
6944
+ return Promise.resolve(React.createElement(StreamingWrapper));
6945
+ }
6946
+ };
6538
6947
  }
6539
6948
 
6949
+
6950
+
6540
6951
  buildRequestHeaders() {
6541
6952
  const headers = {
6542
6953
  'Accept': 'text/x-component',
@@ -6645,11 +7056,14 @@ class RscClient {
6645
7056
 
6646
7057
  let rootElement = null;
6647
7058
 
6648
- const elementKeys = Array.from(elements.keys()).sort((a, b) => parseInt(b) - parseInt(a));
6649
-
7059
+ const elementKeys = Array.from(elements.keys()).sort((a, b) => parseInt(a) - parseInt(b));
6650
7060
  for (const key of elementKeys) {
6651
7061
  const element = elements.get(key);
6652
- if (Array.isArray(element) && element[0] === '$') {
7062
+ if (Array.isArray(element) && element.length >= 2 && element[0] === '$') {
7063
+ const [, type, , props] = element;
7064
+ if (type === 'react.suspense' && props && props.boundaryId) {
7065
+ continue;
7066
+ }
6653
7067
  rootElement = element;
6654
7068
  break;
6655
7069
  }
@@ -6678,7 +7092,30 @@ class RscClient {
6678
7092
 
6679
7093
  let actualType = type;
6680
7094
 
6681
- if (typeof type === 'string' && type.startsWith('$L')) {
7095
+ if (typeof type === 'string' && type.includes('#')) {
7096
+ const clientComponent = getClientComponent(type);
7097
+ if (clientComponent) {
7098
+ actualType = clientComponent;
7099
+ } else {
7100
+ actualType = ({ children, ...restProps }) => React.createElement(
7101
+ 'div',
7102
+ {
7103
+ ...restProps,
7104
+ 'data-client-component': type,
7105
+ style: {
7106
+ border: '2px dashed #f00',
7107
+ padding: '8px',
7108
+ margin: '4px',
7109
+ backgroundColor: '#fff0f0'
7110
+ }
7111
+ },
7112
+ React.createElement('small', { style: { color: '#c00' } },
7113
+ 'Missing Client Component: ' + type
7114
+ ),
7115
+ children
7116
+ );
7117
+ }
7118
+ } else if (typeof type === 'string' && type.startsWith('$L')) {
6682
7119
  if (modules.has(type)) {
6683
7120
  const moduleData = modules.get(type);
6684
7121
  const clientComponentKey = moduleData.id + '#' + moduleData.name;
@@ -6856,9 +7293,7 @@ function ServerComponentWrapper({
6856
7293
  }, [componentId, JSON.stringify(props)]);
6857
7294
 
6858
7295
  if (loading) {
6859
- return fallback || React.createElement('div', { className: 'rsc-loading' },
6860
- 'Loading ' + componentId + '...'
6861
- );
7296
+ return fallback || null;
6862
7297
  }
6863
7298
 
6864
7299
  if (error) {
@@ -6871,7 +7306,7 @@ function ServerComponentWrapper({
6871
7306
  if (data) {
6872
7307
  if (data._isRscResponse) {
6873
7308
  return React.createElement(Suspense,
6874
- { fallback: fallback || React.createElement('div', null, 'Loading...') },
7309
+ { fallback: fallback || null },
6875
7310
  data.readRoot()
6876
7311
  );
6877
7312
  } else if (data) {
@@ -6919,11 +7354,12 @@ function createServerComponentWrapper(componentName, importPath) {
6919
7354
  }, []);
6920
7355
 
6921
7356
  return React.createElement(Suspense, {
6922
- fallback: React.createElement('div', null, 'Loading ' + componentName + '...')
7357
+ fallback: null
6923
7358
  }, React.createElement(ServerComponentWrapper, {
6924
7359
  key: componentName + '-' + mountKey, // Force re-mount with key change
6925
7360
  componentId: componentName,
6926
- props: props
7361
+ props: props,
7362
+ fallback: null
6927
7363
  }));
6928
7364
  };
6929
7365
 
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent, Routes, buildSearchString, buildUrl, createHttpRuntimeClient, extractParamNames, findMatchingRoute, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, normalizePathname, parseSearchParams, parseUrl, router_default, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, withRouter } from "./runtime-client-CC4YQweh.js";
2
- import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-BvGV8m79.js";
2
+ import { FileRouteGenerator, convertFilePatternToRoutePattern, createRouteManifest, defineRariConfig, generateFileRoutes, loadRouteManifest, rari, rariRouter, validateRoutes, watchFileRoutes } from "./server-CpI87WFQ.js";
3
3
  import "./server-build-DaBgiV55.js";
4
4
 
5
5
  export { FileRouteGenerator, HttpRuntimeClient, Link, Navigate, Outlet, RouteComponent as Route, router_default as RouterProvider, Routes, buildSearchString, buildUrl, convertFilePatternToRoutePattern, createHttpRuntimeClient, createRouteManifest, defineRariConfig, extractParamNames, findMatchingRoute, generateFileRoutes, getRoutePriority, isDynamicRoute, isPathActive, joinPaths, loadRouteManifest, normalizePathname, parseSearchParams, parseUrl, rari, rariRouter, useNavigation, useParams, usePathname, useRoute, useRouter, useSearchParams, validateRoutes, watchFileRoutes, withRouter };