@suifei/dsh-market-lens 0.29.2 → 0.30.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.
package/README.md CHANGED
@@ -204,6 +204,10 @@ node scripts/release.mjs <x.y.z> --msg "..." --token <npm granular token> [--hos
204
204
  - Yahoo 在部分区域返回 403:美股自动落到腾讯,K 线历史长度可能缩短。
205
205
  - 分时图未进首版;详情页暂以 K 线为主视图。
206
206
 
207
+ ## 安全
208
+
209
+ 本包只读公开行情、无交易无用户数据出口;npm 扫描器告警的逐条处置与证据见 **`SECURITY.md`**(zod 内存 DoS 已在 0.29.3 修复,其余 eval/URL 等为误报或职责所需)。
210
+
207
211
  ## License
208
212
 
209
213
  MIT · 图标为本仓库原创绘制。
package/client.js CHANGED
@@ -382,7 +382,7 @@ window.__ModuleLoader__.load({
382
382
  }
383
383
 
384
384
  // ---------- diagnostic reporting (batched POST /market-lens/diag) ----------
385
- const CLIENT_REV = '0.29.2';
385
+ const CLIENT_REV = '0.30.0';
386
386
  const diagQueue = [];
387
387
  let diagTimer = 0;
388
388
  // the host meta tells the real level; until then assume the shipped 'errors' default
@@ -2086,49 +2086,63 @@ window.__ModuleLoader__.load({
2086
2086
  const SCROLL_VPX = 28; // wall px/s (~8 lamp rows/s): uniform scroll, smooth and cheap
2087
2087
  const VERT_SRC = 'attribute vec2 aPos; void main() { gl_Position = vec4(aPos, 0.0, 1.0); }';
2088
2088
  const FRAG_SRC = [
2089
- 'precision highp float;',
2090
- 'uniform vec2 iRes; uniform vec4 uGeo; uniform vec4 uBand; uniform vec4 uPx; uniform vec2 uSzT;',
2091
- 'uniform float uScroll; uniform float uTime;',
2092
- 'uniform sampler2D uStatic; uniform sampler2D uTape;',
2093
- 'vec3 tap5(sampler2D s, vec2 sz, vec2 wp) {',
2094
- ' vec2 uv = wp / sz; vec2 pu = 1.0 / sz; vec3 c = texture2D(s, uv).rgb;',
2095
- ' c = max(c, texture2D(s, uv + vec2(pu.x, 0.0)).rgb);',
2096
- ' c = max(c, texture2D(s, uv - vec2(pu.x, 0.0)).rgb);',
2097
- ' c = max(c, texture2D(s, uv + vec2(0.0, pu.y)).rgb);',
2098
- ' c = max(c, texture2D(s, uv - vec2(0.0, pu.y)).rgb);',
2099
- ' return c;',
2100
- '}',
2101
- 'void main() {',
2102
- ' vec2 f = vec2(gl_FragCoord.x, iRes.y - gl_FragCoord.y);',
2103
- ' vec2 w = (f - uGeo.xy) / uGeo.z;',
2104
- ' if (w.x < 0.0 || w.y < 0.0 || w.x >= uPx.z || w.y >= uPx.w) { gl_FragColor = vec4(0.016, 0.027, 0.051, 1.0); return; }',
2105
- ' vec2 cell = floor(w / uPx.x);',
2106
- ' vec2 ctr = (cell + 0.5) * uPx.x;',
2107
- ' float half_ = max(0.5 * uPx.y * uGeo.z, 0.5) - 0.3;',
2108
- ' vec2 rr = f - uGeo.xy - cell * uPx.x * uGeo.z;',
2109
- ' vec2 qq = abs(rr - 0.5 * uPx.x * uGeo.z) - max(half_, 0.12);',
2110
- ' float d = length(max(qq, 0.0)) + min(max(qq.x, qq.y), 0.0);',
2111
- ' float mask = smoothstep(0.45, -0.05, d);',
2112
- ' float inBand = step(uBand.x, ctr.y) * step(ctr.y, uBand.x + uBand.y);',
2113
- ' vec2 tp = vec2(ctr.x, mod(ctr.y - uBand.x + uScroll, uBand.z));',
2114
- ' vec3 lit = mix(tap5(uStatic, uPx.zw, ctr), tap5(uTape, uSzT, tp), inBand);',
2115
- ' vec2 bwn = vec2(w.x, mod(w.y - uBand.x + uScroll, uBand.z)) / uSzT;',
2116
- ' vec3 bleed = mix(texture2D(uStatic, w / uPx.zw).rgb, texture2D(uTape, bwn).rgb, inBand);',
2117
- ' float lum = max(lit.r, max(lit.g, lit.b));',
2118
- ' vec3 base = mix(vec3(0.016, 0.024, 0.043), vec3(0.05, 0.1, 0.17), mask);',
2119
- ' vec3 col = mix(base, lit, mask * smoothstep(0.1, 0.3, lum));',
2120
- ' col += bleed * 0.14;',
2121
- ' float hh = fract(sin(dot(cell + vec2(floor(uTime * 3.0) * 17.0, floor(uTime * 2.0) * 31.0), vec2(127.1, 311.7))) * 43758.545);',
2122
- ' col *= mix(0.93, 1.05, hh);',
2123
- ' col *= mix(1.0, 0.15, step(hh, 0.002));',
2124
- ' col *= mix(1.0, 1.5, step(0.9978, hh));',
2125
- ' float sy = fract(uTime * 0.07) * (uPx.w + 240.0) - 120.0;',
2126
- ' col += vec3(0.05, 0.085, 0.12) * exp(-pow((w.y - sy) * 0.018, 2.0)) * (0.4 + 0.6 * mask);',
2127
- ' vec2 vq = w / uPx.zw - 0.5;',
2128
- ' col *= 1.0 - dot(vq, vq) * 0.6;',
2129
- ' gl_FragColor = vec4(min(col, vec3(1.0)), 1.0);',
2130
- '}',
2131
- ].join('\n');
2089
+ 'precision highp float;',
2090
+ 'uniform vec2 iRes; uniform vec4 uGeo; uniform vec4 uBand; uniform vec4 uPx; uniform vec2 uSzT;',
2091
+ 'uniform float uScroll; uniform float uTime;',
2092
+ 'uniform sampler2D uStatic; uniform sampler2D uTape;',
2093
+ 'vec3 tap5(sampler2D s, vec2 sz, vec2 wp) {',
2094
+ ' vec2 uv = wp / sz; vec2 pu = 1.0 / sz; vec3 c = texture2D(s, uv).rgb;',
2095
+ ' c = max(c, texture2D(s, uv + vec2(pu.x, 0.0)).rgb);',
2096
+ ' c = max(c, texture2D(s, uv - vec2(pu.x, 0.0)).rgb);',
2097
+ ' c = max(c, texture2D(s, uv + vec2(0.0, pu.y)).rgb);',
2098
+ ' c = max(c, texture2D(s, uv - vec2(0.0, pu.y)).rgb);',
2099
+ ' return c;',
2100
+ '}',
2101
+ 'void main() {',
2102
+ ' vec2 f = vec2(gl_FragCoord.x, iRes.y - gl_FragCoord.y);',
2103
+ ' vec2 w = (f - uGeo.xy) / uGeo.z;',
2104
+ ' if (w.x < 0.0 || w.y < 0.0 || w.x >= uPx.z || w.y >= uPx.w) { gl_FragColor = vec4(0.016, 0.027, 0.051, 1.0); return; }',
2105
+ ' vec2 qn = w / uPx.zw - 0.5;',
2106
+ ' float r2 = dot(qn, qn);',
2107
+ ' vec2 wd = clamp((qn * (1.0 + 0.045 * r2) + 0.5) * uPx.zw, vec2(0.0), uPx.zw - vec2(0.01));',
2108
+ ' vec2 cell = floor(wd / uPx.x);',
2109
+ ' vec2 ctr = (cell + 0.5) * uPx.x;',
2110
+ ' float half_ = max(0.5 * uPx.y * uGeo.z, 0.5) - 0.3;',
2111
+ ' vec2 rr = f - uGeo.xy - cell * uPx.x * uGeo.z;',
2112
+ ' vec2 qq = abs(rr - 0.5 * uPx.x * uGeo.z) - max(half_, 0.12);',
2113
+ ' float d = length(max(qq, 0.0)) + min(max(qq.x, qq.y), 0.0);',
2114
+ ' float mask = smoothstep(0.45, -0.05, d);',
2115
+ ' float inBand = step(uBand.x, ctr.y) * step(ctr.y, uBand.x + uBand.y);',
2116
+ ' vec2 tp = vec2(ctr.x, mod(ctr.y - uBand.x + uScroll, uBand.z));',
2117
+ ' vec3 lit = mix(tap5(uStatic, uPx.zw, ctr), tap5(uTape, uSzT, tp), inBand);',
2118
+ ' float lum = max(lit.r, max(lit.g, lit.b));',
2119
+ ' float breath = 0.94 + 0.06 * sin(uTime * 1.1);',
2120
+ ' vec3 base = mix(vec3(0.016, 0.024, 0.043), vec3(0.05, 0.1, 0.17), mask);',
2121
+ ' vec3 col = mix(base, lit * breath, mask * smoothstep(0.1, 0.3, lum));',
2122
+ ' vec2 bwn = vec2(wd.x, mod(wd.y - uBand.x + uScroll, uBand.z)) / uSzT;',
2123
+ ' vec3 bleed = mix(texture2D(uStatic, wd / uPx.zw).rgb, texture2D(uTape, bwn).rgb, inBand);',
2124
+ ' col += bleed * 0.16;',
2125
+ ' float ca = 0.002 + 0.010 * r2;',
2126
+ ' vec2 wR = wd + (wd - uPx.zw * 0.5) * ca;',
2127
+ ' float inBR = step(uBand.x, wR.y) * step(wR.y, uBand.x + uBand.y);',
2128
+ ' vec2 tpR = vec2(wR.x, mod(wR.y - uBand.x + uScroll, uBand.z));',
2129
+ ' float red = mix(texture2D(uStatic, wR / uPx.zw).r, texture2D(uTape, tpR / uSzT).r, inBR);',
2130
+ ' col.r = mix(col.r, red, 0.55);',
2131
+ ' float hh = fract(sin(dot(cell + vec2(floor(uTime * 3.0) * 17.0, floor(uTime * 2.0) * 31.0), vec2(127.1, 311.7))) * 43758.545);',
2132
+ ' col *= mix(0.93, 1.05, hh);',
2133
+ ' col *= mix(1.0, 0.15, step(hh, 0.002));',
2134
+ ' col *= mix(1.0, 1.5, step(0.9978, hh));',
2135
+ ' float wave = 0.5 + 0.5 * sin(cell.y * 0.35 - uTime * 1.7);',
2136
+ ' col *= 0.985 + 0.015 * wave;',
2137
+ ' float sy = fract(uTime * 0.07) * (uPx.w + 240.0) - 120.0;',
2138
+ ' col += vec3(0.05, 0.085, 0.12) * exp(-pow((w.y - sy) * 0.018, 2.0)) * (0.4 + 0.6 * mask);',
2139
+ ' float refl = 0.5 + 0.5 * sin(dot(wd, vec2(0.9, 1.4)) - uTime * 0.31);',
2140
+ ' col += vec3(0.10, 0.14, 0.20) * smoothstep(0.98, 1.0, refl) * 0.35;',
2141
+ ' vec2 vq = w / uPx.zw - 0.5;',
2142
+ ' col *= 1.0 - dot(vq, vq) * 0.62;',
2143
+ ' gl_FragColor = vec4(min(col, vec3(1.0)), 1.0);',
2144
+ '}',
2145
+ ].join('\n');
2132
2146
  function wallGL(gl) {
2133
2147
  const sh = (type, s) => { const o = gl.createShader(type); gl.shaderSource(o, s); gl.compileShader(o); return o; };
2134
2148
  const prog = gl.createProgram();
@@ -2147,7 +2161,7 @@ window.__ModuleLoader__.load({
2147
2161
  ['iRes', 'uGeo', 'uBand', 'uPx', 'uSzT', 'uScroll', 'uTime', 'uStatic', 'uTape'].forEach((n) => { U[n] = gl.getUniformLocation(prog, n); });
2148
2162
  gl.uniform1i(U.uStatic, 0);
2149
2163
  gl.uniform1i(U.uTape, 1);
2150
- return { prog, U };
2164
+ return { prog, U, buf };
2151
2165
  }
2152
2166
 
2153
2167
  /**
@@ -2326,6 +2340,7 @@ window.__ModuleLoader__.load({
2326
2340
  const staticRef = React.useRef(null);
2327
2341
  const tapeCvRef = React.useRef(null);
2328
2342
  const dirtyRef = React.useRef(false);
2343
+ const glResRef = React.useRef(null);
2329
2344
  const geoPlanRef = React.useRef(null);
2330
2345
  const pitchRef = React.useRef(0);
2331
2346
  const topRef = React.useRef(0);
@@ -2554,18 +2569,27 @@ window.__ModuleLoader__.load({
2554
2569
  cv.height = size.h;
2555
2570
  const gl = typeof WebGL2RenderingContext === 'undefined' ? null : cv.getContext('webgl2', { alpha: false, antialias: false });
2556
2571
  const x2d = gl === null ? cv.getContext('2d') : null;
2557
- const W = gl === null ? null : wallGL(gl);
2558
- let tex = null;
2559
- if (gl !== null && W !== null) {
2560
- tex = { s: gl.createTexture(), t: gl.createTexture() };
2561
- [tex.s, tex.t].forEach((tt) => {
2562
- gl.bindTexture(gl.TEXTURE_2D, tt);
2563
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
2564
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
2565
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
2566
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
2567
- });
2572
+ // GL program + textures are created once per context and reused across
2573
+ // resizes; the old effect recompiled the shader and leaked two textures,
2574
+ // a program and a buffer on every [size] change
2575
+ let res = glResRef.current;
2576
+ if (gl !== null && (res === null || res.gl !== gl)) {
2577
+ const W = wallGL(gl);
2578
+ if (W === null) { res = null; } else {
2579
+ const tex = { s: gl.createTexture(), t: gl.createTexture() };
2580
+ [tex.s, tex.t].forEach((tt) => {
2581
+ gl.bindTexture(gl.TEXTURE_2D, tt);
2582
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
2583
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
2584
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
2585
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
2586
+ });
2587
+ res = { gl, W, tex };
2588
+ }
2589
+ glResRef.current = res;
2568
2590
  }
2591
+ const W = res === null ? null : res.W;
2592
+ const tex = res === null ? null : res.tex;
2569
2593
  const sc = Math.min(size.w / WALL_W_PX, size.h / WALL_H_PX);
2570
2594
  const dw = Math.round(WALL_W_PX * sc);
2571
2595
  const dh = Math.round(WALL_H_PX * sc);
@@ -2584,6 +2608,7 @@ window.__ModuleLoader__.load({
2584
2608
  const tC = tapeCvRef.current;
2585
2609
  if (gp === null || sC === null || tC === null) return;
2586
2610
  if (W === null) {
2611
+ if (x2d === null) return; // webgl2 present but shader failed: no 2d context is available on the same canvas
2587
2612
  x2d.fillStyle = '#04070d';
2588
2613
  x2d.fillRect(0, 0, size.w, size.h);
2589
2614
  x2d.drawImage(sC, ox, oy, dw, dh);
@@ -2621,6 +2646,19 @@ window.__ModuleLoader__.load({
2621
2646
  raf = window.requestAnimationFrame(step);
2622
2647
  return () => window.cancelAnimationFrame(raf);
2623
2648
  }, [size]);
2649
+ // release GPU objects once when the board unmounts (resizes reuse them)
2650
+ React.useEffect(() => () => {
2651
+ const r = glResRef.current;
2652
+ if (r !== null && r.gl !== null) {
2653
+ try {
2654
+ r.gl.deleteTexture(r.tex.s);
2655
+ r.gl.deleteTexture(r.tex.t);
2656
+ r.gl.deleteProgram(r.W.prog);
2657
+ r.gl.deleteBuffer(r.W.buf);
2658
+ } catch (e) { /* context already lost */ }
2659
+ glResRef.current = null;
2660
+ }
2661
+ }, []);
2624
2662
  const hit = (event) => {
2625
2663
  const rect = canvasRef.current.getBoundingClientRect();
2626
2664
  const { ox, oy, sc } = geoRef.current;
package/index.js CHANGED
@@ -167,7 +167,7 @@ export function apply(ctx, config) {
167
167
  service,
168
168
  diag,
169
169
  alerts,
170
- config: { ...config, version: '0.29.2' },
170
+ config: { ...config, version: '0.30.0' },
171
171
  });
172
172
 
173
173
  ctx.effect(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suifei/dsh-market-lens",
3
- "version": "0.29.2",
3
+ "version": "0.30.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -45,6 +45,14 @@
45
45
  "@deepseek-ai/dsh-tools": "0.2.2-rc.1",
46
46
  "@deepseek-ai/schemastery": "~3.19.0"
47
47
  },
48
+ "overrides": {
49
+ "zod": "^4.6.6"
50
+ },
51
+ "pnpm": {
52
+ "overrides": {
53
+ "zod": "^4.6.6"
54
+ }
55
+ },
48
56
  "peerDependencies": {
49
57
  "@deepseek-ai/cordis": "~4.1.0"
50
58
  },