@ai-matrx/desktop-protocol 0.1.1 → 0.3.0
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/CHANGELOG.md +37 -0
- package/README.md +7 -1
- package/dist/client.cjs +77 -17
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +31 -3
- package/dist/client.d.ts +31 -3
- package/dist/client.js +77 -17
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +19 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -12
- package/dist/index.d.ts +21 -12
- package/dist/index.js +19 -13
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +28 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +23 -8
- package/dist/react.d.ts +23 -8
- package/dist/react.js +28 -1
- package/dist/react.js.map +1 -1
- package/dist/{registry-DJbrsZ4u.d.cts → registry-DQ5_mP_5.d.cts} +13 -15
- package/dist/{registry-DJbrsZ4u.d.ts → registry-DQ5_mP_5.d.ts} +13 -15
- package/package.json +1 -1
package/dist/client.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BackoffOptions } from '@ai-matrx/realtime';
|
|
2
2
|
export { RECONNECT_ALARM_ATTEMPTS } from '@ai-matrx/realtime';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { W as Welcome, D as DesktopProtocolError, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, C as ClientType } from './registry-
|
|
5
|
-
export { i as isDesktopProtocolError } from './registry-
|
|
4
|
+
import { W as Welcome, D as DesktopProtocolError, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, C as ClientType } from './registry-DQ5_mP_5.cjs';
|
|
5
|
+
export { i as isDesktopProtocolError } from './registry-DQ5_mP_5.cjs';
|
|
6
6
|
import { FrameHeader } from './frame.cjs';
|
|
7
7
|
|
|
8
8
|
/** The subset of the WHATWG WebSocket the client uses — browser, React Native, `ws` and Workers all fit. */
|
|
@@ -167,6 +167,18 @@ interface DesktopClient {
|
|
|
167
167
|
on<E extends EventName>(name: E, handler: EventHandler<E>): () => void;
|
|
168
168
|
/** Hand the relay a fresh token without dropping the socket. */
|
|
169
169
|
reauth(token: string): void;
|
|
170
|
+
/**
|
|
171
|
+
* The app came back to the foreground or the network changed (`visibilitychange` → visible,
|
|
172
|
+
* `pageshow`, `online`). Reconnecting → dial now instead of waiting out the backoff. Open → probe:
|
|
173
|
+
* a ping must be answered within `probeMs` (default 4000) or the socket is treated as dead and
|
|
174
|
+
* redialed at once. A phone resumed from sleep often holds a socket the OS already killed, and two
|
|
175
|
+
* silent heartbeats would cost 50 s. Resource streams reattach with `since_seq` as usual.
|
|
176
|
+
*/
|
|
177
|
+
wake(options?: WakeOptions): void;
|
|
178
|
+
}
|
|
179
|
+
interface WakeOptions {
|
|
180
|
+
/** How long an open socket has to answer the probe ping. Default 4000. */
|
|
181
|
+
probeMs?: number;
|
|
170
182
|
}
|
|
171
183
|
|
|
172
184
|
/**
|
|
@@ -178,4 +190,20 @@ interface DesktopClient {
|
|
|
178
190
|
|
|
179
191
|
declare function createDesktopClient(options: DesktopClientOptions): DesktopClient;
|
|
180
192
|
|
|
181
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Wire a client's wake() to the browser events that mean "the person is back": the page becomes
|
|
195
|
+
* visible again (iOS Safari suspends a background tab's sockets), a back/forward-cache restore
|
|
196
|
+
* (`pageshow` with persisted), and the network returning (`online`). Framework-free; the React
|
|
197
|
+
* binding is `useDesktopWake` in `./react`.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
/** The subset of window/document the binding listens on — injectable for tests and non-DOM hosts. */
|
|
201
|
+
interface WakeTargets {
|
|
202
|
+
window: Pick<Window, "addEventListener" | "removeEventListener">;
|
|
203
|
+
document: Pick<Document, "addEventListener" | "removeEventListener" | "visibilityState">;
|
|
204
|
+
}
|
|
205
|
+
declare function bindDesktopWake(client: Pick<DesktopClient, "wake">, options?: WakeOptions & {
|
|
206
|
+
targets?: WakeTargets;
|
|
207
|
+
}): () => void;
|
|
208
|
+
|
|
209
|
+
export { type ClientTimers, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BackoffOptions } from '@ai-matrx/realtime';
|
|
2
2
|
export { RECONNECT_ALARM_ATTEMPTS } from '@ai-matrx/realtime';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { W as Welcome, D as DesktopProtocolError, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, C as ClientType } from './registry-
|
|
5
|
-
export { i as isDesktopProtocolError } from './registry-
|
|
4
|
+
import { W as Welcome, D as DesktopProtocolError, O as OpName, a as OpParams, b as OpResult, c as OPS, S as StreamMeta, E as EndReason, d as EVENTS, C as ClientType } from './registry-DQ5_mP_5.js';
|
|
5
|
+
export { i as isDesktopProtocolError } from './registry-DQ5_mP_5.js';
|
|
6
6
|
import { FrameHeader } from './frame.js';
|
|
7
7
|
|
|
8
8
|
/** The subset of the WHATWG WebSocket the client uses — browser, React Native, `ws` and Workers all fit. */
|
|
@@ -167,6 +167,18 @@ interface DesktopClient {
|
|
|
167
167
|
on<E extends EventName>(name: E, handler: EventHandler<E>): () => void;
|
|
168
168
|
/** Hand the relay a fresh token without dropping the socket. */
|
|
169
169
|
reauth(token: string): void;
|
|
170
|
+
/**
|
|
171
|
+
* The app came back to the foreground or the network changed (`visibilitychange` → visible,
|
|
172
|
+
* `pageshow`, `online`). Reconnecting → dial now instead of waiting out the backoff. Open → probe:
|
|
173
|
+
* a ping must be answered within `probeMs` (default 4000) or the socket is treated as dead and
|
|
174
|
+
* redialed at once. A phone resumed from sleep often holds a socket the OS already killed, and two
|
|
175
|
+
* silent heartbeats would cost 50 s. Resource streams reattach with `since_seq` as usual.
|
|
176
|
+
*/
|
|
177
|
+
wake(options?: WakeOptions): void;
|
|
178
|
+
}
|
|
179
|
+
interface WakeOptions {
|
|
180
|
+
/** How long an open socket has to answer the probe ping. Default 4000. */
|
|
181
|
+
probeMs?: number;
|
|
170
182
|
}
|
|
171
183
|
|
|
172
184
|
/**
|
|
@@ -178,4 +190,20 @@ interface DesktopClient {
|
|
|
178
190
|
|
|
179
191
|
declare function createDesktopClient(options: DesktopClientOptions): DesktopClient;
|
|
180
192
|
|
|
181
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Wire a client's wake() to the browser events that mean "the person is back": the page becomes
|
|
195
|
+
* visible again (iOS Safari suspends a background tab's sockets), a back/forward-cache restore
|
|
196
|
+
* (`pageshow` with persisted), and the network returning (`online`). Framework-free; the React
|
|
197
|
+
* binding is `useDesktopWake` in `./react`.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
/** The subset of window/document the binding listens on — injectable for tests and non-DOM hosts. */
|
|
201
|
+
interface WakeTargets {
|
|
202
|
+
window: Pick<Window, "addEventListener" | "removeEventListener">;
|
|
203
|
+
document: Pick<Document, "addEventListener" | "removeEventListener" | "visibilityState">;
|
|
204
|
+
}
|
|
205
|
+
declare function bindDesktopWake(client: Pick<DesktopClient, "wake">, options?: WakeOptions & {
|
|
206
|
+
targets?: WakeTargets;
|
|
207
|
+
}): () => void;
|
|
208
|
+
|
|
209
|
+
export { type ClientTimers, type DesktopClient, type DesktopClientDiagnostic, type DesktopClientOptions, type DesktopClientState, type DesktopClientStatus, DesktopProtocolError, type DesktopStream, type EventHandler, type EventName, type EventPayload, OpName, OpParams, OpResult, type RequestOptions, type StreamHandlers, type StreamOpName, type StreamOptions, type WakeOptions, type WakeTargets, type WebSocketFactory, type WebSocketLike, bindDesktopWake, createDesktopClient };
|
package/dist/client.js
CHANGED
|
@@ -95,6 +95,7 @@ import { z as z2 } from "zod";
|
|
|
95
95
|
import { z } from "zod";
|
|
96
96
|
var PROTOCOL_MAJOR = 1;
|
|
97
97
|
var PROTOCOL_MINOR = 0;
|
|
98
|
+
var PROTOCOL_VERSION = `${PROTOCOL_MAJOR}.${PROTOCOL_MINOR}`;
|
|
98
99
|
var ProtocolVersion = z.string().regex(/^[1-9][0-9]{0,2}\.[0-9]{1,3}$/);
|
|
99
100
|
var RequestId = z.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
|
|
100
101
|
var ResourceId = z.string().regex(/^(pty|watch)_[A-Za-z0-9]{16,40}$/);
|
|
@@ -366,12 +367,9 @@ var FsEntry = z6.strictObject({
|
|
|
366
367
|
kind: FsKind,
|
|
367
368
|
size: nonNegInt,
|
|
368
369
|
mtime: z6.number().min(0),
|
|
369
|
-
// seconds, float
|
|
370
|
-
mtime_ms: epochMs,
|
|
370
|
+
// seconds, float
|
|
371
371
|
mode: z6.int().min(0).max(4095),
|
|
372
|
-
target: AbsPath.nullable()
|
|
373
|
-
// symlink target, never followed
|
|
374
|
-
hidden: z6.boolean()
|
|
372
|
+
target: AbsPath.nullable()
|
|
375
373
|
});
|
|
376
374
|
var FsListParams = z6.strictObject({
|
|
377
375
|
path: AbsPath,
|
|
@@ -379,10 +377,12 @@ var FsListParams = z6.strictObject({
|
|
|
379
377
|
depth: z6.int().min(1).max(32).default(1),
|
|
380
378
|
pattern: z6.string().max(256).optional(),
|
|
381
379
|
// glob on name
|
|
382
|
-
limit: z6.int().min(1).max(5e3).default(
|
|
380
|
+
limit: z6.int().min(1).max(5e3).default(1e3),
|
|
383
381
|
page_token: z6.string().max(256).optional(),
|
|
384
|
-
|
|
385
|
-
|
|
382
|
+
// Desktop additions; their defaults ARE the daemon's behaviour: dotfiles listed, siblings in
|
|
383
|
+
// binary (byte) order of name, depth-first.
|
|
384
|
+
show_hidden: z6.boolean().default(true),
|
|
385
|
+
sort: z6.enum(["name", "mtime", "size", "kind"]).default("name")
|
|
386
386
|
});
|
|
387
387
|
var FsListResult = z6.strictObject({
|
|
388
388
|
entries: z6.array(FsEntry),
|
|
@@ -466,7 +466,7 @@ var FsSearchPathsParams = z6.strictObject({
|
|
|
466
466
|
hidden: z6.boolean().default(false),
|
|
467
467
|
max_results: z6.int().min(1).max(5e3).default(100)
|
|
468
468
|
});
|
|
469
|
-
var FsSearchPathsResult = z6.strictObject({ paths: z6.array(
|
|
469
|
+
var FsSearchPathsResult = z6.strictObject({ paths: z6.array(z6.string().min(3).max(4096).regex(/^\.\/[^\\\u0000]+$/)) });
|
|
470
470
|
var FsSearchContentParams = z6.strictObject({
|
|
471
471
|
query: z6.string().min(1).max(1024),
|
|
472
472
|
cwd: AbsPath,
|
|
@@ -479,13 +479,14 @@ var FsSearchContentParams = z6.strictObject({
|
|
|
479
479
|
var FsSearchContentResult = z6.strictObject({
|
|
480
480
|
results: z6.array(
|
|
481
481
|
z6.strictObject({
|
|
482
|
-
path:
|
|
482
|
+
path: z6.string().min(1).max(4096).regex(/^[^/\\\u0000][^\\\u0000]*$/),
|
|
483
483
|
lines: z6.string(),
|
|
484
484
|
line_number: z6.int().min(1),
|
|
485
|
-
submatches: z6.array(
|
|
485
|
+
submatches: z6.array(
|
|
486
|
+
z6.strictObject({ match: z6.strictObject({ text: z6.string() }), start: nonNegInt, end: nonNegInt })
|
|
487
|
+
)
|
|
486
488
|
})
|
|
487
|
-
)
|
|
488
|
-
truncated: z6.boolean()
|
|
489
|
+
)
|
|
489
490
|
});
|
|
490
491
|
var FsChange = z6.strictObject({
|
|
491
492
|
type: z6.enum(["created", "modified", "deleted", "moved"]),
|
|
@@ -732,7 +733,9 @@ function createDesktopClient(options) {
|
|
|
732
733
|
let helloId = null;
|
|
733
734
|
let reconnectTimer = null;
|
|
734
735
|
let heartbeatTimer = null;
|
|
736
|
+
let probeTimer = null;
|
|
735
737
|
let lastHeardAt = 0;
|
|
738
|
+
let heardCount = 0;
|
|
736
739
|
let closedByUser = false;
|
|
737
740
|
const newId = (prefix) => `${prefix}${(++nextId).toString(36)}`;
|
|
738
741
|
function setState(patch) {
|
|
@@ -787,6 +790,7 @@ function createDesktopClient(options) {
|
|
|
787
790
|
ws.onmessage = (event) => {
|
|
788
791
|
if (generation !== socketGeneration) return;
|
|
789
792
|
lastHeardAt = timers.now();
|
|
793
|
+
heardCount++;
|
|
790
794
|
onMessage(event.data);
|
|
791
795
|
};
|
|
792
796
|
ws.onerror = () => {
|
|
@@ -828,6 +832,10 @@ function createDesktopClient(options) {
|
|
|
828
832
|
timers.clearTimeout(heartbeatTimer);
|
|
829
833
|
heartbeatTimer = null;
|
|
830
834
|
}
|
|
835
|
+
if (probeTimer !== null) {
|
|
836
|
+
timers.clearTimeout(probeTimer);
|
|
837
|
+
probeTimer = null;
|
|
838
|
+
}
|
|
831
839
|
const terminal = code === null ? void 0 : TERMINAL_CLOSE.get(code);
|
|
832
840
|
const lost = error ?? (terminal ? new DesktopProtocolError(terminal[0], terminal[1]) : new DesktopProtocolError("DEVICE_OFFLINE", "Connection lost", { retryable: true }));
|
|
833
841
|
for (const [id, p] of pending) {
|
|
@@ -1204,15 +1212,16 @@ function createDesktopClient(options) {
|
|
|
1204
1212
|
});
|
|
1205
1213
|
result.catch(() => void 0);
|
|
1206
1214
|
done.catch(() => void 0);
|
|
1215
|
+
const attach = op === "session.attach" ? params : null;
|
|
1207
1216
|
const s = {
|
|
1208
1217
|
op,
|
|
1209
1218
|
handlers,
|
|
1210
1219
|
options: opts,
|
|
1211
1220
|
id: newId("s"),
|
|
1212
1221
|
sid: null,
|
|
1213
|
-
resourceId: null,
|
|
1214
|
-
lastSeq: 0,
|
|
1215
|
-
expectSeq: 1,
|
|
1222
|
+
resourceId: attach ? attach.resource_id : null,
|
|
1223
|
+
lastSeq: attach?.since_seq ?? 0,
|
|
1224
|
+
expectSeq: attach ? attach.since_seq === void 0 ? null : attach.since_seq + 1 : 1,
|
|
1216
1225
|
windowBytes: opts.windowBytes ?? DEFAULT_WINDOW_BYTES,
|
|
1217
1226
|
consumedUncredited: 0,
|
|
1218
1227
|
sendWindow: DEFAULT_WINDOW_BYTES,
|
|
@@ -1301,6 +1310,34 @@ function createDesktopClient(options) {
|
|
|
1301
1310
|
function reauth(token) {
|
|
1302
1311
|
sendJson({ type: "relay", op: "reauth", token });
|
|
1303
1312
|
}
|
|
1313
|
+
function wake(opts = {}) {
|
|
1314
|
+
if (closedByUser || state.status === "closed") return;
|
|
1315
|
+
if (state.status === "idle" || state.status === "reconnecting") {
|
|
1316
|
+
connect();
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
if (state.status === "connecting" || !socket || probeTimer !== null) return;
|
|
1320
|
+
const generation = socketGeneration;
|
|
1321
|
+
const heardBefore = heardCount;
|
|
1322
|
+
try {
|
|
1323
|
+
socket.send(PING_TEXT);
|
|
1324
|
+
} catch {
|
|
1325
|
+
}
|
|
1326
|
+
probeTimer = timers.setTimeout(() => {
|
|
1327
|
+
probeTimer = null;
|
|
1328
|
+
if (generation !== socketGeneration || !socket) return;
|
|
1329
|
+
if (heardCount > heardBefore) return;
|
|
1330
|
+
const silentMs = timers.now() - lastHeardAt;
|
|
1331
|
+
diagnose({ kind: "heartbeat_timeout", silentMs });
|
|
1332
|
+
const dead = socket;
|
|
1333
|
+
onSocketGone(generation, null, new DesktopProtocolError("TIMEOUT", "Connection went silent", { retryable: true }));
|
|
1334
|
+
try {
|
|
1335
|
+
dead.close(CloseCode.NORMAL, "wake probe timeout");
|
|
1336
|
+
} catch {
|
|
1337
|
+
}
|
|
1338
|
+
if (state.status === "reconnecting") connect();
|
|
1339
|
+
}, opts.probeMs ?? 4e3);
|
|
1340
|
+
}
|
|
1304
1341
|
return {
|
|
1305
1342
|
connect,
|
|
1306
1343
|
close,
|
|
@@ -1315,12 +1352,35 @@ function createDesktopClient(options) {
|
|
|
1315
1352
|
request,
|
|
1316
1353
|
stream,
|
|
1317
1354
|
on,
|
|
1318
|
-
reauth
|
|
1355
|
+
reauth,
|
|
1356
|
+
wake
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// src/client/wake.ts
|
|
1361
|
+
function bindDesktopWake(client, options = {}) {
|
|
1362
|
+
const targets = options.targets ?? (typeof window !== "undefined" && typeof document !== "undefined" ? { window, document } : null);
|
|
1363
|
+
if (!targets) return () => void 0;
|
|
1364
|
+
const wakeOptions = options.probeMs === void 0 ? {} : { probeMs: options.probeMs };
|
|
1365
|
+
const onVisibility = () => {
|
|
1366
|
+
if (targets.document.visibilityState === "visible") client.wake(wakeOptions);
|
|
1367
|
+
};
|
|
1368
|
+
const onWake = () => client.wake(wakeOptions);
|
|
1369
|
+
targets.document.addEventListener("visibilitychange", onVisibility);
|
|
1370
|
+
targets.window.addEventListener("pageshow", onWake);
|
|
1371
|
+
targets.window.addEventListener("online", onWake);
|
|
1372
|
+
targets.window.addEventListener("focus", onWake);
|
|
1373
|
+
return () => {
|
|
1374
|
+
targets.document.removeEventListener("visibilitychange", onVisibility);
|
|
1375
|
+
targets.window.removeEventListener("pageshow", onWake);
|
|
1376
|
+
targets.window.removeEventListener("online", onWake);
|
|
1377
|
+
targets.window.removeEventListener("focus", onWake);
|
|
1319
1378
|
};
|
|
1320
1379
|
}
|
|
1321
1380
|
export {
|
|
1322
1381
|
DesktopProtocolError,
|
|
1323
1382
|
RECONNECT_ALARM_ATTEMPTS,
|
|
1383
|
+
bindDesktopWake,
|
|
1324
1384
|
createDesktopClient,
|
|
1325
1385
|
isDesktopProtocolError
|
|
1326
1386
|
};
|