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": [
|
||||
"presetter-preset-essentials",
|
||||
"presetter-preset-hybrid"
|
||||
],
|
||||
"config": {
|
||||
"tsconfig": {
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": false
|
||||
}
|
||||
},
|
||||
"variable": {
|
||||
"source": "src"
|
||||
}
|
||||
"presetter-preset-hybrid",
|
||||
"@lumeweb/node-library-preset"
|
||||
]
|
||||
}
|
||||
|
|
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",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0-develop.41",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.mjs",
|
||||
"types": "lib/index.d.ts",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/libportal.git"
|
||||
|
@ -16,24 +15,26 @@
|
|||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lumeweb/node-library-preset": "^0.2.7",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/commit-analyzer": "^10.0.1",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/npm": "^10.0.4",
|
||||
"@semantic-release/release-notes-generator": "^11.0.3",
|
||||
"presetter": "^3.5.5",
|
||||
"presetter-preset-essentials": "^3.5.5",
|
||||
"presetter-preset-hybrid": "^3.5.5",
|
||||
"presetter": "^4.0.1",
|
||||
"presetter-preset-hybrid": "4.0.1",
|
||||
"presetter-preset-strict": "^4.0.1",
|
||||
"semantic-release": "^21.0.5"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"_id": "@lumeweb/libportal@0.1.0",
|
||||
"scripts": {
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lumeweb/libs5": "^0.1.0-develop.61",
|
||||
"@noble/curves": "^1.1.0",
|
||||
"@noble/hashes": "^1.3.1",
|
||||
"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 { RegisterRequest } from "./requests/account.js";
|
||||
import fetch, {
|
||||
FormData,
|
||||
Blob,
|
||||
RequestInit,
|
||||
Response,
|
||||
HeadersInit,
|
||||
} from "node-fetch";
|
||||
import {
|
||||
LoginRequest,
|
||||
LogoutRequest,
|
||||
|
@ -21,24 +14,29 @@ import {
|
|||
UploadStatusResponse,
|
||||
} from "./responses/files.js";
|
||||
|
||||
import TUS from "tus-js-client";
|
||||
import * as TUS from "tus-js-client";
|
||||
import streamToBlob from "stream-to-blob";
|
||||
|
||||
import defer from "p-defer";
|
||||
import { blake3 } from "@noble/hashes/blake3";
|
||||
import { encodeCid } from "./cid.js";
|
||||
import { Readable as NodeReadableStream } from "stream";
|
||||
import {
|
||||
AuthStatusResponse,
|
||||
LoginResponse,
|
||||
PubkeyChallengeResponse,
|
||||
} 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 {
|
||||
portalUrl: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
privateKey?: Uint8Array;
|
||||
jwt?: string;
|
||||
}
|
||||
|
||||
interface FetchOptions {
|
||||
|
@ -62,6 +60,10 @@ export class Client {
|
|||
throw new Error("Portal url is required");
|
||||
}
|
||||
|
||||
if (options.jwt) {
|
||||
this.jwtSessionKey = options.jwt;
|
||||
}
|
||||
|
||||
this._options = options;
|
||||
}
|
||||
|
||||
|
@ -69,6 +71,10 @@ export class Client {
|
|||
return this._options.email as string;
|
||||
}
|
||||
|
||||
get portalUrl(): string {
|
||||
return this._options.portalUrl as string;
|
||||
}
|
||||
|
||||
set email(email: string) {
|
||||
this._options.email = email;
|
||||
}
|
||||
|
@ -77,6 +83,10 @@ export class Client {
|
|||
return this._options.password as string;
|
||||
}
|
||||
|
||||
get jwt(): string | undefined {
|
||||
return this.jwtSessionKey;
|
||||
}
|
||||
|
||||
set password(password: string) {
|
||||
this._options.email = password;
|
||||
}
|
||||
|
@ -105,6 +115,10 @@ export class Client {
|
|||
}
|
||||
|
||||
async login(): Promise<LoginResponse> {
|
||||
if (this._options.privateKey) {
|
||||
return this.loginPubkey();
|
||||
}
|
||||
|
||||
return this.post<LoginResponse>("/api/v1/auth/login", {
|
||||
email: this._options.email,
|
||||
password: this._options.password,
|
||||
|
@ -131,7 +145,7 @@ export class Client {
|
|||
return json.status as boolean;
|
||||
}
|
||||
|
||||
async loginPubkey(): Promise<void> {
|
||||
async loginPubkey(): Promise<LoginResponse> {
|
||||
if (!this._options.privateKey) {
|
||||
throw new Error("Private key is required");
|
||||
}
|
||||
|
@ -144,7 +158,7 @@ export class Client {
|
|||
);
|
||||
|
||||
const signature = ed.sign(
|
||||
new TextEncoder().encode(challenge.challenge),
|
||||
utf8ToBytes(challenge.challenge),
|
||||
this._options.privateKey,
|
||||
);
|
||||
|
||||
|
@ -158,6 +172,8 @@ export class Client {
|
|||
);
|
||||
|
||||
this.jwtSessionKey = loginRet.token;
|
||||
|
||||
return { token: loginRet.token };
|
||||
}
|
||||
|
||||
logout(request: LogoutRequest): Promise<void> {
|
||||
|
@ -186,6 +202,7 @@ export class Client {
|
|||
}
|
||||
|
||||
async downloadProof(cid: string): Promise<ArrayBuffer> {
|
||||
const Response = await this.getFetchResponseObject();
|
||||
return await new Response(
|
||||
await this.get<any>(`/api/v1/files/proof/${cid}`, {
|
||||
auth: true,
|
||||
|
@ -206,13 +223,27 @@ export class Client {
|
|||
if (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.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 (!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(
|
||||
stream: ReadableStream,
|
||||
hashStream: ReadableStream,
|
||||
size: bigint,
|
||||
);
|
||||
async uploadFile(stream: Uint8Array, size?: bigint);
|
||||
): Promise<CID>;
|
||||
async uploadFile(stream: Uint8Array, size?: bigint): Promise<CID>;
|
||||
async uploadFile(
|
||||
stream: NodeJS.ReadableStream,
|
||||
hashStream: NodeJS.ReadableStream,
|
||||
size?: bigint,
|
||||
);
|
||||
async uploadFile(
|
||||
stream: any,
|
||||
hashStream?: any,
|
||||
size?: bigint,
|
||||
): Promise<string> {
|
||||
): Promise<CID>;
|
||||
async uploadFile(stream: any, hashStream?: any, size?: bigint): Promise<CID> {
|
||||
const Blob = await this.getBlobObject();
|
||||
|
||||
if (stream instanceof Uint8Array || stream instanceof Blob) {
|
||||
size = BigInt(stream.length);
|
||||
}
|
||||
|
@ -295,36 +324,47 @@ export class Client {
|
|||
return this.uploadFileTus(stream, hashStream, size);
|
||||
}
|
||||
|
||||
private async uploadFileSmall(stream: Blob): Promise<string>;
|
||||
private async uploadFileSmall(stream: Blob): Promise<CID>;
|
||||
private async uploadFileSmall(
|
||||
stream: ReadableStream,
|
||||
hashStream: ReadableStream,
|
||||
): Promise<string>;
|
||||
private async uploadFileSmall(stream: Uint8Array): Promise<string>;
|
||||
private async uploadFileSmall(stream: NodeJS.ReadableStream): Promise<string>;
|
||||
private async uploadFileSmall(stream: any): Promise<string> {
|
||||
): Promise<CID>;
|
||||
private async uploadFileSmall(stream: Uint8Array): Promise<CID>;
|
||||
private async uploadFileSmall(stream: NodeJS.ReadableStream): Promise<CID>;
|
||||
private async uploadFileSmall(stream: any): Promise<CID> {
|
||||
const Blob = await this.getBlobObject();
|
||||
|
||||
if (stream instanceof ReadableStream) {
|
||||
stream = await streamToBlob(stream);
|
||||
}
|
||||
|
||||
if (stream instanceof NodeReadableStream) {
|
||||
let data = new Uint8Array();
|
||||
for await (const chunk of stream) {
|
||||
data = Uint8Array.from([...data, ...chunk]);
|
||||
}
|
||||
let NodeReadableStream =
|
||||
(await this.getNodeReadableObject()) as NodeReadableStreamType;
|
||||
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
const _FormData = await this.getFormDataObject();
|
||||
|
||||
const formData = new _FormData();
|
||||
formData.set("file", stream as Blob);
|
||||
|
||||
const response = await this.post<UploadResponse>(
|
||||
|
@ -333,29 +373,26 @@ export class Client {
|
|||
{ 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(
|
||||
stream: ReadableStream,
|
||||
hashStream: ReadableStream,
|
||||
size?: bigint,
|
||||
): Promise<string>;
|
||||
private async uploadFileTus(
|
||||
stream: Uint8Array,
|
||||
size?: bigint,
|
||||
): Promise<string>;
|
||||
): Promise<CID>;
|
||||
private async uploadFileTus(stream: Uint8Array, size?: bigint): Promise<CID>;
|
||||
private async uploadFileTus(
|
||||
stream: NodeJS.ReadableStream,
|
||||
hashStream: ReadableStream,
|
||||
size?: bigint,
|
||||
): Promise<string>;
|
||||
): Promise<CID>;
|
||||
private async uploadFileTus(
|
||||
stream: any,
|
||||
hashStream?: any,
|
||||
size?: bigint,
|
||||
): Promise<string> {
|
||||
): Promise<CID> {
|
||||
if (["bigint", "number"].includes(typeof hashStream)) {
|
||||
size = BigInt(hashStream);
|
||||
hashStream = undefined;
|
||||
|
@ -368,7 +405,10 @@ export class Client {
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -381,7 +421,7 @@ export class Client {
|
|||
if (
|
||||
!(stream instanceof ReadableStreamDefaultReader) &&
|
||||
!(stream instanceof Blob) &&
|
||||
!(stream instanceof NodeReadableStream)
|
||||
!(NodeReadableStream && stream instanceof NodeReadableStream)
|
||||
) {
|
||||
throw new Error("Invalid stream");
|
||||
}
|
||||
|
@ -426,10 +466,10 @@ export class Client {
|
|||
|
||||
await ret.promise;
|
||||
|
||||
const cid = encodeCid(hash, size as bigint);
|
||||
const cid = CID.fromHash(hash, Number(size));
|
||||
|
||||
while (true) {
|
||||
const status = await this.getUploadStatus(cid as string);
|
||||
const status = await this.getUploadStatus(cid.toString());
|
||||
|
||||
if (status.status === "uploaded") {
|
||||
break;
|
||||
|
@ -440,7 +480,7 @@ export class Client {
|
|||
});
|
||||
}
|
||||
|
||||
return cid as string;
|
||||
return cid;
|
||||
}
|
||||
|
||||
async getUploadStatus(cid: string) {
|
||||
|
@ -471,7 +511,10 @@ export class Client {
|
|||
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({});
|
||||
|
||||
for await (const chunk of stream) {
|
||||
|
@ -489,4 +532,52 @@ export class Client {
|
|||
|
||||
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 "./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