@ai-matrx/desktop-protocol 0.5.0 → 0.7.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 +25 -0
- package/dist/client.cjs +47 -13
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +4 -2
- package/dist/client.d.ts +4 -2
- package/dist/client.js +47 -13
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +57 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +57 -2
- package/dist/index.js.map +1 -1
- package/dist/react.d.cts +20 -1
- package/dist/react.d.ts +20 -1
- package/dist/{registry-BeY9D7h0.d.cts → registry-Duc_VFN8.d.cts} +93 -3
- package/dist/{registry-BeY9D7h0.d.ts → registry-Duc_VFN8.d.ts} +93 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
- `CLOSE_RULES` / `closeRule(code)` / `isTerminalClose(code)` (`src/close-policy.ts`): the one table
|
|
6
|
+
of what a dialer does after each close — `reconnect_now`, `reconnect`, `reauth` (one retry with a
|
|
7
|
+
fresh token; a second refusal before any welcome is terminal, outcome `signed_out`), or `stop`
|
|
8
|
+
with an `outcome` (`not_owned` 4003, `removed` 4004, `replaced` 4009, `revoked` 4010,
|
|
9
|
+
`upgrade_required` 4426). A CloseCode without a rule fails to compile; unknown codes reconnect.
|
|
10
|
+
- The client reads that table (its private terminal list is gone) and reports
|
|
11
|
+
`DesktopClientState.outcome` when it stops; 4001/4008 no longer redial forever.
|
|
12
|
+
|
|
13
|
+
Consumer action: never keep a local list of terminal close codes; branch on `closeRule(code)` and
|
|
14
|
+
show `state.outcome`.
|
|
15
|
+
|
|
16
|
+
## 0.6.0
|
|
17
|
+
|
|
18
|
+
- `RelayDeviceStatusEvent.since_ms` is `null` for a device that has never connected (protocol 1.1;
|
|
19
|
+
`NULL_SINCE`): a 1.0 reader is sent `0`, its old meaning (`statusForPeer`).
|
|
20
|
+
- A WebSocket client may announce its minor at connect by also offering
|
|
21
|
+
`versionSubprotocol(PROTOCOL_VERSION)` (e.g. `matrx.v1.1`) beside `SUBPROTOCOL`;
|
|
22
|
+
`announcedVersion(offered)` reads it (servers still answer `SUBPROTOCOL`).
|
|
23
|
+
- The versioning test also refuses a 1.0 field changing type, except a widening to null listed in
|
|
24
|
+
`NULL_SINCE`.
|
|
25
|
+
|
|
26
|
+
Consumer action: treat `since_ms: null` as "never connected"; offer the version subprotocol.
|
|
27
|
+
|
|
3
28
|
## 0.5.0
|
|
4
29
|
|
|
5
30
|
Version skew is the normal state, so a minor protocol addition must never make an older peer
|
package/dist/client.cjs
CHANGED
|
@@ -311,6 +311,29 @@ var CloseCode = {
|
|
|
311
311
|
};
|
|
312
312
|
var CloseCodeValue = import_zod3.z.literal([1e3, 1001, 1006, 1012, 1013, 4001, 4003, 4004, 4008, 4009, 4010, 4400, 4426]);
|
|
313
313
|
|
|
314
|
+
// src/close-policy.ts
|
|
315
|
+
var CLOSE_RULES = {
|
|
316
|
+
[CloseCode.NORMAL]: { action: "reconnect", error: ["DEVICE_OFFLINE", "Connection closed"] },
|
|
317
|
+
[CloseCode.GOING_AWAY]: { action: "reconnect_now", error: ["DEVICE_OFFLINE", "Connection lost"] },
|
|
318
|
+
[CloseCode.ABNORMAL]: { action: "reconnect_now", error: ["DEVICE_OFFLINE", "Connection lost"] },
|
|
319
|
+
[CloseCode.DEVICE_RECONNECTED]: { action: "reconnect_now", error: ["DEVICE_OFFLINE", "Device reconnected"] },
|
|
320
|
+
[CloseCode.TRY_AGAIN_LATER]: { action: "reconnect", error: ["DEVICE_OFFLINE", "Relay busy; retrying"] },
|
|
321
|
+
[CloseCode.AUTH_INVALID]: { action: "reauth", outcome: "signed_out", error: ["AUTH_INVALID", "Sign-in was not accepted"] },
|
|
322
|
+
[CloseCode.AUTH_FORBIDDEN]: { action: "stop", outcome: "not_owned", error: ["AUTH_FORBIDDEN", "Not this device's owner"] },
|
|
323
|
+
[CloseCode.DEVICE_NOT_FOUND]: { action: "stop", outcome: "removed", error: ["NOT_FOUND", "Device not found"] },
|
|
324
|
+
[CloseCode.AUTH_EXPIRED]: { action: "reauth", outcome: "signed_out", error: ["AUTH_EXPIRED", "Sign-in expired"] },
|
|
325
|
+
[CloseCode.REPLACED]: { action: "stop", outcome: "replaced", error: ["CONFLICT", "Replaced by a newer connection"] },
|
|
326
|
+
[CloseCode.DEVICE_REVOKED]: { action: "stop", outcome: "revoked", error: ["AUTH_DEVICE_REVOKED", "This device was revoked"] },
|
|
327
|
+
// A malformed message, or a connection the relay lost track of: a fresh socket starts clean.
|
|
328
|
+
[CloseCode.PROTOCOL_ERROR]: { action: "reconnect", error: ["PROTOCOL_ERROR", "Connection reset by the relay"] },
|
|
329
|
+
[CloseCode.UPGRADE_REQUIRED]: { action: "stop", outcome: "upgrade_required", error: ["PROTOCOL_VERSION_UNSUPPORTED", "Protocol upgrade required"] }
|
|
330
|
+
};
|
|
331
|
+
var UNKNOWN = { action: "reconnect", error: ["DEVICE_OFFLINE", "Connection lost"] };
|
|
332
|
+
function closeRule(code) {
|
|
333
|
+
if (code === null || code === void 0) return CLOSE_RULES[CloseCode.ABNORMAL];
|
|
334
|
+
return CLOSE_RULES[code] ?? UNKNOWN;
|
|
335
|
+
}
|
|
336
|
+
|
|
314
337
|
// src/schema/frame.ts
|
|
315
338
|
var import_zod4 = require("zod");
|
|
316
339
|
var FrameHeader = import_zod4.z.strictObject({
|
|
@@ -646,7 +669,11 @@ var SessionControlChangedEvent = import_zod8.z.strictObject({ controller_client_
|
|
|
646
669
|
var import_zod9 = require("zod");
|
|
647
670
|
var RelayDeviceStatusEvent = import_zod9.z.strictObject({
|
|
648
671
|
online: import_zod9.z.boolean(),
|
|
649
|
-
|
|
672
|
+
/**
|
|
673
|
+
* When the device last went online/offline; null = it has never connected (since 1.1 —
|
|
674
|
+
* NULL_SINCE: a 1.0 reader is sent 0, its old meaning).
|
|
675
|
+
*/
|
|
676
|
+
since_ms: epochMs.nullable(),
|
|
650
677
|
app_version: import_zod9.z.string().max(32).nullable(),
|
|
651
678
|
protocol_version: ProtocolVersion.nullable()
|
|
652
679
|
});
|
|
@@ -728,13 +755,6 @@ var EVENTS = {
|
|
|
728
755
|
|
|
729
756
|
// src/client/client.ts
|
|
730
757
|
var WS_OPEN = 1;
|
|
731
|
-
var TERMINAL_CLOSE = /* @__PURE__ */ new Map([
|
|
732
|
-
[CloseCode.DEVICE_REVOKED, ["AUTH_DEVICE_REVOKED", "This device was revoked"]],
|
|
733
|
-
[CloseCode.AUTH_FORBIDDEN, ["AUTH_FORBIDDEN", "Not this device's owner"]],
|
|
734
|
-
[CloseCode.DEVICE_NOT_FOUND, ["NOT_FOUND", "Device not found"]],
|
|
735
|
-
[CloseCode.REPLACED, ["CONFLICT", "Replaced by a newer connection"]],
|
|
736
|
-
[CloseCode.UPGRADE_REQUIRED, ["PROTOCOL_VERSION_UNSUPPORTED", "Protocol upgrade required"]]
|
|
737
|
-
]);
|
|
738
758
|
var defaultTimers = {
|
|
739
759
|
setTimeout: (fn, ms) => globalThis.setTimeout(fn, ms),
|
|
740
760
|
clearTimeout: (handle) => globalThis.clearTimeout(handle),
|
|
@@ -777,8 +797,10 @@ function createDesktopClient(options) {
|
|
|
777
797
|
attempts: 0,
|
|
778
798
|
retryInMs: null,
|
|
779
799
|
lastError: null,
|
|
780
|
-
lastCloseCode: null
|
|
800
|
+
lastCloseCode: null,
|
|
801
|
+
outcome: null
|
|
781
802
|
};
|
|
803
|
+
let authRefusals = 0;
|
|
782
804
|
const listeners = /* @__PURE__ */ new Set();
|
|
783
805
|
const readyWaiters = /* @__PURE__ */ new Set();
|
|
784
806
|
const pending = /* @__PURE__ */ new Map();
|
|
@@ -813,6 +835,7 @@ function createDesktopClient(options) {
|
|
|
813
835
|
}
|
|
814
836
|
function connect() {
|
|
815
837
|
if (state.status === "connecting" || state.status === "handshaking" || state.status === "open") return;
|
|
838
|
+
if (state.status === "closed" || state.status === "idle") authRefusals = 0;
|
|
816
839
|
closedByUser = false;
|
|
817
840
|
if (reconnectTimer !== null) {
|
|
818
841
|
timers.clearTimeout(reconnectTimer);
|
|
@@ -894,8 +917,11 @@ function createDesktopClient(options) {
|
|
|
894
917
|
timers.clearTimeout(probeTimer);
|
|
895
918
|
probeTimer = null;
|
|
896
919
|
}
|
|
897
|
-
const
|
|
898
|
-
|
|
920
|
+
const rule = code === null ? null : closeRule(code);
|
|
921
|
+
if (rule?.action === "reauth") authRefusals++;
|
|
922
|
+
const stopped = rule !== null && (rule.action === "stop" || rule.action === "reauth" && authRefusals >= 2);
|
|
923
|
+
const terminal = stopped && rule ? rule : void 0;
|
|
924
|
+
const lost = error ?? (terminal ? new DesktopProtocolError(terminal.error[0], terminal.error[1]) : rule && rule.action === "reauth" ? new DesktopProtocolError(rule.error[0], rule.error[1], { retryable: true }) : new DesktopProtocolError("DEVICE_OFFLINE", "Connection lost", { retryable: true }));
|
|
899
925
|
for (const [id, p] of pending) {
|
|
900
926
|
pending.delete(id);
|
|
901
927
|
p.cleanup();
|
|
@@ -912,7 +938,14 @@ function createDesktopClient(options) {
|
|
|
912
938
|
endStream(s, null, lost);
|
|
913
939
|
}
|
|
914
940
|
if (closedByUser || terminal) {
|
|
915
|
-
setState({
|
|
941
|
+
setState({
|
|
942
|
+
status: "closed",
|
|
943
|
+
welcome: null,
|
|
944
|
+
lastError: closedByUser ? state.lastError : lost,
|
|
945
|
+
lastCloseCode: code,
|
|
946
|
+
retryInMs: null,
|
|
947
|
+
outcome: closedByUser ? null : terminal?.outcome ?? null
|
|
948
|
+
});
|
|
916
949
|
rejectReadyWaiters(lost);
|
|
917
950
|
return;
|
|
918
951
|
}
|
|
@@ -1066,7 +1099,8 @@ function createDesktopClient(options) {
|
|
|
1066
1099
|
}
|
|
1067
1100
|
helloId = null;
|
|
1068
1101
|
backoff.markConnected();
|
|
1069
|
-
|
|
1102
|
+
authRefusals = 0;
|
|
1103
|
+
setState({ status: "open", welcome: welcome.data, attempts: 0, retryInMs: null, lastError: null, outcome: null });
|
|
1070
1104
|
for (const w of [...readyWaiters]) {
|
|
1071
1105
|
readyWaiters.delete(w);
|
|
1072
1106
|
w.resolve(welcome.data);
|