@absolutejs/absolute 0.19.0-beta.1023 → 0.19.0-beta.1025

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 (45) hide show
  1. package/dist/angular/browser.js +13 -17
  2. package/dist/angular/browser.js.map +3 -3
  3. package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
  4. package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
  5. package/dist/angular/index.js +595 -267
  6. package/dist/angular/index.js.map +11 -8
  7. package/dist/angular/server.js +577 -249
  8. package/dist/angular/server.js.map +11 -8
  9. package/dist/build.js +827 -735
  10. package/dist/build.js.map +11 -10
  11. package/dist/cli/config/server.js +49 -42
  12. package/dist/cli/index.js +366 -9
  13. package/dist/client/index.js +34 -20
  14. package/dist/client/index.js.map +6 -6
  15. package/dist/index.js +899 -800
  16. package/dist/index.js.map +12 -11
  17. package/dist/islands/index.js +416 -95
  18. package/dist/islands/index.js.map +10 -7
  19. package/dist/react/browser.js +13 -17
  20. package/dist/react/browser.js.map +3 -3
  21. package/dist/react/index.js +484 -156
  22. package/dist/react/index.js.map +12 -9
  23. package/dist/react/server.js +69 -62
  24. package/dist/react/server.js.map +5 -5
  25. package/dist/src/cli/scripts/tunnelRelay.d.ts +9 -0
  26. package/dist/src/client/preserveIslandMarkup.d.ts +4 -1
  27. package/dist/src/core/angularServerModule.d.ts +1 -0
  28. package/dist/src/dev/tunnel/client.d.ts +20 -0
  29. package/dist/src/dev/tunnel/protocol.d.ts +85 -0
  30. package/dist/src/dev/tunnel/relay.d.ts +28 -0
  31. package/dist/src/utils/loadConfig.d.ts +4 -0
  32. package/dist/svelte/index.js +389 -61
  33. package/dist/svelte/index.js.map +11 -8
  34. package/dist/svelte/server.js +50 -43
  35. package/dist/svelte/server.js.map +3 -3
  36. package/dist/types/angular.d.ts +3 -0
  37. package/dist/types/build.d.ts +11 -0
  38. package/dist/types/globals.d.ts +0 -1
  39. package/dist/vue/browser.js +13 -17
  40. package/dist/vue/browser.js.map +3 -3
  41. package/dist/vue/index.js +477 -153
  42. package/dist/vue/index.js.map +12 -9
  43. package/dist/vue/server.js +50 -43
  44. package/dist/vue/server.js.map +3 -3
  45. package/package.json +2 -6
@@ -35275,7 +35275,6 @@ var ensureConfigCert = (host) => {
35275
35275
  };
35276
35276
  // src/constants.ts
35277
35277
  var BASE_36_RADIX = 36;
35278
- var BYTES_PER_KILOBYTE = 1024;
35279
35278
  var CONFIG_DEFAULT_HOST = "config.absolute.localhost";
35280
35279
  var CONFIG_DEFAULT_PORT = 4099;
35281
35280
  var HTTP_STATUS_BAD_REQUEST = 400;
@@ -35410,61 +35409,69 @@ var pipeStreamWithHeadInjection = (stream, markup) => {
35410
35409
  var pipeStreamWithIslandMarkerDetection = (stream, markup) => {
35411
35410
  const encoder = new TextEncoder;
35412
35411
  const decoder = new TextDecoder;
35413
- const lookbehind = Math.max(ISLAND_MARKER.length, BYTES_PER_KILOBYTE);
35414
- const processPending = (controller, pending, injected) => {
35415
- if (injected) {
35416
- controller.enqueue(encoder.encode(pending));
35417
- return { injected, pending: "" };
35412
+ const headLookbehind = CLOSING_HEAD_TAG.length - 1;
35413
+ const enqueue = (controller, text) => {
35414
+ if (text.length > 0) {
35415
+ controller.enqueue(encoder.encode(text));
35418
35416
  }
35419
- const markerIndex = pending.indexOf(ISLAND_MARKER);
35420
- if (markerIndex >= 0) {
35421
- const tagStart = pending.lastIndexOf("<", markerIndex);
35422
- const injectAt = tagStart >= 0 ? tagStart : markerIndex;
35423
- const next = `${pending.slice(0, injectAt)}${markup}${pending.slice(injectAt)}`;
35424
- controller.enqueue(encoder.encode(next));
35425
- return { injected: true, pending: "" };
35417
+ };
35418
+ const processHolding = (controller, held) => {
35419
+ if (!held.includes(ISLAND_MARKER)) {
35420
+ return { held, injected: false, pending: "", sawHead: true };
35426
35421
  }
35427
- return {
35428
- injected,
35429
- pending: flushSafePendingText(controller, encoder, pending, lookbehind)
35430
- };
35422
+ enqueue(controller, `${markup}${held}`);
35423
+ return { held: "", injected: true, pending: "", sawHead: true };
35431
35424
  };
35432
- const finishIslandMarkerStream = (controller, pending) => {
35433
- const finalPending = pending + decoder.decode();
35434
- if (finalPending.length > 0) {
35435
- controller.enqueue(encoder.encode(finalPending));
35425
+ const processHead = (controller, pending) => {
35426
+ const headIndex = pending.indexOf(CLOSING_HEAD_TAG);
35427
+ if (headIndex < 0) {
35428
+ return {
35429
+ held: "",
35430
+ injected: false,
35431
+ pending: flushSafePendingText(controller, encoder, pending, headLookbehind),
35432
+ sawHead: false
35433
+ };
35436
35434
  }
35437
- controller.close();
35435
+ enqueue(controller, pending.slice(0, headIndex));
35436
+ return processHolding(controller, pending.slice(headIndex));
35438
35437
  };
35439
- const consumeIslandChunk = async (controller, reader, pending, injected) => {
35440
- const { done, value } = await readStreamChunk(reader);
35441
- if (done || !value) {
35442
- return { done, injected, pending };
35438
+ const processChunk = (controller, state, chunk) => {
35439
+ if (state.injected) {
35440
+ enqueue(controller, chunk);
35441
+ return state;
35443
35442
  }
35444
- const processed = processPending(controller, pending + streamChunkToString(value, decoder), injected);
35445
- return {
35446
- done,
35447
- injected: processed.injected,
35448
- pending: processed.pending
35449
- };
35443
+ if (!state.sawHead) {
35444
+ return processHead(controller, state.pending + chunk);
35445
+ }
35446
+ return processHolding(controller, state.held + chunk);
35450
35447
  };
35451
- const runIslandMarkerLoop = async (controller, reader) => {
35452
- const consumeNextIslandChunk = async (injected, pending) => {
35453
- const consumed = await consumeIslandChunk(controller, reader, pending, injected);
35454
- const nextState = updateInjectedState(consumed, injected, pending);
35455
- if (nextState.done) {
35456
- return { injected, pending };
35448
+ const finishMarkerStream = (controller, state) => {
35449
+ const tail = decoder.decode();
35450
+ const remainder = state.injected ? tail : (state.sawHead ? state.held : state.pending) + tail;
35451
+ enqueue(controller, remainder);
35452
+ controller.close();
35453
+ };
35454
+ const runMarkerLoop = (controller, reader) => {
35455
+ const consumeNext = async (state) => {
35456
+ const { done, value } = await readStreamChunk(reader);
35457
+ if (done || !value) {
35458
+ return state;
35457
35459
  }
35458
- return consumeNextIslandChunk(nextState.injected, nextState.pending);
35460
+ return consumeNext(processChunk(controller, state, streamChunkToString(value, decoder)));
35459
35461
  };
35460
- return consumeNextIslandChunk(false, "");
35462
+ return consumeNext({
35463
+ held: "",
35464
+ injected: false,
35465
+ pending: "",
35466
+ sawHead: false
35467
+ });
35461
35468
  };
35462
35469
  return new ReadableStream({
35463
35470
  async start(controller) {
35464
35471
  const reader = stream.getReader();
35465
35472
  try {
35466
- const { pending } = await runIslandMarkerLoop(controller, reader);
35467
- finishIslandMarkerStream(controller, pending);
35473
+ const finalState = await runMarkerLoop(controller, reader);
35474
+ finishMarkerStream(controller, finalState);
35468
35475
  } catch (error) {
35469
35476
  controller.error(error);
35470
35477
  }
package/dist/cli/index.js CHANGED
@@ -55,6 +55,16 @@ var init_constants = __esm(() => {
55
55
  TWO_THIRDS = 2 / 3;
56
56
  });
57
57
 
58
+ // src/dev/tunnel/protocol.ts
59
+ var TUNNEL_CONTROL_PATH = "/__abs_tunnel/control", TUNNEL_FORWARDED_HOST_HEADER = "x-absolute-tunnel-host", decodeTunnelMessage = (raw) => {
60
+ try {
61
+ const parsed = JSON.parse(raw);
62
+ return parsed;
63
+ } catch {
64
+ return null;
65
+ }
66
+ }, encodeTunnelMessage = (message) => JSON.stringify(message);
67
+
58
68
  // src/utils/getDurationString.ts
59
69
  var getDurationString = (duration) => {
60
70
  let durationString;
@@ -172658,14 +172668,337 @@ var init_typecheck = __esm(() => {
172658
172668
  ];
172659
172669
  });
172660
172670
 
172671
+ // src/dev/tunnel/relay.ts
172672
+ var DEFAULT_RELAY_PORT = 8787, DEFAULT_REQUEST_TIMEOUT_MS = 30000, headersToObject = (headers) => {
172673
+ const out = {};
172674
+ headers.forEach((value, key) => {
172675
+ out[key] = value;
172676
+ });
172677
+ return out;
172678
+ }, startTunnelRelay = (options) => {
172679
+ const port = options.port ?? (Number(process.env.PORT) || DEFAULT_RELAY_PORT);
172680
+ const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
172681
+ let client = null;
172682
+ const pending = new Map;
172683
+ const publicSockets = new Map;
172684
+ const resolvePublicUrl = (request) => {
172685
+ if (options.publicUrl)
172686
+ return options.publicUrl.replace(/\/$/, "");
172687
+ const url = new URL(request.url);
172688
+ const host = request.headers.get("x-forwarded-host") ?? url.host;
172689
+ const proto = request.headers.get("x-forwarded-proto") ?? url.protocol.replace(":", "");
172690
+ return `${proto}://${host}`;
172691
+ };
172692
+ const isWebSocketUpgrade = (request) => request.headers.get("upgrade")?.toLowerCase() === "websocket";
172693
+ const server2 = Bun.serve({
172694
+ port,
172695
+ websocket: {
172696
+ close(ws) {
172697
+ if (ws.data.control) {
172698
+ if (client === ws)
172699
+ client = null;
172700
+ return;
172701
+ }
172702
+ publicSockets.delete(ws.data.id);
172703
+ client?.send(encodeTunnelMessage({ id: ws.data.id, type: "ws_close" }));
172704
+ },
172705
+ message(ws, raw) {
172706
+ if (!ws.data.control) {
172707
+ const binary = typeof raw !== "string";
172708
+ const bytes = typeof raw === "string" ? Buffer.from(raw, "utf8") : Buffer.from(raw);
172709
+ client?.send(encodeTunnelMessage({
172710
+ binary,
172711
+ dataBase64: bytes.toString("base64"),
172712
+ id: ws.data.id,
172713
+ type: "ws_data"
172714
+ }));
172715
+ return;
172716
+ }
172717
+ const message = decodeTunnelMessage(typeof raw === "string" ? raw : raw.toString());
172718
+ if (!message)
172719
+ return;
172720
+ switch (message.type) {
172721
+ case "ping":
172722
+ ws.send(encodeTunnelMessage({ type: "pong" }));
172723
+ break;
172724
+ case "response":
172725
+ case "error":
172726
+ pending.get(message.id)?.(message);
172727
+ break;
172728
+ case "ws_open_ack":
172729
+ if (!message.ok)
172730
+ publicSockets.get(message.id)?.close();
172731
+ break;
172732
+ case "ws_data": {
172733
+ const target = publicSockets.get(message.id);
172734
+ const bytes = Buffer.from(message.dataBase64, "base64");
172735
+ target?.send(message.binary ? bytes : bytes.toString("utf8"));
172736
+ break;
172737
+ }
172738
+ case "ws_close":
172739
+ publicSockets.get(message.id)?.close(message.code, message.reason);
172740
+ publicSockets.delete(message.id);
172741
+ break;
172742
+ default:
172743
+ break;
172744
+ }
172745
+ },
172746
+ open(ws) {
172747
+ if (ws.data.control) {
172748
+ client = ws;
172749
+ ws.send(encodeTunnelMessage({ publicUrl: options.publicUrl ?? "", type: "ready" }));
172750
+ return;
172751
+ }
172752
+ publicSockets.set(ws.data.id, ws);
172753
+ client?.send(encodeTunnelMessage({
172754
+ headers: ws.data.headers,
172755
+ id: ws.data.id,
172756
+ type: "ws_open",
172757
+ url: ws.data.url
172758
+ }));
172759
+ }
172760
+ },
172761
+ async fetch(request, srv) {
172762
+ const url = new URL(request.url);
172763
+ if (url.pathname === TUNNEL_CONTROL_PATH) {
172764
+ if (url.searchParams.get("token") !== options.token) {
172765
+ return new Response("Forbidden", { status: 403 });
172766
+ }
172767
+ const upgraded = srv.upgrade(request, { data: { control: true } });
172768
+ return upgraded ? undefined : new Response("Upgrade failed", { status: 426 });
172769
+ }
172770
+ if (!client) {
172771
+ return new Response("Tunnel offline: no dev client connected.", { status: 503 });
172772
+ }
172773
+ if (isWebSocketUpgrade(request)) {
172774
+ const id2 = crypto.randomUUID();
172775
+ const upgraded = srv.upgrade(request, {
172776
+ data: {
172777
+ control: false,
172778
+ headers: headersToObject(request.headers),
172779
+ id: id2,
172780
+ url: url.pathname + url.search
172781
+ }
172782
+ });
172783
+ return upgraded ? undefined : new Response("Upgrade failed", { status: 426 });
172784
+ }
172785
+ const id = crypto.randomUUID();
172786
+ const bodyBytes = ["GET", "HEAD"].includes(request.method) ? null : new Uint8Array(await request.arrayBuffer());
172787
+ const headers = headersToObject(request.headers);
172788
+ headers[TUNNEL_FORWARDED_HOST_HEADER] = resolvePublicUrl(request);
172789
+ const message = {
172790
+ headers,
172791
+ id,
172792
+ method: request.method,
172793
+ type: "request",
172794
+ url: url.pathname + url.search,
172795
+ ...bodyBytes && bodyBytes.length > 0 ? { bodyBase64: Buffer.from(bodyBytes).toString("base64") } : {}
172796
+ };
172797
+ const responsePromise = new Promise((resolve14) => {
172798
+ pending.set(id, resolve14);
172799
+ });
172800
+ client.send(encodeTunnelMessage(message));
172801
+ const timeout = new Promise((resolve14) => setTimeout(() => resolve14({ id, message: "timeout", type: "error" }), requestTimeoutMs));
172802
+ const result = await Promise.race([responsePromise, timeout]);
172803
+ pending.delete(id);
172804
+ if (result.type === "error") {
172805
+ return new Response(`Tunnel error: ${result.message}`, { status: 504 });
172806
+ }
172807
+ if (result.type !== "response") {
172808
+ return new Response("Tunnel protocol error", { status: 502 });
172809
+ }
172810
+ return new Response(result.bodyBase64 ? Buffer.from(result.bodyBase64, "base64") : null, { headers: result.headers, status: result.status });
172811
+ }
172812
+ });
172813
+ console.info(`[tunnel-relay] listening on :${server2.port} (control ${TUNNEL_CONTROL_PATH})`);
172814
+ return server2;
172815
+ };
172816
+ var init_relay = () => {};
172817
+
172818
+ // src/cli/scripts/tunnelRelay.ts
172819
+ var exports_tunnelRelay = {};
172820
+ __export(exports_tunnelRelay, {
172821
+ tunnelRelay: () => tunnelRelay
172822
+ });
172823
+ var tunnelRelay = () => {
172824
+ const token = process.env.ABSOLUTE_TUNNEL_TOKEN;
172825
+ if (!token) {
172826
+ console.error("[tunnel-relay] ABSOLUTE_TUNNEL_TOKEN is required.");
172827
+ process.exit(1);
172828
+ }
172829
+ startTunnelRelay({
172830
+ port: Number(process.env.PORT) || undefined,
172831
+ publicUrl: process.env.ABSOLUTE_TUNNEL_PUBLIC_URL,
172832
+ token
172833
+ });
172834
+ };
172835
+ var init_tunnelRelay = __esm(() => {
172836
+ init_relay();
172837
+ });
172838
+
172661
172839
  // src/cli/scripts/dev.ts
172662
172840
  init_constants();
172663
- init_startupBanner();
172664
172841
  var {$: $2, env } = globalThis.Bun;
172665
172842
  import { spawn as nodeSpawn } from "child_process";
172666
172843
  import { createWriteStream, existsSync as existsSync5, readFileSync as readFileSync7 } from "fs";
172667
172844
  import { resolve as resolve3 } from "path";
172668
172845
 
172846
+ // src/dev/tunnel/client.ts
172847
+ var RECONNECT_DELAY_MS = 2000;
172848
+ var controlSocketUrl = (relayUrl, token) => {
172849
+ const url = new URL(relayUrl);
172850
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
172851
+ url.pathname = TUNNEL_CONTROL_PATH;
172852
+ url.search = `?token=${encodeURIComponent(token)}`;
172853
+ return url.toString();
172854
+ };
172855
+ var STRIPPED_REQUEST_HEADERS = new Set(["host", "connection", "content-length", TUNNEL_FORWARDED_HOST_HEADER]);
172856
+ var startTunnelClient = (options) => {
172857
+ const publicUrl = options.relayUrl.replace(/\/$/, "");
172858
+ const localWsOrigin = options.localOrigin.replace(/^http/, "ws");
172859
+ let socket = null;
172860
+ let closed = false;
172861
+ let reconnectTimer = null;
172862
+ const localSockets = new Map;
172863
+ const sendFrameToRelay = (id, data, binary) => {
172864
+ const bytes = typeof data === "string" ? Buffer.from(data, "utf8") : data;
172865
+ const message = {
172866
+ binary,
172867
+ dataBase64: bytes.toString("base64"),
172868
+ id,
172869
+ type: "ws_data"
172870
+ };
172871
+ socket?.send(encodeTunnelMessage(message));
172872
+ };
172873
+ const openLocalWs = (id, url) => {
172874
+ const local = new WebSocket(`${localWsOrigin}${url}`);
172875
+ local.binaryType = "arraybuffer";
172876
+ const entry = { pending: [], ready: false, ws: local };
172877
+ localSockets.set(id, entry);
172878
+ local.addEventListener("open", () => {
172879
+ entry.ready = true;
172880
+ socket?.send(encodeTunnelMessage({ id, ok: true, type: "ws_open_ack" }));
172881
+ for (const frame of entry.pending) {
172882
+ local.send(frame.binary ? frame.bytes : frame.bytes.toString("utf8"));
172883
+ }
172884
+ entry.pending = [];
172885
+ });
172886
+ local.addEventListener("message", (event) => {
172887
+ if (typeof event.data === "string") {
172888
+ sendFrameToRelay(id, event.data, false);
172889
+ } else if (event.data instanceof ArrayBuffer) {
172890
+ sendFrameToRelay(id, Buffer.from(event.data), true);
172891
+ }
172892
+ });
172893
+ local.addEventListener("close", (event) => {
172894
+ localSockets.delete(id);
172895
+ socket?.send(encodeTunnelMessage({ code: event.code, id, type: "ws_close" }));
172896
+ });
172897
+ local.addEventListener("error", () => {
172898
+ if (!entry.ready) {
172899
+ socket?.send(encodeTunnelMessage({ error: "local ws failed", id, ok: false, type: "ws_open_ack" }));
172900
+ }
172901
+ });
172902
+ };
172903
+ const forwardFrameToLocal = (message) => {
172904
+ const entry = localSockets.get(message.id);
172905
+ if (!entry)
172906
+ return;
172907
+ const bytes = Buffer.from(message.dataBase64, "base64");
172908
+ if (!entry.ready) {
172909
+ entry.pending.push({ binary: message.binary, bytes });
172910
+ return;
172911
+ }
172912
+ entry.ws.send(message.binary ? bytes : bytes.toString("utf8"));
172913
+ };
172914
+ const handleRequest = async (message) => {
172915
+ const headers = {};
172916
+ for (const [key, value] of Object.entries(message.headers)) {
172917
+ if (!STRIPPED_REQUEST_HEADERS.has(key.toLowerCase()))
172918
+ headers[key] = value;
172919
+ }
172920
+ try {
172921
+ const response = await fetch(`${options.localOrigin}${message.url}`, {
172922
+ body: message.bodyBase64 ? Buffer.from(message.bodyBase64, "base64") : undefined,
172923
+ headers,
172924
+ method: message.method,
172925
+ redirect: "manual"
172926
+ });
172927
+ const bodyBytes = new Uint8Array(await response.arrayBuffer());
172928
+ const responseHeaders = {};
172929
+ response.headers.forEach((value, key) => {
172930
+ responseHeaders[key] = value;
172931
+ });
172932
+ const reply = {
172933
+ headers: responseHeaders,
172934
+ id: message.id,
172935
+ status: response.status,
172936
+ type: "response",
172937
+ ...bodyBytes.length > 0 ? { bodyBase64: Buffer.from(bodyBytes).toString("base64") } : {}
172938
+ };
172939
+ socket?.send(encodeTunnelMessage(reply));
172940
+ } catch (error) {
172941
+ socket?.send(encodeTunnelMessage({
172942
+ id: message.id,
172943
+ message: error instanceof Error ? error.message : String(error),
172944
+ type: "error"
172945
+ }));
172946
+ }
172947
+ };
172948
+ const connect = () => {
172949
+ if (closed)
172950
+ return;
172951
+ socket = new WebSocket(controlSocketUrl(options.relayUrl, options.token));
172952
+ socket.addEventListener("message", (event) => {
172953
+ const message = decodeTunnelMessage(String(event.data));
172954
+ if (!message)
172955
+ return;
172956
+ switch (message.type) {
172957
+ case "request":
172958
+ handleRequest(message);
172959
+ break;
172960
+ case "ready":
172961
+ options.onReady?.(publicUrl);
172962
+ break;
172963
+ case "ping":
172964
+ socket?.send(encodeTunnelMessage({ type: "pong" }));
172965
+ break;
172966
+ case "ws_open":
172967
+ openLocalWs(message.id, message.url);
172968
+ break;
172969
+ case "ws_data":
172970
+ forwardFrameToLocal(message);
172971
+ break;
172972
+ case "ws_close":
172973
+ localSockets.get(message.id)?.ws.close();
172974
+ localSockets.delete(message.id);
172975
+ break;
172976
+ default:
172977
+ break;
172978
+ }
172979
+ });
172980
+ socket.addEventListener("close", () => {
172981
+ if (closed)
172982
+ return;
172983
+ reconnectTimer = setTimeout(connect, RECONNECT_DELAY_MS);
172984
+ });
172985
+ socket.addEventListener("error", () => {});
172986
+ };
172987
+ connect();
172988
+ return {
172989
+ publicUrl,
172990
+ close() {
172991
+ closed = true;
172992
+ if (reconnectTimer)
172993
+ clearTimeout(reconnectTimer);
172994
+ socket?.close();
172995
+ }
172996
+ };
172997
+ };
172998
+
172999
+ // src/cli/scripts/dev.ts
173000
+ init_startupBanner();
173001
+
172669
173002
  // src/cli/interactive.ts
172670
173003
  init_constants();
172671
173004
  import { openSync } from "fs";
@@ -173037,13 +173370,18 @@ var setupHttpsCert = async () => {
173037
173370
  }
173038
173371
  await setupCertWithPrompt(ensureDevCert2, setupMkcert2);
173039
173372
  };
173040
- var resolveDevConfig = (configDev) => ({
173041
- port: Number(env.ABSOLUTE_PORT) || Number(env.PORT) || configDev?.port || DEFAULT_PORT,
173042
- portRange: Number(env.ABSOLUTE_PORT_RANGE) || configDev?.portRange || DEFAULT_PORT_RANGE,
173043
- strictPort: env.ABSOLUTE_STRICT_PORT === "true" || configDev?.strictPort === true,
173044
- host: env.ABSOLUTE_HOST ?? configDev?.host ?? "localhost",
173045
- https: env.ABSOLUTE_HTTPS === "true" || configDev?.https === true
173046
- });
173373
+ var resolveDevConfig = (configDev) => {
173374
+ const relay = env.ABSOLUTE_TUNNEL_RELAY ?? configDev?.tunnel?.relay;
173375
+ const token = env.ABSOLUTE_TUNNEL_TOKEN ?? configDev?.tunnel?.token;
173376
+ return {
173377
+ host: env.ABSOLUTE_HOST ?? configDev?.host ?? "localhost",
173378
+ https: env.ABSOLUTE_HTTPS === "true" || configDev?.https === true,
173379
+ port: Number(env.ABSOLUTE_PORT) || Number(env.PORT) || configDev?.port || DEFAULT_PORT,
173380
+ portRange: Number(env.ABSOLUTE_PORT_RANGE) || configDev?.portRange || DEFAULT_PORT_RANGE,
173381
+ strictPort: env.ABSOLUTE_STRICT_PORT === "true" || configDev?.strictPort === true,
173382
+ ...relay && token ? { tunnel: { relay, token } } : {}
173383
+ };
173384
+ };
173047
173385
  var dev = async (serverEntry, configPath2) => {
173048
173386
  let httpsEnabled = false;
173049
173387
  let resolvedDev;
@@ -173078,7 +173416,7 @@ var dev = async (serverEntry, configPath2) => {
173078
173416
  console.error(cliTag("\x1B[31m", String(err.message ?? err)));
173079
173417
  process.exit(1);
173080
173418
  });
173081
- let port = initialPortProbe.port;
173419
+ let { port } = initialPortProbe;
173082
173420
  if (initialPortProbe.fellBack) {
173083
173421
  const displayHost = resolvedDev.host === "0.0.0.0" ? "localhost" : resolvedDev.host;
173084
173422
  console.log(cliTag("\x1B[33m", `Port ${resolvedDev.port} is in use, trying another one... \u2192 http://${displayHost}:${port}/`));
@@ -173123,11 +173461,24 @@ var dev = async (serverEntry, configPath2) => {
173123
173461
  let cleaning = false;
173124
173462
  let interactive = null;
173125
173463
  let serverReady = false;
173464
+ let tunnelClient = null;
173465
+ const startTunnelIfConfigured = () => {
173466
+ if (tunnelClient || !resolvedDev.tunnel)
173467
+ return;
173468
+ tunnelClient = startTunnelClient({
173469
+ localOrigin: `http://localhost:${port}`,
173470
+ relayUrl: resolvedDev.tunnel.relay,
173471
+ token: resolvedDev.tunnel.token,
173472
+ onReady: (publicUrl) => process.stdout.write(` \x1B[32m\u279C\x1B[0m \x1B[1mPublic:\x1B[0m ${publicUrl}/
173473
+ `)
173474
+ });
173475
+ };
173126
173476
  const checkServerReady = (value) => {
173127
173477
  const chunk = value.toString();
173128
173478
  if (!chunk.includes("Local:"))
173129
173479
  return;
173130
173480
  serverReady = true;
173481
+ startTunnelIfConfigured();
173131
173482
  interactive?.showPrompt();
173132
173483
  };
173133
173484
  const RESTART_MARKER = "[abs:restart]";
@@ -173391,6 +173742,7 @@ var dev = async (serverEntry, configPath2) => {
173391
173742
  });
173392
173743
  if (interactive)
173393
173744
  interactive.dispose();
173745
+ tunnelClient?.close();
173394
173746
  if (paused)
173395
173747
  sendSignal("SIGCONT");
173396
173748
  killChildTree("SIGTERM");
@@ -175905,6 +176257,10 @@ if (command === "dev") {
175905
176257
  sendTelemetryEvent("cli:command", { command });
175906
176258
  const { setupMkcert: setupMkcert2 } = await Promise.resolve().then(() => (init_devCert(), exports_devCert));
175907
176259
  setupMkcert2();
176260
+ } else if (command === "tunnel-relay") {
176261
+ sendTelemetryEvent("cli:command", { command });
176262
+ const { tunnelRelay: tunnelRelay2 } = await Promise.resolve().then(() => (init_tunnelRelay(), exports_tunnelRelay));
176263
+ tunnelRelay2();
175908
176264
  } else {
175909
176265
  const message = command ? `Unknown command: ${command}` : "No command specified";
175910
176266
  console.error(message);
@@ -175922,5 +176278,6 @@ if (command === "dev") {
175922
176278
  console.error(" prettier Run Prettier check (cached)");
175923
176279
  console.error(" typecheck Run type checkers for all frameworks");
175924
176280
  console.error(" telemetry Manage anonymous telemetry");
176281
+ console.error(" tunnel-relay Run the public reverse-tunnel relay (for webhook dev)");
175925
176282
  process.exit(1);
175926
176283
  }
@@ -259,12 +259,20 @@ __export(exports_react, {
259
259
  });
260
260
  import { createElement } from "react";
261
261
  import { hydrateRoot } from "react-dom/client";
262
- var reactIslandRoots, isPropsRecord = (value) => typeof value === "object" && value !== null, isReactComponent = (value) => typeof value === "function", hydrateReactIsland = (component, element, props) => {
262
+ var reactIslandRoots, isPropsRecord = (value) => typeof value === "object" && value !== null, HOST_REACT_EXPANDO_PREFIXES, detachFromHostReactRoot = (element) => {
263
+ for (const key of Object.keys(element)) {
264
+ const isHostExpando = HOST_REACT_EXPANDO_PREFIXES.some((prefix) => key.startsWith(prefix));
265
+ if (!isHostExpando)
266
+ continue;
267
+ Reflect.deleteProperty(element, key);
268
+ }
269
+ }, isReactComponent = (value) => typeof value === "function", hydrateReactIsland = (component, element, props) => {
263
270
  const existingRoot = reactIslandRoots.get(element);
264
271
  if (existingRoot) {
265
272
  existingRoot.render(isPropsRecord(props) ? createElement(component, props) : createElement(component));
266
273
  return;
267
274
  }
275
+ detachFromHostReactRoot(element);
268
276
  if (!isPropsRecord(props)) {
269
277
  reactIslandRoots.set(element, hydrateRoot(element, createElement(component)));
270
278
  return;
@@ -273,6 +281,14 @@ var reactIslandRoots, isPropsRecord = (value) => typeof value === "object" && va
273
281
  };
274
282
  var init_react = __esm(() => {
275
283
  reactIslandRoots = new WeakMap;
284
+ HOST_REACT_EXPANDO_PREFIXES = [
285
+ "__reactFiber$",
286
+ "__reactProps$",
287
+ "__reactContainer$",
288
+ "__reactEvents$",
289
+ "__reactListeners$",
290
+ "__reactHandles$"
291
+ ];
276
292
  });
277
293
 
278
294
  // src/client/hydrators/svelte.ts
@@ -524,9 +540,12 @@ var initDominoAdapter = (platformServer) => {
524
540
  return {
525
541
  APP_BASE_HREF: common.APP_BASE_HREF,
526
542
  bootstrapApplication: platformBrowser.bootstrapApplication,
543
+ Component: core.Component,
527
544
  DomSanitizer: platformBrowser.DomSanitizer,
528
545
  ENVIRONMENT_INITIALIZER: core.ENVIRONMENT_INITIALIZER,
529
546
  inject: core.inject,
547
+ InjectionToken: core.InjectionToken,
548
+ NgComponentOutlet: common.NgComponentOutlet,
530
549
  provideClientHydration: platformBrowser.provideClientHydration,
531
550
  provideServerRendering: platformServer.provideServerRendering,
532
551
  provideZonelessChangeDetection: core.provideZonelessChangeDetection,
@@ -782,9 +801,8 @@ var angularIslandSelector = "abs-angular-island", isAngularComponent = (value) =
782
801
  const componentName = typeof component.name === "string" && component.name.length > 0 ? component.name : "AngularIsland";
783
802
  return `${componentName}:${JSON.stringify(props)}`;
784
803
  }, buildAngularIslandWrapperMetadata = async (component, islandId, wrapperKey) => {
785
- const { Component, InjectionToken, inject } = await import("@angular/core");
786
- const { NgComponentOutlet } = await import("@angular/common");
787
804
  const deps = await getAngularDeps();
805
+ const { Component, InjectionToken, NgComponentOutlet, inject } = deps;
788
806
  const selector = getAngularIslandSelector(islandId);
789
807
  const propsToken = new InjectionToken(`${wrapperKey}:props`);
790
808
 
@@ -1014,13 +1032,6 @@ init_islands();
1014
1032
 
1015
1033
  // src/client/preserveIslandMarkup.ts
1016
1034
  init_islandMarkupAttributes();
1017
- var getClaimMap = () => {
1018
- if (typeof window === "undefined") {
1019
- return null;
1020
- }
1021
- window.__ABS_CLAIMED_ISLAND_MARKUP__ ??= new Map;
1022
- return window.__ABS_CLAIMED_ISLAND_MARKUP__;
1023
- };
1024
1035
  var getSnapshotMap = () => {
1025
1036
  if (typeof window === "undefined") {
1026
1037
  return null;
@@ -1079,19 +1090,22 @@ var preserveIslandMarkup = (props) => {
1079
1090
  innerHTML: ""
1080
1091
  };
1081
1092
  }
1082
- const claimMap = getClaimMap();
1083
1093
  const snapshotMap = getSnapshotMap();
1084
1094
  const signature = getIslandSignature(props);
1085
- const claimedCount = claimMap?.get(signature) ?? 0;
1086
- const snapshotCandidate = snapshotMap?.get(signature)?.[claimedCount];
1087
- const candidates = Array.from(document.querySelectorAll('[data-island="true"]')).filter((element) => isMatchingIslandElement(element, props));
1088
- const candidate = candidates[claimedCount];
1089
- if (claimMap) {
1090
- claimMap.set(signature, claimedCount + 1);
1095
+ const snapshotCandidate = snapshotMap?.get(signature)?.[0];
1096
+ if (snapshotCandidate) {
1097
+ return snapshotCandidate;
1098
+ }
1099
+ const liveCandidate = Array.from(document.querySelectorAll('[data-island="true"]')).find((element) => isMatchingIslandElement(element, props));
1100
+ if (!liveCandidate) {
1101
+ return {
1102
+ attributes: getIslandMarkerAttributes(props),
1103
+ innerHTML: ""
1104
+ };
1091
1105
  }
1092
1106
  return {
1093
- attributes: snapshotCandidate?.attributes ?? getIslandMarkerAttributes(props),
1094
- innerHTML: snapshotCandidate?.innerHTML ?? candidate?.innerHTML ?? ""
1107
+ attributes: Object.fromEntries(liveCandidate.getAttributeNames().map((name) => [name, liveCandidate.getAttribute(name) ?? ""])),
1108
+ innerHTML: liveCandidate.innerHTML
1095
1109
  };
1096
1110
  };
1097
1111
 
@@ -1242,5 +1256,5 @@ export {
1242
1256
  createIslandManifestResolver
1243
1257
  };
1244
1258
 
1245
- //# debugId=48A5E34EBDE550F464756E2164756E21
1259
+ //# debugId=07B15BB8DBC2C0A764756E2164756E21
1246
1260
  //# sourceMappingURL=index.js.map