@absolutejs/absolute 0.20.0-beta.0 → 0.20.0-beta.10

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 (118) hide show
  1. package/README.md +45 -0
  2. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  3. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  4. package/dist/angular/index.js +354 -22
  5. package/dist/angular/index.js.map +9 -6
  6. package/dist/angular/server.js +354 -22
  7. package/dist/angular/server.js.map +9 -6
  8. package/dist/build.js +742 -359
  9. package/dist/build.js.map +26 -24
  10. package/dist/cli/config/server.js +2 -2
  11. package/dist/cli/index.js +16105 -8429
  12. package/dist/dev/client/cssUtils.ts +112 -41
  13. package/dist/dev/client/handlers/html.ts +75 -15
  14. package/dist/dev/client/handlers/htmx.ts +43 -8
  15. package/dist/dev/client/handlers/react.ts +114 -32
  16. package/dist/dev/client/handlers/rebuild.ts +38 -8
  17. package/dist/dev/client/handlers/svelte.ts +33 -50
  18. package/dist/dev/client/handlers/vue.ts +36 -45
  19. package/dist/dev/client/hmrClient.ts +38 -6
  20. package/dist/dev/client/hmrTiming.ts +148 -0
  21. package/dist/dev/serverBootstrap.js +20 -11
  22. package/dist/index.js +1728 -864
  23. package/dist/index.js.map +38 -33
  24. package/dist/mobile/browser.js +14 -1
  25. package/dist/mobile/browser.js.map +3 -3
  26. package/dist/mobile/index.js +4853 -279
  27. package/dist/mobile/index.js.map +34 -7
  28. package/dist/mobile/remoteMacAgentEntry.js +29 -0
  29. package/dist/mobile/shellAuth.js +43 -0
  30. package/dist/mobile/shellBootstrap.js +581 -0
  31. package/dist/mobile/shellSync.js +74 -0
  32. package/dist/react/index.js +16 -3
  33. package/dist/react/index.js.map +4 -4
  34. package/dist/react/jsxDevRuntimeCompat.js +22 -2
  35. package/dist/react/jsxDevRuntimeCompat.js.map +5 -4
  36. package/dist/react/jsxRuntimeCompat.js +90 -0
  37. package/dist/react/jsxRuntimeCompat.js.map +10 -0
  38. package/dist/react/server.js +16 -3
  39. package/dist/react/server.js.map +4 -4
  40. package/dist/src/angular/pageHandler.d.ts +3 -0
  41. package/dist/src/build/compileVue.d.ts +1 -1
  42. package/dist/src/build/pwa.d.ts +15 -0
  43. package/dist/src/build/resolveBuildMode.d.ts +7 -0
  44. package/dist/src/cli/config/server.d.ts +1 -1
  45. package/dist/src/cli/scripts/dev.d.ts +4 -1
  46. package/dist/src/cli/scripts/mobile.d.ts +1 -0
  47. package/dist/src/cli/utils.d.ts +2 -2
  48. package/dist/src/core/build.d.ts +1 -1
  49. package/dist/src/core/pageHandlers.d.ts +11 -2
  50. package/dist/src/core/prepare.d.ts +6 -0
  51. package/dist/src/dev/clientManager.d.ts +9 -0
  52. package/dist/src/dev/configResolver.d.ts +2 -0
  53. package/dist/src/dev/moduleMapper.d.ts +1 -1
  54. package/dist/src/dev/moduleServer.d.ts +2 -1
  55. package/dist/src/dev/pathUtils.d.ts +1 -1
  56. package/dist/src/dev/reactComponentClassifier.d.ts +1 -1
  57. package/dist/src/mobile/androidConformance.d.ts +42 -0
  58. package/dist/src/mobile/androidEmulatorController.d.ts +105 -0
  59. package/dist/src/mobile/androidNativeWatcher.d.ts +19 -0
  60. package/dist/src/mobile/androidRelease.d.ts +51 -0
  61. package/dist/src/mobile/androidWebView.d.ts +46 -0
  62. package/dist/src/mobile/associationFiles.d.ts +49 -0
  63. package/dist/src/mobile/buildMetadata.d.ts +10 -0
  64. package/dist/src/mobile/buildPipeline.d.ts +9 -0
  65. package/dist/src/mobile/buildRelease.d.ts +24 -0
  66. package/dist/src/mobile/capacitorBundle.d.ts +42 -0
  67. package/dist/src/mobile/capacitorProject.d.ts +9 -0
  68. package/dist/src/mobile/client.d.ts +5 -1
  69. package/dist/src/mobile/config.d.ts +17 -0
  70. package/dist/src/mobile/emulatorDoctor.d.ts +25 -0
  71. package/dist/src/mobile/emulatorInstaller.d.ts +41 -0
  72. package/dist/src/mobile/index.d.ts +19 -0
  73. package/dist/src/mobile/iosConformance.d.ts +15 -0
  74. package/dist/src/mobile/iosNativeWatcher.d.ts +19 -0
  75. package/dist/src/mobile/iosRelease.d.ts +61 -0
  76. package/dist/src/mobile/iosSimulatorController.d.ts +89 -0
  77. package/dist/src/mobile/materializedBundle.d.ts +14 -0
  78. package/dist/src/mobile/nativeAuth.d.ts +17 -0
  79. package/dist/src/mobile/nativeBackgroundSync.d.ts +4 -0
  80. package/dist/src/mobile/nativeDeepLinks.d.ts +5 -0
  81. package/dist/src/mobile/releaseArtifact.d.ts +3 -0
  82. package/dist/src/mobile/releaseDoctor.d.ts +13 -0
  83. package/dist/src/mobile/releasePublisher.d.ts +130 -0
  84. package/dist/src/mobile/remoteMacAgent.d.ts +2 -0
  85. package/dist/src/mobile/remoteMacAgentEntry.d.ts +1 -0
  86. package/dist/src/mobile/remoteMacProtocol.d.ts +114 -0
  87. package/dist/src/mobile/remoteMacWire.d.ts +2 -0
  88. package/dist/src/mobile/routeMatcher.d.ts +3 -0
  89. package/dist/src/mobile/routeMetadataTransform.d.ts +13 -0
  90. package/dist/src/mobile/shellAuth.d.ts +13 -0
  91. package/dist/src/mobile/shellBootstrap.d.ts +18 -0
  92. package/dist/src/mobile/shellSync.d.ts +19 -0
  93. package/dist/src/mobile/staticDocument.d.ts +5 -0
  94. package/dist/src/mobile/transport.d.ts +43 -0
  95. package/dist/src/plugins/hmr.d.ts +3 -0
  96. package/dist/src/plugins/imageOptimizer.d.ts +1 -1
  97. package/dist/src/react/hooks/useMediaQuery.d.ts +1 -1
  98. package/dist/src/react/jsxDevRuntimeCompat.d.ts +1 -1
  99. package/dist/src/react/jsxRuntimeCompat.d.ts +7 -0
  100. package/dist/src/react/pageHandler.d.ts +3 -0
  101. package/dist/src/svelte/pageHandler.d.ts +3 -0
  102. package/dist/src/utils/loadConfig.d.ts +2 -0
  103. package/dist/src/utils/logger.d.ts +2 -0
  104. package/dist/src/utils/userAgentFunctions.d.ts +1 -1
  105. package/dist/src/vue/pageHandler.d.ts +3 -0
  106. package/dist/svelte/index.js +325 -23
  107. package/dist/svelte/index.js.map +8 -5
  108. package/dist/svelte/server.js +320 -18
  109. package/dist/svelte/server.js.map +8 -5
  110. package/dist/types/build.d.ts +59 -0
  111. package/dist/types/cli.d.ts +2 -0
  112. package/dist/types/globals.d.ts +14 -0
  113. package/dist/types/messages.d.ts +12 -0
  114. package/dist/vue/index.js +325 -23
  115. package/dist/vue/index.js.map +8 -5
  116. package/dist/vue/server.js +320 -18
  117. package/dist/vue/server.js.map +8 -5
  118. package/package.json +52 -8
package/README.md CHANGED
@@ -105,6 +105,51 @@ export const server = new Elysia()
105
105
  2. Route handlers (`handleReactPageRequest`, `handleSveltePageRequest`, …) stream HTML and inject scripts/assets based on that manifest.
106
106
  3. The static plugin serves all compiled files from `/build`.
107
107
 
108
+ ### Installable PWA and offline Sync
109
+
110
+ Enable the web-app shell once in `absolutejs.config.ts`. AbsoluteJS generates a
111
+ single shared browser bootstrap, service worker, and optional manifest, then
112
+ wires them into React, Vue, Svelte, Angular, HTML, HTMX, and island client
113
+ entries. Route and page code does not change.
114
+
115
+ ```ts
116
+ import { defineConfig } from '@absolutejs/absolute';
117
+
118
+ export default defineConfig({
119
+ // Existing framework directories and build settings...
120
+ pwa: {
121
+ manifest: {
122
+ name: 'Acme',
123
+ shortName: 'Acme',
124
+ themeColor: '#111827',
125
+ icons: [
126
+ {
127
+ src: '/icons/app-512.png',
128
+ sizes: '512x512',
129
+ type: 'image/png'
130
+ }
131
+ ]
132
+ },
133
+ serviceWorker: {
134
+ offline: {
135
+ fallback: '/offline.html',
136
+ assetPrefix: '/assets/'
137
+ }
138
+ },
139
+ // With @absolutejs/auth + syncSocket(), this provisions the existing
140
+ // HTTP-only web session and durable IndexedDB transport automatically.
141
+ sync: true
142
+ }
143
+ });
144
+ ```
145
+
146
+ The default outputs are `/sw.js`, `/manifest.webmanifest`, and the internal
147
+ shared bootstrap at `/__absolute/pwa/bootstrap.js`. Put referenced icons and the
148
+ offline fallback in `publicDirectory`. The worker uses Background Sync when the
149
+ browser offers it, while online/focus/visibility resume remains the correctness
150
+ path. Native Capacitor clients continue to use their Bearer and SQLite
151
+ transport; no web cookie or token is copied into the worker.
152
+
108
153
  ### Immutable production images
109
154
 
110
155
  Build production assets and the server bundle while constructing the image,
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-I85QVn/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-kHyqnr/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-I85QVn/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-kHyqnr/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-I85QVn/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-kHyqnr/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";
@@ -3281,7 +3281,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
3281
3281
  getStreamingSlotsRuntimeScript()
3282
3282
  ].filter(Boolean).join(";");
3283
3283
  return `<script${createNonceAttr(nonce)}>${escapeScriptContent(runtimeBody)}</script>`;
3284
- }, toUint8 = (value, encoder) => encoder.encode(value), isRecord4 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord4(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
3284
+ }, toUint8 = (value, encoder) => encoder.encode(value), isRecord5 = (value) => Boolean(value) && typeof value === "object", isSafeHtmlLike = (value) => isRecord5(value) && typeof value.changingThisBreaksApplicationSecurity === "string", normalizeSafeHtml = (value) => {
3285
3285
  if (isSafeHtmlLike(value)) {
3286
3286
  return value.changingThisBreaksApplicationSecurity;
3287
3287
  }
@@ -3342,7 +3342,7 @@ var SLOT_ID_PREFIX = "abs-slot-", CLOSING_BODY_TAG = "</body>", CLOSING_HEAD_TAG
3342
3342
  }, createTimeoutError = (slot, timeoutMs) => {
3343
3343
  const error = Object.assign(new Error(`Streaming slot "${slot.id}" timed out after ${timeoutMs}ms`), { __absTimeout: true });
3344
3344
  return error;
3345
- }, isSlotPatchPayloadObject = (value) => isRecord4(value) && ("html" in value), isTimeoutError = (error) => isRecord4(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
3345
+ }, isSlotPatchPayloadObject = (value) => isRecord5(value) && ("html" in value), isTimeoutError = (error) => isRecord5(error) && error.__absTimeout === true, toStreamingSlot = (slot, policy) => ({
3346
3346
  errorHtml: slot.errorHtml === undefined ? policy.errorHtml : slot.errorHtml,
3347
3347
  fallbackHtml: normalizeSlotText(slot.fallbackHtml, policy.fallbackHtml),
3348
3348
  id: slot.id ?? createStreamingSlotId(),
@@ -3924,6 +3924,19 @@ var colors2, frameworkColors, formatPath = (filePath) => {
3924
3924
  const errorMsg = error instanceof Error ? error.message : error;
3925
3925
  const fullMessage = `${colors2.red}error${colors2.reset} ${message}${errorMsg ? `: ${errorMsg}` : ""}`;
3926
3926
  console.error(`${timestamp} ${tag} ${fullMessage}`);
3927
+ }, logHmrClientUpdate = (path, framework, duration, target, serverMs, clientMs, outcome = "applied", kind) => {
3928
+ const timestamp = `${colors2.dim}${formatTimestamp()}${colors2.reset}`;
3929
+ const targetLabel = target.startsWith("capacitor-") ? target.slice("capacitor-".length) : target;
3930
+ const tag = `${colors2.cyan}[hmr:${targetLabel}]${colors2.reset}`;
3931
+ const pathColor = framework ? getFrameworkColor(framework) : colors2.white;
3932
+ const breakdown = serverMs === undefined || clientMs === undefined ? "" : `; server ${serverMs}ms, client ${clientMs}ms`;
3933
+ let action = "failed after";
3934
+ if (outcome === "applied")
3935
+ action = "applied in";
3936
+ else if (outcome === "reloaded")
3937
+ action = "falling back to reload after";
3938
+ const kindLabel = kind ? `${kind} ` : "";
3939
+ console.log(`${timestamp} ${tag} ${framework ?? "update"} ${kindLabel}${pathColor}${formatPath(path)}${colors2.reset} ${colors2.dim}${action} ${duration}ms${breakdown}${colors2.reset}`);
3927
3940
  }, logHmrUpdate = (path, framework, duration) => {
3928
3941
  log("hmr update", { duration, framework, path });
3929
3942
  }, logInfo = (message) => {
@@ -5654,6 +5667,7 @@ var requestContext = Object.prototype.hasOwnProperty.call(window, '__ABS_ANGULAR
5654
5667
  var pageHasIslands = Boolean(pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__) || Boolean(document.querySelector('[data-island="true"]'));
5655
5668
  var pageHasRawStreamingSlots = Boolean(document.querySelector('[data-absolute-raw-slot="true"]'));
5656
5669
  var pageHasStreamingSlots = Boolean(document.querySelector('[data-absolute-slot="true"]'));
5670
+ var isClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';
5657
5671
  var contextProviders = [{ provide: REQUEST_CONTEXT, useValue: requestContext }];
5658
5672
  // Page-level providers are injected directly into the page module's
5659
5673
  // server output by \`compileAngular\`'s providers-injection step
@@ -5704,13 +5718,14 @@ if (!document.querySelector(_sel)) {
5704
5718
  }
5705
5719
 
5706
5720
  var providers = [provideZonelessChangeDetection()];
5707
- if (!window.__HMR_SKIP_HYDRATION__ && !pageHasIslands) {
5721
+ if (!isClientRender && !window.__HMR_SKIP_HYDRATION__ && !pageHasIslands) {
5708
5722
  providers.push(provideClientHydration(withHttpTransferCacheOptions(absoluteHttpTransferCacheOptions)));
5709
5723
  }
5710
5724
  delete window.__HMR_SKIP_HYDRATION__;
5711
5725
  providers.push.apply(providers, pageProviders);
5712
5726
  providers.push.apply(providers, contextProviders);
5713
5727
  window.__ABS_SLOT_HYDRATION_PENDING__ = pageHasRawStreamingSlots;
5728
+ var absolutePageReady = Promise.resolve();
5714
5729
 
5715
5730
  if (pageHasRawStreamingSlots) {
5716
5731
  window.__ABS_SLOT_HYDRATION_PENDING__ = false;
@@ -5720,7 +5735,7 @@ if (pageHasRawStreamingSlots) {
5720
5735
  });
5721
5736
  }
5722
5737
  } else {
5723
- bootstrapApplication(${componentClassName}, {
5738
+ absolutePageReady = bootstrapApplication(${componentClassName}, {
5724
5739
  providers: providers
5725
5740
  }).then(function (appRef) {
5726
5741
  window.__ANGULAR_APP__ = appRef;
@@ -5730,8 +5745,17 @@ if (pageHasRawStreamingSlots) {
5730
5745
  window.__ABS_SLOT_FLUSH__();
5731
5746
  });
5732
5747
  }
5748
+ return appRef;
5733
5749
  });
5734
5750
  }
5751
+ window.__ABSOLUTE_PAGE_READY__ = absolutePageReady;
5752
+ window.__ABSOLUTE_PAGE_DISPOSE__ = async function() {
5753
+ await absolutePageReady;
5754
+ if (window.__ANGULAR_APP__) {
5755
+ window.__ANGULAR_APP__.destroy();
5756
+ window.__ANGULAR_APP__ = null;
5757
+ }
5758
+ };
5735
5759
  `.trim() : `
5736
5760
  import '@angular/compiler';
5737
5761
  import { bootstrapApplication } from '@angular/platform-browser';
@@ -5750,6 +5774,7 @@ var requestContext = Object.prototype.hasOwnProperty.call(window, '__ABS_ANGULAR
5750
5774
  var pageHasIslands = Boolean(pageModule.__ABSOLUTE_PAGE_HAS_ISLANDS__) || Boolean(document.querySelector('[data-island="true"]'));
5751
5775
  var pageHasRawStreamingSlots = Boolean(document.querySelector('[data-absolute-raw-slot="true"]'));
5752
5776
  var pageHasStreamingSlots = Boolean(document.querySelector('[data-absolute-slot="true"]'));
5777
+ var isClientRender = window.__ABSOLUTE_PAGE_RENDER_MODE__ === 'client';
5753
5778
  var contextProviders = [{ provide: REQUEST_CONTEXT, useValue: requestContext }];
5754
5779
  // Page-level providers are injected directly into the page module's
5755
5780
  // server output by \`compileAngular\`'s providers-injection step
@@ -5769,11 +5794,21 @@ var absoluteHttpTransferCacheOptions = {
5769
5794
 
5770
5795
  enableProdMode();
5771
5796
 
5797
+ // Production mobile/client-only activation starts from AbsoluteJS's empty
5798
+ // #root shell rather than server-rendered Angular markup. Create the page's
5799
+ // actual Angular host from its compiled selector so application authors do
5800
+ // not need framework-specific mobile configuration.
5801
+ var _sel = ${componentClassName}.\u0275cmp?.selectors?.[0]?.[0] || 'ng-app';
5802
+ if (!document.querySelector(_sel)) {
5803
+ (document.getElementById('root') || document.body).appendChild(document.createElement(_sel));
5804
+ }
5805
+
5772
5806
  var providers = [provideZonelessChangeDetection()].concat(pageProviders).concat(contextProviders);
5773
- if (!pageHasIslands) {
5807
+ if (!isClientRender && !pageHasIslands) {
5774
5808
  providers.unshift(provideClientHydration(withHttpTransferCacheOptions(absoluteHttpTransferCacheOptions)));
5775
5809
  }
5776
5810
  window.__ABS_SLOT_HYDRATION_PENDING__ = pageHasRawStreamingSlots;
5811
+ var absolutePageReady = Promise.resolve();
5777
5812
 
5778
5813
  if (pageHasRawStreamingSlots) {
5779
5814
  window.__ABS_SLOT_HYDRATION_PENDING__ = false;
@@ -5783,7 +5818,7 @@ if (pageHasRawStreamingSlots) {
5783
5818
  });
5784
5819
  }
5785
5820
  } else {
5786
- bootstrapApplication(${componentClassName}, {
5821
+ absolutePageReady = bootstrapApplication(${componentClassName}, {
5787
5822
  providers: providers
5788
5823
  }).then(function (appRef) {
5789
5824
  window.__ANGULAR_APP__ = appRef;
@@ -5793,8 +5828,17 @@ if (pageHasRawStreamingSlots) {
5793
5828
  window.__ABS_SLOT_FLUSH__();
5794
5829
  });
5795
5830
  }
5831
+ return appRef;
5796
5832
  });
5797
5833
  }
5834
+ window.__ABSOLUTE_PAGE_READY__ = absolutePageReady;
5835
+ window.__ABSOLUTE_PAGE_DISPOSE__ = async function() {
5836
+ await absolutePageReady;
5837
+ if (window.__ANGULAR_APP__) {
5838
+ window.__ANGULAR_APP__.destroy();
5839
+ window.__ANGULAR_APP__ = null;
5840
+ }
5841
+ };
5798
5842
  `.trim();
5799
5843
  const indexHash = Bun.hash(hydration).toString(BASE_36_RADIX);
5800
5844
  const indexUnchanged = cachedWrapper?.indexHash === indexHash;
@@ -14936,7 +14980,7 @@ var provideDeterministicEnv = (options = {}) => {
14936
14980
  };
14937
14981
  // src/angular/pageHandler.ts
14938
14982
  init_constants();
14939
- import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
14983
+ import { AsyncLocalStorage as AsyncLocalStorage4 } from "async_hooks";
14940
14984
  import { lstat, mkdir as mkdir4, readlink, symlink } from "fs/promises";
14941
14985
  import { basename as basename5, dirname as dirname6, join as join10, resolve as resolve8 } from "path";
14942
14986
  import { pathToFileURL as pathToFileURL2 } from "url";
@@ -15329,6 +15373,276 @@ var lowerAngularServerIslands = async (html) => {
15329
15373
  // src/angular/pageHandler.ts
15330
15374
  init_devRouteRegistrationCallsite();
15331
15375
 
15376
+ // src/core/requestContext.ts
15377
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
15378
+ import { Elysia as Elysia2 } from "elysia";
15379
+ var REQUEST_STORAGE_KEY = Symbol.for("absolutejs.requestAsyncLocalStorage");
15380
+ var isAbsoluteRequestStorage = (value) => typeof value === "object" && value !== null && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
15381
+ var getRequestStorage = () => {
15382
+ const value = Reflect.get(globalThis, REQUEST_STORAGE_KEY);
15383
+ return isAbsoluteRequestStorage(value) ? value : undefined;
15384
+ };
15385
+ var ensureRequestStorage = () => {
15386
+ const existing = getRequestStorage();
15387
+ if (existing)
15388
+ return existing;
15389
+ const storage = new AsyncLocalStorage2;
15390
+ Reflect.set(globalThis, REQUEST_STORAGE_KEY, storage);
15391
+ return storage;
15392
+ };
15393
+ var absoluteRequestContext = new Elysia2({
15394
+ name: "absolutejs-request-context"
15395
+ }).request(({ request }) => {
15396
+ ensureRequestStorage().enterWith({ request });
15397
+ }).as("global");
15398
+ var getCurrentAbsoluteRequest = () => getRequestStorage()?.getStore()?.request;
15399
+ var runWithAbsoluteRequest = (request, callback) => ensureRequestStorage().run({ request }, callback);
15400
+
15401
+ // src/mobile/producerContextState.ts
15402
+ var ABSOLUTE_MOBILE_PRODUCER_STORAGE_KEY = Symbol.for("absolutejs.mobileProducerAsyncLocalStorage");
15403
+ var frameworks = new Set([
15404
+ "angular",
15405
+ "ember",
15406
+ "html",
15407
+ "htmx",
15408
+ "react",
15409
+ "svelte",
15410
+ "vue"
15411
+ ]);
15412
+ var isCompatibilityPage = (value) => typeof value === "object" && value !== null && ("bundleHash" in value) && typeof value.bundleHash === "string" && ("contract" in value) && typeof value.contract === "string" && ("framework" in value) && typeof value.framework === "string" && frameworks.has(value.framework) && ("pageId" in value) && typeof value.pageId === "string" && ("propsSchemaHash" in value) && typeof value.propsSchemaHash === "string";
15413
+ var getCurrentAbsoluteMobileProducerContext = () => {
15414
+ const value = Reflect.get(globalThis, ABSOLUTE_MOBILE_PRODUCER_STORAGE_KEY);
15415
+ if (typeof value !== "object" || value === null || !("getStore" in value) || typeof value.getStore !== "function") {
15416
+ return;
15417
+ }
15418
+ const context = value.getStore();
15419
+ if (typeof context !== "object" || context === null || !("page" in context) || !isCompatibilityPage(context.page) || !("releaseId" in context) || typeof context.releaseId !== "string") {
15420
+ return;
15421
+ }
15422
+ return { page: context.page, releaseId: context.releaseId };
15423
+ };
15424
+
15425
+ // src/mobile/pageProtocol.ts
15426
+ var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json";
15427
+ var ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION = 1;
15428
+ var BAD_REQUEST_STATUS = 400;
15429
+ var OK_STATUS = 200;
15430
+ var SERVER_ERROR_STATUS = 500;
15431
+ var UPGRADE_REQUIRED_STATUS = 426;
15432
+ var MOBILE_PAGE_REQUEST_HEADERS = {
15433
+ appBuild: "x-absolute-mobile-app-build",
15434
+ pageBundle: "x-absolute-mobile-page-bundle",
15435
+ pageContracts: "x-absolute-mobile-page-contracts",
15436
+ pageId: "x-absolute-mobile-page-id",
15437
+ protocol: "x-absolute-mobile-protocol",
15438
+ runtime: "x-absolute-mobile-runtime"
15439
+ };
15440
+ var parseMediaType = (value) => value.split(";", 1)[0]?.trim().toLowerCase();
15441
+ var acceptsAbsoluteMobilePage = (request) => {
15442
+ if (!request)
15443
+ return false;
15444
+ return (request.headers.get("accept") ?? "").split(",").some((value) => parseMediaType(value) === ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE);
15445
+ };
15446
+ var readRequiredHeader = (request, name) => {
15447
+ const value = request.headers.get(name)?.trim();
15448
+ return value ? value : undefined;
15449
+ };
15450
+ var parseAbsoluteMobilePageRequest = (request) => {
15451
+ if (!request || !acceptsAbsoluteMobilePage(request)) {
15452
+ return { kind: "not-mobile" };
15453
+ }
15454
+ const protocolValue = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.protocol);
15455
+ const runtime = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.runtime);
15456
+ const appBuild = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.appBuild);
15457
+ const pageBundle = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.pageBundle);
15458
+ const pageContractsValue = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.pageContracts);
15459
+ const pageId = readRequiredHeader(request, MOBILE_PAGE_REQUEST_HEADERS.pageId);
15460
+ if (!protocolValue || !/^\d+$/.test(protocolValue)) {
15461
+ return {
15462
+ kind: "invalid",
15463
+ message: `Missing or invalid ${MOBILE_PAGE_REQUEST_HEADERS.protocol} header.`
15464
+ };
15465
+ }
15466
+ if (!runtime) {
15467
+ return {
15468
+ kind: "invalid",
15469
+ message: `Missing ${MOBILE_PAGE_REQUEST_HEADERS.runtime} header.`
15470
+ };
15471
+ }
15472
+ if (!appBuild) {
15473
+ return {
15474
+ kind: "invalid",
15475
+ message: `Missing ${MOBILE_PAGE_REQUEST_HEADERS.appBuild} header.`
15476
+ };
15477
+ }
15478
+ if (!pageBundle) {
15479
+ return {
15480
+ kind: "invalid",
15481
+ message: `Missing ${MOBILE_PAGE_REQUEST_HEADERS.pageBundle} header.`
15482
+ };
15483
+ }
15484
+ if (!pageContractsValue) {
15485
+ return {
15486
+ kind: "invalid",
15487
+ message: `Missing ${MOBILE_PAGE_REQUEST_HEADERS.pageContracts} header.`
15488
+ };
15489
+ }
15490
+ if (!pageId) {
15491
+ return {
15492
+ kind: "invalid",
15493
+ message: `Missing ${MOBILE_PAGE_REQUEST_HEADERS.pageId} header.`
15494
+ };
15495
+ }
15496
+ const pageContracts = [
15497
+ ...new Set(pageContractsValue.split(",").map((value) => value.trim()).filter(Boolean))
15498
+ ];
15499
+ if (pageContracts.length === 0) {
15500
+ return {
15501
+ kind: "invalid",
15502
+ message: `${MOBILE_PAGE_REQUEST_HEADERS.pageContracts} must contain at least one contract.`
15503
+ };
15504
+ }
15505
+ return {
15506
+ client: {
15507
+ appBuild,
15508
+ pageBundle,
15509
+ pageContracts,
15510
+ pageId,
15511
+ protocol: Number(protocolValue),
15512
+ runtime
15513
+ },
15514
+ kind: "mobile"
15515
+ };
15516
+ };
15517
+ var responseHeaders = () => {
15518
+ const headers = new Headers({
15519
+ "cache-control": "no-store",
15520
+ "content-type": `${ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE}; version=${ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION}`
15521
+ });
15522
+ headerVaryValues.forEach((value) => headers.append("vary", value));
15523
+ return headers;
15524
+ };
15525
+ var headerVaryValues = [
15526
+ "Accept",
15527
+ MOBILE_PAGE_REQUEST_HEADERS.protocol,
15528
+ MOBILE_PAGE_REQUEST_HEADERS.runtime,
15529
+ MOBILE_PAGE_REQUEST_HEADERS.appBuild,
15530
+ MOBILE_PAGE_REQUEST_HEADERS.pageBundle,
15531
+ MOBILE_PAGE_REQUEST_HEADERS.pageContracts,
15532
+ MOBILE_PAGE_REQUEST_HEADERS.pageId
15533
+ ];
15534
+ var envelopeResponse = (response, status) => new Response(JSON.stringify({
15535
+ protocol: ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION,
15536
+ response
15537
+ }), { headers: responseHeaders(), status });
15538
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
15539
+ var normalizeJsonValue = (value) => {
15540
+ const serialized = JSON.stringify(value);
15541
+ if (serialized === undefined) {
15542
+ throw new TypeError("Mobile page props must be JSON-serializable.");
15543
+ }
15544
+ const parsed = JSON.parse(serialized);
15545
+ if (!isRecord4(parsed)) {
15546
+ throw new TypeError("Mobile page props must serialize to an object.");
15547
+ }
15548
+ return parsed;
15549
+ };
15550
+ var finalizeArchivedMobilePage = (context, input) => {
15551
+ const { page } = context;
15552
+ if (page.pageId !== input.compatibility.pageId || page.framework !== input.compatibility.framework) {
15553
+ return envelopeResponse({
15554
+ kind: "invalid-request",
15555
+ message: "Archived producer page identity does not match its release artifact."
15556
+ }, BAD_REQUEST_STATUS);
15557
+ }
15558
+ try {
15559
+ const [currentRepresentation] = input.compatibility.representations;
15560
+ if (!currentRepresentation) {
15561
+ throw new TypeError("Mobile page has no current representation.");
15562
+ }
15563
+ return envelopeResponse({
15564
+ contract: page.contract,
15565
+ framework: page.framework,
15566
+ kind: "page",
15567
+ pageId: page.pageId,
15568
+ props: normalizeJsonValue(currentRepresentation.mapProps(input.props)),
15569
+ status: input.status ?? OK_STATUS
15570
+ }, input.status ?? OK_STATUS);
15571
+ } catch (error) {
15572
+ console.error(`[Mobile] Archived producer ${context.releaseId} failed for ${page.pageId}:`, error);
15573
+ return createAbsoluteMobilePageErrorResponse(page.pageId);
15574
+ }
15575
+ };
15576
+ var createAbsoluteMobileInvalidRequestResponse = (message) => envelopeResponse({ kind: "invalid-request", message }, BAD_REQUEST_STATUS);
15577
+ var createAbsoluteMobilePageErrorResponse = (pageId) => envelopeResponse({
15578
+ code: "representation-failed",
15579
+ kind: "error",
15580
+ pageId,
15581
+ status: SERVER_ERROR_STATUS
15582
+ }, SERVER_ERROR_STATUS);
15583
+ var createAbsoluteMobileUpgradeResponse = (result) => envelopeResponse(result, UPGRADE_REQUIRED_STATUS);
15584
+ var finalizeAbsoluteMobilePage = (input) => {
15585
+ const parsed = parseAbsoluteMobilePageRequest(input.request);
15586
+ if (parsed.kind === "not-mobile")
15587
+ return;
15588
+ if (parsed.kind === "invalid") {
15589
+ return envelopeResponse({ kind: "invalid-request", message: parsed.message }, BAD_REQUEST_STATUS);
15590
+ }
15591
+ const { client } = parsed;
15592
+ if (client.pageId !== input.compatibility.pageId) {
15593
+ return envelopeResponse({
15594
+ kind: "invalid-request",
15595
+ message: `Requested mobile page ${client.pageId} does not match ${input.compatibility.pageId}.`
15596
+ }, BAD_REQUEST_STATUS);
15597
+ }
15598
+ const producerContext = getCurrentAbsoluteMobileProducerContext();
15599
+ if (producerContext)
15600
+ return finalizeArchivedMobilePage(producerContext, input);
15601
+ if (client.protocol !== ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION) {
15602
+ return envelopeResponse({
15603
+ kind: "upgrade-required",
15604
+ pageId: input.compatibility.pageId,
15605
+ reason: "protocol"
15606
+ }, UPGRADE_REQUIRED_STATUS);
15607
+ }
15608
+ if (!input.compatibility.runtimes.includes(client.runtime)) {
15609
+ return envelopeResponse({
15610
+ kind: "upgrade-required",
15611
+ pageId: input.compatibility.pageId,
15612
+ reason: "runtime",
15613
+ supportedRuntimes: [...input.compatibility.runtimes]
15614
+ }, UPGRADE_REQUIRED_STATUS);
15615
+ }
15616
+ const clientContracts = new Set(client.pageContracts);
15617
+ const representation = input.compatibility.representations.find(({ contract }) => clientContracts.has(contract));
15618
+ if (!representation) {
15619
+ return envelopeResponse({
15620
+ kind: "upgrade-required",
15621
+ pageId: input.compatibility.pageId,
15622
+ reason: "page-contract",
15623
+ supportedContracts: input.compatibility.representations.map(({ contract }) => contract)
15624
+ }, UPGRADE_REQUIRED_STATUS);
15625
+ }
15626
+ try {
15627
+ return envelopeResponse({
15628
+ contract: representation.contract,
15629
+ framework: input.compatibility.framework,
15630
+ kind: "page",
15631
+ pageId: input.compatibility.pageId,
15632
+ props: normalizeJsonValue(representation.mapProps(input.props)),
15633
+ status: input.status ?? OK_STATUS
15634
+ }, input.status ?? OK_STATUS);
15635
+ } catch (error) {
15636
+ console.error(`[Mobile] Failed to produce ${input.compatibility.pageId} representation ${representation.contract}:`, error);
15637
+ return envelopeResponse({
15638
+ code: "representation-failed",
15639
+ kind: "error",
15640
+ pageId: input.compatibility.pageId,
15641
+ status: SERVER_ERROR_STATUS
15642
+ }, SERVER_ERROR_STATUS);
15643
+ }
15644
+ };
15645
+
15332
15646
  // src/angular/ssrSanitizer.ts
15333
15647
  var escapeHtml2 = (str) => String(str).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
15334
15648
  var bypassValue = (value) => ({
@@ -15440,7 +15754,7 @@ var withRegisteredStreamingSlots = async (renderResponse, options = {}) => {
15440
15754
 
15441
15755
  // src/core/streamingSlotWarningScope.ts
15442
15756
  init_logger();
15443
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
15757
+ import { AsyncLocalStorage as AsyncLocalStorage3 } from "async_hooks";
15444
15758
  var STREAMING_SLOT_WARNING_STORAGE_KEY2 = Symbol.for("absolutejs.streamingSlotWarningAsyncLocalStorage");
15445
15759
  var isObjectRecord4 = (value) => Boolean(value) && typeof value === "object";
15446
15760
  var isAsyncLocalStorage3 = (value) => isObjectRecord4(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
@@ -15456,7 +15770,7 @@ var ensureWarningStorage = () => {
15456
15770
  if (existing) {
15457
15771
  return existing;
15458
15772
  }
15459
- const storage = new AsyncLocalStorage2;
15773
+ const storage = new AsyncLocalStorage3;
15460
15774
  Reflect.set(globalThis, STREAMING_SLOT_WARNING_STORAGE_KEY2, storage);
15461
15775
  return storage;
15462
15776
  };
@@ -15498,11 +15812,11 @@ var runWithStreamingSlotWarningScope = (task, metadata) => ensureWarningStorage(
15498
15812
 
15499
15813
  // src/angular/pageHandler.ts
15500
15814
  init_ssrRender();
15501
- var isRecord5 = (value) => typeof value === "object" && value !== null;
15815
+ var isRecord6 = (value) => typeof value === "object" && value !== null;
15502
15816
  var isAngularComponent2 = (value) => typeof value === "function";
15503
15817
  var componentHostsRouterOutlet = (component) => {
15504
15818
  const componentDef = Reflect.get(component, "\u0275cmp");
15505
- if (!isRecord5(componentDef))
15819
+ if (!isRecord6(componentDef))
15506
15820
  return false;
15507
15821
  const rawDependencies = componentDef.dependencies;
15508
15822
  const dependencies = typeof rawDependencies === "function" ? Reflect.apply(rawDependencies, undefined, []) : rawDependencies;
@@ -15512,7 +15826,7 @@ var componentHostsRouterOutlet = (component) => {
15512
15826
  if (dependency === null || typeof dependency !== "object" && typeof dependency !== "function")
15513
15827
  return false;
15514
15828
  const directiveDef = Reflect.get(dependency, "\u0275dir") ?? dependency;
15515
- if (!isRecord5(directiveDef))
15829
+ if (!isRecord6(directiveDef))
15516
15830
  return false;
15517
15831
  const { selectors } = directiveDef;
15518
15832
  return Array.isArray(selectors) && JSON.stringify(selectors).includes("router-outlet");
@@ -15542,7 +15856,7 @@ var ensureAngularCompiler = () => {
15542
15856
  }
15543
15857
  return compilerImportPromise;
15544
15858
  };
15545
- var readAngularPageModule = (value) => isRecord5(value) ? value : null;
15859
+ var readAngularPageModule = (value) => isRecord6(value) ? value : null;
15546
15860
  var resolveAngularSsrOutDir = (projectRoot = process.cwd(), configuredOutDir = process.env.ABSOLUTE_ANGULAR_SSR_OUTDIR) => configuredOutDir ?? join10(projectRoot, ".absolutejs", "runtime", "angular-ssr");
15547
15861
  var createAngularRuntimeCacheBuster = () => `${Date.now().toString(BASE_36_RADIX)}.${Math.random().toString(BASE_36_RADIX).substring(2, RANDOM_ID_END_INDEX)}`;
15548
15862
  var existingNodeModulesLinkMatches = async (nodeModulesLink, expectedTarget) => {
@@ -15643,14 +15957,32 @@ var resolveRequestRenderUrl = (request) => {
15643
15957
  return "/";
15644
15958
  }
15645
15959
  };
15646
- var angularSsrContext = new AsyncLocalStorage3;
15960
+ var angularSsrContext = new AsyncLocalStorage4;
15647
15961
  setSsrContextGetter(() => angularSsrContext.getStore());
15648
15962
  var handleAngularPageRequest = async (input) => {
15649
15963
  const requestId = `angular_${Date.now()}_${Math.random().toString(BASE_36_RADIX).substring(2, RANDOM_ID_END_INDEX)}`;
15964
+ const request = input.request ?? getCurrentAbsoluteRequest();
15965
+ const pageId = input.__absoluteMobile?.pageId ?? derivePageName(input.pagePath);
15966
+ const currentContract = input.__absoluteMobile?.contract ?? `angular:${pageId}:${ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION}`;
15967
+ const mobileResponse = finalizeAbsoluteMobilePage({
15968
+ compatibility: {
15969
+ framework: "angular",
15970
+ pageId,
15971
+ representations: [
15972
+ { contract: currentContract, mapProps: (props) => props }
15973
+ ],
15974
+ runtimes: [String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)]
15975
+ },
15976
+ props: isRecord6(input.requestContext) ? input.requestContext : Object.create(null),
15977
+ request,
15978
+ status: input.responseInit?.status
15979
+ });
15980
+ if (mobileResponse)
15981
+ return mobileResponse;
15650
15982
  return angularSsrContext.run(requestId, async () => {
15651
- const spaNotFound = await renderSpaNotFound("angular", derivePageName(input.pagePath), input.request);
15983
+ const spaNotFound = await renderSpaNotFound("angular", derivePageName(input.pagePath), request);
15652
15984
  if (spaNotFound)
15653
- return withPageCacheHeaders(spaNotFound, input.request);
15985
+ return withPageCacheHeaders(spaNotFound, request);
15654
15986
  await ensureAngularCompiler();
15655
15987
  const userHeadTag = input.headTag ?? "<head></head>";
15656
15988
  const resolvedIndexPath = input.indexPath;
@@ -15658,7 +15990,7 @@ var handleAngularPageRequest = async (input) => {
15658
15990
  const resolvedPagePath = input.pagePath;
15659
15991
  const maybeRequestContext = input.requestContext;
15660
15992
  const responseInit = input.responseInit ?? {};
15661
- const resolvedUrl = resolveRequestRenderUrl(input.request);
15993
+ const resolvedUrl = resolveRequestRenderUrl(request);
15662
15994
  const siblingCss = await readSiblingCss(resolvedPagePath);
15663
15995
  const resolvedHeadTag = injectInlineCss(userHeadTag, siblingCss);
15664
15996
  cacheRouteData(resolvedPagePath, {
@@ -15695,7 +16027,7 @@ var handleAngularPageRequest = async (input) => {
15695
16027
  ...handlerCallProviders,
15696
16028
  ...await buildServerAnimationProviders(usesLegacyAnimations)
15697
16029
  ];
15698
- const providers = buildProviders(deps, sanitizer, input.request, maybeRequestContext, responseInit, combinedProviders);
16030
+ const providers = buildProviders(deps, sanitizer, request, maybeRequestContext, responseInit, combinedProviders);
15699
16031
  const rawHtml = await renderAngularApp(deps, PageComponent, providers, htmlString, resolvedUrl);
15700
16032
  const shouldProcessIslands = hasIslands || rawHtml.includes("<absolute-island");
15701
16033
  const htmlWithLoweredIslands = shouldProcessIslands ? await lowerAngularServerIslands(rawHtml) : rawHtml;
@@ -15703,18 +16035,18 @@ var handleAngularPageRequest = async (input) => {
15703
16035
  return new Response(html, withHtmlContentType(responseInit));
15704
16036
  };
15705
16037
  const pageResponse = await runWithStreamingSlotWarningScope(() => options?.collectStreamingSlots === true ? withRegisteredStreamingSlots(renderPageResponse, options) : renderPageResponse(), { handlerCallsite });
15706
- return withPageCacheHeaders(pageResponse, input.request);
16038
+ return withPageCacheHeaders(pageResponse, request);
15707
16039
  } catch (error) {
15708
16040
  console.error("[SSR] Angular render error:", error);
15709
16041
  const pageName = derivePageName(resolvedPagePath);
15710
16042
  const conventionResponse = await renderConventionError("angular", pageName, error);
15711
16043
  if (conventionResponse) {
15712
- return withPageCacheHeaders(conventionResponse, input.request);
16044
+ return withPageCacheHeaders(conventionResponse, request);
15713
16045
  }
15714
16046
  return withPageCacheHeaders(new Response(ssrErrorPage("angular", error), {
15715
16047
  headers: { "Content-Type": "text/html" },
15716
16048
  status: 500
15717
- }), input.request);
16049
+ }), request);
15718
16050
  }
15719
16051
  });
15720
16052
  };
@@ -16258,5 +16590,5 @@ export {
16258
16590
  ABSOLUTE_HTTP_TRANSFER_CACHE_SKIP_HEADER
16259
16591
  };
16260
16592
 
16261
- //# debugId=E2408FA291D0349964756E2164756E21
16593
+ //# debugId=7ED2C1B48F6EF28964756E2164756E21
16262
16594
  //# sourceMappingURL=index.js.map