solana-web3-on-steroids 1.0.6 → 1.0.7
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/README.md +3 -38
- package/docs/assets/architecture-diagram.svg +293 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,44 +43,9 @@ Intercepts simulation logs and translates raw program errors into human-readable
|
|
|
43
43
|
|
|
44
44
|

|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```mermaid
|
|
50
|
-
graph TD
|
|
51
|
-
subgraph "Application Layer"
|
|
52
|
-
App[Your dApp]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
subgraph "Steroids Resilience Layer"
|
|
56
|
-
Client[SteroidClient]
|
|
57
|
-
Conn[SteroidConnection Proxy]
|
|
58
|
-
Tx[SteroidTransaction Engine]
|
|
59
|
-
Wallet[SteroidWallet Wrapper]
|
|
60
|
-
|
|
61
|
-
Client --> Conn
|
|
62
|
-
Client --> Tx
|
|
63
|
-
Client --> Wallet
|
|
64
|
-
|
|
65
|
-
Tx -.-> Conn
|
|
66
|
-
Wallet -.-> Tx
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
subgraph "Infrastucture Layer (RPC)"
|
|
70
|
-
Primary[Primary RPC Node]
|
|
71
|
-
F1[Fallback Node 1]
|
|
72
|
-
F2[Fallback Node 2]
|
|
73
|
-
CNodes[Confirmation Nodes]
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
App --> Client
|
|
77
|
-
Conn -- "Health Checks & Failover" --> Primary
|
|
78
|
-
Conn -- "Automatic Swap" --> F1
|
|
79
|
-
Conn -- "Automatic Swap" --> F2
|
|
80
|
-
Tx -- "Re-broadcasting" --> Primary
|
|
81
|
-
Tx -- "Multi-node Polling" --> CNodes
|
|
82
|
-
```
|
|
83
|
-
<!-- END_TECHNICAL_DIAGRAM -->
|
|
46
|
+
### Technical Resilience Flow
|
|
47
|
+
|
|
48
|
+

|
|
84
49
|
|
|
85
50
|
---
|
|
86
51
|
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
<svg viewBox="0 0 1400 900" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<!-- Gradients -->
|
|
4
|
+
<linearGradient id="appGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
5
|
+
<stop offset="0%" style="stop-color:#667eea;stop-opacity:1" />
|
|
6
|
+
<stop offset="100%" style="stop-color:#764ba2;stop-opacity:1" />
|
|
7
|
+
</linearGradient>
|
|
8
|
+
|
|
9
|
+
<linearGradient id="steroidsGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
10
|
+
<stop offset="0%" style="stop-color:#9945FF;stop-opacity:1" />
|
|
11
|
+
<stop offset="100%" style="stop-color:#14F195;stop-opacity:1" />
|
|
12
|
+
</linearGradient>
|
|
13
|
+
|
|
14
|
+
<linearGradient id="infraGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
15
|
+
<stop offset="0%" style="stop-color:#f093fb;stop-opacity:1" />
|
|
16
|
+
<stop offset="100%" style="stop-color:#f5576c;stop-opacity:1" />
|
|
17
|
+
</linearGradient>
|
|
18
|
+
|
|
19
|
+
<!-- Arrow markers -->
|
|
20
|
+
<marker id="arrowSolid" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
21
|
+
<polygon points="0 0, 10 3, 0 6" fill="#333333"/>
|
|
22
|
+
</marker>
|
|
23
|
+
|
|
24
|
+
<marker id="arrowDashed" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
25
|
+
<polygon points="0 0, 10 3, 0 6" fill="#666666"/>
|
|
26
|
+
</marker>
|
|
27
|
+
|
|
28
|
+
<marker id="arrowGreen" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
29
|
+
<polygon points="0 0, 10 3, 0 6" fill="#14F195"/>
|
|
30
|
+
</marker>
|
|
31
|
+
|
|
32
|
+
<marker id="arrowPurple" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
33
|
+
<polygon points="0 0, 10 3, 0 6" fill="#9945FF"/>
|
|
34
|
+
</marker>
|
|
35
|
+
|
|
36
|
+
<!-- Drop shadow -->
|
|
37
|
+
<filter id="shadow" x="-50%" y="-50%" width="200%" height="200%">
|
|
38
|
+
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
|
|
39
|
+
<feOffset dx="0" dy="2" result="offsetblur"/>
|
|
40
|
+
<feComponentTransfer>
|
|
41
|
+
<feFuncA type="linear" slope="0.2"/>
|
|
42
|
+
</feComponentTransfer>
|
|
43
|
+
<feMerge>
|
|
44
|
+
<feMergeNode/>
|
|
45
|
+
<feMergeNode in="SourceGraphic"/>
|
|
46
|
+
</feMerge>
|
|
47
|
+
</filter>
|
|
48
|
+
|
|
49
|
+
<!-- Glow effect -->
|
|
50
|
+
<filter id="glow">
|
|
51
|
+
<feGaussianBlur stdDeviation="2" result="coloredBlur"/>
|
|
52
|
+
<feMerge>
|
|
53
|
+
<feMergeNode in="coloredBlur"/>
|
|
54
|
+
<feMergeNode in="SourceGraphic"/>
|
|
55
|
+
</feMerge>
|
|
56
|
+
</filter>
|
|
57
|
+
</defs>
|
|
58
|
+
|
|
59
|
+
<!-- Background -->
|
|
60
|
+
<rect width="1400" height="900" fill="#F8FAFC"/>
|
|
61
|
+
|
|
62
|
+
<!-- Grid pattern -->
|
|
63
|
+
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
|
|
64
|
+
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#E2E8F0" stroke-width="1" opacity="0.5"/>
|
|
65
|
+
</pattern>
|
|
66
|
+
<rect width="1400" height="900" fill="url(#grid)"/>
|
|
67
|
+
|
|
68
|
+
<!-- ==================== APPLICATION LAYER ==================== -->
|
|
69
|
+
<g id="application-layer">
|
|
70
|
+
<!-- Layer background -->
|
|
71
|
+
<rect x="50" y="50" width="1300" height="150" rx="16" fill="#FFFFFF" stroke="url(#appGrad)" stroke-width="3" opacity="0.1"/>
|
|
72
|
+
<rect x="50" y="50" width="1300" height="150" rx="16" fill="none" stroke="url(#appGrad)" stroke-width="3"/>
|
|
73
|
+
|
|
74
|
+
<!-- Layer title -->
|
|
75
|
+
<text x="70" y="85" font-family="'SF Pro Display', system-ui, sans-serif" font-size="18" font-weight="700" fill="url(#appGrad)">
|
|
76
|
+
Application Layer
|
|
77
|
+
</text>
|
|
78
|
+
|
|
79
|
+
<!-- App node -->
|
|
80
|
+
<g id="app-node" filter="url(#shadow)">
|
|
81
|
+
<rect x="550" y="110" width="300" height="70" rx="12" fill="#FFFFFF" stroke="#667eea" stroke-width="3"/>
|
|
82
|
+
<text x="700" y="145" font-family="'SF Pro Display', system-ui, sans-serif" font-size="20" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
83
|
+
Your dApp
|
|
84
|
+
</text>
|
|
85
|
+
<text x="700" y="165" font-family="'SF Pro Text', system-ui, sans-serif" font-size="12" fill="#64748B" text-anchor="middle">
|
|
86
|
+
Application Code
|
|
87
|
+
</text>
|
|
88
|
+
</g>
|
|
89
|
+
</g>
|
|
90
|
+
|
|
91
|
+
<!-- ==================== STEROIDS RESILIENCE LAYER ==================== -->
|
|
92
|
+
<g id="steroids-layer">
|
|
93
|
+
<!-- Layer background -->
|
|
94
|
+
<rect x="50" y="250" width="1300" height="380" rx="16" fill="#FFFFFF" stroke="url(#steroidsGrad)" stroke-width="3" opacity="0.1"/>
|
|
95
|
+
<rect x="50" y="250" width="1300" height="380" rx="16" fill="none" stroke="url(#steroidsGrad)" stroke-width="3"/>
|
|
96
|
+
|
|
97
|
+
<!-- Layer title -->
|
|
98
|
+
<text x="70" y="285" font-family="'SF Pro Display', system-ui, sans-serif" font-size="18" font-weight="700" fill="url(#steroidsGrad)">
|
|
99
|
+
Steroids Resilience Layer
|
|
100
|
+
</text>
|
|
101
|
+
|
|
102
|
+
<!-- SteroidClient -->
|
|
103
|
+
<g id="client-node" filter="url(#shadow)">
|
|
104
|
+
<rect x="550" y="320" width="300" height="70" rx="12" fill="#FFFFFF" stroke="#9945FF" stroke-width="3"/>
|
|
105
|
+
<circle cx="575" cy="355" r="6" fill="#9945FF" filter="url(#glow)"/>
|
|
106
|
+
<text x="700" y="350" font-family="'SF Pro Display', system-ui, sans-serif" font-size="18" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
107
|
+
SteroidClient
|
|
108
|
+
</text>
|
|
109
|
+
<text x="700" y="370" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" text-anchor="middle">
|
|
110
|
+
Main Entry Point
|
|
111
|
+
</text>
|
|
112
|
+
</g>
|
|
113
|
+
|
|
114
|
+
<!-- SteroidConnection Proxy -->
|
|
115
|
+
<g id="conn-node" filter="url(#shadow)">
|
|
116
|
+
<rect x="100" y="450" width="280" height="70" rx="12" fill="#FFFFFF" stroke="#14F195" stroke-width="3"/>
|
|
117
|
+
<circle cx="125" cy="485" r="6" fill="#14F195" filter="url(#glow)"/>
|
|
118
|
+
<text x="240" y="480" font-family="'SF Pro Display', system-ui, sans-serif" font-size="17" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
119
|
+
SteroidConnection
|
|
120
|
+
</text>
|
|
121
|
+
<text x="240" y="500" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" text-anchor="middle">
|
|
122
|
+
Proxy Pattern
|
|
123
|
+
</text>
|
|
124
|
+
</g>
|
|
125
|
+
|
|
126
|
+
<!-- SteroidTransaction Engine -->
|
|
127
|
+
<g id="tx-node" filter="url(#shadow)">
|
|
128
|
+
<rect x="440" y="450" width="280" height="70" rx="12" fill="#FFFFFF" stroke="#FF6B9D" stroke-width="3"/>
|
|
129
|
+
<circle cx="465" cy="485" r="6" fill="#FF6B9D" filter="url(#glow)"/>
|
|
130
|
+
<text x="580" y="480" font-family="'SF Pro Display', system-ui, sans-serif" font-size="17" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
131
|
+
SteroidTransaction
|
|
132
|
+
</text>
|
|
133
|
+
<text x="580" y="500" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" text-anchor="middle">
|
|
134
|
+
Submission Engine
|
|
135
|
+
</text>
|
|
136
|
+
</g>
|
|
137
|
+
|
|
138
|
+
<!-- SteroidWallet Wrapper -->
|
|
139
|
+
<g id="wallet-node" filter="url(#shadow)">
|
|
140
|
+
<rect x="780" y="450" width="280" height="70" rx="12" fill="#FFFFFF" stroke="#FFA500" stroke-width="3"/>
|
|
141
|
+
<circle cx="805" cy="485" r="6" fill="#FFA500" filter="url(#glow)"/>
|
|
142
|
+
<text x="920" y="480" font-family="'SF Pro Display', system-ui, sans-serif" font-size="17" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
143
|
+
SteroidWallet
|
|
144
|
+
</text>
|
|
145
|
+
<text x="920" y="500" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" text-anchor="middle">
|
|
146
|
+
Wallet Wrapper
|
|
147
|
+
</text>
|
|
148
|
+
</g>
|
|
149
|
+
|
|
150
|
+
<!-- Internal connections within Steroids layer -->
|
|
151
|
+
<!-- Client to Connection -->
|
|
152
|
+
<path d="M 650 390 L 300 450" stroke="#333333" stroke-width="2.5" fill="none" marker-end="url(#arrowSolid)"/>
|
|
153
|
+
|
|
154
|
+
<!-- Client to Transaction -->
|
|
155
|
+
<path d="M 670 390 L 600 450" stroke="#333333" stroke-width="2.5" fill="none" marker-end="url(#arrowSolid)"/>
|
|
156
|
+
|
|
157
|
+
<!-- Client to Wallet -->
|
|
158
|
+
<path d="M 750 390 L 880 450" stroke="#333333" stroke-width="2.5" fill="none" marker-end="url(#arrowSolid)"/>
|
|
159
|
+
|
|
160
|
+
<!-- Transaction to Connection (dashed) -->
|
|
161
|
+
<path d="M 520 450 L 340 480" stroke="#666666" stroke-width="2" fill="none" stroke-dasharray="8,4" marker-end="url(#arrowDashed)"/>
|
|
162
|
+
|
|
163
|
+
<!-- Wallet to Transaction (dashed) -->
|
|
164
|
+
<path d="M 820 450 L 670 470" stroke="#666666" stroke-width="2" fill="none" stroke-dasharray="8,4" marker-end="url(#arrowDashed)"/>
|
|
165
|
+
</g>
|
|
166
|
+
|
|
167
|
+
<!-- ==================== INFRASTRUCTURE LAYER (RPC) ==================== -->
|
|
168
|
+
<g id="infra-layer">
|
|
169
|
+
<!-- Layer background -->
|
|
170
|
+
<rect x="50" y="680" width="1300" height="170" rx="16" fill="#FFFFFF" stroke="url(#infraGrad)" stroke-width="3" opacity="0.1"/>
|
|
171
|
+
<rect x="50" y="680" width="1300" height="170" rx="16" fill="none" stroke="url(#infraGrad)" stroke-width="3"/>
|
|
172
|
+
|
|
173
|
+
<!-- Layer title -->
|
|
174
|
+
<text x="70" y="715" font-family="'SF Pro Display', system-ui, sans-serif" font-size="18" font-weight="700" fill="url(#infraGrad)">
|
|
175
|
+
Infrastructure Layer (RPC)
|
|
176
|
+
</text>
|
|
177
|
+
|
|
178
|
+
<!-- Primary RPC Node -->
|
|
179
|
+
<g id="primary-node" filter="url(#shadow)">
|
|
180
|
+
<rect x="120" y="750" width="240" height="70" rx="12" fill="#FFFFFF" stroke="#10B981" stroke-width="3"/>
|
|
181
|
+
<circle cx="145" cy="785" r="7" fill="#10B981" filter="url(#glow)"/>
|
|
182
|
+
<text x="240" y="780" font-family="'SF Pro Display', system-ui, sans-serif" font-size="16" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
183
|
+
Primary RPC Node
|
|
184
|
+
</text>
|
|
185
|
+
<text x="240" y="800" font-family="'SF Mono', monospace" font-size="10" fill="#64748B" text-anchor="middle">
|
|
186
|
+
Active
|
|
187
|
+
</text>
|
|
188
|
+
</g>
|
|
189
|
+
|
|
190
|
+
<!-- Fallback Node 1 -->
|
|
191
|
+
<g id="fallback1-node" filter="url(#shadow)">
|
|
192
|
+
<rect x="400" y="750" width="240" height="70" rx="12" fill="#FFFFFF" stroke="#3B82F6" stroke-width="3"/>
|
|
193
|
+
<circle cx="425" cy="785" r="7" fill="#3B82F6" filter="url(#glow)"/>
|
|
194
|
+
<text x="520" y="780" font-family="'SF Pro Display', system-ui, sans-serif" font-size="16" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
195
|
+
Fallback Node 1
|
|
196
|
+
</text>
|
|
197
|
+
<text x="520" y="800" font-family="'SF Mono', monospace" font-size="10" fill="#64748B" text-anchor="middle">
|
|
198
|
+
Standby
|
|
199
|
+
</text>
|
|
200
|
+
</g>
|
|
201
|
+
|
|
202
|
+
<!-- Fallback Node 2 -->
|
|
203
|
+
<g id="fallback2-node" filter="url(#shadow)">
|
|
204
|
+
<rect x="680" y="750" width="240" height="70" rx="12" fill="#FFFFFF" stroke="#3B82F6" stroke-width="3"/>
|
|
205
|
+
<circle cx="705" cy="785" r="7" fill="#3B82F6" filter="url(#glow)"/>
|
|
206
|
+
<text x="800" y="780" font-family="'SF Pro Display', system-ui, sans-serif" font-size="16" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
207
|
+
Fallback Node 2
|
|
208
|
+
</text>
|
|
209
|
+
<text x="800" y="800" font-family="'SF Mono', monospace" font-size="10" fill="#64748B" text-anchor="middle">
|
|
210
|
+
Standby
|
|
211
|
+
</text>
|
|
212
|
+
</g>
|
|
213
|
+
|
|
214
|
+
<!-- Confirmation Nodes -->
|
|
215
|
+
<g id="confirm-nodes" filter="url(#shadow)">
|
|
216
|
+
<rect x="960" y="750" width="240" height="70" rx="12" fill="#FFFFFF" stroke="#F59E0B" stroke-width="3"/>
|
|
217
|
+
<circle cx="985" cy="785" r="7" fill="#F59E0B" filter="url(#glow)"/>
|
|
218
|
+
<text x="1080" y="780" font-family="'SF Pro Display', system-ui, sans-serif" font-size="16" font-weight="700" fill="#1E293B" text-anchor="middle">
|
|
219
|
+
Confirmation Nodes
|
|
220
|
+
</text>
|
|
221
|
+
<text x="1080" y="800" font-family="'SF Mono', monospace" font-size="10" fill="#64748B" text-anchor="middle">
|
|
222
|
+
Multi-node Polling
|
|
223
|
+
</text>
|
|
224
|
+
</g>
|
|
225
|
+
</g>
|
|
226
|
+
|
|
227
|
+
<!-- ==================== CROSS-LAYER CONNECTIONS ==================== -->
|
|
228
|
+
|
|
229
|
+
<!-- App to Client -->
|
|
230
|
+
<path d="M 700 180 L 700 320" stroke="#667eea" stroke-width="3" fill="none" marker-end="url(#arrowPurple)"/>
|
|
231
|
+
|
|
232
|
+
<!-- Connection to Primary (Health Checks & Failover) -->
|
|
233
|
+
<path d="M 240 520 L 240 750" stroke="#14F195" stroke-width="2.5" fill="none" marker-end="url(#arrowGreen)"/>
|
|
234
|
+
<text x="250" y="640" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" font-weight="600">
|
|
235
|
+
Health Checks
|
|
236
|
+
</text>
|
|
237
|
+
<text x="250" y="655" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" font-weight="600">
|
|
238
|
+
& Failover
|
|
239
|
+
</text>
|
|
240
|
+
|
|
241
|
+
<!-- Connection to Fallback 1 (Automatic Swap) -->
|
|
242
|
+
<path d="M 320 520 L 480 750" stroke="#3B82F6" stroke-width="2" fill="none" stroke-dasharray="8,4" marker-end="url(#arrowSolid)"/>
|
|
243
|
+
<text x="350" y="650" font-family="'SF Pro Text', system-ui, sans-serif" font-size="10" fill="#64748B" font-style="italic">
|
|
244
|
+
Automatic Swap
|
|
245
|
+
</text>
|
|
246
|
+
|
|
247
|
+
<!-- Connection to Fallback 2 (Automatic Swap) -->
|
|
248
|
+
<path d="M 340 520 L 720 750" stroke="#3B82F6" stroke-width="2" fill="none" stroke-dasharray="8,4" marker-end="url(#arrowSolid)"/>
|
|
249
|
+
|
|
250
|
+
<!-- Transaction to Primary (Re-broadcasting) -->
|
|
251
|
+
<path d="M 520 520 L 280 750" stroke="#FF6B9D" stroke-width="2.5" fill="none" marker-end="url(#arrowSolid)"/>
|
|
252
|
+
<text x="340" y="640" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" font-weight="600">
|
|
253
|
+
Re-broadcasting
|
|
254
|
+
</text>
|
|
255
|
+
|
|
256
|
+
<!-- Transaction to Confirmation Nodes (Multi-node Polling) -->
|
|
257
|
+
<path d="M 650 520 L 1050 750" stroke="#F59E0B" stroke-width="2.5" fill="none" marker-end="url(#arrowSolid)"/>
|
|
258
|
+
<text x="820" y="640" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B" font-weight="600">
|
|
259
|
+
Multi-node Polling
|
|
260
|
+
</text>
|
|
261
|
+
|
|
262
|
+
<!-- Legend -->
|
|
263
|
+
<g id="legend">
|
|
264
|
+
<rect x="1120" y="320" width="220" height="140" rx="10" fill="#FFFFFF" stroke="#CBD5E1" stroke-width="2" filter="url(#shadow)"/>
|
|
265
|
+
<text x="1140" y="345" font-family="'SF Pro Display', system-ui, sans-serif" font-size="13" font-weight="700" fill="#1E293B">
|
|
266
|
+
Legend
|
|
267
|
+
</text>
|
|
268
|
+
|
|
269
|
+
<!-- Solid arrow -->
|
|
270
|
+
<line x1="1140" y1="365" x2="1180" y2="365" stroke="#333333" stroke-width="2.5" marker-end="url(#arrowSolid)"/>
|
|
271
|
+
<text x="1190" y="370" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B">
|
|
272
|
+
Direct connection
|
|
273
|
+
</text>
|
|
274
|
+
|
|
275
|
+
<!-- Dashed arrow -->
|
|
276
|
+
<line x1="1140" y1="390" x2="1180" y2="390" stroke="#666666" stroke-width="2" stroke-dasharray="8,4" marker-end="url(#arrowDashed)"/>
|
|
277
|
+
<text x="1190" y="395" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B">
|
|
278
|
+
Internal reference
|
|
279
|
+
</text>
|
|
280
|
+
|
|
281
|
+
<!-- Active indicator -->
|
|
282
|
+
<circle cx="1150" cy="415" r="5" fill="#10B981"/>
|
|
283
|
+
<text x="1165" y="420" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B">
|
|
284
|
+
Active node
|
|
285
|
+
</text>
|
|
286
|
+
|
|
287
|
+
<!-- Standby indicator -->
|
|
288
|
+
<circle cx="1150" cy="440" r="5" fill="#3B82F6"/>
|
|
289
|
+
<text x="1165" y="445" font-family="'SF Pro Text', system-ui, sans-serif" font-size="11" fill="#64748B">
|
|
290
|
+
Standby node
|
|
291
|
+
</text>
|
|
292
|
+
</g>
|
|
293
|
+
</svg>
|