@fireemu/win32-x64 0.1.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.
@@ -0,0 +1,128 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { format } from "node:util";
3
+
4
+ const CONSOLE_LEVELS = Object.freeze({
5
+ log: "info",
6
+ info: "info",
7
+ debug: "debug",
8
+ warn: "error",
9
+ error: "error",
10
+ });
11
+
12
+ const TRUNCATION_MARKER = "... [truncated]";
13
+ const STRUCTURED_SEVERITIES = new Set([
14
+ "DEBUG",
15
+ "INFO",
16
+ "NOTICE",
17
+ "WARNING",
18
+ "ERROR",
19
+ "CRITICAL",
20
+ "ALERT",
21
+ "EMERGENCY",
22
+ ]);
23
+ const MAX_STRUCTURED_LOG_DEPTH = 64;
24
+
25
+ // Cloud Logging documents an approximate 256 KiB limit for the whole LogEntry. Applying that
26
+ // value conservatively to the message also leaves ample room below the 16 MiB protocol limit.
27
+ export const MAX_LOG_MESSAGE_BYTES = 256 * 1024;
28
+
29
+ export function boundLogMessage(value, maxBytes = MAX_LOG_MESSAGE_BYTES) {
30
+ const bytes = Buffer.from(String(value), "utf8");
31
+ // A UTF-8 round trip replaces lone UTF-16 surrogates while preserving valid pairs. Without
32
+ // this, JSON.stringify emits an escape that serde_json correctly refuses on the protocol side.
33
+ const message = bytes.toString("utf8");
34
+ if (bytes.length <= maxBytes) return message;
35
+ const marker = Buffer.from(TRUNCATION_MARKER, "utf8");
36
+ if (maxBytes <= marker.length) return marker.subarray(0, maxBytes).toString("utf8");
37
+ let end = maxBytes - marker.length;
38
+ while (end > 0 && (bytes[end] & 0xc0) === 0x80) end -= 1;
39
+ return `${bytes.subarray(0, end).toString("utf8")}${TRUNCATION_MARKER}`;
40
+ }
41
+
42
+ function hasUnpairedSurrogate(text) {
43
+ for (let index = 0; index < text.length; index += 1) {
44
+ const unit = text.charCodeAt(index);
45
+ if (unit >= 0xd800 && unit <= 0xdbff) {
46
+ const next = text.charCodeAt(index + 1);
47
+ if (!(next >= 0xdc00 && next <= 0xdfff)) return true;
48
+ index += 1;
49
+ } else if (unit >= 0xdc00 && unit <= 0xdfff) {
50
+ return true;
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+
56
+ function isSafeStructuredValue(root) {
57
+ const pending = [{ value: root, depth: 1 }];
58
+ while (pending.length > 0) {
59
+ const { value, depth } = pending.pop();
60
+ if (depth > MAX_STRUCTURED_LOG_DEPTH) return false;
61
+ if (typeof value === "string" && hasUnpairedSurrogate(value)) return false;
62
+ if (value && typeof value === "object") {
63
+ for (const [key, child] of Object.entries(value)) {
64
+ if (hasUnpairedSurrogate(key)) return false;
65
+ pending.push({ value: child, depth: depth + 1 });
66
+ }
67
+ }
68
+ }
69
+ return true;
70
+ }
71
+
72
+ function structuredEntry(message, fallbackLevel) {
73
+ try {
74
+ const parsed = JSON.parse(message);
75
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
76
+ return { level: fallbackLevel, message };
77
+ }
78
+ const severity = typeof parsed?.severity === "string" ? parsed.severity.toUpperCase() : "";
79
+ if (!STRUCTURED_SEVERITIES.has(severity) || !isSafeStructuredValue(parsed)) {
80
+ return { level: fallbackLevel, message };
81
+ }
82
+ const { severity: _severity, message: structuredMessage, ...fields } = parsed;
83
+ return {
84
+ level: severity.toLowerCase(),
85
+ message: typeof structuredMessage === "string" ? structuredMessage : "",
86
+ fields,
87
+ };
88
+ } catch {
89
+ // Plain console output is not structured logging.
90
+ }
91
+ return { level: fallbackLevel, message };
92
+ }
93
+
94
+ export function createInvocationLogger(emit) {
95
+ const context = new AsyncLocalStorage();
96
+
97
+ return {
98
+ run(metadata, task) {
99
+ return context.run(metadata, task);
100
+ },
101
+ install(target = console) {
102
+ const originals = new Map();
103
+ for (const [method, level] of Object.entries(CONSOLE_LEVELS)) {
104
+ const original = target[method].bind(target);
105
+ originals.set(method, original);
106
+ target[method] = (...values) => {
107
+ const active = context.getStore();
108
+ if (!active?.functionName) {
109
+ original(...values);
110
+ return;
111
+ }
112
+ const message = boundLogMessage(format(...values));
113
+ const entry =
114
+ values.length === 1 ? structuredEntry(message, level) : { level, message };
115
+ emit({
116
+ ...entry,
117
+ functionName: active.functionName,
118
+ invocationId: active.invocationId,
119
+ user: true,
120
+ });
121
+ };
122
+ }
123
+ return () => {
124
+ for (const [method, original] of originals) target[method] = original;
125
+ };
126
+ },
127
+ };
128
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@fireemu/win32-x64",
3
+ "version": "0.1.0",
4
+ "description": "The fireemu daemon for win32-x64",
5
+ "homepage": "https://github.com/t-k/fireemu#readme",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/t-k/fireemu.git"
9
+ },
10
+ "license": "Apache-2.0",
11
+ "os": [
12
+ "win32"
13
+ ],
14
+ "cpu": [
15
+ "x64"
16
+ ],
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "files": [
21
+ "bin",
22
+ "README.md",
23
+ "LICENSE",
24
+ "THIRD_PARTY_LICENSES.txt"
25
+ ],
26
+ "preferUnplugged": true
27
+ }