bun-memory 1.1.21 → 1.1.23
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 +73 -123
- package/example/trigger-bot.ts +4 -0
- package/package.json +1 -1
- package/structs/Memory.ts +565 -805
- package/structs/Win32Error.ts +28 -284
- package/types/Memory.ts +143 -795
package/structs/Win32Error.ts
CHANGED
|
@@ -1,197 +1,51 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Win32 error helper for Bun using `bun:ffi`.
|
|
3
|
-
*
|
|
4
|
-
* Exposes {@link Win32Error}, an `Error` subclass that formats Windows error codes
|
|
5
|
-
* using `FormatMessageW` from `kernel32.dll`. Messages are memoized for performance
|
|
6
|
-
* and the resulting error string contains the failing operation, the numeric code,
|
|
7
|
-
* and the human-readable description.
|
|
8
|
-
*
|
|
9
|
-
* For a complete list of error codes, visit…
|
|
10
|
-
* https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes
|
|
11
|
-
*
|
|
12
|
-
* @remarks
|
|
13
|
-
* - Requires Windows operating system.
|
|
14
|
-
* - Requires Bun runtime environment (uses `bun:ffi`).
|
|
15
|
-
* - Designed to be fast and allocation-conscious.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```typescript
|
|
19
|
-
* import Win32Error from './Win32Error';
|
|
20
|
-
*
|
|
21
|
-
* // Typical usage in error handling
|
|
22
|
-
* try {
|
|
23
|
-
* const result = someWin32Operation();
|
|
24
|
-
* if (result === INVALID_HANDLE_VALUE) {
|
|
25
|
-
* throw new Win32Error('CreateFile', GetLastError());
|
|
26
|
-
* }
|
|
27
|
-
* } catch (error) {
|
|
28
|
-
* if (error instanceof Win32Error) {
|
|
29
|
-
* console.log(`Operation: ${error.what}`);
|
|
30
|
-
* console.log(`Error code: ${error.code}`);
|
|
31
|
-
* console.log(`Message: ${error.message}`);
|
|
32
|
-
* }
|
|
33
|
-
* }
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
1
|
import { dlopen, FFIType } from 'bun:ffi';
|
|
38
2
|
|
|
39
|
-
/**
|
|
40
|
-
* Minimal Kernel32 Windows API functions imported via Foreign Function Interface (FFI).
|
|
41
|
-
* This module only imports FormatMessageW for converting error codes to human-readable messages.
|
|
42
|
-
*
|
|
43
|
-
* @remarks
|
|
44
|
-
* FormatMessageW is used instead of FormatMessageA to properly handle Unicode characters
|
|
45
|
-
* in error messages, which is important for internationalization support.
|
|
46
|
-
*/
|
|
47
3
|
const { symbols: Kernel32 } = dlopen('kernel32.dll', {
|
|
48
|
-
/**
|
|
49
|
-
* FormatMessageW - Formats a message string using a message definition from a message table resource.
|
|
50
|
-
*
|
|
51
|
-
* @param dwFlags - Formatting options (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS)
|
|
52
|
-
* @param lpSource - Location of the message definition (unused when FROM_SYSTEM is specified)
|
|
53
|
-
* @param dwMessageId - Message identifier (Win32 error code)
|
|
54
|
-
* @param dwLanguageId - Language identifier (0 for system default)
|
|
55
|
-
* @param lpBuffer - Buffer to receive the formatted message
|
|
56
|
-
* @param nSize - Size of the buffer in TCHARs
|
|
57
|
-
* @param Arguments - Array of values for message insertion (unused with IGNORE_INSERTS)
|
|
58
|
-
* @returns Number of TCHARs stored in the buffer, 0 on failure
|
|
59
|
-
*/
|
|
60
4
|
FormatMessageW: { args: [FFIType.u32, FFIType.u64, FFIType.u32, FFIType.u32, FFIType.ptr, FFIType.u32, FFIType.u64], returns: FFIType.u32 },
|
|
61
5
|
});
|
|
62
6
|
|
|
63
7
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* This class extends the standard JavaScript Error class to provide enhanced
|
|
67
|
-
* error reporting for Windows API failures. It automatically formats Win32
|
|
68
|
-
* error codes into human-readable messages using the Windows FormatMessageW API.
|
|
69
|
-
*
|
|
70
|
-
* Key features:
|
|
71
|
-
* - Automatic error message formatting using Windows system messages
|
|
72
|
-
* - Message caching for improved performance on repeated error codes
|
|
73
|
-
* - Preserves both the operation name and numeric error code
|
|
74
|
-
* - Provides stack trace capture for debugging
|
|
8
|
+
* Represents a Windows (Win32) system error.
|
|
75
9
|
*
|
|
76
|
-
*
|
|
77
|
-
* ```typescript
|
|
78
|
-
* // Basic usage with a Win32 API call
|
|
79
|
-
* const hSnapshot = Kernel32.CreateToolhelp32Snapshot(dwFlags, th32ProcessID);
|
|
80
|
-
*
|
|
81
|
-
* if (hSnapshot === -1) {
|
|
82
|
-
* // Wrap with context and the last error code you observed
|
|
83
|
-
* throw new Win32Error('CreateToolhelp32Snapshot', Kernel32.GetLastError());
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
10
|
+
* Extends Error to provide formatted Win32 error messages using FormatMessageW.
|
|
86
11
|
*
|
|
87
12
|
* @example
|
|
88
|
-
* ```
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* const hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
|
|
92
|
-
* if (hProcess === 0n) {
|
|
93
|
-
* throw new Win32Error('OpenProcess', GetLastError());
|
|
94
|
-
* }
|
|
95
|
-
* } catch (error) {
|
|
96
|
-
* if (error instanceof Win32Error) {
|
|
97
|
-
* console.error(`Failed operation: ${error.what}`);
|
|
98
|
-
* console.error(`Win32 error code: ${error.code}`);
|
|
99
|
-
* console.error(`System message: ${error.message}`);
|
|
100
|
-
*
|
|
101
|
-
* // Handle specific error codes
|
|
102
|
-
* switch (error.code) {
|
|
103
|
-
* case 5: // ERROR_ACCESS_DENIED
|
|
104
|
-
* console.log('Access denied - try running as administrator');
|
|
105
|
-
* break;
|
|
106
|
-
* case 87: // ERROR_INVALID_PARAMETER
|
|
107
|
-
* console.log('Invalid parameter provided to the function');
|
|
108
|
-
* break;
|
|
109
|
-
* default:
|
|
110
|
-
* console.log('Unexpected error occurred');
|
|
111
|
-
* }
|
|
112
|
-
* }
|
|
113
|
-
* }
|
|
114
|
-
* ```
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```typescript
|
|
118
|
-
* // Custom error handling utility
|
|
119
|
-
* function handleWin32Result<T>(
|
|
120
|
-
* result: T,
|
|
121
|
-
* invalidValue: T,
|
|
122
|
-
* operation: string,
|
|
123
|
-
* getLastError: () => number
|
|
124
|
-
* ): T {
|
|
125
|
-
* if (result === invalidValue) {
|
|
126
|
-
* throw new Win32Error(operation, getLastError());
|
|
127
|
-
* }
|
|
128
|
-
* return result;
|
|
129
|
-
* }
|
|
130
|
-
*
|
|
131
|
-
* // Usage
|
|
132
|
-
* const handle = handleWin32Result(
|
|
133
|
-
* CreateFileW(filename, access, share, null, disposition, flags, null),
|
|
134
|
-
* INVALID_HANDLE_VALUE,
|
|
135
|
-
* 'CreateFileW',
|
|
136
|
-
* GetLastError
|
|
137
|
-
* );
|
|
13
|
+
* ```ts
|
|
14
|
+
* import Win32Error from './Win32Error';
|
|
15
|
+
* throw new Win32Error('OpenProcess', 5);
|
|
138
16
|
* ```
|
|
139
17
|
*/
|
|
140
18
|
class Win32Error extends Error {
|
|
141
19
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* The constructor automatically formats the Win32 error code into a human-readable
|
|
145
|
-
* message using the Windows FormatMessageW API. Messages are cached to improve
|
|
146
|
-
* performance when the same error code is encountered multiple times.
|
|
147
|
-
*
|
|
148
|
-
* The resulting error message follows the format:
|
|
149
|
-
* "{operation} failed ({code}): {system_message}"
|
|
150
|
-
*
|
|
151
|
-
* @param what - Name of the operation that failed (e.g., "OpenProcess", "CreateFile")
|
|
152
|
-
* @param code - The Win32 error code (DWORD) associated with the failure
|
|
153
|
-
*
|
|
154
|
-
* @throws {Error} This constructor does not throw, but may produce "Unknown error"
|
|
155
|
-
* messages if FormatMessageW fails to format the error code
|
|
156
|
-
*
|
|
20
|
+
* Win32 error code.
|
|
157
21
|
* @example
|
|
158
|
-
* ```
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null);
|
|
162
|
-
* if (hFile === INVALID_HANDLE_VALUE) {
|
|
163
|
-
* throw new Win32Error('CreateFileW', GetLastError());
|
|
22
|
+
* ```ts
|
|
23
|
+
* if (error instanceof Win32Error) {
|
|
24
|
+
* console.log(error.code);
|
|
164
25
|
* }
|
|
165
|
-
* // Result: "CreateFileW failed (2): The system cannot find the file specified."
|
|
166
26
|
* ```
|
|
167
|
-
|
|
27
|
+
*/
|
|
28
|
+
public readonly code: number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Name of the failed operation.
|
|
168
32
|
* @example
|
|
169
|
-
* ```
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* if (hProcess === 0n) {
|
|
173
|
-
* throw new Win32Error('OpenProcess', GetLastError());
|
|
33
|
+
* ```ts
|
|
34
|
+
* if (error instanceof Win32Error) {
|
|
35
|
+
* console.log(error.what);
|
|
174
36
|
* }
|
|
175
|
-
* // Result: "OpenProcess failed (5): Access is denied."
|
|
176
37
|
* ```
|
|
177
|
-
|
|
38
|
+
*/
|
|
39
|
+
public readonly what: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new Win32Error with a formatted message.
|
|
43
|
+
* @param what Name of the failed operation (e.g., "OpenProcess").
|
|
44
|
+
* @param code Win32 error code.
|
|
178
45
|
* @example
|
|
179
|
-
* ```
|
|
180
|
-
*
|
|
181
|
-
* const hHeap = GetProcessHeap();
|
|
182
|
-
* const ptr = HeapAlloc(hHeap, 0, 1024);
|
|
183
|
-
* if (ptr === 0n) {
|
|
184
|
-
* throw new Win32Error('HeapAlloc', GetLastError());
|
|
185
|
-
* }
|
|
186
|
-
* // Result: "HeapAlloc failed (8): Not enough memory resources are available to process this command."
|
|
46
|
+
* ```ts
|
|
47
|
+
* throw new Win32Error('CreateFileW', 2);
|
|
187
48
|
* ```
|
|
188
|
-
*
|
|
189
|
-
* @remarks
|
|
190
|
-
* - The constructor formats the error message using `FormatMessageW` and memoizes
|
|
191
|
-
* the message text per code to avoid repeated system calls
|
|
192
|
-
* - Messages are cleaned of newline characters and trimmed for consistent formatting
|
|
193
|
-
* - If FormatMessageW fails, "Unknown error" is used as the message
|
|
194
|
-
* - Stack trace is captured using Error.captureStackTrace when available
|
|
195
49
|
*/
|
|
196
50
|
constructor(what: string, code: number) {
|
|
197
51
|
let message = Win32Error.formatMessageWCache.get(code);
|
|
@@ -225,126 +79,16 @@ class Win32Error extends Error {
|
|
|
225
79
|
}
|
|
226
80
|
|
|
227
81
|
/**
|
|
228
|
-
* Cache of formatted error messages
|
|
229
|
-
*
|
|
230
|
-
* This cache stores the human-readable error messages returned by FormatMessageW
|
|
231
|
-
* to avoid repeated FFI calls for the same error codes. This optimization is
|
|
232
|
-
* particularly beneficial in scenarios where the same errors occur frequently.
|
|
233
|
-
*
|
|
234
|
-
* The cache is implemented as a static Map and persists for the lifetime of the
|
|
235
|
-
* application. Memory usage is typically minimal as there are a finite number
|
|
236
|
-
* of possible Win32 error codes, and most applications encounter only a subset.
|
|
237
|
-
*
|
|
238
|
-
* @remarks
|
|
239
|
-
* - Messages are cached after the first successful FormatMessageW call
|
|
240
|
-
* - Failed FormatMessageW calls result in "Unknown error" being cached
|
|
241
|
-
* - The cache is never cleared, ensuring consistent performance throughout application lifetime
|
|
242
|
-
* - Thread-safe in Node.js/Bun single-threaded environment
|
|
243
|
-
*
|
|
82
|
+
* Cache of formatted error messages by code.
|
|
244
83
|
* @private
|
|
245
84
|
*/
|
|
246
85
|
private static readonly formatMessageWCache = new Map<number, string>();
|
|
247
86
|
|
|
248
87
|
/**
|
|
249
|
-
* Static buffer
|
|
250
|
-
*
|
|
251
|
-
* This buffer is allocated once and reused for all FormatMessageW calls to minimize
|
|
252
|
-
* memory allocations. The buffer size of 4,096 bytes (2,048 UTF-16 characters) is
|
|
253
|
-
* sufficient for typical Windows system error messages.
|
|
254
|
-
*
|
|
255
|
-
* The buffer is allocated as unsafe (uninitialized) memory for performance, as
|
|
256
|
-
* FormatMessageW will overwrite its contents completely.
|
|
257
|
-
*
|
|
258
|
-
* @remarks
|
|
259
|
-
* - Buffer size: 4,096 bytes (2,048 UTF-16 characters)
|
|
260
|
-
* - Shared across all Win32Error instances to minimize memory footprint
|
|
261
|
-
* - Contents are overwritten on each FormatMessageW call
|
|
262
|
-
* - Adequate size for all standard Windows system error messages
|
|
263
|
-
*
|
|
88
|
+
* Static buffer for FormatMessageW calls.
|
|
264
89
|
* @private
|
|
265
90
|
*/
|
|
266
91
|
private static readonly scratch4096 = Buffer.allocUnsafe(4_096);
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* The Win32 error code associated with this failure.
|
|
270
|
-
*
|
|
271
|
-
* This property contains the numeric error code that was returned by the Windows API
|
|
272
|
-
* function GetLastError() at the time of the failure. This code can be used for
|
|
273
|
-
* programmatic error handling and logging.
|
|
274
|
-
*
|
|
275
|
-
* Common Win32 error codes include:
|
|
276
|
-
* - 2: ERROR_FILE_NOT_FOUND - The system cannot find the file specified
|
|
277
|
-
* - 3: ERROR_PATH_NOT_FOUND - The system cannot find the path specified
|
|
278
|
-
* - 5: ERROR_ACCESS_DENIED - Access is denied
|
|
279
|
-
* - 6: ERROR_INVALID_HANDLE - The handle is invalid
|
|
280
|
-
* - 87: ERROR_INVALID_PARAMETER - The parameter is incorrect
|
|
281
|
-
* - 122: ERROR_INSUFFICIENT_BUFFER - The data area passed to a system call is too small
|
|
282
|
-
*
|
|
283
|
-
* @example
|
|
284
|
-
* ```typescript
|
|
285
|
-
* try {
|
|
286
|
-
* // Some Win32 operation that might fail
|
|
287
|
-
* performWin32Operation();
|
|
288
|
-
* } catch (error) {
|
|
289
|
-
* if (error instanceof Win32Error) {
|
|
290
|
-
* switch (error.code) {
|
|
291
|
-
* case 2: // ERROR_FILE_NOT_FOUND
|
|
292
|
-
* console.log('File not found, creating new file...');
|
|
293
|
-
* break;
|
|
294
|
-
* case 5: // ERROR_ACCESS_DENIED
|
|
295
|
-
* console.log('Access denied, requesting elevated privileges...');
|
|
296
|
-
* break;
|
|
297
|
-
* default:
|
|
298
|
-
* console.log(`Unexpected error code: ${error.code}`);
|
|
299
|
-
* }
|
|
300
|
-
* }
|
|
301
|
-
* }
|
|
302
|
-
* ```
|
|
303
|
-
*
|
|
304
|
-
* @readonly
|
|
305
|
-
*/
|
|
306
|
-
public readonly code: number;
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* The operation or Windows API function name that failed.
|
|
310
|
-
*
|
|
311
|
-
* This property contains the name of the operation or API function that was being
|
|
312
|
-
* executed when the error occurred. It provides context for debugging and logging,
|
|
313
|
-
* making it easier to identify which specific operation failed in complex code.
|
|
314
|
-
*
|
|
315
|
-
* The operation name is typically the exact name of the Win32 API function that
|
|
316
|
-
* was called, but can also be a descriptive name for higher-level operations.
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```typescript
|
|
320
|
-
* try {
|
|
321
|
-
* const hFile = CreateFileW(filename, access, share, null, disposition, flags, null);
|
|
322
|
-
* if (hFile === INVALID_HANDLE_VALUE) {
|
|
323
|
-
* throw new Win32Error('CreateFileW', GetLastError());
|
|
324
|
-
* }
|
|
325
|
-
* } catch (error) {
|
|
326
|
-
* if (error instanceof Win32Error) {
|
|
327
|
-
* console.log(`Failed operation: ${error.what}`); // "CreateFileW"
|
|
328
|
-
* console.log(`Error details: ${error.message}`); // "CreateFileW failed (2): The system cannot find the file specified."
|
|
329
|
-
* }
|
|
330
|
-
* }
|
|
331
|
-
* ```
|
|
332
|
-
*
|
|
333
|
-
* @example
|
|
334
|
-
* ```typescript
|
|
335
|
-
* // Using descriptive operation names for complex operations
|
|
336
|
-
* try {
|
|
337
|
-
* // Multiple API calls involved in process enumeration
|
|
338
|
-
* enumerateProcesses();
|
|
339
|
-
* } catch (apiError) {
|
|
340
|
-
* // Re-throw with more descriptive operation name
|
|
341
|
-
* throw new Win32Error('ProcessEnumeration', apiError.code);
|
|
342
|
-
* }
|
|
343
|
-
* ```
|
|
344
|
-
*
|
|
345
|
-
* @readonly
|
|
346
|
-
*/
|
|
347
|
-
public readonly what: string;
|
|
348
92
|
}
|
|
349
93
|
|
|
350
94
|
export default Win32Error;
|