bun-memory 1.1.24 → 1.1.26

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/structs/Memory.ts CHANGED
@@ -1,9 +1,11 @@
1
- import { CString, FFIType, dlopen } from 'bun:ffi';
1
+ import { CString, FFIType, dlopen, ptr } from 'bun:ffi';
2
2
 
3
3
  import type { Module, NetworkUtlVector, Point, QAngle, Quaternion, Region, RGB, RGBA, Scratch, UPtr, UPtrArray, Vector2, Vector3, Vector4 } from '../types/Memory';
4
4
  import Win32Error from './Win32Error';
5
5
 
6
- const { symbols: Kernel32 } = dlopen('kernel32.dll', {
6
+ const {
7
+ symbols: { CloseHandle, CreateToolhelp32Snapshot, GetLastError, Module32FirstW, Module32NextW, OpenProcess, Process32FirstW, Process32NextW, ReadProcessMemory, VirtualQueryEx, WriteProcessMemory },
8
+ } = dlopen('kernel32.dll', {
7
9
  CloseHandle: { args: [FFIType.u64], returns: FFIType.bool },
8
10
  CreateToolhelp32Snapshot: { args: [FFIType.u32, FFIType.u32], returns: FFIType.u64 },
9
11
  GetLastError: { returns: FFIType.u32 },
@@ -27,6 +29,7 @@ const { symbols: Kernel32 } = dlopen('kernel32.dll', {
27
29
  * Many scalar reads utilize `TypedArray` scratches to avoid a second FFI hop, such as calling `bun:ffi.read.*`.
28
30
  *
29
31
  * @todo Add support for 32 or 64-bit processes using IsWow64Process2 (Windows 10+).
32
+ * @todo When adding 32-bit support, several u64 will need changed to u64_fast.
30
33
  *
31
34
  * @example
32
35
  * ```ts
@@ -50,21 +53,21 @@ class Memory {
50
53
  const dwFlags = 0x00000002; /* TH32CS_SNAPPROCESS */
51
54
  const th32ProcessID = 0;
52
55
 
53
- const hSnapshot = Kernel32.CreateToolhelp32Snapshot(dwFlags, th32ProcessID);
56
+ const hSnapshot = CreateToolhelp32Snapshot(dwFlags, th32ProcessID);
54
57
 
55
58
  if (hSnapshot === -1n) {
56
- throw new Win32Error('CreateToolhelp32Snapshot', Kernel32.GetLastError());
59
+ throw new Win32Error('CreateToolhelp32Snapshot', GetLastError());
57
60
  }
58
61
 
59
62
  const lppe = Buffer.allocUnsafe(0x238 /* sizeof(PROCESSENTRY32) */);
60
63
  /* */ lppe.writeUInt32LE(0x238 /* sizeof(PROCESSENTRY32) */);
61
64
 
62
- const bProcess32FirstW = Kernel32.Process32FirstW(hSnapshot, lppe);
65
+ const bProcess32FirstW = Process32FirstW(hSnapshot, lppe);
63
66
 
64
67
  if (!bProcess32FirstW) {
65
- Kernel32.CloseHandle(hSnapshot);
68
+ CloseHandle(hSnapshot);
66
69
 
67
- throw new Win32Error('Process32FirstW', Kernel32.GetLastError());
70
+ throw new Win32Error('Process32FirstW', GetLastError());
68
71
  }
69
72
 
70
73
  do {
@@ -81,12 +84,12 @@ class Memory {
81
84
  const desiredAccess = 0x001f0fff; /* PROCESS_ALL_ACCESS */
82
85
  const inheritHandle = false;
83
86
 
84
- const hProcess = Kernel32.OpenProcess(desiredAccess, inheritHandle, th32ProcessID);
87
+ const hProcess = OpenProcess(desiredAccess, inheritHandle, th32ProcessID);
85
88
 
86
89
  if (hProcess === 0n) {
87
- Kernel32.CloseHandle(hSnapshot);
90
+ CloseHandle(hSnapshot);
88
91
 
89
- throw new Win32Error('OpenProcess', Kernel32.GetLastError());
92
+ throw new Win32Error('OpenProcess', GetLastError());
90
93
  }
91
94
 
92
95
  this._modules = {};
@@ -96,12 +99,12 @@ class Memory {
96
99
 
97
100
  this.refresh();
98
101
 
99
- Kernel32.CloseHandle(hSnapshot);
102
+ CloseHandle(hSnapshot);
100
103
 
101
104
  return;
102
- } while (Kernel32.Process32NextW(hSnapshot, lppe));
105
+ } while (Process32NextW(hSnapshot, lppe));
103
106
 
104
- Kernel32.CloseHandle(hSnapshot);
107
+ CloseHandle(hSnapshot);
105
108
 
106
109
  throw new Error(`Process not found: ${identifier}…`);
107
110
  }
@@ -180,10 +183,10 @@ class Memory {
180
183
  let lpAddress = BigInt(address); // prettier-ignore
181
184
  const lpBuffer = this.ScratchMemoryBasicInformation;
182
185
 
183
- const bVirtualQueryEx = !!Kernel32.VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength);
186
+ const bVirtualQueryEx = !!VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength);
184
187
 
185
188
  if (!bVirtualQueryEx) {
186
- throw new Win32Error('VirtualQueryEx', Kernel32.GetLastError());
189
+ throw new Win32Error('VirtualQueryEx', GetLastError());
187
190
  }
188
191
 
189
192
  const end = lpAddress + BigInt(length);
@@ -201,11 +204,101 @@ class Memory {
201
204
  }
202
205
 
203
206
  lpAddress = baseAddress + regionSize;
204
- } while (lpAddress < end && !!Kernel32.VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength));
207
+ } while (lpAddress < end && !!VirtualQueryEx(this.hProcess, lpAddress, lpBuffer, dwLength));
205
208
 
206
209
  return result;
207
210
  }
208
211
 
212
+ /**
213
+ * Closes the process handle.
214
+ * @example
215
+ * ```ts
216
+ * const cs2 = new Memory('cs2.exe');
217
+ * cs2.close();
218
+ * ```
219
+ */
220
+ public close(): void {
221
+ CloseHandle(this.hProcess);
222
+
223
+ return;
224
+ }
225
+
226
+ /**
227
+ * Disposes resources held by this Memory instance.
228
+ * Called automatically when using `using` blocks.
229
+ * @example
230
+ * ```ts
231
+ * using const mem = new Memory('cs2.exe');
232
+ * // mem is disposed at the end of the block
233
+ * ```
234
+ */
235
+ public [Symbol.dispose](): void {
236
+ this.close();
237
+
238
+ return;
239
+ }
240
+
241
+ /**
242
+ * Asynchronously disposes resources held by this Memory instance.
243
+ * Use in `await using` blocks for async cleanup.
244
+ * @example
245
+ * ```ts
246
+ * await using const mem = new Memory('cs2.exe');
247
+ * // mem is disposed asynchronously at the end of the block
248
+ * ```
249
+ */
250
+ public [Symbol.asyncDispose](): Promise<void> {
251
+ this.close();
252
+
253
+ return Promise.resolve();
254
+ }
255
+
256
+ /**
257
+ * Refreshes the module list for the process.
258
+ * @example
259
+ * ```ts
260
+ * const cs2 = new Memory('cs2.exe');
261
+ * cs2.refresh();
262
+ * ```
263
+ */
264
+ public refresh(): void {
265
+ const dwFlags = 0x00000008 /* TH32CS_SNAPMODULE */ | 0x00000010; /* TH32CS_SNAPMODULE32 */
266
+
267
+ const hSnapshot = CreateToolhelp32Snapshot(dwFlags, this.th32ProcessID)!;
268
+
269
+ if (hSnapshot === -1n) {
270
+ throw new Win32Error('CreateToolhelp32Snapshot', GetLastError());
271
+ }
272
+
273
+ this.ScratchModuleEntry32W.writeUInt32LE(0x438 /* sizeof(MODULEENTRY32W) */);
274
+
275
+ const lpme = this.ScratchModuleEntry32W;
276
+
277
+ const bModule32FirstW = Module32FirstW(hSnapshot, lpme);
278
+
279
+ if (!bModule32FirstW) {
280
+ CloseHandle(hSnapshot);
281
+
282
+ throw new Win32Error('Module32FirstW', GetLastError());
283
+ }
284
+
285
+ const modules: Memory['_modules'] = {};
286
+
287
+ do {
288
+ const modBaseAddr = lpme.readBigUInt64LE(0x18);
289
+ const modBaseSize = lpme.readUInt32LE(0x20);
290
+ const szModule = lpme.toString('utf16le', 0x30, 0x230).replace(/\0+$/, '');
291
+
292
+ modules[szModule] = Object.freeze({ base: modBaseAddr, name: szModule, size: modBaseSize });
293
+ } while (Module32NextW(hSnapshot, lpme));
294
+
295
+ CloseHandle(hSnapshot);
296
+
297
+ this._modules = Object.freeze(modules);
298
+
299
+ return;
300
+ }
301
+
209
302
  /**
210
303
  * Follows a pointer chain with offsets.
211
304
  * @param address Base address.
@@ -236,6 +329,7 @@ class Memory {
236
329
  * @param address Address to read from.
237
330
  * @param scratch Buffer to fill.
238
331
  * @returns The filled buffer.
332
+ * @todo Consider inlining the call in the if to cut a binding… I hate the idea… 🫠…
239
333
  * @example
240
334
  * ```ts
241
335
  * const cs2 = new Memory('cs2.exe');
@@ -244,14 +338,14 @@ class Memory {
244
338
  */
245
339
  public read<T extends Scratch>(address: bigint, scratch: T): T {
246
340
  const lpBaseAddress = address;
247
- const lpBuffer = scratch.ptr;
341
+ const lpBuffer = ptr(scratch);
248
342
  const nSize = scratch.byteLength;
249
343
  const numberOfBytesRead = 0x00n;
250
344
 
251
- const bReadProcessMemory = Kernel32.ReadProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesRead);
345
+ const bReadProcessMemory = ReadProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesRead);
252
346
 
253
347
  if (!bReadProcessMemory) {
254
- throw new Win32Error('ReadProcessMemory', Kernel32.GetLastError());
348
+ throw new Win32Error('ReadProcessMemory', GetLastError());
255
349
  }
256
350
 
257
351
  return scratch;
@@ -262,6 +356,8 @@ class Memory {
262
356
  * @param address Address to write to.
263
357
  * @param scratch Buffer to write.
264
358
  * @returns This instance.
359
+ * @todo Add a `force: boolean` option that uses `VirtualProtectEx` for a temporary protection change when set to `true`.
360
+ * @todo Consider inlining the call in the if to cut a binding… I hate the idea… 🫠…
265
361
  * @example
266
362
  * ```ts
267
363
  * const cs2 = new Memory('cs2.exe');
@@ -274,75 +370,15 @@ class Memory {
274
370
  const nSize = scratch.byteLength;
275
371
  const numberOfBytesWritten = 0x00n;
276
372
 
277
- const WriteProcessMemory = Kernel32.WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
373
+ const bWriteProcessMemory = WriteProcessMemory(this.hProcess, lpBaseAddress, lpBuffer, nSize, numberOfBytesWritten);
278
374
 
279
- if (!WriteProcessMemory) {
280
- throw new Win32Error('WriteProcessMemory', Kernel32.GetLastError());
375
+ if (!bWriteProcessMemory) {
376
+ throw new Win32Error('WriteProcessMemory', GetLastError());
281
377
  }
282
378
 
283
379
  return this;
284
380
  }
285
381
 
286
- /**
287
- * Closes the process handle.
288
- * @example
289
- * ```ts
290
- * const cs2 = new Memory('cs2.exe');
291
- * cs2.close();
292
- * ```
293
- */
294
- public close(): void {
295
- Kernel32.CloseHandle(this.hProcess);
296
-
297
- return;
298
- }
299
-
300
- /**
301
- * Refreshes the module list for the process.
302
- * @example
303
- * ```ts
304
- * const cs2 = new Memory('cs2.exe');
305
- * cs2.refresh();
306
- * ```
307
- */
308
- public refresh(): void {
309
- const dwFlags = 0x00000008 /* TH32CS_SNAPMODULE */ | 0x00000010; /* TH32CS_SNAPMODULE32 */
310
-
311
- const hSnapshot = Kernel32.CreateToolhelp32Snapshot(dwFlags, this.th32ProcessID)!;
312
-
313
- if (hSnapshot === -1n) {
314
- throw new Win32Error('CreateToolhelp32Snapshot', Kernel32.GetLastError());
315
- }
316
-
317
- this.ScratchModuleEntry32W.writeUInt32LE(0x438 /* sizeof(MODULEENTRY32W) */);
318
-
319
- const lpme = this.ScratchModuleEntry32W;
320
-
321
- const bModule32FirstW = Kernel32.Module32FirstW(hSnapshot, lpme);
322
-
323
- if (!bModule32FirstW) {
324
- Kernel32.CloseHandle(hSnapshot);
325
-
326
- throw new Win32Error('Module32FirstW', Kernel32.GetLastError());
327
- }
328
-
329
- const modules: Memory['_modules'] = {};
330
-
331
- do {
332
- const modBaseAddr = lpme.readBigUInt64LE(0x18);
333
- const modBaseSize = lpme.readUInt32LE(0x20);
334
- const szModule = lpme.toString('utf16le', 0x30, 0x230).replace(/\0+$/, '');
335
-
336
- modules[szModule] = Object.freeze({ base: modBaseAddr, name: szModule, size: modBaseSize });
337
- } while (Kernel32.Module32NextW(hSnapshot, lpme));
338
-
339
- Kernel32.CloseHandle(hSnapshot);
340
-
341
- this._modules = Object.freeze(modules);
342
-
343
- return;
344
- }
345
-
346
382
  /**
347
383
  * Reads or writes a boolean value.
348
384
  * @param address Address to access.
@@ -996,6 +1032,22 @@ class Memory {
996
1032
  return this;
997
1033
  }
998
1034
 
1035
+ public pointRaw(address: bigint): Float32Array;
1036
+ public pointRaw(address: bigint, values: Float32Array): this;
1037
+ public pointRaw(address: bigint, values?: Float32Array): Float32Array | this {
1038
+ if (values === undefined) {
1039
+ return this.f32Array(address, 0x02);
1040
+ }
1041
+
1042
+ if (values.length !== 0x02) {
1043
+ throw new RangeError('values.length must be 2.');
1044
+ }
1045
+
1046
+ this.write(address, values);
1047
+
1048
+ return this;
1049
+ }
1050
+
999
1051
  /**
1000
1052
  * Reads or writes a QAngle (object with pitch, yaw, roll).
1001
1053
  * @param address Address to access.
@@ -1059,6 +1111,7 @@ class Memory {
1059
1111
  const pitch = scratch[j];
1060
1112
  const yaw = scratch[j + 0x01];
1061
1113
  const roll = scratch[j + 0x02];
1114
+
1062
1115
  result[i] = { pitch, yaw, roll };
1063
1116
  }
1064
1117
 
@@ -1081,6 +1134,34 @@ class Memory {
1081
1134
  return this;
1082
1135
  }
1083
1136
 
1137
+ /**
1138
+ * Reads or writes a raw QAngle as a Float32Array.
1139
+ * @param address Address to access.
1140
+ * @param values Optional Float32Array to write.
1141
+ * @returns Float32Array read or this instance if writing.
1142
+ * @example
1143
+ * ```ts
1144
+ * const cs2 = new Memory('cs2.exe');
1145
+ * const raw = cs2.qAngleRaw(0x12345678n);
1146
+ * cs2.qAngleRaw(0x12345678n, new Float32Array([1,2,3]));
1147
+ * ```
1148
+ */
1149
+ public qAngleRaw(address: bigint): Float32Array;
1150
+ public qAngleRaw(address: bigint, values: Float32Array): this;
1151
+ public qAngleRaw(address: bigint, values?: Float32Array): Float32Array | this {
1152
+ if (values === undefined) {
1153
+ return this.f32Array(address, 0x03);
1154
+ }
1155
+
1156
+ if (values.length !== 0x03) {
1157
+ throw new RangeError('values.length must be 3.');
1158
+ }
1159
+
1160
+ this.write(address, values);
1161
+
1162
+ return this;
1163
+ }
1164
+
1084
1165
  /**
1085
1166
  * Reads or writes a Quaternion (object with w, x, y, z).
1086
1167
  * @param address Address to access.
@@ -1171,6 +1252,34 @@ class Memory {
1171
1252
  return this;
1172
1253
  }
1173
1254
 
1255
+ /**
1256
+ * Reads or writes a raw Quaternion as a Float32Array.
1257
+ * @param address Address to access.
1258
+ * @param values Optional Float32Array to write.
1259
+ * @returns Float32Array read or this instance if writing.
1260
+ * @example
1261
+ * ```ts
1262
+ * const cs2 = new Memory('cs2.exe');
1263
+ * const raw = cs2.quaternionRaw(0x12345678n);
1264
+ * cs2.quaternionRaw(0x12345678n, new Float32Array([1,0,0,0]));
1265
+ * ```
1266
+ */
1267
+ public quaternionRaw(address: bigint): Float32Array;
1268
+ public quaternionRaw(address: bigint, values: Float32Array): this;
1269
+ public quaternionRaw(address: bigint, values?: Float32Array): Float32Array | this {
1270
+ if (values === undefined) {
1271
+ return this.f32Array(address, 0x04);
1272
+ }
1273
+
1274
+ if (values.length !== 0x04) {
1275
+ throw new RangeError('values.length must be 4.');
1276
+ }
1277
+
1278
+ this.write(address, values);
1279
+
1280
+ return this;
1281
+ }
1282
+
1174
1283
  /**
1175
1284
  * Reads or writes an RGB color (object with r, g, b).
1176
1285
  * @param address Address to access.
@@ -1205,6 +1314,34 @@ class Memory {
1205
1314
  return this.write(address, Scratch3);
1206
1315
  }
1207
1316
 
1317
+ /**
1318
+ * Reads or writes a raw RGB value as a Uint8Array.
1319
+ * @param address Address to access.
1320
+ * @param values Optional buffer to write.
1321
+ * @returns Uint8Array read or this instance if writing.
1322
+ * @example
1323
+ * ```ts
1324
+ * const cs2 = new Memory('cs2.exe');
1325
+ * const raw = cs2.rgbRaw(0x12345678n);
1326
+ * cs2.rgbRaw(0x12345678n, new Uint8Array([255,0,0]));
1327
+ * ```
1328
+ */
1329
+ public rgbRaw(address: bigint): Uint8Array;
1330
+ public rgbRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray): this;
1331
+ public rgbRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray): Uint8Array | this {
1332
+ if (values === undefined) {
1333
+ return this.u8Array(address, 0x03);
1334
+ }
1335
+
1336
+ if (values.length !== 0x03) {
1337
+ throw new RangeError('values.length must be 3.');
1338
+ }
1339
+
1340
+ this.write(address, values);
1341
+
1342
+ return this;
1343
+ }
1344
+
1208
1345
  /**
1209
1346
  * Reads or writes an RGBA color (object with r, g, b, a).
1210
1347
  * @param address Address to access.
@@ -1241,6 +1378,34 @@ class Memory {
1241
1378
  return this.write(address, Scratch4);
1242
1379
  }
1243
1380
 
1381
+ /**
1382
+ * Reads or writes a raw RGBA value as a Uint8Array.
1383
+ * @param address Address to access.
1384
+ * @param values Optional buffer to write.
1385
+ * @returns Uint8Array read or this instance if writing.
1386
+ * @example
1387
+ * ```ts
1388
+ * const cs2 = new Memory('cs2.exe');
1389
+ * const raw = cs2.rgbaRaw(0x12345678n);
1390
+ * cs2.rgbaRaw(0x12345678n, new Uint8Array([255,0,0,255]));
1391
+ * ```
1392
+ */
1393
+ public rgbaRaw(address: bigint): Uint8Array;
1394
+ public rgbaRaw(address: bigint, values: Buffer | Uint8Array | Uint8ClampedArray): this;
1395
+ public rgbaRaw(address: bigint, values?: Buffer | Uint8Array | Uint8ClampedArray): Uint8Array | this {
1396
+ if (values === undefined) {
1397
+ return this.u8Array(address, 0x04);
1398
+ }
1399
+
1400
+ if (values.length !== 0x04) {
1401
+ throw new RangeError('values.length must be 4.');
1402
+ }
1403
+
1404
+ this.write(address, values);
1405
+
1406
+ return this;
1407
+ }
1408
+
1244
1409
  /**
1245
1410
  * Reads or writes a 16-bit unsigned integer.
1246
1411
  * @param address Address to access.
@@ -1569,6 +1734,22 @@ class Memory {
1569
1734
  return this.pointArray(address, lengthOrValues);
1570
1735
  }
1571
1736
 
1737
+ public vector2Raw(address: bigint): Float32Array;
1738
+ public vector2Raw(address: bigint, values: Float32Array): this;
1739
+ public vector2Raw(address: bigint, values?: Float32Array): Float32Array | this {
1740
+ if (values === undefined) {
1741
+ return this.f32Array(address, 0x02);
1742
+ }
1743
+
1744
+ if (values.length !== 0x02) {
1745
+ throw new RangeError('values.length must be 2.');
1746
+ }
1747
+
1748
+ this.write(address, values);
1749
+
1750
+ return this;
1751
+ }
1752
+
1572
1753
  /**
1573
1754
  * Reads or writes a Vector3 (object with x, y, z).
1574
1755
  * @param address Address to access.
@@ -1655,6 +1836,22 @@ class Memory {
1655
1836
  return this;
1656
1837
  }
1657
1838
 
1839
+ public vector3Raw(address: bigint): Float32Array;
1840
+ public vector3Raw(address: bigint, values: Float32Array): this;
1841
+ public vector3Raw(address: bigint, values?: Float32Array): Float32Array | this {
1842
+ if (values === undefined) {
1843
+ return this.f32Array(address, 0x03);
1844
+ }
1845
+
1846
+ if (values.length !== 0x03) {
1847
+ throw new RangeError('values.length must be 3.');
1848
+ }
1849
+
1850
+ this.write(address, values);
1851
+
1852
+ return this;
1853
+ }
1854
+
1658
1855
  /**
1659
1856
  * Reads or writes a Vector4 (object with w, x, y, z).
1660
1857
  * @param address Address to access.
@@ -1701,6 +1898,22 @@ class Memory {
1701
1898
  return this.quaternionArray(address, lengthOrValues);
1702
1899
  }
1703
1900
 
1901
+ public vector4Raw(address: bigint): Float32Array;
1902
+ public vector4Raw(address: bigint, values: Float32Array): this;
1903
+ public vector4Raw(address: bigint, values?: Float32Array): Float32Array | this {
1904
+ if (values === undefined) {
1905
+ return this.f32Array(address, 0x04);
1906
+ }
1907
+
1908
+ if (values.length !== 0x04) {
1909
+ throw new RangeError('values.length must be 4.');
1910
+ }
1911
+
1912
+ this.write(address, values);
1913
+
1914
+ return this;
1915
+ }
1916
+
1704
1917
  // Public utility methods…
1705
1918
 
1706
1919
  /**
@@ -1716,19 +1929,15 @@ class Memory {
1716
1929
  * ```
1717
1930
  */
1718
1931
  public indexOf(needle: Scratch, address: bigint, length: number): bigint {
1719
- const haystackUint8Array = new Uint8Array(length);
1720
-
1721
- this.read(address, haystackUint8Array);
1722
-
1723
- const haystackBuffer = Buffer.from(haystackUint8Array.buffer, haystackUint8Array.byteOffset, haystackUint8Array.byteLength);
1932
+ const haystack = Buffer.allocUnsafe(length);
1724
1933
 
1725
- const needleUint8Array = ArrayBuffer.isView(needle) //
1726
- ? new Uint8Array(needle.buffer, needle.byteOffset, needle.byteLength)
1727
- : new Uint8Array(needle);
1934
+ this.read(address, haystack);
1728
1935
 
1729
- const needleBuffer = Buffer.from(needleUint8Array.buffer, needleUint8Array.byteOffset, needleUint8Array.byteLength);
1936
+ const needleBuffer = ArrayBuffer.isView(needle) //
1937
+ ? Buffer.from(needle.buffer, needle.byteOffset, needle.byteLength)
1938
+ : Buffer.from(needle);
1730
1939
 
1731
- const indexOf = haystackBuffer.indexOf(needleBuffer);
1940
+ const indexOf = haystack.indexOf(needleBuffer);
1732
1941
 
1733
1942
  return indexOf !== -1 ? BigInt(indexOf) + address : -1n;
1734
1943
  }