@session-foundation/swarm-routing 0.0.1 → 0.0.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/package.json +5 -5
- package/.dependency-cruiser.cjs +0 -6
- package/.turbo/turbo-build.log +0 -20
- package/.turbo/turbo-lint.log +0 -8
- package/eslint.config.mjs +0 -4
- package/src/index.ts +0 -1
- package/src/swarm_routing.ts +0 -153
- package/tests/swarm_routing.test.d.ts.map +0 -1
- package/tests/swarm_routing.test.ts +0 -362
- package/tsconfig.build.json +0 -7
- package/tsconfig.json +0 -30
- package/tsconfig.test.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/tsup.config.ts +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@session-foundation/swarm-routing",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Routes requests across storage nodes by pubkey XOR distance",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"lodash": "^4.17.21",
|
|
17
|
-
"@session-foundation/network-requests": "^0.0.
|
|
18
|
-
"@session-foundation/basic-types": "^0.0.
|
|
17
|
+
"@session-foundation/network-requests": "^0.0.7",
|
|
18
|
+
"@session-foundation/basic-types": "^0.0.8"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@turbo/gen": "^2.4.4",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"tsup": "^8.4.0",
|
|
31
31
|
"tsx": "^4.21.0",
|
|
32
32
|
"typescript": "5.8.2",
|
|
33
|
-
"@repo/tsup-config": "^0.0.0",
|
|
34
33
|
"@repo/typescript-config": "^0.0.0",
|
|
34
|
+
"@session-foundation/dep-cruiser-config-shared": "^1.0.0",
|
|
35
35
|
"@repo/eslint-config": "^0.0.0",
|
|
36
|
-
"@
|
|
36
|
+
"@repo/tsup-config": "^0.0.0"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public",
|
package/.dependency-cruiser.cjs
DELETED
package/.turbo/turbo-build.log
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
> @session-foundation/swarm-routing@0.0.1 build /home/audric/pro/contribs/session-pkgs/packages/swarm-routing
|
|
4
|
-
> tsup src/index.ts --format cjs,esm --dts --tsconfig tsconfig.build.json
|
|
5
|
-
|
|
6
|
-
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
-
[34mCLI[39m Using tsconfig: tsconfig.build.json
|
|
8
|
-
[34mCLI[39m tsup v8.5.1
|
|
9
|
-
[34mCLI[39m Using tsup config: /home/audric/pro/contribs/session-pkgs/packages/swarm-routing/tsup.config.ts
|
|
10
|
-
[34mCLI[39m Target: esnext
|
|
11
|
-
[34mCJS[39m Build start
|
|
12
|
-
[34mESM[39m Build start
|
|
13
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m4.05 KB[39m
|
|
14
|
-
[32mESM[39m ⚡️ Build success in 47ms
|
|
15
|
-
[32mCJS[39m [1mdist/index.cjs [22m[32m5.08 KB[39m
|
|
16
|
-
[32mCJS[39m ⚡️ Build success in 50ms
|
|
17
|
-
DTS Build start
|
|
18
|
-
DTS ⚡️ Build success in 834ms
|
|
19
|
-
DTS dist/index.d.ts 1.55 KB
|
|
20
|
-
DTS dist/index.d.mts 1.55 KB
|
package/.turbo/turbo-lint.log
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
> @session-foundation/swarm-routing@0.0.1 lint /home/audric/pro/contribs/session-pkgs/packages/swarm-routing
|
|
4
|
-
> eslint . --max-warnings 0 && dependency-cruiser --config .dependency-cruiser.cjs .
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[32m✔[39m no dependency violations found (21 modules, 21 dependencies cruised)
|
|
8
|
-
|
package/eslint.config.mjs
DELETED
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './swarm_routing';
|
package/src/swarm_routing.ts
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import type { WithSwarmStr } from '@session-foundation/basic-types';
|
|
2
|
-
import { createHexString, fromHex } from '@session-foundation/basic-types';
|
|
3
|
-
|
|
4
|
-
export type WithSwarm = { swarm: Swarm };
|
|
5
|
-
|
|
6
|
-
export class Swarm {
|
|
7
|
-
private readonly hi: number; // upper 32 bits, unsigned
|
|
8
|
-
private readonly lo: number; // lower 32 bits, unsigned
|
|
9
|
-
|
|
10
|
-
private constructor(hi: number, lo: number) {
|
|
11
|
-
this.hi = hi >>> 0;
|
|
12
|
-
this.lo = lo >>> 0;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Build from 8 big-endian bytes (output of the XOR reduction step). */
|
|
16
|
-
static fromBytes(bytes: Uint8Array): Swarm {
|
|
17
|
-
const hi =
|
|
18
|
-
((bytes[0]! << 24) | (bytes[1]! << 16) | (bytes[2]! << 8) | bytes[3]!) >>>
|
|
19
|
-
0;
|
|
20
|
-
const lo =
|
|
21
|
-
((bytes[4]! << 24) | (bytes[5]! << 16) | (bytes[6]! << 8) | bytes[7]!) >>>
|
|
22
|
-
0;
|
|
23
|
-
return new Swarm(hi, lo);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Parse a hex string (with or without 0x prefix, any length up to 16 chars). */
|
|
27
|
-
static fromHex(hex: string): Swarm {
|
|
28
|
-
const clean =
|
|
29
|
-
hex.startsWith('0x') || hex.startsWith('0X') ? hex.slice(2) : hex;
|
|
30
|
-
const padded = clean.padStart(16, '0');
|
|
31
|
-
const hi = parseInt(padded.slice(0, 8), 16);
|
|
32
|
-
const lo = parseInt(padded.slice(8), 16);
|
|
33
|
-
return new Swarm(hi, lo);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ── Comparisons ────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
/** -1 if this < other, 0 if equal, 1 if this > other (unsigned 64-bit). */
|
|
39
|
-
compareTo(other: Swarm): number {
|
|
40
|
-
if (this.hi !== other.hi) return this.hi < other.hi ? -1 : 1;
|
|
41
|
-
if (this.lo !== other.lo) return this.lo < other.lo ? -1 : 1;
|
|
42
|
-
return 0;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
isLessThan(other: Swarm): boolean {
|
|
46
|
-
return this.compareTo(other) < 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
equals(other: Swarm): boolean {
|
|
50
|
-
return this.hi === other.hi && this.lo === other.lo;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ── Arithmetic ─────────────────────────────────────────────────────────────
|
|
54
|
-
|
|
55
|
-
/** Unsigned 64-bit subtraction with wraparound (mod 2^64). */
|
|
56
|
-
subtract(other: Swarm): Swarm {
|
|
57
|
-
const lo = (this.lo - other.lo) >>> 0;
|
|
58
|
-
const borrow = this.lo < other.lo ? 1 : 0;
|
|
59
|
-
const hi = (this.hi - other.hi - borrow) >>> 0;
|
|
60
|
-
return new Swarm(hi, lo);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ── Serialisation ──────────────────────────────────────────────────────────
|
|
64
|
-
|
|
65
|
-
/** 16-character zero-padded lowercase hex string. */
|
|
66
|
-
toString(): string {
|
|
67
|
-
return (
|
|
68
|
-
this.hi.toString(16).padStart(8, '0') +
|
|
69
|
-
this.lo.toString(16).padStart(8, '0')
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
toJSON(): string {
|
|
74
|
-
return this.toString();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ── Routing ────────────────────────────────────────────────────────────────
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* XOR the four 8-byte chunks of a 32-byte x25519 pubkey, then interpret
|
|
81
|
-
* the result as a big-endian uint64. Equivalent of C++ pubkey_to_swarm_space.
|
|
82
|
-
*/
|
|
83
|
-
static pubkeyToSwarmSpace(pk: Uint8Array): Swarm {
|
|
84
|
-
const xored = new Uint8Array(8);
|
|
85
|
-
for (let i = 0; i < 4; i++)
|
|
86
|
-
for (let j = 0; j < 8; j++) xored[j]! ^= pk[i * 8 + j]!;
|
|
87
|
-
return Swarm.fromBytes(xored);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Group nodes by swarm and return them sorted by swarm ID ascending.
|
|
92
|
-
* Equivalent of C++ generate_swarms.
|
|
93
|
-
*/
|
|
94
|
-
static generateSwarms<T extends WithSwarmStr>(
|
|
95
|
-
nodes: T[],
|
|
96
|
-
): Array<[Swarm, T[]]> {
|
|
97
|
-
const grouped = new Map<string, T[]>();
|
|
98
|
-
for (const node of nodes) {
|
|
99
|
-
const bucket = grouped.get(node.swarm) ?? [];
|
|
100
|
-
bucket.push(node);
|
|
101
|
-
grouped.set(node.swarm, bucket);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const result: Array<[Swarm, T[]]> = [];
|
|
105
|
-
for (const [swarmHex, members] of grouped)
|
|
106
|
-
result.push([Swarm.fromHex(swarmHex), members]);
|
|
107
|
-
|
|
108
|
-
result.sort((a, b) => a[0].compareTo(b[0]));
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Find the swarm closest to the given x25519 pubkey using circular uint64
|
|
114
|
-
* distance. Equivalent of C++ get_swarm.
|
|
115
|
-
*/
|
|
116
|
-
static getFor<T extends WithSwarmStr>(
|
|
117
|
-
swarmPubkeyHex: string,
|
|
118
|
-
allSwarms: Array<[Swarm, T[]]>,
|
|
119
|
-
): [Swarm, T[]] {
|
|
120
|
-
if (allSwarms.length === 0) {
|
|
121
|
-
throw new Error('No swarms found: allSwarms.length === 0');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (allSwarms.length === 1) {
|
|
125
|
-
return allSwarms[0]!;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const pkNoPrefix =
|
|
129
|
-
swarmPubkeyHex.length === 66 ? swarmPubkeyHex.slice(2) : swarmPubkeyHex;
|
|
130
|
-
|
|
131
|
-
const pk = fromHex(createHexString(pkNoPrefix));
|
|
132
|
-
const swarmId = Swarm.pubkeyToSwarmSpace(pk);
|
|
133
|
-
|
|
134
|
-
// lower_bound: first index where allSwarms[i][0] >= swarmId
|
|
135
|
-
let lo = 0,
|
|
136
|
-
hi = allSwarms.length;
|
|
137
|
-
while (lo < hi) {
|
|
138
|
-
const mid = (lo + hi) >> 1;
|
|
139
|
-
if (allSwarms[mid]![0].isLessThan(swarmId)) lo = mid + 1;
|
|
140
|
-
else hi = mid;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const rightIdx = lo === allSwarms.length ? 0 : lo;
|
|
144
|
-
const leftIdx = rightIdx === 0 ? allSwarms.length - 1 : rightIdx - 1;
|
|
145
|
-
|
|
146
|
-
const dright = allSwarms[rightIdx]![0].subtract(swarmId);
|
|
147
|
-
const dleft = swarmId.subtract(allSwarms[leftIdx]![0]);
|
|
148
|
-
|
|
149
|
-
return dright.isLessThan(dleft)
|
|
150
|
-
? allSwarms[rightIdx]!
|
|
151
|
-
: allSwarms[leftIdx]!;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"swarm_routing.test.d.ts","sourceRoot":"","sources":["swarm_routing.test.ts"],"names":[],"mappings":""}
|