🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@arcjet/stable-hash

Package Overview
Dependencies
Maintainers
2
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@arcjet/stable-hash - npm Package Compare versions

Comparing version
1.6.1
to
1.7.0-rc.0
+6
dist/edge-light.d.ts
import { FieldHasher, StringWriter, bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
//#region src/edge-light.d.ts
declare const hash: ReturnType<typeof makeHasher>;
//#endregion
export { FieldHasher, StringWriter, bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
import { bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
//#region src/edge-light.ts
const hash = makeHasher(crypto.subtle);
//#endregion
export { bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
//#region src/hasher.d.ts
/**
* Writer.
*/
interface StringWriter {
/**
* Write data.
*
* @param data
* Value.
*/
writeString(data: string): void;
}
interface SubtleCryptoLike {
digest(algorithm: {
name: string;
} | string, data: ArrayBufferView<ArrayBufferLike> | ArrayBufferLike): Promise<ArrayBuffer>;
}
/**
* Hash a field.
*/
type FieldHasher = (data: StringWriter) => void;
/**
* Create a hasher for a boolean.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
declare function bool(key: string, value: boolean): FieldHasher;
/**
* Create a hasher for an unsigned 32-bit integer.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
declare function uint32(key: string, value: number): FieldHasher;
/**
* Create a hasher for a string.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
declare function string(key: string, value: string): FieldHasher;
/**
* Create a hasher for a 64-bit floating point number.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
declare function float64(key: string, value: number): FieldHasher;
/**
* Create a hasher for an array of strings.
*
* @param key
* Key.
* @param values
* Values.
* @returns
* Hasher.
*/
declare function stringSliceOrdered(key: string, values: ReadonlyArray<string>): FieldHasher;
/**
* Create a hasher.
*
* @param subtle
* Subtle crypto.
* @returns
* Hasher.
*/
declare function makeHasher(subtle: SubtleCryptoLike): (...hashers: ReadonlyArray<FieldHasher>) => Promise<string>;
//#endregion
export { FieldHasher, StringWriter, bool, float64, makeHasher, string, stringSliceOrdered, uint32 };
//#region src/hasher.ts
var Sha256 = class {
encoder;
subtle;
buf;
constructor(subtle) {
this.subtle = subtle;
this.encoder = new TextEncoder();
this.buf = "";
}
writeString(data) {
this.buf += data;
}
async digest() {
const buf = this.encoder.encode(this.buf);
const digest = await this.subtle.digest("SHA-256", buf);
return new Uint8Array(digest);
}
};
const maxUint32 = 4294967295;
const fieldSeparator = ":";
const itemSeparator = ",";
/**
* Create a hasher for a boolean.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function bool(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
if (value) data.writeString("true");
else data.writeString("false");
};
}
/**
* Create a hasher for an unsigned 32-bit integer.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function uint32(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
if (value > maxUint32) data.writeString("0");
else data.writeString(value.toFixed(0));
};
}
/**
* Create a hasher for a string.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function string(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString(`"`);
data.writeString(value.replaceAll(`"`, `\\"`));
data.writeString(`"`);
};
}
/**
* Create a hasher for a 64-bit floating point number.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function float64(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString(value.toString());
};
}
/**
* Create a hasher for an array of strings.
*
* @param key
* Key.
* @param values
* Values.
* @returns
* Hasher.
*/
function stringSliceOrdered(key, values) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString("[");
for (const value of Array.from(values).sort()) {
data.writeString(`"`);
data.writeString(value.replaceAll(`"`, `\\"`));
data.writeString(`"`);
data.writeString(itemSeparator);
}
data.writeString("]");
};
}
/**
* Create a hasher.
*
* @param subtle
* Subtle crypto.
* @returns
* Hasher.
*/
function makeHasher(subtle) {
/**
* Hash fields.
*
* @param hashers
* Hashers.
* @returns
* Promise to a hash.
*/
return async function hash(...hashers) {
const h = new Sha256(subtle);
for (const hasher of hashers) {
hasher(h);
h.writeString(itemSeparator);
}
return hex(await h.digest());
};
}
const hexSliceLookupTable = (function() {
const alphabet = "0123456789abcdef";
const table = new Array(256);
for (let i = 0; i < 16; ++i) {
const i16 = i * 16;
for (let j = 0; j < 16; ++j) table[i16 + j] = alphabet[i] + alphabet[j];
}
return table;
})();
function hex(buf) {
const len = buf.length;
const start = 0;
const end = len;
let out = "";
for (let i = start; i < end; ++i) out += hexSliceLookupTable[buf[i]];
return out;
}
//#endregion
export { bool, float64, makeHasher, string, stringSliceOrdered, uint32 };
import { FieldHasher, StringWriter, bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
//#region src/index.d.ts
declare const hash: ReturnType<typeof makeHasher>;
//#endregion
export { FieldHasher, StringWriter, bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
import { bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
import * as crypto from "node:crypto";
//#region src/index.ts
const hash = makeHasher(crypto.subtle);
//#endregion
export { bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
import { FieldHasher, StringWriter, bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
//#region src/workerd.d.ts
declare const hash: ReturnType<typeof makeHasher>;
//#endregion
export { FieldHasher, StringWriter, bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
import { bool, float64, makeHasher, string, stringSliceOrdered, uint32 } from "./hasher.js";
//#region src/workerd.ts
const hash = makeHasher(crypto.subtle);
//#endregion
export { bool, float64, hash, makeHasher, string, stringSliceOrdered, uint32 };
+41
-39
{
"name": "@arcjet/stable-hash",
"version": "1.6.1",
"version": "1.7.0-rc.0",
"description": "Arcjet stable hashing utility",

@@ -8,12 +8,6 @@ "keywords": [

"hash",
"utility",
"util"
"util",
"utility"
],
"license": "Apache-2.0",
"homepage": "https://arcjet.com",
"repository": {
"type": "git",
"url": "git+https://github.com/arcjet/arcjet-js.git",
"directory": "stable-hash"
},
"bugs": {

@@ -23,2 +17,3 @@ "url": "https://github.com/arcjet/arcjet-js/issues",

},
"license": "Apache-2.0",
"author": {

@@ -29,43 +24,50 @@ "name": "Arcjet",

},
"engines": {
"node": ">=22.21.0 <23 || >=24.5.0"
"repository": {
"type": "git",
"url": "git+https://github.com/arcjet/arcjet-js.git",
"directory": "stable-hash"
},
"files": [
"dist"
],
"type": "module",
"main": "./index.js",
"types": "./index.d.ts",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"edge-light": "./edge-light.js",
"workerd": "./workerd.js",
"default": "./index.js"
".": {
"edge-light": {
"types": "./dist/edge-light.d.ts",
"default": "./dist/edge-light.js"
},
"workerd": {
"types": "./dist/workerd.d.ts",
"default": "./dist/workerd.js"
},
"default": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./package.json": "./package.json"
},
"files": [
"edge-light.d.ts",
"edge-light.js",
"hasher.d.ts",
"hasher.js",
"index.d.ts",
"index.js",
"workerd.d.ts",
"workerd.js"
],
"publishConfig": {
"access": "public",
"tag": "latest"
},
"scripts": {
"build": "rollup --config rollup.config.js",
"lint": "eslint .",
"test-api": "node --test -- test/*.test.js",
"test-coverage": "node --experimental-test-coverage --test -- test/*.test.js",
"test": "npm run build && npm run lint && npm run test-coverage"
"build": "tsdown",
"typecheck": "tsgo --noEmit",
"test-api": "node --test -- test/*.test.ts",
"test-coverage": "node --experimental-test-coverage --test -- test/*.test.ts",
"test": "npm run build && npm run test-coverage"
},
"dependencies": {},
"devDependencies": {
"@arcjet/eslint-config": "1.6.1",
"@arcjet/rollup-config": "1.6.1",
"@rollup/wasm-node": "4.62.2",
"@types/node": "22.19.21",
"eslint": "9.39.4",
"typescript": "5.9.3"
"tsdown": "0.22.3",
"typescript": "6.0.3"
},
"publishConfig": {
"access": "public",
"tag": "latest"
"engines": {
"node": ">=22.21.0 <23 || >=24.5.0"
}
}
export * from "./hasher.js";
export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
import { makeHasher } from './hasher.js';
export { bool, float64, string, stringSliceOrdered, uint32 } from './hasher.js';
const hash = makeHasher(crypto.subtle);
export { hash, makeHasher };
/**
* Writer.
*/
export interface StringWriter {
/**
* Write data.
*
* @param data
* Value.
*/
writeString(data: string): void;
}
interface SubtleCryptoLike {
digest(algorithm: {
name: string;
} | string, data: ArrayBufferView<ArrayBufferLike> | ArrayBufferLike): Promise<ArrayBuffer>;
}
/**
* Hash a field.
*/
export type FieldHasher = (data: StringWriter) => void;
/**
* Create a hasher for a boolean.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
export declare function bool(key: string, value: boolean): FieldHasher;
/**
* Create a hasher for an unsigned 32-bit integer.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
export declare function uint32(key: string, value: number): FieldHasher;
/**
* Create a hasher for a string.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
export declare function string(key: string, value: string): FieldHasher;
/**
* Create a hasher for a 64-bit floating point number.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
export declare function float64(key: string, value: number): FieldHasher;
/**
* Create a hasher for an array of strings.
*
* @param key
* Key.
* @param values
* Values.
* @returns
* Hasher.
*/
export declare function stringSliceOrdered(key: string, values: ReadonlyArray<string>): FieldHasher;
/**
* Create a hasher.
*
* @param subtle
* Subtle crypto.
* @returns
* Hasher.
*/
export declare function makeHasher(subtle: SubtleCryptoLike): (...hashers: ReadonlyArray<FieldHasher>) => Promise<string>;
export {};
class Sha256 {
encoder;
subtle;
buf;
constructor(subtle) {
this.subtle = subtle;
this.encoder = new TextEncoder();
this.buf = "";
}
writeString(data) {
this.buf += data;
}
async digest() {
const buf = this.encoder.encode(this.buf);
const digest = await this.subtle.digest("SHA-256", buf);
return new Uint8Array(digest);
}
}
// After this, it needs to wrap to 0
const maxUint32 = 4294967295;
const fieldSeparator = ":";
const itemSeparator = ",";
/**
* Create a hasher for a boolean.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function bool(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
if (value) {
data.writeString("true");
}
else {
data.writeString("false");
}
};
}
/**
* Create a hasher for an unsigned 32-bit integer.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function uint32(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
if (value > maxUint32) {
data.writeString("0");
}
else {
data.writeString(value.toFixed(0));
}
};
}
/**
* Create a hasher for a string.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function string(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString(`"`);
data.writeString(value.replaceAll(`"`, `\\"`));
data.writeString(`"`);
};
}
/**
* Create a hasher for a 64-bit floating point number.
*
* @param key
* Key.
* @param value
* Value.
* @returns
* Hasher.
*/
function float64(key, value) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString(value.toString());
};
}
/**
* Create a hasher for an array of strings.
*
* @param key
* Key.
* @param values
* Values.
* @returns
* Hasher.
*/
function stringSliceOrdered(key, values) {
return (data) => {
data.writeString(key);
data.writeString(fieldSeparator);
data.writeString("[");
for (const value of Array.from(values).sort()) {
data.writeString(`"`);
data.writeString(value.replaceAll(`"`, `\\"`));
data.writeString(`"`);
data.writeString(itemSeparator);
}
data.writeString("]");
};
}
/**
* Create a hasher.
*
* @param subtle
* Subtle crypto.
* @returns
* Hasher.
*/
function makeHasher(subtle) {
/**
* Hash fields.
*
* @param hashers
* Hashers.
* @returns
* Promise to a hash.
*/
return async function hash(...hashers) {
const h = new Sha256(subtle);
for (const hasher of hashers) {
hasher(h);
h.writeString(itemSeparator);
}
const digest = await h.digest();
return hex(digest);
};
}
// Hex encoding logic from https://github.com/feross/buffer but adjusted for
// our use.
//
// Licensed: The MIT License (MIT)
//
// Copyright (c) Feross Aboukhadijeh, and other contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// https://github.com/feross/buffer/blob/5857e295f4d37e3ad02c3abcbf7e8e5ef51f3be6/index.js#L2096-L2106
const hexSliceLookupTable = (function () {
const alphabet = "0123456789abcdef";
const table = new Array(256);
for (let i = 0; i < 16; ++i) {
const i16 = i * 16;
for (let j = 0; j < 16; ++j) {
table[i16 + j] = alphabet[i] + alphabet[j];
}
}
return table;
})();
// https://github.com/feross/buffer/blob/5857e295f4d37e3ad02c3abcbf7e8e5ef51f3be6/index.js#L1085-L1096
function hex(buf) {
const len = buf.length;
const start = 0;
const end = len;
let out = "";
for (let i = start; i < end; ++i) {
out += hexSliceLookupTable[buf[i]];
}
return out;
}
export { bool, float64, makeHasher, string, stringSliceOrdered, uint32 };
export * from "./hasher.js";
export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
import * as crypto from 'node:crypto';
import { makeHasher } from './hasher.js';
export { bool, float64, string, stringSliceOrdered, uint32 } from './hasher.js';
const hash = makeHasher(crypto.subtle);
export { hash, makeHasher };
export * from "./hasher.js";
export declare const hash: (...hashers: ReadonlyArray<import("./hasher.js").FieldHasher>) => Promise<string>;
import { makeHasher } from './hasher.js';
export { bool, float64, string, stringSliceOrdered, uint32 } from './hasher.js';
const hash = makeHasher(crypto.subtle);
export { hash, makeHasher };