@freesignal/socketio 0.1.0 → 0.1.2

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/dist/base.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { Database, LocalStorage, Crypto, KeyExchangeDataBundle } from "@freesignal/interfaces";
2
+ import { Datagram, PrivateIdentityKey, UserId } from "@freesignal/protocol";
3
+ import { ExportedKeySession } from "@freesignal/protocol/double-ratchet";
4
+ import { BootstrapRequest, FreeSignalNode } from "@freesignal/protocol/node";
5
+ export declare class FreeSignalSocketio extends FreeSignalNode {
6
+ protected readonly outbox: LocalStorage<string, Uint8Array[]>;
7
+ constructor(storage: Database<{
8
+ sessions: LocalStorage<string, ExportedKeySession>;
9
+ keyExchange: LocalStorage<string, Crypto.KeyPair>;
10
+ users: LocalStorage<string, string>;
11
+ bundles: LocalStorage<string, KeyExchangeDataBundle>;
12
+ bootstraps: LocalStorage<string, BootstrapRequest>;
13
+ outbox: LocalStorage<string, Uint8Array[]>;
14
+ }>, privateIdentityKey?: PrivateIdentityKey);
15
+ protected addToOutbox(userId: string | UserId, datagram: Datagram | Uint8Array): Promise<void>;
16
+ protected flushOutbox(): Promise<void>;
17
+ onClose: () => void;
18
+ onError: (err: Event | Error) => void;
19
+ }
package/dist/base.js ADDED
@@ -0,0 +1,36 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Datagram, UserId } from "@freesignal/protocol";
11
+ import { FreeSignalNode } from "@freesignal/protocol/node";
12
+ export class FreeSignalSocketio extends FreeSignalNode {
13
+ constructor(storage, privateIdentityKey) {
14
+ super(storage, privateIdentityKey);
15
+ this.onClose = () => { };
16
+ this.onError = () => { };
17
+ this.outbox = storage.outbox;
18
+ }
19
+ addToOutbox(userId, datagram) {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ const array = yield this.outbox.get(userId.toString());
22
+ this.outbox.set(userId.toString(), [...(array !== null && array !== void 0 ? array : []), Datagram.from(datagram).toBytes()]);
23
+ });
24
+ }
25
+ flushOutbox() {
26
+ return __awaiter(this, void 0, void 0, function* () {
27
+ var _a;
28
+ for (const [userId, array] of Array.from((_a = yield this.outbox.entries()) !== null && _a !== void 0 ? _a : [])) {
29
+ yield this.outbox.delete(userId);
30
+ for (const data of array) {
31
+ this.emitter.emit('send', { userId: UserId.from(userId), datagram: Datagram.from(data) });
32
+ }
33
+ }
34
+ });
35
+ }
36
+ }
@@ -0,0 +1,29 @@
1
+ import { Database, LocalStorage, Crypto, KeyExchangeDataBundle } from "@freesignal/interfaces";
2
+ import { Datagram, PrivateIdentityKey, UserId } from "@freesignal/protocol";
3
+ import { ExportedKeySession, KeySession } from "@freesignal/protocol/double-ratchet";
4
+ import { BootstrapRequest } from "@freesignal/protocol/node";
5
+ import { EventCallback } from "easyemitter.ts";
6
+ import { FreeSignalSocketio } from "./base.js";
7
+ export declare class FreeSignalClient extends FreeSignalSocketio {
8
+ private _serverId?;
9
+ private socket?;
10
+ constructor(storage: Database<{
11
+ sessions: LocalStorage<string, ExportedKeySession>;
12
+ keyExchange: LocalStorage<string, Crypto.KeyPair>;
13
+ users: LocalStorage<string, string>;
14
+ bundles: LocalStorage<string, KeyExchangeDataBundle>;
15
+ bootstraps: LocalStorage<string, BootstrapRequest>;
16
+ outbox: LocalStorage<string, Uint8Array[]>;
17
+ }>, privateIdentityKey?: PrivateIdentityKey);
18
+ get connected(): boolean;
19
+ get serverId(): UserId | undefined;
20
+ protected sendHandler: EventCallback<{
21
+ session?: KeySession;
22
+ payload?: Uint8Array;
23
+ datagram?: Datagram;
24
+ request?: BootstrapRequest;
25
+ userId?: UserId;
26
+ }, typeof this.emitter>;
27
+ connect(url: string | URL): Promise<void>;
28
+ close(): void;
29
+ }
package/dist/client.js ADDED
@@ -0,0 +1,70 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { UserId } from "@freesignal/protocol";
11
+ import { io } from "socket.io-client";
12
+ import { FreeSignalSocketio } from "./base.js";
13
+ export class FreeSignalClient extends FreeSignalSocketio {
14
+ constructor(storage, privateIdentityKey) {
15
+ super(storage, privateIdentityKey);
16
+ this.sendHandler = (eventData) => {
17
+ const { session, datagram, userId } = eventData;
18
+ if (!userId && !session)
19
+ throw new Error("UserId missing");
20
+ const receiverId = (userId === null || userId === void 0 ? void 0 : userId.toString()) || (session === null || session === void 0 ? void 0 : session.userId.toString());
21
+ if (!datagram)
22
+ throw new Error("Datagram missing");
23
+ if (!!this._serverId && receiverId !== this._serverId)
24
+ this.sendRelay(this._serverId, receiverId, datagram);
25
+ else if (!this.socket || !this.socket.connected)
26
+ this.addToOutbox(receiverId, datagram);
27
+ else
28
+ this.socket.send(datagram.toBytes());
29
+ };
30
+ this.emitter.on('send', this.sendHandler);
31
+ }
32
+ get connected() {
33
+ var _a, _b;
34
+ return (_b = (_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected) !== null && _b !== void 0 ? _b : false;
35
+ }
36
+ get serverId() {
37
+ return this._serverId ? UserId.from(this._serverId) : undefined;
38
+ }
39
+ connect(url) {
40
+ return new Promise((resolve, reject) => {
41
+ try {
42
+ this.socket = io(url.toString(), {
43
+ auth: {
44
+ userId: this.userId.toString()
45
+ }
46
+ });
47
+ this.socket.on('handshake', (userId) => __awaiter(this, void 0, void 0, function* () {
48
+ this._serverId = userId;
49
+ yield this.waitHandshaked(userId);
50
+ yield this.flushOutbox();
51
+ resolve();
52
+ }));
53
+ this.socket.on('message', (data) => __awaiter(this, void 0, void 0, function* () { this.open(data); }));
54
+ this.socket.on('disconnect', () => {
55
+ this.onClose();
56
+ this.socket = undefined;
57
+ });
58
+ }
59
+ catch (error) {
60
+ reject(error);
61
+ }
62
+ });
63
+ }
64
+ close() {
65
+ if (!this.socket)
66
+ throw new Error("Socket not connected");
67
+ this.socket.close();
68
+ this.onClose();
69
+ }
70
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * FreeSignal Protocol
3
+ *
4
+ * Copyright (C) 2025 Christian Braghette
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
18
+ */
19
+ import { Database, LocalStorage, Crypto, KeyExchangeDataBundle } from "@freesignal/interfaces";
20
+ import { Datagram, PrivateIdentityKey, UserId } from "@freesignal/protocol";
21
+ import { ExportedKeySession, KeySession } from "@freesignal/protocol/double-ratchet";
22
+ import { BootstrapRequest } from "@freesignal/protocol/node";
23
+ import { EventCallback } from "easyemitter.ts";
24
+ import { type Server as HttpServer } from "http";
25
+ import { FreeSignalSocketio } from "./base.js";
26
+ export declare class FreeSignalServer extends FreeSignalSocketio {
27
+ private wss?;
28
+ private readonly connections;
29
+ constructor(storage: Database<{
30
+ sessions: LocalStorage<string, ExportedKeySession>;
31
+ keyExchange: LocalStorage<string, Crypto.KeyPair>;
32
+ users: LocalStorage<string, string>;
33
+ bundles: LocalStorage<string, KeyExchangeDataBundle>;
34
+ bootstraps: LocalStorage<string, BootstrapRequest>;
35
+ outbox: LocalStorage<string, Uint8Array[]>;
36
+ }>, privateIdentityKey?: PrivateIdentityKey);
37
+ protected sendHandler: EventCallback<{
38
+ session?: KeySession;
39
+ datagram?: Datagram;
40
+ userId?: UserId;
41
+ }, typeof this.emitter>;
42
+ listen(): this;
43
+ listen(port: number): this;
44
+ listen(server: HttpServer): this;
45
+ close(): void;
46
+ }
package/dist/server.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * FreeSignal Protocol
3
+ *
4
+ * Copyright (C) 2025 Christian Braghette
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>
18
+ */
19
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
20
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
21
+ return new (P || (P = Promise))(function (resolve, reject) {
22
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
23
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
24
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
25
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
26
+ });
27
+ };
28
+ import { Server } from 'socket.io';
29
+ import { FreeSignalSocketio } from "./base.js";
30
+ export class FreeSignalServer extends FreeSignalSocketio {
31
+ constructor(storage, privateIdentityKey) {
32
+ super(storage, privateIdentityKey);
33
+ this.connections = new Map();
34
+ this.sendHandler = (eventData) => {
35
+ const { session, datagram, userId } = eventData;
36
+ if (!userId && !session)
37
+ throw new Error("UserId missing");
38
+ const receiverId = (userId === null || userId === void 0 ? void 0 : userId.toString()) || (session === null || session === void 0 ? void 0 : session.userId.toString());
39
+ const socket = this.connections.get(receiverId);
40
+ if (!socket)
41
+ throw new Error("Socket not found for user: " + userId);
42
+ if (!datagram)
43
+ throw new Error("Datagram missing");
44
+ if (!socket.connected)
45
+ this.addToOutbox(receiverId, datagram);
46
+ else
47
+ socket.send(datagram.toBytes());
48
+ };
49
+ this.emitter.on('send', this.sendHandler);
50
+ this.emitter.on('bootstrap', ({ request }) => request === null || request === void 0 ? void 0 : request.accept());
51
+ }
52
+ listen(server) {
53
+ server !== null && server !== void 0 ? server : (server = 12437);
54
+ this.wss = new Server(server, {
55
+ cors: {
56
+ origin: (origin, callback) => {
57
+ // origin può essere undefined (curl, mobile app, server)
58
+ callback(null, true);
59
+ },
60
+ methods: ["GET", "POST"]
61
+ }
62
+ });
63
+ this.wss.on('connection', (socket) => __awaiter(this, void 0, void 0, function* () {
64
+ const userId = socket.handshake.auth.userId;
65
+ if (!userId) {
66
+ socket.disconnect();
67
+ return;
68
+ }
69
+ console.debug("Client connected: ", userId);
70
+ this.connections.set(userId, socket);
71
+ socket.on('message', (data) => this.open(data));
72
+ socket.on('disconnect', () => this.connections.delete(userId));
73
+ socket.emit('handshake', this.userId.toString());
74
+ if (!(yield this.sessions.has(userId)))
75
+ this.sendBootstrap(userId);
76
+ else
77
+ this.sendHandshake(userId);
78
+ }));
79
+ return this;
80
+ }
81
+ close() {
82
+ var _a;
83
+ if ((_a = this.wss) === null || _a === void 0 ? void 0 : _a.close((err) => err ? this.onError(err) : undefined))
84
+ this.onClose();
85
+ }
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@freesignal/socketio",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Socket.io trasnport package for FreeSignal protocol",
5
5
  "homepage": "https://github.com/christianbraghette/freesignal-socketio#readme",
6
6
  "bugs": {
@@ -14,13 +14,17 @@
14
14
  "author": "Christian Braghette",
15
15
  "type": "module",
16
16
  "exports": {
17
- ".": {
18
- "import": "./dist/index.js",
19
- "require": "./dist/index.js",
20
- "types": "./dist/index.d.ts"
17
+ "./server": {
18
+ "import": "./dist/server.js",
19
+ "require": "./dist/server.js",
20
+ "types": "./dist/server.d.ts"
21
+ },
22
+ "./client": {
23
+ "import": "./dist/client.js",
24
+ "require": "./dist/client.js",
25
+ "types": "./dist/client.d.ts"
21
26
  }
22
27
  },
23
- "main": "./dist/index.js",
24
28
  "scripts": {
25
29
  "pretest": "tsc",
26
30
  "test": "node ./dist/test.js",