Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Oct 14, 2021
1 parent b17317d commit 69bb2cf
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 120 deletions.
4 changes: 0 additions & 4 deletions .github/funding.yml

This file was deleted.

7 changes: 2 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ jobs:
fail-fast: false
matrix:
node-version:
- 14
- 12
- 10
- 8
- 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
yarn.lock
coverage
1 change: 1 addition & 0 deletions browser.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './index.js';
48 changes: 10 additions & 38 deletions browser.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,27 @@
/* eslint-env browser */
/* global globalThis:readonly */
'use strict';

// Ponyfill for `globalThis`
const _globalThis = (() => {
if (typeof globalThis !== 'undefined') {
return globalThis;
}

if (typeof self !== 'undefined') {
return self;
}

/* istanbul ignore next */
if (typeof window !== 'undefined') {
return window;
}

/* istanbul ignore next */
if (typeof global !== 'undefined') {
return global;
}
})();

const bufferToHex = buffer => {
const view = new DataView(buffer);

let hexCodes = '';
for (let i = 0; i < view.byteLength; i += 4) {
hexCodes += view.getUint32(i).toString(16).padStart(8, '0');
for (let index = 0; index < view.byteLength; index += 4) {
hexCodes += view.getUint32(index).toString(16).padStart(8, '0');
}

return hexCodes;
};

const create = algorithm => async (buffer, options) => {
const create = algorithm => async (buffer, {outputFormat = 'hex'} = {}) => {
if (typeof buffer === 'string') {
buffer = new _globalThis.TextEncoder().encode(buffer);
buffer = new globalThis.TextEncoder().encode(buffer);
}

options = {
outputFormat: 'hex',
...options
};

const hash = await _globalThis.crypto.subtle.digest(algorithm, buffer);
const hash = await globalThis.crypto.subtle.digest(algorithm, buffer);

return options.outputFormat === 'hex' ? bufferToHex(hash) : hash;
return outputFormat === 'hex' ? bufferToHex(hash) : hash;
};

exports.sha1 = create('SHA-1');
exports.sha256 = create('SHA-256');
exports.sha384 = create('SHA-384');
exports.sha512 = create('SHA-512');
export const sha1 = create('SHA-1');
export const sha256 = create('SHA-256');
export const sha384 = create('SHA-384');
export const sha512 = create('SHA-512');
38 changes: 30 additions & 8 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ export interface OptionBufferOutput {
/**
[SHA-1 is insecure](https://stackoverflow.com/a/38045085/64949) and should not be used for anything sensitive.
@returns The hex-encoded hash.
@returns The Hex-encoded hash.
@example
```
import {sha1} from 'crypto-hash';
console.log(await sha1('🦄'));
//=> '5df82936cbf0864be4b7ba801bee392457fde9e4'
```
*/
export function sha1(
input: string | ArrayBuffer | ArrayBufferView,
Expand All @@ -21,16 +29,14 @@ export function sha1(
): Promise<ArrayBuffer>;

/**
@returns The hex-encoded hash.
@returns The Hex-encoded hash.
@example
```
import {sha256} from 'crypto-hash';
(async () => {
console.log(await sha256('🦄'));
//=> '5df82936cbf0864be4b7ba801bee392457fde9e4'
})();
console.log(await sha256('🦄'));
//=> '36bf255468003165652fe978eaaa8898e191664028475f83f506dabd95298efc'
```
*/
export function sha256(
Expand All @@ -43,7 +49,15 @@ export function sha256(
): Promise<ArrayBuffer>;

/**
@returns The hex-encoded hash.
@returns The Hex-encoded hash.
@example
```
import {sha384} from 'crypto-hash';
console.log(await sha384('🦄'));
//=> 'a9d4dfb503394bd9701d60eb5fb1d7fb800580b43d874165103b16d311fb5c97545cb89f06c31f30e219f5b603e834ca'
```
*/
export function sha384(
input: string | ArrayBuffer | ArrayBufferView,
Expand All @@ -55,7 +69,15 @@ export function sha384(
): Promise<ArrayBuffer>;

/**
@returns The hex-encoded hash.
@returns The Hex-encoded hash.
@example
```
import {sha512} from 'crypto-hash';
console.log(await sha512('🦄'));
//=> '7d9e515c59bd15d0692f9bc0c68f50f82b62a99bef4b8dc490cec165296210dff005529a4cb84a655eee6ddec82339e6bdbab21bdb287b71a543a56cfab53905'
```
*/
export function sha512(
input: string | ArrayBuffer | ArrayBufferView,
Expand Down
47 changes: 14 additions & 33 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
'use strict';
const crypto = require('crypto');
const path = require('path');

const requireOptional = (name, defaultValue) => {
try {
return require(name);
} catch (_) {
return defaultValue;
}
};
import {Buffer} from 'node:buffer';
import {Worker} from 'node:worker_threads';
import crypto from 'node:crypto';

const {Worker} = requireOptional('worker_threads', {});

const threadFilePath = path.join(__dirname, 'thread.js');
const threadFilePath = new URL('thread.js', import.meta.url);

let worker; // Lazy
let taskIdCounter = 0;
const tasks = new Map();

const createWorker = () => {
worker = new Worker(threadFilePath);

worker.on('message', message => {
const task = tasks.get(message.id);
tasks.delete(message.id);
Expand Down Expand Up @@ -48,29 +39,19 @@ const taskWorker = (value, transferList) => new Promise(resolve => {
worker.postMessage({id, value}, transferList);
});

let create = algorithm => async (buffer, options) => {
options = {
outputFormat: 'hex',
...options
};

let create = algorithm => async (buffer, {outputFormat = 'hex'} = {}) => {
const hash = crypto.createHash(algorithm);
hash.update(buffer, typeof buffer === 'string' ? 'utf8' : undefined);

if (options.outputFormat === 'hex') {
if (outputFormat === 'hex') {
return hash.digest('hex');
}

return hash.digest().buffer;
};

if (Worker !== undefined) {
create = algorithm => async (source, options) => {
options = {
outputFormat: 'hex',
...options
};

create = algorithm => async (source, {outputFormat = 'hex'} = {}) => {
let buffer;
if (typeof source === 'string') {
// Saving one copy operation by writing string to buffer right away and then transfering buffer
Expand All @@ -80,19 +61,19 @@ if (Worker !== undefined) {
const finalSource = source instanceof ArrayBuffer ? new Uint8Array(source) : source;

// Creating a copy of buffer at call time, will be transfered later
buffer = finalSource.buffer.slice(0);
buffer = finalSource.buffer.slice(0); // eslint-disable-line unicorn/prefer-spread
}

const result = await taskWorker({algorithm, buffer}, [buffer]);
if (options.outputFormat === 'hex') {
if (outputFormat === 'hex') {
return Buffer.from(result).toString('hex');
}

return result;
};
}

exports.sha1 = create('sha1');
exports.sha256 = create('sha256');
exports.sha384 = create('sha384');
exports.sha512 = create('sha512');
export const sha1 = create('sha1');
export const sha256 = create('sha256');
export const sha384 = create('sha384');
export const sha512 = create('sha512');
2 changes: 1 addition & 1 deletion index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType} from 'tsd';
import {sha1, sha256, sha384, sha512} from '.';
import {sha1, sha256, sha384, sha512} from './index.js';

expectType<Promise<string>>(sha1('🦄'));
expectType<Promise<ArrayBuffer>>(sha1('🦄', {outputFormat: 'buffer'}));
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": {
"node": "./index.js",
"default": "./browser.js"
},
"engines": {
"node": ">=8"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"test": "xo && ava test.js && karmatic test-browser.js && tsd"
Expand All @@ -20,6 +25,7 @@
"index.js",
"index.d.ts",
"browser.js",
"brower.d.ts",
"thread.js"
],
"keywords": [
Expand All @@ -36,17 +42,11 @@
"browser"
],
"devDependencies": {
"@sindresorhus/is": "^0.15.0",
"ava": "^1.4.1",
"hash.js": "^1.1.5",
"karmatic": "1.0.7",
"tsd": "^0.7.2",
"xo": "^0.24.0"
},
"browser": "browser.js",
"xo": {
"rules": {
"import/no-unresolved": "off"
}
"@sindresorhus/is": "^4.2.0",
"ava": "^3.15.0",
"hash.js": "^1.1.7",
"karmatic": "2.1.0",
"tsd": "^0.18.0",
"xo": "^0.45.0"
}
}
18 changes: 8 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@ The browser version is only ~300 bytes minified & gzipped.

When used in the browser, it must be in a [secure context (HTTPS)](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle).

This package is more modern browsers. IE11 is not supported.
This package is for modern browsers. IE11 is not supported.

## Install

```
$ npm install crypto-hash
```sh
npm install crypto-hash
```

## Usage

```js
const {sha256} = require('crypto-hash');
import {sha256} from 'crypto-hash';

(async () => {
console.log(await sha256('🦄'));
//=> '5df82936cbf0864be4b7ba801bee392457fde9e4'
})();
console.log(await sha256('🦄'));
//=> '5df82936cbf0864be4b7ba801bee392457fde9e4'
```

## API
Expand All @@ -36,9 +34,9 @@ const {sha256} = require('crypto-hash');
### sha384(input, options?)
### sha512(input, options?)

Returns a `Promise<string>` with a hex-encoded hash.
Returns a `Promise<string>` with a Hex-encoded hash.

*In Node.js 12 or later, the operation is executed using [`worker_threads`](https://nodejs.org/api/worker_threads.html). A thread is lazily spawned on the first operation and lives until the end of the program execution. It's `unref`ed, so it won't keep the process alive.*
*In Node.js, the operation is executed using [`worker_threads`](https://nodejs.org/api/worker_threads.html). A thread is lazily spawned on the first operation and lives until the end of the program execution. It's `unref`ed, so it won't keep the process alive.*

[SHA-1 is insecure](https://stackoverflow.com/a/38045085/64949) and should not be used for anything sensitive.

Expand Down
7 changes: 3 additions & 4 deletions test-browser.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* eslint-env jasmine */
'use strict';
const hashjs = require('hash.js');
const is = require('@sindresorhus/is');
const {sha1, sha256, sha384, sha512} = require('./browser');
import hashjs from 'hash.js';
import is from '@sindresorhus/is';
import {sha1, sha256, sha384, sha512} from './browser.js';

const fixture = 'foo bar baz';

Expand Down
3 changes: 2 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {Buffer} from 'node:buffer';
import test from 'ava';
import hashjs from 'hash.js';
import is from '@sindresorhus/is';
import {sha1, sha256, sha384, sha512} from '.';
import {sha1, sha256, sha384, sha512} from './index.js';

const fixture = 'foo bar baz';

Expand Down
6 changes: 3 additions & 3 deletions thread.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';
const crypto = require('crypto');
const {parentPort} = require('worker_threads');
import {Buffer} from 'node:buffer';
import crypto from 'node:crypto';
import {parentPort} from 'node:worker_threads';

parentPort.on('message', message => {
const {algorithm, buffer} = message.value;
Expand Down

0 comments on commit 69bb2cf

Please sign in to comment.