@absolutejs/absolute 0.19.0-beta.123 → 0.19.0-beta.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.absolutejs/tsconfig.tsbuildinfo +1 -1
- package/.claude/settings.local.json +4 -1
- package/HTTP2_STATUS.md +81 -0
- package/dist/index.js +31 -235
- package/dist/index.js.map +4 -5
- package/package.json +1 -1
- package/dist/src/dev/http2Bridge.d.ts +0 -3
|
@@ -240,7 +240,10 @@
|
|
|
240
240
|
"Bash(find /home/alexkahn/abs/absolutejs -name *.d.ts -path */node_modules/@types/node/*http2*)",
|
|
241
241
|
"Bash(fuser -k 3001/tcp)",
|
|
242
242
|
"WebFetch(domain:groups.google.com)",
|
|
243
|
-
"WebFetch(domain:developer.chrome.com)"
|
|
243
|
+
"WebFetch(domain:developer.chrome.com)",
|
|
244
|
+
"Bash(~/alex/bun-combined-patch/build/release/bun h2-benchmark.ts 3000)",
|
|
245
|
+
"Bash(~/alex/bun-combined-patch/build/release/bun h2-benchmark.ts 3000 https)",
|
|
246
|
+
"Bash(fuser -k 3000/tcp)"
|
|
244
247
|
]
|
|
245
248
|
}
|
|
246
249
|
}
|
package/HTTP2_STATUS.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# HTTP/2 Dev Server — Status & Roadmap
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Serve dev module fetches (/@src/, vendor, etc.) over HTTP/2 multiplexed connections
|
|
5
|
+
to eliminate the HTTP/1.1 6-connection bottleneck on import-heavy pages.
|
|
6
|
+
|
|
7
|
+
## What's Built & Working
|
|
8
|
+
|
|
9
|
+
### HTTPS / TLS (shipping now)
|
|
10
|
+
- `dev: { https: true }` config option
|
|
11
|
+
- `src/dev/devCert.ts` — mkcert + self-signed cert generation
|
|
12
|
+
- `src/plugins/networking.ts` — Bun.serve with TLS when HTTPS enabled
|
|
13
|
+
- `src/cli/scripts/dev.ts` — passes `ABSOLUTE_HTTPS=true` to server process
|
|
14
|
+
|
|
15
|
+
### HTTP/2 Plumbing (ready, waiting on Bun)
|
|
16
|
+
- `src/core/prepare.ts` — exposes `globalThis.__http2Config` when `dev.https` is enabled
|
|
17
|
+
- `src/plugins/hmr.ts` — skips Elysia `.ws('/hmr')` when `__http2Config` is set (h2 mode handles WS differently)
|
|
18
|
+
- `types/globals.d.ts` — `__http2Config` type declaration
|
|
19
|
+
- `types/build.ts` — `dev.https` config type
|
|
20
|
+
|
|
21
|
+
### RFC 8441 WebSocket over HTTP/2 (tested, not shipping)
|
|
22
|
+
We built and tested WebSocket over HTTP/2 via Extended CONNECT (RFC 8441).
|
|
23
|
+
This runs WebSocket as a multiplexed h2 stream — no separate HTTP/1.1 connection.
|
|
24
|
+
- Browser sends `:method: CONNECT` + `:protocol: websocket` on an h2 stream
|
|
25
|
+
- Server responds `:status: 200`, stream becomes bidirectional WebSocket
|
|
26
|
+
- Minimal WebSocket frame parser/writer handles text messages for HMR
|
|
27
|
+
- Confirmed working with Chrome via Playwright
|
|
28
|
+
|
|
29
|
+
### Bun Patch: enableConnectProtocol (PR-ready)
|
|
30
|
+
**Repo:** `~/alex/bun-http2-patch` (branch: `feat/http2-enable-connect-protocol`)
|
|
31
|
+
|
|
32
|
+
**The bug:** `session.settings({ enableConnectProtocol: true })` is validated in JS
|
|
33
|
+
and the Zig struct has the field, but `loadSettingsFromJSValue()` in
|
|
34
|
+
`src/bun.js/api/bun/h2_frame_parser.zig` silently ignores it. The setting is never
|
|
35
|
+
sent in the SETTINGS frame, so browsers never try Extended CONNECT.
|
|
36
|
+
|
|
37
|
+
**The fix:** 7 lines in `loadSettingsFromJSValue()` following the exact `enablePush` pattern.
|
|
38
|
+
|
|
39
|
+
**Status:** Built, tested, confirmed working. Ready for PR to oven-sh/bun.
|
|
40
|
+
|
|
41
|
+
## What's Blocking
|
|
42
|
+
|
|
43
|
+
### Bun Issue #14672 — HTTP/2 for Bun.serve()
|
|
44
|
+
**This is the critical blocker.** Currently `Bun.serve()` only speaks HTTP/1.1.
|
|
45
|
+
Our JS-level bridge (`node:http2` → `app.fetch()` → `arrayBuffer()` → `stream.end()`)
|
|
46
|
+
works but adds per-request overhead that negates the multiplexing gain at scale:
|
|
47
|
+
|
|
48
|
+
| Metric | HTTP/1.1 (Bun.serve) | HTTP/2 (JS bridge) |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| Resource fetch sum (250 resources) | 21,626ms | **4,310ms** (5x better) |
|
|
51
|
+
| Page load wall time | **~2,800ms** | ~22,000ms (8x worse) |
|
|
52
|
+
|
|
53
|
+
The h2 multiplexing works (5x faster aggregate fetch), but the JS bridge overhead
|
|
54
|
+
per-request makes overall load 8x slower than Bun.serve's native Zig path.
|
|
55
|
+
|
|
56
|
+
**Track:** https://github.com/oven-sh/bun/issues/14672
|
|
57
|
+
|
|
58
|
+
### Bun Issue #26721 — allowHTTP1 broken on node:http2
|
|
59
|
+
`allowHTTP1: true` doesn't advertise `http/1.1` in ALPN, so HTTP/1.1 fallback
|
|
60
|
+
for WebSocket upgrade never works. Our RFC 8441 approach bypasses this entirely,
|
|
61
|
+
but it's relevant if someone wants the traditional `ws` upgrade path.
|
|
62
|
+
|
|
63
|
+
**Track:** https://github.com/oven-sh/bun/issues/26721
|
|
64
|
+
|
|
65
|
+
### Bun Quirk — listen(port, hostname) breaks ALPN
|
|
66
|
+
Passing a hostname to `server.listen(port, hostname)` on a `node:http2` server
|
|
67
|
+
causes ALPN negotiation to fail. `server.listen(port)` works fine.
|
|
68
|
+
Not filed as an issue yet.
|
|
69
|
+
|
|
70
|
+
## When Bun.serve Gets HTTP/2
|
|
71
|
+
|
|
72
|
+
Once #14672 lands, the path to enable HTTP/2 is:
|
|
73
|
+
|
|
74
|
+
1. **networking.ts** — pass h2 option to `app.listen()` / `Bun.serve()` config
|
|
75
|
+
2. **hmr.ts** — the `__http2Config` check already skips `.ws()` in h2 mode
|
|
76
|
+
3. **WebSocket** — use RFC 8441 Extended CONNECT (requires enableConnectProtocol patch or Bun fixing it natively)
|
|
77
|
+
4. Remove the `__http2Config` bridge pattern if Bun.serve handles h2 + WS natively
|
|
78
|
+
|
|
79
|
+
## Combined Patch Build
|
|
80
|
+
**Repo:** `~/alex/bun-combined-patch` (both reactFastRefresh + enableConnectProtocol)
|
|
81
|
+
**Script:** `scripts/use-combined-bun.sh`
|
package/dist/index.js
CHANGED
|
@@ -205047,188 +205047,6 @@ var init_hmr = __esm(() => {
|
|
|
205047
205047
|
init_webSocket();
|
|
205048
205048
|
});
|
|
205049
205049
|
|
|
205050
|
-
// src/dev/http2Bridge.ts
|
|
205051
|
-
var exports_http2Bridge = {};
|
|
205052
|
-
__export(exports_http2Bridge, {
|
|
205053
|
-
bridgeHttp2Stream: () => bridgeHttp2Stream
|
|
205054
|
-
});
|
|
205055
|
-
var WS_OPCODE_TEXT = 1, WS_OPCODE_CLOSE = 8, WS_OPCODE_PING = 9, WS_OPCODE_PONG = 10, parseWsFrame = (buf) => {
|
|
205056
|
-
if (buf.length < 2)
|
|
205057
|
-
return null;
|
|
205058
|
-
const byte0 = buf[0];
|
|
205059
|
-
const byte1 = buf[1];
|
|
205060
|
-
const opcode = byte0 & 15;
|
|
205061
|
-
const masked = (byte1 & 128) !== 0;
|
|
205062
|
-
let payloadLen = byte1 & 127;
|
|
205063
|
-
let offset = 2;
|
|
205064
|
-
if (payloadLen === 126) {
|
|
205065
|
-
if (buf.length < 4)
|
|
205066
|
-
return null;
|
|
205067
|
-
payloadLen = buf.readUInt16BE(2);
|
|
205068
|
-
offset = 4;
|
|
205069
|
-
} else if (payloadLen === 127) {
|
|
205070
|
-
if (buf.length < 10)
|
|
205071
|
-
return null;
|
|
205072
|
-
payloadLen = Number(buf.readBigUInt64BE(2));
|
|
205073
|
-
offset = 10;
|
|
205074
|
-
}
|
|
205075
|
-
if (masked) {
|
|
205076
|
-
if (buf.length < offset + 4 + payloadLen)
|
|
205077
|
-
return null;
|
|
205078
|
-
const maskKey = buf.subarray(offset, offset + 4);
|
|
205079
|
-
offset += 4;
|
|
205080
|
-
const payload = Buffer.allocUnsafe(payloadLen);
|
|
205081
|
-
for (let i = 0;i < payloadLen; i++) {
|
|
205082
|
-
payload[i] = buf[offset + i] ^ maskKey[i & 3];
|
|
205083
|
-
}
|
|
205084
|
-
return { opcode, payload, totalLen: offset + payloadLen };
|
|
205085
|
-
}
|
|
205086
|
-
if (buf.length < offset + payloadLen)
|
|
205087
|
-
return null;
|
|
205088
|
-
return {
|
|
205089
|
-
opcode,
|
|
205090
|
-
payload: buf.subarray(offset, offset + payloadLen),
|
|
205091
|
-
totalLen: offset + payloadLen
|
|
205092
|
-
};
|
|
205093
|
-
}, writeWsFrame = (opcode, payload) => {
|
|
205094
|
-
const len = payload.length;
|
|
205095
|
-
let header;
|
|
205096
|
-
if (len < 126) {
|
|
205097
|
-
header = Buffer.allocUnsafe(2);
|
|
205098
|
-
header[0] = 128 | opcode;
|
|
205099
|
-
header[1] = len;
|
|
205100
|
-
} else if (len < 65536) {
|
|
205101
|
-
header = Buffer.allocUnsafe(4);
|
|
205102
|
-
header[0] = 128 | opcode;
|
|
205103
|
-
header[1] = 126;
|
|
205104
|
-
header.writeUInt16BE(len, 2);
|
|
205105
|
-
} else {
|
|
205106
|
-
header = Buffer.allocUnsafe(10);
|
|
205107
|
-
header[0] = 128 | opcode;
|
|
205108
|
-
header[1] = 127;
|
|
205109
|
-
header.writeBigUInt64BE(BigInt(len), 2);
|
|
205110
|
-
}
|
|
205111
|
-
return Buffer.concat([header, payload]);
|
|
205112
|
-
}, createHttp2WebSocket = (stream) => {
|
|
205113
|
-
let state = WS_READY_STATE_OPEN;
|
|
205114
|
-
let buffer = Buffer.alloc(0);
|
|
205115
|
-
let onMessage = null;
|
|
205116
|
-
let onClose = null;
|
|
205117
|
-
stream.on("data", (chunk) => {
|
|
205118
|
-
buffer = Buffer.concat([buffer, chunk]);
|
|
205119
|
-
while (buffer.length > 0) {
|
|
205120
|
-
const frame = parseWsFrame(buffer);
|
|
205121
|
-
if (!frame)
|
|
205122
|
-
break;
|
|
205123
|
-
buffer = buffer.subarray(frame.totalLen);
|
|
205124
|
-
if (frame.opcode === WS_OPCODE_TEXT && onMessage) {
|
|
205125
|
-
onMessage(frame.payload.toString("utf-8"));
|
|
205126
|
-
} else if (frame.opcode === WS_OPCODE_PING) {
|
|
205127
|
-
if (!stream.destroyed) {
|
|
205128
|
-
stream.write(writeWsFrame(WS_OPCODE_PONG, frame.payload));
|
|
205129
|
-
}
|
|
205130
|
-
} else if (frame.opcode === WS_OPCODE_CLOSE) {
|
|
205131
|
-
if (!stream.destroyed) {
|
|
205132
|
-
stream.write(writeWsFrame(WS_OPCODE_CLOSE, Buffer.alloc(0)));
|
|
205133
|
-
stream.end();
|
|
205134
|
-
}
|
|
205135
|
-
state = 3;
|
|
205136
|
-
if (onClose)
|
|
205137
|
-
onClose();
|
|
205138
|
-
}
|
|
205139
|
-
}
|
|
205140
|
-
});
|
|
205141
|
-
stream.on("close", () => {
|
|
205142
|
-
if (state === WS_READY_STATE_OPEN) {
|
|
205143
|
-
state = 3;
|
|
205144
|
-
if (onClose)
|
|
205145
|
-
onClose();
|
|
205146
|
-
}
|
|
205147
|
-
});
|
|
205148
|
-
stream.on("error", () => {
|
|
205149
|
-
state = 3;
|
|
205150
|
-
});
|
|
205151
|
-
const ws = {
|
|
205152
|
-
get readyState() {
|
|
205153
|
-
return state;
|
|
205154
|
-
},
|
|
205155
|
-
send(data) {
|
|
205156
|
-
if (state !== WS_READY_STATE_OPEN || stream.destroyed)
|
|
205157
|
-
return;
|
|
205158
|
-
stream.write(writeWsFrame(WS_OPCODE_TEXT, Buffer.from(data)));
|
|
205159
|
-
},
|
|
205160
|
-
close() {
|
|
205161
|
-
if (state !== WS_READY_STATE_OPEN || stream.destroyed)
|
|
205162
|
-
return;
|
|
205163
|
-
stream.write(writeWsFrame(WS_OPCODE_CLOSE, Buffer.alloc(0)));
|
|
205164
|
-
stream.end();
|
|
205165
|
-
state = 2;
|
|
205166
|
-
},
|
|
205167
|
-
onMessage: null,
|
|
205168
|
-
onClose: null
|
|
205169
|
-
};
|
|
205170
|
-
onMessage = (data) => ws.onMessage?.(data);
|
|
205171
|
-
onClose = () => ws.onClose?.();
|
|
205172
|
-
return ws;
|
|
205173
|
-
}, bridgeHttp2Stream = async (stream, headers, fetchHandler, hmrState2, manifest) => {
|
|
205174
|
-
const method = headers[":method"] ?? "GET";
|
|
205175
|
-
const path = headers[":path"] ?? "/";
|
|
205176
|
-
if (method === "CONNECT" && headers[":protocol"] === "websocket" && hmrState2 && manifest) {
|
|
205177
|
-
stream.respond({ ":status": 200 });
|
|
205178
|
-
const ws = createHttp2WebSocket(stream);
|
|
205179
|
-
ws.onMessage = (data) => handleHMRMessage(hmrState2, ws, data);
|
|
205180
|
-
ws.onClose = () => handleClientDisconnect(hmrState2, ws);
|
|
205181
|
-
handleClientConnect(hmrState2, ws, manifest);
|
|
205182
|
-
return;
|
|
205183
|
-
}
|
|
205184
|
-
const authority = headers[":authority"] ?? "localhost";
|
|
205185
|
-
const scheme = headers[":scheme"] ?? "https";
|
|
205186
|
-
const url = `${scheme}://${authority}${path}`;
|
|
205187
|
-
const requestHeaders = new Headers;
|
|
205188
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
205189
|
-
if (key.startsWith(":") || value === undefined)
|
|
205190
|
-
continue;
|
|
205191
|
-
const headerValue = Array.isArray(value) ? value.join(", ") : value;
|
|
205192
|
-
requestHeaders.set(key, headerValue);
|
|
205193
|
-
}
|
|
205194
|
-
const hasBody = method !== "GET" && method !== "HEAD";
|
|
205195
|
-
const bodyBlob = hasBody ? await new Promise((resolve24) => {
|
|
205196
|
-
const chunks = [];
|
|
205197
|
-
stream.on("data", (chunk) => chunks.push(chunk));
|
|
205198
|
-
stream.on("end", () => {
|
|
205199
|
-
resolve24(new Blob([Buffer.concat(chunks)]));
|
|
205200
|
-
});
|
|
205201
|
-
}) : null;
|
|
205202
|
-
const request = new Request(url, {
|
|
205203
|
-
body: bodyBlob,
|
|
205204
|
-
headers: requestHeaders,
|
|
205205
|
-
method
|
|
205206
|
-
});
|
|
205207
|
-
try {
|
|
205208
|
-
const response = await fetchHandler(request);
|
|
205209
|
-
const responseHeaders = {
|
|
205210
|
-
":status": response.status
|
|
205211
|
-
};
|
|
205212
|
-
response.headers.forEach((value, key) => {
|
|
205213
|
-
responseHeaders[key] = value;
|
|
205214
|
-
});
|
|
205215
|
-
if (!response.body) {
|
|
205216
|
-
stream.respond(responseHeaders);
|
|
205217
|
-
stream.end();
|
|
205218
|
-
return;
|
|
205219
|
-
}
|
|
205220
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
205221
|
-
stream.respond(responseHeaders);
|
|
205222
|
-
stream.end(Buffer.from(arrayBuffer));
|
|
205223
|
-
} catch {
|
|
205224
|
-
stream.respond({ ":status": 500, "content-type": "text/plain" });
|
|
205225
|
-
stream.end("Internal Server Error");
|
|
205226
|
-
}
|
|
205227
|
-
};
|
|
205228
|
-
var init_http2Bridge = __esm(() => {
|
|
205229
|
-
init_webSocket();
|
|
205230
|
-
});
|
|
205231
|
-
|
|
205232
205050
|
// src/dev/devCert.ts
|
|
205233
205051
|
var exports_devCert = {};
|
|
205234
205052
|
__export(exports_devCert, {
|
|
@@ -205612,8 +205430,6 @@ var pageRouterPlugin = () => {
|
|
|
205612
205430
|
};
|
|
205613
205431
|
// src/plugins/networking.ts
|
|
205614
205432
|
init_constants();
|
|
205615
|
-
import { readFileSync as readFileSync12 } from "fs";
|
|
205616
|
-
import { join as join18 } from "path";
|
|
205617
205433
|
import { argv } from "process";
|
|
205618
205434
|
var {env: env3 } = globalThis.Bun;
|
|
205619
205435
|
|
|
@@ -205646,65 +205462,45 @@ if (hostFlag) {
|
|
|
205646
205462
|
localIP = getLocalIPAddress();
|
|
205647
205463
|
host = "0.0.0.0";
|
|
205648
205464
|
}
|
|
205649
|
-
var
|
|
205650
|
-
|
|
205651
|
-
|
|
205465
|
+
var tls = (() => {
|
|
205466
|
+
if (env3.NODE_ENV !== "development")
|
|
205467
|
+
return;
|
|
205468
|
+
if (env3.ABSOLUTE_HTTPS !== "true")
|
|
205469
|
+
return;
|
|
205470
|
+
try {
|
|
205471
|
+
const { loadDevCert: loadDevCert2 } = (init_devCert(), __toCommonJS(exports_devCert));
|
|
205472
|
+
return loadDevCert2();
|
|
205473
|
+
} catch {
|
|
205474
|
+
return;
|
|
205475
|
+
}
|
|
205476
|
+
})();
|
|
205477
|
+
var protocol = tls ? "https" : "http";
|
|
205478
|
+
var networking = (app) => app.listen({
|
|
205479
|
+
hostname: host,
|
|
205480
|
+
port,
|
|
205481
|
+
...tls ? {
|
|
205482
|
+
tls: {
|
|
205483
|
+
cert: tls.cert,
|
|
205484
|
+
key: tls.key
|
|
205485
|
+
}
|
|
205486
|
+
} : {}
|
|
205487
|
+
}, () => {
|
|
205652
205488
|
const isHotReload = Boolean(globalThis.__hmrServerStartup);
|
|
205653
205489
|
globalThis.__hmrServerStartup = true;
|
|
205654
|
-
if (isHotReload)
|
|
205490
|
+
if (isHotReload) {
|
|
205655
205491
|
return;
|
|
205492
|
+
}
|
|
205493
|
+
const buildDuration = globalThis.__hmrBuildDuration ?? Number(env3.ABSOLUTE_BUILD_DURATION || 0);
|
|
205494
|
+
const version = globalThis.__absoluteVersion || env3.ABSOLUTE_VERSION || "";
|
|
205656
205495
|
startupBanner({
|
|
205657
|
-
duration:
|
|
205496
|
+
duration: buildDuration,
|
|
205658
205497
|
host,
|
|
205659
205498
|
networkUrl: hostFlag ? `${protocol}://${localIP}:${port}/` : undefined,
|
|
205660
205499
|
port,
|
|
205661
205500
|
protocol,
|
|
205662
|
-
version
|
|
205501
|
+
version
|
|
205663
205502
|
});
|
|
205664
|
-
};
|
|
205665
|
-
var networking = (app) => {
|
|
205666
|
-
if (isHttpsDev) {
|
|
205667
|
-
const certDir = join18(process.cwd(), ".absolutejs");
|
|
205668
|
-
const cert = readFileSync12(join18(certDir, "cert.pem"), "utf-8");
|
|
205669
|
-
const key = readFileSync12(join18(certDir, "key.pem"), "utf-8");
|
|
205670
|
-
app.compile();
|
|
205671
|
-
const http2 = __require("http2");
|
|
205672
|
-
const server2 = http2.createSecureServer({
|
|
205673
|
-
cert,
|
|
205674
|
-
key,
|
|
205675
|
-
settings: { enableConnectProtocol: true }
|
|
205676
|
-
});
|
|
205677
|
-
server2.on("session", (session) => {
|
|
205678
|
-
session.settings({ enableConnectProtocol: true });
|
|
205679
|
-
});
|
|
205680
|
-
const { bridgeHttp2Stream: bridgeHttp2Stream2 } = (init_http2Bridge(), __toCommonJS(exports_http2Bridge));
|
|
205681
|
-
const http2Config = globalThis.__http2Config;
|
|
205682
|
-
server2.on("stream", (stream, headers) => {
|
|
205683
|
-
bridgeHttp2Stream2(stream, headers, app.fetch.bind(app), http2Config?.hmrState, http2Config?.manifest);
|
|
205684
|
-
});
|
|
205685
|
-
server2.listen(Number(port), () => {
|
|
205686
|
-
showBanner();
|
|
205687
|
-
});
|
|
205688
|
-
return app;
|
|
205689
|
-
}
|
|
205690
|
-
const tls = (() => {
|
|
205691
|
-
if (!isHttpsDev)
|
|
205692
|
-
return;
|
|
205693
|
-
try {
|
|
205694
|
-
const { loadDevCert: loadDevCert2 } = (init_devCert(), __toCommonJS(exports_devCert));
|
|
205695
|
-
return loadDevCert2();
|
|
205696
|
-
} catch {
|
|
205697
|
-
return;
|
|
205698
|
-
}
|
|
205699
|
-
})();
|
|
205700
|
-
return app.listen({
|
|
205701
|
-
hostname: host,
|
|
205702
|
-
port,
|
|
205703
|
-
...tls ? { tls: { cert: tls.cert, key: tls.key } } : {}
|
|
205704
|
-
}, () => {
|
|
205705
|
-
showBanner();
|
|
205706
|
-
});
|
|
205707
|
-
};
|
|
205503
|
+
});
|
|
205708
205504
|
// src/utils/defineConfig.ts
|
|
205709
205505
|
var defineConfig = (config) => config;
|
|
205710
205506
|
// src/utils/generateHeadElement.ts
|
|
@@ -205804,5 +205600,5 @@ export {
|
|
|
205804
205600
|
ANGULAR_INIT_TIMEOUT_MS
|
|
205805
205601
|
};
|
|
205806
205602
|
|
|
205807
|
-
//# debugId=
|
|
205603
|
+
//# debugId=E99B445C59288BB764756E2164756E21
|
|
205808
205604
|
//# sourceMappingURL=index.js.map
|