mirror of
https://github.com/urbit/shrub.git
synced 2024-11-24 13:06:09 +03:00
Merge remote-tracking branch 'origin/master' into release/next-sys
This commit is contained in:
commit
5996b3aa1e
3
.eslintrc.js
Normal file
3
.eslintrc.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
ignorePatterns: ["**/*"]
|
||||||
|
};
|
2
.github/actions/glob/Dockerfile
vendored
2
.github/actions/glob/Dockerfile
vendored
@ -1,4 +1,4 @@
|
|||||||
FROM jaredtobin/janeway:v0.15.3.1
|
FROM tloncorp/janeway:v0.15.4
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
EXPOSE 22/tcp
|
EXPOSE 22/tcp
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
2
.github/workflows/chromatic.yml
vendored
2
.github/workflows/chromatic.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- run: cd 'pkg/interface' && npm i
|
- run: npm i && npm run bootstrap
|
||||||
- name: Publish to Chromatic
|
- name: Publish to Chromatic
|
||||||
uses: chromaui/action@v1
|
uses: chromaui/action@v1
|
||||||
with:
|
with:
|
||||||
|
24
.github/workflows/frontend-test.yml
vendored
Normal file
24
.github/workflows/frontend-test.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: frontend-test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'pkg/interface/**'
|
||||||
|
- 'pkg/btc-wallet/**'
|
||||||
|
- 'pkg/npm/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
frontend-test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: "Test changed frontend packages"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- run: git fetch --prune
|
||||||
|
- name: 'Setup root deps'
|
||||||
|
run: npm ci
|
||||||
|
- name: 'Setup dependencies'
|
||||||
|
run: npm run bootstrap
|
||||||
|
- name: 'Run tests'
|
||||||
|
run: npm run test -- --since origin/$GITHUB_BASE_REF --include-dependents
|
14
.github/workflows/typescript-check.yml
vendored
14
.github/workflows/typescript-check.yml
vendored
@ -1,14 +0,0 @@
|
|||||||
name: typescript-check
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'pkg/interface/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
typescript-check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: "Check pkg/interface types"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- run: cd 'pkg/interface' && npm i && npm run tsc
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -33,6 +33,7 @@ result-*
|
|||||||
|
|
||||||
# NodeJS
|
# NodeJS
|
||||||
node_modules
|
node_modules
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
# Haskell
|
# Haskell
|
||||||
.stack-work
|
.stack-work
|
||||||
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_
|
8
.husky/pre-commit
Executable file
8
.husky/pre-commit
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
command -v npx > /dev/null || {
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
npx lint-staged
|
8
lerna.json
Normal file
8
lerna.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
"pkg/npm/*",
|
||||||
|
"pkg/btc-wallet",
|
||||||
|
"pkg/interface"
|
||||||
|
],
|
||||||
|
"version": "independent"
|
||||||
|
}
|
6915
package-lock.json
generated
Normal file
6915
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
Normal file
21
package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "root",
|
||||||
|
"private": true,
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^7.29.0",
|
||||||
|
"husky": "^6.0.0",
|
||||||
|
"lerna": "^4.0.0",
|
||||||
|
"lint-staged": "^11.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"watch-libs": "lerna run watch --no-private --parallel",
|
||||||
|
"build-libs": "lerna run build --no-private",
|
||||||
|
"test": "lerna run test",
|
||||||
|
"prepare": "husky install .husky",
|
||||||
|
"bootstrap": "lerna bootstrap",
|
||||||
|
"build:prod": "lerna run build:prod"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,ts,tsx}": "eslint --cache --fix"
|
||||||
|
}
|
||||||
|
}
|
@ -11,21 +11,25 @@
|
|||||||
::
|
::
|
||||||
/- *bitcoin, json-rpc, *btc-provider
|
/- *bitcoin, json-rpc, *btc-provider
|
||||||
/+ dbug, default-agent, bl=btc, groupl=group, resource
|
/+ dbug, default-agent, bl=btc, groupl=group, resource
|
||||||
|
~% %btc-provider-top ..part ~
|
||||||
|%
|
|%
|
||||||
|
+$ card card:agent:gall
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-0
|
$% state-0
|
||||||
|
state-1
|
||||||
|
state-2
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ state-0 [%0 =host-info =whitelist]
|
+$ state-0 [%0 =host-info =whitelist]
|
||||||
::
|
+$ state-1 [%1 =host-info =whitelist timer=(unit @da)]
|
||||||
+$ card card:agent:gall
|
+$ state-2 [%2 =host-info =whitelist timer=(unit @da) interval=@dr]
|
||||||
::
|
|
||||||
--
|
--
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
=| state-0
|
=| state-2
|
||||||
=* state -
|
=* state -
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
=<
|
=<
|
||||||
|
~% %btc-provider-agent ..send-status ~
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
+* this .
|
+* this .
|
||||||
def ~(. (default-agent this %|) bowl)
|
def ~(. (default-agent this %|) bowl)
|
||||||
@ -33,13 +37,13 @@
|
|||||||
::
|
::
|
||||||
++ on-init
|
++ on-init
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
~& > '%btc-provider initialized successfully'
|
|
||||||
=| wl=^whitelist
|
=| wl=^whitelist
|
||||||
:- ~
|
:- ~
|
||||||
%_ this
|
%_ this
|
||||||
host-info
|
host-info ['' connected=%.n %main block=0 clients=*(set ship)]
|
||||||
['' connected=%.n %main block=0 clients=*(set ship)]
|
whitelist wl(public %.n, kids %.n)
|
||||||
whitelist wl(public %.n, kids %.n)
|
timer ~
|
||||||
|
interval ~m1
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-save
|
++ on-save
|
||||||
@ -49,24 +53,144 @@
|
|||||||
++ on-load
|
++ on-load
|
||||||
|= old-state=vase
|
|= old-state=vase
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
~& > '%btc-provider recompiled successfully '
|
=/ old !<(versioned-state old-state)
|
||||||
`this(state !<(versioned-state old-state))
|
?- -.old
|
||||||
|
%2
|
||||||
|
[~ this(state old)]
|
||||||
|
::
|
||||||
|
%1
|
||||||
|
`this(state [%2 host-info.old whitelist.old timer.old ~m1])
|
||||||
|
::
|
||||||
|
%0
|
||||||
|
:_ this(state [%2 host-info.old whitelist.old ~ ~m1])
|
||||||
|
?: =('' api-url.host-info.old) ~
|
||||||
|
~[(start-ping-timer:hc ~s0)]
|
||||||
|
==
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
|
~/ %on-poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
|
|^
|
||||||
?> ?|((team:title our.bowl src.bowl) (is-client:hc src.bowl))
|
?> ?|((team:title our.bowl src.bowl) (is-client:hc src.bowl))
|
||||||
=^ cards state
|
=^ cards state
|
||||||
?+ mark (on-poke:def mark vase)
|
?+ mark (on-poke:def mark vase)
|
||||||
%btc-provider-command
|
%btc-provider-command
|
||||||
?> (team:title our.bowl src.bowl)
|
?> (team:title our.bowl src.bowl)
|
||||||
(handle-command:hc !<(command vase))
|
(handle-command !<(command vase))
|
||||||
|
::
|
||||||
%btc-provider-action
|
%btc-provider-action
|
||||||
(handle-action:hc !<(action vase))
|
(handle-action !<(action vase))
|
||||||
|
::
|
||||||
|
%noun
|
||||||
|
?. =(q.vase %kick-timer) `state
|
||||||
|
:_ state(timer `now.bowl)
|
||||||
|
:* (start-ping-timer ~s0)
|
||||||
|
?~ timer ~
|
||||||
|
[[%pass /block-time %arvo %b %rest u.timer] ~]
|
||||||
|
==
|
||||||
==
|
==
|
||||||
[cards this]
|
[cards this]
|
||||||
|
::
|
||||||
|
++ handle-command
|
||||||
|
|= comm=command
|
||||||
|
^- (quip card _state)
|
||||||
|
?- -.comm
|
||||||
|
%set-credentials
|
||||||
|
:_ %_ state
|
||||||
|
host-info [api-url.comm %.n network.comm 0 *(set ship)]
|
||||||
|
timer `now.bowl
|
||||||
|
==
|
||||||
|
:* (start-ping-timer:hc ~s0)
|
||||||
|
?~ timer ~
|
||||||
|
[[%pass /block-time %arvo %b %rest u.timer] ~]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%add-whitelist
|
||||||
|
:- ~
|
||||||
|
?- -.wt.comm
|
||||||
|
%public
|
||||||
|
state(public.whitelist %.y)
|
||||||
|
::
|
||||||
|
%kids
|
||||||
|
state(kids.whitelist %.y)
|
||||||
|
::
|
||||||
|
%users
|
||||||
|
state(users.whitelist (~(uni in users.whitelist) users.wt.comm))
|
||||||
|
::
|
||||||
|
%groups
|
||||||
|
state(groups.whitelist (~(uni in groups.whitelist) groups.wt.comm))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%remove-whitelist
|
||||||
|
=. state
|
||||||
|
?- -.wt.comm
|
||||||
|
%public
|
||||||
|
state(public.whitelist %.n)
|
||||||
|
::
|
||||||
|
%kids
|
||||||
|
state(kids.whitelist %.n)
|
||||||
|
::
|
||||||
|
%users
|
||||||
|
state(users.whitelist (~(dif in users.whitelist) users.wt.comm))
|
||||||
|
::
|
||||||
|
%groups
|
||||||
|
state(groups.whitelist (~(dif in groups.whitelist) groups.wt.comm))
|
||||||
|
==
|
||||||
|
clean-client-list
|
||||||
|
::
|
||||||
|
%set-interval
|
||||||
|
`state(interval inte.comm)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: +clean-client-list: remove clients who are no longer whitelisted
|
||||||
|
:: called after a whitelist change
|
||||||
|
::
|
||||||
|
++ clean-client-list
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ to-kick=(set ship)
|
||||||
|
%- silt
|
||||||
|
%+ murn ~(tap in clients.host-info)
|
||||||
|
|= c=ship ^- (unit ship)
|
||||||
|
?:((is-whitelisted:hc c) ~ `c)
|
||||||
|
:_ state(clients.host-info (~(dif in clients.host-info) to-kick))
|
||||||
|
%+ turn ~(tap in to-kick)
|
||||||
|
|=(c=ship [%give %kick ~[/clients] `c])
|
||||||
|
::
|
||||||
|
:: if not connected, only %ping action is allowed
|
||||||
|
::
|
||||||
|
++ handle-action
|
||||||
|
|= act=action
|
||||||
|
^- (quip card _state)
|
||||||
|
:_ state
|
||||||
|
?. ?|(connected.host-info ?=(%ping -.act))
|
||||||
|
~[(send-update:hc [%| %not-connected 500] ~)]
|
||||||
|
:_ ~
|
||||||
|
%+ req-card act
|
||||||
|
^- action:rpc-types
|
||||||
|
?- -.act
|
||||||
|
%address-info [%get-address-info address.act]
|
||||||
|
%tx-info [%get-tx-vals txid.act]
|
||||||
|
%raw-tx [%get-raw-tx txid.act]
|
||||||
|
%broadcast-tx [%broadcast-tx rawtx.act]
|
||||||
|
%ping [%get-block-info ~]
|
||||||
|
%block-info [%get-block-info block.act]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ req-card
|
||||||
|
|= [act=action ract=action:rpc-types]
|
||||||
|
=/ req=request:http
|
||||||
|
(gen-request:bl host-info ract)
|
||||||
|
[%pass (rpc-wire act) %arvo %i %request req *outbound-config:iris]
|
||||||
|
::
|
||||||
|
++ rpc-wire
|
||||||
|
|= act=action
|
||||||
|
^- wire
|
||||||
|
/[-.act]/(scot %p src.bowl)/(scot %ux (cut 3 [0 20] eny.bowl))
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|
~/ %on-watch
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:: checking provider permissions before trying to subscribe
|
:: checking provider permissions before trying to subscribe
|
||||||
@ -83,31 +207,124 @@
|
|||||||
==
|
==
|
||||||
[%give %fact ~ %json !>(jon)]~
|
[%give %fact ~ %json !>(jon)]~
|
||||||
::
|
::
|
||||||
?> ?=([%clients *] pax)
|
?> ?| ?=([%clients ~] pax)
|
||||||
|
?& ?=([%clients @ ~] pax)
|
||||||
|
=(src.bowl (slav %p i.t.pax))
|
||||||
|
==
|
||||||
|
==
|
||||||
?. (is-whitelisted:hc src.bowl)
|
?. (is-whitelisted:hc src.bowl)
|
||||||
~|("btc-provider: blocked client {<src.bowl>}" !!)
|
~|("btc-provider: blocked client {<src.bowl>}" !!)
|
||||||
~& > "btc-provider: accepted client {<src.bowl>}"
|
~& > "btc-provider: accepted client {<src.bowl>}"
|
||||||
:- [do-ping:hc]~
|
`this(clients.host-info (~(put in clients.host-info) src.bowl))
|
||||||
this(clients.host-info (~(put in clients.host-info) src.bowl))
|
|
||||||
::
|
::
|
||||||
++ on-arvo
|
++ on-arvo
|
||||||
|= [=wire =sign-arvo]
|
~/ %on-arvo
|
||||||
|
|= [wir=wire =sign-arvo]
|
||||||
|
|^
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
:: check for connectivity every 30 seconds
|
:: check for connectivity every 30 seconds
|
||||||
::
|
::
|
||||||
?: ?=([%ping-timer *] wire)
|
?: ?=([%ping-timer *] wir)
|
||||||
:_ this
|
`this
|
||||||
:~ do-ping:hc
|
?: ?=([%block-ping *] wir)
|
||||||
(start-ping-timer:hc ~s30)
|
:_ this(timer `(add now.bowl interval))
|
||||||
|
:~ do-ping
|
||||||
|
(start-ping-timer:hc interval)
|
||||||
==
|
==
|
||||||
=^ cards state
|
=^ cards state
|
||||||
?+ +<.sign-arvo (on-arvo:def wire sign-arvo)
|
?+ +<.sign-arvo (on-arvo:def wir sign-arvo)
|
||||||
%http-response
|
%http-response
|
||||||
(handle-rpc-response:hc wire client-response.sign-arvo)
|
(handle-rpc-response wir client-response.sign-arvo)
|
||||||
==
|
==
|
||||||
[cards this]
|
[cards this]
|
||||||
|
::
|
||||||
|
++ do-ping
|
||||||
|
^- card
|
||||||
|
=/ act=action [%ping ~]
|
||||||
|
:* %pass /ping/[(scot %da now.bowl)] %agent
|
||||||
|
[our.bowl %btc-provider] %poke
|
||||||
|
%btc-provider-action !>(act)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:: Handles HTTP responses from RPC servers. Parses for errors,
|
||||||
|
:: then handles response. For actions that require collating multiple
|
||||||
|
:: RPC calls, uses req-card to call out to RPC again if more
|
||||||
|
:: information is required.
|
||||||
|
++ handle-rpc-response
|
||||||
|
|= [=wire response=client-response:iris]
|
||||||
|
^- (quip card _state)
|
||||||
|
?. ?=(%finished -.response) `state
|
||||||
|
=* status status-code.response-header.response
|
||||||
|
:: handle error types: connection errors, RPC errors (in order)
|
||||||
|
::
|
||||||
|
=^ conn-err state
|
||||||
|
(connection-error status)
|
||||||
|
?^ conn-err
|
||||||
|
:_ state(connected.host-info %.n)
|
||||||
|
:~ (send-status:hc [%disconnected ~] ~)
|
||||||
|
(send-update:hc [%| u.conn-err] ~)
|
||||||
|
==
|
||||||
|
::
|
||||||
|
%+ handle-rpc-result wire
|
||||||
|
%- parse-result:rpc:bl
|
||||||
|
(get-rpc-response:bl response)
|
||||||
|
::
|
||||||
|
++ handle-rpc-result
|
||||||
|
|= [=wire r=result:rpc-types]
|
||||||
|
^- (quip card _state)
|
||||||
|
=/ ship=(unit ship)
|
||||||
|
(slaw %p (snag 1 wire))
|
||||||
|
?+ -.wire ~|("Unexpected HTTP response" !!)
|
||||||
|
%address-info
|
||||||
|
?> ?=([%get-address-info *] r)
|
||||||
|
:_ state
|
||||||
|
~[(send-update:hc [%.y %address-info +.r] ship)]
|
||||||
|
::
|
||||||
|
%tx-info
|
||||||
|
?> ?=([%get-tx-vals *] r)
|
||||||
|
:_ state
|
||||||
|
~[(send-update:hc [%.y %tx-info +.r] ship)]
|
||||||
|
::
|
||||||
|
%raw-tx
|
||||||
|
?> ?=([%get-raw-tx *] r)
|
||||||
|
:_ state
|
||||||
|
~[(send-update:hc [%.y %raw-tx +.r] ship)]
|
||||||
|
::
|
||||||
|
%broadcast-tx
|
||||||
|
?> ?=([%broadcast-tx *] r)
|
||||||
|
:_ state
|
||||||
|
~[(send-update:hc [%.y %broadcast-tx +.r] ship)]
|
||||||
|
::
|
||||||
|
%ping
|
||||||
|
?> ?=([%get-block-info *] r)
|
||||||
|
:_ state(connected.host-info %.y, block.host-info block.r)
|
||||||
|
:_ ~
|
||||||
|
%- send-status:hc
|
||||||
|
:_ ~
|
||||||
|
?: =(block.host-info block.r)
|
||||||
|
[%connected network.host-info block.r fee.r]
|
||||||
|
[%new-block network.host-info block.r fee.r blockhash.r blockfilter.r]
|
||||||
|
::
|
||||||
|
%block-info
|
||||||
|
?> ?=([%get-block-info *] r)
|
||||||
|
:_ state
|
||||||
|
~[(send-update:hc [%.y %block-info network.host-info +.r] ship)]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ connection-error
|
||||||
|
|= status=@ud
|
||||||
|
^- [(unit error) _state]
|
||||||
|
?+ status [`[%rpc-error ~] state]
|
||||||
|
%200 [~ state]
|
||||||
|
%400 [`[%bad-request status] state]
|
||||||
|
%401 [`[%no-auth status] state(connected.host-info %.n)]
|
||||||
|
%502 [`[%not-connected status] state(connected.host-info %.n)]
|
||||||
|
%504 [`[%not-connected status] state(connected.host-info %.n)]
|
||||||
|
==
|
||||||
|
--
|
||||||
::
|
::
|
||||||
++ on-peek
|
++ on-peek
|
||||||
|
~/ %on-peek
|
||||||
|= pax=path
|
|= pax=path
|
||||||
^- (unit (unit cage))
|
^- (unit (unit cage))
|
||||||
?+ pax (on-peek:def pax)
|
?+ pax (on-peek:def pax)
|
||||||
@ -115,7 +332,7 @@
|
|||||||
``noun+!>((is-whitelisted:hc (ship (slav %p +>-.pax))))
|
``noun+!>((is-whitelisted:hc (ship (slav %p +>-.pax))))
|
||||||
::
|
::
|
||||||
[%x %is-client @t ~]
|
[%x %is-client @t ~]
|
||||||
``noun+!>((is-client (ship (slav %p +>-.pax))))
|
``noun+!>((is-client:hc (ship (slav %p +>-.pax))))
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-leave on-leave:def
|
++ on-leave on-leave:def
|
||||||
@ -123,195 +340,32 @@
|
|||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
--
|
--
|
||||||
:: helper core
|
:: helper core
|
||||||
|
~% %btc-provider-helper ..card ~
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
++ handle-command
|
|
||||||
|= comm=command
|
|
||||||
^- (quip card _state)
|
|
||||||
?- -.comm
|
|
||||||
%set-credentials
|
|
||||||
:- :~ do-ping
|
|
||||||
(start-ping-timer ~s30)
|
|
||||||
==
|
|
||||||
%= state
|
|
||||||
host-info
|
|
||||||
[api-url.comm connected=%.n network.comm block=0 clients=*(set ship)]
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%add-whitelist
|
|
||||||
?- -.wt.comm
|
|
||||||
%public
|
|
||||||
`state(public.whitelist %.y)
|
|
||||||
::
|
|
||||||
%kids
|
|
||||||
`state(kids.whitelist %.y)
|
|
||||||
::
|
|
||||||
%users
|
|
||||||
`state(users.whitelist (~(uni in users.whitelist) users.wt.comm))
|
|
||||||
::
|
|
||||||
%groups
|
|
||||||
`state(groups.whitelist (~(uni in groups.whitelist) groups.wt.comm))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
%remove-whitelist
|
|
||||||
=. state
|
|
||||||
?- -.wt.comm
|
|
||||||
%public
|
|
||||||
state(public.whitelist %.n)
|
|
||||||
::
|
|
||||||
%kids
|
|
||||||
state(kids.whitelist %.n)
|
|
||||||
::
|
|
||||||
%users
|
|
||||||
state(users.whitelist (~(dif in users.whitelist) users.wt.comm))
|
|
||||||
::
|
|
||||||
%groups
|
|
||||||
state(groups.whitelist (~(dif in groups.whitelist) groups.wt.comm))
|
|
||||||
==
|
|
||||||
clean-client-list
|
|
||||||
==
|
|
||||||
:: if not connected, only %ping action is allowed
|
|
||||||
::
|
|
||||||
++ handle-action
|
|
||||||
|= act=action
|
|
||||||
^- (quip card _state)
|
|
||||||
?. ?|(connected.host-info ?=(%ping -.act))
|
|
||||||
~& >>> "Not connected to RPC"
|
|
||||||
[~[(send-update [%| %not-connected 500])] state]
|
|
||||||
::
|
|
||||||
=/ ract=action:rpc-types
|
|
||||||
?- -.act :: ~|("Invalid action" !!)
|
|
||||||
%address-info
|
|
||||||
[%get-address-info address.act]
|
|
||||||
::
|
|
||||||
%tx-info
|
|
||||||
[%get-tx-vals txid.act]
|
|
||||||
::
|
|
||||||
%raw-tx
|
|
||||||
[%get-raw-tx txid.act]
|
|
||||||
::
|
|
||||||
%broadcast-tx
|
|
||||||
[%broadcast-tx rawtx.act]
|
|
||||||
::
|
|
||||||
%ping
|
|
||||||
[%get-block-info ~]
|
|
||||||
::
|
|
||||||
%block-info
|
|
||||||
[%get-block-info block.act]
|
|
||||||
==
|
|
||||||
[~[(req-card act ract)] state]
|
|
||||||
::
|
|
||||||
++ req-card
|
|
||||||
|= [act=action ract=action:rpc-types]
|
|
||||||
=| out=outbound-config:iris
|
|
||||||
=/ req=request:http
|
|
||||||
(gen-request:bl host-info ract)
|
|
||||||
[%pass (rpc-wire act) %arvo %i %request req out]
|
|
||||||
:: wire structure: /action-tas/now
|
|
||||||
::
|
|
||||||
++ rpc-wire
|
|
||||||
|= act=action ^- wire
|
|
||||||
/[-.act]/[(scot %ux (cut 3 [0 20] eny.bowl))]
|
|
||||||
::
|
|
||||||
++ kick-client
|
|
||||||
|= client=ship
|
|
||||||
^- (quip card _state)
|
|
||||||
~& >>> "dropping client {<client>}"
|
|
||||||
:- ~[[%give %kick ~[/clients] `client]]
|
|
||||||
state(clients.host-info (~(dif in clients.host-info) (silt ~[client])))
|
|
||||||
::
|
|
||||||
:: Handles HTTP responses from RPC servers. Parses for errors, then handles response.
|
|
||||||
:: For actions that require collating multiple RPC calls, uses req-card to call out
|
|
||||||
:: to RPC again if more information is required.
|
|
||||||
::
|
|
||||||
++ handle-rpc-response
|
|
||||||
|= [=wire response=client-response:iris]
|
|
||||||
^- (quip card _state)
|
|
||||||
?. ?=(%finished -.response) `state
|
|
||||||
=* status status-code.response-header.response
|
|
||||||
:: handle error types: connection errors, RPC errors (in order)
|
|
||||||
::
|
|
||||||
=^ conn-err state
|
|
||||||
(connection-error status)
|
|
||||||
?^ conn-err
|
|
||||||
:_ state(connected.host-info %.n)
|
|
||||||
~[(send-status [%disconnected ~]) (send-update [%| u.conn-err])]
|
|
||||||
::
|
|
||||||
%+ handle-rpc-result wire
|
|
||||||
%- parse-result:rpc:bl
|
|
||||||
(get-rpc-response:bl response)
|
|
||||||
::
|
|
||||||
++ connection-error
|
|
||||||
|= status=@ud
|
|
||||||
^- [(unit error) _state]
|
|
||||||
?+ status [`[%rpc-error ~] state]
|
|
||||||
%200
|
|
||||||
[~ state]
|
|
||||||
%400
|
|
||||||
[`[%bad-request status] state]
|
|
||||||
%401
|
|
||||||
[`[%no-auth status] state(connected.host-info %.n)]
|
|
||||||
%502
|
|
||||||
[`[%not-connected status] state(connected.host-info %.n)]
|
|
||||||
%504
|
|
||||||
[`[%not-connected status] state(connected.host-info %.n)]
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ handle-rpc-result
|
|
||||||
|= [=wire r=result:rpc-types]
|
|
||||||
^- (quip card _state)
|
|
||||||
?+ -.wire ~|("Unexpected HTTP response" !!)
|
|
||||||
%address-info
|
|
||||||
?> ?=([%get-address-info *] r)
|
|
||||||
:_ state
|
|
||||||
~[(send-update [%.y %address-info +.r])]
|
|
||||||
::
|
|
||||||
%tx-info
|
|
||||||
?> ?=([%get-tx-vals *] r)
|
|
||||||
:_ state
|
|
||||||
~[(send-update [%.y %tx-info +.r])]
|
|
||||||
::
|
|
||||||
%raw-tx
|
|
||||||
?> ?=([%get-raw-tx *] r)
|
|
||||||
:_ state
|
|
||||||
~[(send-update [%.y %raw-tx +.r])]
|
|
||||||
::
|
|
||||||
%broadcast-tx
|
|
||||||
?> ?=([%broadcast-tx *] r)
|
|
||||||
:_ state
|
|
||||||
~[(send-update [%.y %broadcast-tx +.r])]
|
|
||||||
::
|
|
||||||
%ping
|
|
||||||
?> ?=([%get-block-info *] r)
|
|
||||||
:_ state(connected.host-info %.y, block.host-info block.r)
|
|
||||||
?: =(block.host-info block.r)
|
|
||||||
~[(send-status [%connected network.host-info block.r fee.r])]
|
|
||||||
~[(send-status [%new-block network.host-info block.r fee.r blockhash.r blockfilter.r])]
|
|
||||||
::
|
|
||||||
%block-info
|
|
||||||
?> ?=([%get-block-info *] r)
|
|
||||||
:_ state
|
|
||||||
~[(send-update [%.y %block-info network.host-info +.r])]
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ send-status
|
++ send-status
|
||||||
|= =status ^- card
|
|= [=status ship=(unit ship)]
|
||||||
|
^- card
|
||||||
%- ?: ?=(%new-block -.status)
|
%- ?: ?=(%new-block -.status)
|
||||||
~&(>> "%new-block: {<block.status>}" same)
|
~&(>> "%new-block: {<block.status>}" same)
|
||||||
same
|
same
|
||||||
[%give %fact ~[/clients] %btc-provider-status !>(status)]
|
=- [%give %fact ~[-] %btc-provider-status !>(status)]
|
||||||
|
?~ ship /clients
|
||||||
|
/clients/(scot %p u.ship)
|
||||||
::
|
::
|
||||||
++ send-update
|
++ send-update
|
||||||
|= =update
|
|= [=update ship=(unit ship)]
|
||||||
^- card
|
^- card
|
||||||
=+ c=[%give %fact ~[/clients] %btc-provider-update !>(update)]
|
%- ?: ?=(%.y -.update)
|
||||||
?: ?=(%.y -.update)
|
same
|
||||||
:: ~& >> "prov. update: {<p.update>}"
|
~&(>> "prov. err: {<p.update>}" same)
|
||||||
c
|
=- [%give %fact ~[-] %btc-provider-update !>(update)]
|
||||||
~& >> "prov. err: {<p.update>}"
|
?~ ship /clients
|
||||||
c
|
/clients/(scot %p u.ship)
|
||||||
::
|
::
|
||||||
++ is-whitelisted
|
++ is-whitelisted
|
||||||
|= user=ship ^- ?
|
~/ %is-whitelisted
|
||||||
|
|= user=ship
|
||||||
|
^- ?
|
||||||
|^
|
|^
|
||||||
?| public.whitelist
|
?| public.whitelist
|
||||||
=(our.bowl user)
|
=(our.bowl user)
|
||||||
@ -319,8 +373,10 @@
|
|||||||
(~(has in users.whitelist) user)
|
(~(has in users.whitelist) user)
|
||||||
in-group
|
in-group
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ is-kid
|
++ is-kid
|
||||||
=(our.bowl (sein:title our.bowl now.bowl user))
|
=(our.bowl (sein:title our.bowl now.bowl user))
|
||||||
|
::
|
||||||
++ in-group
|
++ in-group
|
||||||
=/ gs ~(tap in groups.whitelist)
|
=/ gs ~(tap in groups.whitelist)
|
||||||
|-
|
|-
|
||||||
@ -328,35 +384,15 @@
|
|||||||
?: (~(is-member groupl bowl) user i.gs)
|
?: (~(is-member groupl bowl) user i.gs)
|
||||||
%.y
|
%.y
|
||||||
$(gs t.gs)
|
$(gs t.gs)
|
||||||
:: .^((unit group:g) %gx ;:(weld /=group-store=/groups p /noun))
|
|
||||||
--
|
--
|
||||||
:: +clean-client-list: remove clients who are no longer whitelisted
|
|
||||||
:: called after a whitelist change
|
|
||||||
::
|
|
||||||
++ clean-client-list
|
|
||||||
^- (quip card _state)
|
|
||||||
=/ to-kick=(set ship)
|
|
||||||
%- silt
|
|
||||||
%+ murn ~(tap in clients.host-info)
|
|
||||||
|= c=ship ^- (unit ship)
|
|
||||||
?:((is-whitelisted c) ~ `c)
|
|
||||||
:_ state(clients.host-info (~(dif in clients.host-info) to-kick))
|
|
||||||
%+ turn ~(tap in to-kick)
|
|
||||||
|=(c=ship [%give %kick ~[/clients] `c])
|
|
||||||
::
|
::
|
||||||
++ is-client
|
++ is-client
|
||||||
|= user=ship ^- ?
|
|= user=ship
|
||||||
|
^- ?
|
||||||
(~(has in clients.host-info) user)
|
(~(has in clients.host-info) user)
|
||||||
::
|
::
|
||||||
++ start-ping-timer
|
++ start-ping-timer
|
||||||
|= interval=@dr ^- card
|
|= interval=@dr
|
||||||
[%pass /ping-timer %arvo %b %wait (add now.bowl interval)]
|
|
||||||
::
|
|
||||||
++ do-ping
|
|
||||||
^- card
|
^- card
|
||||||
=/ act=action [%ping ~]
|
[%pass /block-ping %arvo %b %wait (add now.bowl interval)]
|
||||||
:* %pass /ping/[(scot %da now.bowl)] %agent
|
|
||||||
[our.bowl %btc-provider] %poke
|
|
||||||
%btc-provider-action !>(act)
|
|
||||||
==
|
|
||||||
--
|
--
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,6 @@
|
|||||||
<div id="portal-root"></div>
|
<div id="portal-root"></div>
|
||||||
<script src="/~landscape/js/channel.js"></script>
|
<script src="/~landscape/js/channel.js"></script>
|
||||||
<script src="/~landscape/js/session.js"></script>
|
<script src="/~landscape/js/session.js"></script>
|
||||||
<script src="/~btc/js/bundle/index.f7ab13b7db3ec1f8b55a.js"></script>
|
<script src="/~btc/js/bundle/index.3e8bcc150ebd820dd3b2.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
[%glob =glob:glob]
|
[%glob =glob:glob]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ state-3
|
+$ state-4
|
||||||
$: %3
|
$: %4
|
||||||
=configuration:srv
|
=configuration:srv
|
||||||
=serving
|
=serving
|
||||||
==
|
==
|
||||||
@ -22,7 +22,7 @@
|
|||||||
%+ verb |
|
%+ verb |
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
::
|
::
|
||||||
=| state-3
|
=| state-4
|
||||||
=* state -
|
=* state -
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
|_ =bowl:gall
|
|_ =bowl:gall
|
||||||
@ -42,6 +42,7 @@
|
|||||||
==
|
==
|
||||||
:~ (connect /)
|
:~ (connect /)
|
||||||
(connect /'~landscape')
|
(connect /'~landscape')
|
||||||
|
[%pass /serve-who %arvo %e %serve [~ /who] %home /gen/who/hoon ~]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ connect
|
++ connect
|
||||||
@ -56,6 +57,7 @@
|
|||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
|^
|
|^
|
||||||
=+ !<(old-state=versioned-state old-vase)
|
=+ !<(old-state=versioned-state old-vase)
|
||||||
|
=| cards=(list card)
|
||||||
=? old-state ?=(%0 -.old-state)
|
=? old-state ?=(%0 -.old-state)
|
||||||
%= old-state
|
%= old-state
|
||||||
- %1
|
- %1
|
||||||
@ -79,16 +81,23 @@
|
|||||||
^- [^content ? ?]
|
^- [^content ? ?]
|
||||||
[content public %.y]
|
[content public %.y]
|
||||||
==
|
==
|
||||||
?> ?=(%3 -.old-state)
|
=? cards ?=(%3 -.old-state)
|
||||||
[~ this(state old-state)]
|
:_ cards
|
||||||
|
[%pass /serve-who %arvo %e %serve [~ /who] %home /gen/who/hoon ~]
|
||||||
|
=? old-state ?=(%3 -.old-state)
|
||||||
|
old-state(- %4)
|
||||||
|
?> ?=(%4 -.old-state)
|
||||||
|
[cards this(state old-state)]
|
||||||
::
|
::
|
||||||
+$ serving-0 (map url-base=path [=clay=path public=?])
|
+$ serving-0 (map url-base=path [=clay=path public=?])
|
||||||
+$ serving-1 (map url-base=path [=content public=?])
|
+$ serving-1 (map url-base=path [=content public=?])
|
||||||
|
+$ serving-3 (map url-base=path [=content public=? single-page=?])
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-0
|
$% state-0
|
||||||
[%1 state-1]
|
[%1 state-1]
|
||||||
[%2 state-1]
|
[%2 state-1]
|
||||||
state-3
|
state-3
|
||||||
|
state-4
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ state-0
|
+$ state-0
|
||||||
@ -100,6 +109,11 @@
|
|||||||
$: =configuration:srv
|
$: =configuration:srv
|
||||||
serving=serving-1
|
serving=serving-1
|
||||||
==
|
==
|
||||||
|
+$ state-3
|
||||||
|
$: %3
|
||||||
|
=configuration:srv
|
||||||
|
serving=serving-3
|
||||||
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
@ -205,30 +219,35 @@
|
|||||||
?~ ext.req-line site.req-line
|
?~ ext.req-line site.req-line
|
||||||
(snoc site.req-line u.ext.req-line)
|
(snoc site.req-line u.ext.req-line)
|
||||||
=/ content=(unit [=content suffix=path public=?])
|
=/ content=(unit [=content suffix=path public=?])
|
||||||
(get-content pax is-file)
|
(match-content-path pax is-file)
|
||||||
?~ content [not-found:gen %.n]
|
?~ content [not-found:gen %.n]
|
||||||
?- -.content.u.content
|
?- -.content.u.content
|
||||||
%clay
|
%clay
|
||||||
=/ scry-path=path
|
=/ scry-start=path
|
||||||
:* (scot %p our.bowl)
|
:* (scot %p our.bowl)
|
||||||
q.byk.bowl
|
q.byk.bowl
|
||||||
(scot %da now.bowl)
|
(scot %da now.bowl)
|
||||||
(lowercase (weld path.content.u.content suffix.u.content))
|
path.content.u.content
|
||||||
==
|
==
|
||||||
|
=/ scry-path=path
|
||||||
|
(weld scry-start (lowercase suffix.u.content))
|
||||||
|
=? scry-path !.^(? %cu scry-path)
|
||||||
|
(weld scry-start /index/html)
|
||||||
?. .^(? %cu scry-path) [not-found:gen %.n]
|
?. .^(? %cu scry-path) [not-found:gen %.n]
|
||||||
?: ?=([~ %woff2] ext.req-line)
|
?: ?=([~ %woff2] ext.req-line)
|
||||||
:_ public.u.content
|
:_ public.u.content
|
||||||
[[200 [['content-type' '/font/woff2'] ~]] `.^(octs %cx scry-path)]
|
[[200 [['content-type' '/font/woff2'] ~]] `.^(octs %cx scry-path)]
|
||||||
=/ file (as-octs:mimes:html .^(@ %cx scry-path))
|
=/ file (as-octs:mimes:html .^(@ %cx scry-path))
|
||||||
:_ public.u.content
|
:_ public.u.content
|
||||||
?+ ext.req-line not-found:gen
|
=/ ext (rear scry-path)
|
||||||
[~ %js] (js-response:gen file)
|
?+ ext not-found:gen
|
||||||
[~ %css] (css-response:gen file)
|
%js (js-response:gen file)
|
||||||
[~ %png] (png-response:gen file)
|
%css (css-response:gen file)
|
||||||
[~ %svg] (svg-response:gen file)
|
%png (png-response:gen file)
|
||||||
[~ %ico] (ico-response:gen file)
|
%svg (svg-response:gen file)
|
||||||
|
%ico (ico-response:gen file)
|
||||||
::
|
::
|
||||||
[~ %html]
|
%html
|
||||||
%. file
|
%. file
|
||||||
%* . html-response:gen
|
%* . html-response:gen
|
||||||
cache
|
cache
|
||||||
@ -262,17 +281,8 @@
|
|||||||
char
|
char
|
||||||
(add char ^~((sub 'a' 'A')))
|
(add char ^~((sub 'a' 'A')))
|
||||||
::
|
::
|
||||||
++ get-content
|
|
||||||
|= [pax=path is-file=?]
|
|
||||||
^- (unit [content path ?])
|
|
||||||
=/ first-try (match-content-path pax (~(del by serving) /) is-file)
|
|
||||||
?^ first-try first-try
|
|
||||||
=/ root (~(get by serving) /)
|
|
||||||
?~ root ~
|
|
||||||
(match-content-path pax (~(gas by *^serving) [[/ u.root] ~]) is-file)
|
|
||||||
::
|
|
||||||
++ match-content-path
|
++ match-content-path
|
||||||
|= [pax=path =^serving is-file=?]
|
|= [pax=path is-file=?]
|
||||||
^- (unit [content path ?])
|
^- (unit [content path ?])
|
||||||
%+ roll
|
%+ roll
|
||||||
%+ sort ~(tap by serving)
|
%+ sort ~(tap by serving)
|
||||||
@ -338,6 +348,13 @@
|
|||||||
[%x %clay %base %hash ~]
|
[%x %clay %base %hash ~]
|
||||||
=/ versions (base-hash:version [our now]:bowl)
|
=/ versions (base-hash:version [our now]:bowl)
|
||||||
``hash+!>(?~(versions 0v0 (end [0 25] i.versions)))
|
``hash+!>(?~(versions 0v0 (end [0 25] i.versions)))
|
||||||
|
::
|
||||||
|
[%x %our ~]
|
||||||
|
``json+!>(s+(scot %p our.bowl))
|
||||||
|
::
|
||||||
|
[%x %url *]
|
||||||
|
=/ url t.t.path
|
||||||
|
``noun+!>((~(has by serving) url))
|
||||||
==
|
==
|
||||||
++ on-agent on-agent:def
|
++ on-agent on-agent:def
|
||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
/- glob, *resource
|
/- glob, *resource
|
||||||
/+ default-agent, verb, dbug
|
/+ default-agent, verb, dbug
|
||||||
|%
|
|%
|
||||||
++ landscape-hash 0v4.3us6c.ma3il.h5bch.qacg3.70qjl
|
++ landscape-hash 0vrbiqe.v6al2.0b4jc.u9vp7.k1e0i
|
||||||
++ btc-wallet-hash 0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3
|
++ btc-wallet-hash 0v7.v4dng.o33qi.kc497.5jc02.ke5es
|
||||||
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
|
||||||
+$ state-1 [%1 =globs:glob]
|
+$ state-1 [%1 =globs:glob]
|
||||||
+$ all-states
|
+$ all-states
|
||||||
|
@ -26,18 +26,15 @@
|
|||||||
state-one
|
state-one
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ cached-transform
|
+$ post-transform
|
||||||
|
$- indexed-post:store
|
||||||
$-([index:store post:store atom ?] [index:store post:store])
|
$-([index:store post:store atom ?] [index:store post:store])
|
||||||
::
|
::
|
||||||
+$ cached-permission
|
+$ post-to-permission
|
||||||
$-(indexed-post:store $-(vip-metadata:metadata permissions:store))
|
$-(indexed-post:store $-(vip-metadata:metadata permissions:store))
|
||||||
::
|
::
|
||||||
:: TODO: come back to this and potentially use send a %t
|
|
||||||
:: to be notified of validator changes
|
|
||||||
+$ cache
|
+$ cache
|
||||||
$: graph-to-mark=(map resource:res (unit mark))
|
$: graph-to-mark=(map resource:res (unit mark))
|
||||||
perm-marks=(map [mark @tas] cached-permission)
|
|
||||||
transform-marks=(map mark cached-transform)
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ inflated-state
|
+$ inflated-state
|
||||||
@ -47,8 +44,6 @@
|
|||||||
::
|
::
|
||||||
+$ cache-action
|
+$ cache-action
|
||||||
$% [%graph-to-mark (pair resource:res (unit mark))]
|
$% [%graph-to-mark (pair resource:res (unit mark))]
|
||||||
[%perm-marks (pair (pair mark @tas) cached-permission)]
|
|
||||||
[%transform-marks (pair mark cached-transform)]
|
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
@ -90,13 +85,9 @@
|
|||||||
=/ a=cache-action !<(cache-action vase)
|
=/ a=cache-action !<(cache-action vase)
|
||||||
=* c +.state
|
=* c +.state
|
||||||
=* graph-to-mark graph-to-mark.c
|
=* graph-to-mark graph-to-mark.c
|
||||||
=* perm-marks perm-marks.c
|
|
||||||
=* transform-marks transform-marks.c
|
|
||||||
=. c
|
=. c
|
||||||
?- -.a
|
?- -.a
|
||||||
%graph-to-mark c(graph-to-mark (~(put by graph-to-mark) p.a q.a))
|
%graph-to-mark c(graph-to-mark (~(put by graph-to-mark) p.a q.a))
|
||||||
%perm-marks c(perm-marks (~(put by perm-marks) p.a q.a))
|
|
||||||
%transform-marks c(transform-marks (~(put by transform-marks) p.a q.a))
|
|
||||||
==
|
==
|
||||||
[~ this(+.state c)]
|
[~ this(+.state c)]
|
||||||
::
|
::
|
||||||
@ -142,12 +133,9 @@
|
|||||||
|%
|
|%
|
||||||
++ $
|
++ $
|
||||||
^- (quip card (unit vase))
|
^- (quip card (unit vase))
|
||||||
=/ transform=cached-transform
|
=/ transform
|
||||||
%+ fall
|
%. *indexed-post:store
|
||||||
(~(get by transform-marks) u.mark)
|
.^(post-transform (scry:hc %cf %home /[u.mark]/transform-add-nodes))
|
||||||
=/ =tube:clay
|
|
||||||
.^(tube:clay (scry:hc %cc %home /[u.mark]/transform-add-nodes))
|
|
||||||
!<(cached-transform (tube !>(*indexed-post:store)))
|
|
||||||
=/ [* result=(list [index:store node:store])]
|
=/ [* result=(list [index:store node:store])]
|
||||||
%+ roll
|
%+ roll
|
||||||
(flatten-node-map ~(tap by nodes.q.update))
|
(flatten-node-map ~(tap by nodes.q.update))
|
||||||
@ -166,13 +154,6 @@
|
|||||||
%+ poke-self:pass:io %graph-cache-hook
|
%+ poke-self:pass:io %graph-cache-hook
|
||||||
!> ^- cache-action
|
!> ^- cache-action
|
||||||
[%graph-to-mark rid mark]
|
[%graph-to-mark rid mark]
|
||||||
::
|
|
||||||
?: (~(has by transform-marks) u.mark)
|
|
||||||
~
|
|
||||||
:_ ~
|
|
||||||
%+ poke-self:pass:io %graph-cache-hook
|
|
||||||
!> ^- cache-action
|
|
||||||
[%transform-marks u.mark transform]
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ flatten-node-map
|
++ flatten-node-map
|
||||||
@ -322,9 +303,7 @@
|
|||||||
[[%no %no %no] ~]
|
[[%no %no %no] ~]
|
||||||
=/ key [u.mark (perm-mark-name perm)]
|
=/ key [u.mark (perm-mark-name perm)]
|
||||||
=/ convert
|
=/ convert
|
||||||
%+ fall
|
.^(post-to-permission (scry %cf %home /[u.mark]/(perm-mark-name perm)))
|
||||||
(~(get by perm-marks.cache) key)
|
|
||||||
.^(cached-permission (scry %cf %home /[u.mark]/(perm-mark-name perm)))
|
|
||||||
:- ((convert indexed-post) vip)
|
:- ((convert indexed-post) vip)
|
||||||
%- zing
|
%- zing
|
||||||
:~ ?: (~(has by graph-to-mark.cache) resource)
|
:~ ?: (~(has by graph-to-mark.cache) resource)
|
||||||
@ -333,12 +312,6 @@
|
|||||||
%+ poke-self:pass:io %graph-cache-hook
|
%+ poke-self:pass:io %graph-cache-hook
|
||||||
!> ^- cache-action
|
!> ^- cache-action
|
||||||
[%graph-to-mark resource mark]
|
[%graph-to-mark resource mark]
|
||||||
::
|
|
||||||
?: (~(has by perm-marks.cache) key) ~
|
|
||||||
:_ ~
|
|
||||||
%+ poke-self:pass:io %graph-cache-hook
|
|
||||||
!> ^- cache-action
|
|
||||||
[%perm-marks [u.mark (perm-mark-name perm)] convert]
|
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ perm-mark-name
|
++ perm-mark-name
|
||||||
|
@ -16,20 +16,9 @@
|
|||||||
+$ state-5 [%5 network:store]
|
+$ state-5 [%5 network:store]
|
||||||
++ orm orm:store
|
++ orm orm:store
|
||||||
++ orm-log orm-log:store
|
++ orm-log orm-log:store
|
||||||
::
|
|
||||||
+$ cache
|
|
||||||
$: validators=(map mark $-(indexed-post:store indexed-post:store))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
:: TODO: come back to this and potentially use ford runes or otherwise
|
|
||||||
:: send a %t to be notified of validator changes
|
|
||||||
+$ inflated-state
|
|
||||||
$: state-5
|
|
||||||
cache
|
|
||||||
==
|
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
=| inflated-state
|
=| state-5
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
@ -41,7 +30,7 @@
|
|||||||
def ~(. (default-agent this %|) bowl)
|
def ~(. (default-agent this %|) bowl)
|
||||||
::
|
::
|
||||||
++ on-init [~ this]
|
++ on-init [~ this]
|
||||||
++ on-save !>(-.state)
|
++ on-save !>(state)
|
||||||
++ on-load
|
++ on-load
|
||||||
|= =old=vase
|
|= =old=vase
|
||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
@ -91,7 +80,7 @@
|
|||||||
(gas:orm-log ~ [now.bowl logged-update] ~)
|
(gas:orm-log ~ [now.bowl logged-update] ~)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%5 [cards this(-.state old, +.state *cache)]
|
%5 [cards this(state old)]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
@ -593,8 +582,6 @@
|
|||||||
?~ mark
|
?~ mark
|
||||||
[%.y state]
|
[%.y state]
|
||||||
=/ validate=$-(indexed-post:store indexed-post:store)
|
=/ validate=$-(indexed-post:store indexed-post:store)
|
||||||
%+ fall
|
|
||||||
(~(get by validators) u.mark)
|
|
||||||
.^ $-(indexed-post:store indexed-post:store)
|
.^ $-(indexed-post:store indexed-post:store)
|
||||||
%cf
|
%cf
|
||||||
(scot %p our.bowl)
|
(scot %p our.bowl)
|
||||||
@ -604,8 +591,6 @@
|
|||||||
%graph-indexed-post
|
%graph-indexed-post
|
||||||
~
|
~
|
||||||
==
|
==
|
||||||
=? validators !(~(has by validators) u.mark)
|
|
||||||
(~(put by validators) u.mark validate)
|
|
||||||
:_ state
|
:_ state
|
||||||
|- ^- ?
|
|- ^- ?
|
||||||
?~ graph %.y
|
?~ graph %.y
|
||||||
@ -624,7 +609,7 @@
|
|||||||
++ poke-import
|
++ poke-import
|
||||||
|= arc=*
|
|= arc=*
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
=^ cards -.state
|
=^ cards state
|
||||||
(import:store arc our.bowl)
|
(import:store arc our.bowl)
|
||||||
[cards state]
|
[cards state]
|
||||||
--
|
--
|
||||||
|
@ -127,8 +127,13 @@
|
|||||||
++ hide
|
++ hide
|
||||||
|= rid=resource
|
|= rid=resource
|
||||||
^- (quip card _state)
|
^- (quip card _state)
|
||||||
|
=/ =request:view (~(got by joining) rid)
|
||||||
|
?: ?=(final:view progress.request)
|
||||||
|
=. joining (~(del by joining) rid)
|
||||||
|
:_ state
|
||||||
|
(fact:io group-view-update+!>(`update:view`[%initial joining]) /all ~)^~
|
||||||
:- (fact:io group-view-update+!>([%hide rid]) /all ~)^~
|
:- (fact:io group-view-update+!>([%hide rid]) /all ~)^~
|
||||||
state(joining (~(jab by joining) rid |=(request:view +<(hidden %.y))))
|
state(joining (~(put by joining) rid request(hidden %.y)))
|
||||||
::
|
::
|
||||||
++ has-joined
|
++ has-joined
|
||||||
|= rid=resource
|
|= rid=resource
|
||||||
@ -160,7 +165,7 @@
|
|||||||
++ tx-progress
|
++ tx-progress
|
||||||
|= =progress:view
|
|= =progress:view
|
||||||
=. joining
|
=. joining
|
||||||
(~(jab by joining) rid |=(request:view +<(progress progress)))
|
(~(jab by joining) rid |=(req=request:view req(progress progress)))
|
||||||
=; =cage
|
=; =cage
|
||||||
(emit (fact:io cage /all tx+(en-path:resource rid) ~))
|
(emit (fact:io cage /all tx+(en-path:resource rid) ~))
|
||||||
group-view-update+!>([%progress rid progress])
|
group-view-update+!>([%progress rid progress])
|
||||||
@ -217,10 +222,11 @@
|
|||||||
?> ?=(%poke-ack -.sign)
|
?> ?=(%poke-ack -.sign)
|
||||||
?^ p.sign
|
?^ p.sign
|
||||||
(cleanup %no-perms)
|
(cleanup %no-perms)
|
||||||
=> %- emit
|
=. jn-core
|
||||||
%+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook
|
(tx-progress %added)
|
||||||
pull-hook-action+!>([%add ship rid])
|
%- emit
|
||||||
(tx-progress %added)
|
%+ poke-our:(jn-pass-io /pull-groups) %group-pull-hook
|
||||||
|
pull-hook-action+!>([%add ship rid])
|
||||||
::
|
::
|
||||||
%pull-groups
|
%pull-groups
|
||||||
?> ?=(%poke-ack -.sign)
|
?> ?=(%poke-ack -.sign)
|
||||||
@ -324,7 +330,6 @@
|
|||||||
|= =progress:view
|
|= =progress:view
|
||||||
=. jn-core
|
=. jn-core
|
||||||
(tx-progress progress)
|
(tx-progress progress)
|
||||||
=. joining (~(del by joining) rid)
|
|
||||||
=. jn-core
|
=. jn-core
|
||||||
(emit (leave-our:(jn-pass-io /groups) %group-store))
|
(emit (leave-our:(jn-pass-io /groups) %group-store))
|
||||||
(emit (leave-our:(jn-pass-io /md) %metadata-store))
|
(emit (leave-our:(jn-pass-io /md) %metadata-store))
|
||||||
|
@ -74,21 +74,9 @@
|
|||||||
==
|
==
|
||||||
:_ this(state old)
|
:_ this(state old)
|
||||||
=. cards (flop cards)
|
=. cards (flop cards)
|
||||||
%+ welp
|
?: (~(has by wex.bowl) [/graph our.bowl %graph-store])
|
||||||
?: (~(has by wex.bowl) [/graph our.bowl %graph-store])
|
cards
|
||||||
cards
|
[watch-graph:ha cards]
|
||||||
[watch-graph:ha cards]
|
|
||||||
%+ turn
|
|
||||||
^- (list mark)
|
|
||||||
:~ %graph-validator-chat
|
|
||||||
%graph-validator-link
|
|
||||||
%graph-validator-publish
|
|
||||||
==
|
|
||||||
|= =mark
|
|
||||||
^- card
|
|
||||||
=/ =wire /validator/[mark]
|
|
||||||
=/ =rave:clay [%sing %f [%da now.bowl] /[mark]/notification-kind]
|
|
||||||
[%pass wire %arvo %c %warp our.bowl [%home `rave]]
|
|
||||||
::
|
::
|
||||||
++ on-watch
|
++ on-watch
|
||||||
|= =path
|
|= =path
|
||||||
@ -281,11 +269,8 @@
|
|||||||
^- (quip card _this)
|
^- (quip card _this)
|
||||||
?+ wire (on-arvo:def wire sign-arvo)
|
?+ wire (on-arvo:def wire sign-arvo)
|
||||||
::
|
::
|
||||||
[%validator @ ~]
|
:: no longer necessary
|
||||||
:_ this
|
[%validator @ ~] [~ this]
|
||||||
=* validator i.t.wire
|
|
||||||
=/ =rave:clay [%next %f [%da now.bowl] /[validator]/notification-kind]
|
|
||||||
[%pass wire %arvo %c %warp our.bowl [%home `rave]]~
|
|
||||||
==
|
==
|
||||||
++ on-fail on-fail:def
|
++ on-fail on-fail:def
|
||||||
--
|
--
|
||||||
|
@ -24,6 +24,6 @@
|
|||||||
<div id="portal-root"></div>
|
<div id="portal-root"></div>
|
||||||
<script src="/~landscape/js/channel.js"></script>
|
<script src="/~landscape/js/channel.js"></script>
|
||||||
<script src="/~landscape/js/session.js"></script>
|
<script src="/~landscape/js/session.js"></script>
|
||||||
<script src="/~landscape/js/bundle/index.af45eeaf465dff7d73f1.js"></script>
|
<script src="/~landscape/js/bundle/index.8074ae0006fba19803f5.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -107,6 +107,7 @@
|
|||||||
+$ state-9 [%9 base-state-3]
|
+$ state-9 [%9 base-state-3]
|
||||||
+$ state-10 [%10 base-state-3]
|
+$ state-10 [%10 base-state-3]
|
||||||
+$ state-11 [%11 base-state-3]
|
+$ state-11 [%11 base-state-3]
|
||||||
|
+$ state-12 [%12 base-state-3]
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% state-0
|
$% state-0
|
||||||
state-1
|
state-1
|
||||||
@ -120,10 +121,11 @@
|
|||||||
state-9
|
state-9
|
||||||
state-10
|
state-10
|
||||||
state-11
|
state-11
|
||||||
|
state-12
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ inflated-state
|
+$ inflated-state
|
||||||
$: state-11
|
$: state-12
|
||||||
cached-indices
|
cached-indices
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
@ -243,7 +245,7 @@
|
|||||||
=| cards=(list card)
|
=| cards=(list card)
|
||||||
|^
|
|^
|
||||||
=* loop $
|
=* loop $
|
||||||
?: ?=(%11 -.old)
|
?: ?=(%12 -.old)
|
||||||
:- cards
|
:- cards
|
||||||
%_ state
|
%_ state
|
||||||
associations associations.old
|
associations associations.old
|
||||||
@ -251,6 +253,8 @@
|
|||||||
group-indices (rebuild-group-indices associations.old)
|
group-indices (rebuild-group-indices associations.old)
|
||||||
app-indices (rebuild-app-indices associations.old)
|
app-indices (rebuild-app-indices associations.old)
|
||||||
==
|
==
|
||||||
|
?: ?=(%11 -.old)
|
||||||
|
$(-.old %12, associations.old (reset-group-hidden associations.old))
|
||||||
?: ?=(%10 -.old)
|
?: ?=(%10 -.old)
|
||||||
$(-.old %11, associations.old (hide-dm-assoc associations.old))
|
$(-.old %11, associations.old (hide-dm-assoc associations.old))
|
||||||
?: ?=(%9 -.old)
|
?: ?=(%9 -.old)
|
||||||
@ -293,6 +297,17 @@
|
|||||||
:: pre-breach, can safely throw away
|
:: pre-breach, can safely throw away
|
||||||
loop(old *state-8)
|
loop(old *state-8)
|
||||||
::
|
::
|
||||||
|
++ reset-group-hidden
|
||||||
|
|= assoc=associations:store
|
||||||
|
^- associations:store
|
||||||
|
%- ~(gas by *associations:store)
|
||||||
|
%+ turn ~(tap by assoc)
|
||||||
|
|= [m=md-resource:store [g=resource met=metadatum:store]]
|
||||||
|
^- [md-resource:store association:store]
|
||||||
|
=? hidden.met ?=(%groups app-name.m)
|
||||||
|
%.n
|
||||||
|
[m [g met]]
|
||||||
|
::
|
||||||
++ hide-dm-assoc
|
++ hide-dm-assoc
|
||||||
|= assoc=associations:store
|
|= assoc=associations:store
|
||||||
^- associations:store
|
^- associations:store
|
||||||
|
@ -8,6 +8,12 @@
|
|||||||
::
|
::
|
||||||
|%
|
|%
|
||||||
+$ card card:agent:gall
|
+$ card card:agent:gall
|
||||||
|
+$ state-0
|
||||||
|
$: observers=(map serial observer:sur)
|
||||||
|
warm-cache=_|
|
||||||
|
static-conversions=(set [term term])
|
||||||
|
==
|
||||||
|
::
|
||||||
+$ versioned-state
|
+$ versioned-state
|
||||||
$% [%0 observers=(map serial observer:sur)]
|
$% [%0 observers=(map serial observer:sur)]
|
||||||
[%1 observers=(map serial observer:sur)]
|
[%1 observers=(map serial observer:sur)]
|
||||||
@ -15,6 +21,7 @@
|
|||||||
[%3 observers=(map serial observer:sur)]
|
[%3 observers=(map serial observer:sur)]
|
||||||
[%4 observers=(map serial observer:sur)]
|
[%4 observers=(map serial observer:sur)]
|
||||||
[%5 observers=(map serial observer:sur) warm-cache=_|]
|
[%5 observers=(map serial observer:sur) warm-cache=_|]
|
||||||
|
[%6 state-0]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ serial @uv
|
+$ serial @uv
|
||||||
@ -28,7 +35,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
%- agent:dbug
|
%- agent:dbug
|
||||||
=| [%5 observers=(map serial observer:sur) warm-cache=_|]
|
=| [%6 state-0]
|
||||||
=* state -
|
=* state -
|
||||||
::
|
::
|
||||||
^- agent:gall
|
^- agent:gall
|
||||||
@ -44,6 +51,33 @@
|
|||||||
(act [%watch %group-store /groups %group-on-remove-member])
|
(act [%watch %group-store /groups %group-on-remove-member])
|
||||||
(act [%watch %metadata-store /updates %md-on-add-group-feed])
|
(act [%watch %metadata-store /updates %md-on-add-group-feed])
|
||||||
(act [%warm-cache-all ~])
|
(act [%warm-cache-all ~])
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-publish %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-link %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-post %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-dm %graph-indexed-post)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-publish %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-link %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-post %graph-permissions-add)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-publish %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-link %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-post %graph-permissions-remove)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %notification-kind)
|
||||||
|
(warm-static %graph-validator-publish %notification-kind)
|
||||||
|
(warm-static %graph-validator-link %notification-kind)
|
||||||
|
(warm-static %graph-validator-post %notification-kind)
|
||||||
|
(warm-static %graph-validator-dm %notification-kind)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-publish %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-link %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-post %transform-add-nodes)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ act
|
++ act
|
||||||
@ -57,6 +91,19 @@
|
|||||||
%observe-action
|
%observe-action
|
||||||
!>(action)
|
!>(action)
|
||||||
==
|
==
|
||||||
|
::
|
||||||
|
++ warm-static
|
||||||
|
|= [from=term to=term]
|
||||||
|
^- card
|
||||||
|
:* %pass
|
||||||
|
/poke
|
||||||
|
%agent
|
||||||
|
[our.bowl %observe-hook]
|
||||||
|
%poke
|
||||||
|
%observe-action
|
||||||
|
!> ^- action:sur
|
||||||
|
[%warm-static-conversion from to]
|
||||||
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-save !>(state)
|
++ on-save !>(state)
|
||||||
@ -68,8 +115,41 @@
|
|||||||
=| cards=(list card)
|
=| cards=(list card)
|
||||||
|-
|
|-
|
||||||
?- -.old-state
|
?- -.old-state
|
||||||
%5
|
%6
|
||||||
[cards this(state old-state)]
|
[cards this(state old-state)]
|
||||||
|
::
|
||||||
|
%5
|
||||||
|
=. cards
|
||||||
|
%+ weld cards
|
||||||
|
:~ (warm-static %graph-validator-chat %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-publish %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-link %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-post %graph-indexed-post)
|
||||||
|
(warm-static %graph-validator-dm %graph-indexed-post)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-publish %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-link %graph-permissions-add)
|
||||||
|
(warm-static %graph-validator-post %graph-permissions-add)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-publish %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-link %graph-permissions-remove)
|
||||||
|
(warm-static %graph-validator-post %graph-permissions-remove)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %notification-kind)
|
||||||
|
(warm-static %graph-validator-publish %notification-kind)
|
||||||
|
(warm-static %graph-validator-link %notification-kind)
|
||||||
|
(warm-static %graph-validator-post %notification-kind)
|
||||||
|
(warm-static %graph-validator-dm %notification-kind)
|
||||||
|
::
|
||||||
|
(warm-static %graph-validator-chat %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-publish %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-link %transform-add-nodes)
|
||||||
|
(warm-static %graph-validator-post %transform-add-nodes)
|
||||||
|
==
|
||||||
|
$(old-state [%6 observers.old-state %.n ~])
|
||||||
|
::
|
||||||
%4
|
%4
|
||||||
=. cards
|
=. cards
|
||||||
:_ cards
|
:_ cards
|
||||||
@ -109,6 +189,19 @@
|
|||||||
%observe-action
|
%observe-action
|
||||||
!>(action)
|
!>(action)
|
||||||
==
|
==
|
||||||
|
::
|
||||||
|
++ warm-static
|
||||||
|
|= [from=term to=term]
|
||||||
|
^- card
|
||||||
|
:* %pass
|
||||||
|
/poke
|
||||||
|
%agent
|
||||||
|
[our.bowl %observe-hook]
|
||||||
|
%poke
|
||||||
|
%observe-action
|
||||||
|
!> ^- action:sur
|
||||||
|
[%warm-static-conversion from to]
|
||||||
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-poke
|
++ on-poke
|
||||||
@ -122,10 +215,12 @@
|
|||||||
=* observer observer.action
|
=* observer observer.action
|
||||||
=/ vals (silt ~(val by observers))
|
=/ vals (silt ~(val by observers))
|
||||||
?- -.action
|
?- -.action
|
||||||
%watch (watch observer vals)
|
%watch (watch observer vals)
|
||||||
%ignore (ignore observer vals)
|
%ignore (ignore observer vals)
|
||||||
%warm-cache-all warm-cache-all
|
%warm-cache-all warm-cache-all
|
||||||
%cool-cache-all cool-cache-all
|
%cool-cache-all cool-cache-all
|
||||||
|
%warm-static-conversion (warm-static-conversion from.action to.action)
|
||||||
|
%cool-static-conversion (cool-static-conversion from.action to.action)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ watch
|
++ watch
|
||||||
@ -170,6 +265,23 @@
|
|||||||
?. warm-cache
|
?. warm-cache
|
||||||
~|('cannot cool down cache that is already cool' !!)
|
~|('cannot cool down cache that is already cool' !!)
|
||||||
[~ this(warm-cache %.n)]
|
[~ this(warm-cache %.n)]
|
||||||
|
::
|
||||||
|
++ warm-static-conversion
|
||||||
|
|= [from=term to=term]
|
||||||
|
^- (quip card _this)
|
||||||
|
?: (~(has in static-conversions) [from to])
|
||||||
|
~|('cannot warm up a static conversion that is already warm' !!)
|
||||||
|
:_ this(static-conversions (~(put in static-conversions) [from to]))
|
||||||
|
=/ =wire /static-convert/[from]/[to]
|
||||||
|
=/ =rave:clay [%sing %f [%da now.bowl] /[from]/[to]]
|
||||||
|
[%pass wire %arvo %c %warp our.bowl %home `rave]~
|
||||||
|
::
|
||||||
|
++ cool-static-conversion
|
||||||
|
|= [from=term to=term]
|
||||||
|
^- (quip card _this)
|
||||||
|
?. (~(has in static-conversions) [from to])
|
||||||
|
~|('cannot cool a static conversion that is already cool' !!)
|
||||||
|
[~ this(static-conversions (~(del in static-conversions) [from to]))]
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ on-agent
|
++ on-agent
|
||||||
@ -326,6 +438,18 @@
|
|||||||
~
|
~
|
||||||
=/ =rave:clay [%next %b q.p.u.riot mark]
|
=/ =rave:clay [%next %b q.p.u.riot mark]
|
||||||
[%pass wire %arvo %c %warp our.bowl %home `rave]~
|
[%pass wire %arvo %c %warp our.bowl %home `rave]~
|
||||||
|
::
|
||||||
|
[%static-convert @ @ ~]
|
||||||
|
=* from i.t.wire
|
||||||
|
=* to i.t.t.wire
|
||||||
|
?. (~(has in static-conversions) [from to])
|
||||||
|
~
|
||||||
|
?> ?=([%clay %writ *] sign-arvo)
|
||||||
|
=* riot p.sign-arvo
|
||||||
|
?~ riot
|
||||||
|
~
|
||||||
|
=/ =rave:clay [%next %f q.p.u.riot /[from]/[to]]
|
||||||
|
[%pass wire %arvo %c %warp our.bowl %home `rave]~
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ on-watch on-watch:def
|
++ on-watch on-watch:def
|
||||||
|
11
pkg/arvo/gen/group-view/join.hoon
Normal file
11
pkg/arvo/gen/group-view/join.hoon
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
:: group-view|join: Join a group
|
||||||
|
::
|
||||||
|
/- view=group-view
|
||||||
|
:- %say
|
||||||
|
|= $: [now=@da eny=@uvJ =beak]
|
||||||
|
[[him=ship name=term ~] ~]
|
||||||
|
==
|
||||||
|
::
|
||||||
|
:- %group-view-action
|
||||||
|
^- action:view
|
||||||
|
[%join [him name] him]
|
@ -1,5 +1,6 @@
|
|||||||
/- bc=bitcoin
|
/- bc=bitcoin
|
||||||
/+ bcu=bitcoin-utils
|
/+ bcu=bitcoin-utils
|
||||||
|
~% %bip-158-top ..part ~
|
||||||
|%
|
|%
|
||||||
++ params
|
++ params
|
||||||
|%
|
|%
|
||||||
@ -8,6 +9,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ siphash
|
++ siphash
|
||||||
|
~/ %siphash
|
||||||
|= [k=byts m=byts]
|
|= [k=byts m=byts]
|
||||||
^- byts
|
^- byts
|
||||||
|^
|
|^
|
||||||
@ -86,25 +88,28 @@
|
|||||||
:: write appends to the back
|
:: write appends to the back
|
||||||
::
|
::
|
||||||
++ str
|
++ str
|
||||||
|
~% %str ..params ~
|
||||||
|%
|
|%
|
||||||
++ read-bit
|
++ read-bit
|
||||||
|
~/ %read-bit
|
||||||
|= s=bits:bc
|
|= s=bits:bc
|
||||||
^- [bit=@ub rest=bits:bc]
|
^- [bit=@ub rest=bits:bc]
|
||||||
?> (gth wid.s 0)
|
?> (gth wid.s 0)
|
||||||
:* ?:((gth wid.s (met 0 dat.s)) 0b0 0b1)
|
:+ ?:((gth wid.s (met 0 dat.s)) 0b0 0b1)
|
||||||
[(dec wid.s) (end [0 (dec wid.s)] dat.s)]
|
(dec wid.s)
|
||||||
==
|
(end [0 (dec wid.s)] dat.s)
|
||||||
|
::
|
||||||
::
|
::
|
||||||
++ read-bits
|
++ read-bits
|
||||||
|
~/ %read-bits
|
||||||
|= [n=@ s=bits:bc]
|
|= [n=@ s=bits:bc]
|
||||||
^- [bits:bc rest=bits:bc]
|
^- [bits:bc rest=bits:bc]
|
||||||
=| bs=bits:bc
|
=/ r=@ (sub wid.s n)
|
||||||
|-
|
:- n^(cut 0 [r n] dat.s)
|
||||||
?: =(n 0) [bs s]
|
r^(cut 0 [0 r] dat.s)
|
||||||
=^ b s (read-bit s)
|
|
||||||
$(n (dec n), bs (write-bits bs [1 b]))
|
|
||||||
::
|
::
|
||||||
++ write-bits
|
++ write-bits
|
||||||
|
~/ %write-bits
|
||||||
|= [s1=bits:bc s2=bits:bc]
|
|= [s1=bits:bc s2=bits:bc]
|
||||||
^- bits:bc
|
^- bits:bc
|
||||||
[(add wid.s1 wid.s2) (can 0 ~[s2 s1])]
|
[(add wid.s1 wid.s2) (can 0 ~[s2 s1])]
|
||||||
@ -112,6 +117,7 @@
|
|||||||
:: +gol: Golomb-Rice encoding/decoding
|
:: +gol: Golomb-Rice encoding/decoding
|
||||||
::
|
::
|
||||||
++ gol
|
++ gol
|
||||||
|
~% %gol ..params ~
|
||||||
|%
|
|%
|
||||||
:: +en: encode x and append to end of s
|
:: +en: encode x and append to end of s
|
||||||
:: - s: bits stream
|
:: - s: bits stream
|
||||||
@ -119,6 +125,7 @@
|
|||||||
:: - p: golomb-rice p param
|
:: - p: golomb-rice p param
|
||||||
::
|
::
|
||||||
++ en
|
++ en
|
||||||
|
~/ %en
|
||||||
|= [s=bits:bc x=@ p=@]
|
|= [s=bits:bc x=@ p=@]
|
||||||
^- bits:bc
|
^- bits:bc
|
||||||
=+ q=(rsh [0 p] x)
|
=+ q=(rsh [0 p] x)
|
||||||
@ -128,6 +135,7 @@
|
|||||||
(write-bits:str unary r)
|
(write-bits:str unary r)
|
||||||
::
|
::
|
||||||
++ de
|
++ de
|
||||||
|
~/ %de
|
||||||
|= [s=bits:bc p=@]
|
|= [s=bits:bc p=@]
|
||||||
^- [delta=@ rest=bits:bc]
|
^- [delta=@ rest=bits:bc]
|
||||||
|^ ?> (gth wid.s 0)
|
|^ ?> (gth wid.s 0)
|
||||||
@ -148,6 +156,7 @@
|
|||||||
:: +hsh
|
:: +hsh
|
||||||
::
|
::
|
||||||
++ hsh
|
++ hsh
|
||||||
|
~% %hsh ..params ~
|
||||||
|%
|
|%
|
||||||
:: +to-range
|
:: +to-range
|
||||||
:: - item: scriptpubkey to hash
|
:: - item: scriptpubkey to hash
|
||||||
@ -155,9 +164,10 @@
|
|||||||
:: - k: key for siphash (end of blockhash, reversed)
|
:: - k: key for siphash (end of blockhash, reversed)
|
||||||
::
|
::
|
||||||
++ to-range
|
++ to-range
|
||||||
|
~/ %to-range
|
||||||
|= [item=byts f=@ k=byts]
|
|= [item=byts f=@ k=byts]
|
||||||
^- @
|
^- @
|
||||||
(rsh [0 64] (mul f (swp 3 dat:(siphash k item))))
|
(rsh [0 64] (mul f (rev 3 (siphash k item))))
|
||||||
:: +set-construct: return sorted hashes of scriptpubkeys
|
:: +set-construct: return sorted hashes of scriptpubkeys
|
||||||
::
|
::
|
||||||
++ set-construct
|
++ set-construct
|
||||||
@ -171,6 +181,7 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ parse-filter
|
++ parse-filter
|
||||||
|
~/ %parse-filter
|
||||||
|= filter=hexb:bc
|
|= filter=hexb:bc
|
||||||
^- [n=@ux gcs-set=bits:bc]
|
^- [n=@ux gcs-set=bits:bc]
|
||||||
=/ n n:(de:csiz:bcu filter)
|
=/ n n:(de:csiz:bcu filter)
|
||||||
@ -180,6 +191,7 @@
|
|||||||
:: +to-key: blockhash (little endian) to key for siphash
|
:: +to-key: blockhash (little endian) to key for siphash
|
||||||
::
|
::
|
||||||
++ to-key
|
++ to-key
|
||||||
|
~/ %to-key
|
||||||
|= blockhash=tape
|
|= blockhash=tape
|
||||||
^- byts
|
^- byts
|
||||||
%+ take:byt:bcu 16
|
%+ take:byt:bcu 16
|
||||||
@ -191,6 +203,7 @@
|
|||||||
:: - targets: scriptpubkeys to match
|
:: - targets: scriptpubkeys to match
|
||||||
::
|
::
|
||||||
++ match
|
++ match
|
||||||
|
~/ %match
|
||||||
|= [filter=hexb:bc k=byts targets=(list byts)]
|
|= [filter=hexb:bc k=byts targets=(list byts)]
|
||||||
^- ?
|
^- ?
|
||||||
=/ [p=@ m=@] [p:params m:params]
|
=/ [p=@ m=@] [p:params m:params]
|
||||||
@ -214,6 +227,7 @@
|
|||||||
:: - targets: scriptpubkeys to match
|
:: - targets: scriptpubkeys to match
|
||||||
::
|
::
|
||||||
++ all-match
|
++ all-match
|
||||||
|
~/ %all-match
|
||||||
|= [filter=hexb:bc blockhash=hexb:bc targets=(list [address:bc byts])]
|
|= [filter=hexb:bc blockhash=hexb:bc targets=(list [address:bc byts])]
|
||||||
^- (set [address:bc hexb:bc])
|
^- (set [address:bc hexb:bc])
|
||||||
=/ k (to-key (trip (to-cord:hxb:bcu blockhash)))
|
=/ k (to-key (trip (to-cord:hxb:bcu blockhash)))
|
||||||
|
@ -110,6 +110,7 @@
|
|||||||
%cancel-tx (hexb txid.upd)
|
%cancel-tx (hexb txid.upd)
|
||||||
%new-address (address address.upd)
|
%new-address (address address.upd)
|
||||||
%balance (balance balance.upd)
|
%balance (balance balance.upd)
|
||||||
|
%scan-progress (scan-progress main.upd change.upd)
|
||||||
%error s+error.upd
|
%error s+error.upd
|
||||||
%broadcast-success ~
|
%broadcast-success ~
|
||||||
==
|
==
|
||||||
@ -161,6 +162,19 @@
|
|||||||
unconfirmed+(numb q.u.b)
|
unconfirmed+(numb q.u.b)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
|
++ scan-progress
|
||||||
|
|= [main=(unit idx:bitcoin) change=(unit idx:bitcoin)]
|
||||||
|
|^ ^- json
|
||||||
|
%- pairs
|
||||||
|
:~ main+(from-unit main)
|
||||||
|
change+(from-unit change)
|
||||||
|
==
|
||||||
|
++ from-unit
|
||||||
|
|= i=(unit idx:bitcoin)
|
||||||
|
?~ i ~
|
||||||
|
(numb u.i)
|
||||||
|
--
|
||||||
|
::
|
||||||
++ btc-state
|
++ btc-state
|
||||||
|= bs=btc-state:btc-wallet
|
|= bs=btc-state:btc-wallet
|
||||||
^- json
|
^- json
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
:: lib/bitcoin-utils.hoon
|
:: lib/bitcoin-utils.hoon
|
||||||
:: Utilities for working with BTC data types and transactions
|
:: Utilities for working with BTC data types and transactions
|
||||||
::
|
::
|
||||||
/- sur=bitcoin
|
/- *bitcoin
|
||||||
=, sur
|
~% %bitcoin-utils-lib ..part ~
|
||||||
|%
|
|%
|
||||||
::
|
::
|
||||||
:: TODO: move this bit/byt stuff to zuse
|
:: TODO: move this bit/byt stuff to zuse
|
||||||
@ -12,6 +12,7 @@
|
|||||||
:: +blop: munge bit and byt sequences (cat, flip, take, drop)
|
:: +blop: munge bit and byt sequences (cat, flip, take, drop)
|
||||||
::
|
::
|
||||||
++ blop
|
++ blop
|
||||||
|
~/ %blop
|
||||||
|_ =bloq
|
|_ =bloq
|
||||||
+$ biyts [wid=@ud dat=@]
|
+$ biyts [wid=@ud dat=@]
|
||||||
++ cat
|
++ cat
|
||||||
@ -48,6 +49,7 @@
|
|||||||
++ byt ~(. blop 3)
|
++ byt ~(. blop 3)
|
||||||
::
|
::
|
||||||
++ bit
|
++ bit
|
||||||
|
~/ %bit
|
||||||
=/ bl ~(. blop 0)
|
=/ bl ~(. blop 0)
|
||||||
|%
|
|%
|
||||||
++ cat cat:bl:bit
|
++ cat cat:bl:bit
|
||||||
@ -79,16 +81,19 @@
|
|||||||
:: big endian sha256: input and output are both MSB first (big endian)
|
:: big endian sha256: input and output are both MSB first (big endian)
|
||||||
::
|
::
|
||||||
++ sha256
|
++ sha256
|
||||||
|
~/ %sha256
|
||||||
|= =byts
|
|= =byts
|
||||||
^- hexb
|
^- hexb
|
||||||
%- flip:byt
|
%- flip:byt
|
||||||
[32 (shay (flip:byt byts))]
|
[32 (shay (flip:byt byts))]
|
||||||
::
|
::
|
||||||
++ dsha256
|
++ dsha256
|
||||||
|
~/ %dsha256
|
||||||
|= =byts
|
|= =byts
|
||||||
(sha256 (sha256 byts))
|
(sha256 (sha256 byts))
|
||||||
::
|
::
|
||||||
++ hash-160
|
++ hash-160
|
||||||
|
~/ %hash-160
|
||||||
|= val=byts
|
|= val=byts
|
||||||
^- hexb
|
^- hexb
|
||||||
=, ripemd:crypto
|
=, ripemd:crypto
|
||||||
@ -100,8 +105,10 @@
|
|||||||
:: hxb: hex parsing utilities
|
:: hxb: hex parsing utilities
|
||||||
::
|
::
|
||||||
++ hxb
|
++ hxb
|
||||||
|
~% %hxb ..blop ~
|
||||||
|%
|
|%
|
||||||
++ from-cord
|
++ from-cord
|
||||||
|
~/ %from-cord
|
||||||
|= h=@t
|
|= h=@t
|
||||||
^- hexb
|
^- hexb
|
||||||
?: =('' h) 1^0x0
|
?: =('' h) 1^0x0
|
||||||
@ -113,10 +120,11 @@
|
|||||||
=+ (rsh [3 2] -)
|
=+ (rsh [3 2] -)
|
||||||
:: Parse hex to atom
|
:: Parse hex to atom
|
||||||
::
|
::
|
||||||
:- (div (lent (trip h)) 2)
|
=/ a (need (de:base16:mimes:html -))
|
||||||
`@ux`(rash - hex)
|
[-.a `@ux`+.a]
|
||||||
::
|
::
|
||||||
++ to-cord
|
++ to-cord
|
||||||
|
~/ %to-cord
|
||||||
|= =hexb
|
|= =hexb
|
||||||
^- cord
|
^- cord
|
||||||
(en:base16:mimes:html hexb)
|
(en:base16:mimes:html hexb)
|
||||||
@ -128,8 +136,10 @@
|
|||||||
:: - decode: little endian to big endian
|
:: - decode: little endian to big endian
|
||||||
::
|
::
|
||||||
++ csiz
|
++ csiz
|
||||||
|
~% %csiz ..blop ~
|
||||||
|%
|
|%
|
||||||
++ en
|
++ en
|
||||||
|
~/ %en
|
||||||
|= a=@
|
|= a=@
|
||||||
^- hexb
|
^- hexb
|
||||||
=/ l=@ (met 3 a)
|
=/ l=@ (met 3 a)
|
||||||
@ -140,6 +150,7 @@
|
|||||||
~|("Cannot encode CompactSize longer than 8 bytes" !!)
|
~|("Cannot encode CompactSize longer than 8 bytes" !!)
|
||||||
::
|
::
|
||||||
++ de
|
++ de
|
||||||
|
~/ %de
|
||||||
|= h=hexb
|
|= h=hexb
|
||||||
^- [n=hexb rest=hexb]
|
^- [n=hexb rest=hexb]
|
||||||
=/ s=@ux dat:(take:byt 1 h)
|
=/ s=@ux dat:(take:byt 1 h)
|
||||||
@ -162,5 +173,4 @@
|
|||||||
=> (de h)
|
=> (de h)
|
||||||
[dat.n rest]
|
[dat.n rest]
|
||||||
--
|
--
|
||||||
::
|
|
||||||
--
|
--
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
:: top-level Bitcoin constants
|
:: top-level Bitcoin constants
|
||||||
:: expose BIP libraries
|
:: expose BIP libraries
|
||||||
::
|
::
|
||||||
/- sur=bitcoin
|
/- *bitcoin
|
||||||
/+ bech32=bip-b173, pbt=bip-b174, bcu=bitcoin-utils, bip-b158
|
/+ bech32=bip-b173, pbt=bip-b174, bcu=bitcoin-utils, bip-b158
|
||||||
=, sur
|
~% %bitcoin-lib ..part ~
|
||||||
=, bcu
|
|
||||||
|%
|
|%
|
||||||
++ overhead-weight ^-(vbytes 11)
|
++ overhead-weight ^-(vbytes 11)
|
||||||
++ input-weight
|
++ input-weight
|
||||||
|
~/ %input-weight
|
||||||
|= =bipt
|
|= =bipt
|
||||||
^- vbytes
|
^- vbytes
|
||||||
?- bipt
|
?- bipt
|
||||||
@ -40,8 +40,10 @@
|
|||||||
:: adr: address manipulation
|
:: adr: address manipulation
|
||||||
::
|
::
|
||||||
++ adr
|
++ adr
|
||||||
|
~% %adr ..overhead-weight ~
|
||||||
|%
|
|%
|
||||||
++ get-bipt
|
++ get-bipt
|
||||||
|
~/ %get-bipt
|
||||||
|= a=address
|
|= a=address
|
||||||
^- bipt
|
^- bipt
|
||||||
=/ spk=hexb (to-script-pubkey:adr a)
|
=/ spk=hexb (to-script-pubkey:adr a)
|
||||||
@ -52,35 +54,39 @@
|
|||||||
~|("Invalid address" !!)
|
~|("Invalid address" !!)
|
||||||
::
|
::
|
||||||
++ to-cord
|
++ to-cord
|
||||||
|
~/ %to-cord
|
||||||
|= a=address ^- cord
|
|= a=address ^- cord
|
||||||
?: ?=([%base58 *] a)
|
?: ?=([%base58 *] a)
|
||||||
(scot %uc +.a)
|
%- crip
|
||||||
|
%+ slag 2
|
||||||
|
(scow %uc +.a)
|
||||||
+.a
|
+.a
|
||||||
::
|
::
|
||||||
++ from-pubkey
|
++ from-pubkey
|
||||||
|
~/ %from-pubkey
|
||||||
|= [=bipt =network pubkey=hexb]
|
|= [=bipt =network pubkey=hexb]
|
||||||
^- address
|
^- address
|
||||||
?- bipt
|
?- bipt
|
||||||
%44
|
%44
|
||||||
:- %base58
|
:- %base58
|
||||||
=< ^-(@uc dat)
|
=< ^-(@uc dat)
|
||||||
%- cat:byt
|
%- cat:byt:bcu
|
||||||
:- ?- network
|
:- ?- network
|
||||||
%main 1^0x0
|
%main 1^0x0
|
||||||
%testnet 1^0x6f
|
%testnet 1^0x6f
|
||||||
==
|
==
|
||||||
~[(hash-160 pubkey)]
|
~[(hash-160:bcu pubkey)]
|
||||||
::
|
::
|
||||||
%49
|
%49
|
||||||
:- %base58
|
:- %base58
|
||||||
=< ^-(@uc dat)
|
=< ^-(@uc dat)
|
||||||
%- cat:byt
|
%- cat:byt:bcu
|
||||||
:~ ?- network
|
:~ ?- network
|
||||||
%main 1^0x5
|
%main 1^0x5
|
||||||
%testnet 1^0xc4
|
%testnet 1^0xc4
|
||||||
==
|
==
|
||||||
%- hash-160
|
%- hash-160:bcu
|
||||||
(cat:byt ~[2^0x14 (hash-160 pubkey)])
|
(cat:byt:bcu ~[2^0x14 (hash-160:bcu pubkey)])
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
%84
|
%84
|
||||||
@ -89,6 +95,7 @@
|
|||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ from-cord
|
++ from-cord
|
||||||
|
~/ %from-cord
|
||||||
|= addrc=@t
|
|= addrc=@t
|
||||||
|^
|
|^
|
||||||
=/ addrt=tape (trip addrc)
|
=/ addrt=tape (trip addrc)
|
||||||
@ -117,12 +124,13 @@
|
|||||||
--
|
--
|
||||||
::
|
::
|
||||||
++ to-script-pubkey
|
++ to-script-pubkey
|
||||||
|
~/ %to-script-pubkey
|
||||||
|= =address
|
|= =address
|
||||||
^- hexb
|
^- hexb
|
||||||
?- -.address
|
?- -.address
|
||||||
%bech32
|
%bech32
|
||||||
=+ h=(from-address:bech32 +.address)
|
=+ h=(from-address:bech32 +.address)
|
||||||
%- cat:byt
|
%- cat:byt:bcu
|
||||||
:~ 1^0x0
|
:~ 1^0x0
|
||||||
1^wid.h
|
1^wid.h
|
||||||
h
|
h
|
||||||
@ -130,21 +138,21 @@
|
|||||||
::
|
::
|
||||||
%base58
|
%base58
|
||||||
=/ h=hexb [21 `@ux`+.address]
|
=/ h=hexb [21 `@ux`+.address]
|
||||||
=+ lead-byt=dat:(take:byt 1 h)
|
=+ lead-byt=dat:(take:byt:bcu 1 h)
|
||||||
=/ version-network=[bipt network]
|
=/ version-network=[bipt network]
|
||||||
?: =(0x0 lead-byt) [%44 %main]
|
?: =(0x0 lead-byt) [%44 %main]
|
||||||
?: =(0x6f lead-byt) [%44 %testnet]
|
?: =(0x6f lead-byt) [%44 %testnet]
|
||||||
?: =(0x5 lead-byt) [%49 %main]
|
?: =(0x5 lead-byt) [%49 %main]
|
||||||
?: =(0xc4 lead-byt) [%49 %testnet]
|
?: =(0xc4 lead-byt) [%49 %testnet]
|
||||||
~|("Invalid base58 address: {<+.address>}" !!)
|
~|("Invalid base58 address: {<+.address>}" !!)
|
||||||
%- cat:byt
|
%- cat:byt:bcu
|
||||||
?: ?=(%44 -.version-network)
|
?: ?=(%44 -.version-network)
|
||||||
:~ 3^0x76.a914
|
:~ 3^0x76.a914
|
||||||
(drop:byt 1 h)
|
(drop:byt:bcu 1 h)
|
||||||
2^0x88ac
|
2^0x88ac
|
||||||
==
|
==
|
||||||
:~ 2^0xa914
|
:~ 2^0xa914
|
||||||
(drop:byt 1 h)
|
(drop:byt:bcu 1 h)
|
||||||
1^0x87
|
1^0x87
|
||||||
==
|
==
|
||||||
==
|
==
|
||||||
@ -155,6 +163,8 @@
|
|||||||
:: - ignores signatures in inputs
|
:: - ignores signatures in inputs
|
||||||
::
|
::
|
||||||
++ txu
|
++ txu
|
||||||
|
~% %bitcoin-lib-txu ..overhead-weight ~
|
||||||
|
=, bcu
|
||||||
|%
|
|%
|
||||||
++ en
|
++ en
|
||||||
|%
|
|%
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
/- bp=btc-provider, json-rpc
|
/- bp=btc-provider, json-rpc
|
||||||
/+ bc=bitcoin
|
/+ bc=bitcoin, bcu=bitcoin-utils
|
||||||
^?
|
~% %btc-provider-lib ..part ~
|
||||||
::=< [sur .]
|
|
||||||
::=, sur
|
|
||||||
|%
|
|%
|
||||||
:: +from-epoch: time since Jan 1, 1970 in seconds.
|
:: +from-epoch: time since Jan 1, 1970 in seconds.
|
||||||
::
|
::
|
||||||
@ -25,8 +23,8 @@
|
|||||||
~[['Content-Type' 'application/json']]
|
~[['Content-Type' 'application/json']]
|
||||||
=, html
|
=, html
|
||||||
%- some
|
%- some
|
||||||
%- as-octt:mimes
|
%- as-octt:mimes
|
||||||
(en-json body)
|
(en-json body)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ gen-request
|
++ gen-request
|
||||||
@ -36,6 +34,7 @@
|
|||||||
api-url.host-info ract
|
api-url.host-info ract
|
||||||
::
|
::
|
||||||
++ rpc
|
++ rpc
|
||||||
|
~/ %rpc
|
||||||
=, dejs:format
|
=, dejs:format
|
||||||
|%
|
|%
|
||||||
++ parse-result
|
++ parse-result
|
||||||
@ -62,6 +61,7 @@
|
|||||||
%get-block-info
|
%get-block-info
|
||||||
[id.res (block-info res.res)]
|
[id.res (block-info res.res)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ address-info
|
++ address-info
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%address (cu from-cord:adr:bc so)]
|
:~ [%address (cu from-cord:adr:bc so)]
|
||||||
@ -69,47 +69,53 @@
|
|||||||
[%used bo]
|
[%used bo]
|
||||||
[%block ni]
|
[%block ni]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ utxo
|
++ utxo
|
||||||
%- ot
|
%- ot
|
||||||
:~ ['tx_pos' ni]
|
:~ ['tx_pos' ni]
|
||||||
['tx_hash' (cu from-cord:hxb:bc so)]
|
['tx_hash' (cu from-cord:hxb:bcu so)]
|
||||||
[%height ni]
|
[%height ni]
|
||||||
[%value ni]
|
[%value ni]
|
||||||
[%recvd (cu from-epoch ni)]
|
[%recvd (cu from-epoch ni)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ tx-vals
|
++ tx-vals
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%included bo]
|
:~ [%included bo]
|
||||||
[%txid (cu from-cord:hxb:bc so)]
|
[%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%confs ni]
|
[%confs ni]
|
||||||
[%recvd (cu from-epoch ni)]
|
[%recvd (cu from-epoch ni)]
|
||||||
[%inputs (ar tx-val)]
|
[%inputs (ar tx-val)]
|
||||||
[%outputs (ar tx-val)]
|
[%outputs (ar tx-val)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ tx-val
|
++ tx-val
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%pos ni]
|
[%pos ni]
|
||||||
[%address (cu from-cord:adr:bc so)]
|
[%address (cu from-cord:adr:bc so)]
|
||||||
[%value ni]
|
[%value ni]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ raw-tx
|
++ raw-tx
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%rawtx (cu from-cord:hxb:bc so)]
|
[%rawtx (cu from-cord:hxb:bcu so)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ broadcast-tx
|
++ broadcast-tx
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%broadcast bo]
|
[%broadcast bo]
|
||||||
[%included bo]
|
[%included bo]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ block-info
|
++ block-info
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%block ni]
|
:~ [%block ni]
|
||||||
[%fee (mu ni)]
|
[%fee (mu ni)]
|
||||||
[%blockhash (cu from-cord:hxb:bc so)]
|
[%blockhash (cu from-cord:hxb:bcu so)]
|
||||||
[%blockfilter (cu from-cord:hxb:bc so)]
|
[%blockfilter (cu from-cord:hxb:bcu so)]
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
@ -126,17 +132,17 @@
|
|||||||
%get-tx-vals
|
%get-tx-vals
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/gettxvals/'
|
%+ mk-url '/gettxvals/'
|
||||||
(to-cord:hxb:bc txid.ract)
|
(to-cord:hxb:bcu txid.ract)
|
||||||
::
|
::
|
||||||
%get-raw-tx
|
%get-raw-tx
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/getrawtx/'
|
%+ mk-url '/getrawtx/'
|
||||||
(to-cord:hxb:bc txid.ract)
|
(to-cord:hxb:bcu txid.ract)
|
||||||
::
|
::
|
||||||
%broadcast-tx
|
%broadcast-tx
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/broadcasttx/'
|
%+ mk-url '/broadcasttx/'
|
||||||
(to-cord:hxb:bc rawtx.ract)
|
(to-cord:hxb:bcu rawtx.ract)
|
||||||
::
|
::
|
||||||
%get-block-count
|
%get-block-count
|
||||||
%- get-request
|
%- get-request
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
:: lib/btc.hoon
|
:: lib/btc.hoon
|
||||||
::
|
::
|
||||||
/- *btc-wallet, json-rpc, bp=btc-provider
|
/- *btc-wallet, json-rpc, bp=btc-provider
|
||||||
/+ bip32, bc=bitcoin
|
/+ bip32, bc=bitcoin, bcu=bitcoin-utils
|
||||||
=, secp:crypto
|
=, secp:crypto
|
||||||
=+ ecc=secp256k1
|
=+ ecc=secp256k1
|
||||||
|%
|
|%
|
||||||
@ -424,6 +424,7 @@
|
|||||||
%get-block-info
|
%get-block-info
|
||||||
[id.res (block-info res.res)]
|
[id.res (block-info res.res)]
|
||||||
==
|
==
|
||||||
|
::
|
||||||
++ address-info
|
++ address-info
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%address (cu from-cord:adr:bc so)]
|
:~ [%address (cu from-cord:adr:bc so)]
|
||||||
@ -434,7 +435,7 @@
|
|||||||
++ utxo
|
++ utxo
|
||||||
%- ot
|
%- ot
|
||||||
:~ ['tx_pos' ni]
|
:~ ['tx_pos' ni]
|
||||||
['tx_hash' (cu from-cord:hxb:bc so)]
|
['tx_hash' (cu from-cord:hxb:bcu so)]
|
||||||
[%height ni]
|
[%height ni]
|
||||||
[%value ni]
|
[%value ni]
|
||||||
[%recvd (cu from-epoch ni)]
|
[%recvd (cu from-epoch ni)]
|
||||||
@ -442,7 +443,7 @@
|
|||||||
++ tx-vals
|
++ tx-vals
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%included bo]
|
:~ [%included bo]
|
||||||
[%txid (cu from-cord:hxb:bc so)]
|
[%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%confs ni]
|
[%confs ni]
|
||||||
[%recvd (cu from-epoch ni)]
|
[%recvd (cu from-epoch ni)]
|
||||||
[%inputs (ar tx-val)]
|
[%inputs (ar tx-val)]
|
||||||
@ -450,19 +451,19 @@
|
|||||||
==
|
==
|
||||||
++ tx-val
|
++ tx-val
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%pos ni]
|
[%pos ni]
|
||||||
[%address (cu from-cord:adr:bc so)]
|
[%address (cu from-cord:adr:bc so)]
|
||||||
[%value ni]
|
[%value ni]
|
||||||
==
|
==
|
||||||
++ raw-tx
|
++ raw-tx
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%rawtx (cu from-cord:hxb:bc so)]
|
[%rawtx (cu from-cord:hxb:bcu so)]
|
||||||
==
|
==
|
||||||
++ broadcast-tx
|
++ broadcast-tx
|
||||||
%- ot
|
%- ot
|
||||||
:~ [%txid (cu from-cord:hxb:bc so)]
|
:~ [%txid (cu from-cord:hxb:bcu so)]
|
||||||
[%broadcast bo]
|
[%broadcast bo]
|
||||||
[%included bo]
|
[%included bo]
|
||||||
==
|
==
|
||||||
@ -470,8 +471,8 @@
|
|||||||
%- ot
|
%- ot
|
||||||
:~ [%block ni]
|
:~ [%block ni]
|
||||||
[%fee (mu ni)]
|
[%fee (mu ni)]
|
||||||
[%blockhash (cu from-cord:hxb:bc so)]
|
[%blockhash (cu from-cord:hxb:bcu so)]
|
||||||
[%blockfilter (cu from-cord:hxb:bc so)]
|
[%blockfilter (cu from-cord:hxb:bcu so)]
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
@ -488,17 +489,17 @@
|
|||||||
%get-tx-vals
|
%get-tx-vals
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/gettxvals/'
|
%+ mk-url '/gettxvals/'
|
||||||
(to-cord:hxb:bc txid.ract)
|
(to-cord:hxb:bcu txid.ract)
|
||||||
::
|
::
|
||||||
%get-raw-tx
|
%get-raw-tx
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/getrawtx/'
|
%+ mk-url '/getrawtx/'
|
||||||
(to-cord:hxb:bc txid.ract)
|
(to-cord:hxb:bcu txid.ract)
|
||||||
::
|
::
|
||||||
%broadcast-tx
|
%broadcast-tx
|
||||||
%- get-request
|
%- get-request
|
||||||
%+ mk-url '/broadcasttx/'
|
%+ mk-url '/broadcasttx/'
|
||||||
(to-cord:hxb:bc rawtx.ract)
|
(to-cord:hxb:bcu rawtx.ract)
|
||||||
::
|
::
|
||||||
%get-block-count
|
%get-block-count
|
||||||
%- get-request
|
%- get-request
|
||||||
|
2
pkg/arvo/mar/graph/cache/hook.hoon
vendored
2
pkg/arvo/mar/graph/cache/hook.hoon
vendored
@ -2,8 +2,6 @@
|
|||||||
|%
|
|%
|
||||||
+$ cache-action
|
+$ cache-action
|
||||||
$% [%graph-to-mark (pair resource:res (unit mark))]
|
$% [%graph-to-mark (pair resource:res (unit mark))]
|
||||||
[%perm-marks (pair (pair mark @tas) tube:clay)]
|
|
||||||
[%transform-marks (pair mark tube:clay)]
|
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
|
12
pkg/arvo/mar/transform-add-nodes.hoon
Normal file
12
pkg/arvo/mar/transform-add-nodes.hoon
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/- *post
|
||||||
|
|_ i=indexed-post
|
||||||
|
++ grad %noun
|
||||||
|
++ grow
|
||||||
|
|%
|
||||||
|
++ noun i
|
||||||
|
--
|
||||||
|
++ grab
|
||||||
|
|%
|
||||||
|
++ noun indexed-post
|
||||||
|
--
|
||||||
|
--
|
@ -24,6 +24,7 @@
|
|||||||
$% [%set-credentials api-url=@t =network]
|
$% [%set-credentials api-url=@t =network]
|
||||||
[%add-whitelist wt=whitelist-target]
|
[%add-whitelist wt=whitelist-target]
|
||||||
[%remove-whitelist wt=whitelist-target]
|
[%remove-whitelist wt=whitelist-target]
|
||||||
|
[%set-interval inte=@dr]
|
||||||
==
|
==
|
||||||
+$ action
|
+$ action
|
||||||
$% [%address-info =address]
|
$% [%address-info =address]
|
||||||
|
@ -162,6 +162,10 @@
|
|||||||
[%new-address =address]
|
[%new-address =address]
|
||||||
[%balance balance=(unit [confirmed=sats unconfirmed=sats])]
|
[%balance balance=(unit [confirmed=sats unconfirmed=sats])]
|
||||||
[%error =error]
|
[%error =error]
|
||||||
|
:: current index being scanned in each wallet part
|
||||||
|
:: ~ if scan of that part is done
|
||||||
|
::
|
||||||
|
[%scan-progress main=(unit idx) change=(unit idx)]
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
--
|
--
|
||||||
|
@ -10,5 +10,7 @@
|
|||||||
::
|
::
|
||||||
[%warm-cache-all ~]
|
[%warm-cache-all ~]
|
||||||
[%cool-cache-all ~]
|
[%cool-cache-all ~]
|
||||||
|
[%warm-static-conversion from=term to=term]
|
||||||
|
[%cool-static-conversion from=term to=term]
|
||||||
==
|
==
|
||||||
--
|
--
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
:: Note: these are for BTC testnet
|
:: Note: these are for BTC testnet
|
||||||
::
|
::
|
||||||
/- spider, rpc=json-rpc
|
/- spider, rpc=json-rpc
|
||||||
/+ strandio, bc=bitcoin
|
/+ strandio, bc=bitcoin, bcu=bitcoin-utils
|
||||||
=, strand=strand:spider
|
=, strand=strand:spider
|
||||||
=>
|
=>
|
||||||
|%
|
|%
|
||||||
@ -47,8 +47,8 @@
|
|||||||
++ electrs-script-hash
|
++ electrs-script-hash
|
||||||
|= a=address:bc
|
|= a=address:bc
|
||||||
^- hexb:bc
|
^- hexb:bc
|
||||||
%- flip:byt:bc
|
%- flip:byt:bcu
|
||||||
%- sha256:bc
|
%- sha256:bcu
|
||||||
(to-script-pubkey:adr:bc a)
|
(to-script-pubkey:adr:bc a)
|
||||||
::
|
::
|
||||||
++ parse-json-rpc
|
++ parse-json-rpc
|
||||||
|
@ -4,42 +4,34 @@
|
|||||||
|%
|
|%
|
||||||
++ strand strand:spider
|
++ strand strand:spider
|
||||||
++ poke poke:strandio
|
++ poke poke:strandio
|
||||||
++ poke-our poke-our:strandio
|
++ raw-poke-our raw-poke-our:strandio
|
||||||
::
|
::
|
||||||
++ scry-metadata
|
++ scry-metadata
|
||||||
|= rid=resource
|
|= rid=resource
|
||||||
=/ m (strand ,resource)
|
%+ scry:strandio ,(unit resource)
|
||||||
^- form:m
|
;: weld
|
||||||
;< group=(unit resource) bind:m
|
/gx/metadata-store/resource/graph
|
||||||
%+ scry:strandio ,(unit resource)
|
(en-path:resource rid)
|
||||||
;: weld
|
/noun
|
||||||
/gx/metadata-store/resource/graph
|
==
|
||||||
(en-path:resource rid)
|
|
||||||
/noun
|
|
||||||
==
|
|
||||||
(pure:m (need group))
|
|
||||||
::
|
::
|
||||||
++ scry-group
|
++ scry-group
|
||||||
|= rid=resource
|
|= rid=resource
|
||||||
=/ m (strand ,group)
|
%+ scry:strandio ,(unit group)
|
||||||
^- form:m
|
;: weld
|
||||||
;< ugroup=(unit group) bind:m
|
/gx/group-store/groups
|
||||||
%+ scry:strandio ,(unit group)
|
(en-path:resource rid)
|
||||||
;: weld
|
/noun
|
||||||
/gx/group-store/groups
|
==
|
||||||
(en-path:resource rid)
|
|
||||||
/noun
|
|
||||||
==
|
|
||||||
(pure:m (need ugroup))
|
|
||||||
::
|
::
|
||||||
++ delete-graph
|
++ delete-graph
|
||||||
|= [now=time rid=resource]
|
|= [now=time rid=resource]
|
||||||
=/ m (strand ,~)
|
=/ m (strand ,~)
|
||||||
^- form:m
|
^- form:m
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
(poke-our %graph-pull-hook %pull-hook-action !>([%remove rid]))
|
(raw-poke-our %graph-pull-hook %pull-hook-action !>([%remove rid]))
|
||||||
;< ~ bind:m
|
;< ~ bind:m
|
||||||
(poke-our %graph-store %graph-update-2 !>([now [%remove-graph rid]]))
|
(raw-poke-our %graph-store %graph-update-2 !>([now [%remove-graph rid]]))
|
||||||
(pure:m ~)
|
(pure:m ~)
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
@ -52,10 +44,12 @@
|
|||||||
;< =bowl:spider bind:m get-bowl:strandio
|
;< =bowl:spider bind:m get-bowl:strandio
|
||||||
?: =(our.bowl entity.rid.action)
|
?: =(our.bowl entity.rid.action)
|
||||||
(strand-fail:strandio %bad-request ~)
|
(strand-fail:strandio %bad-request ~)
|
||||||
;< group-rid=resource bind:m (scry-metadata rid.action)
|
;< group-rid=(unit resource) bind:m (scry-metadata rid.action)
|
||||||
;< g=group bind:m (scry-group group-rid)
|
?~ group-rid (pure:m !>(~))
|
||||||
|
;< g=(unit group) bind:m (scry-group u.group-rid)
|
||||||
|
?~ g (pure:m !>(~))
|
||||||
;< ~ bind:m (delete-graph now.bowl rid.action)
|
;< ~ bind:m (delete-graph now.bowl rid.action)
|
||||||
?. hidden.g
|
?. hidden.u.g
|
||||||
(pure:m !>(~))
|
(pure:m !>(~))
|
||||||
;< =thread-result:strandio bind:m
|
;< =thread-result:strandio bind:m
|
||||||
(await-thread:strandio %group-leave !>([~ [%leave rid.action]]))
|
(await-thread:strandio %group-leave !>([~ [%leave rid.action]]))
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
date-created now.bowl
|
date-created now.bowl
|
||||||
creator our.bowl
|
creator our.bowl
|
||||||
config [%group ~]
|
config [%group ~]
|
||||||
|
hidden %.n
|
||||||
==
|
==
|
||||||
=/ met-action=action:metadata
|
=/ met-action=action:metadata
|
||||||
[%add rid groups+rid metadatum]
|
[%add rid groups+rid metadatum]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/+ *test, *bitcoin, bip32
|
/+ *test, *bitcoin, *bitcoin-utils, bip32
|
||||||
=, secp:crypto
|
=, secp:crypto
|
||||||
=+ ecc=secp256k1
|
=+ ecc=secp256k1
|
||||||
|%
|
|%
|
||||||
|
27
pkg/btc-wallet/.eslintrc.json
Normal file
27
pkg/btc-wallet/.eslintrc.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"extends": ["eslint:recommended", "plugin:react/recommended", "prettier"],
|
||||||
|
"globals": {
|
||||||
|
"Atomics": "readonly",
|
||||||
|
"SharedArrayBuffer": "readonly"
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"ecmaVersion": 11,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["react"],
|
||||||
|
"rules": {
|
||||||
|
"react/prop-types": 0
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"react": {
|
||||||
|
"version": "detect"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
pkg/btc-wallet/.gitignore
vendored
Normal file
1
pkg/btc-wallet/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.eslintcache
|
1
pkg/btc-wallet/.husky/.gitignore
vendored
Normal file
1
pkg/btc-wallet/.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_
|
@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
cd pkg/interface && npx lint-staged
|
cd pkg/btc-wallet && npx lint-staged src
|
4
pkg/btc-wallet/.prettierrc
Normal file
4
pkg/btc-wallet/.prettierrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
@ -5,4 +5,4 @@ dojo:
|
|||||||
|
|
||||||
it should return with the following hash:
|
it should return with the following hash:
|
||||||
|
|
||||||
`0v1.9p61c.bd4vn.deevh.0ldbq.fkqo3`
|
`0v7.v4dng.o33qi.kc497.5jc02.ke5es`
|
||||||
|
1849
pkg/btc-wallet/package-lock.json
generated
1849
pkg/btc-wallet/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "urbit-bitcoin-wallet",
|
"name": "btc-wallet",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"main": "node install.js",
|
"main": "node install.js",
|
||||||
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --config config/webpack.dev.js",
|
"start": "webpack-dev-server --config config/webpack.dev.js",
|
||||||
"build:dev": "cross-env NODE_ENV=production webpack --config config/webpack.dev.js",
|
"build:dev": "cross-env NODE_ENV=production webpack --config config/webpack.dev.js",
|
||||||
@ -24,8 +25,14 @@
|
|||||||
"babel-plugin-root-import": "^6.5.0",
|
"babel-plugin-root-import": "^6.5.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
|
"eslint": "^7.29.0",
|
||||||
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
"eslint-plugin-react": "^7.24.0",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
"html-webpack-plugin": "^4.2.0",
|
"html-webpack-plugin": "^4.2.0",
|
||||||
|
"husky": "^6.0.0",
|
||||||
|
"lint-staged": "^11.0.0",
|
||||||
|
"prettier": "^2.3.1",
|
||||||
"react-hot-loader": "^4.12.21",
|
"react-hot-loader": "^4.12.21",
|
||||||
"sass": "^1.26.5",
|
"sass": "^1.26.5",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
@ -71,5 +78,9 @@
|
|||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"natives": "1.1.3"
|
"natives": "1.1.3"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.js": "eslint --cache --fix",
|
||||||
|
"*.{js,css,md}": "prettier --write"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ import './css/custom.css';
|
|||||||
|
|
||||||
// rebuild x3
|
// rebuild x3
|
||||||
|
|
||||||
window.NETWORK = 'testnet'; // 'bitcoin'
|
|
||||||
|
|
||||||
const channel = new window.channel();
|
const channel = new window.channel();
|
||||||
api.setChannel(window.ship, channel);
|
api.setChannel(window.ship, channel);
|
||||||
|
|
||||||
|
@ -7,10 +7,13 @@ class UrbitApi {
|
|||||||
this.bindPaths = [];
|
this.bindPaths = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(path, method, ship = this.ship, appl = "btc-wallet", success, fail) {
|
bind(path, method, ship = this.ship, appl = 'btc-wallet', success, fail) {
|
||||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
||||||
|
|
||||||
window.subscriptionId = this.channel.subscribe(ship, appl, path,
|
window.subscriptionId = this.channel.subscribe(
|
||||||
|
ship,
|
||||||
|
appl,
|
||||||
|
path,
|
||||||
(err) => {
|
(err) => {
|
||||||
fail(err);
|
fail(err);
|
||||||
},
|
},
|
||||||
@ -19,32 +22,38 @@ class UrbitApi {
|
|||||||
data: event,
|
data: event,
|
||||||
from: {
|
from: {
|
||||||
ship,
|
ship,
|
||||||
path
|
path,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
fail(err);
|
fail(err);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
btcWalletCommand(data) {
|
btcWalletCommand(data) {
|
||||||
return this.action("btc-wallet", "btc-wallet-command", data);
|
return this.action('btc-wallet', 'btc-wallet-command', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsEvent(data) {
|
settingsEvent(data) {
|
||||||
return this.action("settings-store", "settings-event", data);
|
return this.action('settings-store', 'settings-event', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
action(appl, mark, data) {
|
action(appl, mark, data) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.channel.poke(ship, appl, mark, data,
|
this.channel.poke(
|
||||||
|
this.ship,
|
||||||
|
appl,
|
||||||
|
mark,
|
||||||
|
data,
|
||||||
(json) => {
|
(json) => {
|
||||||
resolve(json);
|
resolve(json);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import {
|
import { Row, Text, Button, Col } from '@tlon/indigo-react';
|
||||||
Box,
|
import Send from './send.js';
|
||||||
Icon,
|
import CurrencyPicker from './currencyPicker.js';
|
||||||
Row,
|
import { satsToCurrency } from '../../lib/util.js';
|
||||||
Text,
|
import { store } from '../../store.js';
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
} from '@tlon/indigo-react';
|
|
||||||
|
|
||||||
import Send from './send.js'
|
|
||||||
import CurrencyPicker from './currencyPicker.js'
|
|
||||||
import { currencyToSats, satsToCurrency } from '../../lib/util.js';
|
|
||||||
|
|
||||||
|
|
||||||
export default class Balance extends Component {
|
export default class Balance extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -21,7 +13,7 @@ export default class Balance extends Component {
|
|||||||
sending: false,
|
sending: false,
|
||||||
copiedButton: false,
|
copiedButton: false,
|
||||||
copiedString: false,
|
copiedString: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.copyAddress = this.copyAddress.bind(this);
|
this.copyAddress = this.copyAddress.bind(this);
|
||||||
}
|
}
|
||||||
@ -29,110 +21,149 @@ export default class Balance extends Component {
|
|||||||
copyAddress(arg) {
|
copyAddress(arg) {
|
||||||
let address = this.props.state.address;
|
let address = this.props.state.address;
|
||||||
navigator.clipboard.writeText(address);
|
navigator.clipboard.writeText(address);
|
||||||
this.props.api.btcWalletCommand({'gen-new-address': null});
|
this.props.api.btcWalletCommand({ 'gen-new-address': null });
|
||||||
|
|
||||||
if (arg === 'button'){
|
if (arg === 'button') {
|
||||||
this.setState({copiedButton: true});
|
this.setState({ copiedButton: true });
|
||||||
setTimeout(() => { this.setState({copiedButton: false}); }, 2000);
|
setTimeout(() => {
|
||||||
|
this.setState({ copiedButton: false });
|
||||||
|
}, 2000);
|
||||||
} else if (arg === 'string') {
|
} else if (arg === 'string') {
|
||||||
this.setState({copiedString: true});
|
this.setState({ copiedString: true });
|
||||||
setTimeout(() => { this.setState({copiedString: false}); }, 2000);
|
setTimeout(() => {
|
||||||
|
this.setState({ copiedString: false });
|
||||||
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const sats = (this.props.state.confirmedBalance || 0);
|
const sats = this.props.state.confirmedBalance || 0;
|
||||||
const unconfirmedSats = this.props.state.unconfirmedBalance;
|
const unconfirmedSats = this.props.state.unconfirmedBalance;
|
||||||
|
|
||||||
const unconfirmedString = unconfirmedSats ? ` (${unconfirmedSats}) ` : '';
|
const unconfirmedString = unconfirmedSats ? ` (${unconfirmedSats}) ` : '';
|
||||||
|
|
||||||
const denomination = this.props.state.denomination;
|
const denomination = this.props.state.denomination;
|
||||||
const value = satsToCurrency(sats, denomination, this.props.state.currencyRates);
|
const value = satsToCurrency(
|
||||||
const sendDisabled = (sats === 0);
|
sats,
|
||||||
const addressText = (this.props.state.address === null) ? '' :
|
denomination,
|
||||||
this.props.state.address.slice(0, 6) + '...' +
|
this.props.state.currencyRates
|
||||||
this.props.state.address.slice(-6);
|
);
|
||||||
|
const sendDisabled = sats === 0;
|
||||||
|
const addressText =
|
||||||
|
this.props.state.address === null
|
||||||
|
? ''
|
||||||
|
: this.props.state.address.slice(0, 6) +
|
||||||
|
'...' +
|
||||||
|
this.props.state.address.slice(-6);
|
||||||
|
|
||||||
const conversion = this.props.state.currencyRates[denomination].last;
|
const conversion = this.props.state.currencyRates[denomination].last;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{this.state.sending ?
|
{this.state.sending ? (
|
||||||
<Send
|
<Send
|
||||||
state={this.props.state}
|
state={this.props.state}
|
||||||
api={api}
|
api={this.props.api}
|
||||||
psbt={this.props.state.psbt}
|
psbt={this.props.state.psbt}
|
||||||
fee={this.props.state.fee}
|
fee={this.props.state.fee}
|
||||||
currencyRates={this.props.state.currencyRates}
|
currencyRates={this.props.state.currencyRates}
|
||||||
shipWallets={this.props.state.shipWallets}
|
shipWallets={this.props.state.shipWallets}
|
||||||
value={value}
|
value={value}
|
||||||
denomination={denomination}
|
denomination={denomination}
|
||||||
sats={sats}
|
sats={sats}
|
||||||
conversion={conversion}
|
conversion={conversion}
|
||||||
network={this.props.network}
|
network={this.props.network}
|
||||||
error={this.props.state.error}
|
error={this.props.state.error}
|
||||||
stopSending={() => {
|
stopSending={() => {
|
||||||
this.setState({sending: false});
|
this.setState({ sending: false });
|
||||||
store.handleEvent({data: {psbt: '', fee: 0, error: '', "broadcast-fail": null}});
|
store.handleEvent({
|
||||||
}}
|
data: { psbt: '', fee: 0, error: '', 'broadcast-fail': null },
|
||||||
/> :
|
});
|
||||||
<Col
|
}}
|
||||||
height="400px"
|
/>
|
||||||
width='100%'
|
) : (
|
||||||
backgroundColor="white"
|
<Col
|
||||||
borderRadius="48px"
|
height="400px"
|
||||||
justifyContent="space-between"
|
width="100%"
|
||||||
mb={5}
|
backgroundColor="white"
|
||||||
p={5}
|
borderRadius="48px"
|
||||||
>
|
justifyContent="space-between"
|
||||||
<Row justifyContent="space-between">
|
mb={5}
|
||||||
<Text color="orange" fontSize={1}>Balance</Text>
|
p={5}
|
||||||
<Text color="lightGray" fontSize="14px" mono style={{cursor: "pointer"}}
|
>
|
||||||
onClick={() => {this.copyAddress('string')}}>
|
<Row justifyContent="space-between">
|
||||||
{this.state.copiedString ? "copied" : addressText}
|
<Text color="orange" fontSize={1}>
|
||||||
</Text>
|
Balance
|
||||||
<CurrencyPicker
|
</Text>
|
||||||
api={this.props.api}
|
<Text
|
||||||
denomination={denomination}
|
color="lightGray"
|
||||||
currencies={this.props.state.currencyRates}
|
fontSize="14px"
|
||||||
/>
|
mono
|
||||||
</Row>
|
style={{ cursor: 'pointer' }}
|
||||||
<Col justifyContent="center" alignItems="center">
|
onClick={() => {
|
||||||
<Text fontSize="40px" color="orange" style={{whiteSpace: "nowrap"}} >
|
this.copyAddress('string');
|
||||||
{value}
|
}}
|
||||||
</Text>
|
>
|
||||||
<Text fontSize={1} color="orange">{`${sats}${unconfirmedString} sats`}</Text>
|
{this.state.copiedString ? 'copied' : addressText}
|
||||||
</Col>
|
</Text>
|
||||||
<Row flexDirection="row-reverse">
|
<CurrencyPicker
|
||||||
<Button children="Send"
|
api={this.props.api}
|
||||||
disabled={sendDisabled}
|
denomination={denomination}
|
||||||
fontSize={1}
|
currencies={this.props.state.currencyRates}
|
||||||
fontWeight="bold"
|
/>
|
||||||
color={sendDisabled ? "lighterGray" : "white"}
|
</Row>
|
||||||
backgroundColor={sendDisabled ? "veryLightGray" : "orange"}
|
<Col justifyContent="center" alignItems="center">
|
||||||
style={{cursor: sendDisabled ? "default" : "pointer" }}
|
<Text
|
||||||
borderColor="none"
|
fontSize="40px"
|
||||||
borderRadius="24px"
|
color="orange"
|
||||||
height="48px"
|
style={{ whiteSpace: 'nowrap' }}
|
||||||
onClick={() => this.setState({sending: true})}
|
>
|
||||||
/>
|
{value}
|
||||||
<Button children={(this.state.copiedButton) ? "Address Copied!" : "Copy Address"}
|
</Text>
|
||||||
mr={3}
|
<Text
|
||||||
disabled={this.state.copiedButton}
|
fontSize={1}
|
||||||
fontSize={1}
|
color="orange"
|
||||||
fontWeight="bold"
|
>{`${sats}${unconfirmedString} sats`}</Text>
|
||||||
color={(this.state.copiedButton) ? "green" : "orange"}
|
</Col>
|
||||||
backgroundColor={(this.state.copiedButton) ? "veryLightGreen" : "midOrange" }
|
<Row flexDirection="row-reverse">
|
||||||
style={{cursor: (this.state.copiedButton) ? "default" : "pointer"}}
|
<Button
|
||||||
borderColor="none"
|
disabled={sendDisabled}
|
||||||
borderRadius="24px"
|
fontSize={1}
|
||||||
height="48px"
|
fontWeight="bold"
|
||||||
onClick={() => {this.copyAddress('button')}}
|
color={sendDisabled ? 'lighterGray' : 'white'}
|
||||||
/>
|
backgroundColor={sendDisabled ? 'veryLightGray' : 'orange'}
|
||||||
</Row>
|
style={{ cursor: sendDisabled ? 'default' : 'pointer' }}
|
||||||
|
borderColor="none"
|
||||||
|
borderRadius="24px"
|
||||||
|
height="48px"
|
||||||
|
onClick={() => this.setState({ sending: true })}
|
||||||
|
>
|
||||||
|
Send
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
mr={3}
|
||||||
|
disabled={this.state.copiedButton}
|
||||||
|
fontSize={1}
|
||||||
|
fontWeight="bold"
|
||||||
|
color={this.state.copiedButton ? 'green' : 'orange'}
|
||||||
|
backgroundColor={
|
||||||
|
this.state.copiedButton ? 'veryLightGreen' : 'midOrange'
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
cursor: this.state.copiedButton ? 'default' : 'pointer',
|
||||||
|
}}
|
||||||
|
borderColor="none"
|
||||||
|
borderRadius="24px"
|
||||||
|
height="48px"
|
||||||
|
onClick={() => {
|
||||||
|
this.copyAddress('button');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{this.state.copiedButton ? 'Address Copied!' : 'Copy Address'}
|
||||||
|
</Button>
|
||||||
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import {
|
|||||||
StatelessTextInput,
|
StatelessTextInput,
|
||||||
Icon,
|
Icon,
|
||||||
Row,
|
Row,
|
||||||
Input,
|
|
||||||
LoadingSpinner,
|
LoadingSpinner,
|
||||||
} from '@tlon/indigo-react';
|
} from '@tlon/indigo-react';
|
||||||
|
|
||||||
@ -23,9 +22,9 @@ export default class ProviderModal extends Component {
|
|||||||
ready: false,
|
ready: false,
|
||||||
provider: null,
|
provider: null,
|
||||||
connecting: false,
|
connecting: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.checkProvider = this.checkProvider.bind(this);
|
this.checkProvider = this.checkProvider.bind(this);
|
||||||
this.submitProvider = this.submitProvider.bind(this);
|
this.submitProvider = this.submitProvider.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,77 +37,88 @@ export default class ProviderModal extends Component {
|
|||||||
|
|
||||||
if (isValidPatp(provider)) {
|
if (isValidPatp(provider)) {
|
||||||
let command = {
|
let command = {
|
||||||
"check-provider": provider
|
'check-provider': provider,
|
||||||
}
|
};
|
||||||
potentialProvider = provider;
|
potentialProvider = provider;
|
||||||
checkingProvider = true;
|
checkingProvider = true;
|
||||||
this.props.api.btcWalletCommand(command);
|
this.props.api.btcWalletCommand(command);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.setState({providerFailed: true, checkingProvider: false});
|
this.setState({ providerFailed: true, checkingProvider: false });
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
this.setState({provider, ready, checkingProvider, potentialProvider});
|
this.setState({ provider, ready, checkingProvider, potentialProvider });
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState){
|
componentDidUpdate() {
|
||||||
if (!this.state.ready){
|
if (!this.state.ready) {
|
||||||
if (this.props.providerPerms[this.state.provider]) {
|
if (this.props.providerPerms[this.state.provider]) {
|
||||||
this.setState({ready: true, checkingProvider: false, providerFailed: false});
|
this.setState({
|
||||||
|
ready: true,
|
||||||
|
checkingProvider: false,
|
||||||
|
providerFailed: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
submitProvider(e){
|
submitProvider() {
|
||||||
if (this.state.ready){
|
if (this.state.ready) {
|
||||||
let command = {
|
let command = {
|
||||||
"set-provider": this.state.provider
|
'set-provider': this.state.provider,
|
||||||
}
|
};
|
||||||
this.props.api.btcWalletCommand(command);
|
this.props.api.btcWalletCommand(command);
|
||||||
this.setState({connecting: true});
|
this.setState({ connecting: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
let workingNode = null;
|
let workingNode = null;
|
||||||
let workingColor = null;
|
let workingColor = null;
|
||||||
let workingBg = null;
|
let workingBg = null;
|
||||||
if (this.state.ready) {
|
if (this.state.ready) {
|
||||||
workingColor = "green";
|
workingColor = 'green';
|
||||||
workingBg = "veryLightGreen"
|
workingBg = 'veryLightGreen';
|
||||||
workingNode =
|
workingNode = (
|
||||||
<Box mt={3}>
|
<Box mt={3}>
|
||||||
<Text fontSize="14px" color="green">
|
<Text fontSize="14px" color="green">
|
||||||
{this.state.provider} is a working provider node
|
{this.state.provider} is a working provider node
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
);
|
||||||
} else if (this.state.providerFailed) {
|
} else if (this.state.providerFailed) {
|
||||||
workingColor = "red";
|
workingColor = 'red';
|
||||||
workingBg = "veryLightRed"
|
workingBg = 'veryLightRed';
|
||||||
workingNode =
|
workingNode = (
|
||||||
<Box mt={3}>
|
<Box mt={3}>
|
||||||
<Text fontSize="14px" color="red">
|
<Text fontSize="14px" color="red">
|
||||||
{this.state.potentialProvider} is not a working provider node
|
{this.state.potentialProvider} is not a working provider node
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box width="100%" height="100%" padding={3}>
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
padding={3}
|
|
||||||
>
|
|
||||||
<Row>
|
<Row>
|
||||||
<Icon icon="Bitcoin" mr={2}/>
|
<Icon icon="Bitcoin" mr={2} />
|
||||||
<Text fontSize="14px" fontWeight="bold">
|
<Text fontSize="14px" fontWeight="bold">
|
||||||
Step 1 of 2: Set up Bitcoin Provider Node
|
Step 1 of 2: Set up Bitcoin Provider Node
|
||||||
</Text>
|
</Text>
|
||||||
</Row>
|
</Row>
|
||||||
<Box mt={3}>
|
<Box mt={3}>
|
||||||
<Text fontSize="14px" fontWeight="regular" color="gray">
|
<Text fontSize="14px" fontWeight="regular" color="gray">
|
||||||
In order to perform Bitcoin transaction in Landscape, you'll need to set a provider node. A provider node is an urbit which maintains a synced Bitcoin ledger.
|
In order to perform Bitcoin transaction in Landscape, you'll
|
||||||
<a fontSize="14px" target="_blank" href="https://urbit.org/bitcoin-wallet"> Learn More</a>
|
need to set a provider node. A provider node is an urbit which
|
||||||
|
maintains a synced Bitcoin ledger.
|
||||||
|
<a
|
||||||
|
fontSize="14px"
|
||||||
|
target="_blank"
|
||||||
|
href="https://urbit.org/bitcoin-wallet"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
Learn More
|
||||||
|
</a>
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mt={3} mb={2}>
|
<Box mt={3} mb={2}>
|
||||||
@ -132,7 +142,7 @@ export default class ProviderModal extends Component {
|
|||||||
borderColor={workingColor}
|
borderColor={workingColor}
|
||||||
onChange={this.checkProvider}
|
onChange={this.checkProvider}
|
||||||
/>
|
/>
|
||||||
{(this.state.checkingProvider) ? <LoadingSpinner/> : null}
|
{this.state.checkingProvider ? <LoadingSpinner /> : null}
|
||||||
</Row>
|
</Row>
|
||||||
{workingNode}
|
{workingNode}
|
||||||
<Row alignItems="center" mt={3}>
|
<Row alignItems="center" mt={3}>
|
||||||
@ -140,12 +150,15 @@ export default class ProviderModal extends Component {
|
|||||||
mr={2}
|
mr={2}
|
||||||
primary
|
primary
|
||||||
disabled={!this.state.ready}
|
disabled={!this.state.ready}
|
||||||
children="Set Peer Node"
|
|
||||||
fontSize="14px"
|
fontSize="14px"
|
||||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
style={{ cursor: this.state.ready ? 'pointer' : 'default' }}
|
||||||
onClick={() => {this.submitProvider(this.state.provider)}}
|
onClick={() => {
|
||||||
/>
|
this.submitProvider(this.state.provider);
|
||||||
{(this.state.connecting) ? <LoadingSpinner/> : null}
|
}}
|
||||||
|
>
|
||||||
|
Set Peer Node
|
||||||
|
</Button>
|
||||||
|
{this.state.connecting ? <LoadingSpinner /> : null}
|
||||||
</Row>
|
</Row>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -1,70 +1,71 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import {
|
import { Box, Icon, Row, Text, LoadingSpinner } from '@tlon/indigo-react';
|
||||||
Box,
|
|
||||||
Icon,
|
|
||||||
Row,
|
|
||||||
Text,
|
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
LoadingSpinner,
|
|
||||||
} from '@tlon/indigo-react';
|
|
||||||
|
|
||||||
import { Sigil } from './sigil.js'
|
|
||||||
|
|
||||||
|
|
||||||
export default class TxAction extends Component {
|
export default class TxAction extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const leftIcon =
|
const leftIcon =
|
||||||
(this.props.action === "sent") ? "ArrowSouth" :
|
this.props.action === 'sent'
|
||||||
(this.props.action === "recv") ? "ArrowNorth" :
|
? 'ArrowSouth'
|
||||||
(this.props.action === "fail") ? "X" :
|
: this.props.action === 'recv'
|
||||||
"NullIcon";
|
? 'ArrowNorth'
|
||||||
|
: this.props.action === 'fail'
|
||||||
|
? 'X'
|
||||||
|
: 'NullIcon';
|
||||||
|
|
||||||
const actionColor =
|
const actionColor =
|
||||||
(this.props.action === "sent") ? "sentBlue" :
|
this.props.action === 'sent'
|
||||||
(this.props.action === "recv") ? "recvGreen" :
|
? 'sentBlue'
|
||||||
(this.props.action === "fail") ? "gray" :
|
: this.props.action === 'recv'
|
||||||
"red";
|
? 'recvGreen'
|
||||||
|
: this.props.action === 'fail'
|
||||||
|
? 'gray'
|
||||||
|
: 'red';
|
||||||
|
|
||||||
const actionText =
|
const actionText =
|
||||||
(this.props.action === "sent" && !this.props.pending) ? "Sent BTC" :
|
this.props.action === 'sent' && !this.props.pending
|
||||||
(this.props.action === "sent" && this.props.pending) ? "Sending BTC" :
|
? 'Sent BTC'
|
||||||
(this.props.action === "recv" && !this.props.pending) ? "Received BTC" :
|
: this.props.action === 'sent' && this.props.pending
|
||||||
(this.props.action === "recv" && this.props.pending) ? "Receiving BTC" :
|
? 'Sending BTC'
|
||||||
(this.props.action === "fail") ? "Failed" :
|
: this.props.action === 'recv' && !this.props.pending
|
||||||
"error";
|
? 'Received BTC'
|
||||||
|
: this.props.action === 'recv' && this.props.pending
|
||||||
|
? 'Receiving BTC'
|
||||||
|
: this.props.action === 'fail'
|
||||||
|
? 'Failed'
|
||||||
|
: 'error';
|
||||||
|
|
||||||
const pending = (!this.props.pending) ? null :
|
const pending = !this.props.pending ? null : (
|
||||||
<LoadingSpinner
|
<LoadingSpinner background="midOrange" foreground="orange" />
|
||||||
background="midOrange"
|
);
|
||||||
foreground="orange"
|
|
||||||
/>
|
|
||||||
|
|
||||||
const url = (this.props.network === 'testnet')
|
const url =
|
||||||
? `http://blockstream.info/testnet/tx/${this.props.txid}`
|
this.props.network === 'testnet'
|
||||||
: `http://blockstream.info/tx/${this.props.txid}`;
|
? `http://blockstream.info/testnet/tx/${this.props.txid}`
|
||||||
|
: `http://blockstream.info/tx/${this.props.txid}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row alignItems="center">
|
<Row alignItems="center">
|
||||||
<Box backgroundColor={actionColor}
|
<Box
|
||||||
width="24px"
|
backgroundColor={actionColor}
|
||||||
height="24px"
|
width="24px"
|
||||||
textAlign="center"
|
height="24px"
|
||||||
alignItems="center"
|
textAlign="center"
|
||||||
borderRadius="2px"
|
alignItems="center"
|
||||||
mr={2}
|
borderRadius="2px"
|
||||||
p={1}
|
mr={2}
|
||||||
|
p={1}
|
||||||
>
|
>
|
||||||
<Icon icon={leftIcon} color="white"/>
|
<Icon icon={leftIcon} color="white" />
|
||||||
</Box>
|
</Box>
|
||||||
<Text color={actionColor} fontSize="14px">{actionText}</Text>
|
<Text color={actionColor} fontSize="14px">
|
||||||
<a href={url} target="_blank">
|
{actionText}
|
||||||
<Icon color={actionColor} icon="ArrowNorthEast" ml={1} mr={2}/>
|
</Text>
|
||||||
|
<a href={url} target="_blank" rel="noreferrer">
|
||||||
|
<Icon color={actionColor} icon="ArrowNorthEast" ml={1} mr={2} />
|
||||||
</a>
|
</a>
|
||||||
{pending}
|
{pending}
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -1,28 +1,16 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { BrowserRouter, Route } from "react-router-dom";
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import _ from 'lodash';
|
|
||||||
import { api } from '../api.js';
|
import { api } from '../api.js';
|
||||||
import { store } from '../store.js';
|
import { store } from '../store.js';
|
||||||
|
import { ThemeProvider } from 'styled-components';
|
||||||
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components';
|
|
||||||
import light from './themes/light';
|
import light from './themes/light';
|
||||||
import dark from './themes/dark';
|
// import dark from './themes/dark';
|
||||||
import {
|
import { Box, Reset } from '@tlon/indigo-react';
|
||||||
Text,
|
|
||||||
Box,
|
|
||||||
Reset,
|
|
||||||
Col,
|
|
||||||
LoadingSpinner,
|
|
||||||
} from '@tlon/indigo-react';
|
|
||||||
import StartupModal from './lib/startupModal.js';
|
import StartupModal from './lib/startupModal.js';
|
||||||
import Header from './lib/header.js'
|
import Body from './lib/body.js';
|
||||||
import Balance from './lib/balance.js'
|
import { subscription } from '../subscription.js';
|
||||||
import Transactions from './lib/transactions.js'
|
|
||||||
import Warning from './lib/warning.js'
|
|
||||||
import Body from './lib/body.js'
|
|
||||||
import { subscription } from '../subscription.js'
|
|
||||||
|
|
||||||
const network = "bitcoin";
|
const network = 'bitcoin';
|
||||||
|
|
||||||
export class Root extends Component {
|
export class Root extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -32,8 +20,8 @@ export class Root extends Component {
|
|||||||
store.setStateHandler(this.setState.bind(this));
|
store.setStateHandler(this.setState.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
componentDidMount() {
|
||||||
this.props.channel.setOnChannelError((e) => {
|
this.props.channel.setOnChannelError(() => {
|
||||||
subscription.start();
|
subscription.start();
|
||||||
});
|
});
|
||||||
subscription.start();
|
subscription.start();
|
||||||
@ -42,34 +30,38 @@ export class Root extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const loaded = this.state.loaded;
|
const loaded = this.state.loaded;
|
||||||
const warning = this.state.showWarning;
|
const warning = this.state.showWarning;
|
||||||
const blur = (!loaded) ? false :
|
const blur = !loaded ? false : !(this.state.wallet && this.state.provider);
|
||||||
!(this.state.wallet && this.state.provider);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ThemeProvider theme={light}>
|
<ThemeProvider theme={light}>
|
||||||
<Reset/>
|
<Reset />
|
||||||
{ (loaded) ? <StartupModal api={api} state={this.state} network={network}/> : null }
|
{loaded ? (
|
||||||
<Box display="flex"
|
<StartupModal api={api} state={this.state} network={network} />
|
||||||
flexDirection='column'
|
) : null}
|
||||||
position='absolute'
|
<Box
|
||||||
alignItems='center'
|
display="flex"
|
||||||
backgroundColor='lightOrange'
|
flexDirection="column"
|
||||||
width='100%'
|
position="absolute"
|
||||||
|
alignItems="center"
|
||||||
|
backgroundColor="lightOrange"
|
||||||
|
width="100%"
|
||||||
minHeight={loaded ? '100%' : 'none'}
|
minHeight={loaded ? '100%' : 'none'}
|
||||||
height={loaded ? 'none' : '100%'}
|
height={loaded ? 'none' : '100%'}
|
||||||
style={{filter: (blur ? 'blur(8px)' : 'none')}}
|
style={{ filter: blur ? 'blur(8px)' : 'none' }}
|
||||||
px={[0,4]}
|
px={[0, 4]}
|
||||||
pb={[0,4]}
|
pb={[0, 4]}
|
||||||
>
|
>
|
||||||
<Body loaded={loaded}
|
<Body
|
||||||
|
loaded={loaded}
|
||||||
state={this.state}
|
state={this.state}
|
||||||
api={api} network={network}
|
api={api}
|
||||||
|
network={network}
|
||||||
warning={warning}
|
warning={warning}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,11 @@ module.exports = {
|
|||||||
extends: '@urbit',
|
extends: '@urbit',
|
||||||
env: {
|
env: {
|
||||||
'jest': true
|
'jest': true
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// Because we use styled system, and use
|
||||||
|
// the convention of each prop on a new line
|
||||||
|
// we probably shouldn't keep this on
|
||||||
|
'max-lines-per-function': ['off', {}]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,8 +36,34 @@ export const globalTypes = {
|
|||||||
|
|
||||||
export const decorators = [
|
export const decorators = [
|
||||||
(Story, context) => {
|
(Story, context) => {
|
||||||
|
window.ship = 'sampel-palnet';
|
||||||
const theme = context.globals.theme === 'light' ? light : dark;
|
const theme = context.globals.theme === 'light' ? light : dark;
|
||||||
|
|
||||||
|
useContactState.setState({
|
||||||
|
contacts: {
|
||||||
|
'~ridlur-figbud': {
|
||||||
|
status: 'please like and subscribe',
|
||||||
|
'last-updated': 1616609090555,
|
||||||
|
avatar: null,
|
||||||
|
cover: null,
|
||||||
|
bio: '',
|
||||||
|
nickname: 'Gav',
|
||||||
|
color: '0x26.3e0f',
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
'~sampel-palnet': {
|
||||||
|
status: 'A test status',
|
||||||
|
'last-updated': 1616609090555,
|
||||||
|
avatar: null,
|
||||||
|
cover: null,
|
||||||
|
bio: '',
|
||||||
|
nickname: 'You',
|
||||||
|
color: '0x26.3e0f',
|
||||||
|
groups: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
useMetadataState.setState({
|
useMetadataState.setState({
|
||||||
associations: {
|
associations: {
|
||||||
groups: {
|
groups: {
|
||||||
@ -66,6 +92,25 @@ export const decorators = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
graph: {
|
graph: {
|
||||||
|
'/ship/~bitbet-bolbel/links': {
|
||||||
|
metadata: {
|
||||||
|
preview: false,
|
||||||
|
vip: '',
|
||||||
|
title: 'Link Collection',
|
||||||
|
description: '',
|
||||||
|
creator: '~darrux-landes',
|
||||||
|
picture: '',
|
||||||
|
hidden: false,
|
||||||
|
config: {
|
||||||
|
graph: 'link',
|
||||||
|
},
|
||||||
|
'date-created': '~2020.4.6..21.53.30..dc68',
|
||||||
|
color: '0x0',
|
||||||
|
},
|
||||||
|
'app-name': 'graph',
|
||||||
|
resource: '/ship/~bitbet-bolbel/links',
|
||||||
|
group: '/ship/~bitbet-bolbel/urbit-community',
|
||||||
|
},
|
||||||
'/ship/~darrux-landes/development': {
|
'/ship/~darrux-landes/development': {
|
||||||
metadata: {
|
metadata: {
|
||||||
preview: false,
|
preview: false,
|
||||||
@ -88,6 +133,47 @@ export const decorators = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
previews: {
|
||||||
|
'/ship/~bollug-worlus/urbit-index': {
|
||||||
|
group: '/ship/~bollug-worlus/urbit-index',
|
||||||
|
channels: {
|
||||||
|
'/ship/~darrux-landes/index-weekly': {
|
||||||
|
metadata: {
|
||||||
|
preview: false,
|
||||||
|
vip: '',
|
||||||
|
title: 'Index Weekly',
|
||||||
|
description: '',
|
||||||
|
creator: '~bollug-worlus',
|
||||||
|
picture: '',
|
||||||
|
hidden: false,
|
||||||
|
config: {
|
||||||
|
graph: 'publish',
|
||||||
|
},
|
||||||
|
'date-created': '~2020.4.6..21.53.30..dc68',
|
||||||
|
color: '0x0',
|
||||||
|
},
|
||||||
|
'app-name': 'graph',
|
||||||
|
resource: '/ship/~bollug-worlus/index-weekly',
|
||||||
|
group: '/ship/~bollug-worlus/urbit-index',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
members: 1237,
|
||||||
|
metadata: {
|
||||||
|
preview: false,
|
||||||
|
vip: '',
|
||||||
|
title: 'Urbit Index',
|
||||||
|
description: '',
|
||||||
|
creator: '~bollug-worlus',
|
||||||
|
picture: '',
|
||||||
|
hidden: false,
|
||||||
|
config: {
|
||||||
|
group: null,
|
||||||
|
},
|
||||||
|
'date-created': '~2020.4.6..21.53.30..dc68',
|
||||||
|
color: '0x0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useContactState.setState({
|
useContactState.setState({
|
||||||
|
@ -28,12 +28,13 @@ module.exports = {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Change the URL to your livenet ship (if making front-end changes) or keep it the
|
Change the URL to your livenet ship (if making front-end changes) or keep it the
|
||||||
same (if [developing on a local development ship][local]). Then, from
|
same (if [developing on a local development ship][local]). Then, from the root
|
||||||
'pkg/interface':
|
of the repository
|
||||||
|
|
||||||
```
|
```bash
|
||||||
npm ci
|
npm i
|
||||||
npm run start
|
npm run bootstrap
|
||||||
|
cd pkg/interface && npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
The dev server will start at `http://localhost:9000`. Sign in as you would
|
The dev server will start at `http://localhost:9000`. Sign in as you would
|
||||||
|
51815
pkg/interface/package-lock.json
generated
51815
pkg/interface/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@reach/disclosure": "^0.10.5",
|
"@reach/disclosure": "^0.10.5",
|
||||||
@ -13,7 +14,8 @@
|
|||||||
"@tlon/indigo-light": "^1.0.7",
|
"@tlon/indigo-light": "^1.0.7",
|
||||||
"@tlon/indigo-react": "^1.2.23",
|
"@tlon/indigo-react": "^1.2.23",
|
||||||
"@tlon/sigil-js": "^1.4.3",
|
"@tlon/sigil-js": "^1.4.3",
|
||||||
"@urbit/api": "file:../npm/api",
|
"@urbit/api": "^1.1.1",
|
||||||
|
"@urbit/http-api": "^1.2.1",
|
||||||
"any-ascii": "^0.1.7",
|
"any-ascii": "^0.1.7",
|
||||||
"aws-sdk": "^2.830.0",
|
"aws-sdk": "^2.830.0",
|
||||||
"big-integer": "^1.6.48",
|
"big-integer": "^1.6.48",
|
||||||
@ -80,7 +82,7 @@
|
|||||||
"@types/yup": "^0.29.11",
|
"@types/yup": "^0.29.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.15.0",
|
"@typescript-eslint/eslint-plugin": "^4.15.0",
|
||||||
"@typescript-eslint/parser": "^4.24.0",
|
"@typescript-eslint/parser": "^4.24.0",
|
||||||
"@urbit/eslint-config": "file:../npm/eslint-config",
|
"@urbit/eslint-config": "^1.0.0",
|
||||||
"@welldone-software/why-did-you-render": "^6.1.0",
|
"@welldone-software/why-did-you-render": "^6.1.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
@ -102,6 +104,7 @@
|
|||||||
"react-hot-loader": "^4.13.0",
|
"react-hot-loader": "^4.13.0",
|
||||||
"sass": "^1.32.5",
|
"sass": "^1.32.5",
|
||||||
"sass-loader": "^8.0.2",
|
"sass-loader": "^8.0.2",
|
||||||
|
"storybook-addon-designs": "^6.0.0",
|
||||||
"ts-mdast": "^1.0.0",
|
"ts-mdast": "^1.0.0",
|
||||||
"typescript": "^4.2.4",
|
"typescript": "^4.2.4",
|
||||||
"webpack": "^4.46.0",
|
"webpack": "^4.46.0",
|
||||||
@ -113,15 +116,15 @@
|
|||||||
"lint-file": "eslint",
|
"lint-file": "eslint",
|
||||||
"tsc": "tsc",
|
"tsc": "tsc",
|
||||||
"tsc:watch": "tsc --watch",
|
"tsc:watch": "tsc --watch",
|
||||||
"preinstall": "./preinstall.sh",
|
|
||||||
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
|
"build:dev": "cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
|
||||||
"build:prod": "cd ../npm/api && npm ci && cd ../../interface && cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
|
"build:prod": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
|
||||||
"start": "webpack-dev-server --config config/webpack.dev.js",
|
"start": "webpack-dev-server --config config/webpack.dev.js",
|
||||||
"test": "jest",
|
"test": "tsc && jest",
|
||||||
"prepare": "cd ../.. && husky install pkg/interface/.husky",
|
"jest": "jest",
|
||||||
"storybook": "start-storybook -p 6006",
|
"storybook": "start-storybook -p 6006",
|
||||||
"build-storybook": "build-storybook",
|
"build-storybook": "build-storybook",
|
||||||
"chromatic": "chromatic --exit-zero-on-changes"
|
"chromatic": "chromatic --exit-zero-on-changes",
|
||||||
|
"hook-lint": "eslint --cache --fix"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -9,4 +9,6 @@ for i in $(find . -type d -maxdepth 1) ; do
|
|||||||
npm ci
|
npm ci
|
||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
cd http-api
|
||||||
|
npm run build
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
import { Path, Patp } from '@urbit/api';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import BaseStore from '../store/base';
|
|
||||||
|
|
||||||
export default class BaseApi<S extends object = {}> {
|
|
||||||
bindPaths: Path[] = [];
|
|
||||||
constructor(public ship: Patp, public channel: any, public store: BaseStore<S>) {}
|
|
||||||
|
|
||||||
unsubscribe(id: number) {
|
|
||||||
this.channel.unsubscribe(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribe(path: Path, method, ship = this.ship, app: string, success, fail, quit, queue = false) {
|
|
||||||
this.bindPaths = _.uniq([...this.bindPaths, path]);
|
|
||||||
|
|
||||||
return this.channel.subscribe(
|
|
||||||
this.ship,
|
|
||||||
app,
|
|
||||||
path,
|
|
||||||
(err) => {
|
|
||||||
fail(err);
|
|
||||||
},
|
|
||||||
(event) => {
|
|
||||||
success({
|
|
||||||
data: event,
|
|
||||||
from: {
|
|
||||||
ship,
|
|
||||||
path
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
(qui) => {
|
|
||||||
quit(qui);
|
|
||||||
},
|
|
||||||
() => {},
|
|
||||||
queue
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
action(
|
|
||||||
appl: string,
|
|
||||||
mark: string,
|
|
||||||
data: any,
|
|
||||||
ship = (window as any).ship
|
|
||||||
): Promise<any> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.channel.poke(
|
|
||||||
ship,
|
|
||||||
appl,
|
|
||||||
mark,
|
|
||||||
data,
|
|
||||||
(json) => {
|
|
||||||
resolve(json);
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
scry<T>(app: string, path: Path): Promise<T> {
|
|
||||||
return fetch(`/~/scry/${app}${path}.json`).then(r => r.json() as Promise<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
async spider<T>(inputMark: string, outputMark: string, threadName: string, body: any): Promise<T> {
|
|
||||||
const res = await fetch(`/spider/${inputMark}/${threadName}/${outputMark}.json`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.json();
|
|
||||||
}
|
|
||||||
}
|
|
47
pkg/interface/src/logic/api/bootstrap.ts
Normal file
47
pkg/interface/src/logic/api/bootstrap.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import airlock from '~/logic/api';
|
||||||
|
import useHarkState from '~/logic/state/hark';
|
||||||
|
import useMetadataState from '~/logic/state/metadata';
|
||||||
|
import useContactState from '../state/contact';
|
||||||
|
import useGraphState from '../state/graph';
|
||||||
|
import useGroupState from '../state/group';
|
||||||
|
import useInviteState from '../state/invite';
|
||||||
|
import useLaunchState from '../state/launch';
|
||||||
|
import useSettingsState from '../state/settings';
|
||||||
|
import useLocalState from '../state/local';
|
||||||
|
import useStorageState from '../state/storage';
|
||||||
|
|
||||||
|
export async function bootstrapApi() {
|
||||||
|
airlock.onError = (e) => {
|
||||||
|
(async () => {
|
||||||
|
const { reconnect } = useLocalState.getState();
|
||||||
|
try {
|
||||||
|
await reconnect();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log('onError');
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|
||||||
|
airlock.onRetry = () => {
|
||||||
|
useLocalState.setState({ subscription: 'reconnecting' });
|
||||||
|
};
|
||||||
|
|
||||||
|
airlock.onOpen = () => {
|
||||||
|
useLocalState.setState({ subscription: 'connected' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const promises = [
|
||||||
|
useHarkState,
|
||||||
|
useMetadataState,
|
||||||
|
useGroupState,
|
||||||
|
useContactState,
|
||||||
|
useSettingsState,
|
||||||
|
useLaunchState,
|
||||||
|
useInviteState,
|
||||||
|
useGraphState,
|
||||||
|
useStorageState
|
||||||
|
].map(state => state.getState().initialize(airlock));
|
||||||
|
await Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
@ -1,124 +0,0 @@
|
|||||||
import { Patp } from '@urbit/api';
|
|
||||||
import { ContactEditField } from '@urbit/api/contacts';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import {edit} from '../reducers/contact-update';
|
|
||||||
import {doOptimistically} from '../state/base';
|
|
||||||
import useContactState from '../state/contact';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class ContactsApi extends BaseApi<StoreState> {
|
|
||||||
add(ship: Patp, contact: any) {
|
|
||||||
contact['last-updated'] = Date.now();
|
|
||||||
return this.storeAction({ add: { ship, contact } });
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(ship: Patp) {
|
|
||||||
return this.storeAction({ remove: { ship } });
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(ship: Patp, editField: ContactEditField) {
|
|
||||||
/* editField can be...
|
|
||||||
{nickname: ''}
|
|
||||||
{email: ''}
|
|
||||||
{phone: ''}
|
|
||||||
{website: ''}
|
|
||||||
{color: 'fff'} // with no 0x prefix
|
|
||||||
{avatar: null}
|
|
||||||
{avatar: ''}
|
|
||||||
{add-group: {ship, name}}
|
|
||||||
{remove-group: {ship, name}}
|
|
||||||
*/
|
|
||||||
const action = {
|
|
||||||
edit: {
|
|
||||||
ship,
|
|
||||||
'edit-field': editField,
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doOptimistically(useContactState, action, this.storeAction.bind(this), [edit])
|
|
||||||
}
|
|
||||||
|
|
||||||
allowShips(ships: Patp[]) {
|
|
||||||
return this.storeAction({
|
|
||||||
allow: {
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
allowGroup(ship: string, name: string) {
|
|
||||||
const group = { ship, name };
|
|
||||||
return this.storeAction({
|
|
||||||
allow: {
|
|
||||||
group
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setPublic(setPublic: any) {
|
|
||||||
return this.storeAction({
|
|
||||||
'set-public': setPublic
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
share(recipient: Patp) {
|
|
||||||
return this.action(
|
|
||||||
'contact-push-hook',
|
|
||||||
'contact-share',
|
|
||||||
{ share: recipient }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchIsAllowed(entity, name, ship, personal) {
|
|
||||||
const isPersonal = personal ? 'true' : 'false';
|
|
||||||
return this.scry<any>(
|
|
||||||
'contact-store',
|
|
||||||
`/is-allowed/${entity}/${name}/${ship}/${isPersonal}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async disallowedShipsForOurContact(ships: string[]): Promise<string[]> {
|
|
||||||
return _.compact(
|
|
||||||
await Promise.all(
|
|
||||||
ships.map(
|
|
||||||
async (s) => {
|
|
||||||
const ship = `~${s}`;
|
|
||||||
if(s === window.ship) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const allowed = await this.fetchIsAllowed(
|
|
||||||
`~${window.ship}`,
|
|
||||||
'personal',
|
|
||||||
ship,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
return allowed ? null : ship;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
retrieve(ship: string) {
|
|
||||||
const resource = { ship, name: '' };
|
|
||||||
return this.action('contact-pull-hook', 'pull-hook-action', {
|
|
||||||
add: {
|
|
||||||
resource,
|
|
||||||
ship
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private storeAction(action: any): Promise<any> {
|
|
||||||
return this.action('contact-store', 'contact-update-0', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewAction(threadName: string, action: any) {
|
|
||||||
return this.spider('contact-view-action', 'json', threadName, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private hookAction(ship: Patp, action: any): Promise<any> {
|
|
||||||
return this.action('contact-push-hook', 'contact-update-0', action);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import type { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class GcpApi extends BaseApi<StoreState> {
|
|
||||||
// Does not touch the store; use the value manually.
|
|
||||||
async isConfigured(): Promise<boolean> {
|
|
||||||
return this.spider('noun', 'json', 'gcp-is-configured', {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does not return the token; read it out of the store.
|
|
||||||
async getToken(): Promise<void> {
|
|
||||||
return this.spider('noun', 'gcp-token', 'gcp-get-token', {})
|
|
||||||
.then((token) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: token
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { Patp } from '@urbit/api';
|
|
||||||
import GlobalStore from '../store/store';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
import ContactsApi from './contacts';
|
|
||||||
import GcpApi from './gcp';
|
|
||||||
import GraphApi from './graph';
|
|
||||||
import GroupsApi from './groups';
|
|
||||||
import { HarkApi } from './hark';
|
|
||||||
import InviteApi from './invite';
|
|
||||||
import LaunchApi from './launch';
|
|
||||||
import LocalApi from './local';
|
|
||||||
import MetadataApi from './metadata';
|
|
||||||
import S3Api from './s3';
|
|
||||||
import SettingsApi from './settings';
|
|
||||||
|
|
||||||
export default class GlobalApi extends BaseApi<StoreState> {
|
|
||||||
local = new LocalApi(this.ship, this.channel, this.store);
|
|
||||||
invite = new InviteApi(this.ship, this.channel, this.store);
|
|
||||||
metadata = new MetadataApi(this.ship, this.channel, this.store);
|
|
||||||
contacts = new ContactsApi(this.ship, this.channel, this.store);
|
|
||||||
groups = new GroupsApi(this.ship, this.channel, this.store);
|
|
||||||
launch = new LaunchApi(this.ship, this.channel, this.store);
|
|
||||||
gcp = new GcpApi(this.ship, this.channel, this.store);
|
|
||||||
s3 = new S3Api(this.ship, this.channel, this.store);
|
|
||||||
graph = new GraphApi(this.ship, this.channel, this.store);
|
|
||||||
hark = new HarkApi(this.ship, this.channel, this.store);
|
|
||||||
settings = new SettingsApi(this.ship, this.channel, this.store);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
public ship: Patp,
|
|
||||||
public channel: any,
|
|
||||||
public store: GlobalStore
|
|
||||||
) {
|
|
||||||
super(ship, channel, store);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,456 +0,0 @@
|
|||||||
import { patp2dec } from 'urbit-ob';
|
|
||||||
import { Content, Enc, GraphNode, GroupPolicy, Path, Patp, Post, Resource } from '@urbit/api';
|
|
||||||
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { decToUd, deSig, resourceAsPath, unixToDa } from '~/logic/lib/util';
|
|
||||||
import { makeResource, resourceFromPath } from '../lib/group';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export const createBlankNodeWithChildPost = (
|
|
||||||
parentIndex = '',
|
|
||||||
childIndex = '',
|
|
||||||
contents: Content[]
|
|
||||||
): GraphNode => {
|
|
||||||
const date = unixToDa(Date.now()).toString();
|
|
||||||
const nodeIndex = parentIndex + '/' + date;
|
|
||||||
|
|
||||||
const childGraph = {};
|
|
||||||
childGraph[childIndex] = {
|
|
||||||
post: {
|
|
||||||
author: `~${window.ship}`,
|
|
||||||
index: nodeIndex + '/' + childIndex,
|
|
||||||
'time-sent': Date.now(),
|
|
||||||
contents,
|
|
||||||
hash: null,
|
|
||||||
signatures: []
|
|
||||||
},
|
|
||||||
children: null
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
post: {
|
|
||||||
author: `~${window.ship}`,
|
|
||||||
index: nodeIndex,
|
|
||||||
'time-sent': Date.now(),
|
|
||||||
contents: [],
|
|
||||||
hash: null,
|
|
||||||
signatures: []
|
|
||||||
},
|
|
||||||
children: childGraph as BigIntOrderedMap<GraphNode>
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function markPending(nodes: any) {
|
|
||||||
_.forEach(nodes, (node) => {
|
|
||||||
node.post.author = deSig(node.post.author);
|
|
||||||
node.post.pending = true;
|
|
||||||
markPending(node.children || {});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createPost = (
|
|
||||||
contents: Content[],
|
|
||||||
parentIndex = '',
|
|
||||||
childIndex = 'DATE_PLACEHOLDER'
|
|
||||||
) => {
|
|
||||||
if (childIndex === 'DATE_PLACEHOLDER') {
|
|
||||||
childIndex = unixToDa(Date.now()).toString();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
author: `~${window.ship}`,
|
|
||||||
index: parentIndex + '/' + childIndex,
|
|
||||||
'time-sent': Date.now(),
|
|
||||||
contents,
|
|
||||||
hash: null,
|
|
||||||
signatures: []
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function moduleToMark(mod: string): string | undefined {
|
|
||||||
if(mod === 'link') {
|
|
||||||
return 'graph-validator-link';
|
|
||||||
}
|
|
||||||
if(mod === 'publish') {
|
|
||||||
return 'graph-validator-publish';
|
|
||||||
}
|
|
||||||
if(mod === 'chat') {
|
|
||||||
return 'graph-validator-chat';
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class GraphApi extends BaseApi<StoreState> {
|
|
||||||
joiningGraphs = new Set<string>();
|
|
||||||
|
|
||||||
private storeAction(action: any): Promise<any> {
|
|
||||||
return this.action('graph-store', 'graph-update-2', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewAction(threadName: string, action: any) {
|
|
||||||
return this.spider('graph-view-action', 'json', threadName, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private hookAction(ship: Patp, action: any): Promise<any> {
|
|
||||||
return this.action('graph-push-hook', 'graph-update-2', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
createManagedGraph(
|
|
||||||
name: string,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
group: Path,
|
|
||||||
mod: string
|
|
||||||
) {
|
|
||||||
const associated = { group: resourceFromPath(group) };
|
|
||||||
const resource = makeResource(`~${window.ship}`, name);
|
|
||||||
|
|
||||||
return this.viewAction('graph-create', {
|
|
||||||
'create': {
|
|
||||||
resource,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
associated,
|
|
||||||
'module': mod,
|
|
||||||
mark: moduleToMark(mod)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createUnmanagedGraph(
|
|
||||||
name: string,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
policy: Enc<GroupPolicy>,
|
|
||||||
mod: string
|
|
||||||
) {
|
|
||||||
const resource = makeResource(`~${window.ship}`, name);
|
|
||||||
|
|
||||||
return this.viewAction('graph-create', {
|
|
||||||
'create': {
|
|
||||||
resource,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
associated: { policy },
|
|
||||||
'module': mod,
|
|
||||||
mark: moduleToMark(mod)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
joinGraph(ship: Patp, name: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
const rid = resourceAsPath(resource);
|
|
||||||
if(this.joiningGraphs.has(rid)) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
this.joiningGraphs.add(rid);
|
|
||||||
return this.viewAction('graph-join', {
|
|
||||||
join: {
|
|
||||||
resource,
|
|
||||||
ship
|
|
||||||
}
|
|
||||||
}).then((res) => {
|
|
||||||
this.joiningGraphs.delete(rid);
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteGraph(name: string) {
|
|
||||||
const resource = makeResource(`~${window.ship}`, name);
|
|
||||||
return this.viewAction('graph-delete', {
|
|
||||||
'delete': {
|
|
||||||
resource
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
leaveGraph(ship: Patp, name: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
return this.viewAction('graph-leave', {
|
|
||||||
'leave': {
|
|
||||||
resource
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
groupifyGraph(ship: Patp, name: string, toPath?: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
const to = toPath && resourceFromPath(toPath);
|
|
||||||
|
|
||||||
return this.viewAction('graph-groupify', {
|
|
||||||
groupify: {
|
|
||||||
resource,
|
|
||||||
to
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
eval(cord: string): Promise<string[] | undefined> {
|
|
||||||
return this.spider('graph-view-action', 'tang', 'graph-eval', {
|
|
||||||
eval: cord
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addGraph(ship: Patp, name: string, graph: any, mark: any) {
|
|
||||||
return this.storeAction({
|
|
||||||
'add-graph': {
|
|
||||||
resource: { ship, name },
|
|
||||||
graph,
|
|
||||||
mark
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addDmMessage(ship: Patp, contents: Content[]) {
|
|
||||||
const post = createPost(contents, `/${patp2dec(ship)}`);
|
|
||||||
const action = {
|
|
||||||
'add-nodes': {
|
|
||||||
resource: { ship: `~${window.ship}`, name: 'dm-inbox' },
|
|
||||||
nodes: {
|
|
||||||
[post.index]: {
|
|
||||||
post,
|
|
||||||
children: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.action('dm-hook', 'graph-update-2', action);
|
|
||||||
markPending(action['add-nodes'].nodes);
|
|
||||||
action['add-nodes'].resource.ship =
|
|
||||||
action['add-nodes'].resource.ship.slice(1);
|
|
||||||
this.store.handleEvent({ data: {
|
|
||||||
'graph-update': action
|
|
||||||
} });
|
|
||||||
}
|
|
||||||
|
|
||||||
acceptDm(ship: Patp) {
|
|
||||||
return this.action('dm-hook', 'dm-hook-action', { 'accept' : ship });
|
|
||||||
}
|
|
||||||
|
|
||||||
declineDm(ship: Patp) {
|
|
||||||
return this.action('dm-hook', 'dm-hook-action', { 'decline' : ship });
|
|
||||||
}
|
|
||||||
|
|
||||||
setScreen(screen: boolean) {
|
|
||||||
return this.action('dm-hook', 'dm-hook-action', { screen });
|
|
||||||
}
|
|
||||||
|
|
||||||
addPost(ship: Patp, name: string, post: Post) {
|
|
||||||
const nodes = {};
|
|
||||||
nodes[post.index] = {
|
|
||||||
post,
|
|
||||||
children: null
|
|
||||||
};
|
|
||||||
return this.addNodes(ship, name, nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
addNode(ship: Patp, name: string, node: GraphNode) {
|
|
||||||
const nodes = {};
|
|
||||||
nodes[node.post.index] = node;
|
|
||||||
|
|
||||||
return this.addNodes(ship, name, nodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
addNodes(ship: Patp, name: string, nodes: Object) {
|
|
||||||
const action = {
|
|
||||||
'add-nodes': {
|
|
||||||
resource: { ship, name },
|
|
||||||
nodes
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const pendingPromise = this.spider(
|
|
||||||
'graph-update-2',
|
|
||||||
'graph-view-action',
|
|
||||||
'graph-add-nodes',
|
|
||||||
action
|
|
||||||
);
|
|
||||||
|
|
||||||
markPending(action['add-nodes'].nodes);
|
|
||||||
action['add-nodes'].resource.ship =
|
|
||||||
action['add-nodes'].resource.ship.slice(1);
|
|
||||||
|
|
||||||
this.store.handleEvent({ data: {
|
|
||||||
'graph-update': action
|
|
||||||
} });
|
|
||||||
|
|
||||||
return pendingPromise;
|
|
||||||
/* TODO: stop lying to our users about pending states
|
|
||||||
return pendingPromise.then((pendingHashes) => {
|
|
||||||
for (let index in action['add-nodes'].nodes) {
|
|
||||||
action['add-nodes'].nodes[index].post.hash =
|
|
||||||
pendingHashes['pending-indices'][index] || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.handleEvent({ data: {
|
|
||||||
'graph-update': {
|
|
||||||
'pending-indices': pendingHashes['pending-indices'],
|
|
||||||
...action
|
|
||||||
}
|
|
||||||
} });
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
async enableGroupFeed(group: Resource, vip: any = ''): Promise<Resource> {
|
|
||||||
const { resource } = await this.spider(
|
|
||||||
'graph-view-action',
|
|
||||||
'resource',
|
|
||||||
'graph-create-group-feed',
|
|
||||||
{
|
|
||||||
'create-group-feed': { resource: group, vip }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
async disableGroupFeed(group: Resource): Promise<void> {
|
|
||||||
await this.spider(
|
|
||||||
'graph-view-action',
|
|
||||||
'json',
|
|
||||||
'graph-disable-group-feed',
|
|
||||||
{
|
|
||||||
'disable-group-feed': { resource: group }
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
removePosts(ship: Patp, name: string, indices: string[]) {
|
|
||||||
return this.hookAction(ship, {
|
|
||||||
'remove-posts': {
|
|
||||||
resource: { ship, name },
|
|
||||||
indices
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeys() {
|
|
||||||
return this.scry<any>('graph-store', '/keys')
|
|
||||||
.then((keys) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: keys
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTags() {
|
|
||||||
return this.scry<any>('graph-store', '/tags')
|
|
||||||
.then((tags) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: tags
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTagQueries() {
|
|
||||||
return this.scry<any>('graph-store', '/tag-queries')
|
|
||||||
.then((tagQueries) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: tagQueries
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getGraph(ship: string, resource: string) {
|
|
||||||
return this.scry<any>('graph-store', `/graph/${ship}/${resource}`)
|
|
||||||
.then((graph) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: graph
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNewest(ship: string, resource: string, count: number, index = '') {
|
|
||||||
const data = await this.scry<any>('graph-store', `/newest/${ship}/${resource}/${count}${index}`);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
this.store.handleEvent({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getOlderSiblings(ship: string, resource: string, count: number, index = '') {
|
|
||||||
const idx = index.split('/').map(decToUd).join('/');
|
|
||||||
const data = await this.scry<any>('graph-store',
|
|
||||||
`/node-siblings/older/${ship}/${resource}/${count}${idx}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
this.store.handleEvent({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getYoungerSiblings(ship: string, resource: string, count: number, index = '') {
|
|
||||||
const idx = index.split('/').map(decToUd).join('/');
|
|
||||||
const data = await this.scry<any>('graph-store',
|
|
||||||
`/node-siblings/younger/${ship}/${resource}/${count}${idx}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
this.store.handleEvent({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getShallowChildren(ship: string, name: string, index = '') {
|
|
||||||
const idx = index.split('/').map(decToUd).join('/');
|
|
||||||
const data = await this.scry<any>('graph-store',
|
|
||||||
`/shallow-children/${ship}/${name}${idx}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
this.store.handleEvent({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDeepOlderThan(ship: string, resource: string, startTime = null, count: number) {
|
|
||||||
const start = startTime ? decToUd(startTime) : 'null';
|
|
||||||
const data = await this.scry<any>('graph-store',
|
|
||||||
`/deep-nodes-older-than/${ship}/${resource}/${count}/${start}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
const node = data['graph-update'];
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: {
|
|
||||||
'graph-update-flat': node,
|
|
||||||
'graph-update': node
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getFirstborn(ship: string, resource: string, index = '') {
|
|
||||||
const idx = index.split('/').map(decToUd).join('/');
|
|
||||||
const data = await this.scry<any>('graph-store',
|
|
||||||
`/firstborn/${ship}/${resource}${idx}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
const node = data['graph-update'];
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: {
|
|
||||||
'graph-update-thread': {
|
|
||||||
index,
|
|
||||||
...node
|
|
||||||
},
|
|
||||||
'graph-update': node
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getGraphSubset(ship: string, resource: string, start: string, end: string) {
|
|
||||||
return this.scry<any>(
|
|
||||||
'graph-store',
|
|
||||||
`/graph-subset/${ship}/${resource}/${end}/${start}`
|
|
||||||
).then((subset) => {
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: subset
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNode(ship: string, resource: string, index: string) {
|
|
||||||
const idx = index.split('/').map(decToUd).join('/');
|
|
||||||
const data = await this.scry<any>(
|
|
||||||
'graph-store',
|
|
||||||
`/node/${ship}/${resource}${idx}`
|
|
||||||
);
|
|
||||||
data['graph-update'].fetch = true;
|
|
||||||
const node = data['graph-update'];
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: {
|
|
||||||
'graph-update-loose': node
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
|||||||
import { Enc, Patp } from '@urbit/api';
|
|
||||||
import {
|
|
||||||
GroupAction,
|
|
||||||
GroupPolicy,
|
|
||||||
|
|
||||||
GroupPolicyDiff, Resource,
|
|
||||||
Tag
|
|
||||||
} from '@urbit/api/groups';
|
|
||||||
import { makeResource } from '../lib/group';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class GroupsApi extends BaseApi<StoreState> {
|
|
||||||
remove(resource: Resource, ships: Patp[]) {
|
|
||||||
return this.proxyAction({ removeMembers: { resource, ships } });
|
|
||||||
}
|
|
||||||
|
|
||||||
addTag(resource: Resource, tag: Tag, ships: Patp[]) {
|
|
||||||
return this.proxyAction({ addTag: { resource, tag, ships } });
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTag(resource: Resource, tag: Tag, ships: Patp[]) {
|
|
||||||
return this.proxyAction({ removeTag: { resource, tag, ships } });
|
|
||||||
}
|
|
||||||
|
|
||||||
add(resource: Resource, ships: Patp[]) {
|
|
||||||
return this.proxyAction({ addMembers: { resource, ships } });
|
|
||||||
}
|
|
||||||
|
|
||||||
removeGroup(resource: Resource) {
|
|
||||||
return this.storeAction({ removeGroup: { resource } });
|
|
||||||
}
|
|
||||||
|
|
||||||
changePolicy(resource: Resource, diff: Enc<GroupPolicyDiff>) {
|
|
||||||
return this.proxyAction({ changePolicy: { resource, diff } });
|
|
||||||
}
|
|
||||||
|
|
||||||
join(ship: string, name: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
|
|
||||||
return this.viewAction({ join: { resource, ship } });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(name: string, policy: Enc<GroupPolicy>, title: string, description: string) {
|
|
||||||
return this.viewThread('group-create', {
|
|
||||||
create: {
|
|
||||||
name,
|
|
||||||
policy,
|
|
||||||
title,
|
|
||||||
description
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteGroup(ship: string, name: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
|
|
||||||
return this.viewThread('group-delete', {
|
|
||||||
remove: resource
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
leaveGroup(ship: string, name: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
return this.viewThread('group-leave', {
|
|
||||||
leave: resource
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
invite(ship: string, name: string, ships: Patp[], description: string) {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
return this.viewThread('group-invite', {
|
|
||||||
invite: {
|
|
||||||
resource,
|
|
||||||
ships,
|
|
||||||
description
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
hide(resource: string) {
|
|
||||||
return this.viewAction({ hide: resource });
|
|
||||||
}
|
|
||||||
|
|
||||||
private proxyAction(action: GroupAction) {
|
|
||||||
return this.action('group-push-hook', 'group-update-0', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private storeAction(action: GroupAction) {
|
|
||||||
return this.action('group-store', 'group-update-0', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewThread(thread: string, action: any) {
|
|
||||||
return this.spider('group-view-action', 'json', thread, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private viewAction(action: any) {
|
|
||||||
return this.action('group-view', 'group-view-action', action);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,233 +0,0 @@
|
|||||||
import { Association, GraphNotifDescription, IndexedNotification, NotifIndex } from '@urbit/api';
|
|
||||||
import { BigInteger } from 'big-integer';
|
|
||||||
import { getParentIndex } from '../lib/notification';
|
|
||||||
import { dateToDa, decToUd } from '../lib/util';
|
|
||||||
import { reduce } from '../reducers/hark-update';
|
|
||||||
import { doOptimistically } from '../state/base';
|
|
||||||
import useHarkState from '../state/hark';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
function getHarkSize() {
|
|
||||||
return useHarkState.getState().notifications.size ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HarkApi extends BaseApi<StoreState> {
|
|
||||||
private harkAction(action: any): Promise<any> {
|
|
||||||
return this.action('hark-store', 'hark-action', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private graphHookAction(action: any) {
|
|
||||||
return this.action('hark-graph-hook', 'hark-graph-hook-action', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private groupHookAction(action: any) {
|
|
||||||
return this.action('hark-group-hook', 'hark-group-hook-action', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
private actOnNotification(frond: string, intTime: BigInteger | undefined, index: NotifIndex) {
|
|
||||||
const time = intTime ? decToUd(intTime.toString()) : null;
|
|
||||||
return this.harkAction({
|
|
||||||
[frond]: {
|
|
||||||
time,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async setMentions(mentions: boolean) {
|
|
||||||
await this.graphHookAction({
|
|
||||||
'set-mentions': mentions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setWatchOnSelf(watchSelf: boolean) {
|
|
||||||
return this.graphHookAction({
|
|
||||||
'set-watch-on-self': watchSelf
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDoNotDisturb(dnd: boolean) {
|
|
||||||
return this.harkAction({
|
|
||||||
'set-dnd': dnd
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async archive(intTime: BigInteger, index: NotifIndex) {
|
|
||||||
const time = intTime ? decToUd(intTime.toString()) : null;
|
|
||||||
const action = {
|
|
||||||
archive: {
|
|
||||||
time,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
};
|
|
||||||
await doOptimistically(useHarkState, action, this.harkAction.bind(this), [reduce]);
|
|
||||||
}
|
|
||||||
|
|
||||||
read(time: BigInteger, index: NotifIndex) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-note': index
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readIndex(index: NotifIndex) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-index': index
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unread(time: BigInteger, index: NotifIndex) {
|
|
||||||
return this.actOnNotification('unread-note', time, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
readGroup(group: string) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-group': group
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
readGraph(graph: string) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-graph': graph
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dismissReadCount(graph: string, index: string) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-count': {
|
|
||||||
graph: {
|
|
||||||
graph,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
markCountAsRead(association: Association, parent: string, description: GraphNotifDescription) {
|
|
||||||
const action = { 'read-count': {
|
|
||||||
graph: {
|
|
||||||
graph: association.resource,
|
|
||||||
group: association.group,
|
|
||||||
description,
|
|
||||||
index: parent
|
|
||||||
} }
|
|
||||||
};
|
|
||||||
doOptimistically(useHarkState, action, this.harkAction.bind(this), [reduce]);
|
|
||||||
}
|
|
||||||
|
|
||||||
markEachAsRead(association: Association, parent: string, child: string, description: GraphNotifDescription, mod: string) {
|
|
||||||
return this.harkAction({
|
|
||||||
'read-each': {
|
|
||||||
index:
|
|
||||||
{ graph:
|
|
||||||
{ graph: association.resource,
|
|
||||||
group: association.group,
|
|
||||||
description,
|
|
||||||
module: mod,
|
|
||||||
index: parent
|
|
||||||
}
|
|
||||||
},
|
|
||||||
target: child
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dec(index: NotifIndex, ref: string) {
|
|
||||||
return this.harkAction({
|
|
||||||
dec: {
|
|
||||||
index,
|
|
||||||
ref
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
seen() {
|
|
||||||
return this.harkAction({ seen: null });
|
|
||||||
}
|
|
||||||
readAll() {
|
|
||||||
return this.harkAction({ 'read-all': null });
|
|
||||||
}
|
|
||||||
|
|
||||||
mute(notif: IndexedNotification) {
|
|
||||||
if('graph' in notif.index && 'graph' in notif.notification.contents) {
|
|
||||||
const { index } = notif;
|
|
||||||
const parentIndex = getParentIndex(index.graph, notif.notification.contents.graph);
|
|
||||||
if(!parentIndex) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return this.ignoreGraph(index.graph.graph, parentIndex);
|
|
||||||
}
|
|
||||||
if('group' in notif.index) {
|
|
||||||
const { group } = notif.index.group;
|
|
||||||
return this.ignoreGroup(group);
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
unmute(notif: IndexedNotification) {
|
|
||||||
if('graph' in notif.index && 'graph' in notif.notification.contents) {
|
|
||||||
const { index } = notif;
|
|
||||||
const parentIndex = getParentIndex(index.graph, notif.notification.contents.graph);
|
|
||||||
if(!parentIndex) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return this.listenGraph(index.graph.graph, parentIndex);
|
|
||||||
}
|
|
||||||
if('group' in notif.index) {
|
|
||||||
return this.listenGroup(notif.index.group.group);
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreGroup(group: string) {
|
|
||||||
return this.groupHookAction({
|
|
||||||
ignore: group
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreGraph(graph: string, index: string) {
|
|
||||||
return this.graphHookAction({
|
|
||||||
ignore: {
|
|
||||||
graph,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listenGroup(group: string) {
|
|
||||||
return this.groupHookAction({
|
|
||||||
listen: group
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
listenGraph(graph: string, index: string) {
|
|
||||||
return this.graphHookAction({
|
|
||||||
listen: {
|
|
||||||
graph,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMore(): Promise<boolean> {
|
|
||||||
const offset = getHarkSize();
|
|
||||||
const count = 3;
|
|
||||||
await this.getSubset(offset, count, false);
|
|
||||||
return offset === getHarkSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSubset(offset:number, count:number, isArchive: boolean) {
|
|
||||||
const where = isArchive ? 'archive' : 'inbox';
|
|
||||||
const data = await this.scry('hark-store', `/recent/${where}/${offset}/${count}`);
|
|
||||||
this.store.handleEvent({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTimeSubset(start?: Date, end?: Date) {
|
|
||||||
const s = start ? dateToDa(start) : '-';
|
|
||||||
const e = end ? dateToDa(end) : '-';
|
|
||||||
const result = await this.scry('hark-hook', `/recent/${s}/${e}`);
|
|
||||||
this.store.handleEvent({
|
|
||||||
data: result
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
8
pkg/interface/src/logic/api/index.ts
Normal file
8
pkg/interface/src/logic/api/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import Urbit from '@urbit/http-api';
|
||||||
|
const api = new Urbit('', '');
|
||||||
|
api.ship = window.ship;
|
||||||
|
// api.verbose = true;
|
||||||
|
// @ts-ignore TODO window typings
|
||||||
|
window.api = api;
|
||||||
|
|
||||||
|
export default api;
|
@ -1,27 +0,0 @@
|
|||||||
import { Serial } from '@urbit/api';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class InviteApi extends BaseApi<StoreState> {
|
|
||||||
accept(app: string, uid: Serial) {
|
|
||||||
return this.inviteAction({
|
|
||||||
accept: {
|
|
||||||
term: app,
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
decline(app: string, uid: Serial) {
|
|
||||||
return this.inviteAction({
|
|
||||||
decline: {
|
|
||||||
term: app,
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private inviteAction(action) {
|
|
||||||
return this.action('invite-store', 'invite-action', action);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class LaunchApi extends BaseApi<StoreState> {
|
|
||||||
add(name: string, tile = { basic : { title: '', linkedUrl: '', iconUrl: '' } }) {
|
|
||||||
return this.launchAction({ add: { name, tile } });
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(name: string) {
|
|
||||||
return this.launchAction({ remove: name });
|
|
||||||
}
|
|
||||||
|
|
||||||
changeFirstTime(firstTime = true) {
|
|
||||||
return this.launchAction({ 'change-first-time': firstTime });
|
|
||||||
}
|
|
||||||
|
|
||||||
changeIsShown(name: string, isShown = true) {
|
|
||||||
return this.launchAction({ 'change-is-shown': { name, isShown } });
|
|
||||||
}
|
|
||||||
|
|
||||||
weather(location: string) {
|
|
||||||
return this.action('weather', 'json', location);
|
|
||||||
}
|
|
||||||
|
|
||||||
private launchAction(data) {
|
|
||||||
return this.action('launch', 'launch-action', data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class LocalApi extends BaseApi<StoreState> {
|
|
||||||
getBaseHash() {
|
|
||||||
this.scry<string>('file-server', '/clay/base/hash').then((baseHash) => {
|
|
||||||
this.store.handleEvent({ data: { baseHash } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getRuntimeLag() {
|
|
||||||
return this.scry<boolean>('launch', '/runtime-lag').then((runtimeLag) => {
|
|
||||||
this.store.handleEvent({ data: { runtimeLag } });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,108 +0,0 @@
|
|||||||
|
|
||||||
import { Association, Metadata, MetadataUpdatePreview, Path } from '@urbit/api';
|
|
||||||
import { uxToHex } from '../lib/util';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class MetadataApi extends BaseApi<StoreState> {
|
|
||||||
metadataAdd(appName: string, resource: Path, group: Path, title: string, description: string, dateCreated: string, color: string, moduleName: string) {
|
|
||||||
const creator = `~${this.ship}`;
|
|
||||||
return this.metadataAction({
|
|
||||||
add: {
|
|
||||||
group,
|
|
||||||
resource: {
|
|
||||||
resource,
|
|
||||||
'app-name': appName
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
color,
|
|
||||||
'date-created': dateCreated,
|
|
||||||
creator,
|
|
||||||
config: { graph: moduleName },
|
|
||||||
picture: '',
|
|
||||||
hidden: false,
|
|
||||||
preview: false,
|
|
||||||
vip: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(appName: string, resource: string, group: string) {
|
|
||||||
return this.metadataAction({
|
|
||||||
remove: {
|
|
||||||
group,
|
|
||||||
resource: {
|
|
||||||
resource,
|
|
||||||
'app-name': appName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
update(association: Association, newMetadata: Partial<Metadata>) {
|
|
||||||
const metadata = { ...association.metadata, ...newMetadata };
|
|
||||||
metadata.color = uxToHex(metadata.color);
|
|
||||||
return this.metadataAction({
|
|
||||||
add: {
|
|
||||||
group: association.group,
|
|
||||||
resource: {
|
|
||||||
resource: association.resource,
|
|
||||||
'app-name': association['app-name']
|
|
||||||
},
|
|
||||||
metadata
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
preview(group: string) {
|
|
||||||
return new Promise<MetadataUpdatePreview>((resolve, reject) => {
|
|
||||||
const tempChannel: any = new (window as any).channel();
|
|
||||||
let done = false;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if(done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
done = true;
|
|
||||||
tempChannel.delete();
|
|
||||||
reject(new Error('offline'));
|
|
||||||
}, 15000);
|
|
||||||
|
|
||||||
tempChannel.subscribe(window.ship, 'metadata-pull-hook', `/preview${group}`,
|
|
||||||
(err) => {
|
|
||||||
console.error(err);
|
|
||||||
reject(err);
|
|
||||||
tempChannel.delete();
|
|
||||||
},
|
|
||||||
(ev: any) => {
|
|
||||||
if ('metadata-hook-update' in ev) {
|
|
||||||
done = true;
|
|
||||||
tempChannel.delete();
|
|
||||||
const upd = ev['metadata-hook-update'].preview as MetadataUpdatePreview;
|
|
||||||
resolve(upd);
|
|
||||||
} else {
|
|
||||||
done = true;
|
|
||||||
tempChannel.delete();
|
|
||||||
reject(new Error('no-permissions'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(quit) => {
|
|
||||||
tempChannel.delete();
|
|
||||||
if(!done) {
|
|
||||||
reject(new Error('offline'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(a) => {
|
|
||||||
console.log(a);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private metadataAction(data) {
|
|
||||||
return this.action('metadata-push-hook', 'metadata-update-1', data);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class S3Api extends BaseApi<StoreState> {
|
|
||||||
setCurrentBucket(bucket: string) {
|
|
||||||
return this.s3Action({ 'set-current-bucket': bucket });
|
|
||||||
}
|
|
||||||
|
|
||||||
addBucket(bucket: string) {
|
|
||||||
return this.s3Action({ 'add-bucket': bucket });
|
|
||||||
}
|
|
||||||
|
|
||||||
removeBucket(bucket: string) {
|
|
||||||
return this.s3Action({ 'remove-bucket': bucket });
|
|
||||||
}
|
|
||||||
|
|
||||||
setEndpoint(endpoint: string) {
|
|
||||||
return this.s3Action({ 'set-endpoint': endpoint });
|
|
||||||
}
|
|
||||||
|
|
||||||
setAccessKeyId(accessKeyId: string) {
|
|
||||||
return this.s3Action({ 'set-access-key-id': accessKeyId });
|
|
||||||
}
|
|
||||||
|
|
||||||
setSecretAccessKey(secretAccessKey: string) {
|
|
||||||
return this.s3Action({ 'set-secret-access-key': secretAccessKey });
|
|
||||||
}
|
|
||||||
|
|
||||||
private s3Action(data: any) {
|
|
||||||
return this.action('s3-store', 's3-action', data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
|||||||
import {
|
|
||||||
Bucket, Key,
|
|
||||||
|
|
||||||
SettingsUpdate, Value
|
|
||||||
} from '@urbit/api/settings';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
import BaseApi from './base';
|
|
||||||
|
|
||||||
export default class SettingsApi extends BaseApi<StoreState> {
|
|
||||||
private storeAction(action: SettingsUpdate): Promise<any> {
|
|
||||||
return this.action('settings-store', 'settings-event', action);
|
|
||||||
}
|
|
||||||
|
|
||||||
putBucket(key: Key, bucket: Bucket) {
|
|
||||||
return this.storeAction({
|
|
||||||
'put-bucket': {
|
|
||||||
'bucket-key': key,
|
|
||||||
'bucket': bucket
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delBucket(key: Key) {
|
|
||||||
return this.storeAction({
|
|
||||||
'del-bucket': {
|
|
||||||
'bucket-key': key
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
putEntry(buc: Key, key: Key, val: Value) {
|
|
||||||
return this.storeAction({
|
|
||||||
'put-entry': {
|
|
||||||
'bucket-key': buc,
|
|
||||||
'entry-key': key,
|
|
||||||
'value': val
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delEntry(buc: Key, key: Key) {
|
|
||||||
return this.storeAction({
|
|
||||||
'put-entry': {
|
|
||||||
'bucket-key': buc,
|
|
||||||
'entry-key': key
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAll() {
|
|
||||||
const { all } = await this.scry('settings-store', '/all');
|
|
||||||
this.store.handleEvent({ data:
|
|
||||||
{ 'settings-data': { all } }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBucket(bucket: Key) {
|
|
||||||
const data: Record<string, unknown> = await this.scry('settings-store', `/bucket/${bucket}`);
|
|
||||||
this.store.handleEvent({ data: { 'settings-data': {
|
|
||||||
'bucket-key': bucket,
|
|
||||||
'bucket': data.bucket
|
|
||||||
} } });
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEntry(bucket: Key, entry: Key) {
|
|
||||||
const data: Record<string, unknown> = await this.scry('settings-store', `/entry/${bucket}/${entry}`);
|
|
||||||
this.store.handleEvent({ data: { 'settings-data': {
|
|
||||||
'bucket-key': bucket,
|
|
||||||
'entry-key': entry,
|
|
||||||
'entry': data.entry
|
|
||||||
} } });
|
|
||||||
}
|
|
||||||
}
|
|
25
pkg/interface/src/logic/lib/contact.ts
Normal file
25
pkg/interface/src/logic/lib/contact.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import airlock from '~/logic/api';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { fetchIsAllowed } from '@urbit/api';
|
||||||
|
|
||||||
|
export async function disallowedShipsForOurContact(
|
||||||
|
ships: string[]
|
||||||
|
): Promise<string[]> {
|
||||||
|
return _.compact(
|
||||||
|
await Promise.all(
|
||||||
|
ships.map(async (s) => {
|
||||||
|
const ship = `~${s}`;
|
||||||
|
if (s === window.ship) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const allowed = await airlock.scry(fetchIsAllowed(
|
||||||
|
`~${window.ship}`,
|
||||||
|
'personal',
|
||||||
|
ship,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
return allowed ? null : ship;
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
16
pkg/interface/src/logic/lib/fakeApi.test.js
Normal file
16
pkg/interface/src/logic/lib/fakeApi.test.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { newApi } from './fakeApi';
|
||||||
|
describe('API shim', () => {
|
||||||
|
it('should allow deep accesses', () => {
|
||||||
|
const api = newApi();
|
||||||
|
|
||||||
|
expect(api.foo.bar.baz.toString()).toBe('[fakeApi]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return promise on call', () => {
|
||||||
|
const api = newApi();
|
||||||
|
const method = api.foo.bar.baz;
|
||||||
|
const res = method();
|
||||||
|
|
||||||
|
expect('then' in res).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
22
pkg/interface/src/logic/lib/fakeApi.ts
Normal file
22
pkg/interface/src/logic/lib/fakeApi.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export function newApi() {
|
||||||
|
const target = () => {};
|
||||||
|
|
||||||
|
const handler = {
|
||||||
|
apply: function (target, that, args) {
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
get: function (target, prop, receiver) {
|
||||||
|
const original = target[prop];
|
||||||
|
if (prop === 'toString') {
|
||||||
|
return () => '[fakeApi]';
|
||||||
|
} else if (typeof original === 'function') {
|
||||||
|
return target[prop].bind(target);
|
||||||
|
} else if (original) {
|
||||||
|
return target[prop];
|
||||||
|
}
|
||||||
|
return newApi();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Proxy(target, handler) as any;
|
||||||
|
}
|
45
pkg/interface/src/logic/lib/fixtures.ts
Normal file
45
pkg/interface/src/logic/lib/fixtures.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { Content, GraphNode, unixToDa } from '@urbit/api';
|
||||||
|
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
|
||||||
|
import bigInt, { BigInteger } from 'big-integer';
|
||||||
|
|
||||||
|
export const makeComment = (
|
||||||
|
author: string,
|
||||||
|
time: number,
|
||||||
|
parentIndex: string,
|
||||||
|
contents: Content[]
|
||||||
|
): [BigInteger, GraphNode] => {
|
||||||
|
const da = unixToDa(time);
|
||||||
|
const index = `${parentIndex}/${da.toString()}`;
|
||||||
|
|
||||||
|
const children = new BigIntOrderedMap<GraphNode>().gas([
|
||||||
|
[
|
||||||
|
bigInt.one,
|
||||||
|
{
|
||||||
|
post: {
|
||||||
|
index: `${index}/1`,
|
||||||
|
author,
|
||||||
|
'time-sent': time,
|
||||||
|
signatures: [],
|
||||||
|
contents: contents,
|
||||||
|
hash: null
|
||||||
|
},
|
||||||
|
children: new BigIntOrderedMap()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
da,
|
||||||
|
{
|
||||||
|
post: {
|
||||||
|
index,
|
||||||
|
author,
|
||||||
|
'time-sent': time,
|
||||||
|
signatures: [],
|
||||||
|
contents: [],
|
||||||
|
hash: null
|
||||||
|
},
|
||||||
|
children
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
@ -12,14 +12,10 @@
|
|||||||
// intrinsic expiry.
|
// intrinsic expiry.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
import GlobalApi from '../api/global';
|
|
||||||
import useStorageState from '../state/storage';
|
import useStorageState from '../state/storage';
|
||||||
|
|
||||||
class GcpManager {
|
class GcpManager {
|
||||||
#api: GlobalApi | null = null;
|
configure() {
|
||||||
|
|
||||||
configure(api: GlobalApi) {
|
|
||||||
this.#api = api;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#running = false;
|
#running = false;
|
||||||
@ -30,10 +26,6 @@ class GcpManager {
|
|||||||
console.warn('GcpManager already running');
|
console.warn('GcpManager already running');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.#api) {
|
|
||||||
console.error('GcpManager must have api set');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.#running = true;
|
this.#running = true;
|
||||||
this.refreshLoop();
|
this.refreshLoop();
|
||||||
}
|
}
|
||||||
@ -63,7 +55,7 @@ class GcpManager {
|
|||||||
|
|
||||||
private refreshLoop() {
|
private refreshLoop() {
|
||||||
if (!this.#configured) {
|
if (!this.#configured) {
|
||||||
this.#api!.gcp.isConfigured()
|
useStorageState.getState().gcp.isConfigured()
|
||||||
.then((configured) => {
|
.then((configured) => {
|
||||||
if (configured === undefined) {
|
if (configured === undefined) {
|
||||||
throw new Error('can\'t check whether GCP is configured?');
|
throw new Error('can\'t check whether GCP is configured?');
|
||||||
@ -82,7 +74,7 @@ class GcpManager {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.#api!.gcp.getToken()
|
useStorageState.getState().gcp.getToken()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const token = useStorageState.getState().gcp.token;
|
const token = useStorageState.getState().gcp.token;
|
||||||
if (token) {
|
if (token) {
|
||||||
|
27
pkg/interface/src/logic/lib/graph.ts
Normal file
27
pkg/interface/src/logic/lib/graph.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { Graph } from '@urbit/api';
|
||||||
|
import { BigInteger } from 'big-integer';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import useMetadataState from '~/logic/state/metadata';
|
||||||
|
|
||||||
|
export function getNodeFromGraph(graph: Graph, index: BigInteger[]) {
|
||||||
|
return _.reduce(
|
||||||
|
index.slice(1),
|
||||||
|
(acc, val) => {
|
||||||
|
return acc?.children?.get(val);
|
||||||
|
},
|
||||||
|
graph.get(index[0])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPostRoute(
|
||||||
|
graph: string,
|
||||||
|
index: BigInteger[],
|
||||||
|
thread = false
|
||||||
|
) {
|
||||||
|
const association = useMetadataState.getState().associations.graph[graph];
|
||||||
|
const segment = thread ? 'thread' : 'replies';
|
||||||
|
|
||||||
|
return `/~landscape${association.group}/feed/${segment}/${index
|
||||||
|
.map(i => i.toString())
|
||||||
|
.join('/')}`;
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
import useLocalState from '~/logic/state/local';
|
|
||||||
import useSettingsState from '~/logic/state/settings';
|
|
||||||
import { BackgroundConfig, RemoteContentPolicy } from '~/types';
|
|
||||||
import GlobalApi from '../api/global';
|
|
||||||
|
|
||||||
const getBackgroundString = (bg: BackgroundConfig) => {
|
|
||||||
if (bg?.type === 'url') {
|
|
||||||
return bg.url;
|
|
||||||
} else if (bg?.type === 'color') {
|
|
||||||
return bg.color;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useMigrateSettings(api: GlobalApi) {
|
|
||||||
const local = useLocalState();
|
|
||||||
const { display, remoteContentPolicy, calm } = useSettingsState();
|
|
||||||
|
|
||||||
return async () => {
|
|
||||||
const promises: Promise<any>[] = [];
|
|
||||||
|
|
||||||
if (local.hideAvatars !== calm.hideAvatars) {
|
|
||||||
promises.push(
|
|
||||||
api.settings.putEntry('calm', 'hideAvatars', local.hideAvatars)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (local.hideNicknames !== calm.hideNicknames) {
|
|
||||||
promises.push(
|
|
||||||
api.settings.putEntry('calm', 'hideNicknames', local.hideNicknames)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
local?.background?.type &&
|
|
||||||
display.background !== getBackgroundString(local.background)
|
|
||||||
) {
|
|
||||||
promises.push(
|
|
||||||
api.settings.putEntry(
|
|
||||||
'display',
|
|
||||||
'background',
|
|
||||||
getBackgroundString(local.background)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
promises.push(
|
|
||||||
api.settings.putEntry(
|
|
||||||
'display',
|
|
||||||
'backgroundType',
|
|
||||||
local.background?.type
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(local.remoteContentPolicy).forEach((_key) => {
|
|
||||||
const key = _key as keyof RemoteContentPolicy;
|
|
||||||
const localVal = local.remoteContentPolicy[key];
|
|
||||||
if (localVal !== remoteContentPolicy[key]) {
|
|
||||||
promises.push(
|
|
||||||
api.settings.putEntry('remoteContentPolicy', key, localVal)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
localStorage.removeItem('localReducer');
|
|
||||||
};
|
|
||||||
}
|
|
@ -10,8 +10,18 @@ const makeIndexes = () => new Map([
|
|||||||
['other', []]
|
['other', []]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export interface OmniboxItem {
|
||||||
|
title: string;
|
||||||
|
link: string;
|
||||||
|
app: string;
|
||||||
|
host: string;
|
||||||
|
description: string;
|
||||||
|
shiftLink: string;
|
||||||
|
shiftDescription: string;
|
||||||
|
}
|
||||||
|
|
||||||
// result schematic
|
// result schematic
|
||||||
const result = function(title, link, app, host, description = 'Open', shiftLink = null, shiftDescription = null) {
|
const result = function(title: string, link: string, app: string, host: string, description = 'Open', shiftLink = null as string | null, shiftDescription = null as string | null): OmniboxItem {
|
||||||
return {
|
return {
|
||||||
'title': title,
|
'title': title,
|
||||||
'link': link,
|
'link': link,
|
||||||
@ -93,7 +103,7 @@ const otherIndex = function(config) {
|
|||||||
return other;
|
return other;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function index(contacts, associations, apps, currentGroup, groups, hide) {
|
export default function index(contacts, associations, apps, currentGroup, groups, hide): Map<string, OmniboxItem[]> {
|
||||||
const indexes = makeIndexes();
|
const indexes = makeIndexes();
|
||||||
indexes.set('ships', shipIndex(contacts));
|
indexes.set('ships', shipIndex(contacts));
|
||||||
// all metadata from all apps is indexed
|
// all metadata from all apps is indexed
|
||||||
@ -117,7 +127,7 @@ export default function index(contacts, associations, apps, currentGroup, groups
|
|||||||
let app = each['app-name'];
|
let app = each['app-name'];
|
||||||
if (each['app-name'] === 'contacts') {
|
if (each['app-name'] === 'contacts') {
|
||||||
app = 'groups';
|
app = 'groups';
|
||||||
};
|
}
|
||||||
|
|
||||||
if (each['app-name'] === 'graph') {
|
if (each['app-name'] === 'graph') {
|
||||||
app = each.metadata.config.graph;
|
app = each.metadata.config.graph;
|
||||||
@ -159,4 +169,4 @@ export default function index(contacts, associations, apps, currentGroup, groups
|
|||||||
indexes.set('other', otherIndex(hide));
|
indexes.set('other', otherIndex(hide));
|
||||||
|
|
||||||
return indexes;
|
return indexes;
|
||||||
};
|
}
|
38
pkg/interface/src/logic/lib/suspend.ts
Normal file
38
pkg/interface/src/logic/lib/suspend.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export type SuspendState = 'result' | 'error' | 'pending';
|
||||||
|
|
||||||
|
export interface Suspender<T> {
|
||||||
|
read: () => T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function suspend<T>(awaiting: Promise<T>): Suspender<T> {
|
||||||
|
let state: SuspendState = 'pending';
|
||||||
|
let result: T | null = null;
|
||||||
|
|
||||||
|
const promise = awaiting
|
||||||
|
.then((res) => {
|
||||||
|
state = 'result';
|
||||||
|
result = res;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
state = 'error';
|
||||||
|
result = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
read: () => {
|
||||||
|
if (state === 'result') {
|
||||||
|
return result!;
|
||||||
|
} else if (state === 'error') {
|
||||||
|
throw result;
|
||||||
|
} else {
|
||||||
|
throw promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function suspendWithResult<T>(result: T): Suspender<T> {
|
||||||
|
return {
|
||||||
|
read: () => result
|
||||||
|
};
|
||||||
|
}
|
@ -5,7 +5,7 @@ const URL_REGEX = new RegExp(String(/^([^[\]]*?)(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;?
|
|||||||
|
|
||||||
const PATP_REGEX = /^([\s\S]*?)(~[a-z_-]+)([\s\S]*)/;
|
const PATP_REGEX = /^([\s\S]*?)(~[a-z_-]+)([\s\S]*)/;
|
||||||
|
|
||||||
const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z]+)([\s\S]*)/.source));
|
const GROUP_REGEX = new RegExp(String(/^([\s\S ]*?)(~[-a-z_]+\/[-a-z0-9]+)([\s\S]*)/.source));
|
||||||
|
|
||||||
const convertToGroupRef = group => `web+urbitgraph://group/${group}`;
|
const convertToGroupRef = group => `web+urbitgraph://group/${group}`;
|
||||||
|
|
||||||
@ -33,9 +33,10 @@ const raceRegexes = (str) => {
|
|||||||
content = { url: link[2] };
|
content = { url: link[2] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(groupRef && groupRef[1].length < pfix?.length) {
|
const perma = parsePermalink(convertToGroupRef(groupRef?.[2]));
|
||||||
|
const [,,host] = perma?.group.split('/') ?? [];
|
||||||
|
if(groupRef && groupRef[1].length < pfix?.length && Boolean(perma) && urbitOb.isValidPatp(host)) {
|
||||||
pfix = groupRef[1];
|
pfix = groupRef[1];
|
||||||
const perma = parsePermalink(convertToGroupRef(groupRef[2]));
|
|
||||||
content = permalinkToReference(perma);
|
content = permalinkToReference(perma);
|
||||||
sfix = groupRef[3];
|
sfix = groupRef[3];
|
||||||
}
|
}
|
||||||
|
@ -113,4 +113,19 @@ describe('tokenizeMessage', () => {
|
|||||||
expect(text).toBe('. foo');
|
expect(text).toBe('. foo');
|
||||||
expect(url).toBe('https://tlon.io/test');
|
expect(url).toBe('https://tlon.io/test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should ignore malformed group links', () => {
|
||||||
|
const example = 'test ~zoid/fakegroup';
|
||||||
|
const [{ text }, ...rest] = tokenizeMessage(example);
|
||||||
|
expect(text).toBe(example);
|
||||||
|
expect(rest.length).toBe(0);
|
||||||
|
});
|
||||||
|
it('should handle groups with numbers', () => {
|
||||||
|
const example = 'oh no, ~sampel/group-123-abc';
|
||||||
|
|
||||||
|
const [{ text }, { reference }] = tokenizeMessage(example);
|
||||||
|
expect(text).toBe('oh no, ');
|
||||||
|
expect(reference.group).toBe('/ship/~sampel/group-123-abc');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DragEvent, useCallback, useEffect, useState } from 'react';
|
import { DragEvent, useCallback, useEffect, useState, useMemo } from 'react';
|
||||||
|
|
||||||
function validateDragEvent(e: DragEvent): FileList | File[] | true | null {
|
function validateDragEvent(e: DragEvent): FileList | File[] | true | null {
|
||||||
const files: File[] = [];
|
const files: File[] = [];
|
||||||
@ -43,7 +43,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
|||||||
}
|
}
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
},
|
},
|
||||||
[setDragging]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDrop = useCallback(
|
const onDrop = useCallback(
|
||||||
@ -56,7 +56,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
dragged(files, e);
|
dragged(files, e);
|
||||||
},
|
},
|
||||||
[setDragging, dragged]
|
[dragged]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDragOver = useCallback(
|
const onDragOver = useCallback(
|
||||||
@ -77,7 +77,7 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
|||||||
setDragging(false);
|
setDragging(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setDragging]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -92,12 +92,12 @@ export function useFileDrag(dragged: (f: FileList | File[], e: DragEvent) => voi
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const bind = {
|
const bind = useMemo(() => ({
|
||||||
onDragLeave,
|
onDragLeave,
|
||||||
onDragOver,
|
onDragOver,
|
||||||
onDrop,
|
onDrop,
|
||||||
onDragEnter
|
onDragEnter
|
||||||
};
|
}), [onDragEnter, onDragOver, onDrop, onDragEnter]);
|
||||||
|
|
||||||
return { bind, dragging };
|
return useMemo(() => ({ bind, dragging }), [bind, dragging]);
|
||||||
}
|
}
|
||||||
|
77
pkg/interface/src/logic/lib/useFileUpload.ts
Normal file
77
pkg/interface/src/logic/lib/useFileUpload.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { useState, ClipboardEvent } from 'react';
|
||||||
|
import { useFileDrag } from './useDrag';
|
||||||
|
import useStorage, { IuseStorage } from './useStorage';
|
||||||
|
|
||||||
|
export type FileUploadSource = 'drag' | 'paste' | 'direct';
|
||||||
|
|
||||||
|
interface FileUploadEventHandlers {
|
||||||
|
onSuccess: (url: string, source: FileUploadSource) => void;
|
||||||
|
onError?: (error: Error) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FileUploadHandler {
|
||||||
|
onFiles: (
|
||||||
|
files: FileList | File[],
|
||||||
|
storage?: IuseStorage,
|
||||||
|
uploadSource?: FileUploadSource
|
||||||
|
) => void | Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFileUploadHandler(obj: any): obj is FileUploadHandler {
|
||||||
|
return typeof obj.onFiles === 'function';
|
||||||
|
}
|
||||||
|
|
||||||
|
type useFileUploadParams = {
|
||||||
|
multiple?: boolean;
|
||||||
|
} & (FileUploadEventHandlers | FileUploadHandler)
|
||||||
|
|
||||||
|
export function useFileUpload({ multiple = true, ...params }: useFileUploadParams) {
|
||||||
|
const storage = useStorage();
|
||||||
|
const {
|
||||||
|
canUpload, uploadDefault
|
||||||
|
} = storage;
|
||||||
|
const [source, setSource] = useState<FileUploadSource>('paste');
|
||||||
|
const drag = useFileDrag(f => uploadFiles(f, 'drag'));
|
||||||
|
|
||||||
|
function onPaste(event: ClipboardEvent) {
|
||||||
|
if (!event.clipboardData || !event.clipboardData.files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
uploadFiles(event.clipboardData.files, 'paste');
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadFiles(files: FileList | File[], uploadSource: FileUploadSource) {
|
||||||
|
if (isFileUploadHandler(params)) {
|
||||||
|
return params.onFiles(files, storage, uploadSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canUpload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSource(uploadSource);
|
||||||
|
|
||||||
|
const { onSuccess, onError } = params as FileUploadEventHandlers;
|
||||||
|
const fileArray = Array.from(files);
|
||||||
|
const toUpload = multiple ? fileArray : _.take(fileArray);
|
||||||
|
toUpload.forEach((file) => {
|
||||||
|
uploadDefault(file)
|
||||||
|
.then(url => onSuccess(url, source))
|
||||||
|
.catch((err: Error) => {
|
||||||
|
console.log(err);
|
||||||
|
onError && onError(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...storage,
|
||||||
|
onPaste,
|
||||||
|
drag
|
||||||
|
};
|
||||||
|
}
|
@ -36,10 +36,10 @@ export function useLazyScroll(
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if((oldCount > count) && ref.current) {
|
if((oldCount > count) && ref.current && !isLoading) {
|
||||||
loadUntil(ref.current);
|
loadUntil(ref.current);
|
||||||
}
|
}
|
||||||
}, [count]);
|
}, [count, isLoading]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!ready) {
|
if(!ready) {
|
||||||
@ -48,7 +48,7 @@ export function useLazyScroll(
|
|||||||
}, [ready]);
|
}, [ready]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current || isDone || !ready) {
|
if (!ref.current || isDone || !ready || isLoading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const scroll = ref.current;
|
const scroll = ref.current;
|
||||||
@ -64,7 +64,7 @@ export function useLazyScroll(
|
|||||||
return () => {
|
return () => {
|
||||||
ref.current?.removeEventListener('scroll', onScroll);
|
ref.current?.removeEventListener('scroll', onScroll);
|
||||||
};
|
};
|
||||||
}, [ref?.current, ready, isDone]);
|
}, [ref?.current, ready, isDone, isLoading]);
|
||||||
|
|
||||||
return { isDone, isLoading };
|
return { isDone, isLoading };
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useMemo, useEffect, useState } from 'react';
|
||||||
|
|
||||||
function retrieve<T>(key: string, initial: T): T {
|
export function retrieve<T>(key: string, initial: T): T {
|
||||||
const s = localStorage.getItem(key);
|
const s = localStorage.getItem(key);
|
||||||
if (s) {
|
if (s) {
|
||||||
try {
|
try {
|
||||||
@ -12,26 +12,16 @@ function retrieve<T>(key: string, initial: T): T {
|
|||||||
return initial;
|
return initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SetStateFunc<T> {
|
|
||||||
(t: T): T;
|
|
||||||
}
|
|
||||||
// See microsoft/typescript#37663 for filed bug
|
|
||||||
type SetState<T> = T extends any ? SetStateFunc<T> : never;
|
|
||||||
export function useLocalStorageState<T>(key: string, initial: T): any {
|
export function useLocalStorageState<T>(key: string, initial: T): any {
|
||||||
const [state, _setState] = useState(() => retrieve(key, initial));
|
const [state, setState] = useState(() => retrieve(key, initial));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
_setState(retrieve(key, initial));
|
setState(retrieve(key, initial));
|
||||||
}, [key]);
|
}, [key]);
|
||||||
|
|
||||||
const setState = useCallback(
|
useEffect(() => {
|
||||||
(s: SetState<T>) => {
|
localStorage.setItem(key, JSON.stringify(state));
|
||||||
const updated = typeof s === 'function' ? s(state) : s;
|
}, [state]);
|
||||||
_setState(updated);
|
|
||||||
localStorage.setItem(key, JSON.stringify(updated));
|
|
||||||
},
|
|
||||||
[_setState, key, state]
|
|
||||||
);
|
|
||||||
|
|
||||||
return [state, setState] as const;
|
return useMemo(() => [state, setState] as const, [state, setState]);
|
||||||
}
|
}
|
||||||
|
29
pkg/interface/src/logic/lib/useResize.ts
Normal file
29
pkg/interface/src/logic/lib/useResize.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { useEffect, useMemo, useRef } from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export function useResize<T extends HTMLElement>(
|
||||||
|
callback: (entry: ResizeObserverEntry, observer: ResizeObserver) => void
|
||||||
|
) {
|
||||||
|
const ref = useRef<T>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function observer(
|
||||||
|
entries: ResizeObserverEntry[],
|
||||||
|
observer: ResizeObserver
|
||||||
|
) {
|
||||||
|
for (const entry of _.flatten(entries)) {
|
||||||
|
callback(entry, observer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resizeObs = new ResizeObserver(observer);
|
||||||
|
resizeObs.observe(ref.current, { box: 'border-box' });
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
resizeObs.unobserve(ref.current);
|
||||||
|
};
|
||||||
|
}, [callback]);
|
||||||
|
|
||||||
|
const bind = useMemo(() => ({ ref }), [ref]);
|
||||||
|
|
||||||
|
return bind;
|
||||||
|
}
|
34
pkg/interface/src/logic/lib/useUrlField.tsx
Normal file
34
pkg/interface/src/logic/lib/useUrlField.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { useField } from 'formik';
|
||||||
|
import { MutableRefObject, useCallback, useMemo } from 'react';
|
||||||
|
import useStorage from './useStorage';
|
||||||
|
|
||||||
|
export function useUrlField(
|
||||||
|
id: string,
|
||||||
|
ref: MutableRefObject<HTMLInputElement>
|
||||||
|
) {
|
||||||
|
const [field, meta, helpers] = useField(id);
|
||||||
|
const { setValue, setError } = helpers;
|
||||||
|
|
||||||
|
const storage = useStorage();
|
||||||
|
const { uploadDefault, canUpload } = storage;
|
||||||
|
|
||||||
|
const onImageUpload = useCallback(async () => {
|
||||||
|
const file = ref.current?.files?.item(0);
|
||||||
|
|
||||||
|
if (!file || !canUpload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const url = await uploadDefault(file);
|
||||||
|
setValue(url);
|
||||||
|
} catch (e) {
|
||||||
|
setError(e.message);
|
||||||
|
}
|
||||||
|
}, [ref.current, uploadDefault, canUpload, setValue]);
|
||||||
|
const extStorage = useMemo(() => ({ ...storage, onImageUpload }), [
|
||||||
|
storage,
|
||||||
|
onImageUpload
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [field, meta, helpers, extStorage] as const;
|
||||||
|
}
|
@ -523,3 +523,32 @@ export const favicon = () => {
|
|||||||
});
|
});
|
||||||
return svg;
|
return svg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function binaryIndexOf(arr: BigInteger[], target: BigInteger): number | undefined {
|
||||||
|
let leftBound = 0;
|
||||||
|
let rightBound = arr.length - 1;
|
||||||
|
while(leftBound <= rightBound) {
|
||||||
|
const halfway = Math.floor((leftBound + rightBound) / 2);
|
||||||
|
if(arr[halfway].greater(target)) {
|
||||||
|
leftBound = halfway + 1;
|
||||||
|
} else if (arr[halfway].lesser(target)) {
|
||||||
|
rightBound = halfway - 1;
|
||||||
|
} else {
|
||||||
|
return halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function jsonFetch<T>(info: RequestInfo, init?: RequestInit): Promise<T> {
|
||||||
|
const res = await fetch(info, init);
|
||||||
|
if(!res.ok) {
|
||||||
|
throw new Error('Bad Fetch Response');
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
return data as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clone<T>(a: T) {
|
||||||
|
return JSON.parse(JSON.stringify(a)) as T;
|
||||||
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import { Cage } from '~/types/cage';
|
|
||||||
import { StoreState } from '../store/type';
|
|
||||||
|
|
||||||
type LocalState = Pick<StoreState, 'connection'>;
|
|
||||||
|
|
||||||
export default class ConnectionReducer<S extends LocalState> {
|
|
||||||
reduce(json: Cage, state: S) {
|
|
||||||
if('connection' in json && json.connection) {
|
|
||||||
console.log(`Conn: ${json.connection}`);
|
|
||||||
state.connection = json.connection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
import { ContactUpdate, deSig } from '@urbit/api';
|
import { ContactUpdate, deSig } from '@urbit/api';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { reduceState } from '../state/base';
|
import { BaseState } from '../state/base';
|
||||||
import useContactState, { ContactState } from '../state/contact';
|
import { ContactState as State } from '../state/contact';
|
||||||
|
|
||||||
|
type ContactState = State & BaseState<State>;
|
||||||
|
|
||||||
const initial = (json: ContactUpdate, state: ContactState): ContactState => {
|
const initial = (json: ContactUpdate, state: ContactState): ContactState => {
|
||||||
const data = _.get(json, 'initial', false);
|
const data = _.get(json, 'initial', false);
|
||||||
@ -71,23 +73,18 @@ const setPublic = (json: ContactUpdate, state: ContactState): ContactState => {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ContactReducer = (json) => {
|
export const reduceNacks = (json, state: ContactState): ContactState => {
|
||||||
const data: ContactUpdate = _.get(json, 'contact-update', false);
|
const data = json?.resource;
|
||||||
if (data) {
|
if(data) {
|
||||||
reduceState<ContactState, ContactUpdate>(useContactState, data, [
|
state.nackedContacts.add(`~${data.res}`);
|
||||||
initial,
|
|
||||||
add,
|
|
||||||
remove,
|
|
||||||
edit,
|
|
||||||
setPublic
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: better isolation
|
|
||||||
const res = _.get(json, 'resource', false);
|
|
||||||
if (res) {
|
|
||||||
useContactState.setState({
|
|
||||||
nackedContacts: useContactState.getState().nackedContacts.add(`~${res.ship}`)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reduce = [
|
||||||
|
initial,
|
||||||
|
add,
|
||||||
|
remove,
|
||||||
|
edit,
|
||||||
|
setPublic
|
||||||
|
];
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
import type { Cage } from '~/types/cage';
|
|
||||||
import type { GcpToken } from '../../types/gcp-state';
|
|
||||||
import { reduceState } from '../state/base';
|
|
||||||
import useStorageState, { StorageState } from '../state/storage';
|
|
||||||
|
|
||||||
export default class GcpReducer {
|
|
||||||
reduce(json: Cage) {
|
|
||||||
reduceState<StorageState, any>(useStorageState, json, [
|
|
||||||
reduceToken
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const reduceToken = (json: Cage, state: StorageState): StorageState => {
|
|
||||||
const data = json['gcp-token'];
|
|
||||||
if (data) {
|
|
||||||
setToken(data, state);
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setToken = (data: any, state: StorageState): StorageState => {
|
|
||||||
if (isToken(data)) {
|
|
||||||
state.gcp.token = data;
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isToken = (token: any): token is GcpToken => {
|
|
||||||
return (typeof(token.accessKey) === 'string' &&
|
|
||||||
typeof(token.expiresIn) === 'number');
|
|
||||||
};
|
|
@ -7,8 +7,13 @@ import BigIntArrayOrderedMap, {
|
|||||||
import bigInt, { BigInteger } from 'big-integer';
|
import bigInt, { BigInteger } from 'big-integer';
|
||||||
import produce from 'immer';
|
import produce from 'immer';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { reduceState } from '../state/base';
|
import { BaseState, reduceState } from '../state/base';
|
||||||
import useGraphState, { GraphState } from '../state/graph';
|
import useGraphState, { GraphState as State } from '../state/graph';
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
|
import { unstable_batchedUpdates } from 'react-dom';
|
||||||
|
|
||||||
|
type GraphState = State & BaseState<State>;
|
||||||
|
|
||||||
const mapifyChildren = (children) => {
|
const mapifyChildren = (children) => {
|
||||||
return new BigIntOrderedMap().gas(
|
return new BigIntOrderedMap().gas(
|
||||||
@ -245,9 +250,6 @@ export const addNodes = (json, state) => {
|
|||||||
post,
|
post,
|
||||||
resource
|
resource
|
||||||
) => {
|
) => {
|
||||||
if (!post.hash) {
|
|
||||||
return [graph, flatGraph, threadGraphs];
|
|
||||||
}
|
|
||||||
const timestamp = post['time-sent'];
|
const timestamp = post['time-sent'];
|
||||||
|
|
||||||
if (state.graphTimesentMap[resource][timestamp]) {
|
if (state.graphTimesentMap[resource][timestamp]) {
|
||||||
@ -403,26 +405,17 @@ export const addNodes = (json, state) => {
|
|||||||
const removePosts = (json, state: GraphState): GraphState => {
|
const removePosts = (json, state: GraphState): GraphState => {
|
||||||
const _remove = (graph, index) => {
|
const _remove = (graph, index) => {
|
||||||
const child = graph.get(index[0]);
|
const child = graph.get(index[0]);
|
||||||
|
if(!child) {
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
if (index.length === 1) {
|
if (index.length === 1) {
|
||||||
if (child) {
|
return graph.set(index[0], {
|
||||||
return graph.set(index[0], {
|
post: child.post.hash || '',
|
||||||
post: child.post.hash || '',
|
children: child.children
|
||||||
children: child.children
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (child) {
|
const node = { ...child, children: _remove(child.children, index.slice(1)) };
|
||||||
_remove(child.children, index.slice(1));
|
return graph.set(index[0], node);
|
||||||
return graph.set(index[0], child);
|
|
||||||
} else {
|
|
||||||
const child = graph.get(index[0]);
|
|
||||||
if (child) {
|
|
||||||
return graph.set(index[0], produce((draft: any) => {
|
|
||||||
draft.children = _remove(draft.children, index.slice(1));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return graph;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -445,39 +438,38 @@ const removePosts = (json, state: GraphState): GraphState => {
|
|||||||
return state;
|
return state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reduceDm = [
|
||||||
|
acceptOrRejectDm,
|
||||||
|
pendings,
|
||||||
|
setScreen
|
||||||
|
];
|
||||||
|
|
||||||
export const GraphReducer = (json) => {
|
export const GraphReducer = (json) => {
|
||||||
const data = _.get(json, 'graph-update', false);
|
const data = _.get(json, 'graph-update', false);
|
||||||
|
|
||||||
if (data) {
|
unstable_batchedUpdates(() => {
|
||||||
reduceState<GraphState, any>(useGraphState, data, [
|
if (data) {
|
||||||
keys,
|
reduceState<GraphState, any>(useGraphState, data, [
|
||||||
addGraph,
|
keys,
|
||||||
removeGraph,
|
addGraph,
|
||||||
addNodes,
|
removeGraph,
|
||||||
removePosts
|
addNodes,
|
||||||
]);
|
removePosts
|
||||||
}
|
]);
|
||||||
const loose = _.get(json, 'graph-update-loose', false);
|
}
|
||||||
if(loose) {
|
const loose = _.get(json, 'graph-update-loose', false);
|
||||||
reduceState<GraphState, any>(useGraphState, loose, [addNodesLoose]);
|
if(loose) {
|
||||||
}
|
reduceState<GraphState, any>(useGraphState, loose, [addNodesLoose]);
|
||||||
|
}
|
||||||
|
|
||||||
const flat = _.get(json, 'graph-update-flat', false);
|
const flat = _.get(json, 'graph-update-flat', false);
|
||||||
if (flat) {
|
if (flat) {
|
||||||
reduceState<GraphState, any>(useGraphState, flat, [addNodesFlat]);
|
reduceState<GraphState, any>(useGraphState, flat, [addNodesFlat]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const thread = _.get(json, 'graph-update-thread', false);
|
const thread = _.get(json, 'graph-update-thread', false);
|
||||||
if (thread) {
|
if (thread) {
|
||||||
reduceState<GraphState, any>(useGraphState, thread, [addNodesThread]);
|
reduceState<GraphState, any>(useGraphState, thread, [addNodesThread]);
|
||||||
}
|
}
|
||||||
const dm = _.get(json, 'dm-hook-action', false);
|
});
|
||||||
if(dm) {
|
|
||||||
console.log(dm);
|
|
||||||
reduceState<GraphState, any>(useGraphState, dm, [
|
|
||||||
acceptOrRejectDm,
|
|
||||||
pendings,
|
|
||||||
setScreen
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user