@linxin666/dsh-remote-web-ui 0.2.7 → 0.2.9
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/LICENSE +202 -28
- package/README.i18n.yaml +2 -2
- package/README.md +14 -7
- package/README.zh.md +3 -2
- package/lib/client.js +40 -8
- package/lib/client.js.map +1 -1
- package/lib/index.js +34 -24
- package/lib/mobile.js +39 -21
- package/lib/mobile.js.map +1 -1
- package/lib/types/client/RemoteEntry.js +3 -3
- package/lib/types/client/UpdateEntry.d.ts.map +1 -1
- package/lib/types/client/UpdateEntry.js +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +28 -14
- package/lib/types/client/pair-api.d.ts +6 -0
- package/lib/types/client/pair-api.d.ts.map +1 -1
- package/lib/types/client/pair-api.js +11 -0
- package/lib/types/client/remote-channel.d.ts +10 -0
- package/lib/types/client/remote-channel.d.ts.map +1 -1
- package/lib/types/client/remote-channel.js +11 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +16 -5
- package/lib/types/mobile/messages.d.ts.map +1 -1
- package/lib/types/mobile/messages.js +5 -3
- package/lib/types/mobile/messages.test.js +20 -0
- package/lib/types/mobile/mux.d.ts +7 -4
- package/lib/types/mobile/mux.d.ts.map +1 -1
- package/lib/types/mobile/mux.js +43 -15
- package/lib/types/mobile/mux.test.js +57 -0
- package/lib/types/remote-api.d.ts +13 -4
- package/lib/types/remote-api.d.ts.map +1 -1
- package/lib/types/remote-api.js +27 -17
- package/lib/types/routes.d.ts +2 -0
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +5 -2
- package/package.json +15 -12
- package/src/client/RemoteEntry.tsx +3 -2
- package/src/client/UpdateEntry.tsx +1 -0
- package/src/client/index.ts +30 -13
- package/src/client/pair-api.ts +16 -0
- package/src/client/remote-channel.ts +21 -0
- package/src/index.ts +16 -5
- package/src/mobile/messages.test.ts +23 -0
- package/src/mobile/messages.ts +5 -3
- package/src/mobile/mux.test.ts +64 -0
- package/src/mobile/mux.ts +44 -17
- package/src/remote-api.ts +34 -17
- package/src/routes.ts +7 -2
package/lib/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import http, { request } from "node:http";
|
|
|
14
14
|
import { connect } from "node:net";
|
|
15
15
|
import { Tunnel, bin, install } from "cloudflared";
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.1-rc.
|
|
17
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-settings@0.1.1-rc.2_@deepseek-ai+cordis@4.0.1_@deepseek-ai+dsh-brand@0_02aaf429ec98c58247037e2222c17a8f/node_modules/@deepseek-ai/dsh-settings/lib/index.js
|
|
18
18
|
/**
|
|
19
19
|
* Structural secret redaction for settings values. `role('secret')` fields are
|
|
20
20
|
* removed from a value before it crosses a wire boundary; a sidecar records
|
|
@@ -975,7 +975,8 @@ var PairingEventsStream = class {
|
|
|
975
975
|
* @returns the exact routes to register on webServer.
|
|
976
976
|
*/
|
|
977
977
|
function makeRoutes(deps) {
|
|
978
|
-
const { service, lanAddresses } = deps;
|
|
978
|
+
const { service, lanAddresses, requirePairingForLan = true } = deps;
|
|
979
|
+
const pairingRequired = () => typeof requirePairingForLan === "function" ? requirePairingForLan() : requirePairingForLan;
|
|
979
980
|
const events = new PairingEventsStream(service);
|
|
980
981
|
/** Loopback-only fence: the desktop panel's control endpoints. */
|
|
981
982
|
const loopbackFence = (req) => isTrustedApiRequest(req, []);
|
|
@@ -1182,14 +1183,16 @@ function makeRoutes(deps) {
|
|
|
1182
1183
|
const paired = deviceId !== void 0 && service.hasDevice(deviceId);
|
|
1183
1184
|
const snapshot = service.snapshot();
|
|
1184
1185
|
const { devices: _devices, ...rest } = snapshot;
|
|
1186
|
+
const visible = paired ? rest : {
|
|
1187
|
+
phase: snapshot.phase,
|
|
1188
|
+
lanAvailable: snapshot.lanAvailable,
|
|
1189
|
+
lanAddresses: snapshot.lanAddresses
|
|
1190
|
+
};
|
|
1185
1191
|
writeJson(res, 200, {
|
|
1186
1192
|
ok: true,
|
|
1187
1193
|
paired,
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
lanAvailable: snapshot.lanAvailable,
|
|
1191
|
-
lanAddresses: snapshot.lanAddresses
|
|
1192
|
-
}
|
|
1194
|
+
requirePairingForLan: pairingRequired(),
|
|
1195
|
+
...visible
|
|
1193
1196
|
});
|
|
1194
1197
|
};
|
|
1195
1198
|
const handleEvents = (req, res) => {
|
|
@@ -1986,17 +1989,19 @@ function loopbackOnlyDenial(innerPath) {
|
|
|
1986
1989
|
}
|
|
1987
1990
|
/**
|
|
1988
1991
|
* Build the remote desktop channel HTTP routes.
|
|
1989
|
-
* @param deps - pairing service + local port.
|
|
1992
|
+
* @param deps - pairing service + local port + live pairing policy.
|
|
1990
1993
|
* @returns the routes to register on webServer.
|
|
1991
1994
|
*/
|
|
1992
1995
|
function makeRemoteApiRoutes(deps) {
|
|
1993
|
-
const { service, port } = deps;
|
|
1996
|
+
const { service, port, requirePairingForLan = true } = deps;
|
|
1994
1997
|
const handler = (req, res) => {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
1998
|
+
if (typeof requirePairingForLan === "function" ? requirePairingForLan() : requirePairingForLan) {
|
|
1999
|
+
const deviceId = readCookie(req.headers.cookie, service.config.cookieName);
|
|
2000
|
+
if (!(deviceId !== void 0 && service.touchDevice(deviceId))) {
|
|
2001
|
+
req.resume();
|
|
2002
|
+
envelopeError(res, 403, "invalid-request", "unpaired", "this device is not paired with the desktop");
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2000
2005
|
}
|
|
2001
2006
|
const method = req.method ?? "GET";
|
|
2002
2007
|
if (!ALLOWED_METHODS.has(method)) {
|
|
@@ -2043,17 +2048,19 @@ function upgradeInnerPath(reqUrl, fallbackPath) {
|
|
|
2043
2048
|
/**
|
|
2044
2049
|
* Build the WebSocket upgrade routes for the event streams and known plugin
|
|
2045
2050
|
* sockets. webServer matches upgrades by exact path.
|
|
2046
|
-
* @param deps - pairing service + local port.
|
|
2051
|
+
* @param deps - pairing service + local port + live pairing policy.
|
|
2047
2052
|
* @returns the upgrade routes to register on webServer.
|
|
2048
2053
|
*/
|
|
2049
2054
|
function makeRemoteApiUpgradeRoutes(deps) {
|
|
2050
|
-
const { service, port } = deps;
|
|
2055
|
+
const { service, port, requirePairingForLan = true } = deps;
|
|
2051
2056
|
const handlerFor = (fallbackPath) => (req, socket, head) => {
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
+
if (typeof requirePairingForLan === "function" ? requirePairingForLan() : requirePairingForLan) {
|
|
2058
|
+
const deviceId = readCookie(req.headers.cookie, service.config.cookieName);
|
|
2059
|
+
if (deviceId === void 0 || !service.touchDevice(deviceId)) {
|
|
2060
|
+
socket.write("HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n");
|
|
2061
|
+
socket.destroy();
|
|
2062
|
+
return;
|
|
2063
|
+
}
|
|
2057
2064
|
}
|
|
2058
2065
|
const inner = upgradeInnerPath(req.url, fallbackPath);
|
|
2059
2066
|
if (loopbackOnlyDenial(inner.split("?")[0] ?? inner) !== void 0) {
|
|
@@ -3184,7 +3191,8 @@ function applyImpl(ctx, config) {
|
|
|
3184
3191
|
const routes = [
|
|
3185
3192
|
...makeRoutes({
|
|
3186
3193
|
service,
|
|
3187
|
-
lanAddresses
|
|
3194
|
+
lanAddresses,
|
|
3195
|
+
requirePairingForLan: () => resolve().requirePairingForLan
|
|
3188
3196
|
}),
|
|
3189
3197
|
...makeMobileRoutes(),
|
|
3190
3198
|
...apiProxy !== void 0 ? makeMobileApiRoutes({
|
|
@@ -3194,13 +3202,15 @@ function applyImpl(ctx, config) {
|
|
|
3194
3202
|
}) : [],
|
|
3195
3203
|
...makeRemoteApiRoutes({
|
|
3196
3204
|
service,
|
|
3197
|
-
port: ctx.webServer.port
|
|
3205
|
+
port: ctx.webServer.port,
|
|
3206
|
+
requirePairingForLan: () => resolve().requirePairingForLan
|
|
3198
3207
|
}),
|
|
3199
3208
|
...updateRoutes
|
|
3200
3209
|
];
|
|
3201
3210
|
const upgrades = makeRemoteApiUpgradeRoutes({
|
|
3202
3211
|
service,
|
|
3203
|
-
port: ctx.webServer.port
|
|
3212
|
+
port: ctx.webServer.port,
|
|
3213
|
+
requirePairingForLan: () => resolve().requirePairingForLan
|
|
3204
3214
|
});
|
|
3205
3215
|
const gate = makeGateListener(service, () => resolve().requirePairingForLan, () => resolve().enabled);
|
|
3206
3216
|
ctx.effect(() => ctx.on("api/gate", gate), "remote-web-ui: api gate");
|
package/lib/mobile.js
CHANGED
|
@@ -11962,7 +11962,7 @@ function superRefine(fn, params) {
|
|
|
11962
11962
|
return /* @__PURE__ */ _superRefine(fn, params);
|
|
11963
11963
|
}
|
|
11964
11964
|
//#endregion
|
|
11965
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
11965
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js
|
|
11966
11966
|
/**
|
|
11967
11967
|
* Message-layer zod schemas: the four wire full forms + error body +
|
|
11968
11968
|
* carrier receipt. The payload slot is unknown in the full-form schemas — business payloads
|
|
@@ -12271,7 +12271,7 @@ union([object({ accepted: literal(true) }), object({
|
|
|
12271
12271
|
reason: union([literal("not-pending"), literal("bad-response")])
|
|
12272
12272
|
})]);
|
|
12273
12273
|
//#endregion
|
|
12274
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
12274
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js
|
|
12275
12275
|
/**
|
|
12276
12276
|
* Return the longest prefix containing at most `maximum` Unicode code points.
|
|
12277
12277
|
* @param value - text to bound.
|
|
@@ -12289,7 +12289,7 @@ function truncateUnicodeCodePoints(value, maximum) {
|
|
|
12289
12289
|
return value;
|
|
12290
12290
|
}
|
|
12291
12291
|
//#endregion
|
|
12292
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
12292
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js
|
|
12293
12293
|
/**
|
|
12294
12294
|
* sessions domain zod schemas (names derived from map keys: sessionListRequestSchema /
|
|
12295
12295
|
* sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide
|
|
@@ -12343,9 +12343,8 @@ object({
|
|
|
12343
12343
|
workspaceId: workspaceIdSchema.optional(),
|
|
12344
12344
|
cwd: string().optional(),
|
|
12345
12345
|
sessionId: sessionIdSchema.optional(),
|
|
12346
|
-
agentPreset: string().optional()
|
|
12347
|
-
|
|
12348
|
-
}).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" }).refine((payload) => payload.reuseWorkspaceBlank !== true || payload.workspaceId !== void 0 && payload.sessionId !== void 0, { message: "session.create reuseWorkspaceBlank requires workspaceId and sessionId" });
|
|
12346
|
+
agentPreset: string().optional()
|
|
12347
|
+
}).refine((payload) => payload.workspaceId === void 0 || payload.cwd === void 0, { message: "session.create accepts workspaceId or cwd, not both" });
|
|
12349
12348
|
object({
|
|
12350
12349
|
sessionId: sessionIdSchema,
|
|
12351
12350
|
agentPreset: string().optional()
|
|
@@ -12527,7 +12526,7 @@ object({ accepted: literal(true) });
|
|
|
12527
12526
|
object({ sessionId: sessionIdSchema });
|
|
12528
12527
|
object({ accepted: literal(true) });
|
|
12529
12528
|
//#endregion
|
|
12530
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
12529
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js
|
|
12531
12530
|
/**
|
|
12532
12531
|
* approvals domain zod schemas (respond is a client-response; the payload schema serves
|
|
12533
12532
|
* the /api/respond endpoint's second parse after routing via the pending table).
|
|
@@ -12561,7 +12560,7 @@ const taskViewSchema = object({
|
|
|
12561
12560
|
finishedAt: number().int().nonnegative().optional()
|
|
12562
12561
|
});
|
|
12563
12562
|
//#endregion
|
|
12564
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
12563
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js
|
|
12565
12564
|
/**
|
|
12566
12565
|
* workspace domain zod schemas (names derived from map keys). The
|
|
12567
12566
|
* WorkspaceId brand cast lives in sessions.schema (see the note there) and
|
|
@@ -12607,7 +12606,7 @@ object({ workspace: workspaceViewSchema });
|
|
|
12607
12606
|
object({ sessionId: sessionIdSchema });
|
|
12608
12607
|
object({ archivedSessionIds: array(sessionIdSchema) });
|
|
12609
12608
|
//#endregion
|
|
12610
|
-
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.
|
|
12609
|
+
//#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.1-rc.2_73bb34f881f3291b26a2607af4c34648/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js
|
|
12611
12610
|
/**
|
|
12612
12611
|
* events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')).
|
|
12613
12612
|
* A frame is the payload slot of the ServerRequest full form; the SessionEvent inside
|
|
@@ -12771,6 +12770,8 @@ function browserSource(url) {
|
|
|
12771
12770
|
}
|
|
12772
12771
|
const DEFAULT_POLL_INTERVAL_MS = 3e3;
|
|
12773
12772
|
const DEFAULT_STALL_THRESHOLD_MS = 12e3;
|
|
12773
|
+
const LIVE_SSE_STALL_MULTIPLIER = 3;
|
|
12774
|
+
const MAX_POLL_BACKOFF_MS = 6e4;
|
|
12774
12775
|
/**
|
|
12775
12776
|
* Stall-check granularity: the single scheduler tick runs at least this
|
|
12776
12777
|
* often so fallback arms within a second of the stall threshold passing,
|
|
@@ -12801,8 +12802,8 @@ var MuxClient = class {
|
|
|
12801
12802
|
lastDataAt = 0;
|
|
12802
12803
|
/**
|
|
12803
12804
|
* Whether the SSE channel has ever delivered a frame in this stream (a
|
|
12804
|
-
* delivered frame proves the tunnel
|
|
12805
|
-
*
|
|
12805
|
+
* delivered frame proves the tunnel can forward SSE; sustained silence may
|
|
12806
|
+
* still mean a suspended mobile tunnel, so polling re-arms after 3 windows).
|
|
12806
12807
|
*/
|
|
12807
12808
|
sseAlive = false;
|
|
12808
12809
|
/** Per-session highest event seq already emitted, for poll dedup. */
|
|
@@ -12812,6 +12813,8 @@ var MuxClient = class {
|
|
|
12812
12813
|
polling = false;
|
|
12813
12814
|
/** Epoch ms of the next due poll while polling (kept on the same tick timer). */
|
|
12814
12815
|
nextPollAt = 0;
|
|
12816
|
+
/** Adaptive delay: productive polls reset it; empty/error polls add one base interval up to one minute. */
|
|
12817
|
+
pollDelayMs;
|
|
12815
12818
|
/**
|
|
12816
12819
|
* @param url - the mobile events endpoint (browser-relative).
|
|
12817
12820
|
* @param options - seams.
|
|
@@ -12821,6 +12824,7 @@ var MuxClient = class {
|
|
|
12821
12824
|
this.sourceFactory = options.sourceFactory ?? browserSource;
|
|
12822
12825
|
this.pollLatest = options.pollLatest ?? ((sessionId) => history(sessionId, void 0, DEFAULT_POLL_PAGE_SIZE));
|
|
12823
12826
|
this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
12827
|
+
this.pollDelayMs = this.pollIntervalMs;
|
|
12824
12828
|
this.stallThresholdMs = options.stallThresholdMs ?? DEFAULT_STALL_THRESHOLD_MS;
|
|
12825
12829
|
this.now = options.now ?? (() => Date.now());
|
|
12826
12830
|
}
|
|
@@ -12858,7 +12862,7 @@ var MuxClient = class {
|
|
|
12858
12862
|
this.stopPolling();
|
|
12859
12863
|
return;
|
|
12860
12864
|
}
|
|
12861
|
-
if (!this.polling && !this.stopped &&
|
|
12865
|
+
if (!this.polling && !this.stopped && this.isSseStalled()) this.startPolling();
|
|
12862
12866
|
}
|
|
12863
12867
|
connect() {
|
|
12864
12868
|
this.sseAlive = false;
|
|
@@ -12900,22 +12904,28 @@ var MuxClient = class {
|
|
|
12900
12904
|
if (this.observeSessionId === void 0) return;
|
|
12901
12905
|
if (this.polling) {
|
|
12902
12906
|
if (this.now() >= this.nextPollAt) {
|
|
12903
|
-
this.nextPollAt =
|
|
12907
|
+
this.nextPollAt = Number.POSITIVE_INFINITY;
|
|
12904
12908
|
this.pollTick();
|
|
12905
12909
|
}
|
|
12906
12910
|
return;
|
|
12907
12911
|
}
|
|
12908
|
-
if (this.
|
|
12909
|
-
|
|
12912
|
+
if (this.isSseStalled()) this.startPolling();
|
|
12913
|
+
}
|
|
12914
|
+
isSseStalled() {
|
|
12915
|
+
const windowMs = this.sseAlive ? this.stallThresholdMs * LIVE_SSE_STALL_MULTIPLIER : this.stallThresholdMs;
|
|
12916
|
+
return this.now() - this.lastDataAt > windowMs;
|
|
12910
12917
|
}
|
|
12911
12918
|
startPolling() {
|
|
12912
12919
|
if (this.polling || this.stopped) return;
|
|
12913
12920
|
this.polling = true;
|
|
12914
|
-
this.
|
|
12921
|
+
this.pollDelayMs = this.pollIntervalMs;
|
|
12922
|
+
this.nextPollAt = Number.POSITIVE_INFINITY;
|
|
12915
12923
|
this.pollTick();
|
|
12916
12924
|
}
|
|
12917
12925
|
stopPolling() {
|
|
12918
12926
|
this.polling = false;
|
|
12927
|
+
this.pollDelayMs = this.pollIntervalMs;
|
|
12928
|
+
this.nextPollAt = 0;
|
|
12919
12929
|
}
|
|
12920
12930
|
/**
|
|
12921
12931
|
* Fetch the latest history page for the observed session and re-emit any
|
|
@@ -12928,14 +12938,19 @@ var MuxClient = class {
|
|
|
12928
12938
|
this.stopPolling();
|
|
12929
12939
|
return;
|
|
12930
12940
|
}
|
|
12941
|
+
let emitted = 0;
|
|
12931
12942
|
try {
|
|
12932
12943
|
const page = await this.pollLatest(sessionId);
|
|
12933
12944
|
let maxSeq = this.pollWatermark.get(sessionId) ?? -1;
|
|
12934
|
-
|
|
12945
|
+
const ordered = [...page.events].sort((left, right) => {
|
|
12946
|
+
return (typeof left.event?.seq === "number" ? left.event.seq : -1) - (typeof right.event?.seq === "number" ? right.event.seq : -1);
|
|
12947
|
+
});
|
|
12948
|
+
for (const entry of ordered) {
|
|
12935
12949
|
const event = entry.event;
|
|
12936
12950
|
const seq = typeof event?.seq === "number" ? event.seq : -1;
|
|
12937
12951
|
if (seq <= maxSeq) continue;
|
|
12938
12952
|
maxSeq = seq;
|
|
12953
|
+
emitted += 1;
|
|
12939
12954
|
this.emit({
|
|
12940
12955
|
type: "session/event",
|
|
12941
12956
|
sessionId,
|
|
@@ -12943,7 +12958,11 @@ var MuxClient = class {
|
|
|
12943
12958
|
});
|
|
12944
12959
|
}
|
|
12945
12960
|
this.pollWatermark.set(sessionId, maxSeq);
|
|
12946
|
-
} catch {}
|
|
12961
|
+
} catch {} finally {
|
|
12962
|
+
if (emitted > 0) this.pollDelayMs = this.pollIntervalMs;
|
|
12963
|
+
else this.pollDelayMs = Math.min(MAX_POLL_BACKOFF_MS, this.pollDelayMs + this.pollIntervalMs);
|
|
12964
|
+
if (this.polling && this.observeSessionId === sessionId) this.nextPollAt = this.now() + this.pollDelayMs;
|
|
12965
|
+
}
|
|
12947
12966
|
}
|
|
12948
12967
|
handleMessage(data) {
|
|
12949
12968
|
if (typeof data !== "string" || data === "") return;
|
|
@@ -13406,7 +13425,6 @@ function applyTurnEnd(state, event) {
|
|
|
13406
13425
|
...message,
|
|
13407
13426
|
...wasPending ? { pending: false } : {},
|
|
13408
13427
|
...failed ? { failed: true } : {},
|
|
13409
|
-
seq: Math.max(message.seq, event.seq),
|
|
13410
13428
|
time: event.time
|
|
13411
13429
|
});
|
|
13412
13430
|
}
|
|
@@ -13475,12 +13493,12 @@ function snapshotOf(state) {
|
|
|
13475
13493
|
for (let index = 1; index < out.length; index += 1) {
|
|
13476
13494
|
const prev = out[index - 1];
|
|
13477
13495
|
const current = out[index];
|
|
13478
|
-
if (prev.seq > current.seq
|
|
13496
|
+
if (prev.seq > current.seq) {
|
|
13479
13497
|
ordered = false;
|
|
13480
13498
|
break;
|
|
13481
13499
|
}
|
|
13482
13500
|
}
|
|
13483
|
-
return ordered ? out : out.sort((a, b) => a.seq - b.seq
|
|
13501
|
+
return ordered ? out : out.sort((a, b) => a.seq - b.seq);
|
|
13484
13502
|
}
|
|
13485
13503
|
//#endregion
|
|
13486
13504
|
//#region src/mobile/markdown.ts
|