blockyard 0.0.9 → 0.1.1
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/CHANGELOG.md +359 -1
- package/README.md +48 -27
- package/SECURITY.md +2 -2
- package/bin/blockyard.js +2 -1
- package/docs/API.md +17 -15
- package/docs/ARCHITECTURE.md +128 -10
- package/docs/CONFIGURATION.md +39 -30
- package/docs/DEFECTS.md +4 -1
- package/docs/GETTING-STARTED.md +18 -8
- package/docs/INSTALL.md +97 -37
- package/docs/MEASUREMENTS.md +147 -0
- package/docs/PLAN-SCORCHED-YARD.md +456 -0
- package/docs/PLAN-SKIES.md +142 -0
- package/docs/SECURITY-AUDIT-2026-09-16.md +647 -0
- package/docs/SECURITY.md +58 -22
- package/docs/TROUBLESHOOTING.md +44 -5
- package/docs/USER-GUIDE.md +505 -35
- package/package.json +4 -2
- package/public/404.html +1 -1
- package/public/css/app.css +393 -82
- package/public/donate-qr.png +0 -0
- package/public/index.html +353 -109
- package/public/js/agents.js +228 -51
- package/public/js/app.js +131 -16
- package/public/js/blockanoid.js +15 -7
- package/public/js/blockout.js +15 -7
- package/public/js/blockscene3d.js +230 -38
- package/public/js/charts.js +21 -21
- package/public/js/depthchart.js +31 -27
- package/public/js/details3d.js +1481 -73
- package/public/js/doom.js +31 -0
- package/public/js/dosaudio.js +48 -0
- package/public/js/dosgame.js +389 -0
- package/public/js/dosio.js +186 -0
- package/public/js/dospc.js +1353 -0
- package/public/js/dosworker.js +196 -0
- package/public/js/explorer.js +7 -1
- package/public/js/livingsky.js +494 -0
- package/public/js/login.js +8 -2
- package/public/js/markets.js +46 -8
- package/public/js/mining.js +314 -36
- package/public/js/panels.js +41 -28
- package/public/js/pricechart.js +14 -13
- package/public/js/quake.js +20 -0
- package/public/js/safenext.js +14 -0
- package/public/js/scorched.js +1051 -0
- package/public/js/scorchedai.js +227 -0
- package/public/js/scorchedair.js +286 -0
- package/public/js/scorchedfx.js +376 -0
- package/public/js/scorchedshop.js +105 -0
- package/public/js/scorchedwind.js +69 -0
- package/public/js/scorchedyard.js +1338 -0
- package/public/js/settings.js +368 -100
- package/public/js/soundcard.js +459 -0
- package/public/js/tetrust.js +15 -6
- package/public/js/tetsound.js +35 -5
- package/public/js/theme.js +235 -0
- package/public/js/wolf3d.js +22 -0
- package/public/js/x86.js +1978 -0
- package/scripts/check.js +46 -0
- package/scripts/donate-qr.py +12 -9
- package/scripts/dos-bench.js +56 -0
- package/scripts/index-build.js +9 -2
- package/scripts/pool-map.js +152 -36
- package/scripts/setup.js +142 -22
- package/scripts/shots.mjs +27 -0
- package/scripts/smoke.sh +7 -6
- package/scripts/tls.js +31 -0
- package/scripts/ui.js +4 -2
- package/server/auth/sessions.js +33 -13
- package/server/chain/blockfile.js +64 -5
- package/server/chain/index/build.js +451 -58
- package/server/chain/index/heights.js +29 -3
- package/server/chain/index/live.js +13 -7
- package/server/chain/index/rows.js +6 -1
- package/server/chain/index/store.js +28 -5
- package/server/chain/index/worker.js +23 -11
- package/server/collect/logparse.js +65 -18
- package/server/collect/markets.js +76 -7
- package/server/collect/mining.js +32 -0
- package/server/collect/monitor.js +54 -12
- package/server/collect/network.js +305 -0
- package/server/config.js +53 -22
- package/server/http/api.js +119 -18
- package/server/http/games.js +77 -0
- package/server/http/server.js +30 -5
- package/server/http/sse.js +53 -7
- package/server/main.js +66 -11
- package/server/rpc/allowlist.js +26 -0
- package/server/rpc/client.js +30 -2
- package/server/store/audit.js +6 -1
- package/server/store/history.js +19 -3
- package/server/store/ledger.js +15 -4
- package/server/tls/selfsigned.js +160 -0
- package/systemd/blockyard.service +41 -8
- package/docs/PRIVATE-LEADERBOARD.md +0 -230
- package/docs/STATE-2026-09-09.md +0 -200
package/public/js/depthchart.js
CHANGED
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
// gives 500 levels, OKX 5000 -- a percent or two either side) is not extended: its line ends,
|
|
11
11
|
// the end is marked, and the total past it counts only the books that reach.
|
|
12
12
|
import { niceTicks } from './charts.js';
|
|
13
|
+
import { INK } from './theme.js'; // the axis, grid and tooltip colours of the chosen theme
|
|
13
14
|
import { prep } from './pricechart.js';
|
|
14
15
|
|
|
15
16
|
export const AGOS = [[60, '1m'], [300, '5m'], [600, '10m'], [1800, '30m'], [3600, '1h']];
|
|
16
17
|
export const ZOOMS = [[0.01, '±1%'], [0.025, '±2.5%'], [0.05, '±5%'], [0.1, '±10%']];
|
|
17
18
|
export const DEPTH_MS = 30_000;
|
|
18
19
|
const D = { data: null, at: 0, busy: false, key: null, ago: 600, zoom: 0.05, hover: null, bound: false, error: null };
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const BID_THEN = 'rgba(61,255,122,0.55)', ASK_THEN = 'rgba(255,69,69,0.55)';
|
|
20
|
+
// the two sides' colours come from the theme's ink (theme.js, 2026-09-16): neon green and red on a
|
|
21
|
+
// dark ground, the theme's own good and bad on a light one, where neon has no contrast
|
|
22
22
|
const PAD_FULL = { top: 28, right: 62, bottom: 22, left: 56 };
|
|
23
23
|
// COMPACT, for the kiosk. The full chart spends 62 px on the right purely to label the change
|
|
24
24
|
// bars' axis and 56 on the left for the cumulative-BTC labels plus a rotated caption -- on a wall
|
|
@@ -90,13 +90,13 @@ export function depthSums(ser, pct) {
|
|
|
90
90
|
return { bids: ser.bid[ib] ?? null, asks: ser.ask[ia] ?? null, atLeast: Boolean(ser.bidPart?.[ib] || ser.askPart?.[ia]) };
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = false } = {}) {
|
|
93
|
+
export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = false, empty = null } = {}) {
|
|
94
94
|
if (!canvas?.getContext) return null;
|
|
95
95
|
const PAD = compact ? PAD_COMPACT : PAD_FULL;
|
|
96
96
|
const { ctx, w, h } = prep(canvas);
|
|
97
97
|
if (!ser) {
|
|
98
|
-
ctx.fillStyle =
|
|
99
|
-
ctx.fillText('asking the exchanges for their order books…', w / 2, h / 2);
|
|
98
|
+
ctx.fillStyle = INK.text; ctx.textAlign = 'center';
|
|
99
|
+
ctx.fillText(empty ?? 'asking the exchanges for their order books…', w / 2, h / 2);
|
|
100
100
|
return null;
|
|
101
101
|
}
|
|
102
102
|
const plotW = Math.max(10, w - PAD.left - PAD.right), plotH = Math.max(40, h - PAD.top - PAD.bottom);
|
|
@@ -120,13 +120,13 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
120
120
|
for (const v of niceTicks(0, vmax, Math.max(3, Math.floor(plotH / 44)))) {
|
|
121
121
|
const y = Math.round(Y(v)) + 0.5;
|
|
122
122
|
if (y < PAD.top) continue;
|
|
123
|
-
ctx.strokeStyle =
|
|
124
|
-
ctx.fillStyle =
|
|
123
|
+
ctx.strokeStyle = INK.grid; line(PAD.left, y, w - PAD.right, y);
|
|
124
|
+
ctx.fillStyle = INK.axisText; ctx.fillText(btc(v), PAD.left - 6, y);
|
|
125
125
|
}
|
|
126
126
|
if (!compact) {
|
|
127
127
|
ctx.save?.();
|
|
128
128
|
ctx.translate(12, PAD.top + plotH / 2); ctx.rotate(-Math.PI / 2);
|
|
129
|
-
ctx.textAlign = 'center'; ctx.fillStyle =
|
|
129
|
+
ctx.textAlign = 'center'; ctx.fillStyle = INK.textDim; ctx.fillText('BTC, cumulative', 0, 0);
|
|
130
130
|
ctx.restore?.();
|
|
131
131
|
}
|
|
132
132
|
ctx.setTransform(Math.min(globalThis.devicePixelRatio || 1, 2), 0, 0, Math.min(globalThis.devicePixelRatio || 1, 2), 0, 0);
|
|
@@ -137,10 +137,10 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
137
137
|
const v = e === 0 ? 0 : Math.sign(e) * 10 ** Math.abs(e);
|
|
138
138
|
const y = Math.round(YC(v)) + 0.5;
|
|
139
139
|
if (!compact) {
|
|
140
|
-
ctx.fillStyle =
|
|
140
|
+
ctx.fillStyle = INK.axisText;
|
|
141
141
|
ctx.fillText(v === 0 ? '0' : `${v > 0 ? '' : '-'}${shortN(Math.abs(v))}`, w - PAD.right + 6, y);
|
|
142
142
|
}
|
|
143
|
-
if (v === 0) { ctx.strokeStyle =
|
|
143
|
+
if (v === 0) { ctx.strokeStyle = INK.axis; line(PAD.left, y, w - PAD.right, y); }
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
// price axis
|
|
@@ -148,10 +148,10 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
148
148
|
for (const p of niceTicks(pmin, pmax, Math.max(3, Math.floor(plotW / 90)))) {
|
|
149
149
|
const x = Math.round(X(p)) + 0.5;
|
|
150
150
|
if (x < PAD.left || x > w - PAD.right) continue;
|
|
151
|
-
ctx.strokeStyle =
|
|
152
|
-
ctx.fillStyle =
|
|
151
|
+
ctx.strokeStyle = INK.grid; line(x, PAD.top, x, PAD.top + plotH);
|
|
152
|
+
ctx.fillStyle = INK.axisText; ctx.fillText(zoom <= 0.01 ? money(p) : kUsd(p), x, h - PAD.bottom / 2);
|
|
153
153
|
}
|
|
154
|
-
ctx.strokeStyle =
|
|
154
|
+
ctx.strokeStyle = INK.axis;
|
|
155
155
|
line(PAD.left + 0.5, PAD.top, PAD.left + 0.5, PAD.top + plotH);
|
|
156
156
|
line(w - PAD.right + 0.5, PAD.top, w - PAD.right + 0.5, PAD.top + plotH);
|
|
157
157
|
line(PAD.left, PAD.top + plotH + 0.5, w - PAD.right, PAD.top + plotH + 0.5);
|
|
@@ -180,15 +180,15 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
180
180
|
ctx.stroke();
|
|
181
181
|
ctx.setLineDash([]); ctx.lineWidth = 1;
|
|
182
182
|
};
|
|
183
|
-
for (const e of ser.exchanges) { curve(e.bids,
|
|
184
|
-
if (ser.change) { curve(ser.thenBid,
|
|
183
|
+
for (const e of ser.exchanges) { curve(e.bids, INK.bidT, 1); curve(e.asks, INK.askT, 1); }
|
|
184
|
+
if (ser.change) { curve(ser.thenBid, INK.bidThen, 1.4, [5, 4]); curve(ser.thenAsk, INK.askThen, 1.4, [5, 4]); }
|
|
185
185
|
const only = (arr, part, want) => arr.map((v, i) => (v != null && (part[i] === want || (i > 0 && part[i - 1] === want) || (i < arr.length - 1 && part[i + 1] === want)) ? v : null));
|
|
186
|
-
curve(only(ser.bid, ser.bidPart, true),
|
|
187
|
-
curve(only(ser.ask, ser.askPart, true),
|
|
188
|
-
curve(only(ser.bid, ser.bidPart, false),
|
|
189
|
-
curve(only(ser.ask, ser.askPart, false),
|
|
186
|
+
curve(only(ser.bid, ser.bidPart, true), INK.bidHalf, 2.2, [2, 3]);
|
|
187
|
+
curve(only(ser.ask, ser.askPart, true), INK.askHalf, 2.2, [2, 3]);
|
|
188
|
+
curve(only(ser.bid, ser.bidPart, false), INK.bid, 2.2);
|
|
189
|
+
curve(only(ser.ask, ser.askPart, false), INK.ask, 2.2);
|
|
190
190
|
// the mid, and where each shallow book ends
|
|
191
|
-
ctx.strokeStyle =
|
|
191
|
+
ctx.strokeStyle = INK.dash;
|
|
192
192
|
const xm = Math.round(X(ser.mid)) + 0.5;
|
|
193
193
|
line(xm, PAD.top, xm, PAD.top + plotH);
|
|
194
194
|
ctx.font = '10px ui-monospace, SFMono-Regular, Menlo, monospace';
|
|
@@ -197,9 +197,9 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
197
197
|
for (const p of [r.low, r.high]) {
|
|
198
198
|
if (p == null || p < pmin || p > pmax) continue;
|
|
199
199
|
const x = Math.round(X(p)) + 0.5;
|
|
200
|
-
ctx.strokeStyle =
|
|
200
|
+
ctx.strokeStyle = INK.dash; line(x, PAD.top + plotH - 8, x, PAD.top + plotH);
|
|
201
201
|
if (!compact) {
|
|
202
|
-
ctx.fillStyle =
|
|
202
|
+
ctx.fillStyle = INK.label; ctx.textAlign = 'center';
|
|
203
203
|
ctx.fillText(`${r.name} ends`, x, PAD.top + plotH - 14 - 11 * (lane++ % 3));
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -207,14 +207,14 @@ export function drawDepth(canvas, ser, { zoom = 0.05, hover = null, compact = fa
|
|
|
207
207
|
ctx.font = '11px ui-monospace, SFMono-Regular, Menlo, monospace';
|
|
208
208
|
|
|
209
209
|
// readout: the pointer's price, or the sums near the mid
|
|
210
|
-
ctx.textAlign = 'left'; ctx.fillStyle =
|
|
210
|
+
ctx.textAlign = 'left'; ctx.fillStyle = INK.bright;
|
|
211
211
|
if (hover && hover.x >= PAD.left && hover.x <= w - PAD.right) {
|
|
212
212
|
const p = pmin + ((hover.x - PAD.left) / plotW) * (pmax - pmin);
|
|
213
213
|
const i = Math.max(0, Math.min(ser.prices.length - 1, Math.round((p - ser.prices[0]) / ser.step)));
|
|
214
214
|
const bidSide = ser.prices[i] <= ser.mid;
|
|
215
215
|
const cum = bidSide ? ser.bid[i] : ser.ask[i];
|
|
216
216
|
const per = ser.exchanges.map((e) => [e.name, bidSide ? e.bids[i] : e.asks?.[i]]).filter(([, v]) => v != null).map(([nm, v]) => `${nm} ${btc(v)}`).join(' · ');
|
|
217
|
-
ctx.strokeStyle =
|
|
217
|
+
ctx.strokeStyle = INK.dash; ctx.setLineDash([3, 3]);
|
|
218
218
|
const x = Math.round(X(ser.prices[i])) + 0.5;
|
|
219
219
|
line(x, PAD.top, x, PAD.top + plotH);
|
|
220
220
|
ctx.setLineDash([]);
|
|
@@ -237,8 +237,12 @@ export function depthBarHtml(ago = D.ago, zoom = D.zoom) {
|
|
|
237
237
|
<div class="mkgrp"><span class="mklab">price window</span>${ZOOMS.map(([z, l]) => b('data-zoom', z, l, z === zoom)).join('')}</div>`;
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
// what the empty chart says while the feed is off: the switch, or the server's hard off
|
|
241
|
+
const offText = (d) => (d?.enabled === false ? (d.polling === false ? 'market polling is off — Display settings → Markets & Price → Enable market polling' : 'market data is off on this server') : null);
|
|
242
|
+
|
|
240
243
|
export function depthNote(d, fmt) {
|
|
241
244
|
if (!d) return 'asking the exchanges for their order books…';
|
|
245
|
+
if (d.enabled === false) return d.note != null ? fmt.esc(d.note) : 'market data is off on this monitor'; // markup sink: escaped (audit 2026-09-16, I2)
|
|
242
246
|
if (d.warming) return 'reading the order books for the first time…';
|
|
243
247
|
const agoL = AGOS.find(([s]) => s === d.ago)?.[1] ?? `${d.ago} s`;
|
|
244
248
|
const parts = [`books read at ${clock(d.at)} UTC, every ${Math.round((d.bookMs ?? DEPTH_MS) / 1000)} s while this tab is open`];
|
|
@@ -252,7 +256,7 @@ export function depthNote(d, fmt) {
|
|
|
252
256
|
function draw() {
|
|
253
257
|
const canvas = document.getElementById('mkDepth');
|
|
254
258
|
if (!canvas) return;
|
|
255
|
-
drawDepth(canvas, depthSeries(D.data), { zoom: D.zoom, hover: D.hover });
|
|
259
|
+
drawDepth(canvas, depthSeries(D.data), { zoom: D.zoom, hover: D.hover, empty: offText(D.data) });
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
/**
|
|
@@ -282,7 +286,7 @@ export function renderDepthInto(canvasId, h, { zoom = 0.025, compact = true } =
|
|
|
282
286
|
ensureDepth(h);
|
|
283
287
|
const canvas = document.getElementById(canvasId);
|
|
284
288
|
if (!canvas) return null;
|
|
285
|
-
return drawDepth(canvas, depthSeries(D.data), { zoom, compact });
|
|
289
|
+
return drawDepth(canvas, depthSeries(D.data), { zoom, compact, empty: offText(D.data) });
|
|
286
290
|
}
|
|
287
291
|
|
|
288
292
|
export function renderDepth(h) {
|