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.
@@ -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
- * Error class representing a Windows (Win32) system error.
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
- * @example
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
- * ```typescript
89
- * // Error handling and inspection
90
- * try {
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
- * Creates a new Win32Error instance with formatted error message.
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
- * ```typescript
159
- * // Handle a file operation failure
160
- * const hFile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ,
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
- * ```typescript
170
- * // Handle process access failure
171
- * const hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, 1234);
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
- * ```typescript
180
- * // Handle memory allocation failure
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 keyed by Win32 error code.
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 used for FormatMessageW system calls.
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;