69 Commits

Author SHA1 Message Date
c2cd314dff 3.2.5 2025-09-12 21:51:15 +00:00
6ba69d84b7 fix(ts_web): Ensure sha256FromBuffer uses correct ArrayBuffer slice for Uint8Array inputs and add local project config files 2025-09-12 21:51:15 +00:00
b6f6f16a45 3.2.4 2025-09-12 21:29:06 +00:00
4d78dba680 fix(deps): Bump devDependencies, update smartjson and add workspace/CI settings 2025-09-12 21:29:06 +00:00
ab7fb5f9e8 3.2.3 2025-08-03 21:21:35 +00:00
386fcc92bb fix(dependencies/config): Update dependency versions and add local settings for web fetch configuration 2025-08-03 21:21:35 +00:00
8ee57ab806 3.2.2 2025-08-03 21:20:06 +00:00
d0715610ec fix(readme): update readme 2025-08-03 21:20:00 +00:00
fdfaf96574 docs(readme): enhance documentation with comprehensive formatting and examples 2025-08-03 21:17:02 +00:00
00fed871fa 3.2.0 2025-06-19 23:43:43 +00:00
d2efaccaa7 feat(package): Update package.json to use exports field for dual entry points 2025-06-19 23:43:43 +00:00
57e08265dc 3.1.0 2025-06-19 23:03:36 +00:00
23ad99d0e2 feat(browser): Implement fallback SHA256 for non-HTTPS environments and enhance browser tests for consistent hashing 2025-06-19 23:03:36 +00:00
0bae2d6eec feat: Merge isohash functionality into smarthash for cross-environment hash support
- Updated test files to use new tapbundle import from @git.zone/tstest.
- Created a new plan for merging isohash into smarthash, detailing objectives and implementation steps.
- Added browser-specific tests for SHA256 hashing functions in test/test.browser.ts.
- Implemented browser-compatible hashing functions in ts_web/index.ts using Web Crypto API.
- Introduced plugins for environment detection and JSON handling in ts_web/plugins.ts.
- Ensured that existing smarthash functionality remains intact and consistent across environments.
2025-06-19 22:44:47 +00:00
df0f761bdb update description 2024-05-29 14:13:30 +02:00
49f990ec2a update tsconfig 2024-04-14 17:40:33 +02:00
1078af0889 update npmextra.json: githost 2024-04-01 21:35:20 +02:00
feb83abd33 update npmextra.json: githost 2024-04-01 19:58:23 +02:00
87a64c361c update npmextra.json: githost 2024-03-30 21:47:21 +01:00
4fa410a3bd 3.0.4 2023-09-22 13:55:56 +02:00
ca447ded30 fix(core): update 2023-09-22 13:55:56 +02:00
777ed7575c 3.0.3 2023-09-22 13:51:12 +02:00
a78e3e3362 fix(core): update 2023-09-22 13:51:11 +02:00
b8e91e9bf8 switch to new org scheme 2023-07-11 00:47:21 +02:00
f6630f065d switch to new org scheme 2023-07-10 02:56:14 +02:00
bc8bf48679 3.0.2 2023-01-09 16:38:10 +01:00
ef06e465cb fix(core): update 2023-01-09 16:38:09 +01:00
e3eca5528d 3.0.1 2022-06-26 11:37:08 +02:00
d43f568795 fix(core): update 2022-06-26 11:37:07 +02:00
85f2cc4745 3.0.0 2022-06-26 11:34:09 +02:00
143eef8781 BREAKING CHANGE(core): switch to esm 2022-06-26 11:34:09 +02:00
bb7bee3b42 2.1.10 2021-03-01 01:27:16 +00:00
50197d4634 fix(core): update 2021-03-01 01:27:15 +00:00
2e7a61541f 2.1.9 2021-03-01 01:26:55 +00:00
5a6ae2f083 fix(core): update 2021-03-01 01:26:55 +00:00
bf1b89a95a 2.1.8 2020-10-05 15:07:29 +00:00
3e2b300cdb fix(core): update 2020-10-05 15:07:28 +00:00
d865e3b874 2.1.7 2020-09-29 15:54:05 +00:00
13f1f854ce fix(core): update 2020-09-29 15:54:05 +00:00
34586b5fec 2.1.6 2019-12-15 22:49:22 +00:00
edb13cbdcf fix(core): update 2019-12-15 22:49:22 +00:00
5c2e01fe84 2.1.5 2019-12-15 19:22:27 +00:00
d348590e9a fix(core): update 2019-12-15 19:22:27 +00:00
c908cd824b 2.1.4 2019-12-15 19:18:45 +00:00
4a62342015 fix(core): update 2019-12-15 19:18:44 +00:00
0a9a0d3e90 2.1.3 2019-12-15 19:17:28 +00:00
8d5238e23e fix(core): update 2019-12-15 19:17:28 +00:00
9e5ce63c24 2.1.2 2019-12-15 19:12:02 +00:00
3921cbc8f8 fix(core): update 2019-12-15 19:12:01 +00:00
1d917c6a96 2.1.1 2019-11-21 14:20:57 +00:00
c06ac22a59 fix(ci): update 2019-11-21 14:20:57 +00:00
58d4d17e8a 2.1.0 2019-11-21 14:17:49 +00:00
0ed76d1ad4 feat(md5): now creates md5 hashes 2019-11-21 14:17:48 +00:00
cb5b3d2172 2.0.6 2019-07-04 17:07:23 +02:00
62b3813a85 fix(core): update 2019-07-04 17:07:23 +02:00
2a3ad3ad80 2.0.5 2019-07-04 16:56:38 +02:00
4d3b6ff3c9 fix(core): update 2019-07-04 16:56:37 +02:00
85c9a9381a 2.0.4 2019-01-30 02:45:39 +01:00
67962faebc fix(snyk): add .snyk file and mark as Open Source 2019-01-30 02:45:38 +01:00
9361702c38 2.0.3 2019-01-30 02:43:09 +01:00
48994e6ff9 fix(core): update 2019-01-30 02:43:08 +01:00
7130e34adb 2.0.2 2019-01-30 02:42:20 +01:00
dba40dc99f fix(core): update 2019-01-30 02:42:19 +01:00
9e0f2ee551 2.0.1 2019-01-30 02:37:55 +01:00
e28c1c73ea fix(core): update 2019-01-30 02:37:55 +01:00
f47ea7def8 2.0.0 2018-09-08 01:04:48 +02:00
eb79ac25c9 BREAKING CHANGE(scope): change and name to @pushrocks/smarthash 2018-09-08 01:04:47 +02:00
9746709aab 1.0.4 2016-08-16 03:45:18 +02:00
2c4e09cf88 update package tags 2016-08-16 03:45:15 +02:00
41 changed files with 10643 additions and 348 deletions

View File

@@ -0,0 +1,66 @@
name: Default (not tags)
on:
push:
tags-ignore:
- '**'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Install pnpm and npmci
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
- name: Run npm prepare
run: npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build

View File

@@ -0,0 +1,124 @@
name: Default (tags)
on:
push:
tags:
- '*'
env:
IMAGE: registry.gitlab.com/hosttoday/ht-docker-node:npmci
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@gitea.lossless.digital/${{gitea.repository}}.git
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
jobs:
security:
runs-on: ubuntu-latest
continue-on-error: true
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Audit production dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --prod
continue-on-error: true
- name: Audit development dependencies
run: |
npmci command npm config set registry https://registry.npmjs.org
npmci command pnpm audit --audit-level=high --dev
continue-on-error: true
test:
if: ${{ always() }}
needs: security
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Test stable
run: |
npmci node install stable
npmci npm install
npmci npm test
- name: Test build
run: |
npmci node install stable
npmci npm install
npmci npm build
release:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Release
run: |
npmci node install stable
npmci npm publish
metadata:
needs: test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
container:
image: ${{ env.IMAGE }}
continue-on-error: true
steps:
- uses: actions/checkout@v3
- name: Prepare
run: |
pnpm install -g pnpm
pnpm install -g @shipzone/npmci
npmci npm prepare
- name: Code quality
run: |
npmci command npm install -g typescript
npmci npm install
- name: Trigger
run: npmci trigger
- name: Build docs and upload artifacts
run: |
npmci node install stable
npmci npm install
pnpm install -g @gitzone/tsdoc
npmci command tsdoc
continue-on-error: true

22
.gitignore vendored
View File

@@ -1,4 +1,20 @@
node_modules/ .nogit/
docs/
# artifacts
coverage/ coverage/
.nogit/ public/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_*/
# custom

View File

@@ -1,36 +0,0 @@
image: hosttoday/ht-docker-node:npmts
stages:
- test
- release
testLEGACY:
stage: test
script:
- npmci test legacy
tags:
- docker
testLTS:
stage: test
script:
- npmci test lts
tags:
- docker
testSTABLE:
stage: test
script:
- npmci test stable
tags:
- docker
release:
stage: release
environment: npmjs-com_registry
script:
- npmci publish
only:
- tags
tags:
- docker

1
.serena/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/cache

68
.serena/project.yml Normal file
View File

@@ -0,0 +1,68 @@
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
# * For C, use cpp
# * For JavaScript, use typescript
# Special requirements:
# * csharp: Requires the presence of a .sln file in the project folder.
language: typescript
# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true
# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed) on 2025-04-07
ignored_paths: []
# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []
# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""
project_name: "smarthash"

11
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "npm test",
"name": "Run npm test",
"request": "launch",
"type": "node-terminal"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}

View File

@@ -1,33 +0,0 @@
# nodehash
simplifies access to node hash functions. TypeScript Ready
## Status
[![build status](https://gitlab.com/pushrocks/nodehash/badges/master/build.svg)](https://gitlab.com/pushrocks/nodehash/commits/master)
## Usage
We recommend the use of TypeScript for best in class intellisense.
```typescript
import * as nodehash from "nodehash";
// from stream
let readStream = fs.createReadStream("./somefile.txt")
nodehash.sha256FromStream(readStream)
.then((resultString){
console.log(resultString); // prints hash of the file
});
// from file
nodehash.sha256FromFile("./somefile.txt")
.then((resultString){
console.log(resultString); // prints hash of the file
});
// from string
nodehash.sha256FromString("some weird random string")
.then((resultString){
console.log(resultString); // prints hash of the file
});
let hashString = nodehash.sha256FromStringSync("some weird random string");
```

114
changelog.md Normal file
View File

@@ -0,0 +1,114 @@
# Changelog
## 2025-09-12 - 3.2.5 - fix(ts_web)
Ensure sha256FromBuffer uses correct ArrayBuffer slice for Uint8Array inputs and add local project config files
- Fix sha256FromBuffer in ts_web: explicitly slice Uint8Array.buffer using byteOffset/byteLength before calling crypto.subtle.digest to ensure the correct ArrayBuffer segment is hashed in browser environments.
- Add .claude/settings.local.json to allow WebFetch to www.npmjs.com for local tooling.
- Add .serena/.gitignore and .serena/project.yml to include project-specific configuration and ignored cache path.
- Add missing newline at end of ts_web/index.ts
## 2025-09-12 - 3.2.4 - fix(deps)
Bump devDependencies, update smartjson and add workspace/CI settings
- Bump @git.zone/tsbuild from ^2.1.70 to ^2.6.8
- Bump @git.zone/tstest from ^2.3.2 to ^2.3.8
- Bump @push.rocks/smartjson from ^5.0.10 to ^5.2.0
- Add pnpm-workspace.yaml with onlyBuiltDependencies: esbuild, mongodb-memory-server, puppeteer
- Add .claude/settings.local.json to allow WebFetch access to www.npmjs.com
## 2025-08-03 - 3.2.3 - fix(dependencies/config)
Update dependency versions and add local settings for web fetch configuration
- Bump @git.zone/tstest from ^1.0.81 to ^2.3.2
- Bump @push.rocks/smartenv from ^5.0.5 to ^5.0.13
- Add .claude/settings.local.json to allow WebFetch permissions for www.npmjs.com
## 2025-08-03 - 3.2.1 - docs(readme)
Enhance readme with comprehensive documentation and modern formatting
- Updated readme.md with enhanced formatting, emojis, and badges
- Added comprehensive API reference with clear examples for all functions
- Included environment compatibility table showing Node.js vs Browser support
- Added advanced usage examples including error handling and import strategies
- Improved documentation structure with better visual organization
- Fixed typo in sha265FromObject examples to sha256FromObject
## 2025-06-19 - 3.2.0 - feat(package)
Update package.json to use exports field for dual entry points
- Replaced the main and typings fields with an exports object that supports both default and web entry points
- Ensures consistency in module resolution between Node.js and browser environments
## 2025-06-19 - 3.1.0 - feat(browser)
Implement fallback SHA256 for non-HTTPS environments and enhance browser tests for consistent hashing
- Added a pure JavaScript SHA256 fallback in ts_web/sha256.fallback.ts for environments without crypto.subtle
- Updated ts_web/index.ts to use the fallback when necessary
- Enhanced browser tests in test/test.browser.ts to verify consistent hash outputs
- Reflected new features in documentation updates (readme.plan.md)
## 2025-06-19 - 3.0.4 - feat
Merge isohash functionality into smarthash to enable crossenvironment hash support. This release introduces browsercompatible SHA256 functions via the Web Crypto API and plugins for environment detection and JSON handling.
- Added new plan and implementation steps to merge isohash into smarthash.
- Updated test files to use the new tapbundle import.
- Implemented browserspecific hashing functions in ts_web/index.ts and ts_web/plugins.ts.
- Created browser tests in test/test.browser.ts for SHA256 functions.
- Ensured consistent smarthash functionality across environments.
Note: Several nonbreaking maintenance updates (e.g. description, tsconfig, and npmextra.json adjustments) were applied between 2024 and 2023 alongside version marker commits.
---
## 2023-09-22 to 2022-06-26 - 3.0.0 - Maintenance
Between versions 3.0.3 and 3.0.0, a series of core fixes and organizational improvements were rolled out.
- Multiple “fix(core)” commits addressed various update needs.
- A couple of releases also switched to a new organization scheme.
- Routine maintenance commits ensured stability across these versions.
---
## 2022-06-26 - 2.1.10 - BREAKING CHANGE
A major change was introduced by switching the module system.
- BREAKING CHANGE(core): Switched to ESM, requiring consumers to update their imports accordingly.
---
## 2021-03-01 to 2019-11-21 - 2.1.0 - Maintenance
Across versions 2.1.9 down to 2.1.0, the project received multiple fixes and CI updates.
- Repeated “fix(core)” commits improved internal stability.
- A “fix(ci)” update was also introduced to streamline continuous integration processes.
---
## 2019-11-21 - 2.0.6 - feat
New functionality was added to expand the available hashing algorithms.
- feat(md5): Now creates MD5 hashes, broadening the projects cryptographic capabilities.
---
## 2019-07-04 to 2018-09-07 - 2.0.0 - Maintenance
This range of releases was dedicated to refining core functionality and enhancing security.
- Numerous “fix(core)” commits ensured consistent behavior.
- A “fix(snyk)” commit added a .snyk file and marked the project as Open Source for improved security auditing.
---
## 2018-09-07 - 1.0.4 - BREAKING CHANGE
A breaking change was introduced by renaming the package scope.
- BREAKING CHANGE(scope): Changed the package name to @pushrocks/smarthash, requiring updates for consumers referencing the old name.
---
## 2016-08-16 to 2016-05-23 - 1.0.0 - Initial Setup
During the early days of the project, core implementation and structure were established.
- Early commits included the initial implementation (“implementation is ready”), package metadata adjustments (e.g. “update package tags”, “fix README”), and structural additions (“add structure”).
- The journey began with the Initial commit on 2016-05-23, setting the groundwork for future development.

1
dist/index.d.ts vendored
View File

@@ -1 +0,0 @@
export * from "./nodehash.sha256";

6
dist/index.js vendored
View File

@@ -1,6 +0,0 @@
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require("./nodehash.sha256"));
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsaUJBQWMsbUJBQW1CLENBQUMsRUFBQSJ9

View File

@@ -1,2 +0,0 @@
/// <reference types="node" />
export declare let hashStreamPipeStop: (resolveFuntion: any) => NodeJS.ReadWriteStream;

View File

@@ -1,13 +0,0 @@
"use strict";
const plugins = require("./nodehash.plugins");
exports.hashStreamPipeStop = (resolveFuntion) => {
let forEach = (chunk, enc, cb) => {
resolveFuntion(chunk.toString("utf8"));
cb(null, chunk);
};
let atEnd = (cb) => {
cb();
};
return plugins.through2(forEach, atEnd);
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWhhc2guaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL25vZGVoYXNoLmhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE1BQVksT0FBTyxXQUFNLG9CQUFvQixDQUFDLENBQUE7QUFFbkMsMEJBQWtCLEdBQUcsQ0FBQyxjQUFjO0lBQzNDLElBQUksT0FBTyxHQUFHLENBQUMsS0FBWSxFQUFDLEdBQUcsRUFBQyxFQUFFO1FBQzlCLGNBQWMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDdkMsRUFBRSxDQUFDLElBQUksRUFBQyxLQUFLLENBQUMsQ0FBQztJQUNuQixDQUFDLENBQUM7SUFFRixJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUU7UUFDWCxFQUFFLEVBQUUsQ0FBQztJQUNULENBQUMsQ0FBQztJQUVGLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBQyxLQUFLLENBQUMsQ0FBQztBQUMzQyxDQUFDLENBQUMifQ==

View File

@@ -1,7 +0,0 @@
import "typings-global";
export import crypto = require("crypto");
export import fs = require("fs");
export import path = require("path");
export import q = require("q");
export import stream = require("stream");
export import through2 = require("through2");

View File

@@ -1,9 +0,0 @@
"use strict";
require("typings-global");
exports.crypto = require("crypto");
exports.fs = require("fs");
exports.path = require("path");
exports.q = require("q");
exports.stream = require("stream");
exports.through2 = require("through2");
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWhhc2gucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL25vZGVoYXNoLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sZ0JBQWdCLENBQUMsQ0FBQTtBQUNWLGNBQU0sV0FBVyxRQUFRLENBQUMsQ0FBQztBQUMzQixVQUFFLFdBQVcsSUFBSSxDQUFDLENBQUM7QUFDbkIsWUFBSSxXQUFXLE1BQU0sQ0FBQyxDQUFDO0FBQ3ZCLFNBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQztBQUNqQixjQUFNLFdBQVcsUUFBUSxDQUFDLENBQUM7QUFDM0IsZ0JBQVEsV0FBVyxVQUFVLENBQUMsQ0FBQyJ9

View File

@@ -1,18 +0,0 @@
/// <reference types="q" />
import * as plugins from "./nodehash.plugins";
/**
* creates sha256 Hash from Stream
*/
export declare let sha256FromStream: (input: any) => plugins.q.Promise<{}>;
/**
* creates sha256 Hash from File;
*/
export declare let sha256FromFile: (filePath: string) => plugins.q.Promise<{}>;
/**
* Computes sha256 Hash from String synchronously
*/
export declare let sha256FromStringSync: (stringArg: any) => any;
/**
* Computes sha256 Hash from String
*/
export declare let sha256FromString: (stringArg: any) => plugins.q.Promise<{}>;

View File

@@ -1,48 +0,0 @@
"use strict";
const plugins = require("./nodehash.plugins");
const helpers = require("./nodehash.helpers");
/**
* creates sha256 Hash from Stream
*/
exports.sha256FromStream = (input) => {
let done = plugins.q.defer();
let hash = plugins.crypto.createHash('sha256');
hash["setEncoding"]("hex");
input
.pipe(hash)
.pipe(helpers.hashStreamPipeStop(done.resolve));
return done.promise;
};
/**
* creates sha256 Hash from File;
*/
exports.sha256FromFile = (filePath) => {
let done = plugins.q.defer();
let absolutePath = plugins.path.resolve(filePath);
let readableStream = plugins.fs.createReadStream(absolutePath);
exports.sha256FromStream(readableStream)
.then((resultHashString) => {
done.resolve(resultHashString);
});
return done.promise;
};
/**
* Computes sha256 Hash from String synchronously
*/
exports.sha256FromStringSync = (stringArg) => {
let hash = plugins.crypto.createHash('sha256');
hash.update(stringArg);
return hash.digest("hex");
};
/**
* Computes sha256 Hash from String
*/
exports.sha256FromString = (stringArg) => {
let done = plugins.q.defer();
let hash = plugins.crypto.createHash('sha256');
hash.update(stringArg);
let hashResult = hash.digest("hex");
done.resolve(hashResult);
return done.promise;
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZWhhc2guc2hhMjU2LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvbm9kZWhhc2guc2hhMjU2LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxNQUFZLE9BQU8sV0FBTSxvQkFBb0IsQ0FBQyxDQUFBO0FBQzlDLE1BQVksT0FBTyxXQUFNLG9CQUFvQixDQUFDLENBQUE7QUFFOUM7O0dBRUc7QUFDUSx3QkFBZ0IsR0FBRyxDQUFDLEtBQUs7SUFDaEMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUM3QixJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUvQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDM0IsS0FBSztTQUNBLElBQUksQ0FBQyxJQUFJLENBQUM7U0FDVixJQUFJLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3BELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0FBQ3hCLENBQUMsQ0FBQztBQUVGOztHQUVHO0FBQ1Esc0JBQWMsR0FBRyxDQUFDLFFBQWU7SUFDeEMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUM3QixJQUFJLFlBQVksR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNsRCxJQUFJLGNBQWMsR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQy9ELHdCQUFnQixDQUFDLGNBQWMsQ0FBQztTQUMzQixJQUFJLENBQUMsQ0FBQyxnQkFBZ0I7UUFDbkIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ25DLENBQUMsQ0FBQyxDQUFDO0lBQ1AsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7QUFDeEIsQ0FBQyxDQUFBO0FBRUQ7O0dBRUc7QUFDUSw0QkFBb0IsR0FBRyxDQUFDLFNBQVM7SUFDeEMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0MsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN2QixNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM5QixDQUFDLENBQUM7QUFFRjs7R0FFRztBQUNRLHdCQUFnQixHQUFHLENBQUMsU0FBUztJQUNwQyxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzdCLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQy9DLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdkIsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNwQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3pCLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDO0FBQ3hCLENBQUMsQ0FBQyJ9

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 Push.Rocks Copyright (c) 2016 Lossless GmbH
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1 +1,36 @@
{} {
"gitzone": {
"projectType": "npm",
"module": {
"githost": "code.foss.global",
"gitscope": "push.rocks",
"gitrepo": "smarthash",
"description": "Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.",
"npmPackagename": "@push.rocks/smarthash",
"license": "MIT",
"keywords": [
"crypto",
"hashing",
"SHA256",
"MD5",
"security",
"node.js",
"browser",
"cross-environment",
"web crypto",
"stream hashing",
"file hashing",
"synchronous hashing",
"asynchronous hashing",
"data integrity",
"typescript"
]
}
},
"npmci": {
"npmAccessLevel": "public"
},
"tsdoc": {
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
}
}

View File

@@ -1,37 +1,69 @@
{ {
"name": "nodehash", "name": "@push.rocks/smarthash",
"version": "1.0.3", "version": "3.2.5",
"description": "simplifies access to node hash functions", "private": false,
"main": "dist/index.js", "description": "Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.",
"typings": "dist/index.d.ts", "exports": {
"scripts": { ".": "./dist_ts/index.js",
"test": "(npmts)" "./web": "./dist_ts_web/index.js"
}, },
"repository": { "scripts": {
"type": "git", "test": "(tstest test/ --web)",
"url": "git+https://github.com/pushrocks/nodehash.git" "build": "(tsbuild tsfolders --allowimplicitany)",
"buildDocs": "tsdoc"
}, },
"keywords": [ "keywords": [
"hash", "crypto",
"node", "hashing",
"sha265" "SHA256",
"MD5",
"security",
"node.js",
"browser",
"cross-environment",
"web crypto",
"stream hashing",
"file hashing",
"synchronous hashing",
"asynchronous hashing",
"data integrity",
"typescript"
], ],
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"bugs": {
"url": "https://github.com/pushrocks/nodehash/issues"
},
"homepage": "https://github.com/pushrocks/nodehash#readme",
"devDependencies": { "devDependencies": {
"npmts-g": "^5.2.8", "@git.zone/tsbuild": "^2.6.8",
"should": "^11.1.0", "@git.zone/tsrun": "^1.2.46",
"typings-test": "^1.0.1" "@git.zone/tstest": "^2.3.8",
"@types/node": "^20.6.3"
}, },
"dependencies": { "dependencies": {
"@types/q": "0.x.x", "@push.rocks/smartenv": "^5.0.13",
"@types/through2": "0.x.x", "@push.rocks/smartjson": "^5.2.0",
"q": "^1.4.1", "@push.rocks/smartpromise": "^4.0.3",
"through2": "^2.0.1", "@types/through2": "^2.0.39",
"typings-global": "^1.0.6" "through2": "^4.0.2"
} },
"files": [
"ts/**/*",
"ts_web/**/*",
"dist/**/*",
"dist_*/**/*",
"dist_ts/**/*",
"dist_ts_web/**/*",
"assets/**/*",
"cli.js",
"npmextra.json",
"readme.md"
],
"browserslist": [
"last 1 chrome versions"
],
"type": "module",
"homepage": "https://code.foss.global/push.rocks/smarthash",
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smarthash.git"
},
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
} }

9407
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,4 @@
onlyBuiltDependencies:
- esbuild
- mongodb-memory-server
- puppeteer

1
readme.hints.md Normal file
View File

@@ -0,0 +1 @@

177
readme.md Normal file
View File

@@ -0,0 +1,177 @@
# 🔐 @push.rocks/smarthash
> **Cross-environment hashing made simple** 🚀
> SHA256 and MD5 hash functions that work seamlessly in both Node.js and browsers, with zero configuration.
[![npm version](https://img.shields.io/npm/v/@push.rocks/smarthash.svg)](https://www.npmjs.com/package/@push.rocks/smarthash)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
[![Cross Platform](https://img.shields.io/badge/Platform-Node.js%20%7C%20Browser-brightgreen.svg)](#)
## ✨ Why SmartHash?
- 🌐 **Universal**: Works in Node.js AND browsers without polyfills
-**Smart Fallbacks**: Automatically handles Web Crypto API limitations (like non-HTTPS environments)
- 🔧 **TypeScript First**: Full type safety and IntelliSense support
- 📦 **Dual Entry Points**: Optimized builds for both environments
- 🎯 **Simple API**: Consistent interface across all platforms
## 🚀 Quick Start
```bash
pnpm install @push.rocks/smarthash
```
## 📖 API Reference
### 🔤 String Hashing
```typescript
import { sha256FromString, sha256FromStringSync } from '@push.rocks/smarthash';
// Async (works everywhere)
const hash = await sha256FromString('Hello, world!');
console.log(hash); // 📄 64-character hex string
// Sync (Node.js only)
const hashSync = sha256FromStringSync('Hello, world!');
console.log(hashSync); // ⚡ Instant result
```
### 🗂️ File & Stream Hashing (Node.js Only)
```typescript
import { sha256FromFile, sha256FromStream } from '@push.rocks/smarthash';
import fs from 'fs';
// Hash files directly
const fileHash = await sha256FromFile('./myfile.txt');
console.log(fileHash); // 📁 File's SHA256 hash
// Hash streams (perfect for large files)
const stream = fs.createReadStream('./largefile.zip');
const streamHash = await sha256FromStream(stream);
console.log(streamHash); // 🌊 Stream's SHA256 hash
```
### 🧱 Buffer Hashing
```typescript
import { sha256FromBuffer } from '@push.rocks/smarthash';
// Works with both Buffer (Node.js) and Uint8Array (Browser)
const encoder = new TextEncoder();
const buffer = encoder.encode('Hello, world!');
const bufferHash = await sha256FromBuffer(buffer);
console.log(bufferHash); // 🔢 Buffer's SHA256 hash
```
### 🎯 Object Hashing
```typescript
import { sha256FromObject } from '@push.rocks/smarthash';
// Consistent hashing for JavaScript objects
const myObject = {
userId: 12345,
role: 'admin',
timestamp: Date.now()
};
const objectHash = await sha256FromObject(myObject);
console.log(objectHash); // 🎯 Deterministic object hash
```
> **🔥 Pro Tip**: Object property order doesn't matter! `{a: 1, b: 2}` and `{b: 2, a: 1}` produce the same hash.
### 🛡️ MD5 Hashing (Node.js Only)
```typescript
import { md5FromString } from '@push.rocks/smarthash';
// Legacy MD5 support (use SHA256 for new projects!)
const md5Hash = await md5FromString('Hello, world!');
console.log(md5Hash); // 🔐 32-character MD5 hash
```
## 🌍 Environment Compatibility
| Function | Node.js | Browser | Notes |
|----------|---------|---------|-------|
| `sha256FromString` | ✅ | ✅ | Universal support |
| `sha256FromStringSync` | ✅ | ❌ | Sync not possible in browsers |
| `sha256FromBuffer` | ✅ | ✅ | Handles Buffer/Uint8Array |
| `sha256FromFile` | ✅ | ❌ | File system access required |
| `sha256FromStream` | ✅ | ❌ | Node.js streams only |
| `sha256FromObject` | ✅ | ✅ | Uses JSON serialization |
| `md5FromString` | ✅ | ❌ | Not supported by Web Crypto API |
## 🔧 Advanced Usage
### Error Handling
```typescript
import { sha256FromString } from '@push.rocks/smarthash';
try {
const hash = await sha256FromString('sensitive data');
console.log(`✅ Hash computed: ${hash}`);
} catch (error) {
console.error('❌ Hashing failed:', error);
}
```
### Browser-Specific Features
In browsers, SmartHash automatically:
- 🔒 Uses Web Crypto API when available (HTTPS contexts)
- 🔄 Falls back to pure JavaScript implementation in non-HTTPS environments
- ⚠️ Warns when trying to use Node.js-only functions
### Import Strategies
```typescript
// Main entry point (Node.js optimized)
import { sha256FromString } from '@push.rocks/smarthash';
// Browser-specific entry point (smaller bundle)
import { sha256FromString } from '@push.rocks/smarthash/web';
```
## 🛠️ Development
```bash
# Run tests (both Node.js and browser)
pnpm test
# Build the project
pnpm build
# Generate documentation
pnpm buildDocs
```
## 🔐 Security Notes
-**SHA256**: Cryptographically secure, recommended for all use cases
- ⚠️ **MD5**: Legacy support only, not recommended for security-critical applications
- 🌍 **Cross-Environment**: Produces identical hashes across Node.js and browsers
- 🔒 **Web Crypto**: Uses native browser APIs when available for maximum performance
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

45
readme.plan.md Normal file
View File

@@ -0,0 +1,45 @@
# Merge Plan: isohash into smarthash
**First line: Command to reread CLAUDE.md**: `cat ~/.claude/CLAUDE.md`
## Objective
Merge the functionality from @push.rocks/isohash into @push.rocks/smarthash to provide cross-environment hash support (browser and Node.js).
## Implementation Steps
### 1. Create ts_web directory structure ✓
- Create `./ts_web` directory for browser-specific code
- This will house the Web Crypto API implementation
### 2. Add required dependencies ✓
- Add `@push.rocks/smartenv` to package.json dependencies
- This is needed for environment detection
### 3. Create web-specific plugin file ✓
- Create `ts_web/plugins.ts` with smartenv import
- Follow the plugins pattern used in the Node.js version
### 4. Implement browser-compatible hash functions ✓
- Copy and adapt `index.ts` from isohash to `ts_web/index.ts`
- Remove circular dependency (isohash importing smarthash)
- Use native Web Crypto API for SHA256 in browser
- Maintain compatibility with existing smarthash API
### 5. Build and verify ✓
- Run `pnpm build` to ensure TypeScript compilation succeeds
- Check that both Node.js and browser builds are created
### 6. Test functionality ✓
- Run `pnpm test` to ensure all tests pass
- Verify browser compatibility through web tests
## Key Considerations
- The web version uses native Web Crypto API for performance
- The Node.js version continues using the existing crypto implementation
- API remains consistent across both environments
- No breaking changes to existing smarthash functionality
## Additional Features Implemented
- **Fallback for non-HTTPS environments**: Added pure JavaScript SHA256 implementation that automatically activates when crypto.subtle is not available (e.g., HTTP or file:// protocols)
- **Comprehensive browser tests**: Created test.browser.ts with specific browser environment tests
- **Cross-environment consistency**: Ensured hash outputs match across Node.js and browser implementations

77
test/test.browser.ts Normal file
View File

@@ -0,0 +1,77 @@
import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as smarthash from '../ts_web/index.js';
tap.test('sha256FromString should work in browser environment', async () => {
const testHash = await smarthash.sha256FromString('test');
const testHash2 = await smarthash.sha256FromString('testString');
const testHash3 = await smarthash.sha256FromString('test');
expect(testHash).toEqual(testHash3);
expect(testHash).not.toEqual(testHash2);
expect(testHash).toBeTypeofString();
expect(testHash).toHaveLength(64); // SHA256 hash is 64 hex characters
});
tap.test('sha256FromBuffer should work with Uint8Array in browser', async () => {
const encoder = new TextEncoder();
const buffer = encoder.encode('test');
const hashFromBuffer = await smarthash.sha256FromBuffer(buffer);
const hashFromString = await smarthash.sha256FromString('test');
expect(hashFromBuffer).toEqual(hashFromString);
});
tap.test('sha265FromObject should produce reproducible hashes', async () => {
const hash1 = await smarthash.sha265FromObject({
hithere: 1,
wow: 'two',
});
const hash2 = await smarthash.sha265FromObject({
wow: 'two',
hithere: 1,
});
const hash3 = await smarthash.sha265FromObject({
wow: 'twoe',
hithere: 1,
});
expect(hash1).toEqual(hash2);
expect(hash1).not.toEqual(hash3);
});
tap.test('sha256FromStringSync should throw in browser environment', async () => {
expect(() => {
smarthash.sha256FromStringSync('test');
}).toThrow();
});
tap.test('sha256FromStream should throw in browser environment', async () => {
expect(() => {
smarthash.sha256FromStream(null);
}).toThrow();
});
tap.test('sha256FromFile should throw in browser environment', async () => {
await expect(smarthash.sha256FromFile('./test.txt')).rejects.toThrow();
});
tap.test('md5FromString should throw in browser environment', async () => {
await expect(smarthash.md5FromString('test')).rejects.toThrow();
});
tap.test('sha256 produces consistent results across environments', async () => {
// Test that our implementation produces the same hash as Node.js crypto
const testHash = await smarthash.sha256FromString('test');
const expectedHash = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';
expect(testHash).toEqual(expectedHash);
// Test with different string
const testHash2 = await smarthash.sha256FromString('hello world');
const expectedHash2 = 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9';
expect(testHash2).toEqual(expectedHash2);
});
export default tap.start();

1
test/test.d.ts vendored
View File

@@ -1 +0,0 @@
import "typings-test";

View File

@@ -1,46 +0,0 @@
"use strict";
require("typings-test");
const should = require("should");
const fs = require("fs");
const nodehash = require("../dist/index");
describe("nodehash", function () {
describe("sha256FromStringSync", function () {
it("should convert a String to sha256 hash synchronously", function () {
let testHash = nodehash.sha256FromStringSync("test");
let testHash2 = nodehash.sha256FromStringSync("testString");
let testHash3 = nodehash.sha256FromStringSync("test");
should.equal(testHash, testHash3);
should.notEqual(testHash, "test");
});
});
describe("sha256fromStringSync", function () {
it("should convert a String to sha256 hash synchronously", function (done) {
nodehash.sha256FromString("test")
.then(resultString => {
let compareString = nodehash.sha256FromStringSync("test");
should.equal(resultString, compareString);
done();
});
});
});
describe("sha256fromStream", function () {
it("should convert a Stream to sha256 and resolve a promise with result", function (done) {
let readStream = fs.createReadStream("./test/testImageForHash.jpg");
nodehash.sha256FromStream(readStream)
.then((resultString) => {
should.equal(resultString, "45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c");
done();
});
});
});
describe("sha256fromFile", function () {
it("should convert a Stream to sha256 and resolve a promise with result", function (done) {
nodehash.sha256FromFile("./test/testImageForHash.jpg")
.then((resultString) => {
should.equal(resultString, "45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c");
done();
});
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLFFBQU8sY0FBYyxDQUFDLENBQUE7QUFDdEIsTUFBTyxNQUFNLFdBQVcsUUFBUSxDQUFDLENBQUM7QUFDbEMsTUFBTyxFQUFFLFdBQVcsSUFBSSxDQUFDLENBQUM7QUFFMUIsTUFBWSxRQUFRLFdBQU0sZUFBZSxDQUFDLENBQUE7QUFFMUMsUUFBUSxDQUFDLFVBQVUsRUFBQztJQUNoQixRQUFRLENBQUMsc0JBQXNCLEVBQUM7UUFDNUIsRUFBRSxDQUFDLHNEQUFzRCxFQUFDO1lBQ3RELElBQUksUUFBUSxHQUFHLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNyRCxJQUFJLFNBQVMsR0FBRyxRQUFRLENBQUMsb0JBQW9CLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUQsSUFBSSxTQUFTLEdBQUcsUUFBUSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3RELE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JDLENBQUMsQ0FBQyxDQUFBO0lBQ04sQ0FBQyxDQUFDLENBQUM7SUFDSCxRQUFRLENBQUMsc0JBQXNCLEVBQUM7UUFDNUIsRUFBRSxDQUFDLHNEQUFzRCxFQUFDLFVBQVMsSUFBSTtZQUNuRSxRQUFRLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDO2lCQUM1QixJQUFJLENBQUMsWUFBWTtnQkFDZCxJQUFJLGFBQWEsR0FBRyxRQUFRLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzFELE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUN6QyxJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFBO1FBQ1YsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDLENBQUMsQ0FBQztJQUNILFFBQVEsQ0FBQyxrQkFBa0IsRUFBQztRQUN4QixFQUFFLENBQUMscUVBQXFFLEVBQUMsVUFBUyxJQUFJO1lBQ2xGLElBQUksVUFBVSxHQUFHLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQ3BFLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUM7aUJBQ2hDLElBQUksQ0FBQyxDQUFDLFlBQW1CO2dCQUN0QixNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksRUFBQyxrRUFBa0UsQ0FBQyxDQUFBO2dCQUM3RixJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1gsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDLENBQUMsQ0FBQztJQUNILFFBQVEsQ0FBQyxnQkFBZ0IsRUFBQztRQUN0QixFQUFFLENBQUMscUVBQXFFLEVBQUMsVUFBUyxJQUFJO1lBQ2xGLFFBQVEsQ0FBQyxjQUFjLENBQUMsNkJBQTZCLENBQUM7aUJBQ2pELElBQUksQ0FBQyxDQUFDLFlBQW1CO2dCQUN0QixNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksRUFBQyxrRUFBa0UsQ0FBQyxDQUFBO2dCQUM3RixJQUFJLEVBQUUsQ0FBQztZQUNYLENBQUMsQ0FBQyxDQUFDO1FBQ1gsQ0FBQyxDQUFDLENBQUE7SUFDTixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUMsQ0FBQyxDQUFDIn0=

View File

@@ -1,46 +1,55 @@
import "typings-test"; import { tap, expect } from '@git.zone/tstest/tapbundle';
import should = require("should"); import * as fs from 'fs';
import fs = require("fs");
import * as nodehash from "../dist/index"; import * as smarthash from '../ts/index.js';
describe("nodehash",function(){ tap.test('sha256FromStringSync should convert a String to sha256 hash synchronously', async () => {
describe("sha256FromStringSync",function(){ const testHash = smarthash.sha256FromStringSync('test');
it("should convert a String to sha256 hash synchronously",function(){ const testHash2 = smarthash.sha256FromStringSync('testString');
let testHash = nodehash.sha256FromStringSync("test"); const testHash3 = smarthash.sha256FromStringSync('test');
let testHash2 = nodehash.sha256FromStringSync("testString"); expect(testHash).toEqual(testHash3);
let testHash3 = nodehash.sha256FromStringSync("test"); expect(testHash).not.toEqual('test');
should.equal(testHash,testHash3); });
should.notEqual(testHash,"test");
}) tap.test('sha256fromStringSync should convert a String to sha256 hash synchronously', async () => {
}); const resultString = await smarthash.sha256FromString('test');
describe("sha256fromStringSync",function(){ const compareString = smarthash.sha256FromStringSync('test');
it("should convert a String to sha256 hash synchronously",function(done){ expect(resultString).toEqual(compareString);
nodehash.sha256FromString("test") });
.then(resultString => {
let compareString = nodehash.sha256FromStringSync("test"); tap.test('sha256fromStream should convert a Stream to sha256', async (tools) => {
should.equal(resultString,compareString); const readStream = fs.createReadStream('./test/testImageForHash.jpg');
done(); const resultString: string = await smarthash.sha256FromStream(readStream);
}) expect(resultString).toEqual('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
}) });
});
describe("sha256fromStream",function(){ tap.test('sha256fromFile should convert a Stream to sha256', async () => {
it("should convert a Stream to sha256 and resolve a promise with result",function(done){ const resultString = await smarthash.sha256FromFile('./test/testImageForHash.jpg');
let readStream = fs.createReadStream("./test/testImageForHash.jpg"); expect(resultString).toEqual('45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c');
nodehash.sha256FromStream(readStream) });
.then((resultString:string) => {
should.equal(resultString,"45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c") tap.test('should produce reproducible hash from Object', async () => {
done(); const hash1 = await smarthash.sha265FromObject({
}); hithere: 1,
}) wow: 'two',
}); });
describe("sha256fromFile",function(){
it("should convert a Stream to sha256 and resolve a promise with result",function(done){ const hash2 = await smarthash.sha265FromObject({
nodehash.sha256FromFile("./test/testImageForHash.jpg") wow: 'two',
.then((resultString:string) => { hithere: 1,
should.equal(resultString,"45b80413ed93acb495691186ce61850449439f9183352b9bff96d5533fa1046c") });
done();
}); const hash3 = await smarthash.sha265FromObject({
}) wow: 'twoe',
}); hithere: 1,
}); });
expect(hash1).toEqual(hash2);
expect(hash1).not.toEqual(hash3);
});
tap.test('should create md5hash from string', async () => {
const md5Hash = await smarthash.md5FromString('hellothere');
expect(md5Hash).toEqual('c6f7c372641dd25e0fddf0215375561f');
});
export default tap.start();

8
ts/00_commitinfo_data.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smarthash',
version: '3.2.5',
description: 'Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.'
}

View File

@@ -1,3 +1,4 @@
import * as plugins from "./nodehash.plugins"; import * as plugins from './nodehash.plugins.js';
export * from "./nodehash.sha256"; export * from './nodehash.sha256.js';
export * from './nodehash.md5.js';

View File

@@ -1,15 +1,14 @@
import * as plugins from "./nodehash.plugins"; import * as plugins from './nodehash.plugins.js';
export let hashStreamPipeStop = (resolveFuntion) => { export const hashStreamPipeStop = (resolveFunctionArg: (inputArg: string) => any) => {
let forEach = (chunk:Buffer,enc,cb) => { const forEach = (chunk: Buffer, enc: any, cb: any) => {
resolveFuntion(chunk.toString("utf8")); resolveFunctionArg(chunk.toString('utf8'));
cb(null,chunk); cb(null, chunk);
}; };
let atEnd = (cb) => { const atEnd = (cb: any) => {
cb(); cb();
}; };
return plugins.through2(forEach,atEnd); return plugins.through2(forEach, atEnd);
}; };

5
ts/nodehash.md5.ts Normal file
View File

@@ -0,0 +1,5 @@
import * as plugins from './nodehash.plugins.js';
export const md5FromString = async (stringToHash: string) => {
return plugins.crypto.createHash('md5').update(stringToHash).digest('hex');
};

View File

@@ -1,7 +1,18 @@
import "typings-global"; // node native scope
export import crypto = require("crypto"); import crypto from 'crypto';
export import fs = require("fs"); import * as fs from 'fs';
export import path = require("path"); import * as path from 'path';
export import q = require("q"); import * as stream from 'stream';
export import stream = require("stream");
export import through2 = require("through2"); export { crypto, fs, path, stream };
// pushrocks scope
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartjson from '@push.rocks/smartjson';
export { smartpromise, smartjson };
// thirdparty scope
import through2 from 'through2';
export { through2 };

View File

@@ -1,51 +1,62 @@
import * as plugins from "./nodehash.plugins"; import * as plugins from './nodehash.plugins.js';
import * as helpers from "./nodehash.helpers"; import * as helpers from './nodehash.helpers.js';
/** /**
* creates sha256 Hash from Stream * creates sha256 Hash from Stream
*/ */
export let sha256FromStream = (input) => { export const sha256FromStream = (input: plugins.stream.Stream): Promise<string> => {
let done = plugins.q.defer(); const done = plugins.smartpromise.defer<string>();
let hash = plugins.crypto.createHash('sha256'); const hash = plugins.crypto.createHash('sha256');
hash["setEncoding"]("hex"); hash.setEncoding('hex');
input input.pipe(hash).pipe(helpers.hashStreamPipeStop(done.resolve));
.pipe(hash) return done.promise;
.pipe(helpers.hashStreamPipeStop(done.resolve));
return done.promise;
}; };
/** /**
* creates sha256 Hash from File; * creates sha256 Hash from File;
*/ */
export let sha256FromFile = (filePath:string) => { export const sha256FromFile = async (filePath: string): Promise<string> => {
let done = plugins.q.defer(); const absolutePath = plugins.path.resolve(filePath);
let absolutePath = plugins.path.resolve(filePath); const readableStream = plugins.fs.createReadStream(absolutePath);
let readableStream = plugins.fs.createReadStream(absolutePath); const hashResult = sha256FromStream(readableStream);
sha256FromStream(readableStream) return hashResult;
.then((resultHashString) => { };
done.resolve(resultHashString);
});
return done.promise;
}
/** /**
* Computes sha256 Hash from String synchronously * Computes sha256 Hash from String synchronously
*/ */
export let sha256FromStringSync = (stringArg) => { export const sha256FromStringSync = (stringArg: string): string => {
let hash = plugins.crypto.createHash('sha256'); const hash = plugins.crypto.createHash('sha256');
hash.update(stringArg); hash.update(stringArg);
return hash.digest("hex"); return hash.digest('hex');
}; };
/** /**
* Computes sha256 Hash from String * Computes sha256 Hash from String
*/ */
export let sha256FromString = (stringArg) => { export const sha256FromString = async (stringArg: string): Promise<string> => {
let done = plugins.q.defer(); const hash = plugins.crypto.createHash('sha256');
let hash = plugins.crypto.createHash('sha256'); hash.update(stringArg);
hash.update(stringArg); const hashResult = hash.digest('hex');
let hashResult = hash.digest("hex"); return hashResult;
done.resolve(hashResult); };
return done.promise;
}; /**
* Computes sha256 Hash from String
*/
export const sha256FromBuffer = async (bufferArg: Buffer): Promise<string> => {
const hash = plugins.crypto.createHash('sha256');
hash.update(bufferArg);
const hashResult = hash.digest('hex');
return hashResult;
};
/**
* computes sha265 Hash from Object
*/
export const sha265FromObject = async (objectArg: any): Promise<string> => {
const stringifiedObject = plugins.smartjson.stringify(objectArg);
const hashResult = await sha256FromString(stringifiedObject);
return hashResult;
};

View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@push.rocks/smarthash',
version: '3.2.5',
description: 'Cross-environment hash functions (SHA256 and MD5) for Node.js and browsers, with support for strings, streams, and files.'
}

116
ts_web/index.ts Normal file
View File

@@ -0,0 +1,116 @@
import * as plugins from './plugins.js';
import { sha256Fallback } from './sha256.fallback.js';
/**
* Convert ArrayBuffer to hex string
*/
const hex = (buffer: ArrayBuffer): string => {
const hexCodes: string[] = [];
const view = new DataView(buffer);
for (let i = 0; i < view.byteLength; i += 4) {
// Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
const value = view.getUint32(i);
// toString(16) will give the hex representation of the number without padding
const stringValue = value.toString(16);
// We use concatenation and slice for padding
const padding = '00000000';
const paddedValue = (padding + stringValue).slice(-padding.length);
hexCodes.push(paddedValue);
}
// Join all the hex strings into one
return hexCodes.join("");
};
/**
* Check if crypto.subtle is available
*/
const isCryptoSubtleAvailable = (): boolean => {
return typeof crypto !== 'undefined' && crypto.subtle !== undefined;
};
/**
* Computes sha256 Hash from String
*/
export const sha256FromString = async (stringArg: string): Promise<string> => {
// Get the string as arraybuffer.
const buffer = (new TextEncoder()).encode(stringArg);
if (isCryptoSubtleAvailable()) {
const hash = await crypto.subtle.digest("SHA-256", buffer);
const result = hex(hash);
return result;
} else {
// Use fallback for non-HTTPS environments
return sha256Fallback(buffer);
}
};
/**
* Computes sha256 Hash from String synchronously
* Note: In browser environment, this is still async internally but we maintain the API
*/
export const sha256FromStringSync = (stringArg: string): string => {
console.warn('sha256FromStringSync is not truly synchronous in browser environment');
throw new Error('sha256FromStringSync is not supported in browser environment. Use sha256FromString instead.');
};
/**
* Computes sha256 Hash from ArrayBuffer
*/
export const sha256FromBuffer = async (bufferArg: ArrayBuffer | Uint8Array): Promise<string> => {
if (isCryptoSubtleAvailable()) {
// Ensure we pass an ArrayBuffer to satisfy BufferSource typing
let inputBuffer: ArrayBuffer;
if (bufferArg instanceof Uint8Array) {
const view = bufferArg;
inputBuffer = view.buffer.slice(
view.byteOffset,
view.byteOffset + view.byteLength
) as ArrayBuffer;
} else {
inputBuffer = bufferArg;
}
const hash = await crypto.subtle.digest("SHA-256", inputBuffer);
const result = hex(hash);
return result;
} else {
// Use fallback for non-HTTPS environments
const uint8Array = bufferArg instanceof Uint8Array ? bufferArg : new Uint8Array(bufferArg);
return sha256Fallback(uint8Array);
}
};
/**
* computes sha265 Hash from Object
*/
export const sha265FromObject = async (objectArg: any): Promise<string> => {
const stringifiedObject = plugins.smartjson.stringify(objectArg);
const hashResult = await sha256FromString(stringifiedObject);
return hashResult;
};
/**
* creates sha256 Hash from Stream
* Note: Not supported in browser environment
*/
export const sha256FromStream = (input: any): Promise<string> => {
throw new Error('sha256FromStream is not supported in browser environment');
};
/**
* creates sha256 Hash from File
* Note: Not supported in browser environment
*/
export const sha256FromFile = async (filePath: string): Promise<string> => {
throw new Error('sha256FromFile is not supported in browser environment');
};
/**
* Computes MD5 Hash from String
* Note: MD5 is not natively supported by Web Crypto API
*/
export const md5FromString = async (stringToHash: string): Promise<string> => {
throw new Error('md5FromString is not supported in browser environment. Web Crypto API does not support MD5.');
};

8
ts_web/plugins.ts Normal file
View File

@@ -0,0 +1,8 @@
// pushrocks scope
import * as smartenv from '@push.rocks/smartenv';
import * as smartjson from '@push.rocks/smartjson';
export {
smartenv,
smartjson
};

121
ts_web/sha256.fallback.ts Normal file
View File

@@ -0,0 +1,121 @@
/**
* Pure JavaScript SHA256 implementation
* Used as fallback when crypto.subtle is not available (non-HTTPS contexts)
*/
/**
* SHA256 constants
*/
const K: number[] = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
/**
* Initial hash values
*/
const H: number[] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
/**
* Rotate right
*/
function rotr(n: number, b: number): number {
return (n >>> b) | (n << (32 - b));
}
/**
* SHA256 compression function
*/
function sha256Transform(W: number[], H: number[]): void {
let a = H[0];
let b = H[1];
let c = H[2];
let d = H[3];
let e = H[4];
let f = H[5];
let g = H[6];
let h = H[7];
for (let j = 0; j < 64; j++) {
if (j >= 16) {
const s0 = rotr(W[j - 15], 7) ^ rotr(W[j - 15], 18) ^ (W[j - 15] >>> 3);
const s1 = rotr(W[j - 2], 17) ^ rotr(W[j - 2], 19) ^ (W[j - 2] >>> 10);
W[j] = (W[j - 16] + s0 + W[j - 7] + s1) >>> 0;
}
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
const ch = (e & f) ^ ((~e) & g);
const temp1 = (h + S1 + ch + K[j] + W[j]) >>> 0;
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
const maj = (a & b) ^ (a & c) ^ (b & c);
const temp2 = (S0 + maj) >>> 0;
h = g;
g = f;
f = e;
e = (d + temp1) >>> 0;
d = c;
c = b;
b = a;
a = (temp1 + temp2) >>> 0;
}
H[0] = (H[0] + a) >>> 0;
H[1] = (H[1] + b) >>> 0;
H[2] = (H[2] + c) >>> 0;
H[3] = (H[3] + d) >>> 0;
H[4] = (H[4] + e) >>> 0;
H[5] = (H[5] + f) >>> 0;
H[6] = (H[6] + g) >>> 0;
H[7] = (H[7] + h) >>> 0;
}
/**
* Calculate SHA256 hash from bytes
*/
export function sha256Fallback(bytes: Uint8Array): string {
const H_copy = [...H];
const msgLen = bytes.length;
const msgBitLen = msgLen * 8;
// Padding
const padLen = (msgLen % 64 < 56) ? 56 - (msgLen % 64) : 120 - (msgLen % 64);
const padded = new Uint8Array(msgLen + padLen + 8);
padded.set(bytes);
padded[msgLen] = 0x80;
// Append length (64-bit big-endian)
const dataView = new DataView(padded.buffer);
dataView.setUint32(padded.length - 8, 0, false); // high 32 bits
dataView.setUint32(padded.length - 4, msgBitLen >>> 0, false); // low 32 bits
// Process blocks
for (let offset = 0; offset < padded.length; offset += 64) {
const W = new Array(64);
// Copy block into W[0..15]
for (let i = 0; i < 16; i++) {
W[i] = dataView.getUint32(offset + i * 4, false);
}
sha256Transform(W, H_copy);
}
// Convert to hex string
let hex = '';
for (let i = 0; i < 8; i++) {
hex += H_copy[i].toString(16).padStart(8, '0');
}
return hex;
}

14
tsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}