@absolutejs/absolute 0.20.0-beta.4 → 0.20.0-beta.6

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 (46) hide show
  1. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  2. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  3. package/dist/angular/index.js +341 -22
  4. package/dist/angular/index.js.map +8 -5
  5. package/dist/angular/server.js +341 -22
  6. package/dist/angular/server.js.map +8 -5
  7. package/dist/build.js +94 -22
  8. package/dist/build.js.map +9 -9
  9. package/dist/cli/index.js +986 -557
  10. package/dist/dev/client/cssUtils.ts +16 -2
  11. package/dist/dev/client/handlers/rebuild.ts +11 -1
  12. package/dist/dev/client/hmrTiming.ts +14 -7
  13. package/dist/index.js +364 -191
  14. package/dist/index.js.map +17 -17
  15. package/dist/mobile/browser.js +14 -1
  16. package/dist/mobile/browser.js.map +3 -3
  17. package/dist/mobile/index.js +588 -99
  18. package/dist/mobile/index.js.map +15 -13
  19. package/dist/mobile/remoteMacAgentEntry.js +8 -8
  20. package/dist/src/angular/pageHandler.d.ts +3 -0
  21. package/dist/src/cli/config/server.d.ts +1 -1
  22. package/dist/src/core/pageHandlers.d.ts +11 -2
  23. package/dist/src/mobile/androidEmulatorController.d.ts +6 -1
  24. package/dist/src/mobile/buildPipeline.d.ts +1 -0
  25. package/dist/src/mobile/capacitorBundle.d.ts +11 -1
  26. package/dist/src/mobile/client.d.ts +4 -0
  27. package/dist/src/mobile/index.d.ts +1 -0
  28. package/dist/src/mobile/nativeAuth.d.ts +17 -0
  29. package/dist/src/mobile/releaseArtifact.d.ts +2 -0
  30. package/dist/src/mobile/shellAuth.d.ts +8 -0
  31. package/dist/src/mobile/shellBootstrap.d.ts +11 -1
  32. package/dist/src/mobile/shellSync.d.ts +2 -0
  33. package/dist/src/mobile/staticDocument.d.ts +5 -0
  34. package/dist/src/mobile/transport.d.ts +9 -1
  35. package/dist/src/plugins/imageOptimizer.d.ts +1 -1
  36. package/dist/src/svelte/pageHandler.d.ts +3 -0
  37. package/dist/src/vue/pageHandler.d.ts +3 -0
  38. package/dist/svelte/index.js +312 -23
  39. package/dist/svelte/index.js.map +7 -4
  40. package/dist/svelte/server.js +307 -18
  41. package/dist/svelte/server.js.map +7 -4
  42. package/dist/vue/index.js +312 -23
  43. package/dist/vue/index.js.map +7 -4
  44. package/dist/vue/server.js +307 -18
  45. package/dist/vue/server.js.map +7 -4
  46. package/package.json +21 -9
package/dist/index.js CHANGED
@@ -10213,9 +10213,10 @@ var indexContentCache, resolveDevClientDir = () => {
10213
10213
  `}
10214
10214
  `,
10215
10215
  `// Attempt hydration with error handling`,
10216
+ `const shouldClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';`,
10216
10217
  `// Use document (not document.body) when the page renders <html><head><body>`,
10217
10218
  `// to avoid "In HTML, <html> cannot be a child of <body>" hydration error`,
10218
- `const container = typeof document !== 'undefined' ? document : null;`,
10219
+ `const container = typeof document !== 'undefined' ? (shouldClientRender ? document.getElementById('root') : document) : null;`,
10219
10220
  `if (!container) {`,
10220
10221
  ` throw new Error('React root container not found: document is null');`,
10221
10222
  `}
@@ -10241,7 +10242,6 @@ var indexContentCache, resolveDevClientDir = () => {
10241
10242
  `if (!window.__REACT_ROOT__) {`,
10242
10243
  ` let root;`,
10243
10244
  ` // Mobile data envelopes and dirty HMR pages have no matching SSR markup.`,
10244
- ` const shouldClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';`,
10245
10245
  ` if (window.__SSR_DIRTY__ || shouldClientRender) {`,
10246
10246
  ` root = createRoot(container);`,
10247
10247
  ` root.render(${isDev2 ? `createElement(ErrorBoundary, null, createElement(PageComponent, mergedProps))` : `createElement(PageComponent, mergedProps)`});`,
@@ -10321,6 +10321,15 @@ var indexContentCache, resolveDevClientDir = () => {
10321
10321
  ` };`,
10322
10322
  ` }`,
10323
10323
  `}`,
10324
+ `if (typeof window !== 'undefined') {`,
10325
+ ` window.__ABSOLUTE_PAGE_READY__ = Promise.resolve();`,
10326
+ ` window.__ABSOLUTE_PAGE_DISPOSE__ = function() {`,
10327
+ ` if (window.__REACT_ROOT__ && typeof window.__REACT_ROOT__.unmount === 'function') {`,
10328
+ ` window.__REACT_ROOT__.unmount();`,
10329
+ ` }`,
10330
+ ` window.__REACT_ROOT__ = null;`,
10331
+ ` };`,
10332
+ `}`,
10324
10333
  ...isDev2 ? [
10325
10334
  `
10326
10335
  // Pre-warm: import the page module from the module server`,
@@ -13031,7 +13040,8 @@ var heldLocks, HELD_LOCKS_ENV = "ABSOLUTE_HELD_BUILD_DIRECTORY_LOCKS", exitHandl
13031
13040
  });
13032
13041
  process.on("uncaughtException", (err) => {
13033
13042
  releaseAllSync();
13034
- throw err;
13043
+ console.error(err);
13044
+ process.exit(1);
13035
13045
  });
13036
13046
  }, isAlreadyExistsError = (error) => error instanceof Error && ("code" in error) && Reflect.get(error, "code") === "EEXIST", lockPathForBuildDirectory = (buildDirectory) => join28(dirname15(buildDirectory), ".absolutejs", "build.lock"), readHeldLockEnv = () => new Set((process.env[HELD_LOCKS_ENV] ?? "").split(`
13037
13047
  `).filter((entry) => entry.length > 0)), writeHeldLockEnv = (locks) => {
@@ -14045,8 +14055,9 @@ import { hydrate, mount, unmount } from "svelte";
14045
14055
  var initialProps = (typeof window !== "undefined" && window.__INITIAL_PROPS__) ? window.__INITIAL_PROPS__ : {};
14046
14056
  var isHMR = typeof window !== "undefined" && window.__SVELTE_COMPONENT__ !== undefined;
14047
14057
  var isSsrDirty = typeof window !== "undefined" && window.__SSR_DIRTY__;
14058
+ var isClientRender = typeof window !== "undefined" && window.__ABSOLUTE_PAGE_RENDER_MODE__ === "client";
14048
14059
  var hasIslandHtml = false;
14049
- var shouldHydrate = typeof window === "undefined" ? false : ${hasAwaitSlot ? "false" : "true"};
14060
+ var shouldHydrate = typeof window === "undefined" || isClientRender ? false : ${hasAwaitSlot ? "false" : "true"};
14050
14061
  var component;
14051
14062
  var target = document.getElementById(${JSON.stringify(SVELTE_PAGE_ROOT_ID)}) || document.body;
14052
14063
 
@@ -14077,6 +14088,8 @@ if (isHMR) {
14077
14088
  }
14078
14089
  component = mount(Component, { target, props: mergedProps });
14079
14090
  window.__HMR_PRESERVED_STATE__ = undefined;
14091
+ } else if (isClientRender) {
14092
+ component = mount(Component, { target, props: initialProps });
14080
14093
  } else if (!shouldHydrate) {
14081
14094
  component = undefined;
14082
14095
  } else if (isSsrDirty || hasIslandHtml) {
@@ -14088,6 +14101,13 @@ if (isHMR) {
14088
14101
  if (typeof window !== "undefined") {
14089
14102
  window.__SVELTE_COMPONENT__ = component;
14090
14103
  window.__SVELTE_UNMOUNT__ = function() { if (component) { unmount(component); } };
14104
+ window.__ABSOLUTE_PAGE_READY__ = Promise.resolve();
14105
+ window.__ABSOLUTE_PAGE_DISPOSE__ = function() {
14106
+ if (component) { unmount(component); }
14107
+ component = undefined;
14108
+ window.__SVELTE_COMPONENT__ = undefined;
14109
+ window.__SVELTE_UNMOUNT__ = undefined;
14110
+ };
14091
14111
  window.__SVELTE_REMOUNT__ = function(props) {
14092
14112
  if (typeof window.__SVELTE_UNMOUNT__ === "function") {
14093
14113
  try { window.__SVELTE_UNMOUNT__(); } catch (err) { /* ignore */ }
@@ -15063,7 +15083,8 @@ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
15063
15083
  "// client-side navigation after mount.",
15064
15084
  'const isHMR = typeof window !== "undefined" && sessionStorage.getItem("__HMR_ACTIVE__");',
15065
15085
  'const isSsrDirty = typeof window !== "undefined" && window.__SSR_DIRTY__;',
15066
- 'const shouldHydrate = typeof window === "undefined" ? false : !(isHMR || isSsrDirty || hasSpaRoutes);',
15086
+ 'const isClientRender = typeof window !== "undefined" && window.__ABSOLUTE_PAGE_RENDER_MODE__ === "client";',
15087
+ 'const shouldHydrate = typeof window === "undefined" ? false : !(isHMR || isSsrDirty || hasSpaRoutes || isClientRender);',
15067
15088
  "const app = shouldHydrate ? createSSRApp(Comp, mergedProps) : createApp(Comp, mergedProps);",
15068
15089
  "",
15069
15090
  "async function bootstrapApp() {",
@@ -15081,11 +15102,17 @@ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
15081
15102
  " }",
15082
15103
  ' app.mount("#root");',
15083
15104
  "}",
15084
- "bootstrapApp();",
15105
+ "const absolutePageReady = bootstrapApp();",
15085
15106
  "",
15086
15107
  "// Store app instance for HMR - used for manual component updates",
15087
15108
  'if (typeof window !== "undefined") {',
15088
15109
  " window.__VUE_APP__ = app;",
15110
+ " window.__ABSOLUTE_PAGE_READY__ = absolutePageReady;",
15111
+ " window.__ABSOLUTE_PAGE_DISPOSE__ = async function() {",
15112
+ " await absolutePageReady;",
15113
+ " app.unmount();",
15114
+ " window.__VUE_APP__ = undefined;",
15115
+ " };",
15089
15116
  "}",
15090
15117
  "",
15091
15118
  "// Post-mount: Apply preserved state to reactive refs in component tree",
@@ -16838,6 +16865,7 @@ var requestContext = Object.prototype.hasOwnProperty.call(window, '__ABS_ANGULAR
16838
16865
  var pageHasIslands = Boolean(pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__) || Boolean(document.querySelector('[data-island="true"]'));
16839
16866
  var pageHasRawStreamingSlots = Boolean(document.querySelector('[data-absolute-raw-slot="true"]'));
16840
16867
  var pageHasStreamingSlots = Boolean(document.querySelector('[data-absolute-slot="true"]'));
16868
+ var isClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';
16841
16869
  var contextProviders = [{ provide: REQUEST_CONTEXT, useValue: requestContext }];
16842
16870
  // Page-level providers are injected directly into the page module's
16843
16871
  // server output by \`compileAngular\`'s providers-injection step
@@ -16888,13 +16916,14 @@ if (!document.querySelector(_sel)) {
16888
16916
  }
16889
16917
 
16890
16918
  var providers = [provideZonelessChangeDetection()];
16891
- if (!window.__HMR_SKIP_HYDRATION__ && !pageHasIslands) {
16919
+ if (!isClientRender && !window.__HMR_SKIP_HYDRATION__ && !pageHasIslands) {
16892
16920
  providers.push(provideClientHydration(withHttpTransferCacheOptions(absoluteHttpTransferCacheOptions)));
16893
16921
  }
16894
16922
  delete window.__HMR_SKIP_HYDRATION__;
16895
16923
  providers.push.apply(providers, pageProviders);
16896
16924
  providers.push.apply(providers, contextProviders);
16897
16925
  window.__ABS_SLOT_HYDRATION_PENDING__ = pageHasRawStreamingSlots;
16926
+ var absolutePageReady = Promise.resolve();
16898
16927
 
16899
16928
  if (pageHasRawStreamingSlots) {
16900
16929
  window.__ABS_SLOT_HYDRATION_PENDING__ = false;
@@ -16904,7 +16933,7 @@ if (pageHasRawStreamingSlots) {
16904
16933
  });
16905
16934
  }
16906
16935
  } else {
16907
- bootstrapApplication(${componentClassName}, {
16936
+ absolutePageReady = bootstrapApplication(${componentClassName}, {
16908
16937
  providers: providers
16909
16938
  }).then(function (appRef) {
16910
16939
  window.__ANGULAR_APP__ = appRef;
@@ -16914,8 +16943,17 @@ if (pageHasRawStreamingSlots) {
16914
16943
  window.__ABS_SLOT_FLUSH__();
16915
16944
  });
16916
16945
  }
16946
+ return appRef;
16917
16947
  });
16918
16948
  }
16949
+ window.__ABSOLUTE_PAGE_READY__ = absolutePageReady;
16950
+ window.__ABSOLUTE_PAGE_DISPOSE__ = async function() {
16951
+ await absolutePageReady;
16952
+ if (window.__ANGULAR_APP__) {
16953
+ window.__ANGULAR_APP__.destroy();
16954
+ window.__ANGULAR_APP__ = null;
16955
+ }
16956
+ };
16919
16957
  `.trim() : `
16920
16958
  import '@angular/compiler';
16921
16959
  import { bootstrapApplication } from '@angular/platform-browser';
@@ -16934,6 +16972,7 @@ var requestContext = Object.prototype.hasOwnProperty.call(window, '__ABS_ANGULAR
16934
16972
  var pageHasIslands = Boolean(pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__) || Boolean(document.querySelector('[data-island="true"]'));
16935
16973
  var pageHasRawStreamingSlots = Boolean(document.querySelector('[data-absolute-raw-slot="true"]'));
16936
16974
  var pageHasStreamingSlots = Boolean(document.querySelector('[data-absolute-slot="true"]'));
16975
+ var isClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';
16937
16976
  var contextProviders = [{ provide: REQUEST_CONTEXT, useValue: requestContext }];
16938
16977
  // Page-level providers are injected directly into the page module's
16939
16978
  // server output by \`compileAngular\`'s providers-injection step
@@ -16953,11 +16992,21 @@ var absoluteHttpTransferCacheOptions = {
16953
16992
 
16954
16993
  enableProdMode();
16955
16994
 
16995
+ // Production mobile/client-only activation starts from AbsoluteJS's empty
16996
+ // #root shell rather than server-rendered Angular markup. Create the page's
16997
+ // actual Angular host from its compiled selector so application authors do
16998
+ // not need framework-specific mobile configuration.
16999
+ var _sel = ${componentClassName}.\u0275cmp?.selectors?.[0]?.[0] || 'ng-app';
17000
+ if (!document.querySelector(_sel)) {
17001
+ (document.getElementById('root') || document.body).appendChild(document.createElement(_sel));
17002
+ }
17003
+
16956
17004
  var providers = [provideZonelessChangeDetection()].concat(pageProviders).concat(contextProviders);
16957
- if (!pageHasIslands) {
17005
+ if (!isClientRender && !pageHasIslands) {
16958
17006
  providers.unshift(provideClientHydration(withHttpTransferCacheOptions(absoluteHttpTransferCacheOptions)));
16959
17007
  }
16960
17008
  window.__ABS_SLOT_HYDRATION_PENDING__ = pageHasRawStreamingSlots;
17009
+ var absolutePageReady = Promise.resolve();
16961
17010
 
16962
17011
  if (pageHasRawStreamingSlots) {
16963
17012
  window.__ABS_SLOT_HYDRATION_PENDING__ = false;
@@ -16967,7 +17016,7 @@ if (pageHasRawStreamingSlots) {
16967
17016
  });
16968
17017
  }
16969
17018
  } else {
16970
- bootstrapApplication(${componentClassName}, {
17019
+ absolutePageReady = bootstrapApplication(${componentClassName}, {
16971
17020
  providers: providers
16972
17021
  }).then(function (appRef) {
16973
17022
  window.__ANGULAR_APP__ = appRef;
@@ -16977,8 +17026,17 @@ if (pageHasRawStreamingSlots) {
16977
17026
  window.__ABS_SLOT_FLUSH__();
16978
17027
  });
16979
17028
  }
17029
+ return appRef;
16980
17030
  });
16981
17031
  }
17032
+ window.__ABSOLUTE_PAGE_READY__ = absolutePageReady;
17033
+ window.__ABSOLUTE_PAGE_DISPOSE__ = async function() {
17034
+ await absolutePageReady;
17035
+ if (window.__ANGULAR_APP__) {
17036
+ window.__ANGULAR_APP__.destroy();
17037
+ window.__ANGULAR_APP__ = null;
17038
+ }
17039
+ };
16982
17040
  `.trim();
16983
17041
  const indexHash = Bun.hash(hydration).toString(BASE_36_RADIX);
16984
17042
  const indexUnchanged = cachedWrapper?.indexHash === indexHash;
@@ -27758,7 +27816,7 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
27758
27816
  });
27759
27817
  });
27760
27818
  return allModuleUpdates;
27761
- }, handleReactHMR = (state, affectedFrameworks, filesToRebuild, manifest, duration) => {
27819
+ }, handleReactHMR = async (state, affectedFrameworks, filesToRebuild, manifest, duration) => {
27762
27820
  if (!affectedFrameworks.includes("react") || !state.resolvedPaths.reactDir) {
27763
27821
  return;
27764
27822
  }
@@ -27770,14 +27828,21 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
27770
27828
  const sourceFiles = reactPageFiles.length > 0 ? reactPageFiles : reactFiles;
27771
27829
  const [primarySource] = sourceFiles;
27772
27830
  try {
27773
- const hasComponentChanges = reactFiles.some((file5) => file5.endsWith(".tsx") || file5.endsWith(".ts") || file5.endsWith(".jsx"));
27774
- const hasCSSChanges = reactFiles.some(isStylePath);
27831
+ const {
27832
+ isReactFastRefreshSupported: isReactFastRefreshSupported2,
27833
+ warnIfReactFastRefreshUnsupported: warnIfReactFastRefreshUnsupported2
27834
+ } = await Promise.resolve().then(() => (init_moduleServer(), exports_moduleServer));
27835
+ warnIfReactFastRefreshUnsupported2();
27836
+ await handleReactModuleServerPath(state, reactFiles, Date.now() - duration, isReactFastRefreshSupported2(), () => {
27837
+ return;
27838
+ });
27839
+ } catch (err) {
27775
27840
  logHmrUpdate(primarySource ?? reactFiles[0] ?? "", "react", duration);
27776
27841
  broadcastToClients(state, {
27777
27842
  data: {
27778
27843
  framework: "react",
27779
- hasComponentChanges,
27780
- hasCSSChanges,
27844
+ hasComponentChanges: true,
27845
+ hasCSSChanges: reactFiles.some(isStylePath),
27781
27846
  manifest,
27782
27847
  primarySource,
27783
27848
  serverDuration: duration,
@@ -27785,7 +27850,6 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
27785
27850
  },
27786
27851
  type: "react-update"
27787
27852
  });
27788
- } catch (err) {
27789
27853
  console.error("[hmr] react live update failed:", err instanceof Error ? err.message : err);
27790
27854
  sendTelemetryEvent("hmr:error", {
27791
27855
  framework: "react",
@@ -27844,8 +27908,14 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
27844
27908
  }
27845
27909
  setCurrentPageIslandMetadata(await loadPageIslandMetadata(config));
27846
27910
  const affectedPages = filesToRebuild.flatMap((file5) => getPagesUsingIslandSource(file5));
27911
+ if (affectedPages.length === 0)
27912
+ return true;
27913
+ const affectedFrameworks = [
27914
+ ...new Set(affectedPages.map((page) => detectFramework(page, state.resolvedPaths)).filter((framework) => framework !== "ignored"))
27915
+ ];
27847
27916
  broadcastToClients(state, {
27848
27917
  data: {
27918
+ affectedFrameworks,
27849
27919
  affectedPages,
27850
27920
  framework: "islands",
27851
27921
  manifest,
@@ -28237,7 +28307,7 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
28237
28307
  }
28238
28308
  }, handleFullBuildHMR = async (state, config, affectedFrameworks, filesToRebuild, manifest, duration) => {
28239
28309
  const allModuleUpdates = collectAllModuleUpdates(affectedFrameworks, filesToRebuild, manifest, state);
28240
- handleReactHMR(state, affectedFrameworks, filesToRebuild, manifest, duration);
28310
+ await handleReactHMR(state, affectedFrameworks, filesToRebuild, manifest, duration);
28241
28311
  handleHTMLScriptHMR(state, filesToRebuild, manifest, duration);
28242
28312
  await handleHTMLPageHMR(state, config, filesToRebuild, manifest, duration);
28243
28313
  await handleVueHMR(state, config, filesToRebuild, manifest, duration);
@@ -28464,7 +28534,8 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
28464
28534
  message: "Rebuild completed successfully",
28465
28535
  type: "rebuild-complete"
28466
28536
  });
28467
- if (config.tailwind && filesToRebuild && filesToRebuild.some(isTailwindCandidate)) {
28537
+ const hasDedicatedStyleUpdate = affectedFrameworks.some((framework) => framework === "styles" || framework === "assets");
28538
+ if (config.tailwind && filesToRebuild && filesToRebuild.some(isTailwindCandidate) && !hasDedicatedStyleUpdate) {
28468
28539
  try {
28469
28540
  const outputPath = resolvePath3(state.resolvedPaths.buildDir, config.tailwind.output);
28470
28541
  const bytes = await Bun.file(outputPath).bytes();
@@ -28485,6 +28556,7 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
28485
28556
  const hasFilesToRebuild = filesToRebuild && filesToRebuild.length > 0;
28486
28557
  const didReloadForIslandChange = hasFilesToRebuild ? await handleIslandSourceReload(state, config, filesToRebuild, manifest, duration) : false;
28487
28558
  if (didReloadForIslandChange) {
28559
+ await runFrameworkFastPaths(state, config, affectedFrameworks, filesToRebuild ?? [], startTime, onRebuildComplete);
28488
28560
  onRebuildComplete({ hmrState: state, manifest });
28489
28561
  return manifest;
28490
28562
  }
@@ -29154,6 +29226,9 @@ var FRAMEWORK_DIR_KEYS, collectDepVendorSourceDirs = (config) => {
29154
29226
  await handleCachedReload();
29155
29227
  return cached;
29156
29228
  }
29229
+ if (config.reactDirectory && !globalThis.__reactModuleRef) {
29230
+ globalThis.__reactModuleRef = await import("react");
29231
+ }
29157
29232
  const startupSteps = [];
29158
29233
  const recordStep = (label, startedAt) => {
29159
29234
  const durationMs = performance.now() - startedAt;
@@ -29329,9 +29404,6 @@ var FRAMEWORK_DIR_KEYS, collectDepVendorSourceDirs = (config) => {
29329
29404
  config.vueDirectory ? loadVendorFiles(state.assetStore, vueVendorDir, "vue") : Promise.resolve(),
29330
29405
  loadVendorFiles(state.assetStore, depVendorDir, "vendor")
29331
29406
  ]);
29332
- if (config.reactDirectory && !globalThis.__reactModuleRef) {
29333
- globalThis.__reactModuleRef = await import("react");
29334
- }
29335
29407
  recordStep("load vendor files", stepStartedAt);
29336
29408
  stepStartedAt = performance.now();
29337
29409
  const { warmCompilers: warmCompilers2 } = await Promise.resolve().then(() => (init_moduleServer(), exports_moduleServer));
@@ -30895,157 +30967,6 @@ var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
30895
30967
  });
30896
30968
  };
30897
30969
 
30898
- // src/core/pageHandlers.ts
30899
- var handleStaticPageRequest = async (pagePath, options = {}, settings = {}) => {
30900
- const html = await file(pagePath).text();
30901
- const transformedHtml = await transformCurrentStaticPageHtml(html, settings);
30902
- return withPageCacheHeaders(await withStreamingSlots(new Response(injectIslandPageContext(transformedHtml), {
30903
- headers: { "Content-Type": "text/html" }
30904
- }), {
30905
- ...options,
30906
- streamingSlots: options.streamingSlots ?? []
30907
- }));
30908
- };
30909
- var handleHTMLPageRequest = (pagePath, options) => {
30910
- const htmlFile = file(pagePath);
30911
- return htmlFile.text().then((html) => {
30912
- if (extractStaticStreamingTags(html).length > 0) {
30913
- throw new Error(`HTML page "${pagePath}" uses <abs-stream-slot>, but HTML pages should pass explicit streamingSlots to handleHTMLPageRequest(...).`);
30914
- }
30915
- return handleStaticPageRequest(pagePath, options, {
30916
- enableStaticStreaming: false
30917
- });
30918
- });
30919
- };
30920
- var handleHTMXPageRequest = async (pagePath) => {
30921
- const html = await file(pagePath).text();
30922
- if (extractStaticStreamingTags(html).length > 0) {
30923
- throw new Error(`HTMX page "${pagePath}" uses <abs-stream-slot>, but HTMX pages should use native hx-* fragment requests instead.`);
30924
- }
30925
- return handleStaticPageRequest(pagePath, {}, {
30926
- enableHTMXStreaming: true,
30927
- enableStaticStreaming: false
30928
- });
30929
- };
30930
- // src/core/prepare.ts
30931
- import { createHash as createHash8 } from "crypto";
30932
- import { existsSync as existsSync39, readdirSync as readdirSync10, readFileSync as readFileSync33 } from "fs";
30933
- import { basename as basename18, join as join50, relative as relative19, resolve as resolvePath4 } from "path";
30934
- import { Elysia as Elysia9, NotFound } from "elysia";
30935
-
30936
- // src/plugins/openApiPlugin.ts
30937
- import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
30938
- import { join as join11 } from "path";
30939
- var FALLBACK_NAME = "AbsoluteJS API";
30940
- var FALLBACK_VERSION = "1.0.0";
30941
- var projectInfo = (cwd) => {
30942
- const path = join11(cwd, "package.json");
30943
- if (!existsSync7(path)) {
30944
- return { name: FALLBACK_NAME, version: FALLBACK_VERSION };
30945
- }
30946
- try {
30947
- const pkg = JSON.parse(readFileSync8(path, "utf-8"));
30948
- return {
30949
- name: typeof pkg.name === "string" ? pkg.name : FALLBACK_NAME,
30950
- version: typeof pkg.version === "string" ? pkg.version : FALLBACK_VERSION
30951
- };
30952
- } catch {
30953
- return { name: FALLBACK_NAME, version: FALLBACK_VERSION };
30954
- }
30955
- };
30956
- var openApiEnabled = (config, isDev) => isDev ? config.openapi !== false : Boolean(config.openapi);
30957
- var createOpenApiPlugin = async (config, cwd) => {
30958
- const setting = config.openapi;
30959
- const options = typeof setting === "object" ? setting : {};
30960
- const info = projectInfo(cwd);
30961
- const { openapi } = await import("@elysia/openapi");
30962
- return openapi({
30963
- documentation: {
30964
- info: {
30965
- description: options.documentation?.description,
30966
- title: options.documentation?.title ?? info.name,
30967
- version: options.documentation?.version ?? info.version
30968
- }
30969
- },
30970
- exclude: {
30971
- paths: [
30972
- /^\/_/,
30973
- /^\/@/,
30974
- /^\/__absolute/,
30975
- /^\/hmr/,
30976
- /^\/\.well-known/,
30977
- /^\/chunk-/,
30978
- /^\/node_modules/
30979
- ]
30980
- },
30981
- path: options.path ?? "/openapi",
30982
- provider: options.provider === "swagger" ? "swagger-ui" : "scalar"
30983
- });
30984
- };
30985
- var withOpenApi = async (app, config, cwd, isDev) => {
30986
- if (!openApiEnabled(config, isDev))
30987
- return app;
30988
- try {
30989
- return app.use(await createOpenApiPlugin(config, cwd));
30990
- } catch (error) {
30991
- const detail = error instanceof Error ? error.message : String(error);
30992
- console.warn(`[absolute] OpenAPI docs disabled \u2014 install @elysia/openapi (${detail})`);
30993
- return app;
30994
- }
30995
- };
30996
-
30997
- // src/plugins/telemetryPlugin.ts
30998
- import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
30999
- import { join as join12 } from "path";
31000
- var OTEL_PACKAGE = "@elysia/opentelemetry";
31001
- var readPackageName = (cwd) => {
31002
- const path = join12(cwd, "package.json");
31003
- if (!existsSync8(path))
31004
- return null;
31005
- try {
31006
- const pkg = JSON.parse(readFileSync9(path, "utf-8"));
31007
- return typeof pkg.name === "string" ? pkg.name : null;
31008
- } catch {
31009
- return null;
31010
- }
31011
- };
31012
- var serviceNameFor = (config, cwd) => {
31013
- const setting = config.telemetry;
31014
- if (typeof setting === "object" && setting.serviceName) {
31015
- return setting.serviceName;
31016
- }
31017
- return readPackageName(cwd) ?? "absolutejs-app";
31018
- };
31019
- var withTelemetry = async (app, config, cwd) => {
31020
- if (!config.telemetry)
31021
- return app;
31022
- try {
31023
- const { opentelemetry } = await import(OTEL_PACKAGE);
31024
- return app.use(opentelemetry({ serviceName: serviceNameFor(config, cwd) }));
31025
- } catch (error) {
31026
- const detail = error instanceof Error ? error.message : String(error);
31027
- console.warn(`[absolute] telemetry enabled but ${OTEL_PACKAGE} isn't installed \u2014 run \`bun add ${OTEL_PACKAGE}\` (${detail})`);
31028
- return app;
31029
- }
31030
- };
31031
-
31032
- // src/core/prepare.ts
31033
- init_loadConfig();
31034
-
31035
- // src/utils/iconVersion.ts
31036
- var iconMimeType = (icon) => {
31037
- if (icon.endsWith(".svg"))
31038
- return "image/svg+xml";
31039
- if (icon.endsWith(".png"))
31040
- return "image/png";
31041
- return "image/x-icon";
31042
- };
31043
- var resolver;
31044
- var applyIconVersion = (href) => resolver ? resolver(href) : href;
31045
- var setIconVersionResolver = (resolverFn) => {
31046
- resolver = resolverFn;
31047
- };
31048
-
31049
30970
  // src/core/requestContext.ts
31050
30971
  import { AsyncLocalStorage } from "async_hooks";
31051
30972
  import { Elysia } from "elysia";
@@ -31071,9 +30992,6 @@ var absoluteRequestContext = new Elysia({
31071
30992
  var getCurrentAbsoluteRequest = () => getRequestStorage()?.getStore()?.request;
31072
30993
  var runWithAbsoluteRequest = (request, callback) => ensureRequestStorage().run({ request }, callback);
31073
30994
 
31074
- // src/mobile/compatibilityDispatcher.ts
31075
- import { Elysia as Elysia2 } from "elysia";
31076
-
31077
30995
  // src/mobile/producerContextState.ts
31078
30996
  var ABSOLUTE_MOBILE_PRODUCER_STORAGE_KEY = Symbol.for("absolutejs.mobileProducerAsyncLocalStorage");
31079
30997
  var frameworks2 = new Set([
@@ -31319,6 +31237,180 @@ var finalizeAbsoluteMobilePage = (input) => {
31319
31237
  }
31320
31238
  };
31321
31239
 
31240
+ // src/core/pageHandlers.ts
31241
+ var finalizeStaticMobilePage = (framework, pagePath, metadata2) => {
31242
+ const pageId = metadata2?.pageId ?? `${framework}:${pagePath}`;
31243
+ const contract = metadata2?.contract ?? `${framework}:${pageId}:${ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION}`;
31244
+ return finalizeAbsoluteMobilePage({
31245
+ compatibility: {
31246
+ framework,
31247
+ pageId,
31248
+ representations: [{ contract, mapProps: () => ({}) }],
31249
+ runtimes: [String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)]
31250
+ },
31251
+ props: {},
31252
+ request: getCurrentAbsoluteRequest()
31253
+ });
31254
+ };
31255
+ var handleStaticPageRequest = async (pagePath, options = {}, settings = {}) => {
31256
+ const html = await file(pagePath).text();
31257
+ const transformedHtml = await transformCurrentStaticPageHtml(html, settings);
31258
+ return withPageCacheHeaders(await withStreamingSlots(new Response(injectIslandPageContext(transformedHtml), {
31259
+ headers: { "Content-Type": "text/html" }
31260
+ }), {
31261
+ ...options,
31262
+ streamingSlots: options.streamingSlots ?? []
31263
+ }));
31264
+ };
31265
+ var handleHTMLPageRequest = (pagePath, options) => {
31266
+ const mobileResponse = finalizeStaticMobilePage("html", pagePath, options?.__absoluteMobile);
31267
+ if (mobileResponse)
31268
+ return Promise.resolve(mobileResponse);
31269
+ const htmlFile = file(pagePath);
31270
+ return htmlFile.text().then((html) => {
31271
+ if (extractStaticStreamingTags(html).length > 0) {
31272
+ throw new Error(`HTML page "${pagePath}" uses <abs-stream-slot>, but HTML pages should pass explicit streamingSlots to handleHTMLPageRequest(...).`);
31273
+ }
31274
+ return handleStaticPageRequest(pagePath, options, {
31275
+ enableStaticStreaming: false
31276
+ });
31277
+ });
31278
+ };
31279
+ var handleHTMXPageRequest = async (pagePath, options = {}) => {
31280
+ const mobileResponse = finalizeStaticMobilePage("htmx", pagePath, options.__absoluteMobile);
31281
+ if (mobileResponse)
31282
+ return mobileResponse;
31283
+ const html = await file(pagePath).text();
31284
+ if (extractStaticStreamingTags(html).length > 0) {
31285
+ throw new Error(`HTMX page "${pagePath}" uses <abs-stream-slot>, but HTMX pages should use native hx-* fragment requests instead.`);
31286
+ }
31287
+ return handleStaticPageRequest(pagePath, {}, {
31288
+ enableHTMXStreaming: true,
31289
+ enableStaticStreaming: false
31290
+ });
31291
+ };
31292
+ // src/core/prepare.ts
31293
+ import { createHash as createHash8 } from "crypto";
31294
+ import { existsSync as existsSync39, readdirSync as readdirSync10, readFileSync as readFileSync33 } from "fs";
31295
+ import { basename as basename18, join as join50, relative as relative19, resolve as resolvePath4 } from "path";
31296
+ import { Elysia as Elysia9, NotFound } from "elysia";
31297
+
31298
+ // src/plugins/openApiPlugin.ts
31299
+ import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
31300
+ import { join as join11 } from "path";
31301
+ var FALLBACK_NAME = "AbsoluteJS API";
31302
+ var FALLBACK_VERSION = "1.0.0";
31303
+ var projectInfo = (cwd) => {
31304
+ const path = join11(cwd, "package.json");
31305
+ if (!existsSync7(path)) {
31306
+ return { name: FALLBACK_NAME, version: FALLBACK_VERSION };
31307
+ }
31308
+ try {
31309
+ const pkg = JSON.parse(readFileSync8(path, "utf-8"));
31310
+ return {
31311
+ name: typeof pkg.name === "string" ? pkg.name : FALLBACK_NAME,
31312
+ version: typeof pkg.version === "string" ? pkg.version : FALLBACK_VERSION
31313
+ };
31314
+ } catch {
31315
+ return { name: FALLBACK_NAME, version: FALLBACK_VERSION };
31316
+ }
31317
+ };
31318
+ var openApiEnabled = (config, isDev) => isDev ? config.openapi !== false : Boolean(config.openapi);
31319
+ var createOpenApiPlugin = async (config, cwd) => {
31320
+ const setting = config.openapi;
31321
+ const options = typeof setting === "object" ? setting : {};
31322
+ const info = projectInfo(cwd);
31323
+ const { openapi } = await import("@elysia/openapi");
31324
+ return openapi({
31325
+ documentation: {
31326
+ info: {
31327
+ description: options.documentation?.description,
31328
+ title: options.documentation?.title ?? info.name,
31329
+ version: options.documentation?.version ?? info.version
31330
+ }
31331
+ },
31332
+ exclude: {
31333
+ paths: [
31334
+ /^\/_/,
31335
+ /^\/@/,
31336
+ /^\/__absolute/,
31337
+ /^\/hmr/,
31338
+ /^\/\.well-known/,
31339
+ /^\/chunk-/,
31340
+ /^\/node_modules/
31341
+ ]
31342
+ },
31343
+ path: options.path ?? "/openapi",
31344
+ provider: options.provider === "swagger" ? "swagger-ui" : "scalar"
31345
+ });
31346
+ };
31347
+ var withOpenApi = async (app, config, cwd, isDev) => {
31348
+ if (!openApiEnabled(config, isDev))
31349
+ return app;
31350
+ try {
31351
+ return app.use(await createOpenApiPlugin(config, cwd));
31352
+ } catch (error) {
31353
+ const detail = error instanceof Error ? error.message : String(error);
31354
+ console.warn(`[absolute] OpenAPI docs disabled \u2014 install @elysia/openapi (${detail})`);
31355
+ return app;
31356
+ }
31357
+ };
31358
+
31359
+ // src/plugins/telemetryPlugin.ts
31360
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
31361
+ import { join as join12 } from "path";
31362
+ var OTEL_PACKAGE = "@elysia/opentelemetry";
31363
+ var readPackageName = (cwd) => {
31364
+ const path = join12(cwd, "package.json");
31365
+ if (!existsSync8(path))
31366
+ return null;
31367
+ try {
31368
+ const pkg = JSON.parse(readFileSync9(path, "utf-8"));
31369
+ return typeof pkg.name === "string" ? pkg.name : null;
31370
+ } catch {
31371
+ return null;
31372
+ }
31373
+ };
31374
+ var serviceNameFor = (config, cwd) => {
31375
+ const setting = config.telemetry;
31376
+ if (typeof setting === "object" && setting.serviceName) {
31377
+ return setting.serviceName;
31378
+ }
31379
+ return readPackageName(cwd) ?? "absolutejs-app";
31380
+ };
31381
+ var withTelemetry = async (app, config, cwd) => {
31382
+ if (!config.telemetry)
31383
+ return app;
31384
+ try {
31385
+ const { opentelemetry } = await import(OTEL_PACKAGE);
31386
+ return app.use(opentelemetry({ serviceName: serviceNameFor(config, cwd) }));
31387
+ } catch (error) {
31388
+ const detail = error instanceof Error ? error.message : String(error);
31389
+ console.warn(`[absolute] telemetry enabled but ${OTEL_PACKAGE} isn't installed \u2014 run \`bun add ${OTEL_PACKAGE}\` (${detail})`);
31390
+ return app;
31391
+ }
31392
+ };
31393
+
31394
+ // src/core/prepare.ts
31395
+ init_loadConfig();
31396
+
31397
+ // src/utils/iconVersion.ts
31398
+ var iconMimeType = (icon) => {
31399
+ if (icon.endsWith(".svg"))
31400
+ return "image/svg+xml";
31401
+ if (icon.endsWith(".png"))
31402
+ return "image/png";
31403
+ return "image/x-icon";
31404
+ };
31405
+ var resolver;
31406
+ var applyIconVersion = (href) => resolver ? resolver(href) : href;
31407
+ var setIconVersionResolver = (resolverFn) => {
31408
+ resolver = resolverFn;
31409
+ };
31410
+
31411
+ // src/mobile/compatibilityDispatcher.ts
31412
+ import { Elysia as Elysia2 } from "elysia";
31413
+
31322
31414
  // src/mobile/releaseArtifact.ts
31323
31415
  import { createHash as createHash4 } from "crypto";
31324
31416
  var ABSOLUTE_MOBILE_COMPATIBILITY_FORMAT = 1;
@@ -31396,13 +31488,19 @@ var parseCompatibilityPage = (value) => {
31396
31488
  if (!isCanonicalRecord(value) || !isPageFramework(value.framework)) {
31397
31489
  throw new TypeError("Compatibility artifact contains an invalid page.");
31398
31490
  }
31491
+ const styleBundleHash = typeof value.styleBundleHash === "string" ? value.styleBundleHash : undefined;
31492
+ const styleBundlePath = typeof value.styleBundlePath === "string" ? value.styleBundlePath : undefined;
31493
+ if (Boolean(styleBundleHash) !== Boolean(styleBundlePath)) {
31494
+ throw new TypeError("Compatibility page style hash and path must be provided together.");
31495
+ }
31399
31496
  return {
31400
31497
  bundleHash: readString(value.bundleHash, "page.bundleHash"),
31401
31498
  bundlePath: readString(value.bundlePath, "page.bundlePath"),
31402
31499
  contract: readString(value.contract, "page.contract"),
31403
31500
  framework: value.framework,
31404
31501
  pageId: readString(value.pageId, "page.pageId"),
31405
- propsSchemaHash: readString(value.propsSchemaHash, "page.propsSchemaHash")
31502
+ propsSchemaHash: readString(value.propsSchemaHash, "page.propsSchemaHash"),
31503
+ ...styleBundleHash && styleBundlePath ? { styleBundleHash, styleBundlePath } : {}
31406
31504
  };
31407
31505
  };
31408
31506
  var parseCompatibilityRoute = (value) => {
@@ -31434,14 +31532,23 @@ var validateProducerModule = (module) => {
31434
31532
  }
31435
31533
  return module;
31436
31534
  };
31437
- var normalizePage = (page) => ({
31438
- bundleHash: requireNonEmpty(page.bundleHash, "page.bundleHash"),
31439
- bundlePath: requireNonEmpty(page.bundlePath, "page.bundlePath"),
31440
- contract: requireNonEmpty(page.contract, "page.contract"),
31441
- framework: page.framework,
31442
- pageId: requireNonEmpty(page.pageId, "page.pageId"),
31443
- propsSchemaHash: requireNonEmpty(page.propsSchemaHash, "page.propsSchemaHash")
31444
- });
31535
+ var normalizePage = (page) => {
31536
+ if (Boolean(page.styleBundleHash) !== Boolean(page.styleBundlePath)) {
31537
+ throw new TypeError("Compatibility page style hash and path must be provided together.");
31538
+ }
31539
+ return {
31540
+ bundleHash: requireNonEmpty(page.bundleHash, "page.bundleHash"),
31541
+ bundlePath: requireNonEmpty(page.bundlePath, "page.bundlePath"),
31542
+ contract: requireNonEmpty(page.contract, "page.contract"),
31543
+ framework: page.framework,
31544
+ pageId: requireNonEmpty(page.pageId, "page.pageId"),
31545
+ propsSchemaHash: requireNonEmpty(page.propsSchemaHash, "page.propsSchemaHash"),
31546
+ ...page.styleBundleHash && page.styleBundlePath ? {
31547
+ styleBundleHash: requireNonEmpty(page.styleBundleHash, "page.styleBundleHash"),
31548
+ styleBundlePath: requireNonEmpty(page.styleBundlePath, "page.styleBundlePath")
31549
+ } : {}
31550
+ };
31551
+ };
31445
31552
  var normalizeRoute = (route) => {
31446
31553
  if (!route.pattern.startsWith("/")) {
31447
31554
  throw new TypeError("route.pattern must start with /.");
@@ -31590,6 +31697,64 @@ var matchesAbsoluteMobileRoutePattern = (pattern, pathname) => {
31590
31697
  var resolveAbsoluteMobileRoute = (routes, pathname, method = "GET") => routes.find((route) => route.method === method && matchesAbsoluteMobileRoutePattern(route.pattern, pathname));
31591
31698
 
31592
31699
  // src/mobile/compatibilityDispatcher.ts
31700
+ var MOBILE_WEBVIEW_ORIGINS = new Set([
31701
+ "capacitor://localhost",
31702
+ "http://localhost",
31703
+ "https://localhost"
31704
+ ]);
31705
+ var MOBILE_REQUEST_HEADER_NAMES = Object.values(MOBILE_PAGE_REQUEST_HEADERS);
31706
+ var MOBILE_CORS_ALLOW_HEADERS = [
31707
+ "accept",
31708
+ "content-type",
31709
+ "authorization",
31710
+ "hx-current-url",
31711
+ "hx-request",
31712
+ "hx-target",
31713
+ "hx-trigger",
31714
+ "hx-trigger-name",
31715
+ ...MOBILE_REQUEST_HEADER_NAMES
31716
+ ].join(", ");
31717
+ var MOBILE_CORS_METHODS = new Set([
31718
+ "DELETE",
31719
+ "GET",
31720
+ "HEAD",
31721
+ "OPTIONS",
31722
+ "PATCH",
31723
+ "POST",
31724
+ "PUT"
31725
+ ]);
31726
+ var mobileWebViewOrigin = (request) => {
31727
+ const origin = request.headers.get("origin");
31728
+ return origin && MOBILE_WEBVIEW_ORIGINS.has(origin) ? origin : undefined;
31729
+ };
31730
+ var applyMobileCorsHeaders = (response, origin) => {
31731
+ response.headers.set("access-control-allow-credentials", "true");
31732
+ response.headers.set("access-control-allow-origin", origin);
31733
+ response.headers.append("vary", "Origin");
31734
+ return response;
31735
+ };
31736
+ var mobilePreflightResponse = (request) => {
31737
+ if (request.method !== "OPTIONS")
31738
+ return;
31739
+ const origin = mobileWebViewOrigin(request);
31740
+ if (!origin)
31741
+ return;
31742
+ const requestedHeaders = request.headers.get("access-control-request-headers");
31743
+ const requestedMethod = request.headers.get("access-control-request-method")?.toUpperCase() ?? "";
31744
+ if (!MOBILE_CORS_METHODS.has(requestedMethod))
31745
+ return;
31746
+ return new Response(null, {
31747
+ headers: {
31748
+ "access-control-allow-credentials": "true",
31749
+ "access-control-allow-headers": requestedHeaders || MOBILE_CORS_ALLOW_HEADERS,
31750
+ "access-control-allow-methods": [...MOBILE_CORS_METHODS].join(", "),
31751
+ "access-control-allow-origin": origin,
31752
+ "access-control-max-age": "600",
31753
+ vary: "Origin, Access-Control-Request-Headers"
31754
+ },
31755
+ status: 204
31756
+ });
31757
+ };
31593
31758
  var artifactOwnsRequest = (artifact, pageId, request) => {
31594
31759
  const { pathname } = new URL(request.url);
31595
31760
  return artifact.routes.some((route) => route.pageId === pageId && route.method === request.method && matchesAbsoluteMobileRoutePattern(route.pattern, pathname));
@@ -31617,6 +31782,9 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
31617
31782
  return new Elysia2({ name: "absolutejs-mobile-compatibility-dispatcher" }).request(async ({ request }) => {
31618
31783
  if (getCurrentAbsoluteMobileProducerContext())
31619
31784
  return;
31785
+ const preflight = mobilePreflightResponse(request);
31786
+ if (preflight)
31787
+ return preflight;
31620
31788
  const parsed = parseAbsoluteMobilePageRequest(request);
31621
31789
  if (parsed.kind !== "mobile")
31622
31790
  return;
@@ -31640,6 +31808,11 @@ var createAbsoluteMobileCompatibilityDispatcher = (options) => {
31640
31808
  console.error(`[Mobile] Failed to load retained producer ${resolved.artifact.releaseId}:`, error);
31641
31809
  return createAbsoluteMobilePageErrorResponse(parsed.client.pageId);
31642
31810
  }
31811
+ }).afterHandle("global", ({ request, responseValue }) => {
31812
+ const origin = mobileWebViewOrigin(request);
31813
+ if (!origin || !(responseValue instanceof Response))
31814
+ return;
31815
+ applyMobileCorsHeaders(responseValue, origin);
31643
31816
  }).as("global");
31644
31817
  };
31645
31818
 
@@ -31685,8 +31858,9 @@ var normalizeEntry = (entry) => {
31685
31858
  };
31686
31859
  var normalizeProductionOrigin = (value) => {
31687
31860
  const parsed = new URL(requireText(value, "mobile.server.productionOrigin"));
31688
- if (parsed.protocol !== "https:") {
31689
- throw new TypeError("mobile.server.productionOrigin must use HTTPS in production.");
31861
+ const isLoopbackHttp = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]");
31862
+ if (parsed.protocol !== "https:" && !isLoopbackHttp) {
31863
+ throw new TypeError("mobile.server.productionOrigin must use HTTPS, except for a loopback development origin.");
31690
31864
  }
31691
31865
  if (parsed.username || parsed.password || parsed.pathname !== "/" || parsed.search || parsed.hash) {
31692
31866
  throw new TypeError("mobile.server.productionOrigin must be an origin without credentials, path, query, or hash.");
@@ -31710,9 +31884,8 @@ var normalizeHosts = (hosts, productionOrigin) => {
31710
31884
  }
31711
31885
  return value;
31712
31886
  };
31713
- const normalized = new Set([
31714
- normalizeHostname(new URL(productionOrigin).hostname)
31715
- ]);
31887
+ const productionHostname = new URL(productionOrigin).hostname;
31888
+ const normalized = new Set(productionHostname === "[::1]" ? [] : [normalizeHostname(productionHostname)]);
31716
31889
  for (const host of hosts ?? []) {
31717
31890
  normalized.add(normalizeHostname(host));
31718
31891
  }
@@ -31750,7 +31923,7 @@ var normalizeAbsoluteMobileConfig = (config, projectRoot) => {
31750
31923
  throw new TypeError("mobile.appId must use reverse-domain notation, for example com.example.app.");
31751
31924
  }
31752
31925
  const productionOrigin = normalizeProductionOrigin(config.server.productionOrigin);
31753
- const deepLinkScheme = config.deepLinks?.scheme?.trim().toLowerCase();
31926
+ const deepLinkScheme = (config.deepLinks?.scheme ?? appId).trim().toLowerCase();
31754
31927
  if (deepLinkScheme && !SCHEME_PATTERN.test(deepLinkScheme)) {
31755
31928
  throw new TypeError("mobile.deepLinks.scheme is not a valid URL scheme.");
31756
31929
  }
@@ -39667,5 +39840,5 @@ export {
39667
39840
  ANGULAR_INIT_TIMEOUT_MS
39668
39841
  };
39669
39842
 
39670
- //# debugId=C32ABD2F8864CE7A64756E2164756E21
39843
+ //# debugId=9A9C24B0F25B4EF864756E2164756E21
39671
39844
  //# sourceMappingURL=index.js.map