@sidebandchat/client 0.0.0-stage → 0.1.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/COPYRIGHT +8 -0
- package/LICENSE +674 -0
- package/README.md +121 -2
- package/dist/activity/activity-sharing-controller.d.ts +131 -0
- package/dist/activity/activity-sharing-controller.d.ts.map +1 -0
- package/dist/activity/activity-sharing-controller.js +351 -0
- package/dist/activity/activity-sharing-controller.js.map +1 -0
- package/dist/activity/index.d.ts +2 -0
- package/dist/activity/index.d.ts.map +1 -0
- package/dist/activity/index.js +2 -0
- package/dist/activity/index.js.map +1 -0
- package/dist/attachments/attachment-client.d.ts +36 -0
- package/dist/attachments/attachment-client.d.ts.map +1 -0
- package/dist/attachments/attachment-client.js +98 -0
- package/dist/attachments/attachment-client.js.map +1 -0
- package/dist/attachments/draft-attachment.d.ts +17 -0
- package/dist/attachments/draft-attachment.d.ts.map +1 -0
- package/dist/attachments/draft-attachment.js +2 -0
- package/dist/attachments/draft-attachment.js.map +1 -0
- package/dist/auth/identity-client.d.ts +64 -0
- package/dist/auth/identity-client.d.ts.map +1 -0
- package/dist/auth/identity-client.js +65 -0
- package/dist/auth/identity-client.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/badges/badge-verifier.d.ts +11 -0
- package/dist/badges/badge-verifier.d.ts.map +1 -0
- package/dist/badges/badge-verifier.js +128 -0
- package/dist/badges/badge-verifier.js.map +1 -0
- package/dist/calls/calls-client.d.ts +16 -0
- package/dist/calls/calls-client.d.ts.map +1 -0
- package/dist/calls/calls-client.js +55 -0
- package/dist/calls/calls-client.js.map +1 -0
- package/dist/calls/index.d.ts +3 -0
- package/dist/calls/index.d.ts.map +1 -0
- package/dist/calls/index.js +2 -0
- package/dist/calls/index.js.map +1 -0
- package/dist/calls/media-controls.d.ts +38 -0
- package/dist/calls/media-controls.d.ts.map +1 -0
- package/dist/calls/media-controls.js +134 -0
- package/dist/calls/media-controls.js.map +1 -0
- package/dist/calls/media-presentation-controller.d.ts +39 -0
- package/dist/calls/media-presentation-controller.d.ts.map +1 -0
- package/dist/calls/media-presentation-controller.js +106 -0
- package/dist/calls/media-presentation-controller.js.map +1 -0
- package/dist/calls/media-types.d.ts +37 -0
- package/dist/calls/media-types.d.ts.map +1 -0
- package/dist/calls/media-types.js +2 -0
- package/dist/calls/media-types.js.map +1 -0
- package/dist/calls/media.d.ts +39 -0
- package/dist/calls/media.d.ts.map +1 -0
- package/dist/calls/media.js +501 -0
- package/dist/calls/media.js.map +1 -0
- package/dist/client/ephemeral-state.d.ts +52 -0
- package/dist/client/ephemeral-state.d.ts.map +1 -0
- package/dist/client/ephemeral-state.js +371 -0
- package/dist/client/ephemeral-state.js.map +1 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/live-event-controller.d.ts +14 -0
- package/dist/client/live-event-controller.d.ts.map +1 -0
- package/dist/client/live-event-controller.js +28 -0
- package/dist/client/live-event-controller.js.map +1 -0
- package/dist/client/platform-adapters.d.ts +122 -0
- package/dist/client/platform-adapters.d.ts.map +1 -0
- package/dist/client/platform-adapters.js +2 -0
- package/dist/client/platform-adapters.js.map +1 -0
- package/dist/client/session-runtime.d.ts +115 -0
- package/dist/client/session-runtime.d.ts.map +1 -0
- package/dist/client/session-runtime.js +607 -0
- package/dist/client/session-runtime.js.map +1 -0
- package/dist/client/sideband-client.d.ts +141 -0
- package/dist/client/sideband-client.d.ts.map +1 -0
- package/dist/client/sideband-client.js +575 -0
- package/dist/client/sideband-client.js.map +1 -0
- package/dist/client/snapshot-client.d.ts +9 -0
- package/dist/client/snapshot-client.d.ts.map +1 -0
- package/dist/client/snapshot-client.js +18 -0
- package/dist/client/snapshot-client.js.map +1 -0
- package/dist/client/state.d.ts +112 -0
- package/dist/client/state.d.ts.map +1 -0
- package/dist/client/state.js +992 -0
- package/dist/client/state.js.map +1 -0
- package/dist/communities/community-client.d.ts +40 -0
- package/dist/communities/community-client.d.ts.map +1 -0
- package/dist/communities/community-client.js +166 -0
- package/dist/communities/community-client.js.map +1 -0
- package/dist/conversations/index.d.ts +2 -0
- package/dist/conversations/index.d.ts.map +1 -0
- package/dist/conversations/index.js +2 -0
- package/dist/conversations/index.js.map +1 -0
- package/dist/conversations/mentions.d.ts +18 -0
- package/dist/conversations/mentions.d.ts.map +1 -0
- package/dist/conversations/mentions.js +108 -0
- package/dist/conversations/mentions.js.map +1 -0
- package/dist/conversations/messaging-client.d.ts +56 -0
- package/dist/conversations/messaging-client.d.ts.map +1 -0
- package/dist/conversations/messaging-client.js +333 -0
- package/dist/conversations/messaging-client.js.map +1 -0
- package/dist/conversations/replies-controller.d.ts +50 -0
- package/dist/conversations/replies-controller.d.ts.map +1 -0
- package/dist/conversations/replies-controller.js +206 -0
- package/dist/conversations/replies-controller.js.map +1 -0
- package/dist/devices/device-client.d.ts +11 -0
- package/dist/devices/device-client.d.ts.map +1 -0
- package/dist/devices/device-client.js +27 -0
- package/dist/devices/device-client.js.map +1 -0
- package/dist/domain.d.ts +528 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +13 -0
- package/dist/domain.js.map +1 -0
- package/dist/entity-id.d.ts +32 -0
- package/dist/entity-id.d.ts.map +1 -0
- package/dist/entity-id.js +17 -0
- package/dist/entity-id.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/instance/index.d.ts +5 -0
- package/dist/instance/index.d.ts.map +1 -0
- package/dist/instance/index.js +3 -0
- package/dist/instance/index.js.map +1 -0
- package/dist/instance/instance-policy.d.ts +13 -0
- package/dist/instance/instance-policy.d.ts.map +1 -0
- package/dist/instance/instance-policy.js +2 -0
- package/dist/instance/instance-policy.js.map +1 -0
- package/dist/instance-access.d.ts +66 -0
- package/dist/instance-access.d.ts.map +1 -0
- package/dist/instance-access.js +84 -0
- package/dist/instance-access.js.map +1 -0
- package/dist/instance-capabilities.d.ts +12 -0
- package/dist/instance-capabilities.d.ts.map +1 -0
- package/dist/instance-capabilities.js +2 -0
- package/dist/instance-capabilities.js.map +1 -0
- package/dist/instance-endpoint.d.ts +32 -0
- package/dist/instance-endpoint.d.ts.map +1 -0
- package/dist/instance-endpoint.js +147 -0
- package/dist/instance-endpoint.js.map +1 -0
- package/dist/model/index.d.ts +3 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +3 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/selectors.d.ts +22 -0
- package/dist/model/selectors.d.ts.map +1 -0
- package/dist/model/selectors.js +73 -0
- package/dist/model/selectors.js.map +1 -0
- package/dist/private-conversation/file-hash.d.ts +2 -0
- package/dist/private-conversation/file-hash.d.ts.map +1 -0
- package/dist/private-conversation/file-hash.js +13 -0
- package/dist/private-conversation/file-hash.js.map +1 -0
- package/dist/private-conversation/private-conversation-crypto.d.ts +48 -0
- package/dist/private-conversation/private-conversation-crypto.d.ts.map +1 -0
- package/dist/private-conversation/private-conversation-crypto.js +169 -0
- package/dist/private-conversation/private-conversation-crypto.js.map +1 -0
- package/dist/private-conversation/private-conversations-client.d.ts +23 -0
- package/dist/private-conversation/private-conversations-client.d.ts.map +1 -0
- package/dist/private-conversation/private-conversations-client.js +77 -0
- package/dist/private-conversation/private-conversations-client.js.map +1 -0
- package/dist/private-conversation/private-transfer-limits.d.ts +9 -0
- package/dist/private-conversation/private-transfer-limits.d.ts.map +1 -0
- package/dist/private-conversation/private-transfer-limits.js +9 -0
- package/dist/private-conversation/private-transfer-limits.js.map +1 -0
- package/dist/private-conversation/private-transfer-protocol.d.ts +53 -0
- package/dist/private-conversation/private-transfer-protocol.d.ts.map +1 -0
- package/dist/private-conversation/private-transfer-protocol.js +184 -0
- package/dist/private-conversation/private-transfer-protocol.js.map +1 -0
- package/dist/private-conversation/private-transfer-transport.d.ts +22 -0
- package/dist/private-conversation/private-transfer-transport.d.ts.map +1 -0
- package/dist/private-conversation/private-transfer-transport.js +94 -0
- package/dist/private-conversation/private-transfer-transport.js.map +1 -0
- package/dist/realtime/realtime-client.d.ts +31 -0
- package/dist/realtime/realtime-client.d.ts.map +1 -0
- package/dist/realtime/realtime-client.js +103 -0
- package/dist/realtime/realtime-client.js.map +1 -0
- package/dist/sbp/codec.d.ts +33 -0
- package/dist/sbp/codec.d.ts.map +1 -0
- package/dist/sbp/codec.js +93 -0
- package/dist/sbp/codec.js.map +1 -0
- package/dist/sbp/command-transport.d.ts +9 -0
- package/dist/sbp/command-transport.d.ts.map +1 -0
- package/dist/sbp/command-transport.js +2 -0
- package/dist/sbp/command-transport.js.map +1 -0
- package/dist/sbp/frame.d.ts +34 -0
- package/dist/sbp/frame.d.ts.map +1 -0
- package/dist/sbp/frame.js +95 -0
- package/dist/sbp/frame.js.map +1 -0
- package/dist/sbp/records.d.ts +32 -0
- package/dist/sbp/records.d.ts.map +1 -0
- package/dist/sbp/records.js +527 -0
- package/dist/sbp/records.js.map +1 -0
- package/dist/sbp/session.d.ts +110 -0
- package/dist/sbp/session.d.ts.map +1 -0
- package/dist/sbp/session.js +349 -0
- package/dist/sbp/session.js.map +1 -0
- package/dist/sbp/value.d.ts +13 -0
- package/dist/sbp/value.d.ts.map +1 -0
- package/dist/sbp/value.js +58 -0
- package/dist/sbp/value.js.map +1 -0
- package/dist/social/social-client.d.ts +38 -0
- package/dist/social/social-client.d.ts.map +1 -0
- package/dist/social/social-client.js +110 -0
- package/dist/social/social-client.js.map +1 -0
- package/dist/transports/media-server-identity.d.ts +8 -0
- package/dist/transports/media-server-identity.d.ts.map +1 -0
- package/dist/transports/media-server-identity.js +22 -0
- package/dist/transports/media-server-identity.js.map +1 -0
- package/dist/workspace/index.d.ts +2 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +2 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/workspace-controller.d.ts +39 -0
- package/dist/workspace/workspace-controller.d.ts.map +1 -0
- package/dist/workspace/workspace-controller.js +188 -0
- package/dist/workspace/workspace-controller.js.map +1 -0
- package/dist/workspace/workspace-selectors.d.ts +49 -0
- package/dist/workspace/workspace-selectors.d.ts.map +1 -0
- package/dist/workspace/workspace-selectors.js +110 -0
- package/dist/workspace/workspace-selectors.js.map +1 -0
- package/package.json +88 -4
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InstanceEndpoint } from "../instance-endpoint.js";
|
|
2
|
+
import { type PrivateTransferControl, type PrivateTransferFrame } from "./private-transfer-protocol.js";
|
|
3
|
+
export type PrivateTransferTransportCallbacks = {
|
|
4
|
+
onFrame: (frame: PrivateTransferFrame) => void;
|
|
5
|
+
onPeerState: (connected: boolean) => void;
|
|
6
|
+
onDisconnect: (reason?: string) => void;
|
|
7
|
+
onError: (reason: unknown) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare class PrivateTransferTransport {
|
|
10
|
+
private readonly key;
|
|
11
|
+
private readonly callbacks;
|
|
12
|
+
private socket?;
|
|
13
|
+
private channel?;
|
|
14
|
+
private closed;
|
|
15
|
+
constructor(key: CryptoKey, callbacks: PrivateTransferTransportCallbacks);
|
|
16
|
+
connect(endpoint: InstanceEndpoint, roomId: string, ticket: string): Promise<void>;
|
|
17
|
+
sendControl(control: PrivateTransferControl): Promise<void>;
|
|
18
|
+
sendChunk(fileId: string, chunk: number, bytes: Uint8Array): Promise<void>;
|
|
19
|
+
close(): void;
|
|
20
|
+
private push;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=private-transfer-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-transfer-transport.d.ts","sourceRoot":"","sources":["../../src/private-conversation/private-transfer-transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC1B,MAAM,gCAAgC,CAAC;AAExC,MAAM,MAAM,iCAAiC,GAAG;IAC9C,OAAO,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,WAAW,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF,qBAAa,wBAAwB;IAMjC,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAU;IAC1B,OAAO,CAAC,MAAM,CAAS;gBAGJ,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,iCAAiC;IAGzD,OAAO,CAAC,QAAQ,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAuClE,WAAW,CAAC,OAAO,EAAE,sBAAsB;IAK3C,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU;IAUhE,KAAK;IAQL,OAAO,CAAC,IAAI;CAUb"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Socket } from "phoenix";
|
|
2
|
+
import { decryptPrivateTransferFrame, encryptPrivateTransferChunk, encryptPrivateTransferControl, } from "./private-transfer-protocol.js";
|
|
3
|
+
export class PrivateTransferTransport {
|
|
4
|
+
key;
|
|
5
|
+
callbacks;
|
|
6
|
+
socket;
|
|
7
|
+
channel;
|
|
8
|
+
closed = false;
|
|
9
|
+
constructor(key, callbacks) {
|
|
10
|
+
this.key = key;
|
|
11
|
+
this.callbacks = callbacks;
|
|
12
|
+
}
|
|
13
|
+
async connect(endpoint, roomId, ticket) {
|
|
14
|
+
if (this.socket)
|
|
15
|
+
throw new Error("Private transfer transport is active");
|
|
16
|
+
this.closed = false;
|
|
17
|
+
this.socket = new Socket(`${endpoint.baseUrl.replace(/\/$/u, "")}/transfers`, { params: { ticket } });
|
|
18
|
+
this.socket.connect();
|
|
19
|
+
this.channel = this.socket.channel(`transfer:${roomId}`);
|
|
20
|
+
this.channel.on("frame", (payload) => {
|
|
21
|
+
const bytes = binaryPayload(payload);
|
|
22
|
+
if (!bytes) {
|
|
23
|
+
this.callbacks.onError(new Error("Invalid private transfer frame"));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
void decryptPrivateTransferFrame(this.key, bytes)
|
|
27
|
+
.then(this.callbacks.onFrame)
|
|
28
|
+
.catch(this.callbacks.onError);
|
|
29
|
+
});
|
|
30
|
+
this.channel.on("peer", (payload) => {
|
|
31
|
+
const state = payload?.state;
|
|
32
|
+
if (state === "connected" || state === "disconnected")
|
|
33
|
+
this.callbacks.onPeerState(state === "connected");
|
|
34
|
+
});
|
|
35
|
+
this.channel.on("disconnect", (payload) => {
|
|
36
|
+
this.callbacks.onDisconnect(typeof payload?.reason ===
|
|
37
|
+
"string"
|
|
38
|
+
? String(payload.reason)
|
|
39
|
+
: undefined);
|
|
40
|
+
});
|
|
41
|
+
this.channel.onError((reason) => this.callbacks.onError(reason));
|
|
42
|
+
this.channel.onClose(() => {
|
|
43
|
+
if (!this.closed)
|
|
44
|
+
this.callbacks.onDisconnect();
|
|
45
|
+
});
|
|
46
|
+
await joinChannel(this.channel);
|
|
47
|
+
}
|
|
48
|
+
async sendControl(control) {
|
|
49
|
+
const frame = await encryptPrivateTransferControl(this.key, control);
|
|
50
|
+
this.push(frame);
|
|
51
|
+
}
|
|
52
|
+
async sendChunk(fileId, chunk, bytes) {
|
|
53
|
+
const frame = await encryptPrivateTransferChunk(this.key, fileId, chunk, bytes);
|
|
54
|
+
this.push(frame);
|
|
55
|
+
}
|
|
56
|
+
close() {
|
|
57
|
+
this.closed = true;
|
|
58
|
+
this.channel?.leave();
|
|
59
|
+
this.socket?.disconnect();
|
|
60
|
+
this.channel = undefined;
|
|
61
|
+
this.socket = undefined;
|
|
62
|
+
}
|
|
63
|
+
push(frame) {
|
|
64
|
+
if (!this.channel)
|
|
65
|
+
throw new Error("Private transfer transport is offline");
|
|
66
|
+
this.channel.push("frame", frame.buffer.slice(frame.byteOffset, frame.byteOffset + frame.byteLength));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function joinChannel(channel) {
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
channel
|
|
72
|
+
.join()
|
|
73
|
+
.receive("ok", () => resolve())
|
|
74
|
+
.receive("error", (reason) => reject(new Error(transferJoinError(reason))))
|
|
75
|
+
.receive("timeout", () => reject(new Error("Timed out connecting the private transfer")));
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function transferJoinError(reason) {
|
|
79
|
+
const value = reason?.reason;
|
|
80
|
+
return typeof value === "string"
|
|
81
|
+
? `Private transfer was rejected: ${value}`
|
|
82
|
+
: "The server rejected the private transfer";
|
|
83
|
+
}
|
|
84
|
+
function binaryPayload(payload) {
|
|
85
|
+
if (payload instanceof ArrayBuffer)
|
|
86
|
+
return payload;
|
|
87
|
+
if (ArrayBuffer.isView(payload)) {
|
|
88
|
+
const copy = new Uint8Array(payload.byteLength);
|
|
89
|
+
copy.set(new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength));
|
|
90
|
+
return copy.buffer;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=private-transfer-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"private-transfer-transport.js","sourceRoot":"","sources":["../../src/private-conversation/private-transfer-transport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CustomStatus, RealtimeSettings } from "../domain.js";
|
|
2
|
+
import type { ActivityId, ConversationId } from "../entity-id.js";
|
|
3
|
+
import type { SbpCommandTransport } from "../sbp/command-transport.js";
|
|
4
|
+
export type SbpRealtimeTransport = SbpCommandTransport & {
|
|
5
|
+
control(opcode: number, payload: unknown): void;
|
|
6
|
+
};
|
|
7
|
+
export type PublishPresenceInput = {
|
|
8
|
+
availability: "offline" | "online" | "idle" | "dnd" | "invisible";
|
|
9
|
+
customStatus?: CustomStatus;
|
|
10
|
+
idleSince?: Date;
|
|
11
|
+
};
|
|
12
|
+
export type PublishActivityInput = {
|
|
13
|
+
id: ActivityId;
|
|
14
|
+
kind: "music" | "game" | "custom";
|
|
15
|
+
startedAt: Date;
|
|
16
|
+
updatedAt: Date;
|
|
17
|
+
expiresAt: Date;
|
|
18
|
+
payload: unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare class SbpRealtimeClient {
|
|
21
|
+
private readonly transport;
|
|
22
|
+
private readonly typingPublications;
|
|
23
|
+
constructor(transport: SbpRealtimeTransport);
|
|
24
|
+
publishPresence(input: PublishPresenceInput): void;
|
|
25
|
+
publishTyping(conversationId: ConversationId, typing: boolean, leaseMs: number): void;
|
|
26
|
+
messageSent(conversationId: ConversationId): void;
|
|
27
|
+
publishActivity(input: PublishActivityInput): void;
|
|
28
|
+
clearActivity(kind: PublishActivityInput["kind"]): void;
|
|
29
|
+
updateSettings(settings: RealtimeSettings): Promise<RealtimeSettings>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=realtime-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-client.d.ts","sourceRoot":"","sources":["../../src/realtime/realtime-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAY,MAAM,cAAc,CAAC;AAC7E,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAElE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IACvD,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IAClE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,iBAAiB;IAMhB,OAAO,CAAC,QAAQ,CAAC,SAAS;IALtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAG/B;gBAEyB,SAAS,EAAE,oBAAoB;IAE5D,eAAe,CAAC,KAAK,EAAE,oBAAoB;IAc3C,aAAa,CACX,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,MAAM;IAyBjB,WAAW,CAAC,cAAc,EAAE,cAAc;IAI1C,eAAe,CAAC,KAAK,EAAE,oBAAoB;IAc3C,aAAa,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC;IAI1C,cAAc,CAAC,QAAQ,EAAE,gBAAgB;CAQhD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { entityRef, requestRef, wireMap } from "../sbp/codec.js";
|
|
2
|
+
import { decodeRealtimeSettings } from "../sbp/records.js";
|
|
3
|
+
export class SbpRealtimeClient {
|
|
4
|
+
transport;
|
|
5
|
+
typingPublications = new Map();
|
|
6
|
+
constructor(transport) {
|
|
7
|
+
this.transport = transport;
|
|
8
|
+
}
|
|
9
|
+
publishPresence(input) {
|
|
10
|
+
this.transport.control(32, wireMap([
|
|
11
|
+
[0, availabilityId(input.availability)],
|
|
12
|
+
...optionalEntry(1, input.customStatus && encodeCustomStatus(input.customStatus)),
|
|
13
|
+
...optionalEntry(3, input.idleSince),
|
|
14
|
+
]));
|
|
15
|
+
}
|
|
16
|
+
publishTyping(conversationId, typing, leaseMs) {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
const previous = this.typingPublications.get(conversationId);
|
|
19
|
+
const refreshAfterMs = Math.max(1_000, Math.floor(leaseMs / 2));
|
|
20
|
+
if ((!previous && !typing) ||
|
|
21
|
+
(previous?.typing === typing &&
|
|
22
|
+
(!typing || now - previous.sentAt < refreshAfterMs))) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.transport.control(34, wireMap([
|
|
26
|
+
[0, entityRef("conversation", conversationId)],
|
|
27
|
+
[1, typing],
|
|
28
|
+
[2, leaseMs],
|
|
29
|
+
]));
|
|
30
|
+
this.typingPublications.set(conversationId, { typing, sentAt: now });
|
|
31
|
+
}
|
|
32
|
+
messageSent(conversationId) {
|
|
33
|
+
this.typingPublications.delete(conversationId);
|
|
34
|
+
}
|
|
35
|
+
publishActivity(input) {
|
|
36
|
+
this.transport.control(36, wireMap([
|
|
37
|
+
[0, requestRef(input.id)],
|
|
38
|
+
[1, activityKindId(input.kind)],
|
|
39
|
+
[2, input.startedAt],
|
|
40
|
+
[3, input.updatedAt],
|
|
41
|
+
[4, input.expiresAt],
|
|
42
|
+
[5, encodeActivityPayload(input.kind, input.payload)],
|
|
43
|
+
]));
|
|
44
|
+
}
|
|
45
|
+
clearActivity(kind) {
|
|
46
|
+
this.transport.control(36, [activityKindId(kind), null]);
|
|
47
|
+
}
|
|
48
|
+
async updateSettings(settings) {
|
|
49
|
+
return decodeRealtimeSettings(await this.transport.command(500, wireMap([[0, encodeSettings(settings)]])));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function availabilityId(value) {
|
|
53
|
+
return { offline: 0, online: 1, idle: 2, dnd: 3, invisible: 4 }[value];
|
|
54
|
+
}
|
|
55
|
+
function activityKindId(value) {
|
|
56
|
+
return { music: 0, game: 1, custom: 255 }[value];
|
|
57
|
+
}
|
|
58
|
+
function encodeActivityPayload(kind, payload) {
|
|
59
|
+
if (kind !== "music")
|
|
60
|
+
return payload;
|
|
61
|
+
const tune = payload;
|
|
62
|
+
if (!tune.title)
|
|
63
|
+
throw new TypeError("Music activity requires a title");
|
|
64
|
+
return [
|
|
65
|
+
0,
|
|
66
|
+
wireMap([
|
|
67
|
+
[0, tune.title],
|
|
68
|
+
...optionalEntry(1, tune.artist ? [tune.artist] : undefined),
|
|
69
|
+
...optionalEntry(2, tune.album),
|
|
70
|
+
[3, playbackStateId(tune.playbackState)],
|
|
71
|
+
...optionalEntry(4, tune.durationMs),
|
|
72
|
+
...optionalEntry(5, tune.positionMs),
|
|
73
|
+
...optionalEntry(8, tune.applicationName),
|
|
74
|
+
...optionalEntry(9, tune.applicationId),
|
|
75
|
+
...optionalEntry(10, tune.trackId ? [["native", tune.trackId]] : undefined),
|
|
76
|
+
...optionalEntry(11, tune.trackUri),
|
|
77
|
+
]),
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
function playbackStateId(value) {
|
|
81
|
+
return { stopped: 0, paused: 1, playing: 2, unknown: 0 }[value ?? "unknown"];
|
|
82
|
+
}
|
|
83
|
+
function encodeCustomStatus(status) {
|
|
84
|
+
return wireMap([
|
|
85
|
+
...optionalEntry(0, status.text),
|
|
86
|
+
...optionalEntry(1, status.emoji),
|
|
87
|
+
...optionalEntry(2, status.expiresAt && new Date(status.expiresAt)),
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
function encodeSettings(settings) {
|
|
91
|
+
const visibility = { nobody: 0, friends: 1, "shared-context": 2 };
|
|
92
|
+
return wireMap([
|
|
93
|
+
[0, visibility[settings.presenceVisibility]],
|
|
94
|
+
[1, visibility[settings.activityVisibility]],
|
|
95
|
+
[2, settings.activitySharingEnabled],
|
|
96
|
+
...optionalEntry(3, settings.customStatus && encodeCustomStatus(settings.customStatus)),
|
|
97
|
+
[4, settings.revision],
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
function optionalEntry(key, value) {
|
|
101
|
+
return value === undefined ? [] : [[key, value]];
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=realtime-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime-client.js","sourceRoot":"","sources":["../../src/realtime/realtime-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Tag } from "cbor-x";
|
|
2
|
+
import { type EntityId } from "../entity-id.js";
|
|
3
|
+
export declare const SBP_ENTITY_TAG = 60003;
|
|
4
|
+
export declare const UUID_TAG = 37;
|
|
5
|
+
export declare const entityKinds: {
|
|
6
|
+
readonly user: 0;
|
|
7
|
+
readonly device: 1;
|
|
8
|
+
readonly conversation: 2;
|
|
9
|
+
readonly community: 3;
|
|
10
|
+
readonly channel: 4;
|
|
11
|
+
readonly attachment: 5;
|
|
12
|
+
readonly role: 6;
|
|
13
|
+
readonly friendship: 7;
|
|
14
|
+
readonly call: 8;
|
|
15
|
+
readonly "private-conversation": 9;
|
|
16
|
+
readonly invitation: 10;
|
|
17
|
+
readonly block: 11;
|
|
18
|
+
};
|
|
19
|
+
export type EntityKind = keyof typeof entityKinds;
|
|
20
|
+
export declare function encodeSbp(value: unknown): Uint8Array;
|
|
21
|
+
export declare function decodeSbp(bytes: Uint8Array): unknown;
|
|
22
|
+
export declare function wireMap(entries: Iterable<readonly [number, unknown]>): Map<number, unknown>;
|
|
23
|
+
export declare function entityRef<Kind extends EntityKind>(kind: Kind, id: EntityId<Kind>): Tag;
|
|
24
|
+
export declare function decodeEntityRef<Kind extends EntityKind>(value: unknown, expectedKind: Kind): EntityId<Kind>;
|
|
25
|
+
export declare function decodeAnyEntityRef(value: unknown): {
|
|
26
|
+
kind: "user" | "device" | "conversation" | "community" | "channel" | "attachment" | "role" | "friendship" | "call" | "private-conversation" | "invitation" | "block";
|
|
27
|
+
id: EntityId<string>;
|
|
28
|
+
};
|
|
29
|
+
export declare function requestRef(id: string): Tag;
|
|
30
|
+
export declare function decodeRequestRef(value: unknown): string;
|
|
31
|
+
export declare function uuidToBytes(value: string): Uint8Array;
|
|
32
|
+
export declare function bytesToUuid(value: Uint8Array): string;
|
|
33
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/sbp/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,GAAG,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1D,eAAO,MAAM,cAAc,QAAS,CAAC;AACrC,eAAO,MAAM,QAAQ,KAAK,CAAC;AAE3B,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAad,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,WAAW,CAAC;AAuBlD,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAEpD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEpD;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,wBAEpE;AAED,wBAAgB,SAAS,CAAC,IAAI,SAAS,UAAU,EAC/C,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,OAGnB;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAS,UAAU,EACrD,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,IAAI,GACjB,QAAQ,CAAC,IAAI,CAAC,CAShB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO;;;EAUhD;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,OAEpC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQvD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAMrD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMrD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Decoder, Encoder, Tag } from "cbor-x";
|
|
2
|
+
import { entityId } from "../entity-id.js";
|
|
3
|
+
export const SBP_ENTITY_TAG = 60_003;
|
|
4
|
+
export const UUID_TAG = 37;
|
|
5
|
+
export const entityKinds = {
|
|
6
|
+
user: 0,
|
|
7
|
+
device: 1,
|
|
8
|
+
conversation: 2,
|
|
9
|
+
community: 3,
|
|
10
|
+
channel: 4,
|
|
11
|
+
attachment: 5,
|
|
12
|
+
role: 6,
|
|
13
|
+
friendship: 7,
|
|
14
|
+
call: 8,
|
|
15
|
+
"private-conversation": 9,
|
|
16
|
+
invitation: 10,
|
|
17
|
+
block: 11,
|
|
18
|
+
};
|
|
19
|
+
const kindNames = new Map(Object.entries(entityKinds).map(([name, value]) => [
|
|
20
|
+
value,
|
|
21
|
+
name,
|
|
22
|
+
]));
|
|
23
|
+
const encoder = new Encoder({
|
|
24
|
+
useRecords: false,
|
|
25
|
+
mapsAsObjects: false,
|
|
26
|
+
structuredClone: false,
|
|
27
|
+
bundleStrings: false,
|
|
28
|
+
tagUint8Array: false,
|
|
29
|
+
});
|
|
30
|
+
const decoder = new Decoder({
|
|
31
|
+
useRecords: false,
|
|
32
|
+
mapsAsObjects: false,
|
|
33
|
+
copyBuffers: true,
|
|
34
|
+
});
|
|
35
|
+
export function encodeSbp(value) {
|
|
36
|
+
return encoder.encode(value);
|
|
37
|
+
}
|
|
38
|
+
export function decodeSbp(bytes) {
|
|
39
|
+
return decoder.decode(bytes);
|
|
40
|
+
}
|
|
41
|
+
export function wireMap(entries) {
|
|
42
|
+
return new Map([...entries].sort(([left], [right]) => left - right));
|
|
43
|
+
}
|
|
44
|
+
export function entityRef(kind, id) {
|
|
45
|
+
return new Tag([entityKinds[kind], uuidToBytes(id)], SBP_ENTITY_TAG);
|
|
46
|
+
}
|
|
47
|
+
export function decodeEntityRef(value, expectedKind) {
|
|
48
|
+
if (!(value instanceof Tag) || value.tag !== SBP_ENTITY_TAG)
|
|
49
|
+
throw new TypeError("Expected an SBP entity reference");
|
|
50
|
+
if (!Array.isArray(value.value) || value.value.length !== 2)
|
|
51
|
+
throw new TypeError("Invalid SBP entity reference");
|
|
52
|
+
const [kind, bytes] = value.value;
|
|
53
|
+
if (kind !== entityKinds[expectedKind] || !isByteString(bytes, 16))
|
|
54
|
+
throw new TypeError(`Expected an SBP ${expectedKind} reference`);
|
|
55
|
+
return entityId(bytesToUuid(bytes));
|
|
56
|
+
}
|
|
57
|
+
export function decodeAnyEntityRef(value) {
|
|
58
|
+
if (!(value instanceof Tag) || value.tag !== SBP_ENTITY_TAG)
|
|
59
|
+
throw new TypeError("Expected an SBP entity reference");
|
|
60
|
+
if (!Array.isArray(value.value) || value.value.length !== 2)
|
|
61
|
+
throw new TypeError("Invalid SBP entity reference");
|
|
62
|
+
const [kind, bytes] = value.value;
|
|
63
|
+
const name = typeof kind === "number" ? kindNames.get(kind) : undefined;
|
|
64
|
+
if (!name || !isByteString(bytes, 16))
|
|
65
|
+
throw new TypeError("Unknown SBP entity reference");
|
|
66
|
+
return { kind: name, id: entityId(bytesToUuid(bytes)) };
|
|
67
|
+
}
|
|
68
|
+
export function requestRef(id) {
|
|
69
|
+
return new Tag(uuidToBytes(id), UUID_TAG);
|
|
70
|
+
}
|
|
71
|
+
export function decodeRequestRef(value) {
|
|
72
|
+
if (!(value instanceof Tag) ||
|
|
73
|
+
value.tag !== UUID_TAG ||
|
|
74
|
+
!isByteString(value.value, 16))
|
|
75
|
+
throw new TypeError("Invalid SBP request ID");
|
|
76
|
+
return bytesToUuid(value.value);
|
|
77
|
+
}
|
|
78
|
+
export function uuidToBytes(value) {
|
|
79
|
+
const compact = value.replaceAll("-", "").toLowerCase();
|
|
80
|
+
if (!/^[0-9a-f]{32}$/.test(compact))
|
|
81
|
+
throw new TypeError("Invalid UUID");
|
|
82
|
+
return Uint8Array.from(compact.match(/../g).map((octet) => Number.parseInt(octet, 16)));
|
|
83
|
+
}
|
|
84
|
+
export function bytesToUuid(value) {
|
|
85
|
+
if (!isByteString(value, 16))
|
|
86
|
+
throw new TypeError("Invalid UUID bytes");
|
|
87
|
+
const compact = Array.from(value, (octet) => octet.toString(16).padStart(2, "0")).join("");
|
|
88
|
+
return `${compact.slice(0, 8)}-${compact.slice(8, 12)}-${compact.slice(12, 16)}-${compact.slice(16, 20)}-${compact.slice(20)}`;
|
|
89
|
+
}
|
|
90
|
+
function isByteString(value, size) {
|
|
91
|
+
return value instanceof Uint8Array && value.byteLength === size;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/sbp/codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type SbpCommandHandle = {
|
|
2
|
+
requestId: string;
|
|
3
|
+
response: Promise<unknown>;
|
|
4
|
+
};
|
|
5
|
+
export type SbpCommandTransport = {
|
|
6
|
+
command(opcode: number, payload: unknown): Promise<unknown>;
|
|
7
|
+
commandWithHandle?: (opcode: number, payload: unknown, requestId?: string) => SbpCommandHandle;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=command-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-transport.d.ts","sourceRoot":"","sources":["../../src/sbp/command-transport.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,iBAAiB,CAAC,EAAE,CAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,KACf,gBAAgB,CAAC;CACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-transport.js","sourceRoot":"","sources":["../../src/sbp/command-transport.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ConversationId } from "../entity-id.js";
|
|
2
|
+
export type SbpStream = {
|
|
3
|
+
kind: "account";
|
|
4
|
+
} | {
|
|
5
|
+
kind: "conversation";
|
|
6
|
+
conversationId: ConversationId;
|
|
7
|
+
};
|
|
8
|
+
export type SbpFrame = {
|
|
9
|
+
kind: "command";
|
|
10
|
+
requestId: string;
|
|
11
|
+
opcode: number;
|
|
12
|
+
payload: unknown;
|
|
13
|
+
} | {
|
|
14
|
+
kind: "response";
|
|
15
|
+
requestId: string;
|
|
16
|
+
status: "ok" | "error";
|
|
17
|
+
opcode?: number;
|
|
18
|
+
payload: unknown;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "event";
|
|
21
|
+
stream: SbpStream;
|
|
22
|
+
eventId: bigint;
|
|
23
|
+
timestamp: Date;
|
|
24
|
+
opcode: number;
|
|
25
|
+
payload: unknown;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "control";
|
|
28
|
+
opcode: number;
|
|
29
|
+
payload: unknown;
|
|
30
|
+
};
|
|
31
|
+
export declare function encodeCommand(requestId: string, opcode: number, payload: unknown): Uint8Array;
|
|
32
|
+
export declare function encodeControl(opcode: number, payload: unknown): Uint8Array;
|
|
33
|
+
export declare function decodeFrame(bytes: Uint8Array): SbpFrame;
|
|
34
|
+
//# sourceMappingURL=frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/sbp/frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAStD,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,cAAc,EAAE,cAAc,CAAA;CAAE,CAAC;AAE7D,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACxE;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1D,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,GACf,UAAU,CAEZ;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,CAE1E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,CAmDvD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { decodeEntityRef, decodeRequestRef, decodeSbp, encodeSbp, requestRef, } from "./codec.js";
|
|
2
|
+
export function encodeCommand(requestId, opcode, payload) {
|
|
3
|
+
return encodeSbp([0, requestRef(requestId), [opcode, payload]]);
|
|
4
|
+
}
|
|
5
|
+
export function encodeControl(opcode, payload) {
|
|
6
|
+
return encodeSbp([3, [opcode, payload]]);
|
|
7
|
+
}
|
|
8
|
+
export function decodeFrame(bytes) {
|
|
9
|
+
const frame = decodeSbp(bytes);
|
|
10
|
+
if (!Array.isArray(frame))
|
|
11
|
+
throw new TypeError("Invalid SBP frame");
|
|
12
|
+
switch (frame[0]) {
|
|
13
|
+
case 0: {
|
|
14
|
+
requireLength(frame, 3);
|
|
15
|
+
const [opcode, payload] = operation(frame[2]);
|
|
16
|
+
return {
|
|
17
|
+
kind: "command",
|
|
18
|
+
requestId: decodeRequestRef(frame[1]),
|
|
19
|
+
opcode,
|
|
20
|
+
payload,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
case 1: {
|
|
24
|
+
requireLength(frame, 4);
|
|
25
|
+
const requestId = decodeRequestRef(frame[1]);
|
|
26
|
+
if (frame[2] === 0) {
|
|
27
|
+
const [opcode, payload] = operation(frame[3]);
|
|
28
|
+
return { kind: "response", requestId, status: "ok", opcode, payload };
|
|
29
|
+
}
|
|
30
|
+
if (frame[2] === 1)
|
|
31
|
+
return {
|
|
32
|
+
kind: "response",
|
|
33
|
+
requestId,
|
|
34
|
+
status: "error",
|
|
35
|
+
payload: frame[3],
|
|
36
|
+
};
|
|
37
|
+
throw new TypeError("Invalid SBP response status");
|
|
38
|
+
}
|
|
39
|
+
case 2: {
|
|
40
|
+
requireLength(frame, 5);
|
|
41
|
+
const [opcode, payload] = operation(frame[4]);
|
|
42
|
+
return {
|
|
43
|
+
kind: "event",
|
|
44
|
+
stream: decodeStream(frame[1]),
|
|
45
|
+
eventId: integer(frame[2]),
|
|
46
|
+
timestamp: timestamp(frame[3]),
|
|
47
|
+
opcode,
|
|
48
|
+
payload,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
case 3: {
|
|
52
|
+
requireLength(frame, 2);
|
|
53
|
+
const [opcode, payload] = operation(frame[1]);
|
|
54
|
+
return { kind: "control", opcode, payload };
|
|
55
|
+
}
|
|
56
|
+
default:
|
|
57
|
+
throw new TypeError("Unknown SBP frame kind");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function operation(value) {
|
|
61
|
+
if (!Array.isArray(value) ||
|
|
62
|
+
value.length !== 2 ||
|
|
63
|
+
!Number.isInteger(value[0]))
|
|
64
|
+
throw new TypeError("Invalid SBP operation");
|
|
65
|
+
return [value[0], value[1]];
|
|
66
|
+
}
|
|
67
|
+
function decodeStream(value) {
|
|
68
|
+
if (!Array.isArray(value))
|
|
69
|
+
throw new TypeError("Invalid SBP stream reference");
|
|
70
|
+
if (value.length === 1 && value[0] === 0)
|
|
71
|
+
return { kind: "account" };
|
|
72
|
+
if (value.length === 2 && value[0] === 1)
|
|
73
|
+
return {
|
|
74
|
+
kind: "conversation",
|
|
75
|
+
conversationId: decodeEntityRef(value[1], "conversation"),
|
|
76
|
+
};
|
|
77
|
+
throw new TypeError("Invalid SBP stream reference");
|
|
78
|
+
}
|
|
79
|
+
function integer(value) {
|
|
80
|
+
if (typeof value === "bigint" && value >= 0n)
|
|
81
|
+
return value;
|
|
82
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
|
|
83
|
+
return BigInt(value);
|
|
84
|
+
throw new TypeError("Invalid SBP ordered ID");
|
|
85
|
+
}
|
|
86
|
+
function timestamp(value) {
|
|
87
|
+
if (value instanceof Date && !Number.isNaN(value.valueOf()))
|
|
88
|
+
return value;
|
|
89
|
+
throw new TypeError("Invalid SBP timestamp");
|
|
90
|
+
}
|
|
91
|
+
function requireLength(value, length) {
|
|
92
|
+
if (value.length !== length)
|
|
93
|
+
throw new TypeError("Invalid SBP frame length");
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frame.js","sourceRoot":"","sources":["../../src/sbp/frame.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { AccountSnapshot, AttachmentMetadata, Block, CallSession, CallTarget, ChatMessage, ClientDevice, Community, CommunityChannel, CommunityInvitation, CommunityMember, CommunityMemberPage, CommunityRole, ConversationSnapshot, ConversationSummary, ContextHistoryPage, HistoryPage, InboxEntry, NotificationSettings, PrivateConversationSession, PrivateTransfer, RealtimeSettings, RosterContact, UserProfile, UserSummary } from "../domain.js";
|
|
2
|
+
export declare function decodeUserSummary(value: unknown): UserSummary;
|
|
3
|
+
export declare function decodeUserProfile(value: unknown): UserProfile;
|
|
4
|
+
export declare function decodeFriendship(value: unknown): RosterContact;
|
|
5
|
+
export declare function decodeConversation(value: unknown): ConversationSummary;
|
|
6
|
+
export declare function decodeMessage(value: unknown): ChatMessage;
|
|
7
|
+
export declare function decodeCommunity(value: unknown): Community;
|
|
8
|
+
export declare function decodeCommunityMemberPage(value: unknown): CommunityMemberPage;
|
|
9
|
+
export declare function decodeCall(value: unknown): CallSession;
|
|
10
|
+
export declare function decodePrivateConversation(value: unknown): PrivateConversationSession;
|
|
11
|
+
export declare function decodePrivateTransfer(value: unknown): PrivateTransfer;
|
|
12
|
+
export declare function decodeCallTarget(value: unknown): CallTarget;
|
|
13
|
+
export declare function decodeCommunityInvitation(value: unknown): CommunityInvitation;
|
|
14
|
+
export declare function decodeRealtimeSettings(value: unknown): RealtimeSettings;
|
|
15
|
+
export declare function decodeAccountSnapshot(value: unknown): AccountSnapshot;
|
|
16
|
+
export declare function decodeConversationSnapshot(value: unknown): ConversationSnapshot;
|
|
17
|
+
export declare function decodeHistoryPage(value: unknown): HistoryPage;
|
|
18
|
+
export declare function decodeContextHistoryPage(value: unknown): ContextHistoryPage;
|
|
19
|
+
export declare function decodeAttachment(value: unknown): AttachmentMetadata;
|
|
20
|
+
export declare function decodeReactionSummaries(value: unknown): {
|
|
21
|
+
emoji: string;
|
|
22
|
+
count: number;
|
|
23
|
+
own: boolean;
|
|
24
|
+
}[];
|
|
25
|
+
export declare function decodeCommunityMember(value: unknown): CommunityMember;
|
|
26
|
+
export declare function decodeCommunityRole(value: unknown): CommunityRole;
|
|
27
|
+
export declare function decodeCommunityChannel(value: unknown): CommunityChannel;
|
|
28
|
+
export declare function decodeInboxEntry(value: unknown): InboxEntry;
|
|
29
|
+
export declare function decodeBlock(value: unknown): Block;
|
|
30
|
+
export declare function decodeNotificationSettings(value: unknown): NotificationSettings;
|
|
31
|
+
export declare function decodeDevice(value: unknown): ClientDevice;
|
|
32
|
+
//# sourceMappingURL=records.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../src/sbp/records.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,kBAAkB,EAClB,KAAK,EAEL,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EAGnB,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,UAAU,EAEV,oBAAoB,EACpB,0BAA0B,EAC1B,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,WAAW,EACZ,MAAM,cAAc,CAAC;AA6BtB,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAS7D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAQ7D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAoB9D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAoBtE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAuCzD;AA8CD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAezD;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAkB7E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CA4BtD;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,GACb,0BAA0B,CAe5B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAuBrE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAgB3D;AAeD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAe7E;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAyBvE;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAiBrE;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,oBAAoB,CAStB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAU7D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAW3E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,CAcnE;AAWD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO;;;;IASrD;AAsCD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAWrE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAWjE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CAoBvE;AAwBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAiB3D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAQjD;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,oBAAoB,CA0BtB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAazD"}
|