flockml 1.0.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.
Files changed (45) hide show
  1. package/deep-profiling-report.html +119 -0
  2. package/dist/activations.d.ts +13 -0
  3. package/dist/activations.js +47 -0
  4. package/dist/break-test.d.ts +1 -0
  5. package/dist/break-test.js +249 -0
  6. package/dist/brutal-test.d.ts +1 -0
  7. package/dist/brutal-test.js +113 -0
  8. package/dist/client-node.d.ts +48 -0
  9. package/dist/client-node.js +174 -0
  10. package/dist/coordinator.d.ts +41 -0
  11. package/dist/coordinator.js +155 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.js +13 -0
  14. package/dist/matrix.d.ts +67 -0
  15. package/dist/matrix.js +185 -0
  16. package/dist/micro-benchmark.d.ts +1 -0
  17. package/dist/micro-benchmark.js +215 -0
  18. package/dist/network.d.ts +32 -0
  19. package/dist/network.js +127 -0
  20. package/dist/privacy.d.ts +17 -0
  21. package/dist/privacy.js +70 -0
  22. package/dist/quantization.d.ts +33 -0
  23. package/dist/quantization.js +92 -0
  24. package/dist/test.d.ts +1 -0
  25. package/dist/test.js +58 -0
  26. package/dist/worker.d.ts +15 -0
  27. package/dist/worker.js +95 -0
  28. package/package.json +21 -0
  29. package/src/activations.ts +45 -0
  30. package/src/break-test.ts +234 -0
  31. package/src/brutal-test.ts +103 -0
  32. package/src/client-node.ts +154 -0
  33. package/src/coordinator.ts +137 -0
  34. package/src/index.ts +5 -0
  35. package/src/messages.d.ts +429 -0
  36. package/src/messages.js +1173 -0
  37. package/src/messages.proto +30 -0
  38. package/src/micro-benchmark.ts +200 -0
  39. package/src/network.ts +113 -0
  40. package/src/privacy.ts +39 -0
  41. package/src/quantization.ts +82 -0
  42. package/src/test.ts +72 -0
  43. package/src/worker.ts +95 -0
  44. package/stress-report.html +190 -0
  45. package/tsconfig.json +14 -0
@@ -0,0 +1,119 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>FlockML TFJS Breakdown</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ </head>
10
+ <body class="bg-gray-950 text-gray-100 p-8 font-sans">
11
+ <div class="max-w-7xl mx-auto">
12
+ <h1 class="text-4xl font-bold mb-2 bg-gradient-to-r from-green-500 to-blue-500 bg-clip-text text-transparent">FlockML V2: TFJS Benchmarking</h1>
13
+ <p class="text-gray-400 mb-8">Hardware-accelerated continuous memory telemetry.</p>
14
+
15
+ <div class="bg-gray-900 border border-gray-800 rounded-xl overflow-hidden shadow-2xl mb-8">
16
+ <table class="w-full text-left border-collapse">
17
+ <thead>
18
+ <tr class="bg-gray-950 text-gray-400 text-sm uppercase tracking-wider">
19
+ <th class="p-4 border-b border-gray-800">Architecture</th>
20
+ <th class="p-4 border-b border-gray-800">Parameters</th>
21
+ <th class="p-4 border-b border-gray-800">Allocation (RAM)</th>
22
+ <th class="p-4 border-b border-gray-800">Train Batch</th>
23
+ <th class="p-4 border-b border-gray-800">8-Bit Quantize</th>
24
+ <th class="p-4 border-b border-gray-800">Protobuf Encode</th>
25
+ <th class="p-4 border-b border-gray-800">Heap Used</th>
26
+ <th class="p-4 border-b border-gray-800">Payload Size</th>
27
+ <th class="p-4 border-b border-gray-800">Status</th>
28
+ </tr>
29
+ </thead>
30
+ <tbody>
31
+
32
+ <tr class="hover:bg-gray-800 transition-colors">
33
+ <td class="p-3 border-b border-gray-800 font-bold">Tiny (MNIST)</td>
34
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">101,632</td>
35
+ <td class="p-3 border-b border-gray-800">12.33 ms</td>
36
+ <td class="p-3 border-b border-gray-800 font-bold text-green-400">9.45 ms</td>
37
+ <td class="p-3 border-b border-gray-800">21.28 ms</td>
38
+ <td class="p-3 border-b border-gray-800">0.41 ms</td>
39
+ <td class="p-3 border-b border-gray-800">-6.29 MB</td>
40
+ <td class="p-3 border-b border-gray-800">0.10 MB</td>
41
+ <td class="p-3 border-b border-gray-800">Success</td>
42
+ </tr>
43
+
44
+ <tr class="hover:bg-gray-800 transition-colors">
45
+ <td class="p-3 border-b border-gray-800 font-bold">Small</td>
46
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">505,000</td>
47
+ <td class="p-3 border-b border-gray-800">26.11 ms</td>
48
+ <td class="p-3 border-b border-gray-800 font-bold text-green-400">13.67 ms</td>
49
+ <td class="p-3 border-b border-gray-800">79.42 ms</td>
50
+ <td class="p-3 border-b border-gray-800">0.09 ms</td>
51
+ <td class="p-3 border-b border-gray-800">-13.89 MB</td>
52
+ <td class="p-3 border-b border-gray-800">0.48 MB</td>
53
+ <td class="p-3 border-b border-gray-800">Success</td>
54
+ </tr>
55
+
56
+ <tr class="hover:bg-gray-800 transition-colors">
57
+ <td class="p-3 border-b border-gray-800 font-bold">Medium (1M Params)</td>
58
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">1,010,000</td>
59
+ <td class="p-3 border-b border-gray-800">39.00 ms</td>
60
+ <td class="p-3 border-b border-gray-800 font-bold text-green-400">24.42 ms</td>
61
+ <td class="p-3 border-b border-gray-800">159.95 ms</td>
62
+ <td class="p-3 border-b border-gray-800">0.26 ms</td>
63
+ <td class="p-3 border-b border-gray-800">51.47 MB</td>
64
+ <td class="p-3 border-b border-gray-800">0.96 MB</td>
65
+ <td class="p-3 border-b border-gray-800">Success</td>
66
+ </tr>
67
+
68
+ <tr class="hover:bg-gray-800 transition-colors">
69
+ <td class="p-3 border-b border-gray-800 font-bold">Large (4M Params)</td>
70
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">4,020,000</td>
71
+ <td class="p-3 border-b border-gray-800">124.86 ms</td>
72
+ <td class="p-3 border-b border-gray-800 font-bold text-green-400">133.69 ms</td>
73
+ <td class="p-3 border-b border-gray-800">601.77 ms</td>
74
+ <td class="p-3 border-b border-gray-800">0.31 ms</td>
75
+ <td class="p-3 border-b border-gray-800">-34.14 MB</td>
76
+ <td class="p-3 border-b border-gray-800">3.84 MB</td>
77
+ <td class="p-3 border-b border-gray-800">Success</td>
78
+ </tr>
79
+
80
+ <tr class="hover:bg-gray-800 transition-colors">
81
+ <td class="p-3 border-b border-gray-800 font-bold">Huge (25M Params)</td>
82
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">25,050,000</td>
83
+ <td class="p-3 border-b border-gray-800">745.24 ms</td>
84
+ <td class="p-3 border-b border-gray-800 font-bold text-green-400">611.36 ms</td>
85
+ <td class="p-3 border-b border-gray-800">5107.36 ms</td>
86
+ <td class="p-3 border-b border-gray-800">2.86 ms</td>
87
+ <td class="p-3 border-b border-gray-800">-21.50 MB</td>
88
+ <td class="p-3 border-b border-gray-800">23.89 MB</td>
89
+ <td class="p-3 border-b border-gray-800">Success</td>
90
+ </tr>
91
+
92
+ <tr class="hover:bg-gray-800 transition-colors">
93
+ <td class="p-3 border-b border-gray-800 font-bold">Colossal (100M Params)</td>
94
+ <td class="p-3 border-b border-gray-800 text-blue-400 font-mono">100,100,000</td>
95
+ <td class="p-3 border-b border-gray-800">3200.91 ms</td>
96
+ <td class="p-3 border-b border-gray-800 font-bold text-red-400">3142.55 ms</td>
97
+ <td class="p-3 border-b border-gray-800">87381.14 ms</td>
98
+ <td class="p-3 border-b border-gray-800">516.91 ms</td>
99
+ <td class="p-3 border-b border-gray-800">-25.78 MB</td>
100
+ <td class="p-3 border-b border-gray-800">95.47 MB</td>
101
+ <td class="p-3 border-b border-gray-800">Success</td>
102
+ </tr>
103
+
104
+ </tbody>
105
+ </table>
106
+ </div>
107
+
108
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
109
+ <div class="p-6 bg-gray-900 border-l-4 border-green-500 rounded-r-xl">
110
+ <h3 class="text-xl font-bold text-green-400 mb-2">Phase 5 Successful: GPU Math</h3>
111
+ <p class="text-gray-300 space-y-2">
112
+ We have completely replaced the pure JS Math Engine with <code>@tensorflow/tfjs</code>. Notice that we no longer crash at 100M parameters. Training memory remains stable because tensors are stored outside V8 Heap.
113
+ </p>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </body>
118
+ </html>
119
+
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Activation Functions & Calculus for the Neural Network.
3
+ *
4
+ * This module contains the non-linear activation functions used in the Forward Pass,
5
+ * and their corresponding mathematical derivatives used in Backpropagation (Chain Rule)
6
+ * to calculate the gradients for weight adjustments.
7
+ */
8
+ export declare function sigmoid(x: number): number;
9
+ export declare function dsigmoid(y: number): number;
10
+ export declare function relu(x: number): number;
11
+ export declare function drelu(y: number): number;
12
+ export declare function tanh(x: number): number;
13
+ export declare function dtanh(y: number): number;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ /**
3
+ * Activation Functions & Calculus for the Neural Network.
4
+ *
5
+ * This module contains the non-linear activation functions used in the Forward Pass,
6
+ * and their corresponding mathematical derivatives used in Backpropagation (Chain Rule)
7
+ * to calculate the gradients for weight adjustments.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.sigmoid = sigmoid;
11
+ exports.dsigmoid = dsigmoid;
12
+ exports.relu = relu;
13
+ exports.drelu = drelu;
14
+ exports.tanh = tanh;
15
+ exports.dtanh = dtanh;
16
+ // Sigmoid function: squashes numbers between 0 and 1.
17
+ // Used for probability outputs.
18
+ function sigmoid(x) {
19
+ return 1 / (1 + Math.exp(-x));
20
+ }
21
+ // The derivative of the Sigmoid function.
22
+ // Crucial for calculating the gradient during backpropagation.
23
+ // Math: f'(x) = f(x) * (1 - f(x))
24
+ function dsigmoid(y) {
25
+ // Note: y is already the sigmoid output here.
26
+ return y * (1 - y);
27
+ }
28
+ // ReLU (Rectified Linear Unit) function.
29
+ // Allows the network to learn non-linear patterns faster without the vanishing gradient problem.
30
+ function relu(x) {
31
+ return Math.max(0, x);
32
+ }
33
+ // Derivative of ReLU.
34
+ // Math: 1 if x > 0 else 0
35
+ function drelu(y) {
36
+ return y > 0 ? 1 : 0;
37
+ }
38
+ // Tanh (Hyperbolic Tangent) function.
39
+ // Squashes numbers between -1 and 1. Good for hidden layers.
40
+ function tanh(x) {
41
+ return Math.tanh(x);
42
+ }
43
+ // Derivative of Tanh.
44
+ // Math: 1 - f(x)^2
45
+ function dtanh(y) {
46
+ return 1 - (y * y);
47
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const coordinator_1 = require("./coordinator");
37
+ const client_node_1 = require("./client-node");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ console.log("=== INITIATING BRUTAL BREAK TEST ===");
41
+ const scales = [100, 1000, 5000, 10000, 50000, 100000, 250000, 500000, 1000000];
42
+ const results = [];
43
+ let broken = false;
44
+ // Mock data
45
+ const inputs = [[0, 0], [0, 1], [1, 0], [1, 1]];
46
+ const targets = [[0], [1], [1], [0]];
47
+ for (const scale of scales) {
48
+ if (broken)
49
+ break;
50
+ console.log(`\n--- Testing Scale: ${scale} Clients ---`);
51
+ try {
52
+ // Check if we're approaching V8 memory limit (assuming 1.4GB default)
53
+ const memBefore = process.memoryUsage().heapUsed / 1024 / 1024;
54
+ if (memBefore > 1000) {
55
+ console.log(`⚠️ Dangerously high memory (${memBefore.toFixed(0)} MB). Approaching V8 limit.`);
56
+ }
57
+ const coordinator = new coordinator_1.Coordinator(2, 4, 1);
58
+ const payloads = [];
59
+ // Simulate clients locally without actually instantiating 100,000 full FlockNode classes
60
+ // to save V8 heap overhead (we want to test the Math/Network layer, not Node.js class overhead)
61
+ // Actually, to be brutally honest, we SHOULD instantiate them to see if the browser memory blows up.
62
+ // But in a real scenario, these are distributed across 100,000 different devices.
63
+ // If we instantiate 100,000 on ONE machine, we are testing the machine, not the architecture's scalability.
64
+ // So, we will generate 1 payload, and copy it N times to simulate N inbound websocket requests.
65
+ console.log(`[Edge] Simulating ${scale} device payloads...`);
66
+ const mockNode = new client_node_1.FlockNode(2, 4, 1);
67
+ mockNode.connect('wss://mock');
68
+ const startingWeights = coordinator.getGlobalWeightsForBroadcast();
69
+ mockNode.syncGlobalWeights(startingWeights.weights_ih, startingWeights.weights_ho, startingWeights.bias_h, startingWeights.bias_o);
70
+ mockNode.trainLocalBatch(inputs, targets);
71
+ const basePayload = mockNode.exportSecureGradients();
72
+ // Create an array of references (or actual copies if we want to test server memory)
73
+ // We must test server memory, so we will allocate real memory for incoming arrays.
74
+ let edgeTime = 0;
75
+ const startPayloadGen = performance.now();
76
+ for (let i = 0; i < scale; i++) {
77
+ // In reality, each client takes ~3ms. So edge computation is deeply parallel.
78
+ // We will just record the theoretical parallel time (which is just ~3ms across the globe)
79
+ // and test the SERVER's ability to hold and process them.
80
+ // Simulate unique payload instances arriving in memory
81
+ payloads.push(new Uint8Array(basePayload));
82
+ }
83
+ const endPayloadGen = performance.now();
84
+ const serverMemBefore = process.memoryUsage().heapUsed / 1024 / 1024;
85
+ console.log(`[Server] Memory Usage Before Aggregation: ${serverMemBefore.toFixed(2)} MB`);
86
+ console.log(`[Server] Coordinator receiving ${scale} payloads...`);
87
+ const startReceive = performance.now();
88
+ for (const p of payloads) {
89
+ coordinator.receiveUpdate(p);
90
+ }
91
+ const endReceive = performance.now();
92
+ console.log(`[Server] Running FedAvg on ${scale} matrices...`);
93
+ const startAgg = performance.now();
94
+ coordinator.aggregate();
95
+ const endAgg = performance.now();
96
+ const serverMemAfter = process.memoryUsage().heapUsed / 1024 / 1024;
97
+ const timeTaken = (endAgg - startReceive);
98
+ console.log(`✅ Success for ${scale} clients. Time: ${timeTaken.toFixed(2)}ms`);
99
+ results.push({
100
+ scale,
101
+ payloadSizeKB: (scale * basePayload.length) / 1024,
102
+ receiveTime: (endReceive - startReceive),
103
+ aggTime: (endAgg - startAgg),
104
+ totalTime: timeTaken,
105
+ memBefore: serverMemBefore,
106
+ memAfter: serverMemAfter,
107
+ status: 'Success'
108
+ });
109
+ // Artificially break if processing takes longer than 5 seconds (real-time websocket timeout)
110
+ if (timeTaken > 5000) {
111
+ console.log(`❌ BROKEN: Server aggregation took ${timeTaken.toFixed(2)}ms (Exceeded 5000ms timeout)`);
112
+ broken = true;
113
+ results[results.length - 1].status = 'Broken: Latency Timeout (>5s)';
114
+ }
115
+ // Force garbage collection if available
116
+ if (global.gc)
117
+ global.gc();
118
+ }
119
+ catch (err) {
120
+ console.log(`❌ BROKEN at ${scale} clients: ${err.message}`);
121
+ broken = true;
122
+ results.push({
123
+ scale,
124
+ payloadSizeKB: 0,
125
+ receiveTime: 0,
126
+ aggTime: 0,
127
+ totalTime: 0,
128
+ memBefore: 0,
129
+ memAfter: 0,
130
+ status: `Broken: ${err.message}`
131
+ });
132
+ }
133
+ }
134
+ // Generate HTML Report
135
+ const htmlPath = path.resolve(process.cwd(), 'stress-report.html');
136
+ const rows = results.map(r => `
137
+ <tr class="${r.status.includes('Broken') ? 'bg-red-900/50 text-red-200' : 'hover:bg-gray-800 transition-colors'}">
138
+ <td class="p-3 border-b border-gray-800 font-mono text-blue-400">${r.scale.toLocaleString()}</td>
139
+ <td class="p-3 border-b border-gray-800">${r.payloadSizeKB.toFixed(2)} KB</td>
140
+ <td class="p-3 border-b border-gray-800">${r.receiveTime.toFixed(2)} ms</td>
141
+ <td class="p-3 border-b border-gray-800">${r.aggTime.toFixed(2)} ms</td>
142
+ <td class="p-3 border-b border-gray-800 font-bold ${r.totalTime > 2000 ? 'text-yellow-400' : 'text-green-400'}">${r.totalTime.toFixed(2)} ms</td>
143
+ <td class="p-3 border-b border-gray-800">${r.memAfter.toFixed(2)} MB</td>
144
+ <td class="p-3 border-b border-gray-800">${r.status}</td>
145
+ </tr>
146
+ `).join('');
147
+ const htmlContent = `
148
+ <!DOCTYPE html>
149
+ <html lang="en">
150
+ <head>
151
+ <meta charset="UTF-8">
152
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
153
+ <title>FlockML Brutal Break Test Report</title>
154
+ <script src="https://cdn.tailwindcss.com"></script>
155
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
156
+ </head>
157
+ <body class="bg-gray-950 text-gray-100 p-8 font-sans">
158
+ <div class="max-w-6xl mx-auto">
159
+ <h1 class="text-4xl font-bold mb-2 bg-gradient-to-r from-red-500 to-orange-500 bg-clip-text text-transparent">FlockML V2 Brutal Break Test</h1>
160
+ <p class="text-gray-400 mb-8">Pushing the Central Coordinator Server to its absolute limits until architecture failure.</p>
161
+
162
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8">
163
+ <div class="bg-gray-900 border border-gray-800 rounded-xl p-6 shadow-2xl">
164
+ <h2 class="text-xl font-semibold mb-4 text-gray-200">Server Latency (FedAvg + Protobuf)</h2>
165
+ <canvas id="latencyChart"></canvas>
166
+ </div>
167
+ <div class="bg-gray-900 border border-gray-800 rounded-xl p-6 shadow-2xl">
168
+ <h2 class="text-xl font-semibold mb-4 text-gray-200">Server Heap Memory Usage</h2>
169
+ <canvas id="memoryChart"></canvas>
170
+ </div>
171
+ </div>
172
+
173
+ <div class="bg-gray-900 border border-gray-800 rounded-xl overflow-hidden shadow-2xl">
174
+ <table class="w-full text-left border-collapse">
175
+ <thead>
176
+ <tr class="bg-gray-950 text-gray-400 text-sm uppercase tracking-wider">
177
+ <th class="p-4 border-b border-gray-800">Concurrent Clients</th>
178
+ <th class="p-4 border-b border-gray-800">Total Bandwidth</th>
179
+ <th class="p-4 border-b border-gray-800">Protobuf Decode</th>
180
+ <th class="p-4 border-b border-gray-800">FedAvg Compute</th>
181
+ <th class="p-4 border-b border-gray-800">Total Server Delay</th>
182
+ <th class="p-4 border-b border-gray-800">Heap Memory</th>
183
+ <th class="p-4 border-b border-gray-800">System Status</th>
184
+ </tr>
185
+ </thead>
186
+ <tbody>
187
+ ${rows}
188
+ </tbody>
189
+ </table>
190
+ </div>
191
+
192
+ <div class="mt-8 p-6 bg-gray-900 border-l-4 border-blue-500 rounded-r-xl">
193
+ <h3 class="text-lg font-bold text-blue-400 mb-2">Architectural Conclusion</h3>
194
+ <p class="text-gray-300">
195
+ This test simulates extreme real-world thundering herd conditions. The breaking point indicates where the single-threaded Node.js Coordinator reaches hardware limits. To scale beyond the breaking point, horizontal scaling (Load Balancers + Redis pub/sub) or migrating the backend math to PyTorch (C++) is required.
196
+ </p>
197
+ </div>
198
+ </div>
199
+
200
+ <script>
201
+ const data = ${JSON.stringify(results)};
202
+ const labels = data.map(d => d.scale.toLocaleString());
203
+
204
+ // Latency Chart
205
+ new Chart(document.getElementById('latencyChart'), {
206
+ type: 'line',
207
+ data: {
208
+ labels,
209
+ datasets: [{
210
+ label: 'Total Delay (ms)',
211
+ data: data.map(d => d.totalTime),
212
+ borderColor: '#3b82f6',
213
+ backgroundColor: 'rgba(59, 130, 246, 0.1)',
214
+ borderWidth: 2,
215
+ fill: true,
216
+ tension: 0.4
217
+ }]
218
+ },
219
+ options: {
220
+ responsive: true,
221
+ scales: { y: { beginAtZero: true, grid: { color: '#1f2937' } }, x: { grid: { color: '#1f2937' } } },
222
+ plugins: { legend: { display: false } }
223
+ }
224
+ });
225
+
226
+ // Memory Chart
227
+ new Chart(document.getElementById('memoryChart'), {
228
+ type: 'bar',
229
+ data: {
230
+ labels,
231
+ datasets: [{
232
+ label: 'Heap Usage (MB)',
233
+ data: data.map(d => d.memAfter),
234
+ backgroundColor: '#f97316',
235
+ borderRadius: 4
236
+ }]
237
+ },
238
+ options: {
239
+ responsive: true,
240
+ scales: { y: { beginAtZero: true, grid: { color: '#1f2937' } }, x: { grid: { color: '#1f2937' } } },
241
+ plugins: { legend: { display: false } }
242
+ }
243
+ });
244
+ </script>
245
+ </body>
246
+ </html>
247
+ `;
248
+ fs.writeFileSync(htmlPath, htmlContent);
249
+ console.log(`\n✅ HTML Report generated at: ${htmlPath}`);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const coordinator_1 = require("./coordinator");
37
+ const client_node_1 = require("./client-node");
38
+ console.log("=== FLOCKML V2 BRUTAL STRESS TEST ===");
39
+ // 1. Initialize Central Coordinator
40
+ const coordinator = new coordinator_1.Coordinator(2, 4, 1);
41
+ console.log("\n[Server] Initialized FedAvg Coordinator.");
42
+ const startingWeights = coordinator.getGlobalWeightsForBroadcast();
43
+ const NUM_CLIENTS = 100;
44
+ const NUM_ATTACKERS = 5;
45
+ console.log(`\n[Network] Spinning up ${NUM_CLIENTS} simulated FlockNodes...`);
46
+ const clients = [];
47
+ for (let i = 0; i < NUM_CLIENTS; i++) {
48
+ const node = new client_node_1.FlockNode(2, 4, 1);
49
+ node.connect('wss://mock.network');
50
+ node.syncGlobalWeights(startingWeights.weights_ih, startingWeights.weights_ho, startingWeights.bias_h, startingWeights.bias_o);
51
+ clients.push(node);
52
+ }
53
+ console.log(`[Network] Initiating local training on all ${NUM_CLIENTS} devices...`);
54
+ const inputs = [[0, 0], [0, 1], [1, 0], [1, 1]];
55
+ const targets = [[0], [1], [1], [0]];
56
+ // 2. Train all nodes
57
+ let start = performance.now();
58
+ for (const client of clients) {
59
+ // Train locally
60
+ client.trainLocalBatch(inputs, targets);
61
+ }
62
+ let end = performance.now();
63
+ console.log(`[Edge] Training complete. Time taken: ${(end - start).toFixed(2)}ms`);
64
+ // 3. Sybil Attack Injection
65
+ console.log(`\n[Attack] Injecting ${NUM_ATTACKERS} Sybil Attacks (Data Poisoning)...`);
66
+ const tf = __importStar(require("@tensorflow/tfjs-core"));
67
+ for (let i = 0; i < NUM_ATTACKERS; i++) {
68
+ // We manually corrupt the weights to mimic a malicious actor modifying the browser memory
69
+ const shape_ih = clients[i].network.weights_ih.shape;
70
+ clients[i].network.weights_ih.assign(tf.fill(shape_ih, NaN));
71
+ const shape_ho = clients[i].network.weights_ho.shape;
72
+ clients[i].network.weights_ho.assign(tf.fill(shape_ho, Infinity));
73
+ }
74
+ // 4. Secure, Quantize, and Serialize
75
+ start = performance.now();
76
+ const payloads = [];
77
+ let totalBytes = 0;
78
+ for (const client of clients) {
79
+ client.privacyEpsilon = 1.0;
80
+ const binaryPayload = client.exportSecureGradients();
81
+ payloads.push(binaryPayload);
82
+ totalBytes += binaryPayload.length;
83
+ }
84
+ end = performance.now();
85
+ console.log(`[Edge] Quantization & Protobuf Encoding complete. Time taken: ${(end - start).toFixed(2)}ms`);
86
+ console.log(`[Network] Total Payload Size for ${NUM_CLIENTS} nodes: ${(totalBytes / 1024).toFixed(2)} KB (Avg: ${(totalBytes / NUM_CLIENTS).toFixed(0)} bytes/node)`);
87
+ // 5. Server Aggregation
88
+ console.log("\n[Server] Receiving 100 Encrypted Binary Payloads...");
89
+ const oldWeight = coordinator.globalModel.weights_ih.dataSync()[0];
90
+ start = performance.now();
91
+ for (const payload of payloads) {
92
+ coordinator.receiveUpdate(payload);
93
+ }
94
+ console.log("[Server] Running Federated Averaging (FedAvg) + Anomaly Detection...");
95
+ coordinator.aggregate();
96
+ end = performance.now();
97
+ const newWeight = coordinator.globalModel.weights_ih.dataSync()[0];
98
+ console.log(`\n=== STRESS TEST RESULTS ===`);
99
+ console.log(`Server Processing Time: ${(end - start).toFixed(2)}ms`);
100
+ console.log(`Global Weight Before: ${oldWeight.toFixed(4)}`);
101
+ console.log(`Global Weight After: ${newWeight.toFixed(4)}`);
102
+ console.log(`Weight Delta: ${(newWeight - oldWeight).toFixed(4)}`);
103
+ if (Number.isNaN(newWeight) || !Number.isFinite(newWeight)) {
104
+ console.log("\n❌ FAILED: The global model was destroyed by the Sybil Attack.");
105
+ process.exit(1);
106
+ }
107
+ else {
108
+ console.log("\n✅ SUCCESS: The global model survived the Sybil attack and successfully aggregated the honest gradients!");
109
+ }
110
+ // Cleanup Web Workers to prevent hanging
111
+ for (const client of clients) {
112
+ client.destroy();
113
+ }
@@ -0,0 +1,48 @@
1
+ import { NeuralNetwork } from './network';
2
+ import { QuantizedPayload } from './quantization';
3
+ import { WorkerManager } from './worker';
4
+ import * as tf from '@tensorflow/tfjs';
5
+ /**
6
+ * The FlockML Client Node.
7
+ *
8
+ * Powered by TFJS. It encapsulates the neural network, the privacy engine, and the quantization engine.
9
+ * In a full production build, this entire class would be serialized into a Blob
10
+ * and executed inside a background Web Worker to keep the UI at 60fps.
11
+ */
12
+ export declare class FlockNode {
13
+ network: NeuralNetwork;
14
+ isConnected: boolean;
15
+ isTraining: boolean;
16
+ privacyEpsilon: number;
17
+ workerManager: WorkerManager;
18
+ dynamicBatchSize: number;
19
+ error_ih?: tf.Tensor2D;
20
+ error_ho?: tf.Tensor2D;
21
+ error_bh?: tf.Tensor2D;
22
+ error_bo?: tf.Tensor2D;
23
+ constructor(inputNodes?: number, hiddenNodes?: number, outputNodes?: number);
24
+ /**
25
+ * Connects to the central FedAvg Coordinator.
26
+ */
27
+ connect(websocketUrl: string): void;
28
+ /**
29
+ * Receives the latest global model from the server.
30
+ */
31
+ syncGlobalWeights(qWeightsIH: QuantizedPayload, qWeightsHO: QuantizedPayload, qBiasH: QuantizedPayload, qBiasO: QuantizedPayload): void;
32
+ /**
33
+ * Performs one local training epoch on a batch of data.
34
+ */
35
+ trainLocalBatch(inputs: number[][], targets: number[][]): void;
36
+ /**
37
+ * Cleans up background threads.
38
+ */
39
+ destroy(): void;
40
+ /**
41
+ * Helper function to map our payload into the protobuf format
42
+ */
43
+ private mapToProto;
44
+ /**
45
+ * Secures, compresses, and binary-serializes the newly trained weights.
46
+ */
47
+ exportSecureGradients(): Uint8Array;
48
+ }