@rezi-ui/node 0.1.0-alpha.2 โ 0.1.0-alpha.20
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 +20 -6
- package/dist/backend/emojiWidthPolicy.d.ts +15 -0
- package/dist/backend/emojiWidthPolicy.d.ts.map +1 -0
- package/dist/backend/emojiWidthPolicy.js +211 -0
- package/dist/backend/emojiWidthPolicy.js.map +1 -0
- package/dist/backend/nodeBackend.d.ts +22 -1
- package/dist/backend/nodeBackend.d.ts.map +1 -1
- package/dist/backend/nodeBackend.js +82 -10
- package/dist/backend/nodeBackend.js.map +1 -1
- package/dist/backend/nodeBackendInline.d.ts.map +1 -1
- package/dist/backend/nodeBackendInline.js +77 -9
- package/dist/backend/nodeBackendInline.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -1
- package/dist/repro/index.d.ts +3 -0
- package/dist/repro/index.d.ts.map +1 -0
- package/dist/repro/index.js +2 -0
- package/dist/repro/index.js.map +1 -0
- package/dist/repro/recorder.d.ts +31 -0
- package/dist/repro/recorder.d.ts.map +1 -0
- package/dist/repro/recorder.js +323 -0
- package/dist/repro/recorder.js.map +1 -0
- package/dist/worker/engineWorker.js +30 -3
- package/dist/worker/engineWorker.js.map +1 -1
- package/dist/worker/testShims/invalidPollBytesNative.d.ts +22 -0
- package/dist/worker/testShims/invalidPollBytesNative.d.ts.map +1 -0
- package/dist/worker/testShims/invalidPollBytesNative.js +65 -0
- package/dist/worker/testShims/invalidPollBytesNative.js.map +1 -0
- package/package.json +11 -7
- package/dist/__e2e__/fixtures/terminal-app.d.ts +0 -2
- package/dist/__e2e__/fixtures/terminal-app.d.ts.map +0 -1
- package/dist/__e2e__/fixtures/terminal-app.js +0 -42
- package/dist/__e2e__/fixtures/terminal-app.js.map +0 -1
- package/dist/__e2e__/terminal-render.e2e.test.d.ts +0 -2
- package/dist/__e2e__/terminal-render.e2e.test.d.ts.map +0 -1
- package/dist/__e2e__/terminal-render.e2e.test.js +0 -125
- package/dist/__e2e__/terminal-render.e2e.test.js.map +0 -1
- package/dist/__tests__/worker_integration.test.d.ts +0 -2
- package/dist/__tests__/worker_integration.test.d.ts.map +0 -1
- package/dist/__tests__/worker_integration.test.js +0 -569
- package/dist/__tests__/worker_integration.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
# @rezi-ui/node
|
|
2
2
|
|
|
3
|
-
Node.js backend for Rezi. This package owns:
|
|
3
|
+
Node.js/Bun backend for Rezi. This package owns:
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
- configurable native engine execution mode (`auto` | `worker` | `inline`)
|
|
6
6
|
- frame scheduling and buffer pooling
|
|
7
7
|
- transfer of drawlists/events between core and the native addon
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Recommended usage:
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import {
|
|
13
|
-
import { createNodeBackend } from "@rezi-ui/node";
|
|
12
|
+
import { createNodeApp } from "@rezi-ui/node";
|
|
14
13
|
```
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
Use `createNodeApp({ initialState, config })` as the default path. It wires
|
|
16
|
+
`@rezi-ui/core` and `@rezi-ui/node` with matched cursor protocol, event caps,
|
|
17
|
+
and fps settings. `executionMode` defaults to `auto` (`fpsCap <= 30` -> inline,
|
|
18
|
+
otherwise worker); set `executionMode: "worker"` or `"inline"` to force a mode.
|
|
19
|
+
|
|
20
|
+
Legacy `createNodeBackend() + createApp()` wiring is deprecated for standard
|
|
21
|
+
app construction.
|
|
22
|
+
|
|
23
|
+
Install:
|
|
17
24
|
|
|
25
|
+
```bash
|
|
26
|
+
npm i @rezi-ui/node
|
|
27
|
+
# or
|
|
28
|
+
bun add @rezi-ui/node
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Docs: `https://rtlzeromemory.github.io/Rezi/`
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type BackendEmojiWidthPolicy = "auto" | "wide" | "narrow";
|
|
2
|
+
export type ResolvedEmojiWidthPolicy = "wide" | "narrow";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve backend emoji width policy and align core/native width models.
|
|
5
|
+
*
|
|
6
|
+
* Resolution order:
|
|
7
|
+
* 1) explicit `requested` ("wide"/"narrow")
|
|
8
|
+
* 2) explicit native override (`nativeConfig.widthPolicy|width_policy`)
|
|
9
|
+
* 3) env override (`ZRUI_EMOJI_WIDTH_POLICY`)
|
|
10
|
+
* 4) optional probe (CPR-based) when `ZRUI_EMOJI_WIDTH_PROBE=1`
|
|
11
|
+
* 5) deterministic default ("wide")
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveBackendEmojiWidthPolicy(requested: BackendEmojiWidthPolicy | undefined, nativeConfig: Readonly<Record<string, unknown>>): Promise<ResolvedEmojiWidthPolicy>;
|
|
14
|
+
export declare function applyEmojiWidthPolicy(policy: ResolvedEmojiWidthPolicy): 0 | 1;
|
|
15
|
+
//# sourceMappingURL=emojiWidthPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emojiWidthPolicy.d.ts","sourceRoot":"","sources":["../../src/backend/emojiWidthPolicy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AACjE,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAkLzD;;;;;;;;;GASG;AACH,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,uBAAuB,GAAG,SAAS,EAC9C,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC9C,OAAO,CAAC,wBAAwB,CAAC,CA8BnC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,wBAAwB,GAAG,CAAC,GAAG,CAAC,CAG7E"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { ZrUiError, setTextMeasureEmojiPolicy } from "@rezi-ui/core";
|
|
2
|
+
const NATIVE_WIDTH_POLICY_NARROW = 0;
|
|
3
|
+
const NATIVE_WIDTH_POLICY_WIDE = 1;
|
|
4
|
+
const PROBE_TIMEOUT_MS_DEFAULT = 80;
|
|
5
|
+
const PROBE_GLYPHS = Object.freeze(["๐", "๐", "๐งช"]);
|
|
6
|
+
const ENV_EMOJI_WIDTH_POLICY = "ZRUI_EMOJI_WIDTH_POLICY";
|
|
7
|
+
const ENV_EMOJI_WIDTH_PROBE = "ZRUI_EMOJI_WIDTH_PROBE";
|
|
8
|
+
function normalizePolicy(raw) {
|
|
9
|
+
if (typeof raw !== "string")
|
|
10
|
+
return null;
|
|
11
|
+
const value = raw.trim().toLowerCase();
|
|
12
|
+
if (value === "auto")
|
|
13
|
+
return "auto";
|
|
14
|
+
if (value === "wide")
|
|
15
|
+
return "wide";
|
|
16
|
+
if (value === "narrow")
|
|
17
|
+
return "narrow";
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function nativeWidthPolicyToResolved(value) {
|
|
21
|
+
return value === NATIVE_WIDTH_POLICY_NARROW ? "narrow" : "wide";
|
|
22
|
+
}
|
|
23
|
+
function resolvedToNativeWidthPolicy(value) {
|
|
24
|
+
return value === "narrow" ? NATIVE_WIDTH_POLICY_NARROW : NATIVE_WIDTH_POLICY_WIDE;
|
|
25
|
+
}
|
|
26
|
+
function readNativeWidthPolicyValues(cfg) {
|
|
27
|
+
const parse = (value, key) => {
|
|
28
|
+
if (value === undefined)
|
|
29
|
+
return null;
|
|
30
|
+
if (typeof value !== "number" || !Number.isInteger(value) || (value !== 0 && value !== 1)) {
|
|
31
|
+
throw new ZrUiError("ZRUI_INVALID_PROPS", `createNodeBackend config mismatch: nativeConfig.${key} must be 0 (narrow) or 1 (wide).`);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
};
|
|
35
|
+
const record = cfg;
|
|
36
|
+
return {
|
|
37
|
+
camel: parse(record.widthPolicy, "widthPolicy"),
|
|
38
|
+
snake: parse(record.width_policy, "width_policy"),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function readNativeWidthPolicyOverride(cfg) {
|
|
42
|
+
const values = readNativeWidthPolicyValues(cfg);
|
|
43
|
+
if (values.camel !== null && values.snake !== null && values.camel !== values.snake) {
|
|
44
|
+
throw new ZrUiError("ZRUI_INVALID_PROPS", `createNodeBackend config mismatch: nativeConfig.widthPolicy=${String(values.camel)} must match nativeConfig.width_policy=${String(values.snake)}.`);
|
|
45
|
+
}
|
|
46
|
+
const nativeValue = values.camel ?? values.snake;
|
|
47
|
+
if (nativeValue === null)
|
|
48
|
+
return null;
|
|
49
|
+
return nativeWidthPolicyToResolved(nativeValue);
|
|
50
|
+
}
|
|
51
|
+
function pushParsedCpr(buffer, out) {
|
|
52
|
+
let pending = buffer;
|
|
53
|
+
while (pending.length > 0) {
|
|
54
|
+
const esc = pending.indexOf("\x1b[");
|
|
55
|
+
if (esc < 0) {
|
|
56
|
+
if (pending.length > 128)
|
|
57
|
+
pending = pending.slice(-128);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (esc > 0) {
|
|
61
|
+
pending = pending.slice(esc);
|
|
62
|
+
}
|
|
63
|
+
const end = pending.indexOf("R", 2);
|
|
64
|
+
if (end < 0)
|
|
65
|
+
break;
|
|
66
|
+
const seq = pending.slice(0, end + 1);
|
|
67
|
+
pending = pending.slice(end + 1);
|
|
68
|
+
const body = seq.slice(2, seq.length - 1);
|
|
69
|
+
const sep = body.indexOf(";");
|
|
70
|
+
if (sep <= 0 || sep >= body.length - 1)
|
|
71
|
+
continue;
|
|
72
|
+
const rowText = body.slice(0, sep);
|
|
73
|
+
const colText = body.slice(sep + 1);
|
|
74
|
+
if (!/^\d+$/.test(rowText) || !/^\d+$/.test(colText))
|
|
75
|
+
continue;
|
|
76
|
+
const row = Number.parseInt(rowText, 10);
|
|
77
|
+
const col = Number.parseInt(colText, 10);
|
|
78
|
+
if (Number.isFinite(row) && Number.isFinite(col)) {
|
|
79
|
+
out.push({ row, col });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return pending;
|
|
83
|
+
}
|
|
84
|
+
async function probeGlyphWidthViaCpr(glyph, timeoutMs) {
|
|
85
|
+
const stdin = process.stdin;
|
|
86
|
+
const stdout = process.stdout;
|
|
87
|
+
if (!stdin.isTTY || !stdout.isTTY)
|
|
88
|
+
return null;
|
|
89
|
+
if (typeof stdin.setRawMode !== "function")
|
|
90
|
+
return null;
|
|
91
|
+
const wasRaw = stdin.isRaw === true;
|
|
92
|
+
let pending = "";
|
|
93
|
+
const cprs = [];
|
|
94
|
+
const onData = (chunk) => {
|
|
95
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
96
|
+
pending = pushParsedCpr(pending + text, cprs);
|
|
97
|
+
};
|
|
98
|
+
let timeout = null;
|
|
99
|
+
try {
|
|
100
|
+
stdin.on("data", onData);
|
|
101
|
+
stdin.resume();
|
|
102
|
+
if (!wasRaw)
|
|
103
|
+
stdin.setRawMode(true);
|
|
104
|
+
// Save cursor, move to a stable column, query CPR, print glyph, query CPR again, restore cursor.
|
|
105
|
+
await new Promise((resolve, reject) => {
|
|
106
|
+
stdout.write(`\x1b[s\x1b[999;1H\x1b[6n${glyph}\x1b[6n\x1b[u`, (err) => {
|
|
107
|
+
if (err)
|
|
108
|
+
reject(err);
|
|
109
|
+
else
|
|
110
|
+
resolve();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
await new Promise((resolve) => {
|
|
114
|
+
const done = () => {
|
|
115
|
+
if (timeout)
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
timeout = null;
|
|
118
|
+
resolve();
|
|
119
|
+
};
|
|
120
|
+
timeout = setTimeout(done, timeoutMs);
|
|
121
|
+
const poll = () => {
|
|
122
|
+
if (cprs.length >= 2) {
|
|
123
|
+
done();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
setTimeout(poll, 2);
|
|
127
|
+
};
|
|
128
|
+
poll();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
if (timeout)
|
|
136
|
+
clearTimeout(timeout);
|
|
137
|
+
stdin.off("data", onData);
|
|
138
|
+
if (!wasRaw) {
|
|
139
|
+
try {
|
|
140
|
+
stdin.setRawMode(false);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// no-op
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const a = cprs[0];
|
|
148
|
+
const b = cprs[1];
|
|
149
|
+
if (!a || !b)
|
|
150
|
+
return null;
|
|
151
|
+
if (b.row !== a.row)
|
|
152
|
+
return null;
|
|
153
|
+
const delta = b.col - a.col;
|
|
154
|
+
if (delta === 1 || delta === 2)
|
|
155
|
+
return delta;
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
async function probeTerminalEmojiWidthPolicy(timeoutMs) {
|
|
159
|
+
const widths = [];
|
|
160
|
+
for (const glyph of PROBE_GLYPHS) {
|
|
161
|
+
const width = await probeGlyphWidthViaCpr(glyph, timeoutMs);
|
|
162
|
+
if (width !== null)
|
|
163
|
+
widths.push(width);
|
|
164
|
+
}
|
|
165
|
+
if (widths.length === 0)
|
|
166
|
+
return null;
|
|
167
|
+
if (widths.includes(1))
|
|
168
|
+
return "narrow";
|
|
169
|
+
return "wide";
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Resolve backend emoji width policy and align core/native width models.
|
|
173
|
+
*
|
|
174
|
+
* Resolution order:
|
|
175
|
+
* 1) explicit `requested` ("wide"/"narrow")
|
|
176
|
+
* 2) explicit native override (`nativeConfig.widthPolicy|width_policy`)
|
|
177
|
+
* 3) env override (`ZRUI_EMOJI_WIDTH_POLICY`)
|
|
178
|
+
* 4) optional probe (CPR-based) when `ZRUI_EMOJI_WIDTH_PROBE=1`
|
|
179
|
+
* 5) deterministic default ("wide")
|
|
180
|
+
*/
|
|
181
|
+
export async function resolveBackendEmojiWidthPolicy(requested, nativeConfig) {
|
|
182
|
+
const requestedPolicy = requested ?? "auto";
|
|
183
|
+
const nativeOverride = readNativeWidthPolicyOverride(nativeConfig);
|
|
184
|
+
if (requestedPolicy === "narrow" || requestedPolicy === "wide") {
|
|
185
|
+
if (nativeOverride !== null && nativeOverride !== requestedPolicy) {
|
|
186
|
+
throw new ZrUiError("ZRUI_INVALID_PROPS", `createNodeBackend config mismatch: emojiWidthPolicy=${requestedPolicy} must match nativeConfig.widthPolicy/width_policy=${nativeOverride === "narrow" ? 0 : 1}.`);
|
|
187
|
+
}
|
|
188
|
+
return requestedPolicy;
|
|
189
|
+
}
|
|
190
|
+
if (nativeOverride !== null)
|
|
191
|
+
return nativeOverride;
|
|
192
|
+
const envOverride = normalizePolicy(process.env[ENV_EMOJI_WIDTH_POLICY]);
|
|
193
|
+
if (envOverride === "wide" || envOverride === "narrow")
|
|
194
|
+
return envOverride;
|
|
195
|
+
/*
|
|
196
|
+
CPR probing is opt-in because it temporarily consumes stdin bytes while
|
|
197
|
+
collecting CPR responses, which can race startup-time key streams.
|
|
198
|
+
*/
|
|
199
|
+
const probeEnabled = process.env[ENV_EMOJI_WIDTH_PROBE] === "1";
|
|
200
|
+
if (probeEnabled) {
|
|
201
|
+
const probed = await probeTerminalEmojiWidthPolicy(PROBE_TIMEOUT_MS_DEFAULT);
|
|
202
|
+
if (probed !== null)
|
|
203
|
+
return probed;
|
|
204
|
+
}
|
|
205
|
+
return "wide";
|
|
206
|
+
}
|
|
207
|
+
export function applyEmojiWidthPolicy(policy) {
|
|
208
|
+
setTextMeasureEmojiPolicy(policy);
|
|
209
|
+
return resolvedToNativeWidthPolicy(policy);
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=emojiWidthPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emojiWidthPolicy.js","sourceRoot":"","sources":["../../src/backend/emojiWidthPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,9 +15,20 @@ export type NodeBackendConfig = Readonly<{
|
|
|
15
15
|
* - "inline": single-thread inline backend (no worker-hop transport)
|
|
16
16
|
*/
|
|
17
17
|
executionMode?: "auto" | "worker" | "inline";
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Prefer createNodeApp({ config: { fpsCap } }) so app/core and backend
|
|
20
|
+
* remain aligned by construction.
|
|
21
|
+
*/
|
|
18
22
|
fpsCap?: number;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated Prefer createNodeApp({ config: { maxEventBytes } }) so app/core and backend
|
|
25
|
+
* remain aligned by construction.
|
|
26
|
+
*/
|
|
19
27
|
maxEventBytes?: number;
|
|
20
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Request drawlist v2 for native cursor support (default: false for compatibility).
|
|
30
|
+
* @deprecated Prefer createNodeApp({ config: { useV2Cursor: true } }).
|
|
31
|
+
*/
|
|
21
32
|
useDrawlistV2?: boolean;
|
|
22
33
|
/**
|
|
23
34
|
* Frame transport mode:
|
|
@@ -35,6 +46,16 @@ export type NodeBackendConfig = Readonly<{
|
|
|
35
46
|
* Keys are forwarded as-is (camelCase or snake_case accepted by the native parser).
|
|
36
47
|
*/
|
|
37
48
|
nativeConfig?: Readonly<Record<string, unknown>>;
|
|
49
|
+
/**
|
|
50
|
+
* Emoji width policy used to keep core layout measurement and native rendering aligned.
|
|
51
|
+
* - "auto": use native/env overrides; optional probe when `ZRUI_EMOJI_WIDTH_PROBE=1`
|
|
52
|
+
* then fallback to deterministic "wide"
|
|
53
|
+
* - "wide": emoji clusters consume 2 cells
|
|
54
|
+
* - "narrow": emoji clusters consume 1 cell
|
|
55
|
+
*
|
|
56
|
+
* This sets core text measurement policy and native `widthPolicy` together.
|
|
57
|
+
*/
|
|
58
|
+
emojiWidthPolicy?: "auto" | "wide" | "narrow";
|
|
38
59
|
}>;
|
|
39
60
|
export type NodeBackendInternalOpts = Readonly<{
|
|
40
61
|
config?: NodeBackendConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodeBackend.d.ts","sourceRoot":"","sources":["../../src/backend/nodeBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAEV,YAAY,EAKZ,cAAc,EAEf,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"nodeBackend.d.ts","sourceRoot":"","sources":["../../src/backend/nodeBackend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAEV,YAAY,EAKZ,cAAc,EAEf,MAAM,eAAe,CAAC;AA0CvB,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC7C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;IAC7C,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjD;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;CAC/C,CAAC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,MAAM,EAAE,QAAQ,CACd,MAAM,CACJ,MAAM,EACN;QACE,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;KAC5B,CACF,CACF,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,YAAY,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;CACtD,CAAC,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,CAAC;AAiMpG,wBAAgB,yBAAyB,CAAC,IAAI,GAAE,uBAA4B,GAAG,WAAW,CAk8BzF"}
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
* @see docs/backend/native.md
|
|
8
8
|
*/
|
|
9
9
|
import { Worker } from "node:worker_threads";
|
|
10
|
-
import { DEFAULT_TERMINAL_CAPS, FRAME_ACCEPTED_ACK_MARKER } from "@rezi-ui/core";
|
|
11
|
-
import { ZR_DRAWLIST_VERSION_V1, ZR_DRAWLIST_VERSION_V2, ZR_ENGINE_ABI_MAJOR, ZR_ENGINE_ABI_MINOR, ZR_ENGINE_ABI_PATCH, ZR_EVENT_BATCH_VERSION_V1, ZrUiError, severityToNum, } from "@rezi-ui/core";
|
|
10
|
+
import { BACKEND_DRAWLIST_V2_MARKER, BACKEND_FPS_CAP_MARKER, BACKEND_MAX_EVENT_BYTES_MARKER, DEFAULT_TERMINAL_CAPS, FRAME_ACCEPTED_ACK_MARKER, } from "@rezi-ui/core";
|
|
11
|
+
import { ZR_DRAWLIST_VERSION_V1, ZR_DRAWLIST_VERSION_V2, ZR_ENGINE_ABI_MAJOR, ZR_ENGINE_ABI_MINOR, ZR_ENGINE_ABI_PATCH, ZR_EVENT_BATCH_VERSION_V1, ZrUiError, setTextMeasureEmojiPolicy, severityToNum, } from "@rezi-ui/core";
|
|
12
12
|
import { FRAME_SAB_CONTROL_CONSUMED_SEQ_WORD, FRAME_SAB_CONTROL_HEADER_WORDS, FRAME_SAB_CONTROL_PUBLISHED_BYTES_WORD, FRAME_SAB_CONTROL_PUBLISHED_SEQ_WORD, FRAME_SAB_CONTROL_PUBLISHED_SLOT_WORD, FRAME_SAB_CONTROL_PUBLISHED_TOKEN_WORD, FRAME_SAB_CONTROL_WORDS_PER_SLOT, FRAME_SAB_SLOT_STATE_FREE, FRAME_SAB_SLOT_STATE_READY, FRAME_SAB_SLOT_STATE_WRITING, FRAME_TRANSPORT_SAB_V1, FRAME_TRANSPORT_TRANSFER_V1, FRAME_TRANSPORT_VERSION, } from "../worker/protocol.js";
|
|
13
|
+
import { applyEmojiWidthPolicy, resolveBackendEmojiWidthPolicy } from "./emojiWidthPolicy.js";
|
|
13
14
|
import { createNodeBackendInlineInternal } from "./nodeBackendInline.js";
|
|
15
|
+
const WIDTH_POLICY_KEY = "widthPolicy";
|
|
14
16
|
function deferred() {
|
|
15
17
|
let resolve;
|
|
16
18
|
let reject;
|
|
@@ -42,9 +44,23 @@ function parsePositiveInt(n) {
|
|
|
42
44
|
return null;
|
|
43
45
|
return n;
|
|
44
46
|
}
|
|
45
|
-
function
|
|
47
|
+
function readNativeTargetFpsValues(cfg) {
|
|
46
48
|
const targetFpsCfg = cfg;
|
|
47
|
-
return
|
|
49
|
+
return {
|
|
50
|
+
camel: parsePositiveInt(targetFpsCfg.targetFps),
|
|
51
|
+
snake: parsePositiveInt(targetFpsCfg.target_fps),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function resolveTargetFps(fpsCap, nativeConfig) {
|
|
55
|
+
const values = readNativeTargetFpsValues(nativeConfig);
|
|
56
|
+
if (values.camel !== null && values.snake !== null && values.camel !== values.snake) {
|
|
57
|
+
throw new ZrUiError("ZRUI_INVALID_PROPS", `createNodeBackend config mismatch: nativeConfig.targetFps=${String(values.camel)} must match nativeConfig.target_fps=${String(values.snake)}.`);
|
|
58
|
+
}
|
|
59
|
+
const nativeTargetFps = values.camel ?? values.snake;
|
|
60
|
+
if (nativeTargetFps !== null && nativeTargetFps !== fpsCap) {
|
|
61
|
+
throw new ZrUiError("ZRUI_INVALID_PROPS", `createNodeBackend config mismatch: fpsCap=${String(fpsCap)} must match nativeConfig.targetFps/target_fps=${String(nativeTargetFps)}. Fix: set nativeConfig.targetFps (or target_fps) to ${String(fpsCap)}, or remove the override and use fpsCap only.`);
|
|
62
|
+
}
|
|
63
|
+
return fpsCap;
|
|
48
64
|
}
|
|
49
65
|
function safeErr(err) {
|
|
50
66
|
return err instanceof Error ? err : new Error(String(err));
|
|
@@ -170,11 +186,10 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
170
186
|
!Array.isArray(cfg.nativeConfig)
|
|
171
187
|
? cfg.nativeConfig
|
|
172
188
|
: Object.freeze({});
|
|
173
|
-
const nativeTargetFps =
|
|
174
|
-
const
|
|
189
|
+
const nativeTargetFps = resolveTargetFps(fpsCap, nativeConfig);
|
|
190
|
+
const initConfigBase = {
|
|
175
191
|
...nativeConfig,
|
|
176
|
-
//
|
|
177
|
-
// explicitly overridden in nativeConfig.
|
|
192
|
+
// fpsCap is the single frame-scheduling knob; native target fps must align.
|
|
178
193
|
targetFps: nativeTargetFps,
|
|
179
194
|
// Negotiation pins (docs/16 + docs/01)
|
|
180
195
|
requestedEngineAbiMajor: ZR_ENGINE_ABI_MAJOR,
|
|
@@ -187,6 +202,7 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
187
202
|
maxEventBytes,
|
|
188
203
|
frameTransport: frameTransportWire,
|
|
189
204
|
};
|
|
205
|
+
let initConfigResolved = null;
|
|
190
206
|
let worker = null;
|
|
191
207
|
let disposed = false;
|
|
192
208
|
let started = false;
|
|
@@ -369,6 +385,26 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
369
385
|
return;
|
|
370
386
|
}
|
|
371
387
|
case "events": {
|
|
388
|
+
if (!Number.isInteger(msg.byteLen) || msg.byteLen < 0) {
|
|
389
|
+
fatal = new ZrUiError("ZRUI_BACKEND_ERROR", `events: invalid byteLen=${String(msg.byteLen)}`);
|
|
390
|
+
failAll(fatal);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (msg.byteLen > msg.batch.byteLength) {
|
|
394
|
+
fatal = new ZrUiError("ZRUI_BACKEND_ERROR", `events: byteLen=${String(msg.byteLen)} exceeds batch.byteLength=${String(msg.batch.byteLength)}`);
|
|
395
|
+
failAll(fatal);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (msg.byteLen > maxEventBytes) {
|
|
399
|
+
fatal = new ZrUiError("ZRUI_BACKEND_ERROR", `events: byteLen=${String(msg.byteLen)} exceeds maxEventBytes=${String(maxEventBytes)}`);
|
|
400
|
+
failAll(fatal);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (!Number.isInteger(msg.droppedSinceLast) || msg.droppedSinceLast < 0) {
|
|
404
|
+
fatal = new ZrUiError("ZRUI_BACKEND_ERROR", `events: invalid droppedSinceLast=${String(msg.droppedSinceLast)}`);
|
|
405
|
+
failAll(fatal);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
372
408
|
const waiter = eventWaiters.shift();
|
|
373
409
|
if (waiter !== undefined) {
|
|
374
410
|
const buf = msg.batch;
|
|
@@ -569,6 +605,21 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
569
605
|
if (started)
|
|
570
606
|
return;
|
|
571
607
|
if (worker === null) {
|
|
608
|
+
if (initConfigResolved === null) {
|
|
609
|
+
const resolvedEmojiWidthPolicy = await resolveBackendEmojiWidthPolicy(cfg.emojiWidthPolicy, nativeConfig);
|
|
610
|
+
const nativeWidthPolicy = applyEmojiWidthPolicy(resolvedEmojiWidthPolicy);
|
|
611
|
+
initConfigResolved = {
|
|
612
|
+
...initConfigBase,
|
|
613
|
+
widthPolicy: nativeWidthPolicy,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
// Keep core measurement policy deterministic across stop/start cycles.
|
|
618
|
+
const widthPolicy = initConfigResolved[WIDTH_POLICY_KEY];
|
|
619
|
+
if (typeof widthPolicy === "number") {
|
|
620
|
+
setTextMeasureEmojiPolicy(widthPolicy === 0 ? "narrow" : "wide");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
572
623
|
startDef = deferred();
|
|
573
624
|
startSettled = false;
|
|
574
625
|
stopDef = null;
|
|
@@ -592,7 +643,7 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
592
643
|
worker.on("exit", (code) => {
|
|
593
644
|
handleWorkerExit(code);
|
|
594
645
|
});
|
|
595
|
-
send({ type: "init", config:
|
|
646
|
+
send({ type: "init", config: initConfigResolved });
|
|
596
647
|
}
|
|
597
648
|
if (startDef === null)
|
|
598
649
|
throw new Error("NodeBackend: invariant violated (startDef is null)");
|
|
@@ -937,6 +988,27 @@ export function createNodeBackendInternal(opts = {}) {
|
|
|
937
988
|
return snapshot;
|
|
938
989
|
}),
|
|
939
990
|
};
|
|
940
|
-
|
|
991
|
+
const out = Object.assign(backend, { debug, perf });
|
|
992
|
+
Object.defineProperties(out, {
|
|
993
|
+
[BACKEND_DRAWLIST_V2_MARKER]: {
|
|
994
|
+
value: useDrawlistV2,
|
|
995
|
+
writable: false,
|
|
996
|
+
enumerable: false,
|
|
997
|
+
configurable: false,
|
|
998
|
+
},
|
|
999
|
+
[BACKEND_MAX_EVENT_BYTES_MARKER]: {
|
|
1000
|
+
value: maxEventBytes,
|
|
1001
|
+
writable: false,
|
|
1002
|
+
enumerable: false,
|
|
1003
|
+
configurable: false,
|
|
1004
|
+
},
|
|
1005
|
+
[BACKEND_FPS_CAP_MARKER]: {
|
|
1006
|
+
value: fpsCap,
|
|
1007
|
+
writable: false,
|
|
1008
|
+
enumerable: false,
|
|
1009
|
+
configurable: false,
|
|
1010
|
+
},
|
|
1011
|
+
});
|
|
1012
|
+
return out;
|
|
941
1013
|
}
|
|
942
1014
|
//# sourceMappingURL=nodeBackend.js.map
|