Compare commits
186 Commits
Author | SHA1 | Date |
---|---|---|
semantic-release-bot | a51a7b928b | |
Derrick Hammer | fceb022378 | |
Derrick Hammer | 3512b88b79 | |
semantic-release-bot | 1c4cfb7bb2 | |
Derrick Hammer | c026c2d9bc | |
Derrick Hammer | 9954616f5a | |
semantic-release-bot | d87fed0e40 | |
Derrick Hammer | 2b5b36b2b5 | |
Derrick Hammer | a048b62600 | |
semantic-release-bot | be1f246f34 | |
Derrick Hammer | 6cb2f82d25 | |
Derrick Hammer | b24d00aa0b | |
semantic-release-bot | cd6ddffdb4 | |
Derrick Hammer | 1f3aefb881 | |
Derrick Hammer | 786fca8403 | |
semantic-release-bot | 7e9510760a | |
Derrick Hammer | 0c0a89f1d0 | |
Derrick Hammer | 931653a796 | |
semantic-release-bot | 0d44285e66 | |
Derrick Hammer | 87167e2201 | |
Derrick Hammer | d30bf07920 | |
semantic-release-bot | 19aef9631c | |
Derrick Hammer | 1fcc70197b | |
Derrick Hammer | 3d16c4c3cf | |
semantic-release-bot | 9defafe783 | |
Derrick Hammer | b5b03242e2 | |
Derrick Hammer | 6f81c29671 | |
semantic-release-bot | e0992e39e4 | |
Derrick Hammer | e25880f84c | |
Derrick Hammer | 71553dee17 | |
semantic-release-bot | 51bc06f688 | |
Derrick Hammer | 0d95f08c76 | |
Derrick Hammer | 71ec4ce85f | |
Derrick Hammer | eb644c9827 | |
semantic-release-bot | f7136f938f | |
Derrick Hammer | c246f6b8a1 | |
Derrick Hammer | d2e91d4e24 | |
semantic-release-bot | f5d24a2328 | |
Derrick Hammer | 11572205e9 | |
Derrick Hammer | 08eb9f726e | |
semantic-release-bot | a6fcccbbd6 | |
Derrick Hammer | e492828186 | |
Derrick Hammer | 8531f2abc9 | |
semantic-release-bot | b19380fbff | |
Derrick Hammer | cff5c1f10a | |
Derrick Hammer | 7b7d770a22 | |
semantic-release-bot | 1149091ee6 | |
Derrick Hammer | bcf6511068 | |
Derrick Hammer | b4b1a979e9 | |
semantic-release-bot | f121f01f36 | |
Derrick Hammer | 294c07484f | |
Derrick Hammer | afbc70341e | |
semantic-release-bot | abb1a64800 | |
Derrick Hammer | 4d906aa11d | |
Derrick Hammer | b8da76cc20 | |
semantic-release-bot | 993ab521d3 | |
Derrick Hammer | 6a9c6a8c2a | |
Derrick Hammer | d2a20610ce | |
semantic-release-bot | 95d572577c | |
Derrick Hammer | 01920ecf16 | |
Derrick Hammer | 55e28b806c | |
semantic-release-bot | c00fafdb73 | |
Derrick Hammer | b6722cf98d | |
Derrick Hammer | c47df51a5f | |
Derrick Hammer | 41bd043154 | |
Derrick Hammer | d2916bf1ce | |
semantic-release-bot | b5635a29b0 | |
Derrick Hammer | cfe5f1328c | |
Derrick Hammer | bd108376ba | |
semantic-release-bot | 7bd66df4b1 | |
Derrick Hammer | aa1ddfac3e | |
Derrick Hammer | 2eb5810dec | |
semantic-release-bot | 069237271a | |
Derrick Hammer | 001119b4c3 | |
Derrick Hammer | 9bece08a19 | |
semantic-release-bot | 2fad185062 | |
Derrick Hammer | 0625b1acbb | |
Derrick Hammer | cfdd7748d7 | |
Derrick Hammer | 5760b20fe7 | |
Derrick Hammer | f6bfaf4509 | |
Derrick Hammer | 693d703a4c | |
Derrick Hammer | 0037179fd1 | |
Derrick Hammer | ea68d0ec0d | |
Derrick Hammer | 9378f87336 | |
Derrick Hammer | d24f5c89d5 | |
Derrick Hammer | cbdc097bda | |
Derrick Hammer | 0d4d6c4007 | |
Derrick Hammer | 587f8696b2 | |
Derrick Hammer | d59b39c8ed | |
Derrick Hammer | 49082c4014 | |
Derrick Hammer | 37b3389aa5 | |
Derrick Hammer | f79a722e77 | |
Derrick Hammer | d85b90cfa0 | |
Derrick Hammer | ae35797a25 | |
semantic-release-bot | b0a9e85d65 | |
Derrick Hammer | d43f43936b | |
Derrick Hammer | 0d0b2d4799 | |
semantic-release-bot | d64dd524ab | |
Derrick Hammer | 61292f5dea | |
Derrick Hammer | d7d146b78d | |
semantic-release-bot | c9d4d330db | |
Derrick Hammer | e0458a05c0 | |
Derrick Hammer | ea9048868a | |
semantic-release-bot | 5445337ba3 | |
Derrick Hammer | 37fd7543af | |
semantic-release-bot | 3e4fc635b1 | |
Derrick Hammer | 47a3daec4e | |
Derrick Hammer | 04bd9636a3 | |
semantic-release-bot | db16e58038 | |
Derrick Hammer | 848f3dff9d | |
Derrick Hammer | 9bc225c542 | |
Derrick Hammer | ed1c4bc937 | |
Derrick Hammer | c20e79635e | |
semantic-release-bot | 7319f5a048 | |
Derrick Hammer | 97489a577f | |
Derrick Hammer | 589821c570 | |
Derrick Hammer | a0c131ffb7 | |
Derrick Hammer | 5b82a9c561 | |
Derrick Hammer | 45fbc1b63d | |
Derrick Hammer | 06a8093786 | |
Derrick Hammer | b8ab5faced | |
Derrick Hammer | dd43e29b29 | |
Derrick Hammer | 051f4b2da7 | |
Derrick Hammer | 50a7c80358 | |
Derrick Hammer | 68283d14e5 | |
Derrick Hammer | 23a55f772b | |
Derrick Hammer | 53dd352c95 | |
Derrick Hammer | 2aa53faf00 | |
Derrick Hammer | 68fec66069 | |
Derrick Hammer | 0c320f992b | |
semantic-release-bot | c69420ae90 | |
Derrick Hammer | 0cbb09b247 | |
Derrick Hammer | cb4048b963 | |
Derrick Hammer | a530a07f01 | |
Derrick Hammer | 1c738c8aae | |
Derrick Hammer | afd79e308f | |
semantic-release-bot | 29adc6dcca | |
Derrick Hammer | 6555fcd9a3 | |
Derrick Hammer | 6d5c27c972 | |
semantic-release-bot | ab31ab6345 | |
Derrick Hammer | bfaa307821 | |
Derrick Hammer | 8f78dd2c7b | |
semantic-release-bot | 3948839aa1 | |
Derrick Hammer | 76910d6253 | |
Derrick Hammer | adacdff1c3 | |
Derrick Hammer | 23c8244a68 | |
Derrick Hammer | a9e94ba896 | |
semantic-release-bot | dd29b6a585 | |
Derrick Hammer | b613805237 | |
Derrick Hammer | 0350feef64 | |
semantic-release-bot | 716a6e37d3 | |
Derrick Hammer | a82436f1c0 | |
Derrick Hammer | 4a90fb0f6e | |
semantic-release-bot | 99e6500d09 | |
Derrick Hammer | 26103b475b | |
Derrick Hammer | 8afd780ac7 | |
semantic-release-bot | da7036496d | |
Derrick Hammer | a8e262bb7b | |
Derrick Hammer | cfc04b2509 | |
Derrick Hammer | 2c77cfa478 | |
Derrick Hammer | 4103ad4652 | |
Derrick Hammer | 891397e535 | |
Derrick Hammer | 2f3a116f8d | |
Derrick Hammer | 1077c4d510 | |
Derrick Hammer | b9b35ab60c | |
Derrick Hammer | c090a49f54 | |
Derrick Hammer | 516d53d45c | |
Derrick Hammer | 80638d62c2 | |
Derrick Hammer | 29b7333d5a | |
Derrick Hammer | af283f63e5 | |
Derrick Hammer | 7edc7d78db | |
Derrick Hammer | 6b98e2d6b0 | |
Derrick Hammer | fb5848f5e5 | |
Derrick Hammer | 10f64fb05f | |
Derrick Hammer | 3b39b2ee88 | |
Derrick Hammer | 2591ea9451 | |
Derrick Hammer | 8b08ecf68c | |
Derrick Hammer | ebcd7fb8b9 | |
Derrick Hammer | 0a502bd2f3 | |
Derrick Hammer | b8e08cbe05 | |
Derrick Hammer | 8ffceebb84 | |
Derrick Hammer | 0f8c4f4780 | |
Derrick Hammer | 41b20b1465 | |
semantic-release-bot | e84915ec08 | |
Derrick Hammer | 7f305a33a1 | |
Derrick Hammer | 3784858600 |
|
@ -1,45 +0,0 @@
|
||||||
version: 2.1
|
|
||||||
|
|
||||||
orbs:
|
|
||||||
node: circleci/node@5.1.0
|
|
||||||
ssh: credijusto/ssh@0.5.2
|
|
||||||
workflows:
|
|
||||||
release:
|
|
||||||
jobs:
|
|
||||||
- node/run:
|
|
||||||
name: build
|
|
||||||
npm-run: build
|
|
||||||
post-steps:
|
|
||||||
- persist_to_workspace:
|
|
||||||
root: .
|
|
||||||
paths:
|
|
||||||
- lib/
|
|
||||||
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
- /^develop-.*$/
|
|
||||||
- node/run:
|
|
||||||
name: release
|
|
||||||
npm-run: semantic-release
|
|
||||||
requires:
|
|
||||||
- build
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- develop
|
|
||||||
- /^develop-.*$/
|
|
||||||
|
|
||||||
context:
|
|
||||||
- publish
|
|
||||||
setup:
|
|
||||||
- attach_workspace:
|
|
||||||
at: ./
|
|
||||||
- add_ssh_keys:
|
|
||||||
fingerprints:
|
|
||||||
- "47:cf:a1:17:d9:81:8e:c5:51:e5:53:c8:33:e4:33:b9"
|
|
||||||
- ssh/ssh-add-host:
|
|
||||||
host_url: GITEA_HOST
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
name: Build/Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
- develop-*
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
debug_enabled:
|
||||||
|
description: debug_enabled
|
||||||
|
type: boolean
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18.x
|
||||||
|
cache: 'npm'
|
||||||
|
- name: Setup Golang
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: 1.19
|
||||||
|
- name: Setup Golang
|
||||||
|
run: |
|
||||||
|
VERSION=0.28.1;
|
||||||
|
TINYGO="tinygo_${VERSION}_amd64.deb";
|
||||||
|
wget -q https://github.com/tinygo-org/tinygo/releases/download/v$VERSION/$TINYGO;
|
||||||
|
sudo dpkg -i $TINYGO && rm $TINYGO;
|
||||||
|
- name: Fetch Wasm Deps
|
||||||
|
run: cd src/golang && go get
|
||||||
|
- run: npm ci
|
||||||
|
- run: npm run build --if-present
|
||||||
|
- name: Install SSH key
|
||||||
|
uses: shimataro/ssh-key-action@v2
|
||||||
|
with:
|
||||||
|
key: ${{ secrets.GITEA_SSH_KEY }}
|
||||||
|
known_hosts: ${{ secrets.GITEA_KNOWN_HOST }}
|
||||||
|
|
||||||
|
- name: Publish
|
||||||
|
run: npm run semantic-release
|
||||||
|
env:
|
||||||
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
- name: Setup tmate session
|
||||||
|
uses: mxschmitt/action-tmate@v3
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled && failure() }}
|
||||||
|
with:
|
||||||
|
limit-access-to-actor: true
|
|
@ -1,22 +1,6 @@
|
||||||
{
|
{
|
||||||
"preset": [
|
"preset": [
|
||||||
"presetter-preset-essentials",
|
"presetter-preset-hybrid",
|
||||||
"presetter-preset-hybrid"
|
"@lumeweb/node-library-preset"
|
||||||
],
|
|
||||||
"config": {
|
|
||||||
"tsconfig": {
|
|
||||||
"compilerOptions": {
|
|
||||||
"lib": [
|
|
||||||
"ES2020",
|
|
||||||
"dom"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"prettier": {
|
|
||||||
"singleQuote": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"variable": {
|
|
||||||
"source": "src"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
32
.releaserc
32
.releaserc
|
@ -1,32 +0,0 @@
|
||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"@semantic-release/commit-analyzer",
|
|
||||||
"@semantic-release/release-notes-generator",
|
|
||||||
[
|
|
||||||
"@semantic-release/changelog",
|
|
||||||
{
|
|
||||||
"changelogFile": "docs/CHANGELOG.md"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@semantic-release/git",
|
|
||||||
{
|
|
||||||
"assets": [
|
|
||||||
"package.json",
|
|
||||||
"docs/CHANGELOG.md",
|
|
||||||
"npm-shrinkwrap.json"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"@semantic-release/npm"
|
|
||||||
],
|
|
||||||
"branches": [
|
|
||||||
"master",
|
|
||||||
{
|
|
||||||
name: "develop",
|
|
||||||
prerelease: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "develop-*",
|
|
||||||
prerelease: true
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
# [0.2.0-develop.41](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.40...v0.2.0-develop.41) (2023-11-17)
|
||||||
|
|
||||||
|
# [0.2.0-develop.40](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.39...v0.2.0-develop.40) (2023-10-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add getter for jwtSessionKey ([9954616](https://git.lumeweb.com/LumeWeb/libportal/commit/9954616f5a80b6f04e7b14aa67cf106733e9d75c))
|
||||||
|
|
||||||
|
# [0.2.0-develop.39](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.38...v0.2.0-develop.39) (2023-09-20)
|
||||||
|
|
||||||
|
# [0.2.0-develop.38](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.37...v0.2.0-develop.38) (2023-09-11)
|
||||||
|
|
||||||
|
# [0.2.0-develop.37](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.36...v0.2.0-develop.37) (2023-09-11)
|
||||||
|
|
||||||
|
# [0.2.0-develop.36](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.35...v0.2.0-develop.36) (2023-09-09)
|
||||||
|
|
||||||
|
# [0.2.0-develop.35](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.34...v0.2.0-develop.35) (2023-09-09)
|
||||||
|
|
||||||
|
# [0.2.0-develop.34](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.33...v0.2.0-develop.34) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.33](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.32...v0.2.0-develop.33) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.32](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.31...v0.2.0-develop.32) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.31](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.30...v0.2.0-develop.31) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.30](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.29...v0.2.0-develop.30) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.29](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.28...v0.2.0-develop.29) (2023-09-08)
|
||||||
|
|
||||||
|
# [0.2.0-develop.28](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.27...v0.2.0-develop.28) (2023-09-07)
|
||||||
|
|
||||||
|
# [0.2.0-develop.27](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.26...v0.2.0-develop.27) (2023-09-07)
|
||||||
|
|
||||||
|
# [0.2.0-develop.26](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.25...v0.2.0-develop.26) (2023-09-07)
|
||||||
|
|
||||||
|
# [0.2.0-develop.25](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.24...v0.2.0-develop.25) (2023-09-04)
|
||||||
|
|
||||||
|
# [0.2.0-develop.24](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.23...v0.2.0-develop.24) (2023-09-04)
|
||||||
|
|
||||||
|
# [0.2.0-develop.23](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.22...v0.2.0-develop.23) (2023-09-03)
|
||||||
|
|
||||||
|
# [0.2.0-develop.22](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.21...v0.2.0-develop.22) (2023-09-03)
|
||||||
|
|
||||||
|
# [0.2.0-develop.21](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.20...v0.2.0-develop.21) (2023-09-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use switch to module in package.json ([b6722cf](https://git.lumeweb.com/LumeWeb/libportal/commit/b6722cf98d347095815532b3923eefb42deb2f0a))
|
||||||
|
|
||||||
|
# [0.2.0-develop.20](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.19...v0.2.0-develop.20) (2023-09-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* check for only undefined or null on the size ([bd10837](https://git.lumeweb.com/LumeWeb/libportal/commit/bd108376ba33bb3c6b5c25606c5ed032e292e911))
|
||||||
|
|
||||||
|
# [0.2.0-develop.19](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.18...v0.2.0-develop.19) (2023-09-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix encodeCid overload typings ([2eb5810](https://git.lumeweb.com/LumeWeb/libportal/commit/2eb5810dec17413ef68f282e9d884bcd867f520d))
|
||||||
|
|
||||||
|
# [0.2.0-develop.18](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.17...v0.2.0-develop.18) (2023-09-02)
|
||||||
|
|
||||||
|
# [0.2.0-develop.17](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.16...v0.2.0-develop.17) (2023-08-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* refactor how we process a nodejs stream, as the current approach is extremely slow and wasteful. We need to do a bit of macgyvering and convert it via pipe to a passthrough so it passes a typeof check for Stream, then import it to form-data Response, and request a blob ([ae35797](https://git.lumeweb.com/LumeWeb/libportal/commit/ae35797a2525d23ac9a552d076a9904e68a7a142))
|
||||||
|
|
||||||
|
# [0.2.0-develop.16](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.15...v0.2.0-develop.16) (2023-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add portalUrl getter ([0d0b2d4](https://git.lumeweb.com/LumeWeb/libportal/commit/0d0b2d4799a277c25f39673a10e4351c1991536c))
|
||||||
|
|
||||||
|
# [0.2.0-develop.15](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.14...v0.2.0-develop.15) (2023-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* further wasm loading fixes ([d7d146b](https://git.lumeweb.com/LumeWeb/libportal/commit/d7d146b78d3737b17baf45bb4dd2dcf8fc7cbe8d))
|
||||||
|
|
||||||
|
# [0.2.0-develop.14](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.13...v0.2.0-develop.14) (2023-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* async loading quirk in firefox js engine ([ea90488](https://git.lumeweb.com/LumeWeb/libportal/commit/ea9048868a4323da810bf139a083daf3ed5d79f7))
|
||||||
|
|
||||||
|
# [0.2.0-develop.13](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.12...v0.2.0-develop.13) (2023-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* switch to using utf8ToBytes ([37fd754](https://git.lumeweb.com/LumeWeb/libportal/commit/37fd7543afe5f06e3193e24cb2c3390c848faadb))
|
||||||
|
|
||||||
|
# [0.2.0-develop.12](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.11...v0.2.0-develop.12) (2023-07-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add ?init query string for vite bundler ([04bd963](https://git.lumeweb.com/LumeWeb/libportal/commit/04bd9636a3fc70f5d23b5e61add7fb3d18604d27))
|
||||||
|
|
||||||
|
# [0.2.0-develop.11](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.10...v0.2.0-develop.11) (2023-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* update uploadFile return type ([848f3df](https://git.lumeweb.com/LumeWeb/libportal/commit/848f3dff9d55e6c08779ae3696c6053d406d2f32))
|
||||||
|
|
||||||
|
# [0.2.0-develop.10](https://git.lumeweb.com/LumeWeb/libportal/compare/v0.2.0-develop.9...v0.2.0-develop.10) (2023-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add missing controller.enqueue ([2aa53fa](https://git.lumeweb.com/LumeWeb/libportal/commit/2aa53faf00cc7024a24dc97fffaeb855faa4e650))
|
||||||
|
* add properties and methods to go wasm middleware, accessed via reflection ([53dd352](https://git.lumeweb.com/LumeWeb/libportal/commit/53dd352c95fec8ec266a53c03f19cecbecf8821b))
|
||||||
|
* ensure root and proof are Uint8Array's ([0c320f9](https://git.lumeweb.com/LumeWeb/libportal/commit/0c320f992bdf269614716b51818ed7063086c01c))
|
||||||
|
* exit not properly exported in wasm ([23a55f7](https://git.lumeweb.com/LumeWeb/libportal/commit/23a55f772b7dde7712742ee5f47a5fda5bb8afd2))
|
||||||
|
* fix wasmDone logic error ([68fec66](https://git.lumeweb.com/LumeWeb/libportal/commit/68fec66069721a6dc94027419ddd2cafbc877cbc))
|
||||||
|
* need to refactor verification stream logic further and check if the stream is done but wasm isn't ([051f4b2](https://git.lumeweb.com/LumeWeb/libportal/commit/051f4b2da75ab2287c99a3514af5d0d4f28017bf))
|
||||||
|
* rename exit to kill to fix symbol conflict ([50a7c80](https://git.lumeweb.com/LumeWeb/libportal/commit/50a7c803584b57e4e294aca117fc1e8b9a2a09c7))
|
||||||
|
* update uploadFile overload types ([45fbc1b](https://git.lumeweb.com/LumeWeb/libportal/commit/45fbc1b63d2c19e186d6f21b022fee62be61866a))
|
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
|
@ -1,9 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "@lumeweb/libportal",
|
"name": "@lumeweb/libportal",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0-develop.41",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "lib/index.mjs",
|
"type": "module",
|
||||||
"types": "lib/index.d.ts",
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "gitea@git.lumeweb.com:LumeWeb/libportal.git"
|
"url": "gitea@git.lumeweb.com:LumeWeb/libportal.git"
|
||||||
|
@ -16,24 +15,26 @@
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@lumeweb/node-library-preset": "^0.2.7",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/commit-analyzer": "^10.0.1",
|
"@semantic-release/commit-analyzer": "^10.0.1",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"@semantic-release/npm": "^10.0.4",
|
"@semantic-release/npm": "^10.0.4",
|
||||||
"@semantic-release/release-notes-generator": "^11.0.3",
|
"@semantic-release/release-notes-generator": "^11.0.3",
|
||||||
"presetter": "^3.5.5",
|
"presetter": "^4.0.1",
|
||||||
"presetter-preset-essentials": "^3.5.5",
|
"presetter-preset-hybrid": "4.0.1",
|
||||||
"presetter-preset-hybrid": "^3.5.5",
|
"presetter-preset-strict": "^4.0.1",
|
||||||
"semantic-release": "^21.0.5"
|
"semantic-release": "^21.0.5"
|
||||||
},
|
},
|
||||||
"readme": "ERROR: No README data found!",
|
"readme": "ERROR: No README data found!",
|
||||||
"_id": "@lumeweb/libportal@0.1.0",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "presetter bootstrap",
|
"prepare": "presetter bootstrap",
|
||||||
"build": "presetter run build",
|
"build": "run build",
|
||||||
|
"build:wasm": "bash -c \"source ~/.gvm/scripts/gvm; mkdir ./lib/wasm && cd src/golang; tinygo build -o ../../lib/wasm/bao.wasm -target wasm ./main.go\"",
|
||||||
"semantic-release": "semantic-release"
|
"semantic-release": "semantic-release"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@lumeweb/libs5": "^0.1.0-develop.61",
|
||||||
"@noble/curves": "^1.1.0",
|
"@noble/curves": "^1.1.0",
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"detect-node": "^2.1.0",
|
"detect-node": "^2.1.0",
|
||||||
|
|
74
src/cid.ts
74
src/cid.ts
|
@ -1,74 +0,0 @@
|
||||||
import { base58btc } from "multiformats/bases/base58";
|
|
||||||
import * as edUtils from "@noble/curves/abstract/utils";
|
|
||||||
|
|
||||||
export const MAGIC_BYTES = new Uint8Array([0x26, 0x1f]);
|
|
||||||
|
|
||||||
export interface CID {
|
|
||||||
hash: Uint8Array;
|
|
||||||
size: bigint;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function encodeCid(hash: Uint8Array, size: bigint);
|
|
||||||
export function encodeCid(hash: string, size: bigint);
|
|
||||||
export function encodeCid(hash: any, size: bigint) {
|
|
||||||
if (typeof hash === "string") {
|
|
||||||
hash = edUtils.hexToBytes(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(hash instanceof Uint8Array)) {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!size) {
|
|
||||||
throw new Error("size required");
|
|
||||||
}
|
|
||||||
|
|
||||||
size = BigInt(size);
|
|
||||||
|
|
||||||
const sizeBytes = new Uint8Array(8);
|
|
||||||
const sizeView = new DataView(sizeBytes.buffer);
|
|
||||||
sizeView.setBigInt64(0, size, true);
|
|
||||||
|
|
||||||
const prefixedHash = Uint8Array.from([...MAGIC_BYTES, ...hash, ...sizeBytes]);
|
|
||||||
return base58btc.encode(prefixedHash).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decodeCid(cid: string): CID {
|
|
||||||
let bytes = base58btc.decode(cid);
|
|
||||||
|
|
||||||
if (!arrayBufferEqual(bytes.slice(0, 2).buffer, bytes.buffer)) {
|
|
||||||
throw new Error("Invalid cid");
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = bytes.slice(2);
|
|
||||||
let cidHash = bytes.slice(0, 32);
|
|
||||||
let size = bytes.slice(32);
|
|
||||||
const sizeView = new DataView(size.buffer);
|
|
||||||
|
|
||||||
return {
|
|
||||||
hash: cidHash,
|
|
||||||
size: sizeView.getBigInt64(0, true),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function arrayBufferEqual(buf1, buf2) {
|
|
||||||
if (buf1 === buf2) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buf1.byteLength !== buf2.byteLength) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var view1 = new DataView(buf1);
|
|
||||||
var view2 = new DataView(buf2);
|
|
||||||
|
|
||||||
var i = buf1.byteLength;
|
|
||||||
while (i--) {
|
|
||||||
if (view1.getUint8(i) !== view2.getUint8(i)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
193
src/client.ts
193
src/client.ts
|
@ -2,13 +2,6 @@ import { ed25519 as ed } from "@noble/curves/ed25519";
|
||||||
import * as edUtils from "@noble/curves/abstract/utils";
|
import * as edUtils from "@noble/curves/abstract/utils";
|
||||||
|
|
||||||
import { RegisterRequest } from "./requests/account.js";
|
import { RegisterRequest } from "./requests/account.js";
|
||||||
import fetch, {
|
|
||||||
FormData,
|
|
||||||
Blob,
|
|
||||||
RequestInit,
|
|
||||||
Response,
|
|
||||||
HeadersInit,
|
|
||||||
} from "node-fetch";
|
|
||||||
import {
|
import {
|
||||||
LoginRequest,
|
LoginRequest,
|
||||||
LogoutRequest,
|
LogoutRequest,
|
||||||
|
@ -21,24 +14,29 @@ import {
|
||||||
UploadStatusResponse,
|
UploadStatusResponse,
|
||||||
} from "./responses/files.js";
|
} from "./responses/files.js";
|
||||||
|
|
||||||
import TUS from "tus-js-client";
|
import * as TUS from "tus-js-client";
|
||||||
import streamToBlob from "stream-to-blob";
|
import streamToBlob from "stream-to-blob";
|
||||||
|
|
||||||
import defer from "p-defer";
|
import defer from "p-defer";
|
||||||
import { blake3 } from "@noble/hashes/blake3";
|
import { blake3 } from "@noble/hashes/blake3";
|
||||||
import { encodeCid } from "./cid.js";
|
|
||||||
import { Readable as NodeReadableStream } from "stream";
|
|
||||||
import {
|
import {
|
||||||
AuthStatusResponse,
|
AuthStatusResponse,
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
PubkeyChallengeResponse,
|
PubkeyChallengeResponse,
|
||||||
} from "./responses/auth.js";
|
} from "./responses/auth.js";
|
||||||
|
import isNode from "detect-node";
|
||||||
|
import { utf8ToBytes } from "@noble/curves/abstract/utils";
|
||||||
|
import { CID, CID_TYPES } from "@lumeweb/libs5";
|
||||||
|
|
||||||
|
type NodeReadableStreamType = typeof import("stream").Readable;
|
||||||
|
type NodePassThroughStreamType = typeof import("stream").PassThrough;
|
||||||
|
|
||||||
export interface ClientOptions {
|
export interface ClientOptions {
|
||||||
portalUrl: string;
|
portalUrl: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
privateKey?: Uint8Array;
|
privateKey?: Uint8Array;
|
||||||
|
jwt?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FetchOptions {
|
interface FetchOptions {
|
||||||
|
@ -62,6 +60,10 @@ export class Client {
|
||||||
throw new Error("Portal url is required");
|
throw new Error("Portal url is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.jwt) {
|
||||||
|
this.jwtSessionKey = options.jwt;
|
||||||
|
}
|
||||||
|
|
||||||
this._options = options;
|
this._options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +71,10 @@ export class Client {
|
||||||
return this._options.email as string;
|
return this._options.email as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get portalUrl(): string {
|
||||||
|
return this._options.portalUrl as string;
|
||||||
|
}
|
||||||
|
|
||||||
set email(email: string) {
|
set email(email: string) {
|
||||||
this._options.email = email;
|
this._options.email = email;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +83,10 @@ export class Client {
|
||||||
return this._options.password as string;
|
return this._options.password as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get jwt(): string | undefined {
|
||||||
|
return this.jwtSessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
set password(password: string) {
|
set password(password: string) {
|
||||||
this._options.email = password;
|
this._options.email = password;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +115,10 @@ export class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(): Promise<LoginResponse> {
|
async login(): Promise<LoginResponse> {
|
||||||
|
if (this._options.privateKey) {
|
||||||
|
return this.loginPubkey();
|
||||||
|
}
|
||||||
|
|
||||||
return this.post<LoginResponse>("/api/v1/auth/login", {
|
return this.post<LoginResponse>("/api/v1/auth/login", {
|
||||||
email: this._options.email,
|
email: this._options.email,
|
||||||
password: this._options.password,
|
password: this._options.password,
|
||||||
|
@ -131,7 +145,7 @@ export class Client {
|
||||||
return json.status as boolean;
|
return json.status as boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async loginPubkey(): Promise<void> {
|
async loginPubkey(): Promise<LoginResponse> {
|
||||||
if (!this._options.privateKey) {
|
if (!this._options.privateKey) {
|
||||||
throw new Error("Private key is required");
|
throw new Error("Private key is required");
|
||||||
}
|
}
|
||||||
|
@ -144,7 +158,7 @@ export class Client {
|
||||||
);
|
);
|
||||||
|
|
||||||
const signature = ed.sign(
|
const signature = ed.sign(
|
||||||
new TextEncoder().encode(challenge.challenge),
|
utf8ToBytes(challenge.challenge),
|
||||||
this._options.privateKey,
|
this._options.privateKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -158,6 +172,8 @@ export class Client {
|
||||||
);
|
);
|
||||||
|
|
||||||
this.jwtSessionKey = loginRet.token;
|
this.jwtSessionKey = loginRet.token;
|
||||||
|
|
||||||
|
return { token: loginRet.token };
|
||||||
}
|
}
|
||||||
|
|
||||||
logout(request: LogoutRequest): Promise<void> {
|
logout(request: LogoutRequest): Promise<void> {
|
||||||
|
@ -186,6 +202,7 @@ export class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadProof(cid: string): Promise<ArrayBuffer> {
|
async downloadProof(cid: string): Promise<ArrayBuffer> {
|
||||||
|
const Response = await this.getFetchResponseObject();
|
||||||
return await new Response(
|
return await new Response(
|
||||||
await this.get<any>(`/api/v1/files/proof/${cid}`, {
|
await this.get<any>(`/api/v1/files/proof/${cid}`, {
|
||||||
auth: true,
|
auth: true,
|
||||||
|
@ -206,13 +223,27 @@ export class Client {
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
fetchOptions.body = options.data;
|
fetchOptions.body = options.data;
|
||||||
|
|
||||||
if (!(fetchOptions.body instanceof FormData)) {
|
const _FormData = await this.getFormDataObject();
|
||||||
|
|
||||||
|
if (!(fetchOptions.body instanceof _FormData)) {
|
||||||
fetchOptions.headers["Content-Type"] = "application/json";
|
fetchOptions.headers["Content-Type"] = "application/json";
|
||||||
fetchOptions.body = JSON.stringify(fetchOptions.body);
|
fetchOptions.body = JSON.stringify(fetchOptions.body);
|
||||||
|
} else {
|
||||||
|
if (isNode) {
|
||||||
|
const formDataToBlob = (
|
||||||
|
await import("formdata-polyfill/formdata-to-blob.js")
|
||||||
|
).formDataToBlob;
|
||||||
|
const Blob = (await import("node-fetch")).Blob;
|
||||||
|
const blob = formDataToBlob(fetchOptions.body, Blob);
|
||||||
|
// @ts-ignore
|
||||||
|
fetchOptions.body = Buffer.from(await blob.arrayBuffer());
|
||||||
|
fetchOptions.headers["Content-Type"] = blob.type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(this.getEndpoint(path), fetchOptions);
|
const fetch = await this.getFetchObject();
|
||||||
|
const response = await fetch(this.getEndpoint(path), fetchOptions as any);
|
||||||
|
|
||||||
if (!options.fullResponse) {
|
if (!options.fullResponse) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
@ -261,23 +292,21 @@ export class Client {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadFile(stream: Blob, size?: bigint);
|
async uploadFile(stream: Blob, size?: bigint): Promise<CID>;
|
||||||
async uploadFile(
|
async uploadFile(
|
||||||
stream: ReadableStream,
|
stream: ReadableStream,
|
||||||
hashStream: ReadableStream,
|
hashStream: ReadableStream,
|
||||||
size: bigint,
|
size: bigint,
|
||||||
);
|
): Promise<CID>;
|
||||||
async uploadFile(stream: Uint8Array, size?: bigint);
|
async uploadFile(stream: Uint8Array, size?: bigint): Promise<CID>;
|
||||||
async uploadFile(
|
async uploadFile(
|
||||||
stream: NodeJS.ReadableStream,
|
stream: NodeJS.ReadableStream,
|
||||||
hashStream: NodeJS.ReadableStream,
|
hashStream: NodeJS.ReadableStream,
|
||||||
size?: bigint,
|
size?: bigint,
|
||||||
);
|
): Promise<CID>;
|
||||||
async uploadFile(
|
async uploadFile(stream: any, hashStream?: any, size?: bigint): Promise<CID> {
|
||||||
stream: any,
|
const Blob = await this.getBlobObject();
|
||||||
hashStream?: any,
|
|
||||||
size?: bigint,
|
|
||||||
): Promise<string> {
|
|
||||||
if (stream instanceof Uint8Array || stream instanceof Blob) {
|
if (stream instanceof Uint8Array || stream instanceof Blob) {
|
||||||
size = BigInt(stream.length);
|
size = BigInt(stream.length);
|
||||||
}
|
}
|
||||||
|
@ -295,36 +324,47 @@ export class Client {
|
||||||
return this.uploadFileTus(stream, hashStream, size);
|
return this.uploadFileTus(stream, hashStream, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async uploadFileSmall(stream: Blob): Promise<string>;
|
private async uploadFileSmall(stream: Blob): Promise<CID>;
|
||||||
private async uploadFileSmall(
|
private async uploadFileSmall(
|
||||||
stream: ReadableStream,
|
stream: ReadableStream,
|
||||||
hashStream: ReadableStream,
|
hashStream: ReadableStream,
|
||||||
): Promise<string>;
|
): Promise<CID>;
|
||||||
private async uploadFileSmall(stream: Uint8Array): Promise<string>;
|
private async uploadFileSmall(stream: Uint8Array): Promise<CID>;
|
||||||
private async uploadFileSmall(stream: NodeJS.ReadableStream): Promise<string>;
|
private async uploadFileSmall(stream: NodeJS.ReadableStream): Promise<CID>;
|
||||||
private async uploadFileSmall(stream: any): Promise<string> {
|
private async uploadFileSmall(stream: any): Promise<CID> {
|
||||||
|
const Blob = await this.getBlobObject();
|
||||||
|
|
||||||
if (stream instanceof ReadableStream) {
|
if (stream instanceof ReadableStream) {
|
||||||
stream = await streamToBlob(stream);
|
stream = await streamToBlob(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream instanceof NodeReadableStream) {
|
let NodeReadableStream =
|
||||||
let data = new Uint8Array();
|
(await this.getNodeReadableObject()) as NodeReadableStreamType;
|
||||||
for await (const chunk of stream) {
|
|
||||||
data = Uint8Array.from([...data, ...chunk]);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = data;
|
let NodePassThroughStream =
|
||||||
|
(await this.getNodePassThroughObject()) as NodePassThroughStreamType;
|
||||||
|
|
||||||
|
if (NodeReadableStream && stream instanceof NodeReadableStream) {
|
||||||
|
const Response = await this.getFetchResponseObject();
|
||||||
|
stream = await new Response(
|
||||||
|
stream.pipe(new NodePassThroughStream()) as any,
|
||||||
|
).blob();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream instanceof Uint8Array) {
|
if (stream instanceof Uint8Array) {
|
||||||
stream = new Blob([Buffer.from(stream)]);
|
stream = new Blob([Buffer.from(stream)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(stream instanceof Blob) && !(stream instanceof NodeReadableStream)) {
|
if (
|
||||||
|
!(stream instanceof Blob) &&
|
||||||
|
!(NodeReadableStream && stream instanceof NodeReadableStream)
|
||||||
|
) {
|
||||||
throw new Error("Invalid stream");
|
throw new Error("Invalid stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const _FormData = await this.getFormDataObject();
|
||||||
|
|
||||||
|
const formData = new _FormData();
|
||||||
formData.set("file", stream as Blob);
|
formData.set("file", stream as Blob);
|
||||||
|
|
||||||
const response = await this.post<UploadResponse>(
|
const response = await this.post<UploadResponse>(
|
||||||
|
@ -333,29 +373,26 @@ export class Client {
|
||||||
{ auth: true },
|
{ auth: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.cid;
|
return CID.decode(response.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async uploadFileTus(stream: Blob, size?: bigint): Promise<string>;
|
private async uploadFileTus(stream: Blob, size?: bigint): Promise<CID>;
|
||||||
private async uploadFileTus(
|
private async uploadFileTus(
|
||||||
stream: ReadableStream,
|
stream: ReadableStream,
|
||||||
hashStream: ReadableStream,
|
hashStream: ReadableStream,
|
||||||
size?: bigint,
|
size?: bigint,
|
||||||
): Promise<string>;
|
): Promise<CID>;
|
||||||
private async uploadFileTus(
|
private async uploadFileTus(stream: Uint8Array, size?: bigint): Promise<CID>;
|
||||||
stream: Uint8Array,
|
|
||||||
size?: bigint,
|
|
||||||
): Promise<string>;
|
|
||||||
private async uploadFileTus(
|
private async uploadFileTus(
|
||||||
stream: NodeJS.ReadableStream,
|
stream: NodeJS.ReadableStream,
|
||||||
hashStream: ReadableStream,
|
hashStream: ReadableStream,
|
||||||
size?: bigint,
|
size?: bigint,
|
||||||
): Promise<string>;
|
): Promise<CID>;
|
||||||
private async uploadFileTus(
|
private async uploadFileTus(
|
||||||
stream: any,
|
stream: any,
|
||||||
hashStream?: any,
|
hashStream?: any,
|
||||||
size?: bigint,
|
size?: bigint,
|
||||||
): Promise<string> {
|
): Promise<CID> {
|
||||||
if (["bigint", "number"].includes(typeof hashStream)) {
|
if (["bigint", "number"].includes(typeof hashStream)) {
|
||||||
size = BigInt(hashStream);
|
size = BigInt(hashStream);
|
||||||
hashStream = undefined;
|
hashStream = undefined;
|
||||||
|
@ -368,7 +405,10 @@ export class Client {
|
||||||
hash = await this.computeHash(hashStream);
|
hash = await this.computeHash(hashStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream instanceof NodeReadableStream) {
|
let NodeReadableStream =
|
||||||
|
(await this.getNodeReadableObject()) as NodeReadableStreamType;
|
||||||
|
|
||||||
|
if (NodeReadableStream && stream instanceof NodeReadableStream) {
|
||||||
hash = await this.computeHash(hashStream);
|
hash = await this.computeHash(hashStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +421,7 @@ export class Client {
|
||||||
if (
|
if (
|
||||||
!(stream instanceof ReadableStreamDefaultReader) &&
|
!(stream instanceof ReadableStreamDefaultReader) &&
|
||||||
!(stream instanceof Blob) &&
|
!(stream instanceof Blob) &&
|
||||||
!(stream instanceof NodeReadableStream)
|
!(NodeReadableStream && stream instanceof NodeReadableStream)
|
||||||
) {
|
) {
|
||||||
throw new Error("Invalid stream");
|
throw new Error("Invalid stream");
|
||||||
}
|
}
|
||||||
|
@ -426,10 +466,10 @@ export class Client {
|
||||||
|
|
||||||
await ret.promise;
|
await ret.promise;
|
||||||
|
|
||||||
const cid = encodeCid(hash, size as bigint);
|
const cid = CID.fromHash(hash, Number(size));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const status = await this.getUploadStatus(cid as string);
|
const status = await this.getUploadStatus(cid.toString());
|
||||||
|
|
||||||
if (status.status === "uploaded") {
|
if (status.status === "uploaded") {
|
||||||
break;
|
break;
|
||||||
|
@ -440,7 +480,7 @@ export class Client {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return cid as string;
|
return cid;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUploadStatus(cid: string) {
|
async getUploadStatus(cid: string) {
|
||||||
|
@ -471,7 +511,10 @@ export class Client {
|
||||||
return edUtils.bytesToHex(hasher.digest());
|
return edUtils.bytesToHex(hasher.digest());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream instanceof NodeReadableStream) {
|
let NodeReadableStream =
|
||||||
|
(await this.getNodeReadableObject()) as NodeReadableStreamType;
|
||||||
|
|
||||||
|
if (NodeReadableStream && stream instanceof NodeReadableStream) {
|
||||||
const hasher = blake3.create({});
|
const hasher = blake3.create({});
|
||||||
|
|
||||||
for await (const chunk of stream) {
|
for await (const chunk of stream) {
|
||||||
|
@ -489,4 +532,52 @@ export class Client {
|
||||||
|
|
||||||
throw new Error("Invalid stream");
|
throw new Error("Invalid stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async getFormDataObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("node-fetch")).FormData;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FormData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getBlobObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("node-fetch")).Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getNodeReadableObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("stream")).Readable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getNodePassThroughObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("stream")).PassThrough;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getFetchObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("node-fetch")).default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getFetchResponseObject() {
|
||||||
|
if (isNode) {
|
||||||
|
return (await import("node-fetch")).Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,663 @@
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
type ImportObject = {
|
||||||
|
wasi_snapshot_preview1: {
|
||||||
|
proc_exit: (code) => void;
|
||||||
|
random_get: (bufPtr, bufLen) => number;
|
||||||
|
fd_seek: () => number;
|
||||||
|
fd_write: (fd, iovs_ptr, iovs_len, nwritten_ptr) => number;
|
||||||
|
fd_close: () => number;
|
||||||
|
fd_fdstat_get: () => number;
|
||||||
|
};
|
||||||
|
env: {
|
||||||
|
"syscall/js.valueInvoke": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.valueDelete": (v_addr, p_ptr, p_len) => void;
|
||||||
|
"syscall/js.copyBytesToGo": (
|
||||||
|
ret_addr,
|
||||||
|
dest_addr,
|
||||||
|
dest_len,
|
||||||
|
dest_cap,
|
||||||
|
source_addr,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => void;
|
||||||
|
"syscall/js.copyBytesToJS": (
|
||||||
|
ret_addr,
|
||||||
|
dest_addr,
|
||||||
|
source_addr,
|
||||||
|
source_len,
|
||||||
|
source_cap,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.valueNew": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.valueInstanceOf": (v_addr, t_addr) => boolean;
|
||||||
|
"runtime.ticks": () => number;
|
||||||
|
"runtime.sleepTicks": (timeout) => void;
|
||||||
|
"syscall/js.valueLoadString": (
|
||||||
|
v_addr,
|
||||||
|
slice_ptr,
|
||||||
|
slice_len,
|
||||||
|
slice_cap,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => void;
|
||||||
|
"syscall/js.valueIndex": (ret_addr, v_addr, i) => void;
|
||||||
|
"syscall/js.valueLength": (v_addr) => any;
|
||||||
|
"syscall/js.valueCall": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
m_ptr,
|
||||||
|
m_len,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => void;
|
||||||
|
"syscall/js.finalizeRef": (sp) => void;
|
||||||
|
"syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => void;
|
||||||
|
"syscall/js.valuePrepareString": (ret_addr, v_addr) => void;
|
||||||
|
"syscall/js.valueSetIndex": (v_addr, i, x_addr) => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let logLine: any = [];
|
||||||
|
|
||||||
|
export default class Go {
|
||||||
|
private _callbackTimeouts: Map<any, any>;
|
||||||
|
private _nextCallbackTimeoutID: number;
|
||||||
|
private _inst?: any;
|
||||||
|
private _values: any[] = [NaN, 0, null, true, false, global, this];
|
||||||
|
private _ids: Map<any, any> = new Map<any, any>();
|
||||||
|
private _idPool: any[] = [];
|
||||||
|
private _goRefCounts: any[] = [];
|
||||||
|
private exited = false;
|
||||||
|
private _resolveCallbackPromise?: () => void;
|
||||||
|
importObject: ImportObject;
|
||||||
|
private _pendingEvent?: any;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._callbackTimeouts = new Map();
|
||||||
|
this._nextCallbackTimeoutID = 1;
|
||||||
|
|
||||||
|
const mem = () => {
|
||||||
|
// The buffer may change when requesting more memory.
|
||||||
|
return new DataView(this._inst.exports.memory.buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setInt64 = (addr, v) => {
|
||||||
|
mem().setUint32(addr + 0, v, true);
|
||||||
|
mem().setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInt64 = (addr) => {
|
||||||
|
const low = mem().getUint32(addr + 0, true);
|
||||||
|
const high = mem().getInt32(addr + 4, true);
|
||||||
|
return low + high * 4294967296;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadValue = (addr) => {
|
||||||
|
const f = mem().getFloat64(addr, true);
|
||||||
|
if (f === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (!isNaN(f)) {
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = mem().getUint32(addr, true);
|
||||||
|
return this._values[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
const storeValue = (addr, v) => {
|
||||||
|
const nanHead = 0x7ff80000;
|
||||||
|
|
||||||
|
if (typeof v === "number") {
|
||||||
|
if (isNaN(v)) {
|
||||||
|
mem().setUint32(addr + 4, nanHead, true);
|
||||||
|
mem().setUint32(addr, 0, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (v === 0) {
|
||||||
|
mem().setUint32(addr + 4, nanHead, true);
|
||||||
|
mem().setUint32(addr, 1, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mem().setFloat64(addr, v, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v) {
|
||||||
|
case undefined:
|
||||||
|
mem().setFloat64(addr, 0, true);
|
||||||
|
return;
|
||||||
|
case null:
|
||||||
|
mem().setUint32(addr + 4, nanHead, true);
|
||||||
|
mem().setUint32(addr, 2, true);
|
||||||
|
return;
|
||||||
|
case true:
|
||||||
|
mem().setUint32(addr + 4, nanHead, true);
|
||||||
|
mem().setUint32(addr, 3, true);
|
||||||
|
return;
|
||||||
|
case false:
|
||||||
|
mem().setUint32(addr + 4, nanHead, true);
|
||||||
|
mem().setUint32(addr, 4, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = this._ids.get(v);
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._idPool.pop();
|
||||||
|
if (id === undefined) {
|
||||||
|
id = this._values.length;
|
||||||
|
}
|
||||||
|
this._values[id] = v;
|
||||||
|
this._goRefCounts[id] = 0;
|
||||||
|
this._ids.set(v, id);
|
||||||
|
}
|
||||||
|
this._goRefCounts[id]++;
|
||||||
|
let typeFlag = 1;
|
||||||
|
switch (typeof v) {
|
||||||
|
case "string":
|
||||||
|
typeFlag = 2;
|
||||||
|
break;
|
||||||
|
case "symbol":
|
||||||
|
typeFlag = 3;
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
typeFlag = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mem().setUint32(addr + 4, nanHead | typeFlag, true);
|
||||||
|
mem().setUint32(addr, id, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadSlice = (array, len, cap?) => {
|
||||||
|
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadSliceOfValues = (array, len, cap) => {
|
||||||
|
const a = new Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
a[i] = loadValue(array + i * 8);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadString = (ptr, len) => {
|
||||||
|
return decoder.decode(
|
||||||
|
new DataView(this._inst.exports.memory.buffer, ptr, len),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeOrigin = Date.now() - performance.now();
|
||||||
|
this.importObject = {
|
||||||
|
wasi_snapshot_preview1: {
|
||||||
|
fd_write: (fd, iovs_ptr, iovs_len, nwritten_ptr) => {
|
||||||
|
let nwritten = 0;
|
||||||
|
if (fd == 1) {
|
||||||
|
for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) {
|
||||||
|
let iov_ptr = iovs_ptr + iovs_i * 8;
|
||||||
|
let ptr = mem().getUint32(iov_ptr + 0, true);
|
||||||
|
let len = mem().getUint32(iov_ptr + 4, true);
|
||||||
|
nwritten += len;
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
let c = mem().getUint8(ptr + i);
|
||||||
|
if (c == 13) {
|
||||||
|
// CR
|
||||||
|
// ignore
|
||||||
|
} else if (c == 10) {
|
||||||
|
// LF
|
||||||
|
// write line
|
||||||
|
let line = decoder.decode(new Uint8Array(logLine));
|
||||||
|
logLine = [];
|
||||||
|
console.log(line);
|
||||||
|
} else {
|
||||||
|
logLine.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error("Invalid file descriptor:", fd);
|
||||||
|
}
|
||||||
|
mem().setUint32(nwritten_ptr, nwritten, true);
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
fd_close: () => 0, // dummy
|
||||||
|
fd_fdstat_get: () => 0, // dummy
|
||||||
|
fd_seek: () => 0, // dummy
|
||||||
|
proc_exit: (code) => {
|
||||||
|
if (global.process) {
|
||||||
|
// Node.js
|
||||||
|
process.exit(code);
|
||||||
|
} else {
|
||||||
|
// Can't exit in a browser.
|
||||||
|
throw "Trying to exit with code " + code;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
random_get: (bufPtr, bufLen) => {
|
||||||
|
crypto.getRandomValues(loadSlice(bufPtr, bufLen));
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
"runtime.ticks": () => {
|
||||||
|
return timeOrigin + performance.now();
|
||||||
|
},
|
||||||
|
"runtime.sleepTicks": (timeout) => {
|
||||||
|
setTimeout(this._inst.exports.go_scheduler, timeout);
|
||||||
|
},
|
||||||
|
"syscall/js.finalizeRef": (sp) => {
|
||||||
|
console.error("syscall/js.finalizeRef not implemented");
|
||||||
|
},
|
||||||
|
"syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => {
|
||||||
|
const s = loadString(value_ptr, value_len);
|
||||||
|
storeValue(ret_ptr, s);
|
||||||
|
},
|
||||||
|
"syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => {
|
||||||
|
let prop = loadString(p_ptr, p_len);
|
||||||
|
let value = loadValue(v_addr);
|
||||||
|
let result = Reflect.get(value, prop);
|
||||||
|
storeValue(retval, result);
|
||||||
|
},
|
||||||
|
"syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => {
|
||||||
|
const v = loadValue(v_addr);
|
||||||
|
const p = loadString(p_ptr, p_len);
|
||||||
|
const x = loadValue(x_addr);
|
||||||
|
Reflect.set(v, p, x);
|
||||||
|
},
|
||||||
|
"syscall/js.valueDelete": (v_addr, p_ptr, p_len) => {
|
||||||
|
const v = loadValue(v_addr);
|
||||||
|
const p = loadString(p_ptr, p_len);
|
||||||
|
Reflect.deleteProperty(v, p);
|
||||||
|
},
|
||||||
|
"syscall/js.valueIndex": (ret_addr, v_addr, i) => {
|
||||||
|
storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
|
||||||
|
},
|
||||||
|
"syscall/js.valueSetIndex": (v_addr, i, x_addr) => {
|
||||||
|
Reflect.set(loadValue(v_addr), i, loadValue(x_addr));
|
||||||
|
},
|
||||||
|
"syscall/js.valueCall": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
m_ptr,
|
||||||
|
m_len,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => {
|
||||||
|
const v = loadValue(v_addr);
|
||||||
|
const name = loadString(m_ptr, m_len);
|
||||||
|
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||||
|
try {
|
||||||
|
const m = Reflect.get(v, name);
|
||||||
|
storeValue(ret_addr, Reflect.apply(m, v, args));
|
||||||
|
mem().setUint8(ret_addr + 8, 1);
|
||||||
|
} catch (err) {
|
||||||
|
storeValue(ret_addr, err);
|
||||||
|
mem().setUint8(ret_addr + 8, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syscall/js.valueInvoke": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const v = loadValue(v_addr);
|
||||||
|
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||||
|
storeValue(ret_addr, Reflect.apply(v, undefined, args));
|
||||||
|
mem().setUint8(ret_addr + 8, 1);
|
||||||
|
} catch (err) {
|
||||||
|
storeValue(ret_addr, err);
|
||||||
|
mem().setUint8(ret_addr + 8, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syscall/js.valueNew": (
|
||||||
|
ret_addr,
|
||||||
|
v_addr,
|
||||||
|
args_ptr,
|
||||||
|
args_len,
|
||||||
|
args_cap,
|
||||||
|
) => {
|
||||||
|
const v = loadValue(v_addr);
|
||||||
|
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
||||||
|
try {
|
||||||
|
storeValue(ret_addr, Reflect.construct(v, args));
|
||||||
|
mem().setUint8(ret_addr + 8, 1);
|
||||||
|
} catch (err) {
|
||||||
|
storeValue(ret_addr, err);
|
||||||
|
mem().setUint8(ret_addr + 8, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"syscall/js.valueLength": (v_addr) => {
|
||||||
|
return loadValue(v_addr).length;
|
||||||
|
},
|
||||||
|
"syscall/js.valuePrepareString": (ret_addr, v_addr) => {
|
||||||
|
const s = String(loadValue(v_addr));
|
||||||
|
const str = encoder.encode(s);
|
||||||
|
storeValue(ret_addr, str);
|
||||||
|
setInt64(ret_addr + 8, str.length);
|
||||||
|
},
|
||||||
|
"syscall/js.valueLoadString": (
|
||||||
|
v_addr,
|
||||||
|
slice_ptr,
|
||||||
|
slice_len,
|
||||||
|
slice_cap,
|
||||||
|
) => {
|
||||||
|
const str = loadValue(v_addr);
|
||||||
|
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
||||||
|
},
|
||||||
|
"syscall/js.valueInstanceOf": (v_addr, t_addr) => {
|
||||||
|
return loadValue(v_addr) instanceof loadValue(t_addr);
|
||||||
|
},
|
||||||
|
"syscall/js.copyBytesToGo": (
|
||||||
|
ret_addr,
|
||||||
|
dest_addr,
|
||||||
|
dest_len,
|
||||||
|
dest_cap,
|
||||||
|
source_addr,
|
||||||
|
) => {
|
||||||
|
let num_bytes_copied_addr = ret_addr;
|
||||||
|
let returned_status_addr = ret_addr + 4;
|
||||||
|
|
||||||
|
const dst = loadSlice(dest_addr, dest_len, dest_cap);
|
||||||
|
const src = loadValue(source_addr);
|
||||||
|
if (
|
||||||
|
!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)
|
||||||
|
) {
|
||||||
|
mem().setUint8(returned_status_addr, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(num_bytes_copied_addr, toCopy.length);
|
||||||
|
mem().setUint8(returned_status_addr, 1);
|
||||||
|
},
|
||||||
|
"syscall/js.copyBytesToJS": (
|
||||||
|
ret_addr,
|
||||||
|
dest_addr,
|
||||||
|
source_addr,
|
||||||
|
source_len,
|
||||||
|
source_cap,
|
||||||
|
) => {
|
||||||
|
let num_bytes_copied_addr = ret_addr;
|
||||||
|
let returned_status_addr = ret_addr + 4;
|
||||||
|
|
||||||
|
const dst = loadValue(dest_addr);
|
||||||
|
const src = loadSlice(source_addr, source_len, source_cap);
|
||||||
|
if (
|
||||||
|
!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)
|
||||||
|
) {
|
||||||
|
mem().setUint8(returned_status_addr, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toCopy = src.subarray(0, dst.length);
|
||||||
|
dst.set(toCopy);
|
||||||
|
setInt64(num_bytes_copied_addr, toCopy.length);
|
||||||
|
mem().setUint8(returned_status_addr, 1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(instance) {
|
||||||
|
this._inst = instance;
|
||||||
|
const mem = new DataView(this._inst.exports.memory.buffer);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const callbackPromise = new Promise((resolve) => {
|
||||||
|
this._resolveCallbackPromise = () => {
|
||||||
|
if (this.exited) {
|
||||||
|
throw new Error("Bad callback: Go program has already exited");
|
||||||
|
}
|
||||||
|
setTimeout(resolve, 0);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this._inst.exports._start();
|
||||||
|
if (this.exited) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await callbackPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_resume() {
|
||||||
|
if (this.exited) {
|
||||||
|
throw new Error("Go program has already exited");
|
||||||
|
}
|
||||||
|
this._inst.exports.resume();
|
||||||
|
}
|
||||||
|
_makeFuncWrapper(id) {
|
||||||
|
const go = this;
|
||||||
|
return function () {
|
||||||
|
const event = { id: id, this: this, args: arguments };
|
||||||
|
go._pendingEvent = event;
|
||||||
|
go._resume();
|
||||||
|
// @ts-ignore
|
||||||
|
return event.result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof global !== "undefined" ||
|
||||||
|
typeof window !== "undefined" ||
|
||||||
|
typeof self !== "undefined"
|
||||||
|
) {
|
||||||
|
if (typeof global !== "undefined") {
|
||||||
|
// global already exists
|
||||||
|
} else if (typeof window !== "undefined") {
|
||||||
|
window.global = window;
|
||||||
|
} else if (typeof self !== "undefined") {
|
||||||
|
self.global = self;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
"Cannot export Go (neither global, window nor self is defined)",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.require && typeof require !== "undefined") {
|
||||||
|
global.require = require;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
if (!global.fs && global.require) {
|
||||||
|
global.fs = require("fs");
|
||||||
|
}
|
||||||
|
|
||||||
|
const enosys = () => {
|
||||||
|
const err = new Error("not implemented");
|
||||||
|
// @ts-ignore
|
||||||
|
err.code = "ENOSYS";
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!global.fs) {
|
||||||
|
let outputBuf = "";
|
||||||
|
global.fs = {
|
||||||
|
constants: {
|
||||||
|
O_WRONLY: -1,
|
||||||
|
O_RDWR: -1,
|
||||||
|
O_CREAT: -1,
|
||||||
|
O_TRUNC: -1,
|
||||||
|
O_APPEND: -1,
|
||||||
|
O_EXCL: -1,
|
||||||
|
},
|
||||||
|
writeSync: (fd, buf) => {
|
||||||
|
outputBuf += decoder.decode(buf);
|
||||||
|
const nl = outputBuf.lastIndexOf("\n");
|
||||||
|
if (nl != -1) {
|
||||||
|
console.log(outputBuf.substr(0, nl));
|
||||||
|
outputBuf = outputBuf.substr(nl + 1);
|
||||||
|
}
|
||||||
|
return buf.length;
|
||||||
|
},
|
||||||
|
write: (fd, buf, offset, length, position, callback) => {
|
||||||
|
if (offset !== 0 || length !== buf.length || position !== null) {
|
||||||
|
callback(enosys());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const n = global.fs.writeSync(fd, buf);
|
||||||
|
callback(null, n);
|
||||||
|
},
|
||||||
|
open: (path, flags, mode, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
fsync: (fd, callback) => {
|
||||||
|
callback(null);
|
||||||
|
},
|
||||||
|
fdatasync: (fd, callback) => {
|
||||||
|
callback(null);
|
||||||
|
},
|
||||||
|
close: (fd, callback) => {
|
||||||
|
callback(null);
|
||||||
|
},
|
||||||
|
createReadStream: enosys,
|
||||||
|
createWriteStream: enosys,
|
||||||
|
ftruncate: (fd, length, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
readFile: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
writeFile: (path, data, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
truncate: (path, length, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
readdir: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
unlink: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
rmdir: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
mkdir: (path, perm, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
stat: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
lstat: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
fstat: (fd, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
rename: (oldPath, newPath, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
symlink: (target, path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
link: (existingPath, newPath, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
readlink: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
chmod: (path, mode, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
lchmod: (path, mode, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
fchmod: (fd, mode, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
chown: (path, uid, gid, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
lchown: (path, uid, gid, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
fchown: (fd, uid, gid, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
utimes: (path, atime, mtime, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
futimes: (fd, atime, mtime, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
realpath: (path, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
fallocate: (fd, mode, offset, length, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
copyFile: (src, dest, flags, callback) => {
|
||||||
|
callback(enosys());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.crypto) {
|
||||||
|
global.crypto = {
|
||||||
|
// @ts-ignore
|
||||||
|
getRandomValues: (arr: number[]) => {
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
arr[i] = Math.floor(Math.random() * 256);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.performance) {
|
||||||
|
// @ts-ignore
|
||||||
|
global.performance = {
|
||||||
|
now: () => Date.now(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.TextEncoder) {
|
||||||
|
global.TextEncoder = TextEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.TextDecoder) {
|
||||||
|
// @ts-ignore
|
||||||
|
global.TextDecoder = TextDecoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.Buffer) {
|
||||||
|
global.Buffer = {
|
||||||
|
// @ts-ignore
|
||||||
|
isBuffer: (x) => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.process) {
|
||||||
|
// @ts-ignore
|
||||||
|
global.process = {
|
||||||
|
getuid: () => -1,
|
||||||
|
getgid: () => -1,
|
||||||
|
geteuid: () => -1,
|
||||||
|
getegid: () => -1,
|
||||||
|
getgroups: () => [],
|
||||||
|
pid: -1,
|
||||||
|
ppid: -1,
|
||||||
|
umask: () => 0,
|
||||||
|
cwd: () => "/",
|
||||||
|
chdir: (dir) => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!global.Error) {
|
||||||
|
// @ts-ignore
|
||||||
|
global.Error = class extends Error {};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||||
|
lukechampine.com/blake3 v1.2.1 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,4 @@
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
|
||||||
|
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
|
@ -0,0 +1,125 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"lukechampine.com/blake3"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
var activeReader *reader
|
||||||
|
var pipe chan []byte
|
||||||
|
var callbackId int
|
||||||
|
var nextBytes chan int
|
||||||
|
var killChan chan bool
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pipe = make(chan []byte)
|
||||||
|
nextBytes = make(chan int)
|
||||||
|
killChan = make(chan bool)
|
||||||
|
callbackId = rand.Int()
|
||||||
|
<-killChan
|
||||||
|
}
|
||||||
|
|
||||||
|
type reader struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) Read(p []byte) (n int, err error) {
|
||||||
|
nextBytes <- len(p)
|
||||||
|
data := <-pipe
|
||||||
|
copy(p[:], data[:])
|
||||||
|
resetWritePromise()
|
||||||
|
return len(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export start
|
||||||
|
func start() int {
|
||||||
|
|
||||||
|
rootChan := make(chan []byte)
|
||||||
|
proofChan := make(chan []byte)
|
||||||
|
|
||||||
|
resetWritePromise()
|
||||||
|
setGlobalObject(getGlobalPrefix()+"_set_root", js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
jsroot := args[0]
|
||||||
|
|
||||||
|
root := make([]byte, jsroot.Get("length").Int())
|
||||||
|
js.CopyBytesToGo(root, jsroot)
|
||||||
|
|
||||||
|
rootChan <- root
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
setGlobalObject(getGlobalPrefix()+"_set_proof", js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
jsproof := args[0]
|
||||||
|
|
||||||
|
proofSlice := make([]byte, jsproof.Get("length").Int())
|
||||||
|
js.CopyBytesToGo(proofSlice, jsproof)
|
||||||
|
|
||||||
|
proofChan <- proofSlice
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
setGlobalObject(getGlobalPrefix()+"_write", js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
d := args[0]
|
||||||
|
data := make([]byte, d.Get("length").Int())
|
||||||
|
js.CopyBytesToGo(data, d)
|
||||||
|
|
||||||
|
pipe <- data
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
rootSlice := <-rootChan
|
||||||
|
proof := <-proofChan
|
||||||
|
|
||||||
|
var root [32]byte
|
||||||
|
|
||||||
|
copy(root[:], rootSlice)
|
||||||
|
|
||||||
|
ret, err := blake3.BaoDecode(io.Discard, activeReader, bytes.NewReader(proof), root)
|
||||||
|
setGlobalObject(getGlobalPrefix()+"_result", ret)
|
||||||
|
setGlobalObject(getGlobalPrefix()+"_error", err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return callbackId
|
||||||
|
}
|
||||||
|
|
||||||
|
//export kill
|
||||||
|
func kill() {
|
||||||
|
killChan <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func createWritePromiseHandler() js.Value {
|
||||||
|
return createPromiseHandler(func(this js.Value, args []js.Value) {
|
||||||
|
bytesToRead := <-nextBytes
|
||||||
|
args[0].Invoke(bytesToRead)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPromiseHandler(cb func(this js.Value, args []js.Value)) js.Value {
|
||||||
|
return js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||||
|
cb(this, args)
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGlobalPrefix() string {
|
||||||
|
return "bao_" + strconv.FormatInt(int64(callbackId), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWritePromiseName() string {
|
||||||
|
return getGlobalPrefix() + "_write_promise"
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetWritePromise() {
|
||||||
|
setGlobalObject(getWritePromiseName(), createWritePromiseHandler())
|
||||||
|
}
|
||||||
|
|
||||||
|
func setGlobalObject(name string, p any) {
|
||||||
|
js.Global().Set(name, p)
|
||||||
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
export * from "./client.js";
|
export * from "./client.js";
|
||||||
export * from "./cid.js";
|
export * from "./verify.js";
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import baoWasm from "./wasm.js";
|
||||||
|
import Go from "./go_wasm.js";
|
||||||
|
|
||||||
|
export async function getVerifiableStream(
|
||||||
|
root: Uint8Array,
|
||||||
|
proof: Uint8Array,
|
||||||
|
data: ReadableStream,
|
||||||
|
) {
|
||||||
|
const wasm = await getWasmInstance();
|
||||||
|
// @ts-ignore
|
||||||
|
const reader = new VariableChunkStream(data);
|
||||||
|
let bytesToRead;
|
||||||
|
|
||||||
|
if (root instanceof ArrayBuffer) {
|
||||||
|
root = new Uint8Array(root);
|
||||||
|
}
|
||||||
|
if (proof instanceof ArrayBuffer) {
|
||||||
|
proof = new Uint8Array(proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getNextBytes = async () => {
|
||||||
|
bytesToRead = getWasmProperty(wasmId, "write_promise");
|
||||||
|
bytesToRead = await bytesToRead;
|
||||||
|
};
|
||||||
|
|
||||||
|
const callExports = (name: string) => {
|
||||||
|
// @ts-ignore
|
||||||
|
return wasm.exports[name]();
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const exit = () => {
|
||||||
|
callExports("kill");
|
||||||
|
cleanup();
|
||||||
|
};
|
||||||
|
|
||||||
|
const done = (controller: ReadableStreamDefaultController) => {
|
||||||
|
controller.close();
|
||||||
|
exit();
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
const win = getWin();
|
||||||
|
const props = Object.getOwnPropertyNames(win);
|
||||||
|
|
||||||
|
props
|
||||||
|
.filter((item) => item.startsWith(`bao_${wasmId}`))
|
||||||
|
.forEach((item) => {
|
||||||
|
delete win[item];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const wasmId = callExports("start");
|
||||||
|
getWasmProperty(wasmId, "set_root")(root);
|
||||||
|
getWasmProperty(wasmId, "set_proof")(proof);
|
||||||
|
await getNextBytes();
|
||||||
|
|
||||||
|
return new ReadableStream({
|
||||||
|
async pull(controller) {
|
||||||
|
let chunk;
|
||||||
|
|
||||||
|
try {
|
||||||
|
chunk = await reader.read(bytesToRead);
|
||||||
|
if (chunk.value) {
|
||||||
|
getWasmProperty(wasmId, "write")(chunk.value);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// @ts-ignore
|
||||||
|
exit();
|
||||||
|
controller.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = getWasmProperty(wasmId, "result");
|
||||||
|
|
||||||
|
const wasmDone = result !== undefined;
|
||||||
|
|
||||||
|
if (!wasmDone) {
|
||||||
|
await getNextBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunk.done || wasmDone) {
|
||||||
|
if (wasmDone) {
|
||||||
|
if (result) {
|
||||||
|
controller.enqueue(chunk.value);
|
||||||
|
done(controller);
|
||||||
|
} else {
|
||||||
|
controller.error(getWasmProperty(wasmId, "error"));
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!wasmDone) {
|
||||||
|
controller.error("stream is ended but verification not complete");
|
||||||
|
exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller.enqueue(chunk.value);
|
||||||
|
done(controller);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controller.enqueue(chunk.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async cancel(reason: any) {
|
||||||
|
await reader.cancel(reason);
|
||||||
|
exit();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWin() {
|
||||||
|
return globalThis || self || window;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWasmProperty(id: number, prop: string) {
|
||||||
|
return getWin()[`bao_${id}_${prop}`];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getWasmInstance() {
|
||||||
|
const go = new Go();
|
||||||
|
let wasm = (await baoWasm(
|
||||||
|
go.importObject,
|
||||||
|
)) as WebAssembly.WebAssemblyInstantiatedSource;
|
||||||
|
go.run(wasm);
|
||||||
|
|
||||||
|
return wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
class VariableChunkStream {
|
||||||
|
private reader: ReadableStreamDefaultReader;
|
||||||
|
private currentChunk: Uint8Array = new Uint8Array();
|
||||||
|
private currentChunkSize = 0;
|
||||||
|
private readerDone = false;
|
||||||
|
|
||||||
|
constructor(stream: ReadableStream) {
|
||||||
|
this.reader = stream.getReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
async read(bytes: number) {
|
||||||
|
if (this.currentChunk.length === 0 && !this.readerDone) {
|
||||||
|
const { done, value } = await this.reader.read();
|
||||||
|
if (done) {
|
||||||
|
return { done: true };
|
||||||
|
}
|
||||||
|
this.currentChunk = value;
|
||||||
|
this.currentChunkSize = this.currentChunk.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.currentChunkSize > bytes) {
|
||||||
|
const chunk = this.currentChunk.slice(0, bytes);
|
||||||
|
this.currentChunk = this.currentChunk.slice(bytes);
|
||||||
|
this.currentChunkSize -= bytes;
|
||||||
|
return { value: chunk, done: false };
|
||||||
|
}
|
||||||
|
if (this.currentChunkSize < bytes && !this.readerDone) {
|
||||||
|
const { done, value } = await this.reader.read();
|
||||||
|
if (done) {
|
||||||
|
this.readerDone = true;
|
||||||
|
}
|
||||||
|
this.currentChunk = new Uint8Array([...this.currentChunk, ...value]);
|
||||||
|
this.currentChunkSize += value.length;
|
||||||
|
return this.read(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunk = this.currentChunk;
|
||||||
|
this.currentChunk = new Uint8Array();
|
||||||
|
this.currentChunkSize = 0;
|
||||||
|
return { value: chunk, done: this.readerDone };
|
||||||
|
}
|
||||||
|
|
||||||
|
async cancel(reason: any) {
|
||||||
|
await this.reader.cancel(reason);
|
||||||
|
this.currentChunk = new Uint8Array();
|
||||||
|
this.currentChunkSize = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import isNode from "detect-node";
|
||||||
|
export default async function (imports) {
|
||||||
|
if (isNode) {
|
||||||
|
const fs = await import("fs/promises");
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
const wasmPath = new URL("wasm/bao.wasm", import.meta.url);
|
||||||
|
const wasm = await fs.readFile(wasmPath);
|
||||||
|
return (await WebAssembly.instantiate(wasm, imports)).instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
let wasm = await import("./wasm/bao.wasm?init");
|
||||||
|
wasm = wasm.default || wasm;
|
||||||
|
wasm = await wasm(imports);
|
||||||
|
return wasm;
|
||||||
|
}
|
Loading…
Reference in New Issue