diff --git a/package.json b/package.json index 88ce2c2c2b9..8a1fef5b9ef 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "devDependencies": { "@bazel/bazelisk": "~1.19.0", "@types/debug": "^4.1.10", - "@types/node": "^20.11.6", + "@types/node": "^20.14.8", "@types/prettier": "^2.7.1", "@typescript-eslint/eslint-plugin": "^7.3.1", "@typescript-eslint/parser": "^7.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 94c815f72de..14cd9294f01 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,8 +26,8 @@ devDependencies: specifier: ^4.1.10 version: 4.1.10 '@types/node': - specifier: ^20.11.6 - version: 20.11.6 + specifier: ^20.14.8 + version: 20.14.14 '@types/prettier': specifier: ^2.7.1 version: 2.7.1 @@ -190,8 +190,8 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true - /@types/node@20.11.6: - resolution: {integrity: sha512-+EOokTnksGVgip2PbYbr3xnR7kZigh4LbybAfBAw5BpnQ+FqBYUsvCEjYd70IXKlbohQ64mzEYmMtlWUY8q//Q==} + /@types/node@20.14.14: + resolution: {integrity: sha512-d64f00982fS9YoOgJkAMolK7MN8Iq3TDdVjchbYHdEmjth/DHowx82GnoA+tVUAN+7vxfYUgAzi+JXbKNd2SDQ==} dependencies: undici-types: 5.26.5 dev: true diff --git a/src/node/buffer.ts b/src/node/buffer.ts index d5e5b9a1e82..68f0be72f14 100644 --- a/src/node/buffer.ts +++ b/src/node/buffer.ts @@ -2,6 +2,8 @@ // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ + import { constants, kMaxLength, @@ -13,12 +15,10 @@ import { transcode, } from 'node-internal:internal_buffer'; -// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const atob = globalThis.atob; -// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const btoa = globalThis.btoa; -// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const Blob = globalThis.Blob; +const File = globalThis.File; export { atob, @@ -28,6 +28,7 @@ export { kStringMaxLength, Blob, Buffer, + File, SlowBuffer, isAscii, isUtf8, @@ -35,16 +36,14 @@ export { }; export default { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment atob, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment btoa, constants, kMaxLength, kStringMaxLength, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment Blob, Buffer, + File, SlowBuffer, isAscii, isUtf8, diff --git a/src/node/internal/crypto_random.ts b/src/node/internal/crypto_random.ts index 459fe29917d..8fd22fd4d01 100644 --- a/src/node/internal/crypto_random.ts +++ b/src/node/internal/crypto_random.ts @@ -70,7 +70,7 @@ export function randomBytes(size: number, callback?: RandomBytesCallback) : Uint } export function randomFillSync( - buffer: ArrayBufferView|ArrayBuffer, + buffer: NodeJS.ArrayBufferView, offset?: number, size?: number) { if (!isAnyArrayBuffer(buffer) && !isArrayBufferView(buffer)) { @@ -79,7 +79,7 @@ export function randomFillSync( 'DataView', 'ArrayBuffer', 'SharedArrayBuffer' - ],buffer); + ], buffer); } const maxLength = (buffer as Uint8Array).length; if (offset !== undefined) { @@ -89,23 +89,23 @@ export function randomFillSync( validateInteger(size!, 'size', 0, maxLength - offset); } else size = maxLength; if (isAnyArrayBuffer(buffer)) { - buffer = Buffer.from(buffer as ArrayBuffer); + buffer = Buffer.from(buffer); } buffer = (buffer as Buffer).subarray(offset, offset + size); - return crypto.getRandomValues(buffer as ArrayBufferView); + return crypto.getRandomValues(buffer); } -export type RandomFillCallback = (err: any|null, buf?: ArrayBufferView|ArrayBuffer) => void; -export function randomFill(buffer: ArrayBufferView|ArrayBuffer, +export type RandomFillCallback = (err: any|null, buf?: NodeJS.ArrayBufferView) => void; +export function randomFill(buffer: NodeJS.ArrayBufferView, callback?: RandomFillCallback) : void; -export function randomFill(buffer: ArrayBufferView|ArrayBuffer, +export function randomFill(buffer: NodeJS.ArrayBufferView, offset: number, callback?: RandomFillCallback) : void; - export function randomFill(buffer: ArrayBufferView|ArrayBuffer, + export function randomFill(buffer: NodeJS.ArrayBufferView, offset: number, size: number, callback?: RandomFillCallback) : void; -export function randomFill(buffer: ArrayBufferView|ArrayBuffer, +export function randomFill(buffer: NodeJS.ArrayBufferView, offsetOrCallback?: number|RandomFillCallback, sizeOrCallback?: number|RandomFillCallback, callback?: RandomFillCallback) { @@ -115,7 +115,7 @@ export function randomFill(buffer: ArrayBufferView|ArrayBuffer, 'DataView', 'ArrayBuffer', 'SharedArrayBuffer' - ],buffer); + ], buffer); } let offset = 0; @@ -203,17 +203,17 @@ export function randomInt(minOrMax: number, if (typeof callback === 'function') { validateInteger(minOrMax, 'min'); validateInteger(maxOrCallback, 'max'); - min = minOrMax as number; + min = minOrMax; max = maxOrCallback as number; } else if (typeof maxOrCallback === 'function') { min = 0; validateInteger(minOrMax, 'max'); - max = minOrMax as number; + max = minOrMax; callback = maxOrCallback as RandomIntCallback; } else if (arguments.length === 2) { validateInteger(minOrMax, 'min'); validateInteger(maxOrCallback, 'max'); - min = minOrMax as number; + min = minOrMax; max = maxOrCallback as number; } else { min = 0; diff --git a/src/node/internal/web_crypto.d.ts b/src/node/internal/web_crypto.d.ts index 3c1b43c1b92..ea465710acc 100644 --- a/src/node/internal/web_crypto.d.ts +++ b/src/node/internal/web_crypto.d.ts @@ -1,12 +1,4 @@ // Just enough of web crypto api to write the code in node-compat - -declare namespace crypto { - function getRandomValues(array: T): T; - function randomUUID(): string; - - const subtle: SubtleCrypto; -} - type SubtleCrypto = unknown; type CryptoKey = unknown; diff --git a/src/workerd/api/blob.c++ b/src/workerd/api/blob.c++ index 1849a4a52d7..f47fc189e56 100644 --- a/src/workerd/api/blob.c++ +++ b/src/workerd/api/blob.c++ @@ -304,7 +304,7 @@ jsg::Ref File::constructor(jsg::Lock& js, jsg::Optional bits, double lastModified; KJ_IF_SOME(m, maybeLastModified) { - lastModified = m; + lastModified = kj::isNaN(m) ? 0 : m; } else { lastModified = dateNow(); } diff --git a/src/workerd/api/node/tests/buffer-nodejs-test.js b/src/workerd/api/node/tests/buffer-nodejs-test.js index e0547414bdb..7c647255e59 100644 --- a/src/workerd/api/node/tests/buffer-nodejs-test.js +++ b/src/workerd/api/node/tests/buffer-nodejs-test.js @@ -42,6 +42,7 @@ import { isAscii, isUtf8, transcode, + File, } from 'node:buffer'; import * as buffer from 'node:buffer'; @@ -5792,3 +5793,104 @@ export const transcodeTest = { } } }; + +// Tests are taken from Node.js +// https://github.com/nodejs/node/blob/a4f609fa/test/parallel/test-file.js +export const fileTest = { + test() { + throws(() => new File(), TypeError); + throws(() => new File([]), TypeError); + throws(() => File.prototype.name, TypeError); + throws(() => File.prototype.lastModified, TypeError); + + { + const keys = Object.keys(File.prototype).sort(); + deepStrictEqual(keys, ['lastModified', 'name']); + } + + { + const file = new File([], 'dummy.txt.exe'); + strictEqual(file.name, 'dummy.txt.exe'); + strictEqual(file.size, 0); + strictEqual(typeof file.lastModified, 'number'); + ok(file.lastModified <= Date.now()); + } + + { + const toPrimitive = { + [Symbol.toPrimitive]() { + return 'NaN'; + } + }; + + const invalidLastModified = [ + null, + 'string', + false, + toPrimitive, + ]; + + for (const lastModified of invalidLastModified) { + const file = new File([], '', { lastModified }); + strictEqual(file.lastModified, 0); + } + } + + { + const file = new File([], '', { lastModified: undefined }); + notStrictEqual(file.lastModified, 0); + } + + { + const toPrimitive = { + [Symbol.toPrimitive]() { + throw new TypeError('boom'); + } + }; + + const throwValues = [ + BigInt(3n), + toPrimitive, + ]; + + for (const lastModified of throwValues) { + throws(() => new File([], '', { lastModified }), TypeError); + } + } + + { + const valid = [ + { + [Symbol.toPrimitive]() { + return 10; + } + }, + new Number(10), + 10, + ]; + + for (const lastModified of valid) { + strictEqual(new File([], '', { lastModified }).lastModified, 10); + } + } + + { + function MyClass() {} + MyClass.prototype.lastModified = 10; + + const file = new File([], '', new MyClass()); + strictEqual(file.lastModified, 10); + } + + { + let counter = 0; + new File([], '', { + get lastModified() { + counter++; + return 10; + } + }); + strictEqual(counter, 1); + } + } +}