diff --git a/## GitHub Copilot Chat.md b/## GitHub Copilot Chat.md new file mode 100644 index 00000000..abc1cd42 --- /dev/null +++ b/## GitHub Copilot Chat.md @@ -0,0 +1,36 @@ +## GitHub Copilot Chat + +- Extension Version: 0.23.2 (prod) +- VS Code: vscode/1.96.4 +- OS: Linux + +## Network + +User Settings: +```json + "github.copilot.advanced.debug.useElectronFetcher": true, + "github.copilot.advanced.debug.useNodeFetcher": false, + "github.copilot.advanced.debug.useNodeFetchFetcher": true +``` + +Connecting to https://api.github.com: +- DNS ipv4 Lookup: timed out after 10 seconds +- DNS ipv6 Lookup: Error (8 ms): getaddrinfo ENOTFOUND api.github.com +- Proxy URL: None (2 ms) +- Electron fetch (configured): timed out after 10 seconds +- Node.js https: timed out after 10 seconds +- Node.js fetch: timed out after 10 seconds +- Helix fetch: timed out after 10 seconds + +Connecting to https://api.individual.githubcopilot.com/_ping: +- DNS ipv4 Lookup: timed out after 10 seconds +- DNS ipv6 Lookup: timed out after 10 seconds +- Proxy URL: None (16 ms) +- Electron fetch (configured): timed out after 10 seconds +- Node.js https: timed out after 10 seconds +- Node.js fetch: timed out after 10 seconds +- Helix fetch: timed out after 10 seconds + +## Documentation + +In corporate networks: [Troubleshooting firewall settings for GitHub Copilot](https://docs.github.com/en/copilot/troubleshooting-github-copilot/troubleshooting-firewall-settings-for-github-copilot). \ No newline at end of file diff --git a/.autorestic.yml b/.autorestic.yml new file mode 100644 index 00000000..3e662abd --- /dev/null +++ b/.autorestic.yml @@ -0,0 +1,10 @@ + +version: 2 +locations: + home: + from: /home/user + to: local_backup +backends: + local_backup: + type: local + path: /home/user/autorestic_backup diff --git a/.babelrc.json b/.babelrc.json new file mode 100644 index 00000000..92e4ea82 --- /dev/null +++ b/.babelrc.json @@ -0,0 +1,5 @@ +{ + "presets": [...], + "plugins": [...] + } +{ "extends": "../../.babelrc" } \ No newline at end of file diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 00000000..bd9fb772 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,2 @@ +> 0.25% +not dead \ No newline at end of file diff --git a/.codesandbox/backend/.env b/.codesandbox/backend/.env new file mode 100644 index 00000000..f2c8abdd --- /dev/null +++ b/.codesandbox/backend/.env @@ -0,0 +1,10 @@ +API_="my secret api key from.env" +DATABASE_SE="super secret" + +MONGO_URL mongodb+srv://:@cluster0.a9ylqls.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0 + +Valid secret +a-string-secret-at-least-256-bits-long + +FACEBOOK_CLIENT_ID=__INSERT_CLIENT_ID_HERE__ +FACEBOOK_CLIENT_SECRET=__INSERT_CLIENT_SECRET_HERE__ \ No newline at end of file diff --git a/.codesandbox/backend/README.md/README.md b/.codesandbox/backend/README.md/README.md new file mode 100644 index 00000000..752293c8 --- /dev/null +++ b/.codesandbox/backend/README.md/README.md @@ -0,0 +1,84 @@ +# Express API Starter Project + +This project includes the packages and babel setup for an express server, and is just meant to make things a little simpler to get up and running with. + +## Getting started + +Install dependencies with `npm install`, then start the server by running `npm run dev` + +## View it live + +Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. + +MongoDB Stress Test +MPK version +Running + +> +c +d +M +o +n +g +o +D +B +− +S +t +r +e +s +s +− +T +e +s +t +> python write_pbs.py --nclients 192 --host 'myhost.domain.com' --port 27018 $> qsub run.pbs + +Dang version +Files: +w.py: Main program +w_run.pbs: PBS script +Example of running w.py + + # Pick a time 100 seconds in the future + future=`python -c "import time; print(int(time.time()) + 100)"` + # Run 1 client at that time + ./w.py --host=128.55.57.13 --ndocs=100 --when=$future +Util files +sharded-mongo : Run simple localhost setup with 2 shards + +Password based authentication +Client-Server program which will facilitate a client to register itself to the server. A server should keep a table of user-hash(password) entry for each user. + +This program registers user with username, password and stores password hash in dictonary. Also, when a user tries to login , password validation occurs. + +Python,Socket programming + +IMPLEMENTATION (python3) +SERVER : socket with multithreading CLIENT : socket HASH : SHA256 ( using pythons hashlib) + +INPUT (client side) +1. Username +2. Password +OUPUT +1. Registeration Successful : new user +2. Connection Successful : password correct +3. Login Failed : password incorrect + +Hash table : Contains User and Password. It is implemented using python Dictionary data structure + +React + Vite +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +@vitejs/plugin-react uses Babel for Fast Refresh +@vitejs/plugin-react-swc uses SWC for Fast Refresh +Expanding the ESLint configuration +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the TS template for information on how to integrate TypeScript and typescript-eslint in your project. + +Install dependencies with npm install, then start the server by running npm run dev \ No newline at end of file diff --git a/.codesandbox/backend/package.json b/.codesandbox/backend/package.json new file mode 100644 index 00000000..40ed5bad --- /dev/null +++ b/.codesandbox/backend/package.json @@ -0,0 +1,31 @@ + +{ + "name": "express-api-starter", + "version": "1.0.0", + "description": "Starter project to get and running with express quickly", + "scripts": { + "start": "babel-node server.js", + "dev": "nodemon server.js --exec babel-node", + "test": "jest" + }, + "author": "Special Garden Group", + "licence": "ISC OR GPL-3.0", + "dependencies": { + "express": "^5.1.0", + "@fontsource/roboto": "^5.2.6", + "@mui/icons-material": "^7.2.0", + "@mui/material": "^7.2.0", + "@mui/styled-engine-sc": "^7.2.0", + "react": "^19.1.0", + "react-dom": "^19.1.0", + "styled-components": "^6.1.19", + "@babel/core": "^7.17.9", + "@babel/node": "^7.16.8", + "@babel/preset-env": "^7.16.11", + "nodemon": "^3.0.1", + "cors": "^2.8.5", + "dotenv": "^16.5.0", + "mongodb": "^6.16.0", + "mongoose": "^8.15.1" + } +} diff --git a/.codesandbox/backend/server.js b/.codesandbox/backend/server.js new file mode 100644 index 00000000..29921db9 --- /dev/null +++ b/.codesandbox/backend/server.js @@ -0,0 +1,148 @@ +import express from 'express' +import bodyParser from 'body-parser' +import cors from 'cors' +import crypto from 'crypto' +import mongoose from 'mongoose' +import bcrypt from 'bcrypt-nodejs' +import dotenv from 'dotenv' + +dotenv.config() + +const mongoUrl =process.env_MONGO_URL II "mongodb://localhost/auth", +mongoose.connect(mongoUrl, { useNewUrlParser: true, useundefinedtopology: true}) +mongoose.Promise = Promise + +const { Schema, model } = mongoose +const userSchema = new Schema({ + +const User = mongoose.model('User', { + name: { + type: String, + unique: true + }, + password:{ + type:String, + required:true + }, + accessToken:{ + type:String, + default: () => crypto.randomBytes(128)toString('hex') + } + }); + const User = model("User", userSchema) + + // Example + // POST Request + const request = {name: "Bob", password: "foobar}; + // DB Entry + const dbEntry = {name :"Bob, password:"5abbc32983def"} + bcrypt.compareSync(request.password, dbEntry.password); + // One-way encryption +const user = new User({name:"Bob", password:bcrypt.hashSync("foobar")}); +user.save(); +// Defines the port the app will run on. Defaults to 8080, but can be overritten when starting the server. For example: +// +// PORT-9000 npm start +const port = process.env.PORT II 8080 +const app = express() +const authenticateUser = async (req, res, next) => { + const user = await User.findOne({accesToken: req.header('Authorization')}); + if(user){ + req.user = user; + next(); + {else{ +res.status(401).json({loggedOut:true}); + }} + } +} + +// Add middlewares to enable cors and json body parsing +app.use(cors()) +app.use(express.json()); +app.use(bodyParser.json()) + +// Start defining your routes here +app.get('/', (req, res) => { + res.send('Hello Member') + app.post('/tweets' authenticateUser); + app.post('/tweets', async (req,res) =>{ + // This will only happen if the next() function is called from middleware! + // now we can access the req.user object from the middleware + }) + + } + }) +}) + +// Start defining your routes here +app.get('/,(req, res) => { + res.send('Hello world') +}) +app.post('/sessions' async (req res) => { + const user = await User.findOne({name: req.body.name}); + if(user && bcrypt.compareSync(req.body.password, user.password)){ + // Success + res.json({userId: user._id, accessToken}}; + }else{ + // Failure + // a.User does not exist + // b. Encrypted password does not march + res.json({notFound: true}); + } + } +}); +app.post("/users", (req, res) => { + try { + const { name, email, password } = req.body + const salt = bcrypt.genSaltSync() + const user = new User({ name, email, password: bcrypt.hashSync(password, salt) }) + user.save() + res.status(201).json({ + success: true, + message: "User created", + id: user._id, + accessToken: user.accessToken, + }) + } catch (error) { + res.status(400).json({ + success: false, + message: "Could not create user", + errors: error + }) + } + }) + + app.get("/secrets", authenticateUser) +app.get("/secrets", (req, res) => { + res.json({ + secret: "This is secret" + app.get('/secrets', (req, res) =>{ + res.jsons({secret: 'This is a super secret message'}) + }); + } + app.post('/sessions' async (req, res) => { + const user = await User.findOne({email: req.body.email}); + if (user && bcrypt.compareSync(req.body.password. user.password)){ + res.json({userId: user_Id, assessToken: user.accessToken}); + }else{ + res.json({notFound: true}); + +// Add middlewares to enable cors and json body parsing +app.use(cors()) +app.use(bodyParser.json()) +//Start defing your routes here +app.get('/',(req, res) => { + //fetch('...,{headers:{Authorization: + 'my secret apt key'}}} + res.send{process.env.API_KEY}}) +} + + + +// Start the server +}) +app.listen(port, () => { + console.log('Server running on http://localhost:${port}') +}) + console.log(bcrypt.hashSync("foobar")); +}) \ No newline at end of file diff --git a/.codesandbox/backend/tasks.json b/.codesandbox/backend/tasks.json new file mode 100644 index 00000000..9a67839b --- /dev/null +++ b/.codesandbox/backend/tasks.json @@ -0,0 +1,23 @@ +{ + // These tasks will run in order when initializing your CodeSandbox project. + "setupTasks": [ + { + "command": "pnpm install", + "name": "Installing Dependencies" + } + ], + + // These tasks can be run from CodeSandbox. Running one will open a log in the app. + "tasks": { + "start": { + "name": "start", + "command": "pnpm start", + "runAtStart": false + }, + "dev": { + "name": "dev", + "command": "pnpm dev", + "runAtStart": true + } + } +} diff --git a/.codesandbox/node/assert.js b/.codesandbox/node/assert.js new file mode 100644 index 00000000..2ddc44d9 --- /dev/null +++ b/.codesandbox/node/assert.js @@ -0,0 +1,824 @@ +'use strict'; + +const { + ArrayPrototypeIndexOf, + ArrayPrototypeJoin, + ArrayPrototypePush, + ArrayPrototypeSlice, + Error, + NumberIsNaN, + ObjectAssign, + ObjectIs, + ObjectKeys, + ObjectPrototypeIsPrototypeOf, + ReflectApply, + RegExpPrototypeExec, + String, + StringPrototypeIndexOf, + StringPrototypeSlice, + StringPrototypeSplit, +} = primordials; + +const { + codes: { + ERR_AMBIGUOUS_ARGUMENT, + ERR_INVALID_ARG_TYPE, + ERR_INVALID_ARG_VALUE, + ERR_INVALID_RETURN_VALUE, + ERR_MISSING_ARGS, + }, +} = require('internal/errors'); +const AssertionError = require('internal/assert/assertion_error'); +const { inspect } = require('internal/util/inspect'); +const { + isPromise, + isRegExp, +} = require('internal/util/types'); +const { isError, deprecate } = require('internal/util'); +const { innerOk } = require('internal/assert/utils'); + +const CallTracker = require('internal/assert/calltracker'); +const { + validateFunction, +} = require('internal/validators'); + +let isDeepEqual; +let isDeepStrictEqual; +let isPartialStrictEqual; + +function lazyLoadComparison() { + const comparison = require('internal/util/comparisons'); + isDeepEqual = comparison.isDeepEqual; + isDeepStrictEqual = comparison.isDeepStrictEqual; + isPartialStrictEqual = comparison.isPartialStrictEqual; +} + +let warned = false; + +// The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +const assert = module.exports = ok; + +const NO_EXCEPTION_SENTINEL = {}; + +// All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function innerFail(obj) { + if (obj.message instanceof Error) throw obj.message; + + throw new AssertionError(obj); +} + +/** + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @param {string} [operator] + * @param {Function} [stackStartFn] + */ +function fail(actual, expected, message, operator, stackStartFn) { + const argsLen = arguments.length; + + let internalMessage = false; + if (actual == null && argsLen <= 1) { + internalMessage = true; + message = 'Failed'; + } else if (argsLen === 1) { + message = actual; + actual = undefined; + } else { + if (warned === false) { + warned = true; + process.emitWarning( + 'assert.fail() with more than one argument is deprecated. ' + + 'Please use assert.strictEqual() instead or only pass a message.', + 'DeprecationWarning', + 'DEP0094', + ); + } + if (argsLen === 2) + operator = '!='; + } + + if (message instanceof Error) throw message; + + const errArgs = { + actual, + expected, + operator: operator === undefined ? 'fail' : operator, + stackStartFn: stackStartFn || fail, + message, + }; + const err = new AssertionError(errArgs); + if (internalMessage) { + err.generatedMessage = true; + } + throw err; +} + +assert.fail = fail; + +// The AssertionError is defined in internal/error. +assert.AssertionError = AssertionError; + +/** + * Pure assertion tests whether a value is truthy, as determined + * by !!value. + * @param {...any} args + * @returns {void} + */ +function ok(...args) { + innerOk(ok, args.length, ...args); +} +assert.ok = ok; + +/** + * The equality assertion tests shallow, coercive equality with ==. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +/* eslint-disable no-restricted-properties */ +assert.equal = function equal(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + // eslint-disable-next-line eqeqeq + if (actual != expected && (!NumberIsNaN(actual) || !NumberIsNaN(expected))) { + innerFail({ + actual, + expected, + message, + operator: '==', + stackStartFn: equal, + }); + } +}; + +/** + * The non-equality assertion tests for whether two objects are not + * equal with !=. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.notEqual = function notEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + // eslint-disable-next-line eqeqeq + if (actual == expected || (NumberIsNaN(actual) && NumberIsNaN(expected))) { + innerFail({ + actual, + expected, + message, + operator: '!=', + stackStartFn: notEqual, + }); + } +}; + +/** + * The deep equivalence assertion tests a deep equality relation. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.deepEqual = function deepEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + if (!isDeepEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'deepEqual', + stackStartFn: deepEqual, + }); + } +}; + +/** + * The deep non-equivalence assertion tests for any deep inequality. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + if (isDeepEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'notDeepEqual', + stackStartFn: notDeepEqual, + }); + } +}; +/* eslint-enable */ + +/** + * The deep strict equivalence assertion tests a deep strict equality + * relation. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + if (!isDeepStrictEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'deepStrictEqual', + stackStartFn: deepStrictEqual, + }); + } +}; + +/** + * The deep strict non-equivalence assertion tests for any deep strict + * inequality. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.notDeepStrictEqual = notDeepStrictEqual; +function notDeepStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + if (isDeepStrictEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'notDeepStrictEqual', + stackStartFn: notDeepStrictEqual, + }); + } +} + +/** + * The strict equivalence assertion tests a strict equality relation. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.strictEqual = function strictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (!ObjectIs(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'strictEqual', + stackStartFn: strictEqual, + }); + } +}; + +/** + * The strict non-equivalence assertion tests for any strict inequality. + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (ObjectIs(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'notStrictEqual', + stackStartFn: notStrictEqual, + }); + } +}; + +/** + * The strict equivalence assertion test between two objects + * @param {any} actual + * @param {any} expected + * @param {string | Error} [message] + * @returns {void} + */ +assert.partialDeepStrictEqual = function partialDeepStrictEqual( + actual, + expected, + message, +) { + if (arguments.length < 2) { + throw new ERR_MISSING_ARGS('actual', 'expected'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + if (!isPartialStrictEqual(actual, expected)) { + innerFail({ + actual, + expected, + message, + operator: 'partialDeepStrictEqual', + stackStartFn: partialDeepStrictEqual, + }); + } +}; + +class Comparison { + constructor(obj, keys, actual) { + for (const key of keys) { + if (key in obj) { + if (actual !== undefined && + typeof actual[key] === 'string' && + isRegExp(obj[key]) && + RegExpPrototypeExec(obj[key], actual[key]) !== null) { + this[key] = actual[key]; + } else { + this[key] = obj[key]; + } + } + } + } +} + +function compareExceptionKey(actual, expected, key, message, keys, fn) { + if (!(key in actual) || !isDeepStrictEqual(actual[key], expected[key])) { + if (!message) { + // Create placeholder objects to create a nice output. + const a = new Comparison(actual, keys); + const b = new Comparison(expected, keys, actual); + + const err = new AssertionError({ + actual: a, + expected: b, + operator: 'deepStrictEqual', + stackStartFn: fn, + }); + err.actual = actual; + err.expected = expected; + err.operator = fn.name; + throw err; + } + innerFail({ + actual, + expected, + message, + operator: fn.name, + stackStartFn: fn, + }); + } +} + +function expectedException(actual, expected, message, fn) { + let generatedMessage = false; + let throwError = false; + + if (typeof expected !== 'function') { + // Handle regular expressions. + if (isRegExp(expected)) { + const str = String(actual); + if (RegExpPrototypeExec(expected, str) !== null) + return; + + if (!message) { + generatedMessage = true; + message = 'The input did not match the regular expression ' + + `${inspect(expected)}. Input:\n\n${inspect(str)}\n`; + } + throwError = true; + // Handle primitives properly. + } else if (typeof actual !== 'object' || actual === null) { + const err = new AssertionError({ + actual, + expected, + message, + operator: 'deepStrictEqual', + stackStartFn: fn, + }); + err.operator = fn.name; + throw err; + } else { + // Handle validation objects. + const keys = ObjectKeys(expected); + // Special handle errors to make sure the name and the message are + // compared as well. + if (expected instanceof Error) { + ArrayPrototypePush(keys, 'name', 'message'); + } else if (keys.length === 0) { + throw new ERR_INVALID_ARG_VALUE('error', + expected, 'may not be an empty object'); + } + if (isDeepEqual === undefined) lazyLoadComparison(); + for (const key of keys) { + if (typeof actual[key] === 'string' && + isRegExp(expected[key]) && + RegExpPrototypeExec(expected[key], actual[key]) !== null) { + continue; + } + compareExceptionKey(actual, expected, key, message, keys, fn); + } + return; + } + // Guard instanceof against arrow functions as they don't have a prototype. + // Check for matching Error classes. + } else if (expected.prototype !== undefined && actual instanceof expected) { + return; + } else if (ObjectPrototypeIsPrototypeOf(Error, expected)) { + if (!message) { + generatedMessage = true; + message = 'The error is expected to be an instance of ' + + `"${expected.name}". Received `; + if (isError(actual)) { + const name = (actual.constructor?.name) || + actual.name; + if (expected.name === name) { + message += 'an error with identical name but a different prototype.'; + } else { + message += `"${name}"`; + } + if (actual.message) { + message += `\n\nError message:\n\n${actual.message}`; + } + } else { + message += `"${inspect(actual, { depth: -1 })}"`; + } + } + throwError = true; + } else { + // Check validation functions return value. + const res = ReflectApply(expected, {}, [actual]); + if (res !== true) { + if (!message) { + generatedMessage = true; + const name = expected.name ? `"${expected.name}" ` : ''; + message = `The ${name}validation function is expected to return` + + ` "true". Received ${inspect(res)}`; + + if (isError(actual)) { + message += `\n\nCaught error:\n\n${actual}`; + } + } + throwError = true; + } + } + + if (throwError) { + const err = new AssertionError({ + actual, + expected, + message, + operator: fn.name, + stackStartFn: fn, + }); + err.generatedMessage = generatedMessage; + throw err; + } +} + +function getActual(fn) { + validateFunction(fn, 'fn'); + try { + fn(); + } catch (e) { + return e; + } + return NO_EXCEPTION_SENTINEL; +} + +function checkIsPromise(obj) { + // Accept native ES6 promises and promises that are implemented in a similar + // way. Do not accept thenables that use a function as `obj` and that have no + // `catch` handler. + return isPromise(obj) || + (obj !== null && typeof obj === 'object' && + typeof obj.then === 'function' && + typeof obj.catch === 'function'); +} + +async function waitForActual(promiseFn) { + let resultPromise; + if (typeof promiseFn === 'function') { + // Return a rejected promise if `promiseFn` throws synchronously. + resultPromise = promiseFn(); + // Fail in case no promise is returned. + if (!checkIsPromise(resultPromise)) { + throw new ERR_INVALID_RETURN_VALUE('instance of Promise', + 'promiseFn', resultPromise); + } + } else if (checkIsPromise(promiseFn)) { + resultPromise = promiseFn; + } else { + throw new ERR_INVALID_ARG_TYPE( + 'promiseFn', ['Function', 'Promise'], promiseFn); + } + + try { + await resultPromise; + } catch (e) { + return e; + } + return NO_EXCEPTION_SENTINEL; +} + +function expectsError(stackStartFn, actual, error, message) { + if (typeof error === 'string') { + if (arguments.length === 4) { + throw new ERR_INVALID_ARG_TYPE('error', + ['Object', 'Error', 'Function', 'RegExp'], + error); + } + if (typeof actual === 'object' && actual !== null) { + if (actual.message === error) { + throw new ERR_AMBIGUOUS_ARGUMENT( + 'error/message', + `The error message "${actual.message}" is identical to the message.`, + ); + } + } else if (actual === error) { + throw new ERR_AMBIGUOUS_ARGUMENT( + 'error/message', + `The error "${actual}" is identical to the message.`, + ); + } + message = error; + error = undefined; + } else if (error != null && + typeof error !== 'object' && + typeof error !== 'function') { + throw new ERR_INVALID_ARG_TYPE('error', + ['Object', 'Error', 'Function', 'RegExp'], + error); + } + + if (actual === NO_EXCEPTION_SENTINEL) { + let details = ''; + if (error?.name) { + details += ` (${error.name})`; + } + details += message ? `: ${message}` : '.'; + const fnType = stackStartFn === assert.rejects ? 'rejection' : 'exception'; + innerFail({ + actual: undefined, + expected: error, + operator: stackStartFn.name, + message: `Missing expected ${fnType}${details}`, + stackStartFn, + }); + } + + if (!error) + return; + + expectedException(actual, error, message, stackStartFn); +} + +function hasMatchingError(actual, expected) { + if (typeof expected !== 'function') { + if (isRegExp(expected)) { + const str = String(actual); + return RegExpPrototypeExec(expected, str) !== null; + } + throw new ERR_INVALID_ARG_TYPE( + 'expected', ['Function', 'RegExp'], expected, + ); + } + // Guard instanceof against arrow functions as they don't have a prototype. + if (expected.prototype !== undefined && actual instanceof expected) { + return true; + } + if (ObjectPrototypeIsPrototypeOf(Error, expected)) { + return false; + } + return ReflectApply(expected, {}, [actual]) === true; +} + +function expectsNoError(stackStartFn, actual, error, message) { + if (actual === NO_EXCEPTION_SENTINEL) + return; + + if (typeof error === 'string') { + message = error; + error = undefined; + } + + if (!error || hasMatchingError(actual, error)) { + const details = message ? `: ${message}` : '.'; + const fnType = stackStartFn === assert.doesNotReject ? + 'rejection' : 'exception'; + innerFail({ + actual, + expected: error, + operator: stackStartFn.name, + message: `Got unwanted ${fnType}${details}\n` + + `Actual message: "${actual?.message}"`, + stackStartFn, + }); + } + throw actual; +} + +/** + * Expects the function `promiseFn` to throw an error. + * @param {() => any} promiseFn + * @param {...any} [args] + * @returns {void} + */ +assert.throws = function throws(promiseFn, ...args) { + expectsError(throws, getActual(promiseFn), ...args); +}; + +/** + * Expects `promiseFn` function or its value to reject. + * @param {() => Promise} promiseFn + * @param {...any} [args] + * @returns {Promise} + */ +assert.rejects = async function rejects(promiseFn, ...args) { + expectsError(rejects, await waitForActual(promiseFn), ...args); +}; + +/** + * Asserts that the function `fn` does not throw an error. + * @param {() => any} fn + * @param {...any} [args] + * @returns {void} + */ +assert.doesNotThrow = function doesNotThrow(fn, ...args) { + expectsNoError(doesNotThrow, getActual(fn), ...args); +}; + +/** + * Expects `fn` or its value to not reject. + * @param {() => Promise} fn + * @param {...any} [args] + * @returns {Promise} + */ +assert.doesNotReject = async function doesNotReject(fn, ...args) { + expectsNoError(doesNotReject, await waitForActual(fn), ...args); +}; + +/** + * Throws `AssertionError` if the value is not `null` or `undefined`. + * @param {any} err + * @returns {void} + */ +assert.ifError = function ifError(err) { + if (err !== null && err !== undefined) { + let message = 'ifError got unwanted exception: '; + if (typeof err === 'object' && typeof err.message === 'string') { + if (err.message.length === 0 && err.constructor) { + message += err.constructor.name; + } else { + message += err.message; + } + } else { + message += inspect(err); + } + + const newErr = new AssertionError({ + actual: err, + expected: null, + operator: 'ifError', + message, + stackStartFn: ifError, + }); + + // Make sure we actually have a stack trace! + const origStack = err.stack; + + if (typeof origStack === 'string') { + // This will remove any duplicated frames from the error frames taken + // from within `ifError` and add the original error frames to the newly + // created ones. + const origStackStart = StringPrototypeIndexOf(origStack, '\n at'); + if (origStackStart !== -1) { + const originalFrames = StringPrototypeSplit( + StringPrototypeSlice(origStack, origStackStart + 1), + '\n', + ); + // Filter all frames existing in err.stack. + let newFrames = StringPrototypeSplit(newErr.stack, '\n'); + for (const errFrame of originalFrames) { + // Find the first occurrence of the frame. + const pos = ArrayPrototypeIndexOf(newFrames, errFrame); + if (pos !== -1) { + // Only keep new frames. + newFrames = ArrayPrototypeSlice(newFrames, 0, pos); + break; + } + } + const stackStart = ArrayPrototypeJoin(newFrames, '\n'); + const stackEnd = ArrayPrototypeJoin(originalFrames, '\n'); + newErr.stack = `${stackStart}\n${stackEnd}`; + } + } + + throw newErr; + } +}; + +function internalMatch(string, regexp, message, fn) { + if (!isRegExp(regexp)) { + throw new ERR_INVALID_ARG_TYPE( + 'regexp', 'RegExp', regexp, + ); + } + const match = fn === assert.match; + if (typeof string !== 'string' || + RegExpPrototypeExec(regexp, string) !== null !== match) { + if (message instanceof Error) { + throw message; + } + + const generatedMessage = !message; + + // 'The input was expected to not match the regular expression ' + + message ||= (typeof string !== 'string' ? + 'The "string" argument must be of type string. Received type ' + + `${typeof string} (${inspect(string)})` : + (match ? + 'The input did not match the regular expression ' : + 'The input was expected to not match the regular expression ') + + `${inspect(regexp)}. Input:\n\n${inspect(string)}\n`); + const err = new AssertionError({ + actual: string, + expected: regexp, + message, + operator: fn.name, + stackStartFn: fn, + }); + err.generatedMessage = generatedMessage; + throw err; + } +} + +/** + * Expects the `string` input to match the regular expression. + * @param {string} string + * @param {RegExp} regexp + * @param {string | Error} [message] + * @returns {void} + */ +assert.match = function match(string, regexp, message) { + internalMatch(string, regexp, message, match); +}; + +/** + * Expects the `string` input not to match the regular expression. + * @param {string} string + * @param {RegExp} regexp + * @param {string | Error} [message] + * @returns {void} + */ +assert.doesNotMatch = function doesNotMatch(string, regexp, message) { + internalMatch(string, regexp, message, doesNotMatch); +}; + +assert.CallTracker = deprecate(CallTracker, 'assert.CallTracker is deprecated.', 'DEP0173'); + +/** + * Expose a strict only variant of assert. + * @param {...any} args + * @returns {void} + */ +function strict(...args) { + innerOk(strict, args.length, ...args); +} + +assert.strict = ObjectAssign(strict, assert, { + equal: assert.strictEqual, + deepEqual: assert.deepStrictEqual, + notEqual: assert.notStrictEqual, + notDeepEqual: assert.notDeepStrictEqual, +}); + +assert.strict.strict = assert.strict; \ No newline at end of file diff --git a/.codesandbox/node/async_hooks.js b/.codesandbox/node/async_hooks.js new file mode 100644 index 00000000..8c57bc67 --- /dev/null +++ b/.codesandbox/node/async_hooks.js @@ -0,0 +1,296 @@ +'use strict'; + +const { + ArrayPrototypeIncludes, + ArrayPrototypeIndexOf, + ArrayPrototypePush, + ArrayPrototypeSplice, + ArrayPrototypeUnshift, + FunctionPrototypeBind, + NumberIsSafeInteger, + ObjectDefineProperties, + ObjectFreeze, + ReflectApply, + Symbol, +} = primordials; + +const { + ERR_ASYNC_CALLBACK, + ERR_ASYNC_TYPE, + ERR_INVALID_ASYNC_ID, +} = require('internal/errors').codes; +const { + deprecate, + kEmptyObject, +} = require('internal/util'); +const { + validateFunction, + validateString, +} = require('internal/validators'); +const internal_async_hooks = require('internal/async_hooks'); + +const AsyncContextFrame = require('internal/async_context_frame'); + +// Get functions +// For userland AsyncResources, make sure to emit a destroy event when the +// resource gets gced. +const { registerDestroyHook, kNoPromiseHook } = internal_async_hooks; +const { + asyncWrap, + executionAsyncId, + triggerAsyncId, + // Private API + hasAsyncIdStack, + getHookArrays, + enableHooks, + disableHooks, + updatePromiseHookMode, + executionAsyncResource, + // Internal Embedder API + newAsyncId, + getDefaultTriggerAsyncId, + emitInit, + emitBefore, + emitAfter, + emitDestroy, + enabledHooksExist, + initHooksExist, + destroyHooksExist, +} = internal_async_hooks; + +// Get symbols +const { + async_id_symbol, trigger_async_id_symbol, + init_symbol, before_symbol, after_symbol, destroy_symbol, + promise_resolve_symbol, +} = internal_async_hooks.symbols; + +// Get constants +const { + kInit, kBefore, kAfter, kDestroy, kTotals, kPromiseResolve, +} = internal_async_hooks.constants; + +// Listener API // + +class AsyncHook { + constructor({ init, before, after, destroy, promiseResolve }) { + if (init !== undefined && typeof init !== 'function') + throw new ERR_ASYNC_CALLBACK('hook.init'); + if (before !== undefined && typeof before !== 'function') + throw new ERR_ASYNC_CALLBACK('hook.before'); + if (after !== undefined && typeof after !== 'function') + throw new ERR_ASYNC_CALLBACK('hook.after'); + if (destroy !== undefined && typeof destroy !== 'function') + throw new ERR_ASYNC_CALLBACK('hook.destroy'); + if (promiseResolve !== undefined && typeof promiseResolve !== 'function') + throw new ERR_ASYNC_CALLBACK('hook.promiseResolve'); + + this[init_symbol] = init; + this[before_symbol] = before; + this[after_symbol] = after; + this[destroy_symbol] = destroy; + this[promise_resolve_symbol] = promiseResolve; + this[kNoPromiseHook] = false; + } + + enable() { + // The set of callbacks for a hook should be the same regardless of whether + // enable()/disable() are run during their execution. The following + // references are reassigned to the tmp arrays if a hook is currently being + // processed. + const { 0: hooks_array, 1: hook_fields } = getHookArrays(); + + // Each hook is only allowed to be added once. + if (ArrayPrototypeIncludes(hooks_array, this)) + return this; + + const prev_kTotals = hook_fields[kTotals]; + + // createHook() has already enforced that the callbacks are all functions, + // so here simply increment the count of whether each callbacks exists or + // not. + hook_fields[kTotals] = hook_fields[kInit] += +!!this[init_symbol]; + hook_fields[kTotals] += hook_fields[kBefore] += +!!this[before_symbol]; + hook_fields[kTotals] += hook_fields[kAfter] += +!!this[after_symbol]; + hook_fields[kTotals] += hook_fields[kDestroy] += +!!this[destroy_symbol]; + hook_fields[kTotals] += + hook_fields[kPromiseResolve] += +!!this[promise_resolve_symbol]; + ArrayPrototypePush(hooks_array, this); + + if (prev_kTotals === 0 && hook_fields[kTotals] > 0) { + enableHooks(); + } + + if (!this[kNoPromiseHook]) { + updatePromiseHookMode(); + } + + return this; + } + + disable() { + const { 0: hooks_array, 1: hook_fields } = getHookArrays(); + + const index = ArrayPrototypeIndexOf(hooks_array, this); + if (index === -1) + return this; + + const prev_kTotals = hook_fields[kTotals]; + + hook_fields[kTotals] = hook_fields[kInit] -= +!!this[init_symbol]; + hook_fields[kTotals] += hook_fields[kBefore] -= +!!this[before_symbol]; + hook_fields[kTotals] += hook_fields[kAfter] -= +!!this[after_symbol]; + hook_fields[kTotals] += hook_fields[kDestroy] -= +!!this[destroy_symbol]; + hook_fields[kTotals] += + hook_fields[kPromiseResolve] -= +!!this[promise_resolve_symbol]; + ArrayPrototypeSplice(hooks_array, index, 1); + + if (prev_kTotals > 0 && hook_fields[kTotals] === 0) { + disableHooks(); + } + + return this; + } +} + + +function createHook(fns) { + return new AsyncHook(fns); +} + + +// Embedder API // + +const destroyedSymbol = Symbol('destroyed'); +const contextFrameSymbol = Symbol('context_frame'); + +class AsyncResource { + constructor(type, opts = kEmptyObject) { + validateString(type, 'type'); + + let triggerAsyncId = opts; + let requireManualDestroy = false; + if (typeof opts !== 'number') { + triggerAsyncId = opts.triggerAsyncId === undefined ? + getDefaultTriggerAsyncId() : opts.triggerAsyncId; + requireManualDestroy = !!opts.requireManualDestroy; + } + + // Unlike emitInitScript, AsyncResource doesn't supports null as the + // triggerAsyncId. + if (!NumberIsSafeInteger(triggerAsyncId) || triggerAsyncId < -1) { + throw new ERR_INVALID_ASYNC_ID('triggerAsyncId', triggerAsyncId); + } + + this[contextFrameSymbol] = AsyncContextFrame.current(); + + const asyncId = newAsyncId(); + this[async_id_symbol] = asyncId; + this[trigger_async_id_symbol] = triggerAsyncId; + + if (initHooksExist()) { + if (enabledHooksExist() && type.length === 0) { + throw new ERR_ASYNC_TYPE(type); + } + + emitInit(asyncId, type, triggerAsyncId, this); + } + + if (!requireManualDestroy && destroyHooksExist()) { + // This prop name (destroyed) has to be synchronized with C++ + const destroyed = { destroyed: false }; + this[destroyedSymbol] = destroyed; + registerDestroyHook(this, asyncId, destroyed); + } + } + + runInAsyncScope(fn, thisArg, ...args) { + const asyncId = this[async_id_symbol]; + emitBefore(asyncId, this[trigger_async_id_symbol], this); + + const contextFrame = this[contextFrameSymbol]; + const prior = AsyncContextFrame.exchange(contextFrame); + try { + return ReflectApply(fn, thisArg, args); + } finally { + AsyncContextFrame.set(prior); + if (hasAsyncIdStack()) + emitAfter(asyncId); + } + } + + emitDestroy() { + if (this[destroyedSymbol] !== undefined) { + this[destroyedSymbol].destroyed = true; + } + emitDestroy(this[async_id_symbol]); + return this; + } + + asyncId() { + return this[async_id_symbol]; + } + + triggerAsyncId() { + return this[trigger_async_id_symbol]; + } + + bind(fn, thisArg) { + validateFunction(fn, 'fn'); + let bound; + if (thisArg === undefined) { + const resource = this; + bound = function(...args) { + ArrayPrototypeUnshift(args, fn, this); + return ReflectApply(resource.runInAsyncScope, resource, args); + }; + } else { + bound = FunctionPrototypeBind(this.runInAsyncScope, this, fn, thisArg); + } + let self = this; + ObjectDefineProperties(bound, { + 'length': { + __proto__: null, + configurable: true, + enumerable: false, + value: fn.length, + writable: false, + }, + 'asyncResource': { + __proto__: null, + configurable: true, + enumerable: true, + get: deprecate(function() { + return self; + }, 'The asyncResource property on bound functions is deprecated', 'DEP0172'), + set: deprecate(function(val) { + self = val; + }, 'The asyncResource property on bound functions is deprecated', 'DEP0172'), + }, + }); + return bound; + } + + static bind(fn, type, thisArg) { + type ||= fn.name; + return (new AsyncResource(type || 'bound-anonymous-fn')).bind(fn, thisArg); + } +} + +// Placing all exports down here because the exported classes won't export +// otherwise. +module.exports = { + // Public API + get AsyncLocalStorage() { + return AsyncContextFrame.enabled ? + require('internal/async_local_storage/async_context_frame') : + require('internal/async_local_storage/async_hooks'); + }, + createHook, + executionAsyncId, + triggerAsyncId, + executionAsyncResource, + asyncWrapProviders: ObjectFreeze({ __proto__: null, ...asyncWrap.Providers }), + // Embedder API + AsyncResource, +}; \ No newline at end of file diff --git a/.codesandbox/node/buffer.js b/.codesandbox/node/buffer.js new file mode 100644 index 00000000..06bfebc7 --- /dev/null +++ b/.codesandbox/node/buffer.js @@ -0,0 +1,1365 @@ +'use strict'; + +const { + Array, + ArrayBufferIsView, + ArrayIsArray, + ArrayPrototypeForEach, + MathFloor, + MathMin, + MathTrunc, + NumberIsInteger, + NumberIsNaN, + NumberMAX_SAFE_INTEGER, + NumberMIN_SAFE_INTEGER, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectPrototypeHasOwnProperty, + ObjectSetPrototypeOf, + RegExpPrototypeSymbolReplace, + StringPrototypeCharCodeAt, + StringPrototypeSlice, + StringPrototypeToLowerCase, + StringPrototypeTrim, + SymbolSpecies, + SymbolToPrimitive, + TypedArrayPrototypeFill, + TypedArrayPrototypeGetBuffer, + TypedArrayPrototypeGetByteLength, + TypedArrayPrototypeGetByteOffset, + TypedArrayPrototypeGetLength, + TypedArrayPrototypeSet, + TypedArrayPrototypeSlice, + Uint8Array, + Uint8ArrayPrototype, +} = primordials; + +const { + byteLengthUtf8, + compare: _compare, + compareOffset, + copy: _copy, + fill: bindingFill, + isAscii: bindingIsAscii, + isUtf8: bindingIsUtf8, + indexOfBuffer, + indexOfNumber, + indexOfString, + swap16: _swap16, + swap32: _swap32, + swap64: _swap64, + kMaxLength, + kStringMaxLength, + atob: _atob, + btoa: _btoa, +} = internalBinding('buffer'); +const { + constants: { + ALL_PROPERTIES, + ONLY_ENUMERABLE, + }, + getOwnNonIndexProperties, + isInsideNodeModules, +} = internalBinding('util'); +const { + customInspectSymbol, + lazyDOMException, + normalizeEncoding, + kIsEncodingSymbol, + defineLazyProperties, + encodingsMap, + deprecate, +} = require('internal/util'); +const { + isAnyArrayBuffer, + isArrayBufferView, + isUint8Array, + isTypedArray, +} = require('internal/util/types'); +const { + inspect: utilInspect, +} = require('internal/util/inspect'); + +const { + codes: { + ERR_BUFFER_OUT_OF_BOUNDS, + ERR_INVALID_ARG_TYPE, + ERR_INVALID_ARG_VALUE, + ERR_INVALID_BUFFER_SIZE, + ERR_MISSING_ARGS, + ERR_OUT_OF_RANGE, + ERR_UNKNOWN_ENCODING, + }, + genericNodeError, +} = require('internal/errors'); +const { + validateArray, + validateBuffer, + validateInteger, + validateNumber, + validateString, +} = require('internal/validators'); +// Provide validateInteger() but with kMaxLength as the default maximum value. +const validateOffset = (value, name, min = 0, max = kMaxLength) => + validateInteger(value, name, min, max); + +const { + FastBuffer, + markAsUntransferable, + addBufferPrototypeMethods, + createUnsafeBuffer, +} = require('internal/buffer'); + +FastBuffer.prototype.constructor = Buffer; +Buffer.prototype = FastBuffer.prototype; +addBufferPrototypeMethods(Buffer.prototype); + +const constants = ObjectDefineProperties({}, { + MAX_LENGTH: { + __proto__: null, + value: kMaxLength, + writable: false, + enumerable: true, + }, + MAX_STRING_LENGTH: { + __proto__: null, + value: kStringMaxLength, + writable: false, + enumerable: true, + }, +}); + +Buffer.poolSize = 8 * 1024; +let poolSize, poolOffset, allocPool, allocBuffer; + +function createPool() { + poolSize = Buffer.poolSize; + allocBuffer = createUnsafeBuffer(poolSize); + allocPool = allocBuffer.buffer; + markAsUntransferable(allocPool); + poolOffset = 0; +} +createPool(); + +function alignPool() { + // Ensure aligned slices + if (poolOffset & 0x7) { + poolOffset |= 0x7; + poolOffset++; + } +} + +let bufferWarningAlreadyEmitted = false; +let nodeModulesCheckCounter = 0; +const bufferWarning = 'Buffer() is deprecated due to security and usability ' + + 'issues. Please use the Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() methods instead.'; + +function showFlaggedDeprecation() { + if (bufferWarningAlreadyEmitted || + ++nodeModulesCheckCounter > 10000 || + (!require('internal/options').getOptionValue('--pending-deprecation') && + isInsideNodeModules(100, true))) { + // We don't emit a warning, because we either: + // - Already did so, or + // - Already checked too many times whether a call is coming + // from node_modules and want to stop slowing down things, or + // - We aren't running with `--pending-deprecation` enabled, + // and the code is inside `node_modules`. + // - We found node_modules in up to the topmost 100 frames, or + // there are more than 100 frames and we don't want to search anymore. + return; + } + + process.emitWarning(bufferWarning, 'DeprecationWarning', 'DEP0005'); + bufferWarningAlreadyEmitted = true; +} + +function toInteger(n, defaultVal) { + n = +n; + if (!NumberIsNaN(n) && + n >= NumberMIN_SAFE_INTEGER && + n <= NumberMAX_SAFE_INTEGER) { + return ((n % 1) === 0 ? n : MathFloor(n)); + } + return defaultVal; +} + +function copyImpl(source, target, targetStart, sourceStart, sourceEnd) { + if (!ArrayBufferIsView(source)) + throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source); + if (!ArrayBufferIsView(target)) + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); + + if (targetStart === undefined) { + targetStart = 0; + } else { + targetStart = NumberIsInteger(targetStart) ? targetStart : toInteger(targetStart, 0); + if (targetStart < 0) + throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart); + } + + if (sourceStart === undefined) { + sourceStart = 0; + } else { + sourceStart = NumberIsInteger(sourceStart) ? sourceStart : toInteger(sourceStart, 0); + if (sourceStart < 0 || sourceStart > source.byteLength) + throw new ERR_OUT_OF_RANGE('sourceStart', `>= 0 && <= ${source.byteLength}`, sourceStart); + } + + if (sourceEnd === undefined) { + sourceEnd = source.byteLength; + } else { + sourceEnd = NumberIsInteger(sourceEnd) ? sourceEnd : toInteger(sourceEnd, 0); + if (sourceEnd < 0) + throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd); + } + + if (targetStart >= target.byteLength || sourceStart >= sourceEnd) + return 0; + + return _copyActual(source, target, targetStart, sourceStart, sourceEnd); +} + +function _copyActual(source, target, targetStart, sourceStart, sourceEnd) { + if (sourceEnd - sourceStart > target.byteLength - targetStart) + sourceEnd = sourceStart + target.byteLength - targetStart; + + let nb = sourceEnd - sourceStart; + const sourceLen = source.byteLength - sourceStart; + if (nb > sourceLen) + nb = sourceLen; + + if (nb <= 0) + return 0; + + _copy(source, target, targetStart, sourceStart, nb); + + return nb; +} + +/** + * The Buffer() constructor is deprecated in documentation and should not be + * used moving forward. Rather, developers should use one of the three new + * factory APIs: Buffer.from(), Buffer.allocUnsafe() or Buffer.alloc() based on + * their specific needs. There is no runtime deprecation because of the extent + * to which the Buffer constructor is used in the ecosystem currently -- a + * runtime deprecation would introduce too much breakage at this time. It's not + * likely that the Buffer constructors would ever actually be removed. + * Deprecation Code: DEP0005 + * @returns {Buffer} + */ +function Buffer(arg, encodingOrOffset, length) { + showFlaggedDeprecation(); + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new ERR_INVALID_ARG_TYPE('string', 'string', arg); + } + return Buffer.alloc(arg); + } + return Buffer.from(arg, encodingOrOffset, length); +} + +ObjectDefineProperty(Buffer, SymbolSpecies, { + __proto__: null, + enumerable: false, + configurable: true, + get() { return FastBuffer; }, +}); + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + * @param {any} value + * @param {BufferEncoding|number} encodingOrOffset + * @param {number} [length] + * @returns {Buffer} + */ +Buffer.from = function from(value, encodingOrOffset, length) { + if (typeof value === 'string') + return fromString(value, encodingOrOffset); + + if (typeof value === 'object' && value !== null) { + if (isAnyArrayBuffer(value)) + return fromArrayBuffer(value, encodingOrOffset, length); + + const valueOf = value.valueOf && value.valueOf(); + if (valueOf != null && + valueOf !== value && + (typeof valueOf === 'string' || typeof valueOf === 'object')) { + return from(valueOf, encodingOrOffset, length); + } + + const b = fromObject(value); + if (b) + return b; + + if (typeof value[SymbolToPrimitive] === 'function') { + const primitive = value[SymbolToPrimitive]('string'); + if (typeof primitive === 'string') { + return fromString(primitive, encodingOrOffset); + } + } + } + + throw new ERR_INVALID_ARG_TYPE( + 'first argument', + ['string', 'Buffer', 'ArrayBuffer', 'Array', 'Array-like Object'], + value, + ); +}; + +/** + * Creates the Buffer as a copy of the underlying ArrayBuffer of the view + * rather than the contents of the view. + * @param {TypedArray} view + * @param {number} [offset] + * @param {number} [length] + * @returns {Buffer} + */ +Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) { + if (!isTypedArray(view)) { + throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray' ], view); + } + + const viewLength = TypedArrayPrototypeGetLength(view); + if (viewLength === 0) { + return Buffer.alloc(0); + } + + if (offset !== undefined || length !== undefined) { + if (offset !== undefined) { + validateInteger(offset, 'offset', 0); + if (offset >= viewLength) return Buffer.alloc(0); + } else { + offset = 0; + } + let end; + if (length !== undefined) { + validateInteger(length, 'length', 0); + end = offset + length; + } else { + end = viewLength; + } + + view = TypedArrayPrototypeSlice(view, offset, end); + } + + return fromArrayLike(new Uint8Array( + TypedArrayPrototypeGetBuffer(view), + TypedArrayPrototypeGetByteOffset(view), + TypedArrayPrototypeGetByteLength(view))); +}; + +// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated +// Buffer() constructor. Must use arrow function syntax to avoid automatically +// adding a `prototype` property and making the function a constructor. +// +// Refs: https://tc39.github.io/ecma262/#sec-%typedarray%.of +// Refs: https://esdiscuss.org/topic/isconstructor#content-11 +const of = (...items) => { + const newObj = createUnsafeBuffer(items.length); + for (let k = 0; k < items.length; k++) + newObj[k] = items[k]; + return newObj; +}; +Buffer.of = of; + +ObjectSetPrototypeOf(Buffer, Uint8Array); + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + * @returns {FastBuffer} + */ +Buffer.alloc = function alloc(size, fill, encoding) { + validateNumber(size, 'size', 0, kMaxLength); + if (fill !== undefined && fill !== 0 && size > 0) { + const buf = createUnsafeBuffer(size); + return _fill(buf, fill, 0, buf.length, encoding); + } + return new FastBuffer(size); +}; + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer + * instance. If `--zero-fill-buffers` is set, will zero-fill the buffer. + * @returns {FastBuffer} + */ +Buffer.allocUnsafe = function allocUnsafe(size) { + validateNumber(size, 'size', 0, kMaxLength); + return allocate(size); +}; + +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled + * Buffer instance that is not allocated off the pre-initialized pool. + * If `--zero-fill-buffers` is set, will zero-fill the buffer. + * @param {number} size + * @returns {FastBuffer|undefined} + */ +Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) { + validateNumber(size, 'size', 0, kMaxLength); + return createUnsafeBuffer(size); +}; + +// If --zero-fill-buffers command line argument is set, a zero-filled +// buffer is returned. +function SlowBuffer(size) { + validateNumber(size, 'size', 0, kMaxLength); + return createUnsafeBuffer(size); +} + +ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype); +ObjectSetPrototypeOf(SlowBuffer, Uint8Array); + +function allocate(size) { + if (size <= 0) { + return new FastBuffer(); + } + if (size < (Buffer.poolSize >>> 1)) { + if (size > (poolSize - poolOffset)) + createPool(); + const b = new FastBuffer(allocPool, poolOffset, size); + poolOffset += size; + alignPool(); + return b; + } + return createUnsafeBuffer(size); +} + +function fromStringFast(string, ops) { + const maxLength = Buffer.poolSize >>> 1; + + let length = string.length; // Min length + + if (length >= maxLength) + return createFromString(string, ops); + + length *= 4; // Max length (4 bytes per character) + + if (length >= maxLength) + length = ops.byteLength(string); // Actual length + + if (length >= maxLength) + return createFromString(string, ops, length); + + if (length > (poolSize - poolOffset)) + createPool(); + + const actual = ops.write(allocBuffer, string, poolOffset, length); + const b = new FastBuffer(allocPool, poolOffset, actual); + + poolOffset += actual; + alignPool(); + return b; +} + +function createFromString(string, ops, length = ops.byteLength(string)) { + const buf = Buffer.allocUnsafeSlow(length); + const actual = ops.write(buf, string, 0, length); + return actual < length ? new FastBuffer(buf.buffer, 0, actual) : buf; +} + +function fromString(string, encoding) { + let ops; + if (!encoding || encoding === 'utf8' || typeof encoding !== 'string') { + ops = encodingOps.utf8; + } else { + ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + } + + return string.length === 0 ? new FastBuffer() : fromStringFast(string, ops); +} + +function fromArrayBuffer(obj, byteOffset, length) { + // Convert byteOffset to integer + if (byteOffset === undefined) { + byteOffset = 0; + } else { + byteOffset = +byteOffset; + if (NumberIsNaN(byteOffset)) + byteOffset = 0; + } + + const maxLength = obj.byteLength - byteOffset; + + if (maxLength < 0) + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + + if (length !== undefined) { + // Convert length to non-negative integer. + length = +length; + if (length > 0) { + if (length > maxLength) + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } else { + length = 0; + } + } + + return new FastBuffer(obj, byteOffset, length); +} + +function fromArrayLike(obj) { + if (obj.length <= 0) + return new FastBuffer(); + if (obj.length < (Buffer.poolSize >>> 1)) { + if (obj.length > (poolSize - poolOffset)) + createPool(); + const b = new FastBuffer(allocPool, poolOffset, obj.length); + TypedArrayPrototypeSet(b, obj, 0); + poolOffset += obj.length; + alignPool(); + return b; + } + return new FastBuffer(obj); +} + +function fromObject(obj) { + if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) { + if (typeof obj.length !== 'number') { + return new FastBuffer(); + } + return fromArrayLike(obj); + } + + if (obj.type === 'Buffer' && ArrayIsArray(obj.data)) { + return fromArrayLike(obj.data); + } +} + +// Static methods + +Buffer.isBuffer = function isBuffer(b) { + return b instanceof Buffer; +}; + +Buffer.compare = function compare(buf1, buf2) { + if (!isUint8Array(buf1)) { + throw new ERR_INVALID_ARG_TYPE('buf1', ['Buffer', 'Uint8Array'], buf1); + } + + if (!isUint8Array(buf2)) { + throw new ERR_INVALID_ARG_TYPE('buf2', ['Buffer', 'Uint8Array'], buf2); + } + + if (buf1 === buf2) { + return 0; + } + + return _compare(buf1, buf2); +}; + +Buffer.isEncoding = function isEncoding(encoding) { + return typeof encoding === 'string' && encoding.length !== 0 && + normalizeEncoding(encoding) !== undefined; +}; +Buffer[kIsEncodingSymbol] = Buffer.isEncoding; + +Buffer.concat = function concat(list, length) { + validateArray(list, 'list'); + + if (list.length === 0) + return new FastBuffer(); + + if (length === undefined) { + length = 0; + for (let i = 0; i < list.length; i++) { + if (list[i].length) { + length += list[i].length; + } + } + } else { + validateOffset(length, 'length'); + } + + const buffer = Buffer.allocUnsafe(length); + let pos = 0; + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + if (!isUint8Array(buf)) { + // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE. + // Instead, find the proper error code for this. + throw new ERR_INVALID_ARG_TYPE( + `list[${i}]`, ['Buffer', 'Uint8Array'], list[i]); + } + pos += _copyActual(buf, buffer, pos, 0, buf.length); + } + + // Note: `length` is always equal to `buffer.length` at this point + if (pos < length) { + // Zero-fill the remaining bytes if the specified `length` was more than + // the actual total length, i.e. if we have some remaining allocated bytes + // there were not initialized. + TypedArrayPrototypeFill(buffer, 0, pos, length); + } + + return buffer; +}; + +function base64ByteLength(str, bytes) { + // Handle padding + if (StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D) + bytes--; + if (bytes > 1 && StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D) + bytes--; + + // Base64 ratio: 3/4 + return (bytes * 3) >>> 2; +} + +const encodingOps = { + utf8: { + encoding: 'utf8', + encodingVal: encodingsMap.utf8, + byteLength: byteLengthUtf8, + write: (buf, string, offset, len) => buf.utf8Write(string, offset, len), + slice: (buf, start, end) => buf.utf8Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir), + }, + ucs2: { + encoding: 'ucs2', + encodingVal: encodingsMap.utf16le, + byteLength: (string) => string.length * 2, + write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), + slice: (buf, start, end) => buf.ucs2Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), + }, + utf16le: { + encoding: 'utf16le', + encodingVal: encodingsMap.utf16le, + byteLength: (string) => string.length * 2, + write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), + slice: (buf, start, end) => buf.ucs2Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), + }, + latin1: { + encoding: 'latin1', + encodingVal: encodingsMap.latin1, + byteLength: (string) => string.length, + write: (buf, string, offset, len) => buf.latin1Write(string, offset, len), + slice: (buf, start, end) => buf.latin1Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir), + }, + ascii: { + encoding: 'ascii', + encodingVal: encodingsMap.ascii, + byteLength: (string) => string.length, + write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len), + slice: (buf, start, end) => buf.asciiSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.ascii), + byteOffset, + encodingsMap.ascii, + dir), + }, + base64: { + encoding: 'base64', + encodingVal: encodingsMap.base64, + byteLength: (string) => base64ByteLength(string, string.length), + write: (buf, string, offset, len) => buf.base64Write(string, offset, len), + slice: (buf, start, end) => buf.base64Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.base64), + byteOffset, + encodingsMap.base64, + dir), + }, + base64url: { + encoding: 'base64url', + encodingVal: encodingsMap.base64url, + byteLength: (string) => base64ByteLength(string, string.length), + write: (buf, string, offset, len) => + buf.base64urlWrite(string, offset, len), + slice: (buf, start, end) => buf.base64urlSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.base64url), + byteOffset, + encodingsMap.base64url, + dir), + }, + hex: { + encoding: 'hex', + encodingVal: encodingsMap.hex, + byteLength: (string) => string.length >>> 1, + write: (buf, string, offset, len) => buf.hexWrite(string, offset, len), + slice: (buf, start, end) => buf.hexSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.hex), + byteOffset, + encodingsMap.hex, + dir), + }, +}; +function getEncodingOps(encoding) { + encoding += ''; + switch (encoding.length) { + case 4: + if (encoding === 'utf8') return encodingOps.utf8; + if (encoding === 'ucs2') return encodingOps.ucs2; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'utf8') return encodingOps.utf8; + if (encoding === 'ucs2') return encodingOps.ucs2; + break; + case 5: + if (encoding === 'utf-8') return encodingOps.utf8; + if (encoding === 'ascii') return encodingOps.ascii; + if (encoding === 'ucs-2') return encodingOps.ucs2; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'utf-8') return encodingOps.utf8; + if (encoding === 'ascii') return encodingOps.ascii; + if (encoding === 'ucs-2') return encodingOps.ucs2; + break; + case 7: + if (encoding === 'utf16le' || + StringPrototypeToLowerCase(encoding) === 'utf16le') + return encodingOps.utf16le; + break; + case 8: + if (encoding === 'utf-16le' || + StringPrototypeToLowerCase(encoding) === 'utf-16le') + return encodingOps.utf16le; + break; + case 6: + if (encoding === 'latin1' || encoding === 'binary') + return encodingOps.latin1; + if (encoding === 'base64') return encodingOps.base64; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'latin1' || encoding === 'binary') + return encodingOps.latin1; + if (encoding === 'base64') return encodingOps.base64; + break; + case 3: + if (encoding === 'hex' || StringPrototypeToLowerCase(encoding) === 'hex') + return encodingOps.hex; + break; + case 9: + if (encoding === 'base64url' || + StringPrototypeToLowerCase(encoding) === 'base64url') + return encodingOps.base64url; + break; + } +} + +function byteLength(string, encoding) { + if (typeof string !== 'string') { + if (isArrayBufferView(string) || isAnyArrayBuffer(string)) { + return string.byteLength; + } + + throw new ERR_INVALID_ARG_TYPE( + 'string', ['string', 'Buffer', 'ArrayBuffer'], string, + ); + } + + const len = string.length; + if (len === 0) + return 0; + + if (!encoding || encoding === 'utf8') { + return byteLengthUtf8(string); + } + + if (encoding === 'ascii') { + return len; + } + + const ops = getEncodingOps(encoding); + if (ops === undefined) { + // TODO (ronag): Makes more sense to throw here. + // throw new ERR_UNKNOWN_ENCODING(encoding); + return byteLengthUtf8(string); + } + + return ops.byteLength(string); +} + +Buffer.byteLength = byteLength; + +// For backwards compatibility. +ObjectDefineProperty(Buffer.prototype, 'parent', { + __proto__: null, + enumerable: true, + get() { + if (!(this instanceof Buffer)) + return undefined; + return this.buffer; + }, +}); +ObjectDefineProperty(Buffer.prototype, 'offset', { + __proto__: null, + enumerable: true, + get() { + if (!(this instanceof Buffer)) + return undefined; + return this.byteOffset; + }, +}); + +Buffer.prototype.copy = + function copy(target, targetStart, sourceStart, sourceEnd) { + return copyImpl(this, target, targetStart, sourceStart, sourceEnd); + }; + +// No need to verify that "buf.length <= MAX_UINT32" since it's a read-only +// property of a typed array. +// This behaves neither like String nor Uint8Array in that we set start/end +// to their upper/lower bounds if the value passed is out of range. +Buffer.prototype.toString = function toString(encoding, start, end) { + if (arguments.length === 0) { + return this.utf8Slice(0, this.length); + } + + const len = this.length; + + if (start <= 0) + start = 0; + else if (start >= len) + return ''; + else + start = MathTrunc(start) || 0; + + if (end === undefined || end > len) + end = len; + else + end = MathTrunc(end) || 0; + + if (end <= start) + return ''; + + if (encoding === undefined) + return this.utf8Slice(start, end); + + const ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + + return ops.slice(this, start, end); +}; + +Buffer.prototype.equals = function equals(otherBuffer) { + if (!isUint8Array(otherBuffer)) { + throw new ERR_INVALID_ARG_TYPE( + 'otherBuffer', ['Buffer', 'Uint8Array'], otherBuffer); + } + + if (this === otherBuffer) + return true; + const len = TypedArrayPrototypeGetByteLength(this); + if (len !== TypedArrayPrototypeGetByteLength(otherBuffer)) + return false; + + return len === 0 || _compare(this, otherBuffer) === 0; +}; + +let INSPECT_MAX_BYTES = 50; +// Override how buffers are presented by util.inspect(). +Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) { + const max = INSPECT_MAX_BYTES; + const actualMax = MathMin(max, this.length); + const remaining = this.length - max; + let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace( + /(.{2})/g, this.hexSlice(0, actualMax), '$1 ')); + if (remaining > 0) + str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; + // Inspect special properties as well, if possible. + if (ctx) { + let extras = false; + const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE; + const obj = { __proto__: null }; + ArrayPrototypeForEach(getOwnNonIndexProperties(this, filter), + (key) => { + extras = true; + obj[key] = this[key]; + }); + if (extras) { + if (this.length !== 0) + str += ', '; + // '[Object: null prototype] {'.length === 26 + // This is guarded with a test. + str += StringPrototypeSlice(utilInspect(obj, { + ...ctx, + breakLength: Infinity, + compact: true, + }), 27, -2); + } + } + let constructorName = 'Buffer'; + try { + const { constructor } = this; + if (typeof constructor === 'function' && ObjectPrototypeHasOwnProperty(constructor, 'name')) { + constructorName = constructor.name; + } + } catch { /* Ignore error and use default name */ } + return `<${constructorName} ${str}>`; +}; +Buffer.prototype.inspect = Buffer.prototype[customInspectSymbol]; + +Buffer.prototype.compare = function compare(target, + targetStart, + targetEnd, + sourceStart, + sourceEnd) { + if (!isUint8Array(target)) { + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); + } + if (arguments.length === 1) + return _compare(this, target); + + if (targetStart === undefined) + targetStart = 0; + else + validateOffset(targetStart, 'targetStart'); + + if (targetEnd === undefined) + targetEnd = target.length; + else + validateOffset(targetEnd, 'targetEnd', 0, target.length); + + if (sourceStart === undefined) + sourceStart = 0; + else + validateOffset(sourceStart, 'sourceStart'); + + if (sourceEnd === undefined) + sourceEnd = this.length; + else + validateOffset(sourceEnd, 'sourceEnd', 0, this.length); + + if (sourceStart >= sourceEnd) + return (targetStart >= targetEnd ? 0 : -1); + if (targetStart >= targetEnd) + return 1; + + return compareOffset(this, target, targetStart, sourceStart, targetEnd, + sourceEnd); +}; + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant if val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { + validateBuffer(buffer); + + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = undefined; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + // Coerce to Number. Values like null and [] become 0. + byteOffset = +byteOffset; + // If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer. + if (NumberIsNaN(byteOffset)) { + byteOffset = dir ? 0 : (buffer.length || buffer.byteLength); + } + dir = !!dir; // Cast to bool. + + if (typeof val === 'number') + return indexOfNumber(buffer, val >>> 0, byteOffset, dir); + + let ops; + if (encoding === undefined) + ops = encodingOps.utf8; + else + ops = getEncodingOps(encoding); + + if (typeof val === 'string') { + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + return ops.indexOf(buffer, val, byteOffset, dir); + } + + if (isUint8Array(val)) { + const encodingVal = + (ops === undefined ? encodingsMap.utf8 : ops.encodingVal); + return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir); + } + + throw new ERR_INVALID_ARG_TYPE( + 'value', ['number', 'string', 'Buffer', 'Uint8Array'], val, + ); +} + +Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true); +}; + +Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false); +}; + +Buffer.prototype.includes = function includes(val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1; +}; + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill(value, offset, end, encoding) { + return _fill(this, value, offset, end, encoding); +}; + +function _fill(buf, value, offset, end, encoding) { + if (typeof value === 'string') { + if (offset === undefined || typeof offset === 'string') { + encoding = offset; + offset = 0; + end = buf.length; + } else if (typeof end === 'string') { + encoding = end; + end = buf.length; + } + + const normalizedEncoding = normalizeEncoding(encoding); + if (normalizedEncoding === undefined) { + validateString(encoding, 'encoding'); + throw new ERR_UNKNOWN_ENCODING(encoding); + } + + if (value.length === 0) { + // If value === '' default to zero. + value = 0; + } else if (value.length === 1) { + // Fast path: If `value` fits into a single byte, use that numeric value. + if (normalizedEncoding === 'utf8') { + const code = StringPrototypeCharCodeAt(value, 0); + if (code < 128) { + value = code; + } + } else if (normalizedEncoding === 'latin1') { + value = StringPrototypeCharCodeAt(value, 0); + } + } + } else { + encoding = undefined; + } + + if (offset === undefined) { + offset = 0; + end = buf.length; + } else { + validateOffset(offset, 'offset'); + // Invalid ranges are not set to a default, so can range check early. + if (end === undefined) { + end = buf.length; + } else { + validateOffset(end, 'end', 0, buf.length); + } + if (offset >= end) + return buf; + } + + + if (typeof value === 'number') { + // OOB check + const byteLen = TypedArrayPrototypeGetByteLength(buf); + const fillLength = end - offset; + if (offset > end || fillLength + offset > byteLen) + throw new ERR_BUFFER_OUT_OF_BOUNDS(); + + TypedArrayPrototypeFill(buf, value, offset, end); + } else { + const res = bindingFill(buf, value, offset, end, encoding); + if (res < 0) { + if (res === -1) + throw new ERR_INVALID_ARG_VALUE('value', value); + throw new ERR_BUFFER_OUT_OF_BOUNDS(); + } + } + + return buf; +} + +Buffer.prototype.write = function write(string, offset, length, encoding) { + // Buffer#write(string); + if (offset === undefined) { + return this.utf8Write(string, 0, this.length); + } + // Buffer#write(string, encoding) + if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + + // Buffer#write(string, offset[, length][, encoding]) + } else { + validateOffset(offset, 'offset', 0, this.length); + + const remaining = this.length - offset; + + if (length === undefined) { + length = remaining; + } else if (typeof length === 'string') { + encoding = length; + length = remaining; + } else { + validateOffset(length, 'length', 0, this.length); + if (length > remaining) + length = remaining; + } + } + + if (!encoding || encoding === 'utf8') + return this.utf8Write(string, offset, length); + if (encoding === 'ascii') + return this.asciiWrite(string, offset, length); + + const ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + return ops.write(this, string, offset, length); +}; + +Buffer.prototype.toJSON = function toJSON() { + if (this.length > 0) { + const data = new Array(this.length); + for (let i = 0; i < this.length; ++i) + data[i] = this[i]; + return { type: 'Buffer', data }; + } + return { type: 'Buffer', data: [] }; +}; + +function adjustOffset(offset, length) { + // Use Math.trunc() to convert offset to an integer value that can be larger + // than an Int32. Hence, don't use offset | 0 or similar techniques. + offset = MathTrunc(offset); + if (offset === 0) { + return 0; + } + if (offset < 0) { + offset += length; + return offset > 0 ? offset : 0; + } + if (offset < length) { + return offset; + } + return NumberIsNaN(offset) ? 0 : length; +} + +Buffer.prototype.subarray = function subarray(start, end) { + const srcLength = this.length; + start = adjustOffset(start, srcLength); + end = end !== undefined ? adjustOffset(end, srcLength) : srcLength; + const newLength = end > start ? end - start : 0; + return new FastBuffer(this.buffer, this.byteOffset + start, newLength); +}; + +Buffer.prototype.slice = function slice(start, end) { + return this.subarray(start, end); +}; + +function swap(b, n, m) { + const i = b[n]; + b[n] = b[m]; + b[m] = i; +} + +Buffer.prototype.swap16 = function swap16() { + // For Buffer.length < 128, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 2 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('16-bits'); + if (len < 128) { + for (let i = 0; i < len; i += 2) + swap(this, i, i + 1); + return this; + } + return _swap16(this); +}; + +Buffer.prototype.swap32 = function swap32() { + // For Buffer.length < 192, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 4 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('32-bits'); + if (len < 192) { + for (let i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; + } + return _swap32(this); +}; + +Buffer.prototype.swap64 = function swap64() { + // For Buffer.length < 192, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 8 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('64-bits'); + if (len < 192) { + for (let i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this; + } + return _swap64(this); +}; + +Buffer.prototype.toLocaleString = Buffer.prototype.toString; + +let transcode; +if (internalBinding('config').hasIntl) { + const { + icuErrName, + transcode: _transcode, + } = internalBinding('icu'); + + // Transcodes the Buffer from one encoding to another, returning a new + // Buffer instance. + transcode = function transcode(source, fromEncoding, toEncoding) { + if (!isUint8Array(source)) { + throw new ERR_INVALID_ARG_TYPE('source', + ['Buffer', 'Uint8Array'], source); + } + if (source.length === 0) return Buffer.alloc(0); + + fromEncoding = normalizeEncoding(fromEncoding) || fromEncoding; + toEncoding = normalizeEncoding(toEncoding) || toEncoding; + const result = _transcode(source, fromEncoding, toEncoding); + if (typeof result !== 'number') + return result; + + const code = icuErrName(result); + const err = genericNodeError( + `Unable to transcode Buffer [${code}]`, + { code: code, errno: result }, + ); + throw err; + }; +} + +function btoa(input) { + // The implementation here has not been performance optimized in any way and + // should not be. + // Refs: https://github.com/nodejs/node/pull/38433#issuecomment-828426932 + if (arguments.length === 0) { + throw new ERR_MISSING_ARGS('input'); + } + const result = _btoa(`${input}`); + if (result === -1) { + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + } + return result; +} + +function atob(input) { + if (arguments.length === 0) { + throw new ERR_MISSING_ARGS('input'); + } + + const result = _atob(`${input}`); + + switch (result) { + case -2: // Invalid character + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + case -1: // Single character remained + throw lazyDOMException( + 'The string to be decoded is not correctly encoded.', + 'InvalidCharacterError'); + case -3: // Possible overflow + // TODO(@anonrig): Throw correct error in here. + throw lazyDOMException('The input causes overflow.', 'InvalidCharacterError'); + default: + return result; + } +} + +function isUtf8(input) { + if (isTypedArray(input) || isAnyArrayBuffer(input)) { + return bindingIsUtf8(input); + } + + throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input); +} + +function isAscii(input) { + if (isTypedArray(input) || isAnyArrayBuffer(input)) { + return bindingIsAscii(input); + } + + throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input); +} + +module.exports = { + Buffer, + SlowBuffer: deprecate( + SlowBuffer, + 'SlowBuffer() is deprecated. Please use Buffer.allocUnsafeSlow()', + 'DEP0030'), + transcode, + isUtf8, + isAscii, + + // Legacy + kMaxLength, + kStringMaxLength, + btoa, + atob, +}; + +ObjectDefineProperties(module.exports, { + constants: { + __proto__: null, + configurable: false, + enumerable: true, + value: constants, + }, + INSPECT_MAX_BYTES: { + __proto__: null, + configurable: true, + enumerable: true, + get() { return INSPECT_MAX_BYTES; }, + set(val) { + validateNumber(val, 'INSPECT_MAX_BYTES', 0); + INSPECT_MAX_BYTES = val; + }, + }, +}); + +defineLazyProperties( + module.exports, + 'internal/blob', + ['Blob', 'resolveObjectURL'], +); +defineLazyProperties( + module.exports, + 'internal/file', + ['File'], +); \ No newline at end of file diff --git a/.codesandbox/node/cluster.js b/.codesandbox/node/cluster.js new file mode 100644 index 00000000..6f3dc168 --- /dev/null +++ b/.codesandbox/node/cluster.js @@ -0,0 +1,8 @@ +'use strict'; + +const { + ObjectPrototypeHasOwnProperty: ObjectHasOwn, +} = primordials; + +const childOrPrimary = ObjectHasOwn(process.env, 'NODE_UNIQUE_ID') ? 'child' : 'primary'; +module.exports = require(`internal/cluster/${childOrPrimary}`); \ No newline at end of file diff --git a/.codesandbox/node/crypto.js b/.codesandbox/node/crypto.js new file mode 100644 index 00000000..06bfebc7 --- /dev/null +++ b/.codesandbox/node/crypto.js @@ -0,0 +1,1365 @@ +'use strict'; + +const { + Array, + ArrayBufferIsView, + ArrayIsArray, + ArrayPrototypeForEach, + MathFloor, + MathMin, + MathTrunc, + NumberIsInteger, + NumberIsNaN, + NumberMAX_SAFE_INTEGER, + NumberMIN_SAFE_INTEGER, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectPrototypeHasOwnProperty, + ObjectSetPrototypeOf, + RegExpPrototypeSymbolReplace, + StringPrototypeCharCodeAt, + StringPrototypeSlice, + StringPrototypeToLowerCase, + StringPrototypeTrim, + SymbolSpecies, + SymbolToPrimitive, + TypedArrayPrototypeFill, + TypedArrayPrototypeGetBuffer, + TypedArrayPrototypeGetByteLength, + TypedArrayPrototypeGetByteOffset, + TypedArrayPrototypeGetLength, + TypedArrayPrototypeSet, + TypedArrayPrototypeSlice, + Uint8Array, + Uint8ArrayPrototype, +} = primordials; + +const { + byteLengthUtf8, + compare: _compare, + compareOffset, + copy: _copy, + fill: bindingFill, + isAscii: bindingIsAscii, + isUtf8: bindingIsUtf8, + indexOfBuffer, + indexOfNumber, + indexOfString, + swap16: _swap16, + swap32: _swap32, + swap64: _swap64, + kMaxLength, + kStringMaxLength, + atob: _atob, + btoa: _btoa, +} = internalBinding('buffer'); +const { + constants: { + ALL_PROPERTIES, + ONLY_ENUMERABLE, + }, + getOwnNonIndexProperties, + isInsideNodeModules, +} = internalBinding('util'); +const { + customInspectSymbol, + lazyDOMException, + normalizeEncoding, + kIsEncodingSymbol, + defineLazyProperties, + encodingsMap, + deprecate, +} = require('internal/util'); +const { + isAnyArrayBuffer, + isArrayBufferView, + isUint8Array, + isTypedArray, +} = require('internal/util/types'); +const { + inspect: utilInspect, +} = require('internal/util/inspect'); + +const { + codes: { + ERR_BUFFER_OUT_OF_BOUNDS, + ERR_INVALID_ARG_TYPE, + ERR_INVALID_ARG_VALUE, + ERR_INVALID_BUFFER_SIZE, + ERR_MISSING_ARGS, + ERR_OUT_OF_RANGE, + ERR_UNKNOWN_ENCODING, + }, + genericNodeError, +} = require('internal/errors'); +const { + validateArray, + validateBuffer, + validateInteger, + validateNumber, + validateString, +} = require('internal/validators'); +// Provide validateInteger() but with kMaxLength as the default maximum value. +const validateOffset = (value, name, min = 0, max = kMaxLength) => + validateInteger(value, name, min, max); + +const { + FastBuffer, + markAsUntransferable, + addBufferPrototypeMethods, + createUnsafeBuffer, +} = require('internal/buffer'); + +FastBuffer.prototype.constructor = Buffer; +Buffer.prototype = FastBuffer.prototype; +addBufferPrototypeMethods(Buffer.prototype); + +const constants = ObjectDefineProperties({}, { + MAX_LENGTH: { + __proto__: null, + value: kMaxLength, + writable: false, + enumerable: true, + }, + MAX_STRING_LENGTH: { + __proto__: null, + value: kStringMaxLength, + writable: false, + enumerable: true, + }, +}); + +Buffer.poolSize = 8 * 1024; +let poolSize, poolOffset, allocPool, allocBuffer; + +function createPool() { + poolSize = Buffer.poolSize; + allocBuffer = createUnsafeBuffer(poolSize); + allocPool = allocBuffer.buffer; + markAsUntransferable(allocPool); + poolOffset = 0; +} +createPool(); + +function alignPool() { + // Ensure aligned slices + if (poolOffset & 0x7) { + poolOffset |= 0x7; + poolOffset++; + } +} + +let bufferWarningAlreadyEmitted = false; +let nodeModulesCheckCounter = 0; +const bufferWarning = 'Buffer() is deprecated due to security and usability ' + + 'issues. Please use the Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() methods instead.'; + +function showFlaggedDeprecation() { + if (bufferWarningAlreadyEmitted || + ++nodeModulesCheckCounter > 10000 || + (!require('internal/options').getOptionValue('--pending-deprecation') && + isInsideNodeModules(100, true))) { + // We don't emit a warning, because we either: + // - Already did so, or + // - Already checked too many times whether a call is coming + // from node_modules and want to stop slowing down things, or + // - We aren't running with `--pending-deprecation` enabled, + // and the code is inside `node_modules`. + // - We found node_modules in up to the topmost 100 frames, or + // there are more than 100 frames and we don't want to search anymore. + return; + } + + process.emitWarning(bufferWarning, 'DeprecationWarning', 'DEP0005'); + bufferWarningAlreadyEmitted = true; +} + +function toInteger(n, defaultVal) { + n = +n; + if (!NumberIsNaN(n) && + n >= NumberMIN_SAFE_INTEGER && + n <= NumberMAX_SAFE_INTEGER) { + return ((n % 1) === 0 ? n : MathFloor(n)); + } + return defaultVal; +} + +function copyImpl(source, target, targetStart, sourceStart, sourceEnd) { + if (!ArrayBufferIsView(source)) + throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source); + if (!ArrayBufferIsView(target)) + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); + + if (targetStart === undefined) { + targetStart = 0; + } else { + targetStart = NumberIsInteger(targetStart) ? targetStart : toInteger(targetStart, 0); + if (targetStart < 0) + throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart); + } + + if (sourceStart === undefined) { + sourceStart = 0; + } else { + sourceStart = NumberIsInteger(sourceStart) ? sourceStart : toInteger(sourceStart, 0); + if (sourceStart < 0 || sourceStart > source.byteLength) + throw new ERR_OUT_OF_RANGE('sourceStart', `>= 0 && <= ${source.byteLength}`, sourceStart); + } + + if (sourceEnd === undefined) { + sourceEnd = source.byteLength; + } else { + sourceEnd = NumberIsInteger(sourceEnd) ? sourceEnd : toInteger(sourceEnd, 0); + if (sourceEnd < 0) + throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd); + } + + if (targetStart >= target.byteLength || sourceStart >= sourceEnd) + return 0; + + return _copyActual(source, target, targetStart, sourceStart, sourceEnd); +} + +function _copyActual(source, target, targetStart, sourceStart, sourceEnd) { + if (sourceEnd - sourceStart > target.byteLength - targetStart) + sourceEnd = sourceStart + target.byteLength - targetStart; + + let nb = sourceEnd - sourceStart; + const sourceLen = source.byteLength - sourceStart; + if (nb > sourceLen) + nb = sourceLen; + + if (nb <= 0) + return 0; + + _copy(source, target, targetStart, sourceStart, nb); + + return nb; +} + +/** + * The Buffer() constructor is deprecated in documentation and should not be + * used moving forward. Rather, developers should use one of the three new + * factory APIs: Buffer.from(), Buffer.allocUnsafe() or Buffer.alloc() based on + * their specific needs. There is no runtime deprecation because of the extent + * to which the Buffer constructor is used in the ecosystem currently -- a + * runtime deprecation would introduce too much breakage at this time. It's not + * likely that the Buffer constructors would ever actually be removed. + * Deprecation Code: DEP0005 + * @returns {Buffer} + */ +function Buffer(arg, encodingOrOffset, length) { + showFlaggedDeprecation(); + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new ERR_INVALID_ARG_TYPE('string', 'string', arg); + } + return Buffer.alloc(arg); + } + return Buffer.from(arg, encodingOrOffset, length); +} + +ObjectDefineProperty(Buffer, SymbolSpecies, { + __proto__: null, + enumerable: false, + configurable: true, + get() { return FastBuffer; }, +}); + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + * @param {any} value + * @param {BufferEncoding|number} encodingOrOffset + * @param {number} [length] + * @returns {Buffer} + */ +Buffer.from = function from(value, encodingOrOffset, length) { + if (typeof value === 'string') + return fromString(value, encodingOrOffset); + + if (typeof value === 'object' && value !== null) { + if (isAnyArrayBuffer(value)) + return fromArrayBuffer(value, encodingOrOffset, length); + + const valueOf = value.valueOf && value.valueOf(); + if (valueOf != null && + valueOf !== value && + (typeof valueOf === 'string' || typeof valueOf === 'object')) { + return from(valueOf, encodingOrOffset, length); + } + + const b = fromObject(value); + if (b) + return b; + + if (typeof value[SymbolToPrimitive] === 'function') { + const primitive = value[SymbolToPrimitive]('string'); + if (typeof primitive === 'string') { + return fromString(primitive, encodingOrOffset); + } + } + } + + throw new ERR_INVALID_ARG_TYPE( + 'first argument', + ['string', 'Buffer', 'ArrayBuffer', 'Array', 'Array-like Object'], + value, + ); +}; + +/** + * Creates the Buffer as a copy of the underlying ArrayBuffer of the view + * rather than the contents of the view. + * @param {TypedArray} view + * @param {number} [offset] + * @param {number} [length] + * @returns {Buffer} + */ +Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) { + if (!isTypedArray(view)) { + throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray' ], view); + } + + const viewLength = TypedArrayPrototypeGetLength(view); + if (viewLength === 0) { + return Buffer.alloc(0); + } + + if (offset !== undefined || length !== undefined) { + if (offset !== undefined) { + validateInteger(offset, 'offset', 0); + if (offset >= viewLength) return Buffer.alloc(0); + } else { + offset = 0; + } + let end; + if (length !== undefined) { + validateInteger(length, 'length', 0); + end = offset + length; + } else { + end = viewLength; + } + + view = TypedArrayPrototypeSlice(view, offset, end); + } + + return fromArrayLike(new Uint8Array( + TypedArrayPrototypeGetBuffer(view), + TypedArrayPrototypeGetByteOffset(view), + TypedArrayPrototypeGetByteLength(view))); +}; + +// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated +// Buffer() constructor. Must use arrow function syntax to avoid automatically +// adding a `prototype` property and making the function a constructor. +// +// Refs: https://tc39.github.io/ecma262/#sec-%typedarray%.of +// Refs: https://esdiscuss.org/topic/isconstructor#content-11 +const of = (...items) => { + const newObj = createUnsafeBuffer(items.length); + for (let k = 0; k < items.length; k++) + newObj[k] = items[k]; + return newObj; +}; +Buffer.of = of; + +ObjectSetPrototypeOf(Buffer, Uint8Array); + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + * @returns {FastBuffer} + */ +Buffer.alloc = function alloc(size, fill, encoding) { + validateNumber(size, 'size', 0, kMaxLength); + if (fill !== undefined && fill !== 0 && size > 0) { + const buf = createUnsafeBuffer(size); + return _fill(buf, fill, 0, buf.length, encoding); + } + return new FastBuffer(size); +}; + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer + * instance. If `--zero-fill-buffers` is set, will zero-fill the buffer. + * @returns {FastBuffer} + */ +Buffer.allocUnsafe = function allocUnsafe(size) { + validateNumber(size, 'size', 0, kMaxLength); + return allocate(size); +}; + +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled + * Buffer instance that is not allocated off the pre-initialized pool. + * If `--zero-fill-buffers` is set, will zero-fill the buffer. + * @param {number} size + * @returns {FastBuffer|undefined} + */ +Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) { + validateNumber(size, 'size', 0, kMaxLength); + return createUnsafeBuffer(size); +}; + +// If --zero-fill-buffers command line argument is set, a zero-filled +// buffer is returned. +function SlowBuffer(size) { + validateNumber(size, 'size', 0, kMaxLength); + return createUnsafeBuffer(size); +} + +ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype); +ObjectSetPrototypeOf(SlowBuffer, Uint8Array); + +function allocate(size) { + if (size <= 0) { + return new FastBuffer(); + } + if (size < (Buffer.poolSize >>> 1)) { + if (size > (poolSize - poolOffset)) + createPool(); + const b = new FastBuffer(allocPool, poolOffset, size); + poolOffset += size; + alignPool(); + return b; + } + return createUnsafeBuffer(size); +} + +function fromStringFast(string, ops) { + const maxLength = Buffer.poolSize >>> 1; + + let length = string.length; // Min length + + if (length >= maxLength) + return createFromString(string, ops); + + length *= 4; // Max length (4 bytes per character) + + if (length >= maxLength) + length = ops.byteLength(string); // Actual length + + if (length >= maxLength) + return createFromString(string, ops, length); + + if (length > (poolSize - poolOffset)) + createPool(); + + const actual = ops.write(allocBuffer, string, poolOffset, length); + const b = new FastBuffer(allocPool, poolOffset, actual); + + poolOffset += actual; + alignPool(); + return b; +} + +function createFromString(string, ops, length = ops.byteLength(string)) { + const buf = Buffer.allocUnsafeSlow(length); + const actual = ops.write(buf, string, 0, length); + return actual < length ? new FastBuffer(buf.buffer, 0, actual) : buf; +} + +function fromString(string, encoding) { + let ops; + if (!encoding || encoding === 'utf8' || typeof encoding !== 'string') { + ops = encodingOps.utf8; + } else { + ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + } + + return string.length === 0 ? new FastBuffer() : fromStringFast(string, ops); +} + +function fromArrayBuffer(obj, byteOffset, length) { + // Convert byteOffset to integer + if (byteOffset === undefined) { + byteOffset = 0; + } else { + byteOffset = +byteOffset; + if (NumberIsNaN(byteOffset)) + byteOffset = 0; + } + + const maxLength = obj.byteLength - byteOffset; + + if (maxLength < 0) + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + + if (length !== undefined) { + // Convert length to non-negative integer. + length = +length; + if (length > 0) { + if (length > maxLength) + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } else { + length = 0; + } + } + + return new FastBuffer(obj, byteOffset, length); +} + +function fromArrayLike(obj) { + if (obj.length <= 0) + return new FastBuffer(); + if (obj.length < (Buffer.poolSize >>> 1)) { + if (obj.length > (poolSize - poolOffset)) + createPool(); + const b = new FastBuffer(allocPool, poolOffset, obj.length); + TypedArrayPrototypeSet(b, obj, 0); + poolOffset += obj.length; + alignPool(); + return b; + } + return new FastBuffer(obj); +} + +function fromObject(obj) { + if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) { + if (typeof obj.length !== 'number') { + return new FastBuffer(); + } + return fromArrayLike(obj); + } + + if (obj.type === 'Buffer' && ArrayIsArray(obj.data)) { + return fromArrayLike(obj.data); + } +} + +// Static methods + +Buffer.isBuffer = function isBuffer(b) { + return b instanceof Buffer; +}; + +Buffer.compare = function compare(buf1, buf2) { + if (!isUint8Array(buf1)) { + throw new ERR_INVALID_ARG_TYPE('buf1', ['Buffer', 'Uint8Array'], buf1); + } + + if (!isUint8Array(buf2)) { + throw new ERR_INVALID_ARG_TYPE('buf2', ['Buffer', 'Uint8Array'], buf2); + } + + if (buf1 === buf2) { + return 0; + } + + return _compare(buf1, buf2); +}; + +Buffer.isEncoding = function isEncoding(encoding) { + return typeof encoding === 'string' && encoding.length !== 0 && + normalizeEncoding(encoding) !== undefined; +}; +Buffer[kIsEncodingSymbol] = Buffer.isEncoding; + +Buffer.concat = function concat(list, length) { + validateArray(list, 'list'); + + if (list.length === 0) + return new FastBuffer(); + + if (length === undefined) { + length = 0; + for (let i = 0; i < list.length; i++) { + if (list[i].length) { + length += list[i].length; + } + } + } else { + validateOffset(length, 'length'); + } + + const buffer = Buffer.allocUnsafe(length); + let pos = 0; + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + if (!isUint8Array(buf)) { + // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE. + // Instead, find the proper error code for this. + throw new ERR_INVALID_ARG_TYPE( + `list[${i}]`, ['Buffer', 'Uint8Array'], list[i]); + } + pos += _copyActual(buf, buffer, pos, 0, buf.length); + } + + // Note: `length` is always equal to `buffer.length` at this point + if (pos < length) { + // Zero-fill the remaining bytes if the specified `length` was more than + // the actual total length, i.e. if we have some remaining allocated bytes + // there were not initialized. + TypedArrayPrototypeFill(buffer, 0, pos, length); + } + + return buffer; +}; + +function base64ByteLength(str, bytes) { + // Handle padding + if (StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D) + bytes--; + if (bytes > 1 && StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D) + bytes--; + + // Base64 ratio: 3/4 + return (bytes * 3) >>> 2; +} + +const encodingOps = { + utf8: { + encoding: 'utf8', + encodingVal: encodingsMap.utf8, + byteLength: byteLengthUtf8, + write: (buf, string, offset, len) => buf.utf8Write(string, offset, len), + slice: (buf, start, end) => buf.utf8Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir), + }, + ucs2: { + encoding: 'ucs2', + encodingVal: encodingsMap.utf16le, + byteLength: (string) => string.length * 2, + write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), + slice: (buf, start, end) => buf.ucs2Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), + }, + utf16le: { + encoding: 'utf16le', + encodingVal: encodingsMap.utf16le, + byteLength: (string) => string.length * 2, + write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), + slice: (buf, start, end) => buf.ucs2Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), + }, + latin1: { + encoding: 'latin1', + encodingVal: encodingsMap.latin1, + byteLength: (string) => string.length, + write: (buf, string, offset, len) => buf.latin1Write(string, offset, len), + slice: (buf, start, end) => buf.latin1Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir), + }, + ascii: { + encoding: 'ascii', + encodingVal: encodingsMap.ascii, + byteLength: (string) => string.length, + write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len), + slice: (buf, start, end) => buf.asciiSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.ascii), + byteOffset, + encodingsMap.ascii, + dir), + }, + base64: { + encoding: 'base64', + encodingVal: encodingsMap.base64, + byteLength: (string) => base64ByteLength(string, string.length), + write: (buf, string, offset, len) => buf.base64Write(string, offset, len), + slice: (buf, start, end) => buf.base64Slice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.base64), + byteOffset, + encodingsMap.base64, + dir), + }, + base64url: { + encoding: 'base64url', + encodingVal: encodingsMap.base64url, + byteLength: (string) => base64ByteLength(string, string.length), + write: (buf, string, offset, len) => + buf.base64urlWrite(string, offset, len), + slice: (buf, start, end) => buf.base64urlSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.base64url), + byteOffset, + encodingsMap.base64url, + dir), + }, + hex: { + encoding: 'hex', + encodingVal: encodingsMap.hex, + byteLength: (string) => string.length >>> 1, + write: (buf, string, offset, len) => buf.hexWrite(string, offset, len), + slice: (buf, start, end) => buf.hexSlice(start, end), + indexOf: (buf, val, byteOffset, dir) => + indexOfBuffer(buf, + fromStringFast(val, encodingOps.hex), + byteOffset, + encodingsMap.hex, + dir), + }, +}; +function getEncodingOps(encoding) { + encoding += ''; + switch (encoding.length) { + case 4: + if (encoding === 'utf8') return encodingOps.utf8; + if (encoding === 'ucs2') return encodingOps.ucs2; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'utf8') return encodingOps.utf8; + if (encoding === 'ucs2') return encodingOps.ucs2; + break; + case 5: + if (encoding === 'utf-8') return encodingOps.utf8; + if (encoding === 'ascii') return encodingOps.ascii; + if (encoding === 'ucs-2') return encodingOps.ucs2; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'utf-8') return encodingOps.utf8; + if (encoding === 'ascii') return encodingOps.ascii; + if (encoding === 'ucs-2') return encodingOps.ucs2; + break; + case 7: + if (encoding === 'utf16le' || + StringPrototypeToLowerCase(encoding) === 'utf16le') + return encodingOps.utf16le; + break; + case 8: + if (encoding === 'utf-16le' || + StringPrototypeToLowerCase(encoding) === 'utf-16le') + return encodingOps.utf16le; + break; + case 6: + if (encoding === 'latin1' || encoding === 'binary') + return encodingOps.latin1; + if (encoding === 'base64') return encodingOps.base64; + encoding = StringPrototypeToLowerCase(encoding); + if (encoding === 'latin1' || encoding === 'binary') + return encodingOps.latin1; + if (encoding === 'base64') return encodingOps.base64; + break; + case 3: + if (encoding === 'hex' || StringPrototypeToLowerCase(encoding) === 'hex') + return encodingOps.hex; + break; + case 9: + if (encoding === 'base64url' || + StringPrototypeToLowerCase(encoding) === 'base64url') + return encodingOps.base64url; + break; + } +} + +function byteLength(string, encoding) { + if (typeof string !== 'string') { + if (isArrayBufferView(string) || isAnyArrayBuffer(string)) { + return string.byteLength; + } + + throw new ERR_INVALID_ARG_TYPE( + 'string', ['string', 'Buffer', 'ArrayBuffer'], string, + ); + } + + const len = string.length; + if (len === 0) + return 0; + + if (!encoding || encoding === 'utf8') { + return byteLengthUtf8(string); + } + + if (encoding === 'ascii') { + return len; + } + + const ops = getEncodingOps(encoding); + if (ops === undefined) { + // TODO (ronag): Makes more sense to throw here. + // throw new ERR_UNKNOWN_ENCODING(encoding); + return byteLengthUtf8(string); + } + + return ops.byteLength(string); +} + +Buffer.byteLength = byteLength; + +// For backwards compatibility. +ObjectDefineProperty(Buffer.prototype, 'parent', { + __proto__: null, + enumerable: true, + get() { + if (!(this instanceof Buffer)) + return undefined; + return this.buffer; + }, +}); +ObjectDefineProperty(Buffer.prototype, 'offset', { + __proto__: null, + enumerable: true, + get() { + if (!(this instanceof Buffer)) + return undefined; + return this.byteOffset; + }, +}); + +Buffer.prototype.copy = + function copy(target, targetStart, sourceStart, sourceEnd) { + return copyImpl(this, target, targetStart, sourceStart, sourceEnd); + }; + +// No need to verify that "buf.length <= MAX_UINT32" since it's a read-only +// property of a typed array. +// This behaves neither like String nor Uint8Array in that we set start/end +// to their upper/lower bounds if the value passed is out of range. +Buffer.prototype.toString = function toString(encoding, start, end) { + if (arguments.length === 0) { + return this.utf8Slice(0, this.length); + } + + const len = this.length; + + if (start <= 0) + start = 0; + else if (start >= len) + return ''; + else + start = MathTrunc(start) || 0; + + if (end === undefined || end > len) + end = len; + else + end = MathTrunc(end) || 0; + + if (end <= start) + return ''; + + if (encoding === undefined) + return this.utf8Slice(start, end); + + const ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + + return ops.slice(this, start, end); +}; + +Buffer.prototype.equals = function equals(otherBuffer) { + if (!isUint8Array(otherBuffer)) { + throw new ERR_INVALID_ARG_TYPE( + 'otherBuffer', ['Buffer', 'Uint8Array'], otherBuffer); + } + + if (this === otherBuffer) + return true; + const len = TypedArrayPrototypeGetByteLength(this); + if (len !== TypedArrayPrototypeGetByteLength(otherBuffer)) + return false; + + return len === 0 || _compare(this, otherBuffer) === 0; +}; + +let INSPECT_MAX_BYTES = 50; +// Override how buffers are presented by util.inspect(). +Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) { + const max = INSPECT_MAX_BYTES; + const actualMax = MathMin(max, this.length); + const remaining = this.length - max; + let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace( + /(.{2})/g, this.hexSlice(0, actualMax), '$1 ')); + if (remaining > 0) + str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; + // Inspect special properties as well, if possible. + if (ctx) { + let extras = false; + const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE; + const obj = { __proto__: null }; + ArrayPrototypeForEach(getOwnNonIndexProperties(this, filter), + (key) => { + extras = true; + obj[key] = this[key]; + }); + if (extras) { + if (this.length !== 0) + str += ', '; + // '[Object: null prototype] {'.length === 26 + // This is guarded with a test. + str += StringPrototypeSlice(utilInspect(obj, { + ...ctx, + breakLength: Infinity, + compact: true, + }), 27, -2); + } + } + let constructorName = 'Buffer'; + try { + const { constructor } = this; + if (typeof constructor === 'function' && ObjectPrototypeHasOwnProperty(constructor, 'name')) { + constructorName = constructor.name; + } + } catch { /* Ignore error and use default name */ } + return `<${constructorName} ${str}>`; +}; +Buffer.prototype.inspect = Buffer.prototype[customInspectSymbol]; + +Buffer.prototype.compare = function compare(target, + targetStart, + targetEnd, + sourceStart, + sourceEnd) { + if (!isUint8Array(target)) { + throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target); + } + if (arguments.length === 1) + return _compare(this, target); + + if (targetStart === undefined) + targetStart = 0; + else + validateOffset(targetStart, 'targetStart'); + + if (targetEnd === undefined) + targetEnd = target.length; + else + validateOffset(targetEnd, 'targetEnd', 0, target.length); + + if (sourceStart === undefined) + sourceStart = 0; + else + validateOffset(sourceStart, 'sourceStart'); + + if (sourceEnd === undefined) + sourceEnd = this.length; + else + validateOffset(sourceEnd, 'sourceEnd', 0, this.length); + + if (sourceStart >= sourceEnd) + return (targetStart >= targetEnd ? 0 : -1); + if (targetStart >= targetEnd) + return 1; + + return compareOffset(this, target, targetStart, sourceStart, targetEnd, + sourceEnd); +}; + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant if val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { + validateBuffer(buffer); + + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = undefined; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + // Coerce to Number. Values like null and [] become 0. + byteOffset = +byteOffset; + // If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer. + if (NumberIsNaN(byteOffset)) { + byteOffset = dir ? 0 : (buffer.length || buffer.byteLength); + } + dir = !!dir; // Cast to bool. + + if (typeof val === 'number') + return indexOfNumber(buffer, val >>> 0, byteOffset, dir); + + let ops; + if (encoding === undefined) + ops = encodingOps.utf8; + else + ops = getEncodingOps(encoding); + + if (typeof val === 'string') { + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + return ops.indexOf(buffer, val, byteOffset, dir); + } + + if (isUint8Array(val)) { + const encodingVal = + (ops === undefined ? encodingsMap.utf8 : ops.encodingVal); + return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir); + } + + throw new ERR_INVALID_ARG_TYPE( + 'value', ['number', 'string', 'Buffer', 'Uint8Array'], val, + ); +} + +Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true); +}; + +Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false); +}; + +Buffer.prototype.includes = function includes(val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1; +}; + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill(value, offset, end, encoding) { + return _fill(this, value, offset, end, encoding); +}; + +function _fill(buf, value, offset, end, encoding) { + if (typeof value === 'string') { + if (offset === undefined || typeof offset === 'string') { + encoding = offset; + offset = 0; + end = buf.length; + } else if (typeof end === 'string') { + encoding = end; + end = buf.length; + } + + const normalizedEncoding = normalizeEncoding(encoding); + if (normalizedEncoding === undefined) { + validateString(encoding, 'encoding'); + throw new ERR_UNKNOWN_ENCODING(encoding); + } + + if (value.length === 0) { + // If value === '' default to zero. + value = 0; + } else if (value.length === 1) { + // Fast path: If `value` fits into a single byte, use that numeric value. + if (normalizedEncoding === 'utf8') { + const code = StringPrototypeCharCodeAt(value, 0); + if (code < 128) { + value = code; + } + } else if (normalizedEncoding === 'latin1') { + value = StringPrototypeCharCodeAt(value, 0); + } + } + } else { + encoding = undefined; + } + + if (offset === undefined) { + offset = 0; + end = buf.length; + } else { + validateOffset(offset, 'offset'); + // Invalid ranges are not set to a default, so can range check early. + if (end === undefined) { + end = buf.length; + } else { + validateOffset(end, 'end', 0, buf.length); + } + if (offset >= end) + return buf; + } + + + if (typeof value === 'number') { + // OOB check + const byteLen = TypedArrayPrototypeGetByteLength(buf); + const fillLength = end - offset; + if (offset > end || fillLength + offset > byteLen) + throw new ERR_BUFFER_OUT_OF_BOUNDS(); + + TypedArrayPrototypeFill(buf, value, offset, end); + } else { + const res = bindingFill(buf, value, offset, end, encoding); + if (res < 0) { + if (res === -1) + throw new ERR_INVALID_ARG_VALUE('value', value); + throw new ERR_BUFFER_OUT_OF_BOUNDS(); + } + } + + return buf; +} + +Buffer.prototype.write = function write(string, offset, length, encoding) { + // Buffer#write(string); + if (offset === undefined) { + return this.utf8Write(string, 0, this.length); + } + // Buffer#write(string, encoding) + if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + + // Buffer#write(string, offset[, length][, encoding]) + } else { + validateOffset(offset, 'offset', 0, this.length); + + const remaining = this.length - offset; + + if (length === undefined) { + length = remaining; + } else if (typeof length === 'string') { + encoding = length; + length = remaining; + } else { + validateOffset(length, 'length', 0, this.length); + if (length > remaining) + length = remaining; + } + } + + if (!encoding || encoding === 'utf8') + return this.utf8Write(string, offset, length); + if (encoding === 'ascii') + return this.asciiWrite(string, offset, length); + + const ops = getEncodingOps(encoding); + if (ops === undefined) + throw new ERR_UNKNOWN_ENCODING(encoding); + return ops.write(this, string, offset, length); +}; + +Buffer.prototype.toJSON = function toJSON() { + if (this.length > 0) { + const data = new Array(this.length); + for (let i = 0; i < this.length; ++i) + data[i] = this[i]; + return { type: 'Buffer', data }; + } + return { type: 'Buffer', data: [] }; +}; + +function adjustOffset(offset, length) { + // Use Math.trunc() to convert offset to an integer value that can be larger + // than an Int32. Hence, don't use offset | 0 or similar techniques. + offset = MathTrunc(offset); + if (offset === 0) { + return 0; + } + if (offset < 0) { + offset += length; + return offset > 0 ? offset : 0; + } + if (offset < length) { + return offset; + } + return NumberIsNaN(offset) ? 0 : length; +} + +Buffer.prototype.subarray = function subarray(start, end) { + const srcLength = this.length; + start = adjustOffset(start, srcLength); + end = end !== undefined ? adjustOffset(end, srcLength) : srcLength; + const newLength = end > start ? end - start : 0; + return new FastBuffer(this.buffer, this.byteOffset + start, newLength); +}; + +Buffer.prototype.slice = function slice(start, end) { + return this.subarray(start, end); +}; + +function swap(b, n, m) { + const i = b[n]; + b[n] = b[m]; + b[m] = i; +} + +Buffer.prototype.swap16 = function swap16() { + // For Buffer.length < 128, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 2 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('16-bits'); + if (len < 128) { + for (let i = 0; i < len; i += 2) + swap(this, i, i + 1); + return this; + } + return _swap16(this); +}; + +Buffer.prototype.swap32 = function swap32() { + // For Buffer.length < 192, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 4 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('32-bits'); + if (len < 192) { + for (let i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; + } + return _swap32(this); +}; + +Buffer.prototype.swap64 = function swap64() { + // For Buffer.length < 192, it's generally faster to + // do the swap in javascript. For larger buffers, + // dropping down to the native code is faster. + const len = this.length; + if (len % 8 !== 0) + throw new ERR_INVALID_BUFFER_SIZE('64-bits'); + if (len < 192) { + for (let i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this; + } + return _swap64(this); +}; + +Buffer.prototype.toLocaleString = Buffer.prototype.toString; + +let transcode; +if (internalBinding('config').hasIntl) { + const { + icuErrName, + transcode: _transcode, + } = internalBinding('icu'); + + // Transcodes the Buffer from one encoding to another, returning a new + // Buffer instance. + transcode = function transcode(source, fromEncoding, toEncoding) { + if (!isUint8Array(source)) { + throw new ERR_INVALID_ARG_TYPE('source', + ['Buffer', 'Uint8Array'], source); + } + if (source.length === 0) return Buffer.alloc(0); + + fromEncoding = normalizeEncoding(fromEncoding) || fromEncoding; + toEncoding = normalizeEncoding(toEncoding) || toEncoding; + const result = _transcode(source, fromEncoding, toEncoding); + if (typeof result !== 'number') + return result; + + const code = icuErrName(result); + const err = genericNodeError( + `Unable to transcode Buffer [${code}]`, + { code: code, errno: result }, + ); + throw err; + }; +} + +function btoa(input) { + // The implementation here has not been performance optimized in any way and + // should not be. + // Refs: https://github.com/nodejs/node/pull/38433#issuecomment-828426932 + if (arguments.length === 0) { + throw new ERR_MISSING_ARGS('input'); + } + const result = _btoa(`${input}`); + if (result === -1) { + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + } + return result; +} + +function atob(input) { + if (arguments.length === 0) { + throw new ERR_MISSING_ARGS('input'); + } + + const result = _atob(`${input}`); + + switch (result) { + case -2: // Invalid character + throw lazyDOMException('Invalid character', 'InvalidCharacterError'); + case -1: // Single character remained + throw lazyDOMException( + 'The string to be decoded is not correctly encoded.', + 'InvalidCharacterError'); + case -3: // Possible overflow + // TODO(@anonrig): Throw correct error in here. + throw lazyDOMException('The input causes overflow.', 'InvalidCharacterError'); + default: + return result; + } +} + +function isUtf8(input) { + if (isTypedArray(input) || isAnyArrayBuffer(input)) { + return bindingIsUtf8(input); + } + + throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input); +} + +function isAscii(input) { + if (isTypedArray(input) || isAnyArrayBuffer(input)) { + return bindingIsAscii(input); + } + + throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input); +} + +module.exports = { + Buffer, + SlowBuffer: deprecate( + SlowBuffer, + 'SlowBuffer() is deprecated. Please use Buffer.allocUnsafeSlow()', + 'DEP0030'), + transcode, + isUtf8, + isAscii, + + // Legacy + kMaxLength, + kStringMaxLength, + btoa, + atob, +}; + +ObjectDefineProperties(module.exports, { + constants: { + __proto__: null, + configurable: false, + enumerable: true, + value: constants, + }, + INSPECT_MAX_BYTES: { + __proto__: null, + configurable: true, + enumerable: true, + get() { return INSPECT_MAX_BYTES; }, + set(val) { + validateNumber(val, 'INSPECT_MAX_BYTES', 0); + INSPECT_MAX_BYTES = val; + }, + }, +}); + +defineLazyProperties( + module.exports, + 'internal/blob', + ['Blob', 'resolveObjectURL'], +); +defineLazyProperties( + module.exports, + 'internal/file', + ['File'], +); \ No newline at end of file diff --git a/.codesandbox/node/dfn.js b/.codesandbox/node/dfn.js new file mode 100644 index 00000000..29b453dc --- /dev/null +++ b/.codesandbox/node/dfn.js @@ -0,0 +1,118 @@ +var dfnMapTarget = -1; +var dfnMapDone = 0; +var dfnMap = {}; +document.addEventListener('DOMContentLoaded', function (event) { + var links = []; + dfnMapTarget = document.links.length; + for (var i = 0; i < dfnMapTarget; i += 1) + links[i] = document.links[i]; + var inc = 100; + for (var i = 0; i < dfnMapTarget; i += inc) { + setTimeout(function (j) { + for (var k = j; k < j+inc && k < dfnMapTarget; k += 1) { + if (links[k].href.indexOf('#') >= 0) { + if (links[k].className != "no-backref" && + links[k].parentNode.className != "no-backref") { + var s = links[k].href.substr(links[k].href.indexOf('#') + 1); + if (!(s in dfnMap)) + dfnMap[s] = []; + dfnMap[s].push(links[k]); + } + } + dfnMapDone += 1; + } + }, 0, i); + } + document.body.className += " dfnEnabled"; +}, false); + +var dfnPanel; +var dfnUniqueId = 0; +var dfnTimeout; +document.addEventListener('click', dfnShow, false); +function dfnShow(event) { + if (dfnTimeout) { + clearTimeout(dfnTimeout); + dfnTimeout = null; + } + if (dfnPanel) { + dfnPanel.parentNode.removeChild(dfnPanel); + dfnPanel = null; + } + if (dfnMapDone == dfnMapTarget) { + var node = event.target; + while (node && (node.nodeType != event.target.ELEMENT_NODE || node.tagName != "DFN")) + node = node.parentNode; + if (node) { + var panel = document.createElement('div'); + panel.className = 'dfnPanel'; + if (node.id) { + var permalinkP = document.createElement('p'); + var permalinkA = document.createElement('a'); + permalinkA.href = '#' + node.id; + permalinkA.textContent = '#' + node.id; + permalinkP.appendChild(permalinkA); + panel.appendChild(permalinkP); + } + var p = document.createElement('p'); + panel.appendChild(p); + if (node.id in dfnMap || node.parentNode.id in dfnMap) { + p.textContent = 'Referenced in:'; + var ul = document.createElement('ul'); + var lastHeader; + var lastLi; + var n; + var sourceLinks = []; + if (node.id in dfnMap) + for (var i = 0; i < dfnMap[node.id].length; i += 1) + sourceLinks.push(dfnMap[node.id][i]); + if (node.parentNode.id in dfnMap) + for (var i = 0; i < dfnMap[node.parentNode.id].length; i += 1) + sourceLinks.push(dfnMap[node.parentNode.id][i]); + for (var i = 0; i < sourceLinks.length; i += 1) { + var link = sourceLinks[i]; + var header = dfnGetCaption(link); + var a = document.createElement('a'); + if (!link.id) + link.id = 'dfnReturnLink-' + dfnUniqueId++; + a.href = '#' + link.id; + if (header != lastHeader) { + lastHeader = header; + n = 1; + var li = document.createElement('li'); + var cloneHeader = header.cloneNode(true); + while (cloneHeader.hasChildNodes()) + if (cloneHeader.firstChild.className == 'section-link') + cloneHeader.removeChild(cloneHeader.firstChild); + else + a.appendChild(cloneHeader.firstChild); + lastLi = li; + li.appendChild(a); + ul.appendChild(li); + } else { + n += 1; + a.appendChild(document.createTextNode('(' + n + ')')); + lastLi.appendChild(document.createTextNode(' ')); + lastLi.appendChild(a); + } + } + panel.appendChild(ul); + } else { + p.textContent = 'No references in this file.'; + } + node.appendChild(panel); + dfnPanel = panel; + } + } else { + dfnTimeout = setTimeout(dfnShow, 250, event); + } +} + +function dfnGetCaption(link) { + var node = link; + while (node && !(node.parentNode.tagName == "DIV" && node.parentNode.className == "section")) + node = node.parentNode; + while (node && (node.nodeType != node.ELEMENT_NODE || !node.tagName.match(/^H[1-6]$/))) + node = node.previousSibling; + return node; +} \ No newline at end of file diff --git a/.codesandbox/node/dgram.js b/.codesandbox/node/dgram.js new file mode 100644 index 00000000..c77ea89c --- /dev/null +++ b/.codesandbox/node/dgram.js @@ -0,0 +1,1111 @@ +'use strict'; + +const { + Array, + ArrayIsArray, + ArrayPrototypePush, + FunctionPrototypeBind, + FunctionPrototypeCall, + ObjectDefineProperty, + ObjectSetPrototypeOf, + ReflectApply, + SymbolAsyncDispose, + SymbolDispose, +} = primordials; + +const { + ErrnoException, + ExceptionWithHostPort, + codes: { + ERR_BUFFER_OUT_OF_BOUNDS, + ERR_INVALID_ARG_TYPE, + ERR_INVALID_FD_TYPE, + ERR_IP_BLOCKED, + ERR_MISSING_ARGS, + ERR_SOCKET_ALREADY_BOUND, + ERR_SOCKET_BAD_BUFFER_SIZE, + ERR_SOCKET_BUFFER_SIZE, + ERR_SOCKET_DGRAM_IS_CONNECTED, + ERR_SOCKET_DGRAM_NOT_CONNECTED, + ERR_SOCKET_DGRAM_NOT_RUNNING, + }, +} = require('internal/errors'); +const { + kStateSymbol, + _createSocketHandle, + newHandle, +} = require('internal/dgram'); +const { isIP } = require('internal/net'); +const { + isInt32, + validateAbortSignal, + validateString, + validateNumber, + validatePort, + validateUint32, +} = require('internal/validators'); +const { Buffer } = require('buffer'); +const { deprecate, guessHandleType, promisify } = require('internal/util'); +const { isArrayBufferView } = require('internal/util/types'); +const EventEmitter = require('events'); +const { addAbortListener } = require('internal/events/abort_listener'); +const { + defaultTriggerAsyncIdScope, + symbols: { async_id_symbol, owner_symbol }, +} = require('internal/async_hooks'); +const { UV_UDP_REUSEADDR } = internalBinding('constants').os; + +const { + constants: { UV_UDP_IPV6ONLY, UV_UDP_REUSEPORT }, + UDP, + SendWrap, +} = internalBinding('udp_wrap'); + +const dc = require('diagnostics_channel'); +const udpSocketChannel = dc.channel('udp.socket'); + +const BIND_STATE_UNBOUND = 0; +const BIND_STATE_BINDING = 1; +const BIND_STATE_BOUND = 2; + +const CONNECT_STATE_DISCONNECTED = 0; +const CONNECT_STATE_CONNECTING = 1; +const CONNECT_STATE_CONNECTED = 2; + +const RECV_BUFFER = true; +const SEND_BUFFER = false; + +// Lazily loaded +let _cluster = null; +function lazyLoadCluster() { + return _cluster ??= require('cluster'); +} +let _blockList = null; +function lazyLoadBlockList() { + return _blockList ??= require('internal/blocklist').BlockList; +} + +function Socket(type, listener) { + FunctionPrototypeCall(EventEmitter, this); + let lookup; + let recvBufferSize; + let sendBufferSize; + let receiveBlockList; + let sendBlockList; + + let options; + if (type !== null && typeof type === 'object') { + options = type; + type = options.type; + lookup = options.lookup; + if (options.recvBufferSize) { + validateUint32(options.recvBufferSize, 'options.recvBufferSize'); + } + if (options.sendBufferSize) { + validateUint32(options.sendBufferSize, 'options.sendBufferSize'); + } + recvBufferSize = options.recvBufferSize; + sendBufferSize = options.sendBufferSize; + if (options.receiveBlockList) { + if (!lazyLoadBlockList().isBlockList(options.receiveBlockList)) { + throw new ERR_INVALID_ARG_TYPE('options.receiveBlockList', 'net.BlockList', options.receiveBlockList); + } + receiveBlockList = options.receiveBlockList; + } + if (options.sendBlockList) { + if (!lazyLoadBlockList().isBlockList(options.sendBlockList)) { + throw new ERR_INVALID_ARG_TYPE('options.sendBlockList', 'net.BlockList', options.sendBlockList); + } + sendBlockList = options.sendBlockList; + } + } + + const handle = newHandle(type, lookup); + handle[owner_symbol] = this; + + this[async_id_symbol] = handle.getAsyncId(); + this.type = type; + + if (typeof listener === 'function') + this.on('message', listener); + + this[kStateSymbol] = { + handle, + receiving: false, + bindState: BIND_STATE_UNBOUND, + connectState: CONNECT_STATE_DISCONNECTED, + queue: undefined, + reuseAddr: options?.reuseAddr, // Use UV_UDP_REUSEADDR if true. + reusePort: options?.reusePort, + ipv6Only: options?.ipv6Only, + recvBufferSize, + sendBufferSize, + receiveBlockList, + sendBlockList, + }; + + if (options?.signal !== undefined) { + const { signal } = options; + validateAbortSignal(signal, 'options.signal'); + const onAborted = () => { + if (this[kStateSymbol].handle) this.close(); + }; + if (signal.aborted) { + onAborted(); + } else { + const disposable = addAbortListener(signal, onAborted); + this.once('close', disposable[SymbolDispose]); + } + } + if (udpSocketChannel.hasSubscribers) { + udpSocketChannel.publish({ + socket: this, + }); + } +} +ObjectSetPrototypeOf(Socket.prototype, EventEmitter.prototype); +ObjectSetPrototypeOf(Socket, EventEmitter); + + +function createSocket(type, listener) { + return new Socket(type, listener); +} + + +function startListening(socket) { + const state = socket[kStateSymbol]; + + state.handle.onmessage = onMessage; + state.handle.onerror = onError; + state.handle.recvStart(); + state.receiving = true; + state.bindState = BIND_STATE_BOUND; + + if (state.recvBufferSize) + bufferSize(socket, state.recvBufferSize, RECV_BUFFER); + + if (state.sendBufferSize) + bufferSize(socket, state.sendBufferSize, SEND_BUFFER); + + socket.emit('listening'); +} + +function replaceHandle(self, newHandle) { + const state = self[kStateSymbol]; + const oldHandle = state.handle; + // Sync the old handle state to new handle + if (!oldHandle.hasRef() && typeof newHandle.unref === 'function') { + newHandle.unref(); + } + // Set up the handle that we got from primary. + newHandle.lookup = oldHandle.lookup; + newHandle.bind = oldHandle.bind; + newHandle.send = oldHandle.send; + newHandle[owner_symbol] = self; + + // Replace the existing handle by the handle we got from primary. + oldHandle.close(); + state.handle = newHandle; +} + +function bufferSize(self, size, buffer) { + if (size >>> 0 !== size) + throw new ERR_SOCKET_BAD_BUFFER_SIZE(); + + const ctx = {}; + const ret = self[kStateSymbol].handle.bufferSize(size, buffer, ctx); + if (ret === undefined) { + throw new ERR_SOCKET_BUFFER_SIZE(ctx); + } + return ret; +} + +// Query primary process to get the server handle and utilize it. +function bindServerHandle(self, options, errCb) { + const cluster = lazyLoadCluster(); + + const state = self[kStateSymbol]; + cluster._getServer(self, options, (err, handle) => { + if (err) { + // Do not call callback if socket is closed + if (state.handle) { + errCb(err); + } + return; + } + + if (!state.handle) { + // Handle has been closed in the mean time. + return handle.close(); + } + + replaceHandle(self, handle); + startListening(self); + }); +} + +Socket.prototype.bind = function(port_, address_ /* , callback */) { + let port = port_; + + healthCheck(this); + const state = this[kStateSymbol]; + + if (state.bindState !== BIND_STATE_UNBOUND) + throw new ERR_SOCKET_ALREADY_BOUND(); + + state.bindState = BIND_STATE_BINDING; + + const cb = arguments.length && arguments[arguments.length - 1]; + if (typeof cb === 'function') { + function removeListeners() { + this.removeListener('error', removeListeners); + this.removeListener('listening', onListening); + } + + function onListening() { + FunctionPrototypeCall(removeListeners, this); + FunctionPrototypeCall(cb, this); + } + + this.on('error', removeListeners); + this.on('listening', onListening); + } + + if (port !== null && + typeof port === 'object' && + typeof port.recvStart === 'function') { + replaceHandle(this, port); + startListening(this); + return this; + } + + // Open an existing fd instead of creating a new one. + if (port !== null && typeof port === 'object' && + isInt32(port.fd) && port.fd > 0) { + const fd = port.fd; + const exclusive = !!port.exclusive; + const state = this[kStateSymbol]; + + const cluster = lazyLoadCluster(); + + if (cluster.isWorker && !exclusive) { + bindServerHandle(this, { + address: null, + port: null, + addressType: this.type, + fd, + flags: null, + }, (err) => { + // Callback to handle error. + const ex = new ErrnoException(err, 'open'); + state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); + }); + return this; + } + + const type = guessHandleType(fd); + if (type !== 'UDP') + throw new ERR_INVALID_FD_TYPE(type); + const err = state.handle.open(fd); + + if (err) + throw new ErrnoException(err, 'open'); + + startListening(this); + return this; + } + + let address; + let exclusive; + + if (port !== null && typeof port === 'object') { + address = port.address || ''; + exclusive = !!port.exclusive; + port = port.port; + } else { + address = typeof address_ === 'function' ? '' : address_; + exclusive = false; + } + + // Defaulting address for bind to all interfaces + if (!address) { + if (this.type === 'udp4') + address = '0.0.0.0'; + else + address = '::'; + } + + // Resolve address first + state.handle.lookup(address, (err, ip) => { + if (!state.handle) + return; // Handle has been closed in the mean time + + if (err) { + state.bindState = BIND_STATE_UNBOUND; + this.emit('error', err); + return; + } + + const cluster = lazyLoadCluster(); + + let flags = 0; + if (state.reuseAddr) + flags |= UV_UDP_REUSEADDR; + if (state.ipv6Only) + flags |= UV_UDP_IPV6ONLY; + if (state.reusePort) { + exclusive = true; + flags |= UV_UDP_REUSEPORT; + } + + if (cluster.isWorker && !exclusive) { + bindServerHandle(this, { + address: ip, + port: port, + addressType: this.type, + fd: -1, + flags: flags, + }, (err) => { + // Callback to handle error. + const ex = new ExceptionWithHostPort(err, 'bind', ip, port); + state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); + }); + } else { + const err = state.handle.bind(ip, port || 0, flags); + if (err) { + const ex = new ExceptionWithHostPort(err, 'bind', ip, port); + state.bindState = BIND_STATE_UNBOUND; + this.emit('error', ex); + // Todo: close? + return; + } + + startListening(this); + } + }); + + return this; +}; + +Socket.prototype.connect = function(port, address, callback) { + port = validatePort(port, 'Port', false); + if (typeof address === 'function') { + callback = address; + address = ''; + } else if (address === undefined) { + address = ''; + } + + validateString(address, 'address'); + + const state = this[kStateSymbol]; + + if (state.connectState !== CONNECT_STATE_DISCONNECTED) + throw new ERR_SOCKET_DGRAM_IS_CONNECTED(); + + state.connectState = CONNECT_STATE_CONNECTING; + if (state.bindState === BIND_STATE_UNBOUND) + this.bind({ port: 0, exclusive: true }, null); + + if (state.bindState !== BIND_STATE_BOUND) { + enqueue(this, FunctionPrototypeBind(_connect, this, + port, address, callback)); + return; + } + + ReflectApply(_connect, this, [port, address, callback]); +}; + + +function _connect(port, address, callback) { + const state = this[kStateSymbol]; + if (callback) + this.once('connect', callback); + + const afterDns = (ex, ip) => { + defaultTriggerAsyncIdScope( + this[async_id_symbol], + doConnect, + ex, this, ip, address, port, callback, + ); + }; + + state.handle.lookup(address, afterDns); +} + + +function doConnect(ex, self, ip, address, port, callback) { + const state = self[kStateSymbol]; + if (!state.handle) + return; + if (!ex && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) { + ex = new ERR_IP_BLOCKED(ip); + } + if (!ex) { + const err = state.handle.connect(ip, port); + if (err) { + ex = new ExceptionWithHostPort(err, 'connect', address, port); + } + } + + if (ex) { + state.connectState = CONNECT_STATE_DISCONNECTED; + return process.nextTick(() => { + if (callback) { + self.removeListener('connect', callback); + callback(ex); + } else { + self.emit('error', ex); + } + }); + } + + state.connectState = CONNECT_STATE_CONNECTED; + process.nextTick(() => self.emit('connect')); +} + + +Socket.prototype.disconnect = function() { + const state = this[kStateSymbol]; + if (state.connectState !== CONNECT_STATE_CONNECTED) + throw new ERR_SOCKET_DGRAM_NOT_CONNECTED(); + + const err = state.handle.disconnect(); + if (err) + throw new ErrnoException(err, 'connect'); + else + state.connectState = CONNECT_STATE_DISCONNECTED; +}; + + +// Thin wrapper around `send`, here for compatibility with dgram_legacy.js +Socket.prototype.sendto = function(buffer, + offset, + length, + port, + address, + callback) { + validateNumber(offset, 'offset'); + validateNumber(length, 'length'); + validateNumber(port, 'port'); + validateString(address, 'address'); + + this.send(buffer, offset, length, port, address, callback); +}; + + +function sliceBuffer(buffer, offset, length) { + if (typeof buffer === 'string') { + buffer = Buffer.from(buffer); + } else if (!isArrayBufferView(buffer)) { + throw new ERR_INVALID_ARG_TYPE('buffer', + ['Buffer', + 'TypedArray', + 'DataView', + 'string'], + buffer); + } + + offset = offset >>> 0; + length = length >>> 0; + if (offset > buffer.byteLength) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + } + + if (offset + length > buffer.byteLength) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } + + return Buffer.from(buffer.buffer, buffer.byteOffset + offset, length); +} + + +function fixBufferList(list) { + const newlist = new Array(list.length); + + for (let i = 0, l = list.length; i < l; i++) { + const buf = list[i]; + if (typeof buf === 'string') + newlist[i] = Buffer.from(buf); + else if (Buffer.isBuffer(buf)) + newlist[i] = buf; + else if (!isArrayBufferView(buf)) + return null; + else + newlist[i] = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength); + } + + return newlist; +} + + +function enqueue(self, toEnqueue) { + const state = self[kStateSymbol]; + + // If the send queue hasn't been initialized yet, do it, and install an + // event handler that flushes the send queue after binding is done. + if (state.queue === undefined) { + state.queue = []; + self.once(EventEmitter.errorMonitor, onListenError); + self.once('listening', onListenSuccess); + } + ArrayPrototypePush(state.queue, toEnqueue); +} + + +function onListenSuccess() { + this.removeListener(EventEmitter.errorMonitor, onListenError); + FunctionPrototypeCall(clearQueue, this); +} + + +function onListenError(err) { + this.removeListener('listening', onListenSuccess); + this[kStateSymbol].queue = undefined; +} + + +function clearQueue() { + const state = this[kStateSymbol]; + const queue = state.queue; + state.queue = undefined; + + // Flush the send queue. + for (const queueEntry of queue) + queueEntry(); +} + +// valid combinations +// For connectionless sockets +// send(buffer, offset, length, port, address, callback) +// send(buffer, offset, length, port, address) +// send(buffer, offset, length, port, callback) +// send(buffer, offset, length, port) +// send(bufferOrList, port, address, callback) +// send(bufferOrList, port, address) +// send(bufferOrList, port, callback) +// send(bufferOrList, port) +// For connected sockets +// send(buffer, offset, length, callback) +// send(buffer, offset, length) +// send(bufferOrList, callback) +// send(bufferOrList) +Socket.prototype.send = function(buffer, + offset, + length, + port, + address, + callback) { + + let list; + const state = this[kStateSymbol]; + const connected = state.connectState === CONNECT_STATE_CONNECTED; + if (!connected) { + if (address || (port && typeof port !== 'function')) { + buffer = sliceBuffer(buffer, offset, length); + } else { + callback = port; + port = offset; + address = length; + } + } else { + if (typeof length === 'number') { + buffer = sliceBuffer(buffer, offset, length); + if (typeof port === 'function') { + callback = port; + port = null; + } + } else { + callback = offset; + } + + if (port || address) + throw new ERR_SOCKET_DGRAM_IS_CONNECTED(); + } + + if (!ArrayIsArray(buffer)) { + if (typeof buffer === 'string') { + list = [ Buffer.from(buffer) ]; + } else if (!isArrayBufferView(buffer)) { + throw new ERR_INVALID_ARG_TYPE('buffer', + ['Buffer', + 'TypedArray', + 'DataView', + 'string'], + buffer); + } else { + list = [ buffer ]; + } + } else if (!(list = fixBufferList(buffer))) { + throw new ERR_INVALID_ARG_TYPE('buffer list arguments', + ['Buffer', + 'TypedArray', + 'DataView', + 'string'], + buffer); + } + + if (!connected) + port = validatePort(port, 'Port', false); + + // Normalize callback so it's either a function or undefined but not anything + // else. + if (typeof callback !== 'function') + callback = undefined; + + if (typeof address === 'function') { + callback = address; + address = undefined; + } else if (address != null) { + validateString(address, 'address'); + } + + healthCheck(this); + + if (state.bindState === BIND_STATE_UNBOUND) + this.bind({ port: 0, exclusive: true }, null); + + if (list.length === 0) + ArrayPrototypePush(list, Buffer.alloc(0)); + + // If the socket hasn't been bound yet, push the outbound packet onto the + // send queue and send after binding is complete. + if (state.bindState !== BIND_STATE_BOUND) { + enqueue(this, FunctionPrototypeBind(this.send, this, + list, port, address, callback)); + return; + } + + const afterDns = (ex, ip) => { + defaultTriggerAsyncIdScope( + this[async_id_symbol], + doSend, + ex, this, ip, list, address, port, callback, + ); + }; + + if (!connected) { + state.handle.lookup(address, afterDns); + } else { + afterDns(null, null); + } +}; + +function doSend(ex, self, ip, list, address, port, callback) { + const state = self[kStateSymbol]; + + if (ex) { + if (typeof callback === 'function') { + process.nextTick(callback, ex); + return; + } + + process.nextTick(() => self.emit('error', ex)); + return; + } else if (!state.handle) { + return; + } + + if (ip && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) { + if (callback) { + process.nextTick(callback, new ERR_IP_BLOCKED(ip)); + } + return; + } + + const req = new SendWrap(); + req.list = list; // Keep reference alive. + req.address = address; + req.port = port; + if (callback) { + req.callback = callback; + req.oncomplete = afterSend; + } + + let err; + if (port) + err = state.handle.send(req, list, list.length, port, ip, !!callback); + else + err = state.handle.send(req, list, list.length, !!callback); + + if (err >= 1) { + // Synchronous finish. The return code is msg_length + 1 so that we can + // distinguish between synchronous success and asynchronous success. + if (callback) + process.nextTick(callback, null, err - 1); + return; + } + + if (err && callback) { + // Don't emit as error, dgram_legacy.js compatibility + const ex = new ExceptionWithHostPort(err, 'send', address, port); + process.nextTick(callback, ex); + } +} + +function afterSend(err, sent) { + if (err) { + err = new ExceptionWithHostPort(err, 'send', this.address, this.port); + } else { + err = null; + } + + this.callback(err, sent); +} + +Socket.prototype.close = function(callback) { + const state = this[kStateSymbol]; + const queue = state.queue; + + if (typeof callback === 'function') + this.on('close', callback); + + if (queue !== undefined) { + ArrayPrototypePush(queue, FunctionPrototypeBind(this.close, this)); + return this; + } + + healthCheck(this); + stopReceiving(this); + state.handle.close(); + state.handle = null; + defaultTriggerAsyncIdScope(this[async_id_symbol], + process.nextTick, + socketCloseNT, + this); + + return this; +}; + +Socket.prototype[SymbolAsyncDispose] = async function() { + if (!this[kStateSymbol].handle) { + return; + } + await FunctionPrototypeCall(promisify(this.close), this); +}; + + +function socketCloseNT(self) { + self.emit('close'); +} + + +Socket.prototype.address = function() { + healthCheck(this); + + const out = {}; + const err = this[kStateSymbol].handle.getsockname(out); + if (err) { + throw new ErrnoException(err, 'getsockname'); + } + + return out; +}; + +Socket.prototype.remoteAddress = function() { + healthCheck(this); + + const state = this[kStateSymbol]; + if (state.connectState !== CONNECT_STATE_CONNECTED) + throw new ERR_SOCKET_DGRAM_NOT_CONNECTED(); + + const out = {}; + const err = state.handle.getpeername(out); + if (err) + throw new ErrnoException(err, 'getpeername'); + + return out; +}; + + +Socket.prototype.setBroadcast = function(arg) { + const err = this[kStateSymbol].handle.setBroadcast(arg ? 1 : 0); + if (err) { + throw new ErrnoException(err, 'setBroadcast'); + } +}; + + +Socket.prototype.setTTL = function(ttl) { + validateNumber(ttl, 'ttl'); + + const err = this[kStateSymbol].handle.setTTL(ttl); + if (err) { + throw new ErrnoException(err, 'setTTL'); + } + + return ttl; +}; + + +Socket.prototype.setMulticastTTL = function(ttl) { + validateNumber(ttl, 'ttl'); + + const err = this[kStateSymbol].handle.setMulticastTTL(ttl); + if (err) { + throw new ErrnoException(err, 'setMulticastTTL'); + } + + return ttl; +}; + + +Socket.prototype.setMulticastLoopback = function(arg) { + const err = this[kStateSymbol].handle.setMulticastLoopback(arg ? 1 : 0); + if (err) { + throw new ErrnoException(err, 'setMulticastLoopback'); + } + + return arg; // 0.4 compatibility +}; + + +Socket.prototype.setMulticastInterface = function(interfaceAddress) { + healthCheck(this); + validateString(interfaceAddress, 'interfaceAddress'); + + const err = this[kStateSymbol].handle.setMulticastInterface(interfaceAddress); + if (err) { + throw new ErrnoException(err, 'setMulticastInterface'); + } +}; + +Socket.prototype.addMembership = function(multicastAddress, + interfaceAddress) { + healthCheck(this); + + if (!multicastAddress) { + throw new ERR_MISSING_ARGS('multicastAddress'); + } + + const { handle } = this[kStateSymbol]; + const err = handle.addMembership(multicastAddress, interfaceAddress); + if (err) { + throw new ErrnoException(err, 'addMembership'); + } +}; + + +Socket.prototype.dropMembership = function(multicastAddress, + interfaceAddress) { + healthCheck(this); + + if (!multicastAddress) { + throw new ERR_MISSING_ARGS('multicastAddress'); + } + + const { handle } = this[kStateSymbol]; + const err = handle.dropMembership(multicastAddress, interfaceAddress); + if (err) { + throw new ErrnoException(err, 'dropMembership'); + } +}; + +Socket.prototype.addSourceSpecificMembership = function(sourceAddress, + groupAddress, + interfaceAddress) { + healthCheck(this); + + validateString(sourceAddress, 'sourceAddress'); + validateString(groupAddress, 'groupAddress'); + + const err = + this[kStateSymbol].handle.addSourceSpecificMembership(sourceAddress, + groupAddress, + interfaceAddress); + if (err) { + throw new ErrnoException(err, 'addSourceSpecificMembership'); + } +}; + + +Socket.prototype.dropSourceSpecificMembership = function(sourceAddress, + groupAddress, + interfaceAddress) { + healthCheck(this); + + validateString(sourceAddress, 'sourceAddress'); + validateString(groupAddress, 'groupAddress'); + + const err = + this[kStateSymbol].handle.dropSourceSpecificMembership(sourceAddress, + groupAddress, + interfaceAddress); + if (err) { + throw new ErrnoException(err, 'dropSourceSpecificMembership'); + } +}; + + +function healthCheck(socket) { + if (!socket[kStateSymbol].handle) { + // Error message from dgram_legacy.js. + throw new ERR_SOCKET_DGRAM_NOT_RUNNING(); + } +} + + +function stopReceiving(socket) { + const state = socket[kStateSymbol]; + + if (!state.receiving) + return; + + state.handle.recvStop(); + state.receiving = false; +} + + +function onMessage(nread, handle, buf, rinfo) { + const self = handle[owner_symbol]; + if (nread < 0) { + return self.emit('error', new ErrnoException(nread, 'recvmsg')); + } + if (self[kStateSymbol]?.receiveBlockList?.check(rinfo.address, + rinfo.family?.toLocaleLowerCase())) { + return; + } + rinfo.size = buf.length; // compatibility + self.emit('message', buf, rinfo); +} + + +function onError(nread, handle, error) { + const self = handle[owner_symbol]; + return self.emit('error', error); +} + + +Socket.prototype.ref = function() { + const handle = this[kStateSymbol].handle; + + if (handle) + handle.ref(); + + return this; +}; + + +Socket.prototype.unref = function() { + const handle = this[kStateSymbol].handle; + + if (handle) + handle.unref(); + + return this; +}; + + +Socket.prototype.setRecvBufferSize = function(size) { + bufferSize(this, size, RECV_BUFFER); +}; + + +Socket.prototype.setSendBufferSize = function(size) { + bufferSize(this, size, SEND_BUFFER); +}; + + +Socket.prototype.getRecvBufferSize = function() { + return bufferSize(this, 0, RECV_BUFFER); +}; + + +Socket.prototype.getSendBufferSize = function() { + return bufferSize(this, 0, SEND_BUFFER); +}; + +Socket.prototype.getSendQueueSize = function() { + return this[kStateSymbol].handle.getSendQueueSize(); +}; + +Socket.prototype.getSendQueueCount = function() { + return this[kStateSymbol].handle.getSendQueueCount(); +}; + +// Deprecated private APIs. +ObjectDefineProperty(Socket.prototype, '_handle', { + __proto__: null, + get: deprecate(function() { + return this[kStateSymbol].handle; + }, 'Socket.prototype._handle is deprecated', 'DEP0112'), + set: deprecate(function(val) { + this[kStateSymbol].handle = val; + }, 'Socket.prototype._handle is deprecated', 'DEP0112'), +}); + + +ObjectDefineProperty(Socket.prototype, '_receiving', { + __proto__: null, + get: deprecate(function() { + return this[kStateSymbol].receiving; + }, 'Socket.prototype._receiving is deprecated', 'DEP0112'), + set: deprecate(function(val) { + this[kStateSymbol].receiving = val; + }, 'Socket.prototype._receiving is deprecated', 'DEP0112'), +}); + + +ObjectDefineProperty(Socket.prototype, '_bindState', { + __proto__: null, + get: deprecate(function() { + return this[kStateSymbol].bindState; + }, 'Socket.prototype._bindState is deprecated', 'DEP0112'), + set: deprecate(function(val) { + this[kStateSymbol].bindState = val; + }, 'Socket.prototype._bindState is deprecated', 'DEP0112'), +}); + + +ObjectDefineProperty(Socket.prototype, '_queue', { + __proto__: null, + get: deprecate(function() { + return this[kStateSymbol].queue; + }, 'Socket.prototype._queue is deprecated', 'DEP0112'), + set: deprecate(function(val) { + this[kStateSymbol].queue = val; + }, 'Socket.prototype._queue is deprecated', 'DEP0112'), +}); + + +ObjectDefineProperty(Socket.prototype, '_reuseAddr', { + __proto__: null, + get: deprecate(function() { + return this[kStateSymbol].reuseAddr; + }, 'Socket.prototype._reuseAddr is deprecated', 'DEP0112'), + set: deprecate(function(val) { + this[kStateSymbol].reuseAddr = val; + }, 'Socket.prototype._reuseAddr is deprecated', 'DEP0112'), +}); + + +Socket.prototype._healthCheck = deprecate(function() { + healthCheck(this); +}, 'Socket.prototype._healthCheck() is deprecated', 'DEP0112'); + + +Socket.prototype._stopReceiving = deprecate(function() { + stopReceiving(this); +}, 'Socket.prototype._stopReceiving() is deprecated', 'DEP0112'); + + +// Legacy alias on the C++ wrapper object. This is not public API, so we may +// want to runtime-deprecate it at some point. There's no hurry, though. +ObjectDefineProperty(UDP.prototype, 'owner', { + __proto__: null, + get() { return this[owner_symbol]; }, + set(v) { return this[owner_symbol] = v; }, +}); + + +module.exports = { + _createSocketHandle: deprecate( + _createSocketHandle, + 'dgram._createSocketHandle() is deprecated', + 'DEP0112', + ), + createSocket, + Socket, +}; \ No newline at end of file diff --git a/.codesandbox/node/hello-world.js b/.codesandbox/node/hello-world.js new file mode 100644 index 00000000..85722910 --- /dev/null +++ b/.codesandbox/node/hello-world.js @@ -0,0 +1,14 @@ +const http = require('node:http'); + +const hostname = '127.0.0.1'; +const port = 3000; + +const server = http.createServer((req, res) => { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello, World!\n'); +}); + +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); \ No newline at end of file diff --git a/.codesandbox/node/https.js b/.codesandbox/node/https.js new file mode 100644 index 00000000..05fb02fe --- /dev/null +++ b/.codesandbox/node/https.js @@ -0,0 +1,660 @@ +'use strict'; + +const { + ArrayPrototypeIndexOf, + ArrayPrototypePush, + ArrayPrototypeShift, + ArrayPrototypeSplice, + ArrayPrototypeUnshift, + FunctionPrototypeCall, + JSONStringify, + NumberParseInt, + ObjectAssign, + ObjectSetPrototypeOf, + ReflectApply, + ReflectConstruct, + SymbolAsyncDispose, +} = primordials; + +const { + assertCrypto, + kEmptyObject, + promisify, + once, +} = require('internal/util'); +const { ERR_PROXY_TUNNEL } = require('internal/errors').codes; +assertCrypto(); + +const tls = require('tls'); +const { + kProxyConfig, + checkShouldUseProxy, + filterEnvForProxies, + kWaitForProxyTunnel, +} = require('internal/http'); +const { Agent: HttpAgent } = require('_http_agent'); +const { + httpServerPreClose, + Server: HttpServer, + setupConnectionsTracking, + storeHTTPOptions, + _connectionListener, +} = require('_http_server'); +const { ClientRequest } = require('_http_client'); +let debug = require('internal/util/debuglog').debuglog('https', (fn) => { + debug = fn; +}); +const net = require('net'); +const { URL, urlToHttpOptions, isURL } = require('internal/url'); +const { validateObject } = require('internal/validators'); +const { isIP } = require('internal/net'); +const assert = require('internal/assert'); +const { getOptionValue } = require('internal/options'); + +function Server(opts, requestListener) { + if (!(this instanceof Server)) return new Server(opts, requestListener); + + let ALPNProtocols = ['http/1.1']; + if (typeof opts === 'function') { + requestListener = opts; + opts = kEmptyObject; + } else if (opts == null) { + opts = kEmptyObject; + } else { + validateObject(opts, 'options'); + // Only one of ALPNProtocols and ALPNCallback can be set, so make sure we + // only set a default ALPNProtocols if the caller has not set either of them + if (opts.ALPNProtocols || opts.ALPNCallback) + ALPNProtocols = undefined; + } + + FunctionPrototypeCall(storeHTTPOptions, this, opts); + FunctionPrototypeCall(tls.Server, this, + { + noDelay: true, + ALPNProtocols, + ...opts, + }, + _connectionListener); + + this.httpAllowHalfOpen = false; + + if (requestListener) { + this.addListener('request', requestListener); + } + + this.addListener('tlsClientError', function addListener(err, conn) { + if (!this.emit('clientError', err, conn)) + conn.destroy(err); + }); + + this.timeout = 0; + this.maxHeadersCount = null; + this.on('listening', setupConnectionsTracking); +} + +ObjectSetPrototypeOf(Server.prototype, tls.Server.prototype); +ObjectSetPrototypeOf(Server, tls.Server); + +Server.prototype.closeAllConnections = HttpServer.prototype.closeAllConnections; + +Server.prototype.closeIdleConnections = HttpServer.prototype.closeIdleConnections; + +Server.prototype.setTimeout = HttpServer.prototype.setTimeout; + +Server.prototype.close = function close() { + httpServerPreClose(this); + ReflectApply(tls.Server.prototype.close, this, arguments); + return this; +}; + +Server.prototype[SymbolAsyncDispose] = async function() { + await FunctionPrototypeCall(promisify(this.close), this); +}; + +/** + * Creates a new `https.Server` instance. + * @param {{ + * IncomingMessage?: IncomingMessage; + * ServerResponse?: ServerResponse; + * insecureHTTPParser?: boolean; + * maxHeaderSize?: number; + * }} [opts] + * @param {Function} [requestListener] + * @returns {Server} + */ +function createServer(opts, requestListener) { + return new Server(opts, requestListener); +} + +// When proxying a HTTPS request, the following needs to be done: +// https://datatracker.ietf.org/doc/html/rfc9110#CONNECT +// 1. Send a CONNECT request to the proxy server. +// 2. Wait for 200 connection established response to establish the tunnel. +// 3. Perform TLS handshake with the endpoint over the socket. +// 4. Tunnel the request using the established connection. +// +// This function computes the tunnel configuration for HTTPS requests. +// The handling of the tunnel connection is done in createConnection. +function getTunnelConfigForProxiedHttps(agent, reqOptions) { + if (!agent[kProxyConfig]) { + return null; + } + if ((reqOptions.protocol || agent.protocol) !== 'https:') { + return null; + } + const shouldUseProxy = checkShouldUseProxy(agent[kProxyConfig], reqOptions); + debug(`getTunnelConfigForProxiedHttps should use proxy for ${reqOptions.host}:${reqOptions.port}:`, shouldUseProxy); + if (!shouldUseProxy) { + return null; + } + const { auth, href } = agent[kProxyConfig]; + // The request is a HTTPS request, assemble the payload for establishing the tunnel. + const ipType = isIP(reqOptions.host); + // The request target must put IPv6 address in square brackets. + // Here reqOptions is already processed by urlToHttpOptions so we'll add them back if necessary. + // See https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2 + const requestHost = ipType === 6 ? `[${reqOptions.host}]` : reqOptions.host; + const requestPort = reqOptions.port || agent.defaultPort; + const endpoint = `${requestHost}:${requestPort}`; + // The ClientRequest constructor should already have validated the host and the port. + // When the request options come from a string invalid characters would be stripped away, + // when it's an object ERR_INVALID_CHAR would be thrown. Here we just assert in case + // agent.createConnection() is called with invalid options. + assert(!endpoint.includes('\r')); + assert(!endpoint.includes('\n')); + + let payload = `CONNECT ${endpoint} HTTP/1.1\r\n`; + // The parseProxyConfigFromEnv() method should have already validated the authorization header + // value. + if (auth) { + payload += `proxy-authorization: ${auth}\r\n`; + } + if (agent.keepAlive || agent.maxSockets !== Infinity) { + payload += 'proxy-connection: keep-alive\r\n'; + } + payload += `host: ${endpoint}`; + payload += '\r\n\r\n'; + + const result = { + __proto__: null, + proxyTunnelPayload: payload, + requestOptions: { // Options used for the request sent after the tunnel is established. + __proto__: null, + servername: reqOptions.servername || ipType ? undefined : reqOptions.host, + ...reqOptions, + }, + }; + debug(`updated request for HTTPS proxy ${href} with`, result); + return result; +}; + +function establishTunnel(agent, socket, options, tunnelConfig, afterSocket) { + const { proxyTunnelPayload } = tunnelConfig; + // By default, the socket is in paused mode. Read to look for the 200 + // connection established response. + function read() { + let chunk; + while ((chunk = socket.read()) !== null) { + if (onProxyData(chunk) !== -1) { + break; + } + } + socket.on('readable', read); + } + + function cleanup() { + socket.removeListener('end', onProxyEnd); + socket.removeListener('error', onProxyError); + socket.removeListener('readable', read); + socket.setTimeout(0); // Clear the timeout for the tunnel establishment. + } + + function onProxyError(err) { + debug('onProxyError', err); + cleanup(); + afterSocket(err, socket); + } + + // Read the headers from the chunks and check for the status code. If it fails we + // clean up the socket and return an error. Otherwise we establish the tunnel. + let buffer = ''; + function onProxyData(chunk) { + const str = chunk.toString(); + debug('onProxyData', str); + buffer += str; + const headerEndIndex = buffer.indexOf('\r\n\r\n'); + if (headerEndIndex === -1) return headerEndIndex; + const statusLine = buffer.substring(0, buffer.indexOf('\r\n')); + const statusCode = statusLine.split(' ')[1]; + if (statusCode !== '200') { + debug(`onProxyData receives ${statusCode}, cleaning up`); + cleanup(); + const targetHost = proxyTunnelPayload.split('\r')[0].split(' ')[1]; + const message = `Failed to establish tunnel to ${targetHost} via ${agent[kProxyConfig].href}: ${statusLine}`; + const err = new ERR_PROXY_TUNNEL(message); + err.statusCode = NumberParseInt(statusCode); + afterSocket(err, socket); + } else { + // https://datatracker.ietf.org/doc/html/rfc9110#CONNECT + // RFC 9110 says that it can be 2xx but in the real world, proxy clients generally only + // accepts 200. + // Proxy servers are not supposed to send anything after the headers - the payload must be + // be empty. So after this point we will proceed with the tunnel e.g. starting TLS handshake. + debug('onProxyData receives 200, establishing tunnel'); + cleanup(); + + // Reuse the tunneled socket to perform the TLS handshake with the endpoint, + // then send the request. + const { requestOptions } = tunnelConfig; + tunnelConfig.requestOptions = null; + requestOptions.socket = socket; + let tunneldSocket; + const onTLSHandshakeError = (err) => { + debug('Propagate error event from tunneled socket to tunnel socket'); + afterSocket(err, tunneldSocket); + }; + tunneldSocket = tls.connect(requestOptions, () => { + debug('TLS handshake over tunnel succeeded'); + tunneldSocket.removeListener('error', onTLSHandshakeError); + afterSocket(null, tunneldSocket); + }); + tunneldSocket.on('free', () => { + debug('Propagate free event from tunneled socket to tunnel socket'); + socket.emit('free'); + }); + tunneldSocket.on('error', onTLSHandshakeError); + } + return headerEndIndex; + } + + function onProxyEnd() { + cleanup(); + const err = new ERR_PROXY_TUNNEL('Connection to establish proxy tunnel ended unexpectedly'); + afterSocket(err, socket); + } + + const proxyTunnelTimeout = tunnelConfig.requestOptions.timeout; + debug('proxyTunnelTimeout', proxyTunnelTimeout, options.timeout); + // It may be worth a separate timeout error/event. + // But it also makes sense to treat the tunnel establishment timeout as + // a normal timeout for the request. + function onProxyTimeout() { + debug('onProxyTimeout', proxyTunnelTimeout); + cleanup(); + const err = new ERR_PROXY_TUNNEL(`Connection to establish proxy tunnel timed out after ${proxyTunnelTimeout}ms`); + err.proxyTunnelTimeout = proxyTunnelTimeout; + afterSocket(err, socket); + } + + if (proxyTunnelTimeout && proxyTunnelTimeout > 0) { + debug('proxy tunnel setTimeout', proxyTunnelTimeout); + socket.setTimeout(proxyTunnelTimeout, onProxyTimeout); + } + + socket.on('error', onProxyError); + socket.on('end', onProxyEnd); + socket.write(proxyTunnelPayload); + + read(); +} + +// HTTPS agents. +// See ProxyConfig in internal/http.js for how the connection should be handled +// when the agent is configured to use a proxy server. +function createConnection(...args) { + // XXX: This signature (port, host, options) is different from all the other + // createConnection() methods. + let options, cb; + if (args[0] !== null && typeof args[0] === 'object') { + options = args[0]; + } else if (args[1] !== null && typeof args[1] === 'object') { + options = { ...args[1] }; + } else if (args[2] === null || typeof args[2] !== 'object') { + options = {}; + } else { + options = { ...args[2] }; + } + if (typeof args[0] === 'number') { + options.port = args[0]; + } + if (typeof args[1] === 'string') { + options.host = args[1]; + } + if (typeof args[args.length - 1] === 'function') { + cb = args[args.length - 1]; + } + + debug('createConnection', options); + + if (options._agentKey) { + const session = this._getSession(options._agentKey); + if (session) { + debug('reuse session for %j', options._agentKey); + options = { + session, + ...options, + }; + } + } + + let socket; + const tunnelConfig = getTunnelConfigForProxiedHttps(this, options); + debug(`https createConnection should use proxy for ${options.host}:${options.port}:`, tunnelConfig); + + if (!tunnelConfig) { + socket = tls.connect(options); + } else { + const connectOptions = { + ...this[kProxyConfig].proxyConnectionOptions, + }; + debug('Create proxy socket', connectOptions); + const onError = (err) => { + cleanupAndPropagate(err, socket); + }; + const proxyTunnelTimeout = tunnelConfig.requestOptions.timeout; + const onTimeout = () => { + const err = new ERR_PROXY_TUNNEL(`Connection to establish proxy tunnel timed out after ${proxyTunnelTimeout}ms`); + err.proxyTunnelTimeout = proxyTunnelTimeout; + cleanupAndPropagate(err, socket); + }; + const cleanupAndPropagate = once((err, currentSocket) => { + debug('cleanupAndPropagate', err); + socket.removeListener('error', onError); + socket.removeListener('timeout', onTimeout); + // An error occurred during tunnel establishment, in that case just destroy the socket. + // and propagate the error to the callback. + + // When the error comes from unexpected status code, the stream is still in good shape, + // in that case let req.onSocket handle the destruction instead. + if (err && err.code === 'ERR_PROXY_TUNNEL' && !err.statusCode) { + socket.destroy(); + } + // This error should go to: + // -> oncreate in Agent.prototype.createSocket + // -> closure in Agent.prototype.addRequest or Agent.prototype.removeSocket + if (cb) { + cb(err, currentSocket); + } + }); + const onProxyConnection = () => { + socket.removeListener('error', onError); + establishTunnel(this, socket, options, tunnelConfig, cleanupAndPropagate); + }; + if (this[kProxyConfig].protocol === 'http:') { + socket = net.connect(connectOptions, onProxyConnection); + } else { + socket = tls.connect(connectOptions, onProxyConnection); + } + + socket.on('error', onError); + if (proxyTunnelTimeout) { + socket.setTimeout(proxyTunnelTimeout, onTimeout); + } + socket[kWaitForProxyTunnel] = true; + } + + if (options._agentKey) { + // Cache new session for reuse + socket.on('session', (session) => { + this._cacheSession(options._agentKey, session); + }); + + // Evict session on error + socket.once('close', (err) => { + if (err) + this._evictSession(options._agentKey); + }); + } + + return socket; +} + +/** + * Creates a new `HttpAgent` instance. + * @param {{ + * keepAlive?: boolean; + * keepAliveMsecs?: number; + * maxSockets?: number; + * maxTotalSockets?: number; + * maxFreeSockets?: number; + * scheduling?: string; + * timeout?: number; + * maxCachedSessions?: number; + * servername?: string; + * defaultPort?: number; + * protocol?: string; + * proxyEnv?: object; + * }} [options] + * @class + */ +function Agent(options) { + if (!(this instanceof Agent)) + return new Agent(options); + + options = { __proto__: null, ...options }; + options.defaultPort ??= 443; + options.protocol ??= 'https:'; + FunctionPrototypeCall(HttpAgent, this, options); + + this.maxCachedSessions = this.options.maxCachedSessions; + if (this.maxCachedSessions === undefined) + this.maxCachedSessions = 100; + + this._sessionCache = { + map: {}, + list: [], + }; +} +ObjectSetPrototypeOf(Agent.prototype, HttpAgent.prototype); +ObjectSetPrototypeOf(Agent, HttpAgent); +Agent.prototype.createConnection = createConnection; + +/** + * Gets a unique name for a set of options. + * @param {{ + * host: string; + * port: number; + * localAddress: string; + * family: number; + * }} [options] + * @returns {string} + */ +Agent.prototype.getName = function getName(options = kEmptyObject) { + let name = FunctionPrototypeCall(HttpAgent.prototype.getName, this, options); + + name += ':'; + if (options.ca) + name += options.ca; + + name += ':'; + if (options.cert) + name += options.cert; + + name += ':'; + if (options.clientCertEngine) + name += options.clientCertEngine; + + name += ':'; + if (options.ciphers) + name += options.ciphers; + + name += ':'; + if (options.key) + name += options.key; + + name += ':'; + if (options.pfx) + name += options.pfx; + + name += ':'; + if (options.rejectUnauthorized !== undefined) + name += options.rejectUnauthorized; + + name += ':'; + if (options.servername && options.servername !== options.host) + name += options.servername; + + name += ':'; + if (options.minVersion) + name += options.minVersion; + + name += ':'; + if (options.maxVersion) + name += options.maxVersion; + + name += ':'; + if (options.secureProtocol) + name += options.secureProtocol; + + name += ':'; + if (options.crl) + name += options.crl; + + name += ':'; + if (options.honorCipherOrder !== undefined) + name += options.honorCipherOrder; + + name += ':'; + if (options.ecdhCurve) + name += options.ecdhCurve; + + name += ':'; + if (options.dhparam) + name += options.dhparam; + + name += ':'; + if (options.secureOptions !== undefined) + name += options.secureOptions; + + name += ':'; + if (options.sessionIdContext) + name += options.sessionIdContext; + + name += ':'; + if (options.sigalgs) + name += JSONStringify(options.sigalgs); + + name += ':'; + if (options.privateKeyIdentifier) + name += options.privateKeyIdentifier; + + name += ':'; + if (options.privateKeyEngine) + name += options.privateKeyEngine; + + return name; +}; + +Agent.prototype._getSession = function _getSession(key) { + return this._sessionCache.map[key]; +}; + +Agent.prototype._cacheSession = function _cacheSession(key, session) { + // Cache is disabled + if (this.maxCachedSessions === 0) + return; + + // Fast case - update existing entry + if (this._sessionCache.map[key]) { + this._sessionCache.map[key] = session; + return; + } + + // Put new entry + if (this._sessionCache.list.length >= this.maxCachedSessions) { + const oldKey = ArrayPrototypeShift(this._sessionCache.list); + debug('evicting %j', oldKey); + delete this._sessionCache.map[oldKey]; + } + + ArrayPrototypePush(this._sessionCache.list, key); + this._sessionCache.map[key] = session; +}; + +Agent.prototype._evictSession = function _evictSession(key) { + const index = ArrayPrototypeIndexOf(this._sessionCache.list, key); + if (index === -1) + return; + + ArrayPrototypeSplice(this._sessionCache.list, index, 1); + delete this._sessionCache.map[key]; +}; + +const globalAgent = new Agent({ + keepAlive: true, scheduling: 'lifo', timeout: 5000, + // This normalized from both --use-env-proxy and NODE_USE_ENV_PROXY settings. + proxyEnv: getOptionValue('--use-env-proxy') ? filterEnvForProxies(process.env) : undefined, +}); + +/** + * Makes a request to a secure web server. + * @param {...any} args + * @returns {ClientRequest} + */ +function request(...args) { + let options = {}; + + if (typeof args[0] === 'string') { + const urlStr = ArrayPrototypeShift(args); + options = urlToHttpOptions(new URL(urlStr)); + } else if (isURL(args[0])) { + options = urlToHttpOptions(ArrayPrototypeShift(args)); + } + + if (args[0] && typeof args[0] !== 'function') { + ObjectAssign(options, ArrayPrototypeShift(args)); + } + + options._defaultAgent = module.exports.globalAgent; + ArrayPrototypeUnshift(args, options); + + return ReflectConstruct(ClientRequest, args); +} + +/** + * Makes a GET request to a secure web server. + * @param {string | URL} input + * @param {{ + * agent?: Agent | boolean; + * auth?: string; + * createConnection?: Function; + * defaultPort?: number; + * family?: number; + * headers?: object; + * hints?: number; + * host?: string; + * hostname?: string; + * insecureHTTPParser?: boolean; + * joinDuplicateHeaders?: boolean; + * localAddress?: string; + * localPort?: number; + * lookup?: Function; + * maxHeaderSize?: number; + * method?: string; + * path?: string; + * port?: number; + * protocol?: string; + * setHost?: boolean; + * socketPath?: string; + * timeout?: number; + * signal?: AbortSignal; + * uniqueHeaders?: Array; + * } | string | URL} [options] + * @param {Function} [cb] + * @returns {ClientRequest} + */ +function get(input, options, cb) { + const req = request(input, options, cb); + req.end(); + return req; +} + +module.exports = { + Agent, + globalAgent, + Server, + createServer, + get, + request, +}; \ No newline at end of file diff --git a/.codesandbox/node/section-links.js b/.codesandbox/node/section-links.js new file mode 100644 index 00000000..a926286d --- /dev/null +++ b/.codesandbox/node/section-links.js @@ -0,0 +1,21 @@ +document.addEventListener('DOMContentLoaded', function(event) { + function f(n) { + if (n.nodeType == 1 && n.tagName.match(/^H[1-6]$/)) { + var span = document.createElement('span'); + span.className = 'section-link'; + span.textContent = '\xa0'; + var a = document.createElement('a'); + a.href = '#' + n.parentNode.id; + a.textContent = '\xb6'; + span.appendChild(a); + n.appendChild(span); + } else { + n = n.firstChild; + while (n) { + f(n); + n = n.nextSibling; + } + } + } + f(document.getElementById('sections')); + }, false); diff --git a/.codesandbox/node/string_decoder.js b/.codesandbox/node/string_decoder.js new file mode 100644 index 00000000..b774af1b --- /dev/null +++ b/.codesandbox/node/string_decoder.js @@ -0,0 +1,125 @@ +'use strict'; + +const { + ArrayBufferIsView, + ObjectDefineProperties, + Symbol, + TypedArrayPrototypeSubarray, +} = primordials; + +const { Buffer } = require('buffer'); +const { + kIncompleteCharactersStart, + kIncompleteCharactersEnd, + kMissingBytes, + kBufferedBytes, + kEncodingField, + kSize, + decode, + flush, +} = internalBinding('string_decoder'); +const { + encodingsMap, + normalizeEncoding, +} = require('internal/util'); +const { + ERR_INVALID_ARG_TYPE, + ERR_INVALID_THIS, + ERR_UNKNOWN_ENCODING, +} = require('internal/errors').codes; + +const kNativeDecoder = Symbol('kNativeDecoder'); + +/** + * StringDecoder provides an interface for efficiently splitting a series of + * buffers into a series of JS strings without breaking apart multibyte + * characters. + * @param {string} [encoding] + */ +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + if (this.encoding === undefined) { + throw new ERR_UNKNOWN_ENCODING(encoding); + } + this[kNativeDecoder] = Buffer.alloc(kSize); + this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; +} + +/** + * Returns a decoded string, omitting any incomplete multi-bytes + * characters at the end of the Buffer, or TypedArray, or DataView + * @param {string | Buffer | TypedArray | DataView} buf + * @returns {string} + * @throws {TypeError} Throws when buf is not in one of supported types + */ +StringDecoder.prototype.write = function write(buf) { + if (typeof buf === 'string') + return buf; + if (!ArrayBufferIsView(buf)) + throw new ERR_INVALID_ARG_TYPE('buf', + ['Buffer', 'TypedArray', 'DataView'], + buf); + if (!this[kNativeDecoder]) { + throw new ERR_INVALID_THIS('StringDecoder'); + } + return decode(this[kNativeDecoder], buf); +}; + +/** + * Returns any remaining input stored in the internal buffer as a string. + * After end() is called, the stringDecoder object can be reused for new + * input. + * @param {string | Buffer | TypedArray | DataView} [buf] + * @returns {string} + */ +StringDecoder.prototype.end = function end(buf) { + const ret = buf === undefined ? '' : this.write(buf); + if (this[kNativeDecoder][kBufferedBytes] > 0) + return ret + flush(this[kNativeDecoder]); + return ret; +}; + +/* Everything below this line is undocumented legacy stuff. */ +/** + * + * @param {string | Buffer | TypedArray | DataView} buf + * @param {number} offset + * @returns {string} + */ +StringDecoder.prototype.text = function text(buf, offset) { + this[kNativeDecoder][kMissingBytes] = 0; + this[kNativeDecoder][kBufferedBytes] = 0; + return this.write(buf.slice(offset)); +}; + +ObjectDefineProperties(StringDecoder.prototype, { + lastChar: { + __proto__: null, + configurable: true, + enumerable: true, + get() { + return TypedArrayPrototypeSubarray(this[kNativeDecoder], + kIncompleteCharactersStart, + kIncompleteCharactersEnd); + }, + }, + lastNeed: { + __proto__: null, + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kMissingBytes]; + }, + }, + lastTotal: { + __proto__: null, + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kBufferedBytes] + + this[kNativeDecoder][kMissingBytes]; + }, + }, +}); + +exports.StringDecoder = StringDecoder; \ No newline at end of file diff --git a/.codesandbox/node/task_processor.js b/.codesandbox/node/task_processor.js new file mode 100644 index 00000000..ebb455ee --- /dev/null +++ b/.codesandbox/node/task_processor.js @@ -0,0 +1,91 @@ +const { parentPort } = require('node:worker_threads'); +parentPort.on('message', (task) => { + parentPort.postMessage(task.a + task.b); +}); +const { AsyncResource } = require('node:async_hooks'); +const { EventEmitter } = require('node:events'); +const path = require('node:path'); +const { Worker } = require('node:worker_threads'); + +const kTaskInfo = Symbol('kTaskInfo'); +const kWorkerFreedEvent = Symbol('kWorkerFreedEvent'); + +class WorkerPoolTaskInfo extends AsyncResource { + constructor(callback) { + super('WorkerPoolTaskInfo'); + this.callback = callback; + } + + done(err, result) { + this.runInAsyncScope(this.callback, null, err, result); + this.emitDestroy(); // `TaskInfo`s are used only once. + } +} + +class WorkerPool extends EventEmitter { + constructor(numThreads) { + super(); + this.numThreads = numThreads; + this.workers = []; + this.freeWorkers = []; + this.tasks = []; + + for (let i = 0; i < numThreads; i++) + this.addNewWorker(); + + // Any time the kWorkerFreedEvent is emitted, dispatch + // the next task pending in the queue, if any. + this.on(kWorkerFreedEvent, () => { + if (this.tasks.length > 0) { + const { task, callback } = this.tasks.shift(); + this.runTask(task, callback); + } + }); + } + + addNewWorker() { + const worker = new Worker(path.resolve(__dirname, 'task_processor.js')); + worker.on('message', (result) => { + // In case of success: Call the callback that was passed to `runTask`, + // remove the `TaskInfo` associated with the Worker, and mark it as free + // again. + worker[kTaskInfo].done(null, result); + worker[kTaskInfo] = null; + this.freeWorkers.push(worker); + this.emit(kWorkerFreedEvent); + }); + worker.on('error', (err) => { + // In case of an uncaught exception: Call the callback that was passed to + // `runTask` with the error. + if (worker[kTaskInfo]) + worker[kTaskInfo].done(err, null); + else + this.emit('error', err); + // Remove the worker from the list and start a new Worker to replace the + // current one. + this.workers.splice(this.workers.indexOf(worker), 1); + this.addNewWorker(); + }); + this.workers.push(worker); + this.freeWorkers.push(worker); + this.emit(kWorkerFreedEvent); + } + + runTask(task, callback) { + if (this.freeWorkers.length === 0) { + // No free threads, wait until a worker thread becomes free. + this.tasks.push({ task, callback }); + return; + } + + const worker = this.freeWorkers.pop(); + worker[kTaskInfo] = new WorkerPoolTaskInfo(callback); + worker.postMessage(task); + } + + close() { + for (const worker of this.workers) worker.terminate(); + } +} + +module.exports = WorkerPool; \ No newline at end of file diff --git a/.codesandbox/node/tls.js b/.codesandbox/node/tls.js new file mode 100644 index 00000000..6cd6b269 --- /dev/null +++ b/.codesandbox/node/tls.js @@ -0,0 +1,405 @@ +'use strict'; + +const { + Array, + ArrayIsArray, + // eslint-disable-next-line no-restricted-syntax + ArrayPrototypePush, + JSONParse, + ObjectDefineProperty, + ObjectFreeze, + StringFromCharCode, +} = primordials; + +const { + ERR_TLS_CERT_ALTNAME_FORMAT, + ERR_TLS_CERT_ALTNAME_INVALID, + ERR_OUT_OF_RANGE, + ERR_INVALID_ARG_VALUE, + ERR_INVALID_ARG_TYPE, +} = require('internal/errors').codes; +const internalUtil = require('internal/util'); +internalUtil.assertCrypto(); +const { + isArrayBufferView, + isUint8Array, +} = require('internal/util/types'); + +const net = require('net'); +const { getOptionValue } = require('internal/options'); +const { + getBundledRootCertificates, + getExtraCACertificates, + getSystemCACertificates, + resetRootCertStore, + getUserRootCertificates, + getSSLCiphers, +} = internalBinding('crypto'); +const { Buffer } = require('buffer'); +const { canonicalizeIP } = internalBinding('cares_wrap'); +const _tls_common = require('_tls_common'); +const _tls_wrap = require('_tls_wrap'); +const { validateString } = require('internal/validators'); + +// Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations +// every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more +// renegotiations are seen. The settings are applied to all remote client +// connections. +exports.CLIENT_RENEG_LIMIT = 3; +exports.CLIENT_RENEG_WINDOW = 600; + +exports.DEFAULT_CIPHERS = getOptionValue('--tls-cipher-list'); + +exports.DEFAULT_ECDH_CURVE = 'auto'; + +if (getOptionValue('--tls-min-v1.0')) + exports.DEFAULT_MIN_VERSION = 'TLSv1'; +else if (getOptionValue('--tls-min-v1.1')) + exports.DEFAULT_MIN_VERSION = 'TLSv1.1'; +else if (getOptionValue('--tls-min-v1.2')) + exports.DEFAULT_MIN_VERSION = 'TLSv1.2'; +else if (getOptionValue('--tls-min-v1.3')) + exports.DEFAULT_MIN_VERSION = 'TLSv1.3'; +else + exports.DEFAULT_MIN_VERSION = 'TLSv1.2'; + +if (getOptionValue('--tls-max-v1.3')) + exports.DEFAULT_MAX_VERSION = 'TLSv1.3'; +else if (getOptionValue('--tls-max-v1.2')) + exports.DEFAULT_MAX_VERSION = 'TLSv1.2'; +else + exports.DEFAULT_MAX_VERSION = 'TLSv1.3'; // Will depend on node version. + + +exports.getCiphers = internalUtil.cachedResult( + () => internalUtil.filterDuplicateStrings(getSSLCiphers(), true), +); + +let bundledRootCertificates; +function cacheBundledRootCertificates() { + bundledRootCertificates ||= ObjectFreeze(getBundledRootCertificates()); + + return bundledRootCertificates; +} + +ObjectDefineProperty(exports, 'rootCertificates', { + __proto__: null, + configurable: false, + enumerable: true, + get: cacheBundledRootCertificates, +}); + +let extraCACertificates; +function cacheExtraCACertificates() { + extraCACertificates ||= ObjectFreeze(getExtraCACertificates()); + + return extraCACertificates; +} + +let systemCACertificates; +function cacheSystemCACertificates() { + systemCACertificates ||= ObjectFreeze(getSystemCACertificates()); + + return systemCACertificates; +} + +let defaultCACertificates; +let hasResetDefaultCACertificates = false; + +function cacheDefaultCACertificates() { + if (defaultCACertificates) { return defaultCACertificates; } + + if (hasResetDefaultCACertificates) { + defaultCACertificates = getUserRootCertificates(); + ObjectFreeze(defaultCACertificates); + return defaultCACertificates; + } + + defaultCACertificates = []; + + if (!getOptionValue('--use-openssl-ca')) { + const bundled = cacheBundledRootCertificates(); + for (let i = 0; i < bundled.length; ++i) { + ArrayPrototypePush(defaultCACertificates, bundled[i]); + } + if (getOptionValue('--use-system-ca')) { + const system = cacheSystemCACertificates(); + for (let i = 0; i < system.length; ++i) { + + ArrayPrototypePush(defaultCACertificates, system[i]); + } + } + } + + if (process.env.NODE_EXTRA_CA_CERTS) { + const extra = cacheExtraCACertificates(); + for (let i = 0; i < extra.length; ++i) { + + ArrayPrototypePush(defaultCACertificates, extra[i]); + } + } + + ObjectFreeze(defaultCACertificates); + return defaultCACertificates; +} + +// TODO(joyeecheung): support X509Certificate output? +function getCACertificates(type = 'default') { + validateString(type, 'type'); + + switch (type) { + case 'default': + return cacheDefaultCACertificates(); + case 'bundled': + return cacheBundledRootCertificates(); + case 'system': + return cacheSystemCACertificates(); + case 'extra': + return cacheExtraCACertificates(); + default: + throw new ERR_INVALID_ARG_VALUE('type', type); + } +} +exports.getCACertificates = getCACertificates; + +function setDefaultCACertificates(certs) { + if (!ArrayIsArray(certs)) { + throw new ERR_INVALID_ARG_TYPE('certs', 'Array', certs); + } + + // Verify that all elements in the array are strings + for (let i = 0; i < certs.length; i++) { + if (typeof certs[i] !== 'string' && !isArrayBufferView(certs[i])) { + throw new ERR_INVALID_ARG_TYPE( + `certs[${i}]`, ['string', 'ArrayBufferView'], certs[i]); + } + } + + resetRootCertStore(certs); + defaultCACertificates = undefined; // Reset the cached default certificates + hasResetDefaultCACertificates = true; +} + +exports.setDefaultCACertificates = setDefaultCACertificates; + +// Convert protocols array into valid OpenSSL protocols list +// ("\x06spdy/2\x08http/1.1\x08http/1.0") +function convertProtocols(protocols) { + const lens = new Array(protocols.length); + const buff = Buffer.allocUnsafe(protocols.reduce((p, c, i) => { + const len = Buffer.byteLength(c); + if (len > 255) { + throw new ERR_OUT_OF_RANGE('The byte length of the protocol at index ' + + `${i} exceeds the maximum length.`, '<= 255', len, true); + } + lens[i] = len; + return p + 1 + len; + }, 0)); + + let offset = 0; + for (let i = 0, c = protocols.length; i < c; i++) { + buff[offset++] = lens[i]; + buff.write(protocols[i], offset); + offset += lens[i]; + } + + return buff; +} + +exports.convertALPNProtocols = function convertALPNProtocols(protocols, out) { + // If protocols is Array - translate it into buffer + if (ArrayIsArray(protocols)) { + out.ALPNProtocols = convertProtocols(protocols); + } else if (isUint8Array(protocols)) { + // Copy new buffer not to be modified by user. + out.ALPNProtocols = Buffer.from(protocols); + } else if (isArrayBufferView(protocols)) { + out.ALPNProtocols = Buffer.from(protocols.buffer.slice( + protocols.byteOffset, + protocols.byteOffset + protocols.byteLength, + )); + } +}; + +function unfqdn(host) { + return host.replace(/[.]$/, ''); +} + +// String#toLowerCase() is locale-sensitive so we use +// a conservative version that only lowercases A-Z. +function toLowerCase(c) { + return StringFromCharCode(32 + c.charCodeAt(0)); +} + +function splitHost(host) { + return unfqdn(host).replace(/[A-Z]/g, toLowerCase).split('.'); +} + +function check(hostParts, pattern, wildcards) { + // Empty strings, null, undefined, etc. never match. + if (!pattern) + return false; + + const patternParts = splitHost(pattern); + + if (hostParts.length !== patternParts.length) + return false; + + // Pattern has empty components, e.g. "bad..example.com". + if (patternParts.includes('')) + return false; + + // RFC 6125 allows IDNA U-labels (Unicode) in names but we have no + // good way to detect their encoding or normalize them so we simply + // reject them. Control characters and blanks are rejected as well + // because nothing good can come from accepting them. + const isBad = (s) => /[^\u0021-\u007F]/u.test(s); + if (patternParts.some(isBad)) + return false; + + // Check host parts from right to left first. + for (let i = hostParts.length - 1; i > 0; i -= 1) { + if (hostParts[i] !== patternParts[i]) + return false; + } + + const hostSubdomain = hostParts[0]; + const patternSubdomain = patternParts[0]; + const patternSubdomainParts = patternSubdomain.split('*', 3); + + // Short-circuit when the subdomain does not contain a wildcard. + // RFC 6125 does not allow wildcard substitution for components + // containing IDNA A-labels (Punycode) so match those verbatim. + if (patternSubdomainParts.length === 1 || + patternSubdomain.includes('xn--')) + return hostSubdomain === patternSubdomain; + + if (!wildcards) + return false; + + // More than one wildcard is always wrong. + if (patternSubdomainParts.length > 2) + return false; + + // *.tld wildcards are not allowed. + if (patternParts.length <= 2) + return false; + + const { 0: prefix, 1: suffix } = patternSubdomainParts; + + if (prefix.length + suffix.length > hostSubdomain.length) + return false; + + if (!hostSubdomain.startsWith(prefix)) + return false; + + if (!hostSubdomain.endsWith(suffix)) + return false; + + return true; +} + +// This pattern is used to determine the length of escaped sequences within +// the subject alt names string. It allows any valid JSON string literal. +// This MUST match the JSON specification (ECMA-404 / RFC8259) exactly. +const jsonStringPattern = + // eslint-disable-next-line no-control-regex + /^"(?:[^"\\\u0000-\u001f]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4}))*"/; + +function splitEscapedAltNames(altNames) { + const result = []; + let currentToken = ''; + let offset = 0; + while (offset !== altNames.length) { + const nextSep = altNames.indexOf(',', offset); + const nextQuote = altNames.indexOf('"', offset); + if (nextQuote !== -1 && (nextSep === -1 || nextQuote < nextSep)) { + // There is a quote character and there is no separator before the quote. + currentToken += altNames.substring(offset, nextQuote); + const match = jsonStringPattern.exec(altNames.substring(nextQuote)); + if (!match) { + throw new ERR_TLS_CERT_ALTNAME_FORMAT(); + } + currentToken += JSONParse(match[0]); + offset = nextQuote + match[0].length; + } else if (nextSep !== -1) { + // There is a separator and no quote before it. + currentToken += altNames.substring(offset, nextSep); + result.push(currentToken); + currentToken = ''; + offset = nextSep + 2; + } else { + currentToken += altNames.substring(offset); + offset = altNames.length; + } + } + result.push(currentToken); + return result; +} + +exports.checkServerIdentity = function checkServerIdentity(hostname, cert) { + const subject = cert.subject; + const altNames = cert.subjectaltname; + const dnsNames = []; + const ips = []; + + hostname = '' + hostname; + + if (altNames) { + const splitAltNames = altNames.includes('"') ? + splitEscapedAltNames(altNames) : + altNames.split(', '); + splitAltNames.forEach((name) => { + if (name.startsWith('DNS:')) { + dnsNames.push(name.slice(4)); + } else if (name.startsWith('IP Address:')) { + ips.push(canonicalizeIP(name.slice(11))); + } + }); + } + + let valid = false; + let reason = 'Unknown reason'; + + hostname = unfqdn(hostname); // Remove trailing dot for error messages. + + if (net.isIP(hostname)) { + valid = ips.includes(canonicalizeIP(hostname)); + if (!valid) + reason = `IP: ${hostname} is not in the cert's list: ` + ips.join(', '); + } else if (dnsNames.length > 0 || subject?.CN) { + const hostParts = splitHost(hostname); + const wildcard = (pattern) => check(hostParts, pattern, true); + + if (dnsNames.length > 0) { + valid = dnsNames.some(wildcard); + if (!valid) + reason = + `Host: ${hostname}. is not in the cert's altnames: ${altNames}`; + } else { + // Match against Common Name only if no supported identifiers exist. + const cn = subject.CN; + + if (ArrayIsArray(cn)) + valid = cn.some(wildcard); + else if (cn) + valid = wildcard(cn); + + if (!valid) + reason = `Host: ${hostname}. is not cert's CN: ${cn}`; + } + } else { + reason = 'Cert does not contain a DNS name'; + } + + if (!valid) { + return new ERR_TLS_CERT_ALTNAME_INVALID(reason, hostname, cert); + } +}; + +exports.createSecureContext = _tls_common.createSecureContext; +exports.SecureContext = _tls_common.SecureContext; +exports.TLSSocket = _tls_wrap.TLSSocket; +exports.Server = _tls_wrap.Server; +exports.createServer = _tls_wrap.createServer; +exports.connect = _tls_wrap.connect; \ No newline at end of file diff --git a/.codesandbox/node/trace_events.js b/.codesandbox/node/trace_events.js new file mode 100644 index 00000000..69fccafc --- /dev/null +++ b/.codesandbox/node/trace_events.js @@ -0,0 +1,75 @@ +'use strict'; + +const { + ObjectAssign, + ObjectDefineProperty, +} = primordials; + +const { test, suite, before, after, beforeEach, afterEach } = require('internal/test_runner/harness'); +const { run } = require('internal/test_runner/runner'); + +module.exports = test; +ObjectAssign(module.exports, { + after, + afterEach, + before, + beforeEach, + describe: suite, + it: test, + run, + suite, + test, +}); + +let lazyMock; + +ObjectDefineProperty(module.exports, 'mock', { + __proto__: null, + configurable: true, + enumerable: true, + get() { + if (lazyMock === undefined) { + const { MockTracker } = require('internal/test_runner/mock/mock'); + + lazyMock = new MockTracker(); + } + + return lazyMock; + }, +}); + +let lazySnapshot; + +ObjectDefineProperty(module.exports, 'snapshot', { + __proto__: null, + configurable: true, + enumerable: true, + get() { + if (lazySnapshot === undefined) { + const { + setDefaultSnapshotSerializers, + setResolveSnapshotPath, + } = require('internal/test_runner/snapshot'); + + lazySnapshot = { + __proto__: null, + setDefaultSnapshotSerializers, + setResolveSnapshotPath, + }; + } + + return lazySnapshot; + }, +}); + +ObjectDefineProperty(module.exports, 'assert', { + __proto__: null, + configurable: true, + enumerable: true, + get() { + const { register } = require('internal/test_runner/assert'); + const assert = { __proto__: null, register }; + ObjectDefineProperty(module.exports, 'assert', assert); + return assert; + }, +}); \ No newline at end of file diff --git a/.codesandbox/node/tty.js b/.codesandbox/node/tty.js new file mode 100644 index 00000000..f9275fab --- /dev/null +++ b/.codesandbox/node/tty.js @@ -0,0 +1,147 @@ +'use strict'; + +const { + NumberIsInteger, + ObjectSetPrototypeOf, +} = primordials; + +const net = require('net'); +const { TTY, isTTY } = internalBinding('tty_wrap'); +const { + ErrnoException, + codes: { + ERR_INVALID_FD, + ERR_TTY_INIT_FAILED, + }, +} = require('internal/errors'); +const { + getColorDepth, + hasColors, +} = require('internal/tty'); + +// Lazy loaded for startup performance. +let readline; + +function isatty(fd) { + return NumberIsInteger(fd) && fd >= 0 && fd <= 2147483647 && + isTTY(fd); +} + +function ReadStream(fd, options) { + if (!(this instanceof ReadStream)) + return new ReadStream(fd, options); + if (fd >> 0 !== fd || fd < 0) + throw new ERR_INVALID_FD(fd); + + const ctx = {}; + const tty = new TTY(fd, ctx); + if (ctx.code !== undefined) { + throw new ERR_TTY_INIT_FAILED(ctx); + } + + net.Socket.call(this, { + readableHighWaterMark: 0, + handle: tty, + manualStart: true, + ...options, + }); + + this.isRaw = false; + this.isTTY = true; +} + +ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype); +ObjectSetPrototypeOf(ReadStream, net.Socket); + +ReadStream.prototype.setRawMode = function(flag) { + flag = !!flag; + const err = this._handle?.setRawMode(flag); + if (err) { + this.emit('error', new ErrnoException(err, 'setRawMode')); + return this; + } + this.isRaw = flag; + return this; +}; + +function WriteStream(fd) { + if (!(this instanceof WriteStream)) + return new WriteStream(fd); + if (fd >> 0 !== fd || fd < 0) + throw new ERR_INVALID_FD(fd); + + const ctx = {}; + const tty = new TTY(fd, ctx); + if (ctx.code !== undefined) { + throw new ERR_TTY_INIT_FAILED(ctx); + } + + net.Socket.call(this, { + readableHighWaterMark: 0, + handle: tty, + manualStart: true, + }); + + // Prevents interleaved or dropped stdout/stderr output for terminals. + // As noted in the following reference, local TTYs tend to be quite fast and + // this behavior has become expected due historical functionality on OS X, + // even though it was originally intended to change in v1.0.2 (Libuv 1.2.1). + // Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671 + this._handle.setBlocking(true); + + const winSize = [0, 0]; + const err = this._handle.getWindowSize(winSize); + if (!err) { + this.columns = winSize[0]; + this.rows = winSize[1]; + } +} + +ObjectSetPrototypeOf(WriteStream.prototype, net.Socket.prototype); +ObjectSetPrototypeOf(WriteStream, net.Socket); + +WriteStream.prototype.isTTY = true; + +WriteStream.prototype.getColorDepth = getColorDepth; + +WriteStream.prototype.hasColors = hasColors; + +WriteStream.prototype._refreshSize = function() { + const oldCols = this.columns; + const oldRows = this.rows; + const winSize = [0, 0]; + const err = this._handle.getWindowSize(winSize); + if (err) { + this.emit('error', new ErrnoException(err, 'getWindowSize')); + return; + } + const { 0: newCols, 1: newRows } = winSize; + if (oldCols !== newCols || oldRows !== newRows) { + this.columns = newCols; + this.rows = newRows; + this.emit('resize'); + } +}; + +// Backwards-compat +WriteStream.prototype.cursorTo = function(x, y, callback) { + if (readline === undefined) readline = require('readline'); + return readline.cursorTo(this, x, y, callback); +}; +WriteStream.prototype.moveCursor = function(dx, dy, callback) { + if (readline === undefined) readline = require('readline'); + return readline.moveCursor(this, dx, dy, callback); +}; +WriteStream.prototype.clearLine = function(dir, callback) { + if (readline === undefined) readline = require('readline'); + return readline.clearLine(this, dir, callback); +}; +WriteStream.prototype.clearScreenDown = function(callback) { + if (readline === undefined) readline = require('readline'); + return readline.clearScreenDown(this, callback); +}; +WriteStream.prototype.getWindowSize = function() { + return [this.columns, this.rows]; +}; + +module.exports = { isatty, ReadStream, WriteStream }; \ No newline at end of file diff --git a/.codesandbox/node/url.js b/.codesandbox/node/url.js new file mode 100644 index 00000000..7e0f36ee --- /dev/null +++ b/.codesandbox/node/url.js @@ -0,0 +1,1028 @@ +'use strict'; + +const { + ArrayPrototypeJoin, + Boolean, + Int8Array, + ObjectAssign, + ObjectKeys, + StringPrototypeAt, + StringPrototypeCharCodeAt, + StringPrototypeIndexOf, + StringPrototypeReplaceAll, + StringPrototypeSlice, + decodeURIComponent, +} = primordials; + +const { URLPattern } = internalBinding('url_pattern'); +const { toASCII } = internalBinding('encoding_binding'); +const { encodeStr, hexTable } = require('internal/querystring'); +const querystring = require('querystring'); + +const { + ERR_INVALID_ARG_TYPE, + ERR_INVALID_URL, +} = require('internal/errors').codes; +const { + validateString, + validateObject, +} = require('internal/validators'); + +// This ensures setURLConstructor() is called before the native +// URL::ToObject() method is used. +const { spliceOne } = require('internal/util'); +const { isInsideNodeModules } = internalBinding('util'); + +// WHATWG URL implementation provided by internal/url +const { + URL, + URLSearchParams, + domainToASCII, + domainToUnicode, + fileURLToPath, + fileURLToPathBuffer, + pathToFileURL: _pathToFileURL, + urlToHttpOptions, + unsafeProtocol, + hostlessProtocol, + slashedProtocol, +} = require('internal/url'); + +const bindingUrl = internalBinding('url'); + +// Original url.parse() API + +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +// define these here so at least they only have to be +// compiled once on the first module load. +const protocolPattern = /^[a-z0-9.+-]+:/i; +const portPattern = /:[0-9]*$/; +const hostPattern = /^\/\/[^@/]+@[^@/]+/; + +// Special case for a simple path URL +const simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/; + +const hostnameMaxLen = 255; +const { + CHAR_SPACE, + CHAR_TAB, + CHAR_CARRIAGE_RETURN, + CHAR_LINE_FEED, + CHAR_NO_BREAK_SPACE, + CHAR_ZERO_WIDTH_NOBREAK_SPACE, + CHAR_HASH, + CHAR_FORWARD_SLASH, + CHAR_LEFT_SQUARE_BRACKET, + CHAR_RIGHT_SQUARE_BRACKET, + CHAR_LEFT_ANGLE_BRACKET, + CHAR_RIGHT_ANGLE_BRACKET, + CHAR_LEFT_CURLY_BRACKET, + CHAR_RIGHT_CURLY_BRACKET, + CHAR_QUESTION_MARK, + CHAR_DOUBLE_QUOTE, + CHAR_SINGLE_QUOTE, + CHAR_PERCENT, + CHAR_SEMICOLON, + CHAR_BACKWARD_SLASH, + CHAR_CIRCUMFLEX_ACCENT, + CHAR_GRAVE_ACCENT, + CHAR_VERTICAL_LINE, + CHAR_AT, + CHAR_COLON, +} = require('internal/constants'); + +let urlParseWarned = false; + +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (!urlParseWarned && !isInsideNodeModules(100, true)) { + urlParseWarned = true; + process.emitWarning( + '`url.parse()` behavior is not standardized and prone to ' + + 'errors that have security implications. Use the WHATWG URL API ' + + 'instead. CVEs are not issued for `url.parse()` vulnerabilities.', + 'DeprecationWarning', + 'DEP0169', + ); + } + + if (url instanceof Url) return url; + + const urlObject = new Url(); + urlObject.parse(url, parseQueryString, slashesDenoteHost); + return urlObject; +} + +function isIpv6Hostname(hostname) { + return ( + StringPrototypeCharCodeAt(hostname, 0) === CHAR_LEFT_SQUARE_BRACKET && + StringPrototypeCharCodeAt(hostname, hostname.length - 1) === + CHAR_RIGHT_SQUARE_BRACKET + ); +} + +// This prevents some common spoofing bugs due to our use of IDNA toASCII. For +// compatibility, the set of characters we use here is the *intersection* of +// "forbidden host code point" in the WHATWG URL Standard [1] and the +// characters in the host parsing loop in Url.prototype.parse, with the +// following additions: +// +// - ':' since this could cause a "protocol spoofing" bug +// - '@' since this could cause parts of the hostname to be confused with auth +// - '[' and ']' since this could cause a non-IPv6 hostname to be interpreted +// as IPv6 by isIpv6Hostname above +// +// [1]: https://url.spec.whatwg.org/#forbidden-host-code-point +const forbiddenHostChars = /[\0\t\n\r #%/:<>?@[\\\]^|]/; +// For IPv6, permit '[', ']', and ':'. +const forbiddenHostCharsIpv6 = /[\0\t\n\r #%/<>?@\\^|]/; + +Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { + validateString(url, 'url'); + + // Copy chrome, IE, opera backslash-handling behavior. + // Back slashes before the query string get converted to forward slashes + // See: https://code.google.com/p/chromium/issues/detail?id=25916 + let hasHash = false; + let hasAt = false; + let start = -1; + let end = -1; + let rest = ''; + let lastPos = 0; + for (let i = 0, inWs = false, split = false; i < url.length; ++i) { + const code = url.charCodeAt(i); + + // Find first and last non-whitespace characters for trimming + const isWs = code < 33 || + code === CHAR_NO_BREAK_SPACE || + code === CHAR_ZERO_WIDTH_NOBREAK_SPACE; + if (start === -1) { + if (isWs) + continue; + lastPos = start = i; + } else if (inWs) { + if (!isWs) { + end = -1; + inWs = false; + } + } else if (isWs) { + end = i; + inWs = true; + } + + // Only convert backslashes while we haven't seen a split character + if (!split) { + switch (code) { + case CHAR_AT: + hasAt = true; + break; + case CHAR_HASH: + hasHash = true; + // Fall through + case CHAR_QUESTION_MARK: + split = true; + break; + case CHAR_BACKWARD_SLASH: + if (i - lastPos > 0) + rest += url.slice(lastPos, i); + rest += '/'; + lastPos = i + 1; + break; + } + } else if (!hasHash && code === CHAR_HASH) { + hasHash = true; + } + } + + // Check if string was non-empty (including strings with only whitespace) + if (start !== -1) { + if (lastPos === start) { + // We didn't convert any backslashes + + if (end === -1) { + if (start === 0) + rest = url; + else + rest = url.slice(start); + } else { + rest = url.slice(start, end); + } + } else if (end === -1 && lastPos < url.length) { + // We converted some backslashes and have only part of the entire string + rest += url.slice(lastPos); + } else if (end !== -1 && lastPos < end) { + // We converted some backslashes and have only part of the entire string + rest += url.slice(lastPos, end); + } + } + + if (!slashesDenoteHost && !hasHash && !hasAt) { + // Try fast path regexp + const simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.slice(1)); + } else { + this.query = this.search.slice(1); + } + } else if (parseQueryString) { + this.search = null; + this.query = { __proto__: null }; + } + return this; + } + } + + let proto = protocolPattern.exec(rest); + let lowerProto; + if (proto) { + proto = proto[0]; + lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.slice(proto.length); + } + + // Figure out if it's got a host + // user@server is *always* interpreted as a hostname, and url + // resolution will treat //foo/bar as host=foo,path=bar because that's + // how the browser resolves relative URLs. + let slashes; + if (slashesDenoteHost || proto || hostPattern.test(rest)) { + slashes = rest.charCodeAt(0) === CHAR_FORWARD_SLASH && + rest.charCodeAt(1) === CHAR_FORWARD_SLASH; + if (slashes && !(proto && hostlessProtocol.has(lowerProto))) { + rest = rest.slice(2); + this.slashes = true; + } + } + + if (!hostlessProtocol.has(lowerProto) && + (slashes || (proto && !slashedProtocol.has(proto)))) { + + // there's a hostname. + // the first instance of /, ?, ;, or # ends the host. + // + // If there is an @ in the hostname, then non-host chars *are* allowed + // to the left of the last @ sign, unless some host-ending character + // comes *before* the @-sign. + // URLs are obnoxious. + // + // ex: + // http://a@b@c/ => user:a@b host:c + // http://a@b?@c => user:a host:b path:/?@c + + let hostEnd = -1; + let atSign = -1; + let nonHost = -1; + for (let i = 0; i < rest.length; ++i) { + switch (rest.charCodeAt(i)) { + case CHAR_TAB: + case CHAR_LINE_FEED: + case CHAR_CARRIAGE_RETURN: + // WHATWG URL removes tabs, newlines, and carriage returns. Let's do that too. + rest = rest.slice(0, i) + rest.slice(i + 1); + i -= 1; + break; + case CHAR_SPACE: + case CHAR_DOUBLE_QUOTE: + case CHAR_PERCENT: + case CHAR_SINGLE_QUOTE: + case CHAR_SEMICOLON: + case CHAR_LEFT_ANGLE_BRACKET: + case CHAR_RIGHT_ANGLE_BRACKET: + case CHAR_BACKWARD_SLASH: + case CHAR_CIRCUMFLEX_ACCENT: + case CHAR_GRAVE_ACCENT: + case CHAR_LEFT_CURLY_BRACKET: + case CHAR_VERTICAL_LINE: + case CHAR_RIGHT_CURLY_BRACKET: + // Characters that are never ever allowed in a hostname from RFC 2396 + if (nonHost === -1) + nonHost = i; + break; + case CHAR_HASH: + case CHAR_FORWARD_SLASH: + case CHAR_QUESTION_MARK: + // Find the first instance of any host-ending characters + if (nonHost === -1) + nonHost = i; + hostEnd = i; + break; + case CHAR_AT: + // At this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. + atSign = i; + nonHost = -1; + break; + } + if (hostEnd !== -1) + break; + } + start = 0; + if (atSign !== -1) { + this.auth = decodeURIComponent(rest.slice(0, atSign)); + start = atSign + 1; + } + if (nonHost === -1) { + this.host = rest.slice(start); + rest = ''; + } else { + this.host = rest.slice(start, nonHost); + rest = rest.slice(nonHost); + } + + // pull out port. + this.parseHost(); + + // We've indicated that there is a hostname, + // so even if it's empty, it has to be present. + if (typeof this.hostname !== 'string') + this.hostname = ''; + + const hostname = this.hostname; + + // If hostname begins with [ and ends with ] + // assume that it's an IPv6 address. + const ipv6Hostname = isIpv6Hostname(hostname); + + // validate a little. + if (!ipv6Hostname) { + rest = getHostname(this, rest, hostname, url); + } + + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // Hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + + if (this.hostname !== '') { + if (ipv6Hostname) { + if (forbiddenHostCharsIpv6.test(this.hostname)) { + throw new ERR_INVALID_URL(url); + } + } else { + // IDNA Support: Returns a punycoded representation of "domain". + // It only converts parts of the domain name that + // have non-ASCII characters, i.e. it doesn't matter if + // you call it with a domain that already is ASCII-only. + this.hostname = toASCII(this.hostname); + + // Prevent two potential routes of hostname spoofing. + // 1. If this.hostname is empty, it must have become empty due to toASCII + // since we checked this.hostname above. + // 2. If any of forbiddenHostChars appears in this.hostname, it must have + // also gotten in due to toASCII. This is since getHostname would have + // filtered them out otherwise. + // Rather than trying to correct this by moving the non-host part into + // the pathname as we've done in getHostname, throw an exception to + // convey the severity of this issue. + if (this.hostname === '' || forbiddenHostChars.test(this.hostname)) { + throw new ERR_INVALID_URL(url); + } + } + } + + const p = this.port ? ':' + this.port : ''; + const h = this.hostname || ''; + this.host = h + p; + + // strip [ and ] from the hostname + // the host field still retains them, though + if (ipv6Hostname) { + this.hostname = this.hostname.slice(1, -1); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } + + // Now rest is set to the post-host stuff. + // Chop off any delim chars. + if (!unsafeProtocol.has(lowerProto)) { + // First, make 100% sure that any "autoEscape" chars get + // escaped, even if encodeURIComponent doesn't think they + // need to be. + rest = autoEscapeStr(rest); + } + + let questionIdx = -1; + let hashIdx = -1; + for (let i = 0; i < rest.length; ++i) { + const code = rest.charCodeAt(i); + if (code === CHAR_HASH) { + this.hash = rest.slice(i); + hashIdx = i; + break; + } else if (code === CHAR_QUESTION_MARK && questionIdx === -1) { + questionIdx = i; + } + } + + if (questionIdx !== -1) { + if (hashIdx === -1) { + this.search = rest.slice(questionIdx); + this.query = rest.slice(questionIdx + 1); + } else { + this.search = rest.slice(questionIdx, hashIdx); + this.query = rest.slice(questionIdx + 1, hashIdx); + } + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + } else if (parseQueryString) { + // No query string, but parseQueryString still requested + this.search = null; + this.query = { __proto__: null }; + } + + const useQuestionIdx = + questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx); + const firstIdx = useQuestionIdx ? questionIdx : hashIdx; + if (firstIdx === -1) { + if (rest.length > 0) + this.pathname = rest; + } else if (firstIdx > 0) { + this.pathname = rest.slice(0, firstIdx); + } + if (slashedProtocol.has(lowerProto) && + this.hostname && !this.pathname) { + this.pathname = '/'; + } + + // To support http.request + if (this.pathname || this.search) { + const p = this.pathname || ''; + const s = this.search || ''; + this.path = p + s; + } + + // Finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; + +let warnInvalidPort = true; +function getHostname(self, rest, hostname, url) { + for (let i = 0; i < hostname.length; ++i) { + const code = hostname.charCodeAt(i); + const isValid = (code !== CHAR_FORWARD_SLASH && + code !== CHAR_BACKWARD_SLASH && + code !== CHAR_HASH && + code !== CHAR_QUESTION_MARK && + code !== CHAR_COLON); + + if (!isValid) { + // If leftover starts with :, then it represents an invalid port. + // But url.parse() is lenient about it for now. + // Issue a warning and continue. + if (warnInvalidPort && code === CHAR_COLON) { + const detail = `The URL ${url} is invalid. Future versions of Node.js will throw an error.`; + process.emitWarning(detail, 'DeprecationWarning', 'DEP0170'); + warnInvalidPort = false; + } + self.hostname = hostname.slice(0, i); + return `/${hostname.slice(i)}${rest}`; + } + } + return rest; +} + +// Escaped characters. Use empty strings to fill up unused entries. +// Using Array is faster than Object/Map +const escapedCodes = [ + /* 0 - 9 */ '', '', '', '', '', '', '', '', '', '%09', + /* 10 - 19 */ '%0A', '', '', '%0D', '', '', '', '', '', '', + /* 20 - 29 */ '', '', '', '', '', '', '', '', '', '', + /* 30 - 39 */ '', '', '%20', '', '%22', '', '', '', '', '%27', + /* 40 - 49 */ '', '', '', '', '', '', '', '', '', '', + /* 50 - 59 */ '', '', '', '', '', '', '', '', '', '', + /* 60 - 69 */ '%3C', '', '%3E', '', '', '', '', '', '', '', + /* 70 - 79 */ '', '', '', '', '', '', '', '', '', '', + /* 80 - 89 */ '', '', '', '', '', '', '', '', '', '', + /* 90 - 99 */ '', '', '%5C', '', '%5E', '', '%60', '', '', '', + /* 100 - 109 */ '', '', '', '', '', '', '', '', '', '', + /* 110 - 119 */ '', '', '', '', '', '', '', '', '', '', + /* 120 - 125 */ '', '', '', '%7B', '%7C', '%7D', +]; + +// Automatically escape all delimiters and unwise characters from RFC 2396. +// Also escape single quotes in case of an XSS attack. +// Return the escaped string. +function autoEscapeStr(rest) { + let escaped = ''; + let lastEscapedPos = 0; + for (let i = 0; i < rest.length; ++i) { + // `escaped` contains substring up to the last escaped character. + const escapedChar = escapedCodes[rest.charCodeAt(i)]; + if (escapedChar) { + // Concat if there are ordinary characters in the middle. + if (i > lastEscapedPos) + escaped += rest.slice(lastEscapedPos, i); + escaped += escapedChar; + lastEscapedPos = i + 1; + } + } + if (lastEscapedPos === 0) // Nothing has been escaped. + return rest; + + // There are ordinary characters at the end. + if (lastEscapedPos < rest.length) + escaped += rest.slice(lastEscapedPos); + + return escaped; +} + +// Format a parsed object into a url string +function urlFormat(urlObject, options) { + // Ensure it's an object, and not a string url. + // If it's an object, this is a no-op. + // this way, you can call urlParse() on strings + // to clean up potentially wonky urls. + if (typeof urlObject === 'string') { + urlObject = urlParse(urlObject); + } else if (typeof urlObject !== 'object' || urlObject === null) { + throw new ERR_INVALID_ARG_TYPE('urlObject', + ['Object', 'string'], urlObject); + } else if (urlObject instanceof URL) { + let fragment = true; + let unicode = false; + let search = true; + let auth = true; + + if (options) { + validateObject(options, 'options'); + + if (options.fragment != null) { + fragment = Boolean(options.fragment); + } + + if (options.unicode != null) { + unicode = Boolean(options.unicode); + } + + if (options.search != null) { + search = Boolean(options.search); + } + + if (options.auth != null) { + auth = Boolean(options.auth); + } + } + + return bindingUrl.format(urlObject.href, fragment, unicode, search, auth); + } + + return Url.prototype.format.call(urlObject); +} + +// These characters do not need escaping: +// ! - . _ ~ +// ' ( ) * : +// digits +// alpha (uppercase) +// alpha (lowercase) +const noEscapeAuth = new Int8Array([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00 - 0x0F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 - 0x1F + 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, // 0x20 - 0x2F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 0x30 - 0x3F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 0x4F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 0x50 - 0x5F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 0x70 - 0x7F +]); + +Url.prototype.format = function format() { + let auth = this.auth || ''; + if (auth) { + auth = encodeStr(auth, noEscapeAuth, hexTable); + auth += '@'; + } + + let protocol = this.protocol || ''; + if (protocol && StringPrototypeCharCodeAt(protocol, protocol.length - 1) !== 58 /* : */) { + protocol += ':'; + } + + let pathname = this.pathname || ''; + let hash = this.hash || ''; + let host = ''; + let query = ''; + + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + ( + StringPrototypeIndexOf(this.hostname, ':') !== -1 && !isIpv6Hostname(this.hostname) ? + '[' + this.hostname + ']' : + this.hostname + ); + if (this.port) { + host += ':' + this.port; + } + } + + if (this.query !== null && typeof this.query === 'object') { + query = querystring.stringify(this.query); + } + let search = this.search || (query && ('?' + query)) || ''; + + if (StringPrototypeIndexOf(pathname, '#') !== -1 || StringPrototypeIndexOf(pathname, '?') !== -1) { + let newPathname = ''; + let lastPos = 0; + const len = pathname.length; + for (let i = 0; i < len; i++) { + const code = StringPrototypeCharCodeAt(pathname, i); + if (code === CHAR_HASH || code === CHAR_QUESTION_MARK) { + if (i > lastPos) { + newPathname += StringPrototypeSlice(pathname, lastPos, i); + } + newPathname += (code === CHAR_HASH ? '%23' : '%3F'); + lastPos = i + 1; + } + } + if (lastPos < len) { + newPathname += StringPrototypeSlice(pathname, lastPos); + } + pathname = newPathname; + } + + // Only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + // unless they had them to begin with. + if (this.slashes || slashedProtocol.has(protocol)) { + if (this.slashes || host) { + if (pathname && StringPrototypeCharCodeAt(pathname, 0) !== CHAR_FORWARD_SLASH) + pathname = '/' + pathname; + host = '//' + host; + } else if (protocol.length >= 4 && + StringPrototypeCharCodeAt(protocol, 0) === 102/* f */ && + StringPrototypeCharCodeAt(protocol, 1) === 105/* i */ && + StringPrototypeCharCodeAt(protocol, 2) === 108/* l */ && + StringPrototypeCharCodeAt(protocol, 3) === 101/* e */) { + host = '//'; + } + } + + // Escape '#' in search. + if (StringPrototypeIndexOf(search, '#') !== -1) { + search = StringPrototypeReplaceAll(search, '#', '%23'); + } + + if (hash && StringPrototypeCharCodeAt(hash, 0) !== CHAR_HASH) { + hash = '#' + hash; + } + if (search && StringPrototypeCharCodeAt(search, 0) !== CHAR_QUESTION_MARK) { + search = '?' + search; + } + + return protocol + host + pathname + search + hash; +}; + +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} + +Url.prototype.resolve = function resolve(relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; + +function urlResolveObject(source, relative) { + if (!source) return relative; + return urlParse(source, false, true).resolveObject(relative); +} + +Url.prototype.resolveObject = function resolveObject(relative) { + if (typeof relative === 'string') { + const rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + + const result = new Url(); + ObjectAssign(result, this); + + // Hash is always overridden, no matter what. + // even href="" will remove it. + result.hash = relative.hash; + + // If the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } + + // Hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // Take everything except the protocol from relative + const relativeWithoutProtocol = ObjectKeys(relative).reduce((acc, key) => { + if (key !== 'protocol') { + acc[key] = relative[key]; + } + return acc; + }, {}); + ObjectAssign(result, relativeWithoutProtocol); + + // urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol.has(result.protocol) && + result.hostname && !result.pathname) { + result.path = result.pathname = '/'; + } + + result.href = result.format(); + return result; + } + + if (relative.protocol && relative.protocol !== result.protocol) { + // If it's a known url protocol, then changing + // the protocol does weird things + // first, if it's not file:, then we MUST have a host, + // and if there was a path + // to begin with, then we MUST have a path. + // if it is file:, then the host is dropped, + // because that's known to be hostless. + // anything else is assumed to be absolute. + if (!slashedProtocol.has(relative.protocol)) { + ObjectAssign(result, relative); + result.href = result.format(); + return result; + } + + result.protocol = relative.protocol; + if (!relative.host && + !/^file:?$/.test(relative.protocol) && + !hostlessProtocol.has(relative.protocol)) { + const relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())); + relative.host ||= ''; + relative.hostname ||= ''; + if (relPath[0] !== '') relPath.unshift(''); + if (relPath.length < 2) relPath.unshift(''); + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // To support http.request + if (result.pathname || result.search) { + const p = result.pathname || ''; + const s = result.search || ''; + result.path = p + s; + } + result.slashes ||= relative.slashes; + result.href = result.format(); + return result; + } + + const isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'); + const isRelAbs = ( + relative.host || (relative.pathname && relative.pathname.charAt(0) === '/') + ); + let mustEndAbs = (isRelAbs || isSourceAbs || + (result.host && relative.pathname)); + const removeAllDots = mustEndAbs; + let srcPath = (result.pathname && result.pathname.split('/')) || []; + const relPath = (relative.pathname && relative.pathname.split('/')) || []; + const noLeadingSlashes = result.protocol && + !slashedProtocol.has(result.protocol); + + // If the url is a non-slashed url, then relative + // links like ../.. should be able + // to crawl up to the hostname, as well. This is strange. + // result.protocol has already been set by now. + // Later on, put the first path part into the host field. + if (noLeadingSlashes) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') srcPath[0] = result.host; + else srcPath.unshift(result.host); + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + result.auth = null; + if (relative.host) { + if (relPath[0] === '') relPath[0] = relative.host; + else relPath.unshift(relative.host); + } + relative.host = null; + } + mustEndAbs &&= (relPath[0] === '' || srcPath[0] === ''); + } + + if (isRelAbs) { + // it's absolute. + if (relative.host || relative.host === '') { + if (result.host !== relative.host) result.auth = null; + result.host = relative.host; + result.port = relative.port; + } + if (relative.hostname || relative.hostname === '') { + if (result.hostname !== relative.hostname) result.auth = null; + result.hostname = relative.hostname; + } + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // Fall through to the dot-handling below. + } else if (relPath.length) { + // it's relative + // throw away the existing file, and take the new path instead. + srcPath ||= []; + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (relative.search !== null && relative.search !== undefined) { + // Just pull out the search. + // like href='?foo'. + // Put this after the other two cases because it simplifies the booleans + if (noLeadingSlashes) { + result.hostname = result.host = srcPath.shift(); + // Occasionally the auth can get stuck only in host. + // This especially happens in cases like + // url.resolveObject('mailto:local1@domain1', 'local2@domain2') + const authInHost = + result.host && result.host.indexOf('@') > 0 && result.host.split('@'); + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + result.search = relative.search; + result.query = relative.query; + // To support http.request + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } + + if (!srcPath.length) { + // No path at all. All other things were already handled above. + result.pathname = null; + // To support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } + + // If a url ENDs in . or .., then it must get a trailing slash. + // however, if it ends in anything else non-slashy, + // then it must NOT get a trailing slash. + let last = srcPath[srcPath.length - 1]; + const hasTrailingSlash = ( + ((result.host || relative.host || srcPath.length > 1) && + (last === '.' || last === '..')) || last === ''); + + // Strip single dots, resolve double dots to parent dir + // if the path tries to go above the root, `up` ends up > 0 + let up = 0; + for (let i = srcPath.length - 1; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + spliceOne(srcPath, i); + } else if (last === '..') { + spliceOne(srcPath, i); + up++; + } else if (up) { + spliceOne(srcPath, i); + up--; + } + } + + // If the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + while (up--) { + srcPath.unshift('..'); + } + } + + if (mustEndAbs && srcPath[0] !== '' && + (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + + if (hasTrailingSlash && StringPrototypeAt(ArrayPrototypeJoin(srcPath, '/'), -1) !== '/') { + srcPath.push(''); + } + + const isAbsolute = srcPath[0] === '' || + (srcPath[0] && srcPath[0].charAt(0) === '/'); + + // put the host back + if (noLeadingSlashes) { + result.hostname = + result.host = isAbsolute ? '' : srcPath.length ? srcPath.shift() : ''; + // Occasionally the auth can get stuck only in host. + // This especially happens in cases like + // url.resolveObject('mailto:local1@domain1', 'local2@domain2') + const authInHost = result.host && result.host.indexOf('@') > 0 ? + result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.host = result.hostname = authInHost.shift(); + } + } + + mustEndAbs ||= (result.host && srcPath.length); + + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + + if (!srcPath.length) { + result.pathname = null; + result.path = null; + } else { + result.pathname = srcPath.join('/'); + } + + // To support request.http + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes ||= relative.slashes; + result.href = result.format(); + return result; +}; + +Url.prototype.parseHost = function parseHost() { + let host = this.host; + let port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.slice(1); + } + host = host.slice(0, host.length - port.length); + } + if (host) this.hostname = host; +}; + +// When used internally, we are not obligated to associate TypeError with +// this function, so non-strings can be rejected by underlying implementation. +// Public API has to validate input and throw appropriate error. +function pathToFileURL(path, options) { + validateString(path, 'path'); + + return _pathToFileURL(path, options); +} + +module.exports = { + // Original API + Url, + parse: urlParse, + resolve: urlResolve, + resolveObject: urlResolveObject, + format: urlFormat, + + // WHATWG API + URL, + URLPattern, + URLSearchParams, + domainToASCII, + domainToUnicode, + + // Utilities + pathToFileURL, + fileURLToPath, + fileURLToPathBuffer, + urlToHttpOptions, +}; \ No newline at end of file diff --git a/.codesandbox/node/util.js b/.codesandbox/node/util.js new file mode 100644 index 00000000..d458b0a2 --- /dev/null +++ b/.codesandbox/node/util.js @@ -0,0 +1,521 @@ +'use strict'; + +const { + ArrayIsArray, + ArrayPrototypePop, + ArrayPrototypePush, + ArrayPrototypeReduce, + Error, + ErrorCaptureStackTrace, + FunctionPrototypeBind, + NumberIsSafeInteger, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectGetOwnPropertyDescriptors, + ObjectKeys, + ObjectSetPrototypeOf, + ObjectValues, + ReflectApply, + RegExp, + RegExpPrototypeSymbolReplace, + StringPrototypeToWellFormed, +} = primordials; + +const { + ErrnoException, + ExceptionWithHostPort, + codes: { + ERR_FALSY_VALUE_REJECTION, + ERR_INVALID_ARG_TYPE, + ERR_OUT_OF_RANGE, + }, + isErrorStackTraceLimitWritable, +} = require('internal/errors'); +const { + format, + formatWithOptions, + inspect, + stripVTControlCharacters, +} = require('internal/util/inspect'); +const { debuglog } = require('internal/util/debuglog'); +const { + validateBoolean, + validateFunction, + validateNumber, + validateString, + validateOneOf, + validateObject, +} = require('internal/validators'); +const { + isReadableStream, + isWritableStream, + isNodeStream, +} = require('internal/streams/utils'); +const types = require('internal/util/types'); + +let utilColors; +function lazyUtilColors() { + utilColors ??= require('internal/util/colors'); + return utilColors; +} +const { getOptionValue } = require('internal/options'); + +const binding = internalBinding('util'); + +const { + deprecate, + getLazy, + getSystemErrorMap, + getSystemErrorName: internalErrorName, + getSystemErrorMessage: internalErrorMessage, + promisify, + defineLazyProperties, +} = require('internal/util'); + +let abortController; + +function lazyAbortController() { + abortController ??= require('internal/abort_controller'); + return abortController; +} + +let internalDeepEqual; + +/** + * @param {string} [code] + * @returns {string} + */ +function escapeStyleCode(code) { + if (code === undefined) return ''; + return `\u001b[${code}m`; +} + +/** + * @param {string | string[]} format + * @param {string} text + * @param {object} [options] + * @param {boolean} [options.validateStream] - Whether to validate the stream. + * @param {Stream} [options.stream] - The stream used for validation. + * @returns {string} + */ +function styleText(format, text, { validateStream = true, stream = process.stdout } = {}) { + validateString(text, 'text'); + validateBoolean(validateStream, 'options.validateStream'); + + let skipColorize; + if (validateStream) { + if ( + !isReadableStream(stream) && + !isWritableStream(stream) && + !isNodeStream(stream) + ) { + throw new ERR_INVALID_ARG_TYPE('stream', ['ReadableStream', 'WritableStream', 'Stream'], stream); + } + + // If the stream is falsy or should not be colorized, set skipColorize to true + skipColorize = !lazyUtilColors().shouldColorize(stream); + } + + // If the format is not an array, convert it to an array + const formatArray = ArrayIsArray(format) ? format : [format]; + + const codes = []; + for (const key of formatArray) { + if (key === 'none') continue; + const formatCodes = inspect.colors[key]; + // If the format is not a valid style, throw an error + if (formatCodes == null) { + validateOneOf(key, 'format', ObjectKeys(inspect.colors)); + } + if (skipColorize) continue; + ArrayPrototypePush(codes, formatCodes); + } + + if (skipColorize) { + return text; + } + + // Build opening codes + let openCodes = ''; + for (let i = 0; i < codes.length; i++) { + openCodes += escapeStyleCode(codes[i][0]); + } + + // Process the text to handle nested styles + let processedText; + if (codes.length > 0) { + processedText = ArrayPrototypeReduce( + codes, + (text, code) => RegExpPrototypeSymbolReplace( + // Find the reset code + new RegExp(`\\u001b\\[${code[1]}m`, 'g'), + text, + (match, offset) => { + // Check if there's more content after this reset + if (offset + match.length < text.length) { + if ( + code[0] === inspect.colors.dim[0] || + code[0] === inspect.colors.bold[0] + ) { + // Dim and bold are not mutually exclusive, so we need to reapply + return `${match}${escapeStyleCode(code[0])}`; + } + return escapeStyleCode(code[0]); + } + return match; + }, + ), + text, + ); + } else { + processedText = text; + } + + // Build closing codes in reverse order + let closeCodes = ''; + for (let i = codes.length - 1; i >= 0; i--) { + closeCodes += escapeStyleCode(codes[i][1]); + } + + return `${openCodes}${processedText}${closeCodes}`; +} + +/** + * Inherit the prototype methods from one constructor into another. + * + * The Function.prototype.inherits from lang.js rewritten as a standalone + * function (not on Function.prototype). NOTE: If this file is to be loaded + * during bootstrapping this function needs to be rewritten using some native + * functions as prototype setup using normal JavaScript does not work as + * expected during bootstrapping (see mirror.js in r114903). + * @param {Function} ctor Constructor function which needs to inherit the + * prototype. + * @param {Function} superCtor Constructor function to inherit prototype from. + * @throws {TypeError} Will error if either constructor is null, or if + * the super constructor lacks a prototype. + */ +function inherits(ctor, superCtor) { + + if (ctor === undefined || ctor === null) + throw new ERR_INVALID_ARG_TYPE('ctor', 'Function', ctor); + + if (superCtor === undefined || superCtor === null) + throw new ERR_INVALID_ARG_TYPE('superCtor', 'Function', superCtor); + + if (superCtor.prototype === undefined) { + throw new ERR_INVALID_ARG_TYPE('superCtor.prototype', + 'Object', superCtor.prototype); + } + ObjectDefineProperty(ctor, 'super_', { + __proto__: null, + value: superCtor, + writable: true, + configurable: true, + }); + ObjectSetPrototypeOf(ctor.prototype, superCtor.prototype); +} + +/** + * @deprecated since v6.0.0 + * @template T + * @template S + * @param {T} target + * @param {S} source + * @returns {(T & S) | null} + */ +function _extend(target, source) { + // Don't do anything if source isn't an object + if (source === null || typeof source !== 'object') return target; + + const keys = ObjectKeys(source); + let i = keys.length; + while (i--) { + target[keys[i]] = source[keys[i]]; + } + return target; +} + +const callbackifyOnRejected = (reason, cb) => { + // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M). + // Because `null` is a special error value in callbacks which means "no error + // occurred", we error-wrap so the callback consumer can distinguish between + // "the promise rejected with null" or "the promise fulfilled with undefined". + if (!reason) { + reason = new ERR_FALSY_VALUE_REJECTION.HideStackFramesError(reason); + ErrorCaptureStackTrace(reason, callbackifyOnRejected); + } + return cb(reason); +}; + +/** + * Converts a Promise-returning function to callback style + * @param {Function} original + * @returns {Function} + */ +function callbackify(original) { + validateFunction(original, 'original'); + + // We DO NOT return the promise as it gives the user a false sense that + // the promise is actually somehow related to the callback's execution + // and that the callback throwing will reject the promise. + function callbackified(...args) { + const maybeCb = ArrayPrototypePop(args); + validateFunction(maybeCb, 'last argument'); + const cb = FunctionPrototypeBind(maybeCb, this); + // In true node style we process the callback on `nextTick` with all the + // implications (stack, `uncaughtException`, `async_hooks`) + ReflectApply(original, this, args) + .then((ret) => process.nextTick(cb, null, ret), + (rej) => process.nextTick(callbackifyOnRejected, rej, cb)); + } + + const descriptors = ObjectGetOwnPropertyDescriptors(original); + // It is possible to manipulate a functions `length` or `name` property. This + // guards against the manipulation. + if (typeof descriptors.length.value === 'number') { + descriptors.length.value++; + } + if (typeof descriptors.name.value === 'string') { + descriptors.name.value += 'Callbackified'; + } + const propertiesValues = ObjectValues(descriptors); + for (let i = 0; i < propertiesValues.length; i++) { + // We want to use null-prototype objects to not rely on globally mutable + // %Object.prototype%. + ObjectSetPrototypeOf(propertiesValues[i], null); + } + ObjectDefineProperties(callbackified, descriptors); + return callbackified; +} + +/** + * @param {number} err + * @returns {string} + */ +function getSystemErrorMessage(err) { + validateNumber(err, 'err'); + if (err >= 0 || !NumberIsSafeInteger(err)) { + throw new ERR_OUT_OF_RANGE('err', 'a negative integer', err); + } + return internalErrorMessage(err); +} + +/** + * @param {number} err + * @returns {string} + */ +function getSystemErrorName(err) { + validateNumber(err, 'err'); + if (err >= 0 || !NumberIsSafeInteger(err)) { + throw new ERR_OUT_OF_RANGE('err', 'a negative integer', err); + } + return internalErrorName(err); +} + +function _errnoException(...args) { + if (isErrorStackTraceLimitWritable()) { + const limit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + const e = new ErrnoException(...args); + Error.stackTraceLimit = limit; + ErrorCaptureStackTrace(e, _exceptionWithHostPort); + return e; + } + return new ErrnoException(...args); +} + +function _exceptionWithHostPort(...args) { + if (isErrorStackTraceLimitWritable()) { + const limit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + const e = new ExceptionWithHostPort(...args); + Error.stackTraceLimit = limit; + ErrorCaptureStackTrace(e, _exceptionWithHostPort); + return e; + } + return new ExceptionWithHostPort(...args); +} + +/** + * Parses the content of a `.env` file. + * @param {string} content + * @returns {Record} + */ +function parseEnv(content) { + validateString(content, 'content'); + return binding.parseEnv(content); +} + +const lazySourceMap = getLazy(() => require('internal/source_map/source_map_cache')); + +/** + * @typedef {object} CallSite // The call site + * @property {string} scriptName // The name of the resource that contains the + * script for the function for this StackFrame + * @property {string} functionName // The name of the function associated with this stack frame + * @property {number} lineNumber // The number, 1-based, of the line for the associate function call + * @property {number} columnNumber // The 1-based column offset on the line for the associated function call + */ + +/** + * @param {CallSite} callSite // The call site object to reconstruct from source map + * @returns {CallSite | undefined} // The reconstructed call site object + */ +function reconstructCallSite(callSite) { + const { scriptName, lineNumber, columnNumber } = callSite; + const sourceMap = lazySourceMap().findSourceMap(scriptName); + if (!sourceMap) return; + const entry = sourceMap.findEntry(lineNumber - 1, columnNumber - 1); + if (!entry?.originalSource) return; + return { + __proto__: null, + // If the name is not found, it is an empty string to match the behavior of `util.getCallSite()` + functionName: entry.name ?? '', + scriptName: entry.originalSource, + lineNumber: entry.originalLine + 1, + column: entry.originalColumn + 1, + columnNumber: entry.originalColumn + 1, + }; +} + +/** + * + * The call site array to map + * @param {CallSite[]} callSites + * Array of objects with the reconstructed call site + * @returns {CallSite[]} + */ +function mapCallSite(callSites) { + const result = []; + for (let i = 0; i < callSites.length; ++i) { + const callSite = callSites[i]; + const found = reconstructCallSite(callSite); + ArrayPrototypePush(result, found ?? callSite); + } + return result; +} + +/** + * @typedef {object} CallSiteOptions // The call site options + * @property {boolean} sourceMap // Enable source map support + */ + +/** + * Returns the callSite + * @param {number} frameCount + * @param {CallSiteOptions} options + * @returns {CallSite[]} + */ +function getCallSites(frameCount = 10, options) { + // If options is not provided check if frameCount is an object + if (options === undefined) { + if (typeof frameCount === 'object') { + // If frameCount is an object, it is the options object + options = frameCount; + validateObject(options, 'options'); + if (options.sourceMap !== undefined) { + validateBoolean(options.sourceMap, 'options.sourceMap'); + } + frameCount = 10; + } else { + // If options is not provided, set it to an empty object + options = {}; + }; + } else { + // If options is provided, validate it + validateObject(options, 'options'); + if (options.sourceMap !== undefined) { + validateBoolean(options.sourceMap, 'options.sourceMap'); + } + } + + // Using kDefaultMaxCallStackSizeToCapture as reference + validateNumber(frameCount, 'frameCount', 1, 200); + // If options.sourceMaps is true or if sourceMaps are enabled but the option.sourceMaps is not set explictly to false + if (options.sourceMap === true || (getOptionValue('--enable-source-maps') && options.sourceMap !== false)) { + return mapCallSite(binding.getCallSites(frameCount)); + } + return binding.getCallSites(frameCount); +}; + +// Keep the `exports =` so that various functions can still be monkeypatched +module.exports = { + _errnoException, + _exceptionWithHostPort, + _extend: deprecate(_extend, + 'The `util._extend` API is deprecated. Please use Object.assign() instead.', + 'DEP0060'), + callbackify, + debug: debuglog, + debuglog, + deprecate, + format, + styleText, + formatWithOptions, + // Deprecated getCallSite. + // This API can be removed in next semver-minor release. + getCallSite: deprecate(getCallSites, + 'The `util.getCallSite` API has been renamed to `util.getCallSites()`.', + 'ExperimentalWarning'), + getCallSites, + getSystemErrorMap, + getSystemErrorName, + getSystemErrorMessage, + inherits, + inspect, + isArray: deprecate(ArrayIsArray, + 'The `util.isArray` API is deprecated. Please use `Array.isArray()` instead.', + 'DEP0044'), + isDeepStrictEqual(a, b, skipPrototype) { + if (internalDeepEqual === undefined) { + internalDeepEqual = require('internal/util/comparisons').isDeepStrictEqual; + } + return internalDeepEqual(a, b, skipPrototype); + }, + promisify, + stripVTControlCharacters, + toUSVString(input) { + return StringPrototypeToWellFormed(`${input}`); + }, + get transferableAbortSignal() { + return lazyAbortController().transferableAbortSignal; + }, + get transferableAbortController() { + return lazyAbortController().transferableAbortController; + }, + get aborted() { + return lazyAbortController().aborted; + }, + types, + parseEnv, +}; + +defineLazyProperties( + module.exports, + 'internal/util/parse_args/parse_args', + ['parseArgs'], +); + +defineLazyProperties( + module.exports, + 'internal/encoding', + ['TextDecoder', 'TextEncoder'], +); + +defineLazyProperties( + module.exports, + 'internal/mime', + ['MIMEType', 'MIMEParams'], +); + +defineLazyProperties( + module.exports, + 'internal/util/diff', + ['diff'], +); + +defineLazyProperties( + module.exports, + 'internal/util/trace_sigint', + ['setTraceSigInt'], +); \ No newline at end of file diff --git a/.codesandbox/node/v8.js b/.codesandbox/node/v8.js new file mode 100644 index 00000000..556ab9c4 --- /dev/null +++ b/.codesandbox/node/v8.js @@ -0,0 +1,481 @@ +// Copyright (c) 2014, StrongLoop Inc. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +'use strict'; + +const { + Array, + BigInt64Array, + BigUint64Array, + DataView, + Error, + Float32Array, + Float64Array, + Int16Array, + Int32Array, + Int8Array, + JSONParse, + ObjectPrototypeToString, + Uint16Array, + Uint32Array, + Uint8Array, + Uint8ClampedArray, + globalThis: { + Float16Array, + }, +} = primordials; + +const { Buffer } = require('buffer'); +const { + validateString, + validateUint32, + validateOneOf, +} = require('internal/validators'); +const { + Serializer, + Deserializer, +} = internalBinding('serdes'); +const { + namespace: startupSnapshot, +} = require('internal/v8/startup_snapshot'); + +let profiler = {}; +if (internalBinding('config').hasInspector) { + profiler = internalBinding('profiler'); +} + +const assert = require('internal/assert'); +const { inspect } = require('internal/util/inspect'); +const { FastBuffer } = require('internal/buffer'); +const { getValidatedPath } = require('internal/fs/utils'); +const { + createHeapSnapshotStream, + triggerHeapSnapshot, +} = internalBinding('heap_utils'); +const { + HeapSnapshotStream, + getHeapSnapshotOptions, + queryObjects, +} = require('internal/heap_utils'); +const promiseHooks = require('internal/promise_hooks'); +const { getOptionValue } = require('internal/options'); + +/** + * Generates a snapshot of the current V8 heap + * and writes it to a JSON file. + * @param {string} [filename] + * @param {{ + * exposeInternals?: boolean, + * exposeNumericValues?: boolean + * }} [options] + * @returns {string} + */ +function writeHeapSnapshot(filename, options) { + if (filename !== undefined) { + filename = getValidatedPath(filename); + } + const optionArray = getHeapSnapshotOptions(options); + return triggerHeapSnapshot(filename, optionArray); +} + +/** + * Generates a snapshot of the current V8 heap + * and returns a Readable Stream. + * @param {{ + * exposeInternals?: boolean, + * exposeNumericValues?: boolean + * }} [options] + * @returns {import('./stream.js').Readable} + */ +function getHeapSnapshot(options) { + const optionArray = getHeapSnapshotOptions(options); + const handle = createHeapSnapshotStream(optionArray); + assert(handle); + return new HeapSnapshotStream(handle); +} + +// We need to get the buffer from the binding at the callsite since +// it's re-initialized after deserialization. +const binding = internalBinding('v8'); + +const { + cachedDataVersionTag, + setFlagsFromString: _setFlagsFromString, + isStringOneByteRepresentation: _isStringOneByteRepresentation, + updateHeapStatisticsBuffer, + updateHeapSpaceStatisticsBuffer, + updateHeapCodeStatisticsBuffer, + setHeapSnapshotNearHeapLimit: _setHeapSnapshotNearHeapLimit, + + // Properties for heap statistics buffer extraction. + kTotalHeapSizeIndex, + kTotalHeapSizeExecutableIndex, + kTotalPhysicalSizeIndex, + kTotalAvailableSize, + kUsedHeapSizeIndex, + kHeapSizeLimitIndex, + kDoesZapGarbageIndex, + kMallocedMemoryIndex, + kPeakMallocedMemoryIndex, + kNumberOfNativeContextsIndex, + kNumberOfDetachedContextsIndex, + kTotalGlobalHandlesSizeIndex, + kUsedGlobalHandlesSizeIndex, + kExternalMemoryIndex, + + // Properties for heap spaces statistics buffer extraction. + kHeapSpaces, + kSpaceSizeIndex, + kSpaceUsedSizeIndex, + kSpaceAvailableSizeIndex, + kPhysicalSpaceSizeIndex, + + // Properties for heap code statistics buffer extraction. + kCodeAndMetadataSizeIndex, + kBytecodeAndMetadataSizeIndex, + kExternalScriptSourceSizeIndex, + kCPUProfilerMetaDataSizeIndex, + + heapStatisticsBuffer, + heapCodeStatisticsBuffer, + heapSpaceStatisticsBuffer, + getCppHeapStatistics: _getCppHeapStatistics, + detailLevel, +} = binding; + +const kNumberOfHeapSpaces = kHeapSpaces.length; + +/** + * Sets V8 command-line flags. + * @param {string} flags + * @returns {void} + */ +function setFlagsFromString(flags) { + validateString(flags, 'flags'); + _setFlagsFromString(flags); +} + +/** + * Return whether this string uses one byte as underlying representation or not. + * @param {string} content + * @returns {boolean} + */ +function isStringOneByteRepresentation(content) { + validateString(content, 'content'); + return _isStringOneByteRepresentation(content); +} + + +/** + * Gets the current V8 heap statistics. + * @returns {{ + * total_heap_size: number; + * total_heap_size_executable: number; + * total_physical_size: number; + * total_available_size: number; + * used_heap_size: number; + * heap_size_limit: number; + * malloced_memory: number; + * peak_malloced_memory: number; + * does_zap_garbage: number; + * number_of_native_contexts: number; + * number_of_detached_contexts: number; + * }} + */ +function getHeapStatistics() { + const buffer = heapStatisticsBuffer; + + updateHeapStatisticsBuffer(); + + return { + total_heap_size: buffer[kTotalHeapSizeIndex], + total_heap_size_executable: buffer[kTotalHeapSizeExecutableIndex], + total_physical_size: buffer[kTotalPhysicalSizeIndex], + total_available_size: buffer[kTotalAvailableSize], + used_heap_size: buffer[kUsedHeapSizeIndex], + heap_size_limit: buffer[kHeapSizeLimitIndex], + malloced_memory: buffer[kMallocedMemoryIndex], + peak_malloced_memory: buffer[kPeakMallocedMemoryIndex], + does_zap_garbage: buffer[kDoesZapGarbageIndex], + number_of_native_contexts: buffer[kNumberOfNativeContextsIndex], + number_of_detached_contexts: buffer[kNumberOfDetachedContextsIndex], + total_global_handles_size: buffer[kTotalGlobalHandlesSizeIndex], + used_global_handles_size: buffer[kUsedGlobalHandlesSizeIndex], + external_memory: buffer[kExternalMemoryIndex], + }; +} + +/** + * Gets the current V8 heap space statistics. + * @returns {{ + * space_name: string; + * space_size: number; + * space_used_size: number; + * space_available_size: number; + * physical_space_size: number; + * }[]} + */ +function getHeapSpaceStatistics() { + const heapSpaceStatistics = new Array(kNumberOfHeapSpaces); + const buffer = heapSpaceStatisticsBuffer; + + for (let i = 0; i < kNumberOfHeapSpaces; i++) { + updateHeapSpaceStatisticsBuffer(i); + heapSpaceStatistics[i] = { + space_name: kHeapSpaces[i], + space_size: buffer[kSpaceSizeIndex], + space_used_size: buffer[kSpaceUsedSizeIndex], + space_available_size: buffer[kSpaceAvailableSizeIndex], + physical_space_size: buffer[kPhysicalSpaceSizeIndex], + }; + } + + return heapSpaceStatistics; +} + +/** + * Gets the current V8 heap code statistics. + * @returns {{ + * code_and_metadata_size: number; + * bytecode_and_metadata_size: number; + * external_script_source_size: number; + * cpu_profiler_metadata_size: number; + * }} + */ +function getHeapCodeStatistics() { + const buffer = heapCodeStatisticsBuffer; + + updateHeapCodeStatisticsBuffer(); + return { + code_and_metadata_size: buffer[kCodeAndMetadataSizeIndex], + bytecode_and_metadata_size: buffer[kBytecodeAndMetadataSizeIndex], + external_script_source_size: buffer[kExternalScriptSourceSizeIndex], + cpu_profiler_metadata_size: buffer[kCPUProfilerMetaDataSizeIndex], + }; +} + +let heapSnapshotNearHeapLimitCallbackAdded = false; +function setHeapSnapshotNearHeapLimit(limit) { + validateUint32(limit, 'limit', true); + if (heapSnapshotNearHeapLimitCallbackAdded || + getOptionValue('--heapsnapshot-near-heap-limit') > 0 + ) { + return; + } + heapSnapshotNearHeapLimitCallbackAdded = true; + _setHeapSnapshotNearHeapLimit(limit); +} + +const detailLevelDict = { + __proto__: null, + detailed: detailLevel.DETAILED, + brief: detailLevel.BRIEF, +}; + +function getCppHeapStatistics(type = 'detailed') { + validateOneOf(type, 'type', ['brief', 'detailed']); + const result = _getCppHeapStatistics(detailLevelDict[type]); + result.detail_level = type; + return result; +} + +/* V8 serialization API */ + +/* JS methods for the base objects */ +Serializer.prototype._getDataCloneError = Error; + +/** + * Reads raw bytes from the deserializer's internal buffer. + * @param {number} length + * @returns {Buffer} + */ +Deserializer.prototype.readRawBytes = function readRawBytes(length) { + const offset = this._readRawBytes(length); + // `this.buffer` can be a Buffer or a plain Uint8Array, so just calling + // `.slice()` doesn't work. + return new FastBuffer(this.buffer.buffer, + this.buffer.byteOffset + offset, + length); +}; + +function arrayBufferViewTypeToIndex(abView) { + const type = ObjectPrototypeToString(abView); + if (type === '[object Int8Array]') return 0; + if (type === '[object Uint8Array]') return 1; + if (type === '[object Uint8ClampedArray]') return 2; + if (type === '[object Int16Array]') return 3; + if (type === '[object Uint16Array]') return 4; + if (type === '[object Int32Array]') return 5; + if (type === '[object Uint32Array]') return 6; + if (type === '[object Float32Array]') return 7; + if (type === '[object Float64Array]') return 8; + if (type === '[object DataView]') return 9; + // Index 10 is FastBuffer. + if (type === '[object BigInt64Array]') return 11; + if (type === '[object BigUint64Array]') return 12; + if (type === '[object Float16Array]') return 13; + return -1; +} + +function arrayBufferViewIndexToType(index) { + if (index === 0) return Int8Array; + if (index === 1) return Uint8Array; + if (index === 2) return Uint8ClampedArray; + if (index === 3) return Int16Array; + if (index === 4) return Uint16Array; + if (index === 5) return Int32Array; + if (index === 6) return Uint32Array; + if (index === 7) return Float32Array; + if (index === 8) return Float64Array; + if (index === 9) return DataView; + if (index === 10) return FastBuffer; + if (index === 11) return BigInt64Array; + if (index === 12) return BigUint64Array; + if (index === 13) return Float16Array; + return undefined; +} + +class DefaultSerializer extends Serializer { + constructor() { + super(); + + this._setTreatArrayBufferViewsAsHostObjects(true); + } + + /** + * Used to write some kind of host object, i.e. an + * object that is created by native C++ bindings. + * @param {object} abView + * @returns {void} + */ + _writeHostObject(abView) { + // Keep track of how to handle different ArrayBufferViews. The default + // Serializer for Node does not use the V8 methods for serializing those + // objects because Node's `Buffer` objects use pooled allocation in many + // cases, and their underlying `ArrayBuffer`s would show up in the + // serialization. Because a) those may contain sensitive data and the user + // may not be aware of that and b) they are often much larger than the + // `Buffer` itself, custom serialization is applied. + let i = 10; // FastBuffer + if (abView.constructor !== Buffer) { + i = arrayBufferViewTypeToIndex(abView); + if (i === -1) { + throw new this._getDataCloneError( + `Unserializable host object: ${inspect(abView)}`); + } + } + this.writeUint32(i); + this.writeUint32(abView.byteLength); + this.writeRawBytes(new Uint8Array(abView.buffer, + abView.byteOffset, + abView.byteLength)); + } +} + +class DefaultDeserializer extends Deserializer { + /** + * Used to read some kind of host object, i.e. an + * object that is created by native C++ bindings. + * @returns {any} + */ + _readHostObject() { + const typeIndex = this.readUint32(); + const ctor = arrayBufferViewIndexToType(typeIndex); + const byteLength = this.readUint32(); + const byteOffset = this._readRawBytes(byteLength); + const BYTES_PER_ELEMENT = ctor.BYTES_PER_ELEMENT || 1; + + const offset = this.buffer.byteOffset + byteOffset; + if (offset % BYTES_PER_ELEMENT === 0) { + return new ctor(this.buffer.buffer, + offset, + byteLength / BYTES_PER_ELEMENT); + } + // Copy to an aligned buffer first. + const buffer_copy = Buffer.allocUnsafe(byteLength); + buffer_copy.set(new Uint8Array(this.buffer.buffer, this.buffer.byteOffset + byteOffset, byteLength)); + return new ctor(buffer_copy.buffer, + buffer_copy.byteOffset, + byteLength / BYTES_PER_ELEMENT); + } +} + +/** + * Uses a `DefaultSerializer` to serialize `value` + * into a buffer. + * @param {any} value + * @returns {Buffer} + */ +function serialize(value) { + const ser = new DefaultSerializer(); + ser.writeHeader(); + ser.writeValue(value); + return ser.releaseBuffer(); +} + +/** + * Uses a `DefaultDeserializer` with default options + * to read a JavaScript value from a buffer. + * @param {Buffer | TypedArray | DataView} buffer + * @returns {any} + */ +function deserialize(buffer) { + const der = new DefaultDeserializer(buffer); + der.readHeader(); + return der.readValue(); +} + +class GCProfiler { + #profiler = null; + + start() { + if (!this.#profiler) { + this.#profiler = new binding.GCProfiler(); + this.#profiler.start(); + } + } + + stop() { + if (this.#profiler) { + const data = this.#profiler.stop(); + this.#profiler = null; + return JSONParse(data); + } + } +} + +module.exports = { + cachedDataVersionTag, + getHeapSnapshot, + getHeapStatistics, + getHeapSpaceStatistics, + getHeapCodeStatistics, + getCppHeapStatistics, + setFlagsFromString, + Serializer, + Deserializer, + DefaultSerializer, + DefaultDeserializer, + deserialize, + takeCoverage: profiler.takeCoverage, + stopCoverage: profiler.stopCoverage, + serialize, + writeHeapSnapshot, + promiseHooks, + queryObjects, + startupSnapshot, + setHeapSnapshotNearHeapLimit, + GCProfiler, + isStringOneByteRepresentation, +}; \ No newline at end of file diff --git a/.codesandbox/node/vm.js b/.codesandbox/node/vm.js new file mode 100644 index 00000000..8b674831 --- /dev/null +++ b/.codesandbox/node/vm.js @@ -0,0 +1,655 @@ +<<<<<<< HEAD +'use strict'; +======= +"use strict"; +>>>>>>> refs/remotes/origin/master + +const { + ArrayPrototypeForEach, + ObjectFreeze, + PromiseReject, + ReflectApply, + Symbol, +} = primordials; + +const { + ContextifyScript, + makeContext, + constants, + measureMemory: _measureMemory, +<<<<<<< HEAD +} = internalBinding('contextify'); +const { + ERR_CONTEXT_NOT_INITIALIZED, + ERR_INVALID_ARG_TYPE, +} = require('internal/errors').codes; +======= +} = internalBinding("contextify"); +const { ERR_CONTEXT_NOT_INITIALIZED, ERR_INVALID_ARG_TYPE } = + require("internal/errors").codes; +>>>>>>> refs/remotes/origin/master +const { + validateArray, + validateBoolean, + validateBuffer, + validateInt32, + validateOneOf, + validateObject, + validateString, + validateStringArray, + validateUint32, + kValidateObjectAllowArray, + kValidateObjectAllowNullable, +<<<<<<< HEAD +} = require('internal/validators'); +======= +} = require("internal/validators"); +>>>>>>> refs/remotes/origin/master +const { + emitExperimentalWarning, + kEmptyObject, + kVmBreakFirstLineSymbol, +<<<<<<< HEAD +} = require('internal/util'); +======= +} = require("internal/util"); +>>>>>>> refs/remotes/origin/master +const { + getHostDefinedOptionId, + internalCompileFunction, + isContext: _isContext, + registerImportModuleDynamically, +<<<<<<< HEAD +} = require('internal/vm'); +const { + vm_dynamic_import_main_context_default, + vm_context_no_contextify, +} = internalBinding('symbols'); +const kParsingContext = Symbol('script parsing context'); +======= +} = require("internal/vm"); +const { vm_dynamic_import_main_context_default, vm_context_no_contextify } = + internalBinding("symbols"); +const kParsingContext = Symbol("script parsing context"); +>>>>>>> refs/remotes/origin/master + +/** + * Check if object is a context object created by vm.createContext(). + * @throws {TypeError} If object is not an object in the first place, throws TypeError. + * @param {object} object Object to check. + * @returns {boolean} + */ +function isContext(object) { +<<<<<<< HEAD + validateObject(object, 'object', kValidateObjectAllowArray); +======= + validateObject(object, "object", kValidateObjectAllowArray); +>>>>>>> refs/remotes/origin/master + + return _isContext(object); +} + +class Script extends ContextifyScript { + constructor(code, options = kEmptyObject) { + code = `${code}`; +<<<<<<< HEAD + if (typeof options === 'string') { + options = { filename: options }; + } else { + validateObject(options, 'options'); + } + + const { + filename = 'evalmachine.', +======= + if (typeof options === "string") { + options = { filename: options }; + } else { + validateObject(options, "options"); + } + + const { + filename = "evalmachine.", +>>>>>>> refs/remotes/origin/master + lineOffset = 0, + columnOffset = 0, + cachedData, + produceCachedData = false, + importModuleDynamically, + [kParsingContext]: parsingContext, + } = options; + +<<<<<<< HEAD + validateString(filename, 'options.filename'); + validateInt32(lineOffset, 'options.lineOffset'); + validateInt32(columnOffset, 'options.columnOffset'); + if (cachedData !== undefined) { + validateBuffer(cachedData, 'options.cachedData'); + } + validateBoolean(produceCachedData, 'options.produceCachedData'); + + const hostDefinedOptionId = + getHostDefinedOptionId(importModuleDynamically, filename); + // Calling `ReThrow()` on a native TryCatch does not generate a new + // abort-on-uncaught-exception check. A dummy try/catch in JS land + // protects against that. + try { // eslint-disable-line no-useless-catch + super(code, + filename, + lineOffset, + columnOffset, + cachedData, + produceCachedData, + parsingContext, + hostDefinedOptionId); +======= + validateString(filename, "options.filename"); + validateInt32(lineOffset, "options.lineOffset"); + validateInt32(columnOffset, "options.columnOffset"); + if (cachedData !== undefined) { + validateBuffer(cachedData, "options.cachedData"); + } + validateBoolean(produceCachedData, "options.produceCachedData"); + + const hostDefinedOptionId = getHostDefinedOptionId( + importModuleDynamically, + filename + ); + // Calling `ReThrow()` on a native TryCatch does not generate a new + // abort-on-uncaught-exception check. A dummy try/catch in JS land + // protects against that. + try { + // eslint-disable-line no-useless-catch + super( + code, + filename, + lineOffset, + columnOffset, + cachedData, + produceCachedData, + parsingContext, + hostDefinedOptionId + ); +>>>>>>> refs/remotes/origin/master + } catch (e) { + throw e; /* node-do-not-add-exception-line */ + } + + registerImportModuleDynamically(this, importModuleDynamically); + } + + runInThisContext(options) { + const { breakOnSigint, args } = getRunInContextArgs(null, options); +<<<<<<< HEAD + if (breakOnSigint && process.listenerCount('SIGINT') > 0) { +======= + if (breakOnSigint && process.listenerCount("SIGINT") > 0) { +>>>>>>> refs/remotes/origin/master + return sigintHandlersWrap(super.runInContext, this, args); + } + return ReflectApply(super.runInContext, this, args); + } + + runInContext(contextifiedObject, options) { + validateContext(contextifiedObject); + const { breakOnSigint, args } = getRunInContextArgs( + contextifiedObject, +<<<<<<< HEAD + options, + ); + if (breakOnSigint && process.listenerCount('SIGINT') > 0) { +======= + options + ); + if (breakOnSigint && process.listenerCount("SIGINT") > 0) { +>>>>>>> refs/remotes/origin/master + return sigintHandlersWrap(super.runInContext, this, args); + } + return ReflectApply(super.runInContext, this, args); + } + + runInNewContext(contextObject, options) { + const context = createContext(contextObject, getContextOptions(options)); + return this.runInContext(context, options); + } +} + +function validateContext(contextifiedObject) { + if (!isContext(contextifiedObject)) { +<<<<<<< HEAD + throw new ERR_INVALID_ARG_TYPE('contextifiedObject', 'vm.Context', + contextifiedObject); +======= + throw new ERR_INVALID_ARG_TYPE( + "contextifiedObject", + "vm.Context", + contextifiedObject + ); +>>>>>>> refs/remotes/origin/master + } +} + +function getRunInContextArgs(contextifiedObject, options = kEmptyObject) { +<<<<<<< HEAD + validateObject(options, 'options'); +======= + validateObject(options, "options"); +>>>>>>> refs/remotes/origin/master + + let timeout = options.timeout; + if (timeout === undefined) { + timeout = -1; + } else { +<<<<<<< HEAD + validateUint32(timeout, 'options.timeout', true); +======= + validateUint32(timeout, "options.timeout", true); +>>>>>>> refs/remotes/origin/master + } + + const { + displayErrors = true, + breakOnSigint = false, + [kVmBreakFirstLineSymbol]: breakFirstLine = false, + } = options; + +<<<<<<< HEAD + validateBoolean(displayErrors, 'options.displayErrors'); + validateBoolean(breakOnSigint, 'options.breakOnSigint'); +======= + validateBoolean(displayErrors, "options.displayErrors"); + validateBoolean(breakOnSigint, "options.breakOnSigint"); +>>>>>>> refs/remotes/origin/master + + return { + breakOnSigint, + args: [ + contextifiedObject, + timeout, + displayErrors, + breakOnSigint, + breakFirstLine, + ], + }; +} + +function getContextOptions(options) { +<<<<<<< HEAD + if (!options) + return {}; +======= + if (!options) return {}; +>>>>>>> refs/remotes/origin/master + const contextOptions = { + name: options.contextName, + origin: options.contextOrigin, + codeGeneration: undefined, + microtaskMode: options.microtaskMode, + }; + if (contextOptions.name !== undefined) +<<<<<<< HEAD + validateString(contextOptions.name, 'options.contextName'); + if (contextOptions.origin !== undefined) + validateString(contextOptions.origin, 'options.contextOrigin'); + if (options.contextCodeGeneration !== undefined) { + validateObject(options.contextCodeGeneration, + 'options.contextCodeGeneration'); + const { strings, wasm } = options.contextCodeGeneration; + if (strings !== undefined) + validateBoolean(strings, 'options.contextCodeGeneration.strings'); + if (wasm !== undefined) + validateBoolean(wasm, 'options.contextCodeGeneration.wasm'); + contextOptions.codeGeneration = { strings, wasm }; + } + if (options.microtaskMode !== undefined) + validateString(options.microtaskMode, 'options.microtaskMode'); +======= + validateString(contextOptions.name, "options.contextName"); + if (contextOptions.origin !== undefined) + validateString(contextOptions.origin, "options.contextOrigin"); + if (options.contextCodeGeneration !== undefined) { + validateObject( + options.contextCodeGeneration, + "options.contextCodeGeneration" + ); + const { strings, wasm } = options.contextCodeGeneration; + if (strings !== undefined) + validateBoolean(strings, "options.contextCodeGeneration.strings"); + if (wasm !== undefined) + validateBoolean(wasm, "options.contextCodeGeneration.wasm"); + contextOptions.codeGeneration = { strings, wasm }; + } + if (options.microtaskMode !== undefined) + validateString(options.microtaskMode, "options.microtaskMode"); +>>>>>>> refs/remotes/origin/master + return contextOptions; +} + +let defaultContextNameIndex = 1; +function createContext(contextObject = {}, options = kEmptyObject) { + if (contextObject !== vm_context_no_contextify && isContext(contextObject)) { + return contextObject; + } + +<<<<<<< HEAD + validateObject(options, 'options'); +======= + validateObject(options, "options"); +>>>>>>> refs/remotes/origin/master + + const { + name = `VM Context ${defaultContextNameIndex++}`, + origin, + codeGeneration, + microtaskMode, + importModuleDynamically, + } = options; + +<<<<<<< HEAD + validateString(name, 'options.name'); + if (origin !== undefined) + validateString(origin, 'options.origin'); + if (codeGeneration !== undefined) + validateObject(codeGeneration, 'options.codeGeneration'); +======= + validateString(name, "options.name"); + if (origin !== undefined) validateString(origin, "options.origin"); + if (codeGeneration !== undefined) + validateObject(codeGeneration, "options.codeGeneration"); +>>>>>>> refs/remotes/origin/master + + let strings = true; + let wasm = true; + if (codeGeneration !== undefined) { + ({ strings = true, wasm = true } = codeGeneration); +<<<<<<< HEAD + validateBoolean(strings, 'options.codeGeneration.strings'); + validateBoolean(wasm, 'options.codeGeneration.wasm'); + } + + validateOneOf(microtaskMode, + 'options.microtaskMode', + ['afterEvaluate', undefined]); + const microtaskQueue = (microtaskMode === 'afterEvaluate'); + + const hostDefinedOptionId = + getHostDefinedOptionId(importModuleDynamically, name); + + const result = makeContext(contextObject, name, origin, strings, wasm, microtaskQueue, hostDefinedOptionId); +======= + validateBoolean(strings, "options.codeGeneration.strings"); + validateBoolean(wasm, "options.codeGeneration.wasm"); + } + + validateOneOf(microtaskMode, "options.microtaskMode", [ + "afterEvaluate", + undefined, + ]); + const microtaskQueue = microtaskMode === "afterEvaluate"; + + const hostDefinedOptionId = getHostDefinedOptionId( + importModuleDynamically, + name + ); + + const result = makeContext( + contextObject, + name, + origin, + strings, + wasm, + microtaskQueue, + hostDefinedOptionId + ); +>>>>>>> refs/remotes/origin/master + // Register the context scope callback after the context was initialized. + registerImportModuleDynamically(result, importModuleDynamically); + return result; +} + +function createScript(code, options) { + return new Script(code, options); +} + +// Remove all SIGINT listeners and re-attach them after the wrapped function +// has executed, so that caught SIGINT are handled by the listeners again. +function sigintHandlersWrap(fn, thisArg, argsArray) { +<<<<<<< HEAD + const sigintListeners = process.rawListeners('SIGINT'); + + process.removeAllListeners('SIGINT'); +======= + const sigintListeners = process.rawListeners("SIGINT"); + + process.removeAllListeners("SIGINT"); +>>>>>>> refs/remotes/origin/master + + try { + return ReflectApply(fn, thisArg, argsArray); + } finally { + // Add using the public methods so that the `newListener` handler of + // process can re-attach the listeners. + ArrayPrototypeForEach(sigintListeners, (listener) => { +<<<<<<< HEAD + process.addListener('SIGINT', listener); +======= + process.addListener("SIGINT", listener); +>>>>>>> refs/remotes/origin/master + }); + } +} + +function runInContext(code, contextifiedObject, options) { + validateContext(contextifiedObject); +<<<<<<< HEAD + if (typeof options === 'string') { +======= + if (typeof options === "string") { +>>>>>>> refs/remotes/origin/master + options = { + filename: options, + [kParsingContext]: contextifiedObject, + }; + } else { + options = { ...options, [kParsingContext]: contextifiedObject }; + } +<<<<<<< HEAD + return createScript(code, options) + .runInContext(contextifiedObject, options); +} + +function runInNewContext(code, contextObject, options) { + if (typeof options === 'string') { +======= + return createScript(code, options).runInContext(contextifiedObject, options); +} + +function runInNewContext(code, contextObject, options) { + if (typeof options === "string") { +>>>>>>> refs/remotes/origin/master + options = { filename: options }; + } + contextObject = createContext(contextObject, getContextOptions(options)); + options = { ...options, [kParsingContext]: contextObject }; + return createScript(code, options).runInNewContext(contextObject, options); +} + +function runInThisContext(code, options) { +<<<<<<< HEAD + if (typeof options === 'string') { +======= + if (typeof options === "string") { +>>>>>>> refs/remotes/origin/master + options = { filename: options }; + } + return createScript(code, options).runInThisContext(options); +} + +function compileFunction(code, params, options = kEmptyObject) { +<<<<<<< HEAD + validateString(code, 'code'); + validateObject(options, 'options'); + if (params !== undefined) { + validateStringArray(params, 'params'); + } + const { + filename = '', +======= + validateString(code, "code"); + validateObject(options, "options"); + if (params !== undefined) { + validateStringArray(params, "params"); + } + const { + filename = "", +>>>>>>> refs/remotes/origin/master + columnOffset = 0, + lineOffset = 0, + cachedData = undefined, + produceCachedData = false, + parsingContext = undefined, + contextExtensions = [], + importModuleDynamically, + } = options; + +<<<<<<< HEAD + validateString(filename, 'options.filename'); + validateInt32(columnOffset, 'options.columnOffset'); + validateInt32(lineOffset, 'options.lineOffset'); + if (cachedData !== undefined) + validateBuffer(cachedData, 'options.cachedData'); + validateBoolean(produceCachedData, 'options.produceCachedData'); + if (parsingContext !== undefined) { + if ( + typeof parsingContext !== 'object' || +======= + validateString(filename, "options.filename"); + validateInt32(columnOffset, "options.columnOffset"); + validateInt32(lineOffset, "options.lineOffset"); + if (cachedData !== undefined) + validateBuffer(cachedData, "options.cachedData"); + validateBoolean(produceCachedData, "options.produceCachedData"); + if (parsingContext !== undefined) { + if ( + typeof parsingContext !== "object" || +>>>>>>> refs/remotes/origin/master + parsingContext === null || + !isContext(parsingContext) + ) { + throw new ERR_INVALID_ARG_TYPE( +<<<<<<< HEAD + 'options.parsingContext', + 'Context', + parsingContext, + ); + } + } + validateArray(contextExtensions, 'options.contextExtensions'); +======= + "options.parsingContext", + "Context", + parsingContext + ); + } + } + validateArray(contextExtensions, "options.contextExtensions"); +>>>>>>> refs/remotes/origin/master + ArrayPrototypeForEach(contextExtensions, (extension, i) => { + const name = `options.contextExtensions[${i}]`; + validateObject(extension, name, kValidateObjectAllowNullable); + }); + +<<<<<<< HEAD + const hostDefinedOptionId = + getHostDefinedOptionId(importModuleDynamically, filename); + + return internalCompileFunction( + code, filename, lineOffset, columnOffset, + cachedData, produceCachedData, parsingContext, contextExtensions, + params, hostDefinedOptionId, importModuleDynamically, +======= + const hostDefinedOptionId = getHostDefinedOptionId( + importModuleDynamically, + filename + ); + + return internalCompileFunction( + code, + filename, + lineOffset, + columnOffset, + cachedData, + produceCachedData, + parsingContext, + contextExtensions, + params, + hostDefinedOptionId, + importModuleDynamically +>>>>>>> refs/remotes/origin/master + ).function; +} + +const measureMemoryModes = { + summary: constants.measureMemory.mode.SUMMARY, + detailed: constants.measureMemory.mode.DETAILED, +}; + +const measureMemoryExecutions = { + default: constants.measureMemory.execution.DEFAULT, + eager: constants.measureMemory.execution.EAGER, +}; + +function measureMemory(options = kEmptyObject) { +<<<<<<< HEAD + emitExperimentalWarning('vm.measureMemory'); + validateObject(options, 'options'); + const { mode = 'summary', execution = 'default' } = options; + validateOneOf(mode, 'options.mode', ['summary', 'detailed']); + validateOneOf(execution, 'options.execution', ['default', 'eager']); + const result = _measureMemory(measureMemoryModes[mode], + measureMemoryExecutions[execution]); +======= + emitExperimentalWarning("vm.measureMemory"); + validateObject(options, "options"); + const { mode = "summary", execution = "default" } = options; + validateOneOf(mode, "options.mode", ["summary", "detailed"]); + validateOneOf(execution, "options.execution", ["default", "eager"]); + const result = _measureMemory( + measureMemoryModes[mode], + measureMemoryExecutions[execution] + ); +>>>>>>> refs/remotes/origin/master + if (result === undefined) { + return PromiseReject(new ERR_CONTEXT_NOT_INITIALIZED()); + } + return result; +} + +const vmConstants = { + __proto__: null, + USE_MAIN_CONTEXT_DEFAULT_LOADER: vm_dynamic_import_main_context_default, + DONT_CONTEXTIFY: vm_context_no_contextify, +}; + +ObjectFreeze(vmConstants); + +module.exports = { + Script, + createContext, + createScript, + runInContext, + runInNewContext, + runInThisContext, + isContext, + compileFunction, + measureMemory, + constants: vmConstants, +}; + +// The vm module is patched to include vm.Module, vm.SourceTextModule +// and vm.SyntheticModule in the pre-execution phase when +<<<<<<< HEAD +// --experimental-vm-modules is on. +======= +// --experimental-vm-modules is on. +>>>>>>> refs/remotes/origin/master diff --git a/.codesandbox/node/wasi.js b/.codesandbox/node/wasi.js new file mode 100644 index 00000000..71dbc60a --- /dev/null +++ b/.codesandbox/node/wasi.js @@ -0,0 +1,176 @@ +'use strict'; +const { + ArrayPrototypeForEach, + ArrayPrototypeMap, + ArrayPrototypePush, + FunctionPrototypeBind, + ObjectEntries, + String, + Symbol, +} = primordials; + +const { + ERR_INVALID_ARG_VALUE, + ERR_WASI_ALREADY_STARTED, +} = require('internal/errors').codes; +const { + emitExperimentalWarning, + kEmptyObject, +} = require('internal/util'); +const { + validateArray, + validateBoolean, + validateFunction, + validateInt32, + validateObject, + validateString, + validateUndefined, +} = require('internal/validators'); +const kExitCode = Symbol('kExitCode'); +const kSetMemory = Symbol('kSetMemory'); +const kStarted = Symbol('kStarted'); +const kInstance = Symbol('kInstance'); +const kBindingName = Symbol('kBindingName'); + +emitExperimentalWarning('WASI'); + +class WASI { + constructor(options = kEmptyObject) { + validateObject(options, 'options'); + + let _WASI; + validateString(options.version, 'options.version'); + switch (options.version) { + case 'unstable': + ({ WASI: _WASI } = internalBinding('wasi')); + this[kBindingName] = 'wasi_unstable'; + break; + case 'preview1': + ({ WASI: _WASI } = internalBinding('wasi')); + this[kBindingName] = 'wasi_snapshot_preview1'; + break; + // When adding support for additional wasi versions add case here + default: + throw new ERR_INVALID_ARG_VALUE('options.version', + options.version, + 'unsupported WASI version'); + } + + if (options.args !== undefined) + validateArray(options.args, 'options.args'); + const args = ArrayPrototypeMap(options.args || [], String); + + const env = []; + if (options.env !== undefined) { + validateObject(options.env, 'options.env'); + ArrayPrototypeForEach( + ObjectEntries(options.env), + ({ 0: key, 1: value }) => { + if (value !== undefined) + ArrayPrototypePush(env, `${key}=${value}`); + }); + } + + const preopens = []; + if (options.preopens !== undefined) { + validateObject(options.preopens, 'options.preopens'); + ArrayPrototypeForEach( + ObjectEntries(options.preopens), + ({ 0: key, 1: value }) => + ArrayPrototypePush(preopens, String(key), String(value)), + ); + } + + const { stdin = 0, stdout = 1, stderr = 2 } = options; + validateInt32(stdin, 'options.stdin', 0); + validateInt32(stdout, 'options.stdout', 0); + validateInt32(stderr, 'options.stderr', 0); + const stdio = [stdin, stdout, stderr]; + + const wrap = new _WASI(args, env, preopens, stdio); + + for (const prop in wrap) { + wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap); + } + + let returnOnExit = true; + if (options.returnOnExit !== undefined) { + validateBoolean(options.returnOnExit, 'options.returnOnExit'); + returnOnExit = options.returnOnExit; + } + if (returnOnExit) + wrap.proc_exit = FunctionPrototypeBind(wasiReturnOnProcExit, this); + + this[kSetMemory] = wrap._setMemory; + delete wrap._setMemory; + this.wasiImport = wrap; + this[kStarted] = false; + this[kExitCode] = 0; + this[kInstance] = undefined; + } + + finalizeBindings(instance, { + memory = instance?.exports?.memory, + } = {}) { + if (this[kStarted]) { + throw new ERR_WASI_ALREADY_STARTED(); + } + + validateObject(instance, 'instance'); + validateObject(instance.exports, 'instance.exports'); + + this[kSetMemory](memory); + + this[kInstance] = instance; + this[kStarted] = true; + } + + // Must not export _initialize, must export _start + start(instance) { + this.finalizeBindings(instance); + + const { _start, _initialize } = this[kInstance].exports; + + validateFunction(_start, 'instance.exports._start'); + validateUndefined(_initialize, 'instance.exports._initialize'); + + try { + _start(); + } catch (err) { + if (err !== kExitCode) { + throw err; + } + } + + return this[kExitCode]; + } + + // Must not export _start, may optionally export _initialize + initialize(instance) { + this.finalizeBindings(instance); + + const { _start, _initialize } = this[kInstance].exports; + + validateUndefined(_start, 'instance.exports._start'); + if (_initialize !== undefined) { + validateFunction(_initialize, 'instance.exports._initialize'); + _initialize(); + } + } + + getImportObject() { + return { [this[kBindingName]]: this.wasiImport }; + } +} + +module.exports = { WASI }; + + +function wasiReturnOnProcExit(rval) { + // If __wasi_proc_exit() does not terminate the process, an assertion is + // triggered in the wasm runtime. Node can sidestep the assertion and return + // an exit code by recording the exit code, and throwing a JavaScript + // exception that WebAssembly cannot catch. + this[kExitCode] = rval; + throw kExitCode; +} \ No newline at end of file diff --git a/.codesandbox/node/worker_pool.js b/.codesandbox/node/worker_pool.js new file mode 100644 index 00000000..bc0e59c7 --- /dev/null +++ b/.codesandbox/node/worker_pool.js @@ -0,0 +1,13 @@ +const WorkerPool = require('./worker_pool.js'); +const os = require('node:os'); + +const pool = new WorkerPool(os.availableParallelism()); + +let finished = 0; +for (let i = 0; i < 10; i++) { + pool.runTask({ a: 42, b: 100 }, (err, result) => { + console.log(i, err, result); + if (++finished === 10) + pool.close(); + }); +} \ No newline at end of file diff --git a/.codesandbox/node/worker_threads.js b/.codesandbox/node/worker_threads.js new file mode 100644 index 00000000..a8e42ebb --- /dev/null +++ b/.codesandbox/node/worker_threads.js @@ -0,0 +1,81 @@ +<<<<<<< HEAD +'use strict'; +======= +"use strict"; +>>>>>>> refs/remotes/origin/master + +const { + isInternalThread, + isMainThread, + SHARE_ENV, + resourceLimits, + setEnvironmentData, + getEnvironmentData, + threadId, + threadName, + Worker, +<<<<<<< HEAD +} = require('internal/worker'); +======= +} = require("internal/worker"); +>>>>>>> refs/remotes/origin/master + +const { + MessagePort, + MessageChannel, + markAsUncloneable, + moveMessagePortToContext, + receiveMessageOnPort, + BroadcastChannel, +<<<<<<< HEAD +} = require('internal/worker/io'); + +const { + postMessageToThread, +} = require('internal/worker/messaging'); +======= +} = require("internal/worker/io"); + +const { postMessageToThread } = require("internal/worker/messaging"); +>>>>>>> refs/remotes/origin/master + +const { + markAsUntransferable, + isMarkedAsUntransferable, +<<<<<<< HEAD +} = require('internal/buffer'); + +const { locks } = require('internal/locks'); +======= +} = require("internal/buffer"); + +const { locks } = require("internal/locks"); +>>>>>>> refs/remotes/origin/master + +module.exports = { + isInternalThread, + isMainThread, + MessagePort, + MessageChannel, + markAsUncloneable, + markAsUntransferable, + isMarkedAsUntransferable, + moveMessagePortToContext, + receiveMessageOnPort, + resourceLimits, + postMessageToThread, + threadId, + threadName, + SHARE_ENV, + Worker, + parentPort: null, + workerData: null, + BroadcastChannel, + setEnvironmentData, + getEnvironmentData, + locks, +<<<<<<< HEAD +}; +======= +}; +>>>>>>> refs/remotes/origin/master diff --git a/.codesandbox/node/zlib.js b/.codesandbox/node/zlib.js new file mode 100644 index 00000000..666aac34 --- /dev/null +++ b/.codesandbox/node/zlib.js @@ -0,0 +1,1543 @@ +<<<<<<< HEAD +'use strict'; +======= +"use strict"; +>>>>>>> refs/remotes/origin/master + +const { + ArrayBuffer, + MathMax, + NumberIsNaN, + ObjectDefineProperties, + ObjectDefineProperty, + ObjectEntries, + ObjectFreeze, + ObjectKeys, + ObjectSetPrototypeOf, + ReflectApply, + Symbol, + Uint32Array, +} = primordials; + +const { + codes: { + ERR_BROTLI_INVALID_PARAM, + ERR_BUFFER_TOO_LARGE, + ERR_INVALID_ARG_TYPE, + ERR_OUT_OF_RANGE, + ERR_TRAILING_JUNK_AFTER_STREAM_END, + ERR_ZSTD_INVALID_PARAM, + }, + genericNodeError, +<<<<<<< HEAD +} = require('internal/errors'); +const { Transform, finished } = require('stream'); +const { + deprecateInstantiation, +} = require('internal/util'); +======= +} = require("internal/errors"); +const { Transform, finished } = require("stream"); +const { deprecateInstantiation } = require("internal/util"); +>>>>>>> refs/remotes/origin/master +const { + isArrayBufferView, + isAnyArrayBuffer, + isUint8Array, +<<<<<<< HEAD +} = require('internal/util/types'); +const binding = internalBinding('zlib'); +const { crc32: crc32Native } = binding; +const assert = require('internal/assert'); +const { + Buffer, + kMaxLength, +} = require('buffer'); +const { owner_symbol } = require('internal/async_hooks').symbols; +======= +} = require("internal/util/types"); +const binding = internalBinding("zlib"); +const { crc32: crc32Native } = binding; +const assert = require("internal/assert"); +const { Buffer, kMaxLength } = require("buffer"); +const { owner_symbol } = require("internal/async_hooks").symbols; +>>>>>>> refs/remotes/origin/master +const { + checkRangesOrGetDefault, + validateFunction, + validateUint32, + validateFiniteNumber, +<<<<<<< HEAD +} = require('internal/validators'); + +const kFlushFlag = Symbol('kFlushFlag'); +const kError = Symbol('kError'); + +const constants = internalBinding('constants').zlib; +const { + // Zlib flush levels + Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH, + // Zlib option values + Z_MIN_CHUNK, Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_MIN_LEVEL, Z_MAX_LEVEL, + Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_CHUNK, Z_DEFAULT_COMPRESSION, + Z_DEFAULT_STRATEGY, Z_DEFAULT_WINDOWBITS, Z_DEFAULT_MEMLEVEL, Z_FIXED, + // Node's compression stream modes (node_zlib_mode) + DEFLATE, DEFLATERAW, INFLATE, INFLATERAW, GZIP, GUNZIP, UNZIP, + BROTLI_DECODE, BROTLI_ENCODE, + ZSTD_COMPRESS, ZSTD_DECOMPRESS, + // Brotli operations (~flush levels) + BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_FLUSH, + BROTLI_OPERATION_FINISH, BROTLI_OPERATION_EMIT_METADATA, + // Zstd end directives (~flush levels) + ZSTD_e_continue, ZSTD_e_flush, ZSTD_e_end, +======= +} = require("internal/validators"); + +const kFlushFlag = Symbol("kFlushFlag"); +const kError = Symbol("kError"); + +const constants = internalBinding("constants").zlib; +const { + // Zlib flush levels + Z_NO_FLUSH, + Z_BLOCK, + Z_PARTIAL_FLUSH, + Z_SYNC_FLUSH, + Z_FULL_FLUSH, + Z_FINISH, + // Zlib option values + Z_MIN_CHUNK, + Z_MIN_WINDOWBITS, + Z_MAX_WINDOWBITS, + Z_MIN_LEVEL, + Z_MAX_LEVEL, + Z_MIN_MEMLEVEL, + Z_MAX_MEMLEVEL, + Z_DEFAULT_CHUNK, + Z_DEFAULT_COMPRESSION, + Z_DEFAULT_STRATEGY, + Z_DEFAULT_WINDOWBITS, + Z_DEFAULT_MEMLEVEL, + Z_FIXED, + // Node's compression stream modes (node_zlib_mode) + DEFLATE, + DEFLATERAW, + INFLATE, + INFLATERAW, + GZIP, + GUNZIP, + UNZIP, + BROTLI_DECODE, + BROTLI_ENCODE, + ZSTD_COMPRESS, + ZSTD_DECOMPRESS, + // Brotli operations (~flush levels) + BROTLI_OPERATION_PROCESS, + BROTLI_OPERATION_FLUSH, + BROTLI_OPERATION_FINISH, + BROTLI_OPERATION_EMIT_METADATA, + // Zstd end directives (~flush levels) + ZSTD_e_continue, + ZSTD_e_flush, + ZSTD_e_end, +>>>>>>> refs/remotes/origin/master +} = constants; + +// Translation table for return codes. +const codes = { + Z_OK: constants.Z_OK, + Z_STREAM_END: constants.Z_STREAM_END, + Z_NEED_DICT: constants.Z_NEED_DICT, + Z_ERRNO: constants.Z_ERRNO, + Z_STREAM_ERROR: constants.Z_STREAM_ERROR, + Z_DATA_ERROR: constants.Z_DATA_ERROR, + Z_MEM_ERROR: constants.Z_MEM_ERROR, + Z_BUF_ERROR: constants.Z_BUF_ERROR, + Z_VERSION_ERROR: constants.Z_VERSION_ERROR, +}; + +for (const ckey of ObjectKeys(codes)) { + codes[codes[ckey]] = ckey; +} + +function zlibBuffer(engine, buffer, callback) { +<<<<<<< HEAD + validateFunction(callback, 'callback'); +======= + validateFunction(callback, "callback"); +>>>>>>> refs/remotes/origin/master + // Streams do not support non-Uint8Array ArrayBufferViews yet. Convert it to a + // Buffer without copying. + if (isArrayBufferView(buffer) && !isUint8Array(buffer)) { + buffer = Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength); + } else if (isAnyArrayBuffer(buffer)) { + buffer = Buffer.from(buffer); + } + engine.buffers = null; + engine.nread = 0; + engine.cb = callback; +<<<<<<< HEAD + engine.on('data', zlibBufferOnData); + engine.on('error', zlibBufferOnError); + engine.on('end', zlibBufferOnEnd); +======= + engine.on("data", zlibBufferOnData); + engine.on("error", zlibBufferOnError); + engine.on("end", zlibBufferOnEnd); +>>>>>>> refs/remotes/origin/master + engine.end(buffer); +} + +function zlibBufferOnData(chunk) { + if (!this.buffers) { + this.buffers = [chunk]; + } else { + this.buffers.push(chunk); + } + this.nread += chunk.length; + if (this.nread > this._maxOutputLength) { + this.close(); +<<<<<<< HEAD + this.removeAllListeners('end'); +======= + this.removeAllListeners("end"); +>>>>>>> refs/remotes/origin/master + this.cb(new ERR_BUFFER_TOO_LARGE(this._maxOutputLength)); + } +} + +function zlibBufferOnError(err) { +<<<<<<< HEAD + this.removeAllListeners('end'); +======= + this.removeAllListeners("end"); +>>>>>>> refs/remotes/origin/master + this.cb(err); +} + +function zlibBufferOnEnd() { + let buf; + if (this.nread === 0) { + buf = Buffer.alloc(0); + } else { + const bufs = this.buffers; +<<<<<<< HEAD + buf = (bufs.length === 1 ? bufs[0] : Buffer.concat(bufs, this.nread)); + } + this.close(); + if (this._info) + this.cb(null, { buffer: buf, engine: this }); + else + this.cb(null, buf); +} + +function zlibBufferSync(engine, buffer) { + if (typeof buffer === 'string') { +======= + buf = bufs.length === 1 ? bufs[0] : Buffer.concat(bufs, this.nread); + } + this.close(); + if (this._info) this.cb(null, { buffer: buf, engine: this }); + else this.cb(null, buf); +} + +function zlibBufferSync(engine, buffer) { + if (typeof buffer === "string") { +>>>>>>> refs/remotes/origin/master + buffer = Buffer.from(buffer); + } else if (!isArrayBufferView(buffer)) { + if (isAnyArrayBuffer(buffer)) { + buffer = Buffer.from(buffer); + } else { + throw new ERR_INVALID_ARG_TYPE( +<<<<<<< HEAD + 'buffer', + ['string', 'Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'], + buffer, +======= + "buffer", + ["string", "Buffer", "TypedArray", "DataView", "ArrayBuffer"], + buffer +>>>>>>> refs/remotes/origin/master + ); + } + } + buffer = processChunkSync(engine, buffer, engine._finishFlushFlag); +<<<<<<< HEAD + if (engine._info) + return { buffer, engine }; +======= + if (engine._info) return { buffer, engine }; +>>>>>>> refs/remotes/origin/master + return buffer; +} + +function zlibOnError(message, errno, code) { + const self = this[owner_symbol]; + // There is no way to cleanly recover. + // Continuing only obscures problems. + + const error = genericNodeError(message, { errno, code }); + error.errno = errno; + error.code = code; + self.destroy(error); + self[kError] = error; +} + +const FLUSH_BOUND = [ +<<<<<<< HEAD + [ Z_NO_FLUSH, Z_BLOCK ], + [ BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_EMIT_METADATA ], + [ ZSTD_e_continue, ZSTD_e_end ], +======= + [Z_NO_FLUSH, Z_BLOCK], + [BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_EMIT_METADATA], + [ZSTD_e_continue, ZSTD_e_end], +>>>>>>> refs/remotes/origin/master +]; +const FLUSH_BOUND_IDX_NORMAL = 0; +const FLUSH_BOUND_IDX_BROTLI = 1; +const FLUSH_BOUND_IDX_ZSTD = 2; + +/** + * The base class for all Zlib-style streams. + * @class + */ +function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) { + let chunkSize = Z_DEFAULT_CHUNK; + let maxOutputLength = kMaxLength; + // The ZlibBase class is not exported to user land, the mode should only be + // passed in by us. +<<<<<<< HEAD + assert(typeof mode === 'number'); +======= + assert(typeof mode === "number"); +>>>>>>> refs/remotes/origin/master + assert(mode >= DEFLATE && mode <= ZSTD_DECOMPRESS); + + let flushBoundIdx; + if (mode === BROTLI_ENCODE || mode === BROTLI_DECODE) { + flushBoundIdx = FLUSH_BOUND_IDX_BROTLI; + } else if (mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS) { + flushBoundIdx = FLUSH_BOUND_IDX_ZSTD; + } else { + flushBoundIdx = FLUSH_BOUND_IDX_NORMAL; + } + + if (opts) { + chunkSize = opts.chunkSize; +<<<<<<< HEAD + if (!validateFiniteNumber(chunkSize, 'options.chunkSize')) { + chunkSize = Z_DEFAULT_CHUNK; + } else if (chunkSize < Z_MIN_CHUNK) { + throw new ERR_OUT_OF_RANGE('options.chunkSize', + `>= ${Z_MIN_CHUNK}`, chunkSize); + } + + flush = checkRangesOrGetDefault( + opts.flush, 'options.flush', + FLUSH_BOUND[flushBoundIdx][0], FLUSH_BOUND[flushBoundIdx][1], flush); + + finishFlush = checkRangesOrGetDefault( + opts.finishFlush, 'options.finishFlush', + FLUSH_BOUND[flushBoundIdx][0], FLUSH_BOUND[flushBoundIdx][1], + finishFlush); + + maxOutputLength = checkRangesOrGetDefault( + opts.maxOutputLength, 'options.maxOutputLength', + 1, kMaxLength, kMaxLength); +======= + if (!validateFiniteNumber(chunkSize, "options.chunkSize")) { + chunkSize = Z_DEFAULT_CHUNK; + } else if (chunkSize < Z_MIN_CHUNK) { + throw new ERR_OUT_OF_RANGE( + "options.chunkSize", + `>= ${Z_MIN_CHUNK}`, + chunkSize + ); + } + + flush = checkRangesOrGetDefault( + opts.flush, + "options.flush", + FLUSH_BOUND[flushBoundIdx][0], + FLUSH_BOUND[flushBoundIdx][1], + flush + ); + + finishFlush = checkRangesOrGetDefault( + opts.finishFlush, + "options.finishFlush", + FLUSH_BOUND[flushBoundIdx][0], + FLUSH_BOUND[flushBoundIdx][1], + finishFlush + ); + + maxOutputLength = checkRangesOrGetDefault( + opts.maxOutputLength, + "options.maxOutputLength", + 1, + kMaxLength, + kMaxLength + ); +>>>>>>> refs/remotes/origin/master + + if (opts.encoding || opts.objectMode || opts.writableObjectMode) { + opts = { ...opts }; + opts.encoding = null; + opts.objectMode = false; + opts.writableObjectMode = false; + } + } + + ReflectApply(Transform, this, [{ autoDestroy: true, ...opts }]); + this[kError] = null; + this.bytesWritten = 0; + this._handle = handle; + handle[owner_symbol] = this; + // Used by processCallback() and zlibOnError() + handle.onerror = zlibOnError; + this._outBuffer = Buffer.allocUnsafe(chunkSize); + this._outOffset = 0; + + this._chunkSize = chunkSize; + this._defaultFlushFlag = flush; + this._finishFlushFlag = finishFlush; + this._defaultFullFlushFlag = fullFlush; + this._info = opts?.info; + this._maxOutputLength = maxOutputLength; + + this._rejectGarbageAfterEnd = opts?.rejectGarbageAfterEnd === true; +} +ObjectSetPrototypeOf(ZlibBase.prototype, Transform.prototype); +ObjectSetPrototypeOf(ZlibBase, Transform); + +<<<<<<< HEAD +ObjectDefineProperty(ZlibBase.prototype, '_closed', { +======= +ObjectDefineProperty(ZlibBase.prototype, "_closed", { +>>>>>>> refs/remotes/origin/master + __proto__: null, + configurable: true, + enumerable: true, + get() { + return !this._handle; + }, +}); + +/** + * @this {ZlibBase} + * @returns {void} + */ +<<<<<<< HEAD +ZlibBase.prototype.reset = function() { + assert(this._handle, 'zlib binding closed'); +======= +ZlibBase.prototype.reset = function () { + assert(this._handle, "zlib binding closed"); +>>>>>>> refs/remotes/origin/master + return this._handle.reset(); +}; + +/** + * @this {ZlibBase} + * This is the _flush function called by the transform class, + * internally, when the last chunk has been written. + * @returns {void} + */ +<<<<<<< HEAD +ZlibBase.prototype._flush = function(callback) { + this._transform(Buffer.alloc(0), '', callback); +======= +ZlibBase.prototype._flush = function (callback) { + this._transform(Buffer.alloc(0), "", callback); +>>>>>>> refs/remotes/origin/master +}; + +/** + * @this {ZlibBase} + * Force Transform compat behavior. + * @returns {void} + */ +<<<<<<< HEAD +ZlibBase.prototype._final = function(callback) { +======= +ZlibBase.prototype._final = function (callback) { +>>>>>>> refs/remotes/origin/master + callback(); +}; + +// If a flush is scheduled while another flush is still pending, a way to figure +// out which one is the "stronger" flush is needed. +// This is currently only used to figure out which flush flag to use for the +// last chunk. +// Roughly, the following holds: +// Z_NO_FLUSH < Z_BLOCK < Z_PARTIAL_FLUSH < +// Z_SYNC_FLUSH < Z_FULL_FLUSH < Z_FINISH +const flushiness = []; +<<<<<<< HEAD +const kFlushFlagList = [Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, + Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH]; +======= +const kFlushFlagList = [ + Z_NO_FLUSH, + Z_BLOCK, + Z_PARTIAL_FLUSH, + Z_SYNC_FLUSH, + Z_FULL_FLUSH, + Z_FINISH, +]; +>>>>>>> refs/remotes/origin/master +for (let i = 0; i < kFlushFlagList.length; i++) { + flushiness[kFlushFlagList[i]] = i; +} + +function maxFlush(a, b) { + return flushiness[a] > flushiness[b] ? a : b; +} + +// Set up a list of 'special' buffers that can be written using .write() +// from the .flush() code as a way of introducing flushing operations into the +// write sequence. +const kFlushBuffers = []; +{ + const dummyArrayBuffer = new ArrayBuffer(); + for (const flushFlag of kFlushFlagList) { + kFlushBuffers[flushFlag] = Buffer.from(dummyArrayBuffer); + kFlushBuffers[flushFlag][kFlushFlag] = flushFlag; + } +} + +<<<<<<< HEAD +ZlibBase.prototype.flush = function(kind, callback) { + if (typeof kind === 'function' || (kind === undefined && !callback)) { +======= +ZlibBase.prototype.flush = function (kind, callback) { + if (typeof kind === "function" || (kind === undefined && !callback)) { +>>>>>>> refs/remotes/origin/master + callback = kind; + kind = this._defaultFullFlushFlag; + } + + if (this.writableFinished) { +<<<<<<< HEAD + if (callback) + process.nextTick(callback); + } else if (this.writableEnded) { + if (callback) + this.once('end', callback); + } else { + this.write(kFlushBuffers[kind], '', callback); +======= + if (callback) process.nextTick(callback); + } else if (this.writableEnded) { + if (callback) this.once("end", callback); + } else { + this.write(kFlushBuffers[kind], "", callback); +>>>>>>> refs/remotes/origin/master + } +}; + +/** + * @this {import('stream').Transform} + * @param {(err?: Error) => any} [callback] + */ +<<<<<<< HEAD +ZlibBase.prototype.close = function(callback) { +======= +ZlibBase.prototype.close = function (callback) { +>>>>>>> refs/remotes/origin/master + if (callback) finished(this, callback); + this.destroy(); +}; + +<<<<<<< HEAD +ZlibBase.prototype._destroy = function(err, callback) { +======= +ZlibBase.prototype._destroy = function (err, callback) { +>>>>>>> refs/remotes/origin/master + _close(this); + callback(err); +}; + +<<<<<<< HEAD +ZlibBase.prototype._transform = function(chunk, encoding, cb) { + let flushFlag = this._defaultFlushFlag; + // We use a 'fake' zero-length chunk to carry information about flushes from + // the public API to the actual stream implementation. + if (typeof chunk[kFlushFlag] === 'number') { +======= +ZlibBase.prototype._transform = function (chunk, encoding, cb) { + let flushFlag = this._defaultFlushFlag; + // We use a 'fake' zero-length chunk to carry information about flushes from + // the public API to the actual stream implementation. + if (typeof chunk[kFlushFlag] === "number") { +>>>>>>> refs/remotes/origin/master + flushFlag = chunk[kFlushFlag]; + } + + // For the last chunk, also apply `_finishFlushFlag`. + if (this.writableEnded && this.writableLength === chunk.byteLength) { + flushFlag = maxFlush(flushFlag, this._finishFlushFlag); + } + processChunk(this, chunk, flushFlag, cb); +}; + +<<<<<<< HEAD +ZlibBase.prototype._processChunk = function(chunk, flushFlag, cb) { + // _processChunk() is left for backwards compatibility + if (typeof cb === 'function') + processChunk(this, chunk, flushFlag, cb); + else + return processChunkSync(this, chunk, flushFlag); +======= +ZlibBase.prototype._processChunk = function (chunk, flushFlag, cb) { + // _processChunk() is left for backwards compatibility + if (typeof cb === "function") processChunk(this, chunk, flushFlag, cb); + else return processChunkSync(this, chunk, flushFlag); +>>>>>>> refs/remotes/origin/master +}; + +function processChunkSync(self, chunk, flushFlag) { + let availInBefore = chunk.byteLength; + let availOutBefore = self._chunkSize - self._outOffset; + let inOff = 0; + let availOutAfter; + let availInAfter; + + const buffers = []; + let nread = 0; + let inputRead = 0; + const state = self._writeState; + const handle = self._handle; + let buffer = self._outBuffer; + let offset = self._outOffset; + const chunkSize = self._chunkSize; + + let error; +<<<<<<< HEAD + self.on('error', function onError(er) { +======= + self.on("error", function onError(er) { +>>>>>>> refs/remotes/origin/master + error = er; + }); + + while (true) { +<<<<<<< HEAD + handle.writeSync(flushFlag, + chunk, // in + inOff, // in_off + availInBefore, // in_len + buffer, // out + offset, // out_off + availOutBefore); // out_len + if (error) + throw error; + else if (self[kError]) + throw self[kError]; +======= + handle.writeSync( + flushFlag, + chunk, // in + inOff, // in_off + availInBefore, // in_len + buffer, // out + offset, // out_off + availOutBefore + ); // out_len + if (error) throw error; + else if (self[kError]) throw self[kError]; +>>>>>>> refs/remotes/origin/master + + availOutAfter = state[0]; + availInAfter = state[1]; + +<<<<<<< HEAD + const inDelta = (availInBefore - availInAfter); +======= + const inDelta = availInBefore - availInAfter; +>>>>>>> refs/remotes/origin/master + inputRead += inDelta; + + const have = availOutBefore - availOutAfter; + if (have > 0) { + const out = buffer.slice(offset, offset + have); + offset += have; + buffers.push(out); + nread += out.byteLength; + + if (nread > self._maxOutputLength) { + _close(self); + throw new ERR_BUFFER_TOO_LARGE(self._maxOutputLength); + } +<<<<<<< HEAD + + } else { + assert(have === 0, 'have should not go down'); +======= + } else { + assert(have === 0, "have should not go down"); +>>>>>>> refs/remotes/origin/master + } + + // Exhausted the output buffer, or used all the input create a new one. + if (availOutAfter === 0 || offset >= chunkSize) { + availOutBefore = chunkSize; + offset = 0; + buffer = Buffer.allocUnsafe(chunkSize); + } + + if (availOutAfter === 0) { + // Not actually done. Need to reprocess. + // Also, update the availInBefore to the availInAfter value, + // so that if we have to hit it a third (fourth, etc.) time, + // it'll have the correct byte counts. + inOff += inDelta; + availInBefore = availInAfter; + } else { + break; + } + } + + self.bytesWritten = inputRead; + _close(self); + +<<<<<<< HEAD + if (nread === 0) + return Buffer.alloc(0); + + return (buffers.length === 1 ? buffers[0] : Buffer.concat(buffers, nread)); +======= + if (nread === 0) return Buffer.alloc(0); + + return buffers.length === 1 ? buffers[0] : Buffer.concat(buffers, nread); +>>>>>>> refs/remotes/origin/master +} + +function processChunk(self, chunk, flushFlag, cb) { + const handle = self._handle; + if (!handle) return process.nextTick(cb); + + handle.buffer = chunk; + handle.cb = cb; + handle.availOutBefore = self._chunkSize - self._outOffset; + handle.availInBefore = chunk.byteLength; + handle.inOff = 0; + handle.flushFlag = flushFlag; + +<<<<<<< HEAD + handle.write(flushFlag, + chunk, // in + 0, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + handle.availOutBefore); // out_len +======= + handle.write( + flushFlag, + chunk, // in + 0, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + handle.availOutBefore + ); // out_len +>>>>>>> refs/remotes/origin/master +} + +function processCallback() { + // This callback's context (`this`) is the `_handle` (ZCtx) object. It is + // important to null out the values once they are no longer needed since + // `_handle` can stay in memory long after the buffer is needed. + const handle = this; + const self = this[owner_symbol]; + const state = self._writeState; + + if (self.destroyed) { + this.buffer = null; + this.cb(); + return; + } + + const availOutAfter = state[0]; + const availInAfter = state[1]; + + const inDelta = handle.availInBefore - availInAfter; + self.bytesWritten += inDelta; + + const have = handle.availOutBefore - availOutAfter; + let streamBufferIsFull = false; + if (have > 0) { + const out = self._outBuffer.slice(self._outOffset, self._outOffset + have); + self._outOffset += have; + streamBufferIsFull = !self.push(out); + } else { +<<<<<<< HEAD + assert(have === 0, 'have should not go down'); +======= + assert(have === 0, "have should not go down"); +>>>>>>> refs/remotes/origin/master + } + + if (self.destroyed) { + this.cb(); + return; + } + + // Exhausted the output buffer, or used all the input create a new one. + if (availOutAfter === 0 || self._outOffset >= self._chunkSize) { + handle.availOutBefore = self._chunkSize; + self._outOffset = 0; + self._outBuffer = Buffer.allocUnsafe(self._chunkSize); + } + + if (availOutAfter === 0) { + // Not actually done. Need to reprocess. + // Also, update the availInBefore to the availInAfter value, + // so that if we have to hit it a third (fourth, etc.) time, + // it'll have the correct byte counts. + handle.inOff += inDelta; + handle.availInBefore = availInAfter; + +<<<<<<< HEAD + + if (!streamBufferIsFull) { + this.write(handle.flushFlag, + this.buffer, // in + handle.inOff, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + self._chunkSize); // out_len +======= + if (!streamBufferIsFull) { + this.write( + handle.flushFlag, + this.buffer, // in + handle.inOff, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + self._chunkSize + ); // out_len +>>>>>>> refs/remotes/origin/master + } else { + const oldRead = self._read; + self._read = (n) => { + self._read = oldRead; +<<<<<<< HEAD + this.write(handle.flushFlag, + this.buffer, // in + handle.inOff, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + self._chunkSize); // out_len +======= + this.write( + handle.flushFlag, + this.buffer, // in + handle.inOff, // in_off + handle.availInBefore, // in_len + self._outBuffer, // out + self._outOffset, // out_off + self._chunkSize + ); // out_len +>>>>>>> refs/remotes/origin/master + self._read(n); + }; + } + return; + } + + if (availInAfter > 0) { + // If we have more input that should be written, but we also have output + // space available, that means that the compression library was not + // interested in receiving more data, and in particular that the input + // stream has ended early. + // This applies to streams where we don't check data past the end of + // what was consumed; that is, everything except Gunzip/Unzip. + + if (self._rejectGarbageAfterEnd) { + const err = new ERR_TRAILING_JUNK_AFTER_STREAM_END(); + self.destroy(err); + this.cb(err); + return; + } + + self.push(null); + } + + // Finished with the chunk. + this.buffer = null; + this.cb(); +} + +/** + * @param {ZlibBase} engine + * @private + */ +function _close(engine) { + // Caller may invoke .close after a zlib error (which will null _handle) + engine._handle?.close(); + engine._handle = null; +} + +const zlibDefaultOpts = { + flush: Z_NO_FLUSH, + finishFlush: Z_FINISH, + fullFlush: Z_FULL_FLUSH, +}; +// Base class for all streams actually backed by zlib and using zlib-specific +// parameters. +function Zlib(opts, mode) { + let windowBits = Z_DEFAULT_WINDOWBITS; + let level = Z_DEFAULT_COMPRESSION; + let memLevel = Z_DEFAULT_MEMLEVEL; + let strategy = Z_DEFAULT_STRATEGY; + let dictionary; + + if (opts) { + // windowBits is special. On the compression side, 0 is an invalid value. + // But on the decompression side, a value of 0 for windowBits tells zlib + // to use the window size in the zlib header of the compressed stream. +<<<<<<< HEAD + if ((opts.windowBits == null || opts.windowBits === 0) && + (mode === INFLATE || + mode === GUNZIP || + mode === UNZIP)) { +======= + if ( + (opts.windowBits == null || opts.windowBits === 0) && + (mode === INFLATE || mode === GUNZIP || mode === UNZIP) + ) { +>>>>>>> refs/remotes/origin/master + windowBits = 0; + } else { + // `{ windowBits: 8 }` is valid for deflate but not gzip. + const min = Z_MIN_WINDOWBITS + (mode === GZIP ? 1 : 0); + windowBits = checkRangesOrGetDefault( +<<<<<<< HEAD + opts.windowBits, 'options.windowBits', + min, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS); + } + + level = checkRangesOrGetDefault( + opts.level, 'options.level', + Z_MIN_LEVEL, Z_MAX_LEVEL, Z_DEFAULT_COMPRESSION); + + memLevel = checkRangesOrGetDefault( + opts.memLevel, 'options.memLevel', + Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_MEMLEVEL); + + strategy = checkRangesOrGetDefault( + opts.strategy, 'options.strategy', + Z_DEFAULT_STRATEGY, Z_FIXED, Z_DEFAULT_STRATEGY); +======= + opts.windowBits, + "options.windowBits", + min, + Z_MAX_WINDOWBITS, + Z_DEFAULT_WINDOWBITS + ); + } + + level = checkRangesOrGetDefault( + opts.level, + "options.level", + Z_MIN_LEVEL, + Z_MAX_LEVEL, + Z_DEFAULT_COMPRESSION + ); + + memLevel = checkRangesOrGetDefault( + opts.memLevel, + "options.memLevel", + Z_MIN_MEMLEVEL, + Z_MAX_MEMLEVEL, + Z_DEFAULT_MEMLEVEL + ); + + strategy = checkRangesOrGetDefault( + opts.strategy, + "options.strategy", + Z_DEFAULT_STRATEGY, + Z_FIXED, + Z_DEFAULT_STRATEGY + ); +>>>>>>> refs/remotes/origin/master + + dictionary = opts.dictionary; + if (dictionary !== undefined && !isArrayBufferView(dictionary)) { + if (isAnyArrayBuffer(dictionary)) { + dictionary = Buffer.from(dictionary); + } else { + throw new ERR_INVALID_ARG_TYPE( +<<<<<<< HEAD + 'options.dictionary', + ['Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'], + dictionary, +======= + "options.dictionary", + ["Buffer", "TypedArray", "DataView", "ArrayBuffer"], + dictionary +>>>>>>> refs/remotes/origin/master + ); + } + } + } + + const handle = new binding.Zlib(mode); + // Ideally, we could let ZlibBase() set up _writeState. I haven't been able + // to come up with a good solution that doesn't break our internal API, + // and with it all supported npm versions at the time of writing. + this._writeState = new Uint32Array(2); +<<<<<<< HEAD + handle.init(windowBits, + level, + memLevel, + strategy, + this._writeState, + processCallback, + dictionary); +======= + handle.init( + windowBits, + level, + memLevel, + strategy, + this._writeState, + processCallback, + dictionary + ); +>>>>>>> refs/remotes/origin/master + + ReflectApply(ZlibBase, this, [opts, mode, handle, zlibDefaultOpts]); + + this._level = level; + this._strategy = strategy; + this._mode = mode; +} +ObjectSetPrototypeOf(Zlib.prototype, ZlibBase.prototype); +ObjectSetPrototypeOf(Zlib, ZlibBase); + +// This callback is used by `.params()` to wait until a full flush happened +// before adjusting the parameters. In particular, the call to the native +// `params()` function should not happen while a write is currently in progress +// on the threadpool. +function paramsAfterFlushCallback(level, strategy, callback) { +<<<<<<< HEAD + assert(this._handle, 'zlib binding closed'); +======= + assert(this._handle, "zlib binding closed"); +>>>>>>> refs/remotes/origin/master + this._handle.params(level, strategy); + if (!this.destroyed) { + this._level = level; + this._strategy = strategy; + if (callback) callback(); + } +} + +Zlib.prototype.params = function params(level, strategy, callback) { +<<<<<<< HEAD + checkRangesOrGetDefault(level, 'level', Z_MIN_LEVEL, Z_MAX_LEVEL); + checkRangesOrGetDefault(strategy, 'strategy', Z_DEFAULT_STRATEGY, Z_FIXED); +======= + checkRangesOrGetDefault(level, "level", Z_MIN_LEVEL, Z_MAX_LEVEL); + checkRangesOrGetDefault(strategy, "strategy", Z_DEFAULT_STRATEGY, Z_FIXED); +>>>>>>> refs/remotes/origin/master + + if (this._level !== level || this._strategy !== strategy) { + this.flush( + Z_SYNC_FLUSH, +<<<<<<< HEAD + paramsAfterFlushCallback.bind(this, level, strategy, callback), +======= + paramsAfterFlushCallback.bind(this, level, strategy, callback) +>>>>>>> refs/remotes/origin/master + ); + } else { + process.nextTick(callback); + } +}; + +// generic zlib +// minimal 2-byte header +function Deflate(opts) { + if (!(this instanceof Deflate)) { +<<<<<<< HEAD + return deprecateInstantiation(Deflate, 'DEP0184', opts); +======= + return deprecateInstantiation(Deflate, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, DEFLATE]); +} +ObjectSetPrototypeOf(Deflate.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Deflate, Zlib); + +function Inflate(opts) { + if (!(this instanceof Inflate)) { +<<<<<<< HEAD + return deprecateInstantiation(Inflate, 'DEP0184', opts); +======= + return deprecateInstantiation(Inflate, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, INFLATE]); +} +ObjectSetPrototypeOf(Inflate.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Inflate, Zlib); + +function Gzip(opts) { + if (!(this instanceof Gzip)) { +<<<<<<< HEAD + return deprecateInstantiation(Gzip, 'DEP0184', opts); +======= + return deprecateInstantiation(Gzip, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, GZIP]); +} +ObjectSetPrototypeOf(Gzip.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Gzip, Zlib); + +function Gunzip(opts) { + if (!(this instanceof Gunzip)) { +<<<<<<< HEAD + return deprecateInstantiation(Gunzip, 'DEP0184', opts); +======= + return deprecateInstantiation(Gunzip, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, GUNZIP]); +} +ObjectSetPrototypeOf(Gunzip.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Gunzip, Zlib); + +function DeflateRaw(opts) { + if (opts && opts.windowBits === 8) opts.windowBits = 9; + if (!(this instanceof DeflateRaw)) { +<<<<<<< HEAD + return deprecateInstantiation(DeflateRaw, 'DEP0184', opts); +======= + return deprecateInstantiation(DeflateRaw, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, DEFLATERAW]); +} +ObjectSetPrototypeOf(DeflateRaw.prototype, Zlib.prototype); +ObjectSetPrototypeOf(DeflateRaw, Zlib); + +function InflateRaw(opts) { + if (!(this instanceof InflateRaw)) { +<<<<<<< HEAD + return deprecateInstantiation(InflateRaw, 'DEP0184', opts); +======= + return deprecateInstantiation(InflateRaw, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, INFLATERAW]); +} +ObjectSetPrototypeOf(InflateRaw.prototype, Zlib.prototype); +ObjectSetPrototypeOf(InflateRaw, Zlib); + +function Unzip(opts) { + if (!(this instanceof Unzip)) { +<<<<<<< HEAD + return deprecateInstantiation(Unzip, 'DEP0184', opts); +======= + return deprecateInstantiation(Unzip, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Zlib, this, [opts, UNZIP]); +} +ObjectSetPrototypeOf(Unzip.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Unzip, Zlib); + +function createConvenienceMethod(ctor, sync) { + if (sync) { + return function syncBufferWrapper(buffer, opts) { + return zlibBufferSync(new ctor(opts), buffer); + }; + } + return function asyncBufferWrapper(buffer, opts, callback) { +<<<<<<< HEAD + if (typeof opts === 'function') { +======= + if (typeof opts === "function") { +>>>>>>> refs/remotes/origin/master + callback = opts; + opts = {}; + } + return zlibBuffer(new ctor(opts), buffer, callback); + }; +} + +const kMaxBrotliParam = MathMax( +<<<<<<< HEAD + ...ObjectEntries(constants) + .map(({ 0: key, 1: value }) => (key.startsWith('BROTLI_PARAM_') ? value : 0)), +======= + ...ObjectEntries(constants).map(({ 0: key, 1: value }) => + key.startsWith("BROTLI_PARAM_") ? value : 0 + ) +>>>>>>> refs/remotes/origin/master +); +const brotliInitParamsArray = new Uint32Array(kMaxBrotliParam + 1); + +const brotliDefaultOpts = { + flush: BROTLI_OPERATION_PROCESS, + finishFlush: BROTLI_OPERATION_FINISH, + fullFlush: BROTLI_OPERATION_FLUSH, +}; +function Brotli(opts, mode) { + assert(mode === BROTLI_DECODE || mode === BROTLI_ENCODE); + + brotliInitParamsArray.fill(-1); + if (opts?.params) { + ObjectKeys(opts.params).forEach((origKey) => { + const key = +origKey; +<<<<<<< HEAD + if (NumberIsNaN(key) || key < 0 || key > kMaxBrotliParam || + (brotliInitParamsArray[key] | 0) !== -1) { +======= + if ( + NumberIsNaN(key) || + key < 0 || + key > kMaxBrotliParam || + (brotliInitParamsArray[key] | 0) !== -1 + ) { +>>>>>>> refs/remotes/origin/master + throw new ERR_BROTLI_INVALID_PARAM(origKey); + } + + const value = opts.params[origKey]; +<<<<<<< HEAD + if (typeof value !== 'number' && typeof value !== 'boolean') { + throw new ERR_INVALID_ARG_TYPE('options.params[key]', + 'number', opts.params[origKey]); +======= + if (typeof value !== "number" && typeof value !== "boolean") { + throw new ERR_INVALID_ARG_TYPE( + "options.params[key]", + "number", + opts.params[origKey] + ); +>>>>>>> refs/remotes/origin/master + } + brotliInitParamsArray[key] = value; + }); + } + +<<<<<<< HEAD + const handle = mode === BROTLI_DECODE ? + new binding.BrotliDecoder(mode) : new binding.BrotliEncoder(mode); +======= + const handle = + mode === BROTLI_DECODE + ? new binding.BrotliDecoder(mode) + : new binding.BrotliEncoder(mode); +>>>>>>> refs/remotes/origin/master + + this._writeState = new Uint32Array(2); + handle.init(brotliInitParamsArray, this._writeState, processCallback); + + ReflectApply(ZlibBase, this, [opts, mode, handle, brotliDefaultOpts]); +} +ObjectSetPrototypeOf(Brotli.prototype, Zlib.prototype); +ObjectSetPrototypeOf(Brotli, Zlib); + +function BrotliCompress(opts) { + if (!(this instanceof BrotliCompress)) { +<<<<<<< HEAD + return deprecateInstantiation(BrotliCompress, 'DEP0184', opts); +======= + return deprecateInstantiation(BrotliCompress, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Brotli, this, [opts, BROTLI_ENCODE]); +} +ObjectSetPrototypeOf(BrotliCompress.prototype, Brotli.prototype); +ObjectSetPrototypeOf(BrotliCompress, Brotli); + +function BrotliDecompress(opts) { + if (!(this instanceof BrotliDecompress)) { +<<<<<<< HEAD + return deprecateInstantiation(BrotliDecompress, 'DEP0184', opts); +======= + return deprecateInstantiation(BrotliDecompress, "DEP0184", opts); +>>>>>>> refs/remotes/origin/master + } + ReflectApply(Brotli, this, [opts, BROTLI_DECODE]); +} +ObjectSetPrototypeOf(BrotliDecompress.prototype, Brotli.prototype); +ObjectSetPrototypeOf(BrotliDecompress, Brotli); + +<<<<<<< HEAD + +======= +>>>>>>> refs/remotes/origin/master +const zstdDefaultOpts = { + flush: ZSTD_e_continue, + finishFlush: ZSTD_e_end, + fullFlush: ZSTD_e_flush, +}; +class Zstd extends ZlibBase { + constructor(opts, mode, initParamsArray, maxParam) { + assert(mode === ZSTD_COMPRESS || mode === ZSTD_DECOMPRESS); + + initParamsArray.fill(-1); + if (opts?.params) { + ObjectKeys(opts.params).forEach((origKey) => { + const key = +origKey; +<<<<<<< HEAD + if (NumberIsNaN(key) || key < 0 || key > maxParam || + (initParamsArray[key] | 0) !== -1) { +======= + if ( + NumberIsNaN(key) || + key < 0 || + key > maxParam || + (initParamsArray[key] | 0) !== -1 + ) { +>>>>>>> refs/remotes/origin/master + throw new ERR_ZSTD_INVALID_PARAM(origKey); + } + + const value = opts.params[origKey]; +<<<<<<< HEAD + if (typeof value !== 'number' && typeof value !== 'boolean') { + throw new ERR_INVALID_ARG_TYPE('options.params[key]', + 'number', opts.params[origKey]); +======= + if (typeof value !== "number" && typeof value !== "boolean") { + throw new ERR_INVALID_ARG_TYPE( + "options.params[key]", + "number", + opts.params[origKey] + ); +>>>>>>> refs/remotes/origin/master + } + initParamsArray[key] = value; + }); + } + +<<<<<<< HEAD + const handle = mode === ZSTD_COMPRESS ? + new binding.ZstdCompress() : new binding.ZstdDecompress(); +======= + const handle = + mode === ZSTD_COMPRESS + ? new binding.ZstdCompress() + : new binding.ZstdDecompress(); +>>>>>>> refs/remotes/origin/master + + const pledgedSrcSize = opts?.pledgedSrcSize ?? undefined; + + const writeState = new Uint32Array(2); + + handle.init( + initParamsArray, + pledgedSrcSize, + writeState, + processCallback, +<<<<<<< HEAD + opts?.dictionary && isArrayBufferView(opts.dictionary) ? opts.dictionary : undefined, +======= + opts?.dictionary && isArrayBufferView(opts.dictionary) + ? opts.dictionary + : undefined +>>>>>>> refs/remotes/origin/master + ); + + super(opts, mode, handle, zstdDefaultOpts); + this._writeState = writeState; + } +} + +<<<<<<< HEAD +const kMaxZstdCParam = MathMax(...ObjectKeys(constants).map( + (key) => (key.startsWith('ZSTD_c_') ? + constants[key] : + 0), +)); +======= +const kMaxZstdCParam = MathMax( + ...ObjectKeys(constants).map((key) => + key.startsWith("ZSTD_c_") ? constants[key] : 0 + ) +); +>>>>>>> refs/remotes/origin/master + +const zstdInitCParamsArray = new Uint32Array(kMaxZstdCParam + 1); + +class ZstdCompress extends Zstd { + constructor(opts) { + super(opts, ZSTD_COMPRESS, zstdInitCParamsArray, kMaxZstdCParam); + } +} + +<<<<<<< HEAD +const kMaxZstdDParam = MathMax(...ObjectKeys(constants).map( + (key) => (key.startsWith('ZSTD_d_') ? + constants[key] : + 0), +)); +======= +const kMaxZstdDParam = MathMax( + ...ObjectKeys(constants).map((key) => + key.startsWith("ZSTD_d_") ? constants[key] : 0 + ) +); +>>>>>>> refs/remotes/origin/master + +const zstdInitDParamsArray = new Uint32Array(kMaxZstdDParam + 1); + +class ZstdDecompress extends Zstd { + constructor(opts) { + super(opts, ZSTD_DECOMPRESS, zstdInitDParamsArray, kMaxZstdDParam); + } +} + +function createProperty(ctor) { + return { + __proto__: null, + configurable: true, + enumerable: true, +<<<<<<< HEAD + value: function(options) { +======= + value: function (options) { +>>>>>>> refs/remotes/origin/master + return new ctor(options); + }, + }; +} + +function crc32(data, value = 0) { +<<<<<<< HEAD + if (typeof data !== 'string' && !isArrayBufferView(data)) { + throw new ERR_INVALID_ARG_TYPE('data', ['Buffer', 'TypedArray', 'DataView', 'string'], data); + } + validateUint32(value, 'value'); +======= + if (typeof data !== "string" && !isArrayBufferView(data)) { + throw new ERR_INVALID_ARG_TYPE( + "data", + ["Buffer", "TypedArray", "DataView", "string"], + data + ); + } + validateUint32(value, "value"); +>>>>>>> refs/remotes/origin/master + return crc32Native(data, value); +} + +// Legacy alias on the C++ wrapper object. This is not public API, so we may +// want to runtime-deprecate it at some point. There's no hurry, though. +<<<<<<< HEAD +ObjectDefineProperty(binding.Zlib.prototype, 'jsref', { + __proto__: null, + get() { return this[owner_symbol]; }, + set(v) { return this[owner_symbol] = v; }, +======= +ObjectDefineProperty(binding.Zlib.prototype, "jsref", { + __proto__: null, + get() { + return this[owner_symbol]; + }, + set(v) { + return (this[owner_symbol] = v); + }, +>>>>>>> refs/remotes/origin/master +}); + +module.exports = { + crc32, + Deflate, + Inflate, + Gzip, + Gunzip, + DeflateRaw, + InflateRaw, + Unzip, + BrotliCompress, + BrotliDecompress, + ZstdCompress, + ZstdDecompress, + + // Convenience methods. + // compress/decompress a string or buffer in one step. + deflate: createConvenienceMethod(Deflate, false), + deflateSync: createConvenienceMethod(Deflate, true), + gzip: createConvenienceMethod(Gzip, false), + gzipSync: createConvenienceMethod(Gzip, true), + deflateRaw: createConvenienceMethod(DeflateRaw, false), + deflateRawSync: createConvenienceMethod(DeflateRaw, true), + unzip: createConvenienceMethod(Unzip, false), + unzipSync: createConvenienceMethod(Unzip, true), + inflate: createConvenienceMethod(Inflate, false), + inflateSync: createConvenienceMethod(Inflate, true), + gunzip: createConvenienceMethod(Gunzip, false), + gunzipSync: createConvenienceMethod(Gunzip, true), + inflateRaw: createConvenienceMethod(InflateRaw, false), + inflateRawSync: createConvenienceMethod(InflateRaw, true), + brotliCompress: createConvenienceMethod(BrotliCompress, false), + brotliCompressSync: createConvenienceMethod(BrotliCompress, true), + brotliDecompress: createConvenienceMethod(BrotliDecompress, false), + brotliDecompressSync: createConvenienceMethod(BrotliDecompress, true), + zstdCompress: createConvenienceMethod(ZstdCompress, false), + zstdCompressSync: createConvenienceMethod(ZstdCompress, true), + zstdDecompress: createConvenienceMethod(ZstdDecompress, false), + zstdDecompressSync: createConvenienceMethod(ZstdDecompress, true), +}; + +ObjectDefineProperties(module.exports, { + createDeflate: createProperty(Deflate), + createInflate: createProperty(Inflate), + createDeflateRaw: createProperty(DeflateRaw), + createInflateRaw: createProperty(InflateRaw), + createGzip: createProperty(Gzip), + createGunzip: createProperty(Gunzip), + createUnzip: createProperty(Unzip), + createBrotliCompress: createProperty(BrotliCompress), + createBrotliDecompress: createProperty(BrotliDecompress), + createZstdCompress: createProperty(ZstdCompress), + createZstdDecompress: createProperty(ZstdDecompress), + constants: { + __proto__: null, + configurable: false, + enumerable: true, + value: constants, + }, + codes: { + __proto__: null, + enumerable: true, + writable: false, + value: ObjectFreeze(codes), + }, +}); + +// These should be considered deprecated +// expose all the zlib constants +for (const { 0: key, 1: value } of ObjectEntries(constants)) { +<<<<<<< HEAD + if (key.startsWith('BROTLI')) continue; +======= + if (key.startsWith("BROTLI")) continue; +>>>>>>> refs/remotes/origin/master + ObjectDefineProperty(module.exports, key, { + __proto__: null, + enumerable: false, + value, + writable: false, + }); +<<<<<<< HEAD +} +======= +} +>>>>>>> refs/remotes/origin/master diff --git a/.env b/.env new file mode 100644 index 00000000..c73b51f8 --- /dev/null +++ b/.env @@ -0,0 +1,4 @@ +API_="my secret api key from.env" +DATABASE_SE="super secret" + +MONGO_URL mongodb+srv://:@cluster0.a9ylqls.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0 \ No newline at end of file diff --git a/.gitignore b/.gitignore index f1ff414e..694dae43 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ node_modules -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local -package-lock.json \ No newline at end of file + +# Local Netlify folder +.netlify diff --git a/.idx/dev.nix b/.idx/dev.nix new file mode 100644 index 00000000..b15c7975 --- /dev/null +++ b/.idx/dev.nix @@ -0,0 +1,67 @@ +# To learn more about how to use Nix to configure your environment +# see: https://firebase.google.com/docs/studio/customize-workspace +{ pkgs, ... }: { + # Which nixpkgs channel to use. + channel = "stable-24.05"; # or "unstable" + + # Use https://search.nixos.org/packages to find packages + packages = [ + pkgs.gcc, + pkgs.make, + pkgs.pkg-config, + pkgs.doas-sudo-shim + pkgs.sudo + pkgs.sudo-rs + pkgs.go + pkgs.python311 + pkgs.python311Packages.pip + pkgs.nodejs_20 + pkgs.nodePackages.nodemon + pkgs.python312Packages.pip + pkgs.openssh + pkgs.eval + pkgs.busybox + pkgs.openssh_gssapi + pkgs.openssh_hpn + ]; + + # Sets environment variables in the workspace + env = {}; + idx = { + # Search for the extensions you want on https://open-vsx.org/ and use "publisher.id" + extensions = [ + # "vscodevim.vim" + ]; + + # Enable previews + previews = { + enable = true; + previews = { + # web = { + # # Example: run "npm run dev" with PORT set to IDX's defined port for previews, + # # and show it in IDX's web preview panel + # command = ["npm" "run" "dev"]; + # manager = "web"; + # env = { + # # Environment variables to set for your server + # PORT = "$PORT"; + # }; + # }; + }; + }; + + # Workspace lifecycle hooks + workspace = { + # Runs when a workspace is first created + onCreate = { + # Example: install JS dependencies from NPM + # npm-install = "npm install"; + }; + # Runs when the workspace is (re)started + onStart = { + # Example: start a background task to watch and re-build backend code + # watch-backend = "npm run watch-backend"; + }; + }; + }; +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..fa18a53d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "start" + ], + "cwd": "${workspaceFolder}", + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Python Debugger: Current File", + "type": "debugpy", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..8277e5a8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "IDX.aI.enableInlineCompletion": true, + "IDX.aI.enableCodebaseIndexing": true, + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [] +} \ No newline at end of file diff --git a/1-multiplication.spec.js b/1-multiplication.spec.js new file mode 100644 index 00000000..ce7ef15d --- /dev/null +++ b/1-multiplication.spec.js @@ -0,0 +1,7 @@ +import { multiply } from './1-multiplication'; + +describe('multiplication', () => { + it('should multiply two numbers correctly', () => { + expect(multiply(2, 3)).toBe(6); + }); +}); \ No newline at end of file diff --git a/2-first-last.js b/2-first-last.js new file mode 100644 index 00000000..403a87dd --- /dev/null +++ b/2-first-last.js @@ -0,0 +1,4 @@ +export const firstLast = (items) => { + return 'First: ${items[0]}, Last: ${items[items[1]}' + +} \ No newline at end of file diff --git a/App.css b/App.css new file mode 100644 index 00000000..e7e7b7c7 --- /dev/null +++ b/App.css @@ -0,0 +1,92 @@ +@import "tailwindcss"; +#root { + margin: 0 auto; + } +} +.App { + font-family: sans-serif; + text-align: center; +} +.input-container { + position: relative; +} +input { + border: 1px solid #e4e4e7; + padding: 0.5rem 0.5rem; + width: 320 - 1600px; +} +.error { + position: absolute; + top: 1.5rem; + left: 0; + color: red; +} + + body { + margin: 0; + font-family: "Montserrat"; + } + + h1, section, header { + padding: 2rem; + } + + .light { + background: aquamarine; + color: rgb(0, 24, 164); + } + + .dark { + background: rgb(0, 24, 164); + color: aquamarine; + } + + button { + padding: 18px; + border-radius: 30px; + border: 0; + background: hotpink; + color: white; + font-size: 16px; + font-weight: bold; + font-family: "Montserrat"; + margin-right: 0.5rem; + } + + select { + border: none; + border-radius: 4px; + color: rgb(0, 24, 164); + font-size: 16px; + font-weight: 600; + height: 40px; + font-family: 'Montserrat'; + padding: 0 20px; + cursor: pointer; + + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } + + main { + padding: 2rem; + } + + .thought { + border: 2px solid blue; + padding: 1rem; + margin-bottom: 1rem; + } + + form { + display: flex; + flex-direction: column; + width: 200px; + padding-bottom: 2rem; + } + + textarea { + height: 100px; + margin-bottom: 1rem; + } \ No newline at end of file diff --git a/App.jsx b/App.jsx new file mode 100644 index 00000000..10f252d0 --- /dev/null +++ b/App.jsx @@ -0,0 +1,61 @@ +import { useState } from "react" +import { useEffect } from "react" + +// Removed duplicate declaration of App component +export const App = () => { + const [count, setCount] = useState(0); + + useEffect(() => { + const handleScroll = () => { + console.log('scrolled!'); + }; + + window.addEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); + + useEffect(() => { + const controller = new AbortController(); + + fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts', { signal: controller.signal }) + .then(response => response.json()) + .then(data => console.log(data)); + + const intervalId = setInterval(() => { + fetch('https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts', { signal: controller.signal }) + .then(response => response.json()) + .then(data => console.log(data)); + + console.log('This runs every second'); + }, 1000); + + return () => { + clearInterval(intervalId); + controller.abort(); + }; + }, []); + return ( +
+ + + + + +

Count: {count}

+ {count > 140 &&

You hit 140!

} +
+ ); + }; + \ No newline at end of file diff --git a/App.tsx b/App.tsx new file mode 100644 index 00000000..213743f7 --- /dev/null +++ b/App.tsx @@ -0,0 +1,126 @@ +import React, { useState } from 'react'; +import { useEffect } from 'react'; +import Card from './Card.tsx'; +import './index.css' +import './components/Card.css' +import './components/Card.tsx' +import './components/Card.jsx' +import './components/form.jsx' +import './components/index.json' +import './components/main.tsx' +import './components/App.css' +import './components/App.js' +import './components/App.jsx' +import './components/index.css' +import './components/index.js' +import './components/tests.ts' +import './components/index.html' +import './components/tests.tsx' +import './form.css'; +// import { Form } from './form' // Removed as 'Form' is not exported from './form' +import './App.css'; +import './index.css'; +import { main } from './main.jsx'; +import Main from './main.tsx'; + +fetch ("https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts") +fetch ("https://happy-thoughts-ux7hkzgmwa-uc.a.run.app/thoughts/THOUGHT_ID/like") +const [thoughts, setThoughts] = useState<{ message: string }[]>([]) +const handleFormSubmit = (event) => { + event.preventDefault() + fetch("", { + method: "POST", + body: JSON.stringify({ + message: "Hello world", + }), + headers: { "Content-Type": "application/json" }, + }) + .then((res) => res.json()) + .then((newThought) => { + setThoughts((previousThoughts) => [newThought, ...previousThoughts]) + }) +} + + +// if creating a Review as an object +interface Review { + id: number; + text: string; + dessert: string; +} + +const App = () => { + const [selectedCard, setSelectedCard] = useState(''); + const [reviews, setReviews] = useState([]); // if implementing an array of reviews + const [review, setReview] = useState(''); // if implementing one review only, as string. + const [reviewText, setReviewText] = useState(''); + + const handleCardSelect = (title: string) => { + setSelectedCard(title); + }; + + // setting a signle review as a text, then clearing the text area + const handleReviewSubmit = (e: React.FormEvent) => { + e.preventDefault(); // stop from doing its default re render here. + setReview(reviewText); + setReviewText(''); + }; + + return ( +
+
+ handleCardSelect("Message App")} + /> +
+ + +
+

Write a message

+
+