mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-25 16:05:27 +03:00
Merge branch 'develop' into i/6103/ames-refactor
This commit is contained in:
commit
2724523a26
@ -1,3 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
ignorePatterns: ["**/*"]
|
|
||||||
};
|
|
62
.github/workflows/publish-npm-packages.yml
vendored
62
.github/workflows/publish-npm-packages.yml
vendored
@ -1,62 +0,0 @@
|
|||||||
name: publish-npm-packages
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'master'
|
|
||||||
paths:
|
|
||||||
- 'pkg/npm/**'
|
|
||||||
jobs:
|
|
||||||
publish-api:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: "Publish '@urbit/api' if a new version is available"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- run: 'npm install'
|
|
||||||
working-directory: 'pkg/npm/api'
|
|
||||||
- uses: JS-DevTools/npm-publish@v1
|
|
||||||
with:
|
|
||||||
check-version: true
|
|
||||||
package: './pkg/npm/api/package.json'
|
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
||||||
publish-http-api:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: "Publish '@urbit/http-api' if a new version is available"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- run: 'npm install'
|
|
||||||
working-directory: 'pkg/npm/http-api'
|
|
||||||
- uses: JS-DevTools/npm-publish@v1
|
|
||||||
with:
|
|
||||||
check-version: true
|
|
||||||
package: './pkg/npm/http-api/package.json'
|
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
||||||
publish-eslint-config:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: "Publish '@urbit/eslint-config' if a new version is available"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: '14'
|
|
||||||
- run: 'npm install'
|
|
||||||
working-directory: 'pkg/npm/eslint-config'
|
|
||||||
- uses: JS-DevTools/npm-publish@v1
|
|
||||||
with:
|
|
||||||
check-version: true
|
|
||||||
package: './pkg/npm/eslint-config/package.json'
|
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|
4
.github/workflows/vere.yml
vendored
4
.github/workflows/vere.yml
vendored
@ -61,12 +61,12 @@ jobs:
|
|||||||
# for the docker build. We don't want in on Mac, where it isn't but
|
# for the docker build. We don't want in on Mac, where it isn't but
|
||||||
# it breaks the nix install. The two `if` clauses should be mutually
|
# it breaks the nix install. The two `if` clauses should be mutually
|
||||||
# exclusive
|
# exclusive
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v20
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
system-features = nixos-test benchmark big-parallel kvm
|
system-features = nixos-test benchmark big-parallel kvm
|
||||||
if: ${{ matrix.type == 'linux' }}
|
if: ${{ matrix.type == 'linux' }}
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v20
|
||||||
if: ${{ matrix.os != 'ubuntu-latest' }}
|
if: ${{ matrix.os != 'ubuntu-latest' }}
|
||||||
|
|
||||||
- uses: cachix/cachix-action@v10
|
- uses: cachix/cachix-action@v10
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
bin
|
|
||||||
doc
|
|
||||||
extras
|
|
||||||
nix
|
|
||||||
pkg/arvo
|
|
||||||
pkg/base-dev
|
|
||||||
pkg/docker-image
|
|
||||||
pkg/ent
|
|
||||||
pkg/garden
|
|
||||||
pkg/garden-dev
|
|
||||||
pkg/ge-additions
|
|
||||||
pkg/herb
|
|
||||||
pkg/hs
|
|
||||||
pkg/libaes_siv
|
|
||||||
pkg/urbit
|
|
||||||
sh
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"packages": [
|
|
||||||
"pkg/npm/*",
|
|
||||||
"pkg/btc-wallet",
|
|
||||||
"pkg/interface",
|
|
||||||
"pkg/grid"
|
|
||||||
],
|
|
||||||
"version": "independent"
|
|
||||||
}
|
|
15716
package-lock.json
generated
15716
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "root",
|
|
||||||
"private": true,
|
|
||||||
"engines": {
|
|
||||||
"node": "16.14.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"eslint": "^7.29.0",
|
|
||||||
"husky": "^6.0.0",
|
|
||||||
"lerna": "^4.0.0",
|
|
||||||
"lint-staged": "^11.1.2",
|
|
||||||
"prettier": "^2.3.2"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"watch-libs": "lerna run watch --no-private --parallel",
|
|
||||||
"build-libs": "lerna run build --no-private",
|
|
||||||
"test": "lerna run test",
|
|
||||||
"bootstrap": "lerna bootstrap",
|
|
||||||
"build:prod": "lerna run build:prod"
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,8 @@
|
|||||||
/+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln
|
/+ drum=hood-drum, helm=hood-helm, kiln=hood-kiln
|
||||||
|%
|
|%
|
||||||
+$ state
|
+$ state
|
||||||
$~ [%25 *state:drum *state:helm *state:kiln]
|
$~ [%26 *state:drum *state:helm *state:kiln]
|
||||||
$>(%25 any-state)
|
$>(%26 any-state)
|
||||||
::
|
::
|
||||||
+$ any-state
|
+$ any-state
|
||||||
$% [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)]
|
$% [ver=?(%1 %2 %3 %4 %5 %6) lac=(map @tas fin-any-state)]
|
||||||
@ -26,6 +26,7 @@
|
|||||||
[%23 drum=state-4:drum helm=state-2:helm kiln=state-9:kiln]
|
[%23 drum=state-4:drum helm=state-2:helm kiln=state-9:kiln]
|
||||||
[%24 drum=state-4:drum helm=state-2:helm kiln=state-10:kiln]
|
[%24 drum=state-4:drum helm=state-2:helm kiln=state-10:kiln]
|
||||||
[%25 drum=state-5:drum helm=state-2:helm kiln=state-10:kiln]
|
[%25 drum=state-5:drum helm=state-2:helm kiln=state-10:kiln]
|
||||||
|
[%26 drum=state-6:drum helm=state-2:helm kiln=state-10:kiln]
|
||||||
==
|
==
|
||||||
+$ any-state-tuple
|
+$ any-state-tuple
|
||||||
$: drum=any-state:drum
|
$: drum=any-state:drum
|
||||||
@ -124,6 +125,7 @@
|
|||||||
|= [=wire syn=sign-arvo]
|
|= [=wire syn=sign-arvo]
|
||||||
^- step:agent:gall
|
^- step:agent:gall
|
||||||
?+ wire ~|([%hood-bad-wire wire] !!)
|
?+ wire ~|([%hood-bad-wire wire] !!)
|
||||||
|
[%drum *] =^(c drum.state (take-arvo:drum-core t.wire syn) [c this])
|
||||||
[%helm *] =^(c helm.state (take-arvo:helm-core t.wire syn) [c this])
|
[%helm *] =^(c helm.state (take-arvo:helm-core t.wire syn) [c this])
|
||||||
[%kiln *] =^(c kiln.state (take-arvo:kiln-core t.wire syn) [c this])
|
[%kiln *] =^(c kiln.state (take-arvo:kiln-core t.wire syn) [c this])
|
||||||
==
|
==
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
:: Helm: Adjust vane error verbosity knob
|
:: Drum: Adjust vane error verbosity knob
|
||||||
::
|
::
|
||||||
/? 310
|
/? 310
|
||||||
::
|
::
|
||||||
@ -6,5 +6,5 @@
|
|||||||
::
|
::
|
||||||
:- %say
|
:- %say
|
||||||
|= [^ [error-tag=@tas level=?(%hush %soft %loud) ~] ~]
|
|= [^ [error-tag=@tas level=?(%hush %soft %loud) ~] ~]
|
||||||
:- %helm-knob
|
:- %drum-knob
|
||||||
[error-tag level]
|
[error-tag level]
|
||||||
|
@ -1,21 +1,28 @@
|
|||||||
/- *sole
|
/- *sole
|
||||||
/+ sole
|
/+ sole
|
||||||
|%
|
|%
|
||||||
+$ state state-5
|
+$ state state-6
|
||||||
+$ any-state
|
+$ any-state
|
||||||
$~ *state
|
$~ *state
|
||||||
$% state-5
|
$% state-6
|
||||||
|
state-5
|
||||||
state-4
|
state-4
|
||||||
state-3
|
state-3
|
||||||
state-2
|
state-2
|
||||||
==
|
==
|
||||||
|
+$ state-6 [%6 pith-6]
|
||||||
+$ state-5 [%5 pith-5]
|
+$ state-5 [%5 pith-5]
|
||||||
+$ state-4 [%4 pith-4]
|
+$ state-4 [%4 pith-4]
|
||||||
+$ state-3 [%3 pith-3]
|
+$ state-3 [%3 pith-3]
|
||||||
+$ state-2 [%2 pith-2]
|
+$ state-2 [%2 pith-2]
|
||||||
::
|
::
|
||||||
+$ pith-5
|
+$ pith-6
|
||||||
$: bin=(map @ source) :: terminals
|
$: bin=(map @ source) :: terminals
|
||||||
|
nob=(map @tas ?(%hush %soft %loud))
|
||||||
|
==
|
||||||
|
::
|
||||||
|
+$ pith-5
|
||||||
|
$: bin=(map @ source)
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
+$ pith-4
|
+$ pith-4
|
||||||
@ -130,7 +137,9 @@
|
|||||||
++ klr klr:format
|
++ klr klr:format
|
||||||
+$ state ^state :: proxy
|
+$ state ^state :: proxy
|
||||||
+$ any-state ^any-state :: proxy
|
+$ any-state ^any-state :: proxy
|
||||||
++ on-init (poke-link %$ our.hid %dojo)
|
++ on-init
|
||||||
|
=+ out=(poke-link %$ our.hid %dojo)
|
||||||
|
out(- [hear-logs -.out])
|
||||||
::
|
::
|
||||||
++ prep
|
++ prep
|
||||||
|= s=@tas
|
|= s=@tas
|
||||||
@ -191,11 +200,16 @@
|
|||||||
=^ txt +> ?@(arg [arg +>] [+.arg (prep -.arg)])
|
=^ txt +> ?@(arg [arg +>] [+.arg (prep -.arg)])
|
||||||
se-abet:(se-blit-sys [%sav pax txt]) ::
|
se-abet:(se-blit-sys [%sav pax txt]) ::
|
||||||
::
|
::
|
||||||
|
++ poke-knob
|
||||||
|
|= [tag=@tas lev=?(%hush %soft %loud)]
|
||||||
|
se-abet(nob (~(put by nob) tag lev))
|
||||||
|
::
|
||||||
++ poke
|
++ poke
|
||||||
|= [=mark =vase]
|
|= [=mark =vase]
|
||||||
?> =(our src):hid
|
?> =(our src):hid
|
||||||
?+ mark ~|([%poke-drum-bad-mark mark] !!)
|
?+ mark ~|([%poke-drum-bad-mark mark] !!)
|
||||||
%dill-poke =;(f (f !<(_+<.f vase)) poke-dill)
|
%dill-poke =;(f (f !<(_+<.f vase)) poke-dill)
|
||||||
|
%drum-knob =;(f (f !<(_+<.f vase)) poke-knob)
|
||||||
%drum-exit =;(f (f !<(_+<.f vase)) poke-exit)
|
%drum-exit =;(f (f !<(_+<.f vase)) poke-exit)
|
||||||
%drum-link =;(f (f !<(_+<.f vase)) poke-link)
|
%drum-link =;(f (f !<(_+<.f vase)) poke-link)
|
||||||
%drum-put =;(f (f !<(_+<.f vase)) poke-put)
|
%drum-put =;(f (f !<(_+<.f vase)) poke-put)
|
||||||
@ -229,7 +243,9 @@
|
|||||||
[%mod -.b p.b]
|
[%mod -.b p.b]
|
||||||
--
|
--
|
||||||
::
|
::
|
||||||
?> ?=(%5 -.old)
|
=? moz ?=(%5 -.old) [hear-logs moz]
|
||||||
|
=? old ?=(%5 -.old) [%6 bin.old ~]
|
||||||
|
?> ?=(%6 -.old)
|
||||||
=. sat old
|
=. sat old
|
||||||
=. dev (~(gut by bin) ses *source)
|
=. dev (~(gut by bin) ses *source)
|
||||||
this
|
this
|
||||||
@ -276,6 +292,15 @@
|
|||||||
=^ gyl this (open way)
|
=^ gyl this (open way)
|
||||||
~& [%drum-quit src.hid gyl]
|
~& [%drum-quit src.hid gyl]
|
||||||
(se-drop %| gyl)
|
(se-drop %| gyl)
|
||||||
|
::
|
||||||
|
++ hear-logs
|
||||||
|
`card:agent:gall`[%pass /drum/dill/logs %arvo %d %logs [~ ~]]
|
||||||
|
::
|
||||||
|
++ take-arvo
|
||||||
|
|= [way=wire syn=sign-arvo]
|
||||||
|
?> =(/dill/logs way)
|
||||||
|
?> ?=(%logs +<.syn)
|
||||||
|
se-abet:(se-told:(prep %$) told.syn)
|
||||||
:: :: ::
|
:: :: ::
|
||||||
:::: :: ::
|
:::: :: ::
|
||||||
:: :: ::
|
:: :: ::
|
||||||
@ -363,6 +388,19 @@
|
|||||||
~| [inx=inx wag=wag fug=fug eel=eel]
|
~| [inx=inx wag=wag fug=fug eel=eel]
|
||||||
`(snag inx `(list gill:gall)`wag)
|
`(snag inx `(list gill:gall)`wag)
|
||||||
::
|
::
|
||||||
|
++ se-told :: render system output
|
||||||
|
|= =told:dill
|
||||||
|
^+ +>
|
||||||
|
?- -.told
|
||||||
|
%crud =/ lev (~(gut by nob) p.told %loud)
|
||||||
|
=? +>.$ !=(%hush lev)
|
||||||
|
(se-text "crud: %{(trip p.told)} event failed")
|
||||||
|
?. =(%loud lev) +>.$
|
||||||
|
(se-dump q.told)
|
||||||
|
%talk (se-dump (flop p.told)) ::NOTE +se-dump flops internally
|
||||||
|
%text (se-text p.told)
|
||||||
|
==
|
||||||
|
::
|
||||||
++ se-belt :: handle input
|
++ se-belt :: handle input
|
||||||
|= bet=dill-belt:dill
|
|= bet=dill-belt:dill
|
||||||
^+ +>
|
^+ +>
|
||||||
@ -438,7 +476,7 @@
|
|||||||
(se-blit %mor [%hop 0] [%wyp ~] lin [%nel ~] ~)
|
(se-blit %mor [%hop 0] [%wyp ~] lin [%nel ~] ~)
|
||||||
::
|
::
|
||||||
++ se-dump :: print tanks
|
++ se-dump :: print tanks
|
||||||
|= tac=(list tank)
|
|= tac=tang
|
||||||
^+ +>
|
^+ +>
|
||||||
=/ wol=wall
|
=/ wol=wall
|
||||||
(zing (turn (flop tac) |=(a=tank (~(win re a) [0 edg]))))
|
(zing (turn (flop tac) |=(a=tank (~(win re a) [0 edg]))))
|
||||||
|
@ -253,10 +253,6 @@
|
|||||||
|= cong=[msg=@ud mem=@ud] =< abet
|
|= cong=[msg=@ud mem=@ud] =< abet
|
||||||
(emit %pass /helm %arvo %a %cong cong)
|
(emit %pass /helm %arvo %a %cong cong)
|
||||||
::
|
::
|
||||||
++ poke-knob
|
|
||||||
|= [error-tag=@tas level=?(%hush %soft %loud)] =< abet
|
|
||||||
(emit %pass /helm %arvo %d %knob error-tag level)
|
|
||||||
::
|
|
||||||
++ poke-serve
|
++ poke-serve
|
||||||
|= [=binding:eyre =generator:eyre] =< abet
|
|= [=binding:eyre =generator:eyre] =< abet
|
||||||
(emit %pass /helm/serv %arvo %e %serve binding generator)
|
(emit %pass /helm/serv %arvo %e %serve binding generator)
|
||||||
@ -300,7 +296,6 @@
|
|||||||
%helm-gall-sift =;(f (f !<(_+<.f vase)) poke-gall-sift)
|
%helm-gall-sift =;(f (f !<(_+<.f vase)) poke-gall-sift)
|
||||||
%helm-gall-verb =;(f (f !<(_+<.f vase)) poke-gall-verb)
|
%helm-gall-verb =;(f (f !<(_+<.f vase)) poke-gall-verb)
|
||||||
%helm-hi =;(f (f !<(_+<.f vase)) poke-hi)
|
%helm-hi =;(f (f !<(_+<.f vase)) poke-hi)
|
||||||
%helm-knob =;(f (f !<(_+<.f vase)) poke-knob)
|
|
||||||
%helm-pans =;(f (f !<(_+<.f vase)) poke-pans)
|
%helm-pans =;(f (f !<(_+<.f vase)) poke-pans)
|
||||||
%helm-mass =;(f (f !<(_+<.f vase)) poke-mass)
|
%helm-mass =;(f (f !<(_+<.f vase)) poke-mass)
|
||||||
%helm-meld =;(f (f !<(_+<.f vase)) poke-meld)
|
%helm-meld =;(f (f !<(_+<.f vase)) poke-meld)
|
||||||
|
10
pkg/arvo/mar/ted/eval.hoon
Normal file
10
pkg/arvo/mar/ted/eval.hoon
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/- eval=ted-eval
|
||||||
|
|_ put=inpt:eval
|
||||||
|
++ grab |%
|
||||||
|
++ noun inpt:eval
|
||||||
|
--
|
||||||
|
++ grow |%
|
||||||
|
++ noun put
|
||||||
|
--
|
||||||
|
++ grad %noun
|
||||||
|
--
|
5
pkg/arvo/sur/ted/eval.hoon
Normal file
5
pkg/arvo/sur/ted/eval.hoon
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
^?
|
||||||
|
|%
|
||||||
|
+$ deps (list path)
|
||||||
|
+$ inpt $@(cord (pair cord deps))
|
||||||
|
--
|
@ -50,12 +50,7 @@
|
|||||||
|: [a=`@`1 b=`@`1]
|
|: [a=`@`1 b=`@`1]
|
||||||
:: quotient
|
:: quotient
|
||||||
^- @
|
^- @
|
||||||
~_ leaf+"divide-by-zero"
|
-:(dvr a b)
|
||||||
?< =(0 b)
|
|
||||||
=+ c=0
|
|
||||||
|-
|
|
||||||
?: (lth a b) c
|
|
||||||
$(a (sub a b), c +(c))
|
|
||||||
::
|
::
|
||||||
++ dvr
|
++ dvr
|
||||||
~/ %dvr
|
~/ %dvr
|
||||||
@ -63,11 +58,16 @@
|
|||||||
::
|
::
|
||||||
:: a: dividend
|
:: a: dividend
|
||||||
:: b: divisor
|
:: b: divisor
|
||||||
|= [a=@ b=@]
|
|: [a=`@`1 b=`@`1]
|
||||||
:: p: quotient
|
:: p: quotient
|
||||||
:: q: remainder
|
:: q: remainder
|
||||||
^- [p=@ q=@]
|
^- [p=@ q=@]
|
||||||
[(div a b) (mod a b)]
|
~_ leaf+"divide-by-zero"
|
||||||
|
?< =(0 b)
|
||||||
|
=+ c=0
|
||||||
|
|-
|
||||||
|
?: (lth a b) [c a]
|
||||||
|
$(a (sub a b), c +(c))
|
||||||
::
|
::
|
||||||
++ gte
|
++ gte
|
||||||
~/ %gte
|
~/ %gte
|
||||||
@ -150,8 +150,7 @@
|
|||||||
|: [a=`@`1 b=`@`1]
|
|: [a=`@`1 b=`@`1]
|
||||||
:: the remainder
|
:: the remainder
|
||||||
^- @
|
^- @
|
||||||
?< =(0 b)
|
+:(dvr a b)
|
||||||
(sub a (mul b (div a b)))
|
|
||||||
::
|
::
|
||||||
++ mul
|
++ mul
|
||||||
~/ %mul
|
~/ %mul
|
||||||
|
@ -1215,26 +1215,26 @@
|
|||||||
[%meld ~] :: unify memory
|
[%meld ~] :: unify memory
|
||||||
[%pack ~] :: compact memory
|
[%pack ~] :: compact memory
|
||||||
[%trim p=@ud] :: trim kernel state
|
[%trim p=@ud] :: trim kernel state
|
||||||
|
[%logs =told] :: system output
|
||||||
== ::
|
== ::
|
||||||
+$ task :: in request ->$
|
+$ task :: in request ->$
|
||||||
$~ [%vega ~] ::
|
$~ [%vega ~] ::
|
||||||
$% [%boot lit=? p=*] :: weird %dill boot
|
$% [%boot lit=? p=*] :: weird %dill boot
|
||||||
[%crop p=@ud] :: trim kernel state
|
[%crop p=@ud] :: trim kernel state
|
||||||
[%crud p=@tas q=(list tank)] :: print error
|
|
||||||
[%flog p=flog] :: wrapped error
|
[%flog p=flog] :: wrapped error
|
||||||
[%heft ~] :: memory report
|
[%heft ~] :: memory report
|
||||||
$>(%init vane-task) :: after gall ready
|
$>(%init vane-task) :: after gall ready
|
||||||
|
[%logs p=(unit ~)] :: watch system output
|
||||||
[%meld ~] :: unify memory
|
[%meld ~] :: unify memory
|
||||||
[%pack ~] :: compact memory
|
[%pack ~] :: compact memory
|
||||||
[%seat =desk] :: install desk
|
[%seat =desk] :: install desk
|
||||||
[%shot ses=@tas task=session-task] :: task for session
|
[%shot ses=@tas task=session-task] :: task for session
|
||||||
[%talk p=(list tank)] :: print tanks
|
|
||||||
[%text p=tape] :: print tape
|
|
||||||
$>(%trim vane-task) :: trim state
|
$>(%trim vane-task) :: trim state
|
||||||
$>(%vega vane-task) :: report upgrade
|
$>(%vega vane-task) :: report upgrade
|
||||||
[%verb ~] :: verbose mode
|
[%verb ~] :: verbose mode
|
||||||
[%knob tag=term level=?(%hush %soft %loud)] :: error verbosity
|
[%knob tag=term level=?(%hush %soft %loud)] :: deprecated removeme
|
||||||
session-task :: for default session
|
session-task :: for default session
|
||||||
|
told :: system output
|
||||||
== ::
|
== ::
|
||||||
:: ::
|
:: ::
|
||||||
+$ session-task :: session request
|
+$ session-task :: session request
|
||||||
@ -1246,6 +1246,12 @@
|
|||||||
[%shut ~] :: close session
|
[%shut ~] :: close session
|
||||||
[%view ~] :: watch session blits
|
[%view ~] :: watch session blits
|
||||||
== ::
|
== ::
|
||||||
|
:: ::
|
||||||
|
+$ told :: system output
|
||||||
|
$% [%crud p=@tas q=tang] :: error
|
||||||
|
[%talk p=(list tank)] :: tanks (in order)
|
||||||
|
[%text p=tape] :: tape
|
||||||
|
== ::
|
||||||
::
|
::
|
||||||
:::: :: (1d2)
|
:::: :: (1d2)
|
||||||
::
|
::
|
||||||
@ -1279,7 +1285,7 @@
|
|||||||
== ::
|
== ::
|
||||||
+$ dill-belt :: arvo input
|
+$ dill-belt :: arvo input
|
||||||
$% belt :: client input
|
$% belt :: client input
|
||||||
[%cru p=@tas q=(list tank)] :: echo error
|
[%cru p=@tas q=(list tank)] :: errmsg (deprecated)
|
||||||
[%hey ~] :: refresh
|
[%hey ~] :: refresh
|
||||||
[%rez p=@ud q=@ud] :: resize, cols, rows
|
[%rez p=@ud q=@ud] :: resize, cols, rows
|
||||||
[%yow p=gill:gall] :: connect to app
|
[%yow p=gill:gall] :: connect to app
|
||||||
@ -1290,11 +1296,11 @@
|
|||||||
== ::
|
== ::
|
||||||
+$ flog :: sent to %dill
|
+$ flog :: sent to %dill
|
||||||
$% [%crop p=@ud] :: trim kernel state
|
$% [%crop p=@ud] :: trim kernel state
|
||||||
[%crud p=@tas q=(list tank)] ::
|
$>(%crud told) ::
|
||||||
[%heft ~] ::
|
[%heft ~] ::
|
||||||
[%meld ~] :: unify memory
|
[%meld ~] :: unify memory
|
||||||
[%pack ~] :: compact memory
|
[%pack ~] :: compact memory
|
||||||
[%text p=tape] ::
|
$>(%text told) ::
|
||||||
[%verb ~] :: verbose mode
|
[%verb ~] :: verbose mode
|
||||||
== ::
|
== ::
|
||||||
:: ::
|
:: ::
|
||||||
|
@ -8,14 +8,12 @@
|
|||||||
-- ::
|
-- ::
|
||||||
=> |% :: console protocol
|
=> |% :: console protocol
|
||||||
+$ axle ::
|
+$ axle ::
|
||||||
$: %6 ::
|
$: %7 ::
|
||||||
hey=(unit duct) :: default duct
|
hey=(unit duct) :: default duct
|
||||||
dug=(map @tas axon) :: conversations
|
dug=(map @tas axon) :: conversations
|
||||||
eye=(jug @tas duct) :: outside listeners
|
eye=(jug @tas duct) :: outside observers
|
||||||
|
ear=(set duct) :: syslog listeners
|
||||||
lit=? :: boot in lite mode
|
lit=? :: boot in lite mode
|
||||||
$= veb :: vane verbosities
|
|
||||||
$~ (~(put by *(map @tas log-level)) %hole %soft) :: quiet packet crashes
|
|
||||||
(map @tas log-level) ::
|
|
||||||
egg=_| :: see +take, removeme
|
egg=_| :: see +take, removeme
|
||||||
== ::
|
== ::
|
||||||
+$ axon :: dill session
|
+$ axon :: dill session
|
||||||
@ -97,10 +95,6 @@
|
|||||||
?+ -.kyz ~& [%strange-kiss -.kyz] +>
|
?+ -.kyz ~& [%strange-kiss -.kyz] +>
|
||||||
%hail (send %hey ~)
|
%hail (send %hey ~)
|
||||||
%belt (send `dill-belt`p.kyz)
|
%belt (send `dill-belt`p.kyz)
|
||||||
%talk (talk p.kyz)
|
|
||||||
%text (fore (tuba p.kyz) ~)
|
|
||||||
%crud :: (send `dill-belt`[%cru p.kyz q.kyz])
|
|
||||||
(crud p.kyz q.kyz)
|
|
||||||
%blew (send(wid p.p.kyz) %rez p.p.kyz q.p.kyz)
|
%blew (send(wid p.p.kyz) %rez p.p.kyz q.p.kyz)
|
||||||
%heft (pass /whey %$ whey/~)
|
%heft (pass /whey %$ whey/~)
|
||||||
%meld (dump kyz)
|
%meld (dump kyz)
|
||||||
@ -115,25 +109,11 @@
|
|||||||
==
|
==
|
||||||
::
|
::
|
||||||
++ crud
|
++ crud
|
||||||
|= [err=@tas tac=(list tank)]
|
|= [err=@tas tac=tang]
|
||||||
:: unknown errors default to %loud
|
=- +>.$(moz (weld - moz))
|
||||||
::
|
%+ turn
|
||||||
=/ lev=log-level (~(gut by veb.all) err %loud)
|
~(tap in ear.all)
|
||||||
:: apply log level for this error tag
|
(late %give %logs %crud err tac)
|
||||||
::
|
|
||||||
?- lev
|
|
||||||
%hush +>.$
|
|
||||||
%soft (fore (tuba "crud: %{(trip err)} event failed") ~)
|
|
||||||
%loud (talk leaf+"crud: %{(trip err)} event failed" (flop tac))
|
|
||||||
==
|
|
||||||
::
|
|
||||||
++ talk
|
|
||||||
|= tac=(list tank)
|
|
||||||
%- fore
|
|
||||||
%- zing
|
|
||||||
%+ turn tac
|
|
||||||
|= a=tank
|
|
||||||
(turn (~(win re a) [0 wid]) tuba)
|
|
||||||
::
|
::
|
||||||
++ dump :: pass down to hey
|
++ dump :: pass down to hey
|
||||||
|= git=gift
|
|= git=gift
|
||||||
@ -155,30 +135,6 @@
|
|||||||
|= [=wire =note]
|
|= [=wire =note]
|
||||||
+>(moz :_(moz [hen %pass wire note]))
|
+>(moz :_(moz [hen %pass wire note]))
|
||||||
::
|
::
|
||||||
++ fore :: send dill output
|
|
||||||
::NOTE there are still implicit assumptions
|
|
||||||
:: about the underlying console app's
|
|
||||||
:: semantics here. specifically, trailing
|
|
||||||
:: newlines are important to not getting
|
|
||||||
:: overwritten by the drum prompt, and a
|
|
||||||
:: bottom-of-screen cursor position gives
|
|
||||||
:: nicest results. a more agnostic solution
|
|
||||||
:: will need to replace this arm, someday.
|
|
||||||
:: perhaps +send this to .ram instead?
|
|
||||||
::
|
|
||||||
|= liz=(list (list @c))
|
|
||||||
~? !=(%$ ses) [%d %foreing-in-session ses]
|
|
||||||
^+ +>
|
|
||||||
=. +>
|
|
||||||
=| biz=(list blit)
|
|
||||||
|- ^+ +>.^$
|
|
||||||
?~ liz (done %blit [%hop 0] [%wyp ~] biz)
|
|
||||||
$(liz t.liz, biz (welp biz [%put i.liz] [%nel ~] ~))
|
|
||||||
:: since dill is acting on its own accord,
|
|
||||||
:: we %hey the term app so it may clean up.
|
|
||||||
::
|
|
||||||
(send %hey ~)
|
|
||||||
::
|
|
||||||
++ from :: receive blit
|
++ from :: receive blit
|
||||||
|= bit=dill-blit
|
|= bit=dill-blit
|
||||||
^+ +>
|
^+ +>
|
||||||
@ -349,10 +305,13 @@
|
|||||||
::
|
::
|
||||||
?: ?=(?(%trim %vega) -.task)
|
?: ?=(?(%trim %vega) -.task)
|
||||||
[~ ..^$]
|
[~ ..^$]
|
||||||
:: %knob sets a verbosity level for an error tag
|
:: %knob used to set a verbosity level for an error tag,
|
||||||
|
:: but dill no longer prints errors itself, so implementing %knob
|
||||||
|
:: has become a recommendation to error printers (like drum).
|
||||||
|
:: remove this when %knob gets removed from lull, next™ kelvin release.
|
||||||
::
|
::
|
||||||
?: ?=(%knob -.task)
|
?: ?=(%knob -.task)
|
||||||
=. veb.all (~(put by veb.all) tag.task level.task)
|
~& [%dill %knob-deprecated]
|
||||||
[~ ..^$]
|
[~ ..^$]
|
||||||
:: %open opens a new dill session
|
:: %open opens a new dill session
|
||||||
::
|
::
|
||||||
@ -400,6 +359,18 @@
|
|||||||
?: ?=(%flee -.task)
|
?: ?=(%flee -.task)
|
||||||
:- ~
|
:- ~
|
||||||
..^$(eye.all (~(del ju eye.all) ses hen))
|
..^$(eye.all (~(del ju eye.all) ses hen))
|
||||||
|
:: %logs opens or closes a subscription to system output
|
||||||
|
::
|
||||||
|
?: ?=(%logs -.task)
|
||||||
|
=. ear.all
|
||||||
|
?~ p.task (~(del in ear.all) hen)
|
||||||
|
(~(put in ear.all) hen)
|
||||||
|
[~ ..^$]
|
||||||
|
:: if we were $told something, give %logs to all interested parties
|
||||||
|
::
|
||||||
|
?: ?=(?(%crud %talk %text) -.task)
|
||||||
|
:_ ..^$
|
||||||
|
(turn ~(tap in ear.all) (late %give %logs task))
|
||||||
::
|
::
|
||||||
=/ nus
|
=/ nus
|
||||||
(ax hen ses)
|
(ax hen ses)
|
||||||
@ -408,8 +379,7 @@
|
|||||||
:: could be before %boot (or %boot failed)
|
:: could be before %boot (or %boot failed)
|
||||||
::
|
::
|
||||||
~& [%dill-call-no-session ses hen -.task]
|
~& [%dill-call-no-session ses hen -.task]
|
||||||
=/ tan ?:(?=(%crud -.task) q.task ~)
|
[~ ..^$]
|
||||||
[((slog (flop tan)) ~) ..^$]
|
|
||||||
::
|
::
|
||||||
=^ moz all abet:(call:u.nus task)
|
=^ moz all abet:(call:u.nus task)
|
||||||
[moz ..^$]
|
[moz ..^$]
|
||||||
@ -417,12 +387,28 @@
|
|||||||
++ load :: import old state
|
++ load :: import old state
|
||||||
=< |= old=any-axle
|
=< |= old=any-axle
|
||||||
?- -.old
|
?- -.old
|
||||||
%6 ..^$(all old)
|
%7 ..^$(all old)
|
||||||
|
%6 $(old (axle-6-to-7 old))
|
||||||
%5 $(old (axle-5-to-6 old))
|
%5 $(old (axle-5-to-6 old))
|
||||||
%4 $(old (axle-4-to-5 old))
|
%4 $(old (axle-4-to-5 old))
|
||||||
==
|
==
|
||||||
|%
|
|%
|
||||||
+$ any-axle $%(axle axle-5 axle-4)
|
+$ any-axle $%(axle axle-6 axle-5 axle-4)
|
||||||
|
::
|
||||||
|
+$ axle-6
|
||||||
|
$: %6
|
||||||
|
hey=(unit duct)
|
||||||
|
dug=(map @tas axon)
|
||||||
|
eye=(jug @tas duct)
|
||||||
|
lit=?
|
||||||
|
veb=(map @tas log-level)
|
||||||
|
egg=_|
|
||||||
|
==
|
||||||
|
::
|
||||||
|
++ axle-6-to-7
|
||||||
|
|= a=axle-6
|
||||||
|
^- axle
|
||||||
|
[%7 hey dug eye ~ lit egg]:a
|
||||||
::
|
::
|
||||||
+$ axle-5
|
+$ axle-5
|
||||||
$: %5
|
$: %5
|
||||||
@ -435,7 +421,7 @@
|
|||||||
::
|
::
|
||||||
++ axle-5-to-6
|
++ axle-5-to-6
|
||||||
|= a=axle-5
|
|= a=axle-5
|
||||||
^- axle
|
^- axle-6
|
||||||
:: [%6 hey `(map @tas axon)`dug eye lit veb |]
|
:: [%6 hey `(map @tas axon)`dug eye lit veb |]
|
||||||
a(- %6, veb [veb.a &])
|
a(- %6, veb [veb.a &])
|
||||||
::
|
::
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
/- spider
|
/- spider, eval=ted-eval
|
||||||
/+ strandio
|
/+ strandio
|
||||||
=, strand=strand:spider
|
=, strand=strand:spider
|
||||||
=>
|
|
||||||
|%
|
|
||||||
+$ deps (list path)
|
|
||||||
+$ inpt $@(cord (pair cord deps))
|
|
||||||
--
|
|
||||||
^- thread:spider
|
^- thread:spider
|
||||||
|= raw=vase
|
|= raw=vase
|
||||||
=/ m (strand ,vase)
|
=/ m (strand ,vase)
|
||||||
^- form:m
|
^- form:m
|
||||||
=+ !<(arg=(unit inpt) raw)
|
=+ !<(arg=(unit inpt:eval) raw)
|
||||||
?~ arg
|
?~ arg
|
||||||
(strand-fail:strand %no-input ~)
|
(strand-fail:strand %no-input ~)
|
||||||
?@ u.arg
|
?@ u.arg
|
||||||
|
@ -1,16 +1,11 @@
|
|||||||
/- spider
|
/- spider, eval=ted-eval
|
||||||
/+ strandio
|
/+ strandio
|
||||||
=, strand=strand:spider
|
=, strand=strand:spider
|
||||||
=>
|
|
||||||
|%
|
|
||||||
+$ deps (list path)
|
|
||||||
+$ inpt $@(cord (pair cord deps))
|
|
||||||
--
|
|
||||||
^- thread:spider
|
^- thread:spider
|
||||||
|= raw=vase
|
|= raw=vase
|
||||||
=/ m (strand ,vase)
|
=/ m (strand ,vase)
|
||||||
^- form:m
|
^- form:m
|
||||||
=+ !<(arg=(unit inpt) raw)
|
=+ !<(arg=(unit inpt:eval) raw)
|
||||||
?~ arg
|
?~ arg
|
||||||
(strand-fail:strand %no-input ~)
|
(strand-fail:strand %no-input ~)
|
||||||
=/ com
|
=/ com
|
||||||
|
@ -733,7 +733,7 @@
|
|||||||
::
|
::
|
||||||
%eth-get-block-by-number
|
%eth-get-block-by-number
|
||||||
:- 'eth_getBlockByNumber'
|
:- 'eth_getBlockByNumber'
|
||||||
:~ (tape (num-to-hex bon.req))
|
:~ (tape (num-to-hex-minimal bon.req))
|
||||||
b+txs.req
|
b+txs.req
|
||||||
==
|
==
|
||||||
::
|
::
|
||||||
@ -942,6 +942,12 @@
|
|||||||
%- render-hex-bytes
|
%- render-hex-bytes
|
||||||
(as-octs:mimes:html n)
|
(as-octs:mimes:html n)
|
||||||
::
|
::
|
||||||
|
++ num-to-hex-minimal
|
||||||
|
|= n=@
|
||||||
|
^- tape
|
||||||
|
%- prefix-hex
|
||||||
|
((x-co:co 1) n)
|
||||||
|
::
|
||||||
++ address-to-hex
|
++ address-to-hex
|
||||||
|= a=address
|
|= a=address
|
||||||
^- tape
|
^- tape
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Each one of the folders in this directory is published at `@urbit/{folder name}`
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"@babel/preset-env",
|
|
||||||
{
|
|
||||||
"targets": "> 1%",
|
|
||||||
"useBuiltIns": "usage",
|
|
||||||
"corejs": "3.19.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
extends: '@urbit'
|
|
||||||
};
|
|
1
pkg/npm/api/.gitignore
vendored
1
pkg/npm/api/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
tmp
|
|
@ -1,41 +0,0 @@
|
|||||||
# Urbit API in JavaScript
|
|
||||||
|
|
||||||
This package simplifies the process of working with Urbit's APIs into fluent, typed functions organized by app. Pairs well with `@urbit/http-api`. Compare:
|
|
||||||
|
|
||||||
Without:
|
|
||||||
```ts
|
|
||||||
import UrbitInterface from '@urbit/http-api';
|
|
||||||
const api: UrbitInterface = useApi();
|
|
||||||
api.poke({
|
|
||||||
app: 'settings-store',
|
|
||||||
mark: 'settings-event',
|
|
||||||
json: {
|
|
||||||
'put-entry': {
|
|
||||||
'bucket-key': bucket,
|
|
||||||
'entry-key': key,
|
|
||||||
'value': value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
With:
|
|
||||||
```ts
|
|
||||||
import UrbitInterface from '@urbit/http-api';
|
|
||||||
import { settings } from '@urbit/api';
|
|
||||||
const api: UrbitInterface = useApi();
|
|
||||||
api.poke(settings.putEntry(bucket, key, value));
|
|
||||||
```
|
|
||||||
|
|
||||||
You may import single functions
|
|
||||||
```ts
|
|
||||||
import { putEntry } from '@urbit/api';
|
|
||||||
```
|
|
||||||
or whole apps:
|
|
||||||
```ts
|
|
||||||
import { settings } from '@urbit/api';
|
|
||||||
```
|
|
||||||
|
|
||||||
This package also provides types and utilities for working with Urbit's internal data structures, such as Nouns, Das, Tas, and so forth.
|
|
||||||
|
|
||||||
This package was originally developed as part of Tlon's Landscape client and therefore the best reference material exists [there](https://github.com/urbit/urbit/tree/master/pkg/interface/src).
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,109 +0,0 @@
|
|||||||
|
|
||||||
import { Patp, Poke, Scry } from '../lib';
|
|
||||||
import {
|
|
||||||
Contact,
|
|
||||||
ContactUpdateAdd,
|
|
||||||
ContactUpdateEdit,
|
|
||||||
ContactUpdateRemove,
|
|
||||||
ContactEditField,
|
|
||||||
ContactShare,
|
|
||||||
ContactUpdate,
|
|
||||||
ContactUpdateAllowShips,
|
|
||||||
ContactUpdateAllowGroup,
|
|
||||||
ContactUpdateSetPublic
|
|
||||||
} from './types';
|
|
||||||
|
|
||||||
export const CONTACT_UPDATE_VERSION = 0;
|
|
||||||
|
|
||||||
const storeAction = <T extends ContactUpdate>(data: T, version: number = CONTACT_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'contact-store',
|
|
||||||
mark: `contact-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { storeAction as contactStoreAction };
|
|
||||||
|
|
||||||
export const addContact = (ship: Patp, contact: Contact): Poke<ContactUpdateAdd> => {
|
|
||||||
contact['last-updated'] = Date.now();
|
|
||||||
|
|
||||||
return storeAction({
|
|
||||||
add: { ship, contact }
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeContact = (ship: Patp): Poke<ContactUpdateRemove> =>
|
|
||||||
storeAction({
|
|
||||||
remove: { ship }
|
|
||||||
});
|
|
||||||
|
|
||||||
export const share = (recipient: Patp, version: number = CONTACT_UPDATE_VERSION): Poke<ContactShare> => ({
|
|
||||||
app: 'contact-push-hook',
|
|
||||||
mark: 'contact-share',
|
|
||||||
json: { share: recipient }
|
|
||||||
});
|
|
||||||
|
|
||||||
export const editContact = (
|
|
||||||
ship: Patp,
|
|
||||||
editField: ContactEditField
|
|
||||||
): Poke<ContactUpdateEdit> =>
|
|
||||||
storeAction({
|
|
||||||
edit: {
|
|
||||||
ship,
|
|
||||||
'edit-field': editField,
|
|
||||||
timestamp: Date.now()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const allowShips = (
|
|
||||||
ships: Patp[]
|
|
||||||
): Poke<ContactUpdateAllowShips> => storeAction({
|
|
||||||
allow: {
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const allowGroup = (
|
|
||||||
ship: string,
|
|
||||||
name: string
|
|
||||||
): Poke<ContactUpdateAllowGroup> => storeAction({
|
|
||||||
allow: {
|
|
||||||
group: { ship, name }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setPublic = (
|
|
||||||
setPublic: any
|
|
||||||
): Poke<ContactUpdateSetPublic> => {
|
|
||||||
return storeAction({
|
|
||||||
'set-public': setPublic
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const retrieve = (
|
|
||||||
ship: string
|
|
||||||
) => {
|
|
||||||
const resource = { ship, name: '' };
|
|
||||||
return {
|
|
||||||
app: 'contact-pull-hook',
|
|
||||||
mark: 'pull-hook-action',
|
|
||||||
json: {
|
|
||||||
add: {
|
|
||||||
resource,
|
|
||||||
ship
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fetchIsAllowed = (
|
|
||||||
entity: string,
|
|
||||||
name: string,
|
|
||||||
ship: string,
|
|
||||||
personal: boolean
|
|
||||||
): Scry => {
|
|
||||||
const isPersonal = personal ? 'true' : 'false';
|
|
||||||
return {
|
|
||||||
app: 'contact-store',
|
|
||||||
path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}`
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,82 +0,0 @@
|
|||||||
import { Path, Patp } from '../lib';
|
|
||||||
import { Resource } from '../groups';
|
|
||||||
|
|
||||||
export type ContactUpdate =
|
|
||||||
| ContactUpdateAdd
|
|
||||||
| ContactUpdateRemove
|
|
||||||
| ContactUpdateEdit
|
|
||||||
| ContactUpdateInitial
|
|
||||||
| ContactUpdateAllowGroup
|
|
||||||
| ContactUpdateAllowShips
|
|
||||||
| ContactUpdateSetPublic;
|
|
||||||
|
|
||||||
export interface ContactUpdateAdd {
|
|
||||||
add: {
|
|
||||||
ship: Patp;
|
|
||||||
contact: Contact;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateRemove {
|
|
||||||
remove: {
|
|
||||||
ship: Patp;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateEdit {
|
|
||||||
edit: {
|
|
||||||
ship: Patp;
|
|
||||||
'edit-field': ContactEditField;
|
|
||||||
timestamp: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateAllowShips {
|
|
||||||
allow: {
|
|
||||||
ships: Patp[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateAllowGroup {
|
|
||||||
allow: {
|
|
||||||
group: Resource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateSetPublic {
|
|
||||||
'set-public': boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactShare {
|
|
||||||
share: Patp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContactUpdateInitial {
|
|
||||||
initial: Rolodex;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Rolodex = {
|
|
||||||
[p in Patp]: Contact;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Contacts = Rolodex;
|
|
||||||
|
|
||||||
export interface Contact {
|
|
||||||
nickname: string;
|
|
||||||
bio: string;
|
|
||||||
status: string;
|
|
||||||
color: string;
|
|
||||||
avatar: string | null;
|
|
||||||
cover: string | null;
|
|
||||||
groups: Path[];
|
|
||||||
'last-updated': number;
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContactKeys = keyof Contact;
|
|
||||||
|
|
||||||
export type ContactEditFieldPrim = Exclude<ContactKeys, 'groups' | 'last-updated'>;
|
|
||||||
|
|
||||||
export type ContactEditField = Partial<Pick<Contact, ContactEditFieldPrim>> & {
|
|
||||||
'add-group'?: Resource;
|
|
||||||
'remove-group'?: Resource;
|
|
||||||
};
|
|
8
pkg/npm/api/deps.d.ts
vendored
8
pkg/npm/api/deps.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
declare module 'urbit-ob' {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a @p-encoded string to a decimal-encoded string.
|
|
||||||
*/
|
|
||||||
function patp2dec(name: string): string
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './lib';
|
|
||||||
export * from './types';
|
|
@ -1,65 +0,0 @@
|
|||||||
import { Poke, Scry } from '../lib';
|
|
||||||
import { Chad } from './types';
|
|
||||||
|
|
||||||
export function chadIsRunning(chad: Chad) {
|
|
||||||
return 'glob' in chad || 'site' in chad;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const scryCharges: Scry = {
|
|
||||||
app: 'docket',
|
|
||||||
path: '/charges'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const scryDockets: Scry = {
|
|
||||||
app: 'docket',
|
|
||||||
path: '/dockets'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const scryTreaties: Scry = {
|
|
||||||
app: 'treaty',
|
|
||||||
path: '/treaties'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const scryDefaultAlly: Scry = {
|
|
||||||
app: 'treaty',
|
|
||||||
path: '/default-ally'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const scryAllies: Scry = {
|
|
||||||
app: 'treaty',
|
|
||||||
path: '/allies'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const scryAllyTreaties = (ship: string): Scry => ({
|
|
||||||
app: 'treaty',
|
|
||||||
path: `/treaties/${ship}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uninstall a desk, and remove docket
|
|
||||||
*/
|
|
||||||
export function docketUninstall(desk: string): Poke<string> {
|
|
||||||
return {
|
|
||||||
app: 'docket',
|
|
||||||
mark: 'docket-uninstall',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function docketInstall(ship: string, desk: string): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'docket',
|
|
||||||
mark: 'docket-install',
|
|
||||||
json: `${ship}/${desk}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function allyShip(ship: string): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'treaty',
|
|
||||||
mark: 'ally-update-0',
|
|
||||||
json: {
|
|
||||||
add: ship
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
import { Cass } from '../hood';
|
|
||||||
export type DeskStatus = 'active' | 'suspended';
|
|
||||||
|
|
||||||
export type DocketHref = DocketHrefSite | DocketHrefGlob;
|
|
||||||
|
|
||||||
export interface DocketHrefGlob {
|
|
||||||
glob: {
|
|
||||||
base: string;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DocketHrefSite {
|
|
||||||
site: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Docket {
|
|
||||||
title: string;
|
|
||||||
info?: string;
|
|
||||||
color: string;
|
|
||||||
href: DocketHref;
|
|
||||||
website: string;
|
|
||||||
license: string;
|
|
||||||
version: string;
|
|
||||||
image?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Charge extends Docket {
|
|
||||||
chad: Chad;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Chad = HungChad | GlobChad | SiteChad | InstallChad | SuspendChad;
|
|
||||||
|
|
||||||
export interface HungChad {
|
|
||||||
hung: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GlobChad {
|
|
||||||
glob: null;
|
|
||||||
}
|
|
||||||
export interface SiteChad {
|
|
||||||
site: null;
|
|
||||||
}
|
|
||||||
export interface InstallChad {
|
|
||||||
install: null;
|
|
||||||
|
|
||||||
}
|
|
||||||
export interface SuspendChad {
|
|
||||||
suspend: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Treaty extends Docket {
|
|
||||||
ship: string;
|
|
||||||
desk: string;
|
|
||||||
cass: Cass;
|
|
||||||
hash: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Charges {
|
|
||||||
[desk: string]: Charge;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Treaties {
|
|
||||||
[ref: string]: Treaty;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Charter = string[];
|
|
||||||
|
|
||||||
export interface Allies {
|
|
||||||
[ship: string]: Charter;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Provider {
|
|
||||||
shipName: string;
|
|
||||||
nickname?: string;
|
|
||||||
status?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ChargeUpdate = ChargeUpdateInitial | ChargeUpdateAdd | ChargeUpdateDel;
|
|
||||||
|
|
||||||
export interface ChargeUpdateInitial {
|
|
||||||
initial: {
|
|
||||||
[desk: string]: Charge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChargeUpdateAdd {
|
|
||||||
'add-charge': {
|
|
||||||
desk: string;
|
|
||||||
charge: Charge;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChargeUpdateDel {
|
|
||||||
'del-charge': string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew;
|
|
||||||
|
|
||||||
export interface AllyUpdateIni {
|
|
||||||
ini: {
|
|
||||||
[ship: string]: string[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllyUpdateAdd {
|
|
||||||
add: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllyUpdateDel {
|
|
||||||
del: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllyUpdateNew {
|
|
||||||
new: {
|
|
||||||
ship: string;
|
|
||||||
alliance: string[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TreatyUpdate = TreatyUpdateIni | TreatyUpdateAdd | TreatyUpdateDel;
|
|
||||||
|
|
||||||
export interface TreatyUpdateIni {
|
|
||||||
ini: {
|
|
||||||
[foreignDesk: string]: Treaty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TreatyUpdateAdd {
|
|
||||||
add: Treaty;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TreatyUpdateDel {
|
|
||||||
del: string;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './lib';
|
|
||||||
export * from './types';
|
|
@ -1,534 +0,0 @@
|
|||||||
import { GroupPolicy, makeResource, Resource, resourceFromPath } from '../groups';
|
|
||||||
|
|
||||||
import { decToUd, deSig, unixToDa, Scry } from '../lib';
|
|
||||||
import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types';
|
|
||||||
import { Content, GraphChildrenPoke, GraphNode, GraphNodePoke, Post } from './types';
|
|
||||||
import { patp2dec } from 'urbit-ob';
|
|
||||||
|
|
||||||
export const GRAPH_UPDATE_VERSION = 3;
|
|
||||||
|
|
||||||
export const createBlankNodeWithChildPost = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
parentIndex = '',
|
|
||||||
childIndex = '',
|
|
||||||
contents: Content[]
|
|
||||||
): GraphNodePoke => {
|
|
||||||
const date = unixToDa(Date.now()).toString();
|
|
||||||
const nodeIndex = parentIndex + '/' + date;
|
|
||||||
|
|
||||||
const childGraph: GraphChildrenPoke = {};
|
|
||||||
childGraph[childIndex] = {
|
|
||||||
post: {
|
|
||||||
author: `~${ship}`,
|
|
||||||
index: nodeIndex + '/' + childIndex,
|
|
||||||
'time-sent': Date.now(),
|
|
||||||
contents,
|
|
||||||
hash: null,
|
|
||||||
signatures: []
|
|
||||||
},
|
|
||||||
children: null
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
post: {
|
|
||||||
author: `~${ship}`,
|
|
||||||
index: nodeIndex,
|
|
||||||
'time-sent': Date.now(),
|
|
||||||
contents: [],
|
|
||||||
hash: null,
|
|
||||||
signatures: []
|
|
||||||
},
|
|
||||||
children: childGraph
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const markPending = (nodes: any): any => {
|
|
||||||
Object.keys(nodes).forEach((key) => {
|
|
||||||
nodes[key].post.author = deSig(nodes[key].post.author);
|
|
||||||
nodes[key].post.pending = true;
|
|
||||||
if (nodes[key].children) {
|
|
||||||
nodes[key].children = markPending(nodes[key].children);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return nodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createPost = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
contents: Content[],
|
|
||||||
parentIndex = '',
|
|
||||||
childIndex = 'DATE_PLACEHOLDER'
|
|
||||||
): Post => {
|
|
||||||
if (childIndex === 'DATE_PLACEHOLDER') {
|
|
||||||
childIndex = unixToDa(Date.now()).toString();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
author: `~${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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const storeAction = <T>(data: T, version: number = GRAPH_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
mark: `graph-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { storeAction as graphStoreAction };
|
|
||||||
|
|
||||||
const viewAction = <T>(threadName: string, action: T): Thread<T> => ({
|
|
||||||
inputMark: 'graph-view-action',
|
|
||||||
outputMark: 'json',
|
|
||||||
threadName,
|
|
||||||
body: action
|
|
||||||
});
|
|
||||||
|
|
||||||
export { viewAction as graphViewAction };
|
|
||||||
|
|
||||||
const hookAction = <T>(data: T, version: number = GRAPH_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'graph-push-hook',
|
|
||||||
mark: `graph-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
const dmAction = <T>(data: T): Poke<T> => ({
|
|
||||||
app: 'dm-hook',
|
|
||||||
mark: 'dm-hook-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { hookAction as graphHookAction };
|
|
||||||
|
|
||||||
export const createManagedGraph = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
name: string,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
group: Path,
|
|
||||||
mod: string
|
|
||||||
): Thread<any> => {
|
|
||||||
const associated = { group: resourceFromPath(group) };
|
|
||||||
const resource = makeResource(`~${ship}`, name);
|
|
||||||
|
|
||||||
return viewAction('graph-create', {
|
|
||||||
create: {
|
|
||||||
resource,
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
associated,
|
|
||||||
module: mod,
|
|
||||||
mark: moduleToMark(mod)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createUnmanagedGraph = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
name: string,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
policy: Enc<GroupPolicy>,
|
|
||||||
mod: string
|
|
||||||
): Thread<any> => viewAction('graph-create', {
|
|
||||||
create: {
|
|
||||||
resource: makeResource(`~${ship}`, name),
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
associated: { policy },
|
|
||||||
module: mod,
|
|
||||||
mark: moduleToMark(mod)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const joinGraph = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string
|
|
||||||
): Thread<any> => viewAction('graph-join', {
|
|
||||||
join: {
|
|
||||||
resource: makeResource(ship, name),
|
|
||||||
ship
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const deleteGraph = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
name: string
|
|
||||||
): Thread<any> => viewAction('graph-delete', {
|
|
||||||
'delete': {
|
|
||||||
resource: makeResource(`~${ship}`, name)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const leaveGraph = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string
|
|
||||||
): Thread<any> => viewAction('graph-leave', {
|
|
||||||
'leave': {
|
|
||||||
resource: makeResource(ship, name)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const groupifyGraph = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
toPath?: string
|
|
||||||
): Thread<any> => {
|
|
||||||
const resource = makeResource(ship, name);
|
|
||||||
const to = toPath && resourceFromPath(toPath);
|
|
||||||
|
|
||||||
return viewAction('graph-groupify', {
|
|
||||||
groupify: {
|
|
||||||
resource,
|
|
||||||
to
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const evalCord = (
|
|
||||||
cord: string
|
|
||||||
): Thread<any> => {
|
|
||||||
return ({
|
|
||||||
inputMark: 'graph-view-action',
|
|
||||||
outputMark: 'tang',
|
|
||||||
threadName: 'graph-eval',
|
|
||||||
body: {
|
|
||||||
eval: cord
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addGraph = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
graph: any,
|
|
||||||
mark: any
|
|
||||||
): Poke<any> => {
|
|
||||||
return storeAction({
|
|
||||||
'add-graph': {
|
|
||||||
resource: { ship, name },
|
|
||||||
graph,
|
|
||||||
mark
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addNodes = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
nodes: Object
|
|
||||||
): Thread<any> => ({
|
|
||||||
inputMark: `graph-update-${GRAPH_UPDATE_VERSION}`,
|
|
||||||
outputMark: 'graph-view-action',
|
|
||||||
threadName: 'graph-add-nodes',
|
|
||||||
body: {
|
|
||||||
'add-nodes': {
|
|
||||||
resource: { ship, name },
|
|
||||||
nodes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addPost = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
post: Post
|
|
||||||
): Thread<any> => {
|
|
||||||
const nodes: Record<string, GraphNode> = {};
|
|
||||||
nodes[post.index] = {
|
|
||||||
post,
|
|
||||||
children: null
|
|
||||||
};
|
|
||||||
return addNodes(ship, name, nodes);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addNode = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
node: GraphNodePoke
|
|
||||||
): Thread<any> => {
|
|
||||||
const nodes: Record<string, GraphNodePoke> = {};
|
|
||||||
nodes[node.post.index] = node;
|
|
||||||
|
|
||||||
return addNodes(ship, name, nodes);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createGroupFeed = (
|
|
||||||
group: Resource,
|
|
||||||
vip: any = ''
|
|
||||||
): Thread<any> => ({
|
|
||||||
inputMark: 'graph-view-action',
|
|
||||||
outputMark: 'resource',
|
|
||||||
threadName: 'graph-create-group-feed',
|
|
||||||
body: {
|
|
||||||
'create-group-feed': {
|
|
||||||
resource: group,
|
|
||||||
vip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const disableGroupFeed = (
|
|
||||||
group: Resource
|
|
||||||
): Thread<any> => ({
|
|
||||||
inputMark: 'graph-view-action',
|
|
||||||
outputMark: 'json',
|
|
||||||
threadName: 'graph-disable-group-feed',
|
|
||||||
body: {
|
|
||||||
'disable-group-feed': {
|
|
||||||
resource: group
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set dm-hook to screen new DMs or not
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const setScreen = (screen: boolean): Poke<any> => dmAction({ screen });
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept a pending DM request
|
|
||||||
*
|
|
||||||
* @param ship the ship to accept
|
|
||||||
*/
|
|
||||||
export const acceptDm = (ship: string) => dmAction({
|
|
||||||
accept: ship
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decline a pending DM request
|
|
||||||
*
|
|
||||||
* @param ship the ship to accept
|
|
||||||
*/
|
|
||||||
export const declineDm = (ship: string) => dmAction({
|
|
||||||
decline: ship
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove posts from a set of indices
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const removePosts = (
|
|
||||||
ship: Patp,
|
|
||||||
name: string,
|
|
||||||
indices: string[]
|
|
||||||
): Poke<any> => hookAction({
|
|
||||||
'remove-posts': {
|
|
||||||
resource: { ship, name },
|
|
||||||
indices
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a DM message from our inbox
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* This does not remove the message from the recipients inbox
|
|
||||||
*/
|
|
||||||
export const removeDmMessage = (
|
|
||||||
our: Patp,
|
|
||||||
index: string
|
|
||||||
): Poke<any> => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
mark: `graph-update-${GRAPH_UPDATE_VERSION}`,
|
|
||||||
json: {
|
|
||||||
'remove-posts': {
|
|
||||||
resource: { ship: our, name: 'dm-inbox' },
|
|
||||||
indices: [index]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a DM to a ship
|
|
||||||
*
|
|
||||||
* @param our sender
|
|
||||||
* @param ship recipient
|
|
||||||
* @param contents contents of message
|
|
||||||
*/
|
|
||||||
export const addDmMessage = (our: PatpNoSig, ship: Patp, contents: Content[]): Poke<any> => {
|
|
||||||
const post = createPost(our, contents, `/${patp2dec(ship)}`);
|
|
||||||
const node: GraphNode = {
|
|
||||||
post,
|
|
||||||
children: null
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
app: 'dm-hook',
|
|
||||||
mark: `graph-update-${GRAPH_UPDATE_VERSION}`,
|
|
||||||
json: {
|
|
||||||
'add-nodes': {
|
|
||||||
resource: { ship: `~${our}`, name: 'dm-inbox' },
|
|
||||||
nodes: {
|
|
||||||
[post.index]: node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const encodeIndex = (idx: string) => idx.split('/').map(decToUd).join('/');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all graph keys
|
|
||||||
*/
|
|
||||||
export const getKeys = (): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: '/keys'
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch newest (larger keys) nodes in a graph under some index
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param count number of nodes to load
|
|
||||||
* @param index index to query
|
|
||||||
*/
|
|
||||||
export const getNewest = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
count: number,
|
|
||||||
index = ''
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/siblings` +
|
|
||||||
`/newest/lone/${count}${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch nodes in a graph that are older (key is smaller) and direct
|
|
||||||
* siblings of some index
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param count number of nodes to load
|
|
||||||
* @param index index to query
|
|
||||||
*/
|
|
||||||
export const getOlderSiblings = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
count: number,
|
|
||||||
index: string
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/siblings/older/lone/${count}${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch nodes in a graph that are younger (key is larger) and direct
|
|
||||||
* siblings of some index
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param count number of nodes to load
|
|
||||||
* @param index index to query
|
|
||||||
*/
|
|
||||||
export const getYoungerSiblings = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
count: number,
|
|
||||||
index: string
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/siblings/newer/lone/${count}${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch all nodes in a graph under some index, without loading children
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param index index to query
|
|
||||||
*/
|
|
||||||
export const getShallowChildren = (ship: string, name: string, index = '') => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/children/lone/~/~${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch newest nodes in a graph as a flat map, including children,
|
|
||||||
* optionally starting at a specified key
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param count number of nodes to load
|
|
||||||
* @param start key to start at
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const getDeepOlderThan = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
count: number,
|
|
||||||
start = ''
|
|
||||||
) => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/siblings` +
|
|
||||||
`/${start.length > 0 ? 'older' : 'newest'}` +
|
|
||||||
`/kith/${count}${encodeIndex(start)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch a flat map of a nodes ancestors and firstborn children
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param index index to query
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const getFirstborn = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
index: string
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/firstborn${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch a single node, and all it's children
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
* @param index index to query
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const getNode = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
index: string
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}/node/index/kith${encodeIndex(index)}`
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch entire graph
|
|
||||||
*
|
|
||||||
* @param ship ship of graph
|
|
||||||
* @param name name of graph
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const getGraph = (
|
|
||||||
ship: string,
|
|
||||||
name: string
|
|
||||||
): Scry => ({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: `/graph/${ship}/${name}`
|
|
||||||
});
|
|
@ -1,94 +0,0 @@
|
|||||||
import { Patp } from '../lib';
|
|
||||||
import { BigIntOrderedMap } from '../lib/BigIntOrderedMap';
|
|
||||||
import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap';
|
|
||||||
|
|
||||||
export interface TextContent {
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
export interface UrlContent {
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
export interface CodeContent {
|
|
||||||
code: {
|
|
||||||
expression: string;
|
|
||||||
output: string[] | undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReferenceContent {
|
|
||||||
reference: AppReference | GraphReference | GroupReference;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GraphReference {
|
|
||||||
graph: {
|
|
||||||
graph: string;
|
|
||||||
group: string;
|
|
||||||
index: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupReference {
|
|
||||||
group: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AppReference {
|
|
||||||
app: {
|
|
||||||
ship: string;
|
|
||||||
desk: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MentionContent {
|
|
||||||
mention: string;
|
|
||||||
emphasis?: 'bold' | 'italic';
|
|
||||||
}
|
|
||||||
export type Content =
|
|
||||||
| TextContent
|
|
||||||
| UrlContent
|
|
||||||
| CodeContent
|
|
||||||
| ReferenceContent
|
|
||||||
| MentionContent;
|
|
||||||
|
|
||||||
export interface Post {
|
|
||||||
author: Patp;
|
|
||||||
contents: Content[];
|
|
||||||
hash: string | null;
|
|
||||||
index: string;
|
|
||||||
pending?: boolean;
|
|
||||||
signatures: string[];
|
|
||||||
'time-sent': number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GraphNodePoke {
|
|
||||||
post: Post;
|
|
||||||
children: GraphChildrenPoke | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GraphChildrenPoke {
|
|
||||||
[k: string]: GraphNodePoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GraphNode {
|
|
||||||
children: Graph | null;
|
|
||||||
post: Post;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlatGraphNode {
|
|
||||||
children: null;
|
|
||||||
post: Post;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Graph = BigIntOrderedMap<GraphNode>;
|
|
||||||
|
|
||||||
export type Graphs = { [rid: string]: Graph };
|
|
||||||
|
|
||||||
export type FlatGraph = BigIntArrayOrderedMap<FlatGraphNode>;
|
|
||||||
|
|
||||||
export type FlatGraphs = { [rid: string]: FlatGraph };
|
|
||||||
|
|
||||||
export type ThreadGraphs = {
|
|
||||||
[rid: string]: {
|
|
||||||
[index: string]: FlatGraph;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,226 +0,0 @@
|
|||||||
import { deSig } from '../index';
|
|
||||||
import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types';
|
|
||||||
import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types';
|
|
||||||
import { GroupUpdate } from './update';
|
|
||||||
|
|
||||||
export const GROUP_UPDATE_VERSION = 0;
|
|
||||||
|
|
||||||
export const proxyAction = <T>(data: T, version: number = GROUP_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'group-push-hook',
|
|
||||||
mark: `group-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
const storeAction = <T extends GroupUpdate>(data: T, version: number = GROUP_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'group-store',
|
|
||||||
mark: `group-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { storeAction as groupStoreAction };
|
|
||||||
|
|
||||||
const viewAction = <T>(data: T): Poke<T> => ({
|
|
||||||
app: 'group-view',
|
|
||||||
mark: 'group-view-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { viewAction as groupViewAction };
|
|
||||||
|
|
||||||
export const viewThread = <T>(thread: string, action: T): Thread<T> => ({
|
|
||||||
inputMark: 'group-view-action',
|
|
||||||
outputMark: 'json',
|
|
||||||
threadName: thread,
|
|
||||||
body: action
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeMembers = (
|
|
||||||
resource: Resource,
|
|
||||||
ships: PatpNoSig[]
|
|
||||||
): Poke<GroupUpdateRemoveMembers> => proxyAction({
|
|
||||||
removeMembers: {
|
|
||||||
resource,
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addTag = (
|
|
||||||
resource: Resource,
|
|
||||||
tag: Tag,
|
|
||||||
ships: Patp[]
|
|
||||||
): Poke<GroupUpdateAddTag> => proxyAction({
|
|
||||||
addTag: {
|
|
||||||
resource,
|
|
||||||
tag,
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeTag = (
|
|
||||||
tag: Tag,
|
|
||||||
resource: Resource,
|
|
||||||
ships: PatpNoSig[]
|
|
||||||
): Poke<GroupUpdateRemoveTag> => proxyAction({
|
|
||||||
removeTag: {
|
|
||||||
tag,
|
|
||||||
resource,
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addMembers = (
|
|
||||||
resource: Resource,
|
|
||||||
ships: PatpNoSig[]
|
|
||||||
): Poke<GroupUpdateAddMembers> => proxyAction({
|
|
||||||
addMembers: {
|
|
||||||
resource,
|
|
||||||
ships
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeGroup = (
|
|
||||||
resource: Resource
|
|
||||||
): Poke<GroupUpdateRemoveGroup> => storeAction({
|
|
||||||
removeGroup: {
|
|
||||||
resource
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const changePolicy = (
|
|
||||||
resource: Resource,
|
|
||||||
diff: Enc<GroupPolicyDiff>
|
|
||||||
): Poke<Enc<GroupUpdateChangePolicy>> => proxyAction({
|
|
||||||
changePolicy: {
|
|
||||||
resource,
|
|
||||||
diff
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const join = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
app: "groups" | "graph",
|
|
||||||
autojoin: boolean,
|
|
||||||
share: boolean
|
|
||||||
): Poke<any> => viewAction({
|
|
||||||
join: {
|
|
||||||
resource: makeResource(ship, name),
|
|
||||||
ship,
|
|
||||||
shareContact: share || false,
|
|
||||||
app,
|
|
||||||
autojoin
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const createGroup = (
|
|
||||||
name: string,
|
|
||||||
policy: Enc<GroupPolicy>,
|
|
||||||
title: string,
|
|
||||||
description: string
|
|
||||||
): Thread<any> => viewThread('group-create', {
|
|
||||||
create: {
|
|
||||||
name,
|
|
||||||
policy,
|
|
||||||
title,
|
|
||||||
description
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const deleteGroup = (
|
|
||||||
ship: string,
|
|
||||||
name: string
|
|
||||||
): Thread<any> => viewThread('group-delete', {
|
|
||||||
remove: makeResource(ship, name)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const leaveGroup = (
|
|
||||||
ship: string,
|
|
||||||
name: string
|
|
||||||
): Thread<any> => viewThread('group-leave', {
|
|
||||||
leave: makeResource(ship, name)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const invite = (
|
|
||||||
ship: string,
|
|
||||||
name: string,
|
|
||||||
ships: Patp[],
|
|
||||||
description: string
|
|
||||||
): Thread<any> => viewThread('group-invite', {
|
|
||||||
invite: {
|
|
||||||
resource: makeResource(ship, name),
|
|
||||||
ships,
|
|
||||||
description
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const abortJoin = (
|
|
||||||
resource: string
|
|
||||||
): Poke<any> => viewAction({
|
|
||||||
abort: resource
|
|
||||||
});
|
|
||||||
|
|
||||||
export const roleTags = ['janitor', 'moderator', 'admin'];
|
|
||||||
// TODO make this type better?
|
|
||||||
|
|
||||||
export const groupBunts = {
|
|
||||||
group: (): Group => ({ members: [], tags: { role: {} }, hidden: false, policy: groupBunts.policy() }),
|
|
||||||
policy: (): GroupPolicy => ({ open: { banned: [], banRanks: [] } })
|
|
||||||
};
|
|
||||||
|
|
||||||
export const joinError = ['no-perms', 'strange', 'abort'] as const;
|
|
||||||
export const joinResult = ['done', ...joinError] as const;
|
|
||||||
export const joinLoad = ['start', 'added', 'metadata'] as const;
|
|
||||||
export const joinProgress = [...joinLoad, ...joinResult] as const;
|
|
||||||
|
|
||||||
export function roleForShip(
|
|
||||||
group: Group,
|
|
||||||
ship: PatpNoSig
|
|
||||||
): RoleTags | undefined {
|
|
||||||
return roleTags.reduce((currRole, role) => {
|
|
||||||
const roleShips = group?.tags?.role?.[role];
|
|
||||||
return roleShips && roleShips.includes(ship) ? role : currRole;
|
|
||||||
}, undefined as RoleTags | undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function resourceFromPath(path: Path): Resource {
|
|
||||||
const [, , ship, name] = path.split('/');
|
|
||||||
return { ship, name };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeResource(ship: string, name: string) {
|
|
||||||
return { ship, name };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isWriter = (group: Group, resource: string, ship: string) => {
|
|
||||||
const graph = group?.tags?.graph;
|
|
||||||
const writers: string[] | undefined = graph && (graph[resource] as any)?.writers;
|
|
||||||
const admins = group?.tags?.role?.admin ?? [];
|
|
||||||
if (typeof writers === 'undefined') {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return [...writers].includes(ship) || admins.includes(ship);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function isChannelAdmin(
|
|
||||||
group: Group,
|
|
||||||
resource: string,
|
|
||||||
ship: string
|
|
||||||
): boolean {
|
|
||||||
const role = roleForShip(group, deSig(ship));
|
|
||||||
|
|
||||||
return (
|
|
||||||
isHost(resource, ship) ||
|
|
||||||
role === 'admin' ||
|
|
||||||
role === 'moderator'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isHost(
|
|
||||||
resource: string,
|
|
||||||
ship: string
|
|
||||||
): boolean {
|
|
||||||
const [, , host] = resource.split('/');
|
|
||||||
|
|
||||||
return ship === host;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './update';
|
|
||||||
export * from './view';
|
|
@ -1,175 +0,0 @@
|
|||||||
import { PatpNoSig, Path, ShipRank, Enc } from '../lib';
|
|
||||||
import { roleTags } from './index';
|
|
||||||
|
|
||||||
export type RoleTags = typeof roleTags[number];
|
|
||||||
interface RoleTag {
|
|
||||||
tag: 'admin' | 'moderator' | 'janitor';
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AppTag {
|
|
||||||
app: string;
|
|
||||||
resource: string;
|
|
||||||
tag: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Tag = AppTag | RoleTag;
|
|
||||||
|
|
||||||
export interface InvitePolicy {
|
|
||||||
invite: {
|
|
||||||
pending: PatpNoSig[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OpenPolicy {
|
|
||||||
open: {
|
|
||||||
banned: PatpNoSig[];
|
|
||||||
banRanks: ShipRank[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Resource {
|
|
||||||
name: string;
|
|
||||||
ship: PatpNoSig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OpenPolicyDiff =
|
|
||||||
| AllowRanksDiff
|
|
||||||
| BanRanksDiff
|
|
||||||
| AllowShipsDiff
|
|
||||||
| BanShipsDiff;
|
|
||||||
|
|
||||||
export interface AllowRanksDiff {
|
|
||||||
allowRanks: ShipRank[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BanRanksDiff {
|
|
||||||
banRanks: ShipRank[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllowShipsDiff {
|
|
||||||
allowShips: PatpNoSig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BanShipsDiff {
|
|
||||||
banShips: PatpNoSig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export type InvitePolicyDiff = AddInvitesDiff | RemoveInvitesDiff;
|
|
||||||
|
|
||||||
export interface AddInvitesDiff {
|
|
||||||
addInvites: PatpNoSig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RemoveInvitesDiff {
|
|
||||||
removeInvites: PatpNoSig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReplacePolicyDiff {
|
|
||||||
replace: GroupPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GroupPolicyDiff =
|
|
||||||
| { open: OpenPolicyDiff }
|
|
||||||
| { invite: InvitePolicyDiff }
|
|
||||||
| ReplacePolicyDiff;
|
|
||||||
|
|
||||||
export type GroupPolicy = OpenPolicy | InvitePolicy;
|
|
||||||
|
|
||||||
export interface TaggedShips {
|
|
||||||
[tag: string]: PatpNoSig[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Tags {
|
|
||||||
role: TaggedShips;
|
|
||||||
[app: string]: TaggedShips;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Group {
|
|
||||||
members: PatpNoSig[];
|
|
||||||
tags: Tags;
|
|
||||||
policy: GroupPolicy;
|
|
||||||
hidden: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Groups = {
|
|
||||||
[p in Path]: Group;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface GroupUpdateInitial {
|
|
||||||
initial: Enc<Groups>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateAddGroup {
|
|
||||||
addGroup: {
|
|
||||||
resource: Resource;
|
|
||||||
policy: Enc<GroupPolicy>;
|
|
||||||
hidden: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateAddMembers {
|
|
||||||
addMembers: {
|
|
||||||
ships: PatpNoSig[];
|
|
||||||
resource: Resource;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateRemoveMembers {
|
|
||||||
removeMembers: {
|
|
||||||
ships: PatpNoSig[];
|
|
||||||
resource: Resource;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateAddTag {
|
|
||||||
addTag: {
|
|
||||||
tag: Tag;
|
|
||||||
resource: Resource;
|
|
||||||
ships: PatpNoSig[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateRemoveTag {
|
|
||||||
removeTag: {
|
|
||||||
tag: Tag;
|
|
||||||
resource: Resource;
|
|
||||||
ships: PatpNoSig[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateChangePolicy {
|
|
||||||
changePolicy: { resource: Resource; diff: GroupPolicyDiff };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateRemoveGroup {
|
|
||||||
removeGroup: {
|
|
||||||
resource: Resource;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateExpose {
|
|
||||||
expose: {
|
|
||||||
resource: Resource;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupUpdateInitialGroup {
|
|
||||||
initialGroup: {
|
|
||||||
resource: Resource;
|
|
||||||
group: Enc<Group>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GroupUpdate =
|
|
||||||
| GroupUpdateInitial
|
|
||||||
| GroupUpdateAddGroup
|
|
||||||
| GroupUpdateAddMembers
|
|
||||||
| GroupUpdateRemoveMembers
|
|
||||||
| GroupUpdateAddTag
|
|
||||||
| GroupUpdateRemoveTag
|
|
||||||
| GroupUpdateChangePolicy
|
|
||||||
| GroupUpdateRemoveGroup
|
|
||||||
| GroupUpdateExpose
|
|
||||||
| GroupUpdateInitialGroup;
|
|
||||||
|
|
||||||
export type GroupAction = Omit<GroupUpdate, 'initialGroup' | 'initial'>;
|
|
@ -1,30 +0,0 @@
|
|||||||
import { joinError, joinProgress, joinResult } from ".";
|
|
||||||
import {Patp} from "../lib";
|
|
||||||
|
|
||||||
export type JoinError = typeof joinError[number];
|
|
||||||
|
|
||||||
export type JoinResult = typeof joinResult[number];
|
|
||||||
|
|
||||||
|
|
||||||
export type JoinProgress = typeof joinProgress[number];
|
|
||||||
|
|
||||||
export interface JoinRequest {
|
|
||||||
/**
|
|
||||||
* Whether to display the join request or not
|
|
||||||
*/
|
|
||||||
hidden: boolean;
|
|
||||||
/**
|
|
||||||
* Timestamp of when the request started
|
|
||||||
*/
|
|
||||||
started: number;
|
|
||||||
ship: Patp;
|
|
||||||
progress: JoinProgress;
|
|
||||||
shareContact: boolean;
|
|
||||||
autojoin: boolean;
|
|
||||||
app: 'graph' | 'groups';
|
|
||||||
invite: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface JoinRequests {
|
|
||||||
[rid: string]: JoinRequest;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,163 +0,0 @@
|
|||||||
import { BigInteger } from 'big-integer';
|
|
||||||
|
|
||||||
import { Poke } from '../lib/types';
|
|
||||||
import {
|
|
||||||
HarkBin,
|
|
||||||
HarkBinId,
|
|
||||||
HarkBody,
|
|
||||||
HarkLid,
|
|
||||||
HarkPlace
|
|
||||||
} from './types';
|
|
||||||
import { decToUd } from '../lib';
|
|
||||||
|
|
||||||
export const harkAction = <T>(data: T): Poke<T> => ({
|
|
||||||
app: 'hark-store',
|
|
||||||
mark: 'hark-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
const graphHookAction = <T>(data: T): Poke<T> => ({
|
|
||||||
app: 'hark-graph-hook',
|
|
||||||
mark: 'hark-graph-hook-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { graphHookAction as harkGraphHookAction };
|
|
||||||
|
|
||||||
const groupHookAction = <T>(data: T): Poke<T> => ({
|
|
||||||
app: 'hark-group-hook',
|
|
||||||
mark: 'hark-group-hook-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export { groupHookAction as harkGroupHookAction };
|
|
||||||
|
|
||||||
export const actOnNotification = (
|
|
||||||
frond: string,
|
|
||||||
intTime: BigInteger,
|
|
||||||
bin: HarkBin
|
|
||||||
): Poke<unknown> =>
|
|
||||||
harkAction({
|
|
||||||
[frond]: {
|
|
||||||
time: decToUd(intTime.toString()),
|
|
||||||
bin
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setMentions = (mentions: boolean): Poke<unknown> =>
|
|
||||||
graphHookAction({
|
|
||||||
'set-mentions': mentions
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setWatchOnSelf = (watchSelf: boolean): Poke<unknown> =>
|
|
||||||
graphHookAction({
|
|
||||||
'set-watch-on-self': watchSelf
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setDoNotDisturb = (dnd: boolean): Poke<unknown> =>
|
|
||||||
harkAction({
|
|
||||||
'set-dnd': dnd
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addNote = (bin: HarkBin, body: HarkBody) =>
|
|
||||||
harkAction({
|
|
||||||
'add-note': {
|
|
||||||
bin,
|
|
||||||
body
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const archive = (bin: HarkBin, lid: HarkLid): Poke<unknown> =>
|
|
||||||
harkAction({
|
|
||||||
archive: {
|
|
||||||
lid,
|
|
||||||
bin
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const opened = harkAction({
|
|
||||||
opened: null
|
|
||||||
});
|
|
||||||
|
|
||||||
export const markCountAsRead = (place: HarkPlace): Poke<unknown> =>
|
|
||||||
harkAction({
|
|
||||||
'read-count': place
|
|
||||||
});
|
|
||||||
|
|
||||||
export const markEachAsRead = (
|
|
||||||
place: HarkPlace,
|
|
||||||
path: string
|
|
||||||
): Poke<unknown> =>
|
|
||||||
harkAction({
|
|
||||||
'read-each': {
|
|
||||||
place,
|
|
||||||
path
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const seen = () => harkAction({ seen: null });
|
|
||||||
|
|
||||||
export const readAll = harkAction({ 'read-all': null });
|
|
||||||
export const archiveAll = harkAction({ 'archive-all': null });
|
|
||||||
|
|
||||||
export const ignoreGroup = (group: string): Poke<unknown> =>
|
|
||||||
groupHookAction({
|
|
||||||
ignore: group
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ignoreGraph = (graph: string, index: string): Poke<unknown> =>
|
|
||||||
graphHookAction({
|
|
||||||
ignore: {
|
|
||||||
graph,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const listenGroup = (group: string): Poke<unknown> =>
|
|
||||||
groupHookAction({
|
|
||||||
listen: group
|
|
||||||
});
|
|
||||||
|
|
||||||
export const listenGraph = (graph: string, index: string): Poke<unknown> =>
|
|
||||||
graphHookAction({
|
|
||||||
listen: {
|
|
||||||
graph,
|
|
||||||
index
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read all graphs belonging to a particular group
|
|
||||||
*/
|
|
||||||
export const readGroup = (group: string) =>
|
|
||||||
harkAction({
|
|
||||||
'read-group': group
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read all unreads in a graph
|
|
||||||
*/
|
|
||||||
export const readGraph = (graph: string) =>
|
|
||||||
harkAction({
|
|
||||||
'read-graph': graph
|
|
||||||
});
|
|
||||||
|
|
||||||
export function harkBinToId(bin: HarkBin): HarkBinId {
|
|
||||||
const { place, path } = bin;
|
|
||||||
return `${place.desk}${place.path}${path}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function harkBinEq(a: HarkBin, b: HarkBin): boolean {
|
|
||||||
return (
|
|
||||||
a.place.path === b.place.path &&
|
|
||||||
a.place.desk === b.place.desk &&
|
|
||||||
a.path === b.path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function harkLidToId(lid: HarkLid): string {
|
|
||||||
if('time' in lid) {
|
|
||||||
return `archive-${lid.time}`;
|
|
||||||
}
|
|
||||||
return Object.keys(lid)[0];
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
|
|
||||||
export interface HarkStats {
|
|
||||||
count: number;
|
|
||||||
each: string[];
|
|
||||||
last: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Timebox {
|
|
||||||
[binId: string]: Notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type HarkContent = { ship: string; } | { text: string; };
|
|
||||||
|
|
||||||
export interface HarkBody {
|
|
||||||
title: HarkContent[];
|
|
||||||
time: number;
|
|
||||||
content: HarkContent[];
|
|
||||||
link: string;
|
|
||||||
binned: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HarkPlace {
|
|
||||||
desk: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HarkBin {
|
|
||||||
path: string;
|
|
||||||
place: HarkPlace;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type HarkLid =
|
|
||||||
{ unseen: null; }
|
|
||||||
| { seen: null; }
|
|
||||||
| { time: string; };
|
|
||||||
|
|
||||||
export type HarkBinId = string;
|
|
||||||
export interface Notification {
|
|
||||||
bin: HarkBin;
|
|
||||||
time: number;
|
|
||||||
body: HarkBody[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotificationGraphConfig {
|
|
||||||
watchOnSelf: boolean;
|
|
||||||
mentions: boolean;
|
|
||||||
watching: WatchedIndex[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Unreads {
|
|
||||||
[path: string]: HarkStats;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface WatchedIndex {
|
|
||||||
graph: string;
|
|
||||||
index: string;
|
|
||||||
}
|
|
||||||
export type GroupNotificationsConfig = string[];
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './lib';
|
|
||||||
export * from './types';
|
|
@ -1,127 +0,0 @@
|
|||||||
import { Poke, Scry } from '../lib';
|
|
||||||
import { Pike } from './types';
|
|
||||||
|
|
||||||
export const getPikes: Scry = {
|
|
||||||
app: 'hood',
|
|
||||||
path: '/kiln/pikes'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install a foreign desk
|
|
||||||
*/
|
|
||||||
export function kilnInstall(
|
|
||||||
ship: string,
|
|
||||||
desk: string,
|
|
||||||
local?: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-install',
|
|
||||||
json: {
|
|
||||||
ship,
|
|
||||||
desk,
|
|
||||||
local: local || desk
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync with a foreign desk
|
|
||||||
*/
|
|
||||||
export function kilnSync(
|
|
||||||
ship: string,
|
|
||||||
desk: string,
|
|
||||||
local?: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-sync',
|
|
||||||
json: {
|
|
||||||
ship,
|
|
||||||
desk,
|
|
||||||
local: local || desk
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsync with a foreign desk
|
|
||||||
*/
|
|
||||||
export function kilnUnsync(
|
|
||||||
ship: string,
|
|
||||||
desk: string,
|
|
||||||
local?: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-unsync',
|
|
||||||
json: {
|
|
||||||
ship,
|
|
||||||
desk,
|
|
||||||
local: local || desk
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uninstall a desk
|
|
||||||
*/
|
|
||||||
export function kilnUninstall(
|
|
||||||
desk: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-uninstall',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kilnSuspend(
|
|
||||||
desk: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-suspend',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kilnRevive(
|
|
||||||
desk: string
|
|
||||||
): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-revive',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kilnBump(): Poke<any> {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-bump',
|
|
||||||
json: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kilnPause(desk: string) {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-pause',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function kilnResume(desk: string) {
|
|
||||||
return {
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'kiln-resume',
|
|
||||||
json: desk
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const scryLag: Scry = ({ app: 'hood', path: '/kiln/lag' });
|
|
||||||
|
|
||||||
export function getPikePublisher(pike: Pike) {
|
|
||||||
return pike.sync?.ship;
|
|
||||||
}
|
|
@ -1,208 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* A pending commit, awaiting a future kelvin version
|
|
||||||
*/
|
|
||||||
interface Woof {
|
|
||||||
aeon: number;
|
|
||||||
weft: Weft;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Rein {
|
|
||||||
/**
|
|
||||||
* Agents not in manifest that should be running
|
|
||||||
*/
|
|
||||||
add: string[];
|
|
||||||
/**
|
|
||||||
* Agents in manifest that should not be running
|
|
||||||
*/
|
|
||||||
sub: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Rail {
|
|
||||||
/**
|
|
||||||
* Original publisher of desk, if available
|
|
||||||
*/
|
|
||||||
publisher: string | null;
|
|
||||||
/**
|
|
||||||
* Ship of foreign vat
|
|
||||||
*/
|
|
||||||
ship: string;
|
|
||||||
/**
|
|
||||||
* Desk of foreign vat
|
|
||||||
*/
|
|
||||||
desk: string;
|
|
||||||
/**
|
|
||||||
* Aeon (version number) that we currently have synced
|
|
||||||
*/
|
|
||||||
aeon: number;
|
|
||||||
next: Woof[];
|
|
||||||
paused: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A tracker of a foreign {@link Vat}
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export interface Arak {
|
|
||||||
rein: Rein;
|
|
||||||
rail: Rail | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A component's kelvin version
|
|
||||||
*/
|
|
||||||
export interface Weft {
|
|
||||||
/**
|
|
||||||
* Name of the component
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Usually %zuse, %hoon, or %lull
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* Kelvin version
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
kelvin: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KilnDiffBlock {
|
|
||||||
block: {
|
|
||||||
desk: string;
|
|
||||||
arak: Arak;
|
|
||||||
weft: Weft;
|
|
||||||
blockers: string[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KilnDiffReset {
|
|
||||||
reset: {
|
|
||||||
desk: string;
|
|
||||||
arak: Arak;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KilnDiffMerge {
|
|
||||||
merge: {
|
|
||||||
desk: string;
|
|
||||||
arak: Arak;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KilnDiffMergeSunk {
|
|
||||||
'merge-sunk': {
|
|
||||||
desk: string;
|
|
||||||
arak: Arak;
|
|
||||||
tang: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KilnDiffMergeFail {
|
|
||||||
'merge-fail': {
|
|
||||||
desk: string;
|
|
||||||
arak: Arak;
|
|
||||||
tang: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type KilnDiff =
|
|
||||||
| KilnDiffBlock
|
|
||||||
| KilnDiffReset
|
|
||||||
| KilnDiffMerge
|
|
||||||
| KilnDiffMergeSunk
|
|
||||||
| KilnDiffMergeFail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cases for revision
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export interface Cass {
|
|
||||||
/**
|
|
||||||
* Revision number
|
|
||||||
*/
|
|
||||||
ud: number;
|
|
||||||
/**
|
|
||||||
* Timestamp of revision, as stringifed `@da`
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* If \@da is outside valid positive unix timestamp, value will be zero
|
|
||||||
*/
|
|
||||||
da: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A local desk installation
|
|
||||||
*/
|
|
||||||
export interface Vat {
|
|
||||||
/**
|
|
||||||
* Desk that this Vat describes
|
|
||||||
*/
|
|
||||||
desk: string;
|
|
||||||
/**
|
|
||||||
* Hash of the desk, rendered as `@uv`
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Equivalent to
|
|
||||||
* ```hoon
|
|
||||||
* .^(@uv %cz /=desk=)
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
hash: string;
|
|
||||||
/**
|
|
||||||
* Current revision
|
|
||||||
*/
|
|
||||||
cass: Cass;
|
|
||||||
/**
|
|
||||||
* Foreign sync
|
|
||||||
*/
|
|
||||||
arak: Arak;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Vats {
|
|
||||||
[desk: string]: Vat;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* TODO: crisp one-liner describing a Pike
|
|
||||||
*/
|
|
||||||
export interface Pike {
|
|
||||||
/**
|
|
||||||
* Hash of the desk, rendered as `@uv`
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* Equivalent to
|
|
||||||
* ```hoon
|
|
||||||
* .^(@uv %cz /=desk=)
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
hash: string;
|
|
||||||
sync: {
|
|
||||||
/**
|
|
||||||
* Source desk for this Pike
|
|
||||||
*/
|
|
||||||
desk: string;
|
|
||||||
/**
|
|
||||||
* Source ship for this Pike
|
|
||||||
*/
|
|
||||||
ship: string;
|
|
||||||
} | null;
|
|
||||||
/**
|
|
||||||
* {@link Weft}s associated with this Pike
|
|
||||||
*/
|
|
||||||
wefts: Weft[];
|
|
||||||
/**
|
|
||||||
* how live is this pike?
|
|
||||||
*
|
|
||||||
* live - app is running
|
|
||||||
* held - app is not running, but is trying to run. this state can be entered
|
|
||||||
* in two main ways:
|
|
||||||
* - when installing an app but it hasn't finished downloading (or it did
|
|
||||||
* but failed to install for some reason)
|
|
||||||
* - when user forced a kelvin upgrade by suspending desks.
|
|
||||||
* dead - app is not running
|
|
||||||
*/
|
|
||||||
zest: "live" | "dead" | "held";
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Pikes {
|
|
||||||
[desk: string]: Pike;
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
export * from './contacts';
|
|
||||||
export * as contacts from './contacts';
|
|
||||||
export * from './graph';
|
|
||||||
export * as graph from './graph';
|
|
||||||
export * from './groups';
|
|
||||||
export * as groups from './groups';
|
|
||||||
export * from './hark';
|
|
||||||
export * as hark from './hark';
|
|
||||||
export * from './invite';
|
|
||||||
// this conflicts with /groups/lib invite
|
|
||||||
// export * as invite from './invite';
|
|
||||||
export * from './metadata';
|
|
||||||
export * as metadata from './metadata';
|
|
||||||
export * from './settings';
|
|
||||||
export * as settings from './settings';
|
|
||||||
export * from './s3';
|
|
||||||
export * as s3 from './s3';
|
|
||||||
export * from './lib';
|
|
||||||
export * from './lib/BigIntOrderedMap';
|
|
||||||
export * from './lib/BigIntArrayOrderedMap';
|
|
||||||
export * as hood from './hood';
|
|
||||||
export * from './hood';
|
|
||||||
export * as docket from './docket';
|
|
||||||
export * from './docket';
|
|
||||||
export * as term from './term';
|
|
||||||
export * from './term';
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,28 +0,0 @@
|
|||||||
import { Poke, Serial } from "../lib";
|
|
||||||
import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types";
|
|
||||||
|
|
||||||
export const inviteAction = <T extends InviteUpdate>(data: T): Poke<T> => ({
|
|
||||||
app: 'invite-store',
|
|
||||||
mark: 'invite-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export const accept = (
|
|
||||||
app: string,
|
|
||||||
uid: Serial
|
|
||||||
): Poke<InviteUpdateAccept> => inviteAction({
|
|
||||||
accept: {
|
|
||||||
term: app,
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const decline = (
|
|
||||||
app: string,
|
|
||||||
uid: Serial
|
|
||||||
): Poke<InviteUpdateDecline> => inviteAction({
|
|
||||||
decline: {
|
|
||||||
term: app,
|
|
||||||
uid
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,75 +0,0 @@
|
|||||||
import { Serial, PatpNoSig, Path } from '../lib';
|
|
||||||
import { Resource } from "../groups";
|
|
||||||
|
|
||||||
export type InviteUpdate =
|
|
||||||
InviteUpdateInitial
|
|
||||||
| InviteUpdateCreate
|
|
||||||
| InviteUpdateDelete
|
|
||||||
| InviteUpdateInvite
|
|
||||||
| InviteUpdateAccept
|
|
||||||
| InviteUpdateAccepted
|
|
||||||
| InviteUpdateDecline;
|
|
||||||
|
|
||||||
export interface InviteUpdateAccept {
|
|
||||||
accept: {
|
|
||||||
term: string;
|
|
||||||
uid: Serial;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateInitial {
|
|
||||||
initial: Invites;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateCreate {
|
|
||||||
create: {
|
|
||||||
term: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateDelete {
|
|
||||||
delete: {
|
|
||||||
term: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateInvite {
|
|
||||||
invite: {
|
|
||||||
term: string;
|
|
||||||
uid: Serial;
|
|
||||||
invite: Invite;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateAccepted {
|
|
||||||
accepted: {
|
|
||||||
term: string;
|
|
||||||
uid: Serial;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InviteUpdateDecline {
|
|
||||||
decline: {
|
|
||||||
term: string;
|
|
||||||
uid: Serial;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual datastructures
|
|
||||||
|
|
||||||
|
|
||||||
export type Invites = {
|
|
||||||
[p in Path]: AppInvites;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AppInvites = {
|
|
||||||
[s in Serial]: Invite;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface Invite {
|
|
||||||
app: string;
|
|
||||||
recipient: PatpNoSig;
|
|
||||||
resource: Resource;
|
|
||||||
ship: PatpNoSig;
|
|
||||||
text: string;
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer';
|
|
||||||
import bigInt, { BigInteger } from 'big-integer';
|
|
||||||
|
|
||||||
setAutoFreeze(false);
|
|
||||||
|
|
||||||
enablePatches();
|
|
||||||
|
|
||||||
export function stringToArr(str: string) {
|
|
||||||
return str.split('/').slice(1).map((ind) => {
|
|
||||||
return bigInt(ind);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function arrToString(arr: BigInteger[]) {
|
|
||||||
let string = '';
|
|
||||||
arr.forEach((key) => {
|
|
||||||
string = string + `/${key.toString()}`;
|
|
||||||
});
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sorted(a: BigInteger[], b: BigInteger[], reversed = false) {
|
|
||||||
const getSort = sortBigIntArr(a, b);
|
|
||||||
if (reversed) {
|
|
||||||
return getSort * -1;
|
|
||||||
} else {
|
|
||||||
return getSort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) {
|
|
||||||
const aLen = a.length;
|
|
||||||
const bLen = b.length;
|
|
||||||
|
|
||||||
const aCop = a.slice(0);
|
|
||||||
const bCop = b.slice(0);
|
|
||||||
aCop.reverse();
|
|
||||||
bCop.reverse();
|
|
||||||
|
|
||||||
let i = 0;
|
|
||||||
while (i < aLen && i < bLen) {
|
|
||||||
if (aCop[i].lt(bCop[i])) {
|
|
||||||
return 1;
|
|
||||||
} else if (aCop[i].gt(bCop[i])) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bLen - aLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class BigIntArrayOrderedMap<V> implements Iterable<[BigInteger[], V]> {
|
|
||||||
root: Record<string, V> = {}
|
|
||||||
cachedIter: [BigInteger[], V][] | null = null;
|
|
||||||
[immerable] = true;
|
|
||||||
reversed = false;
|
|
||||||
|
|
||||||
constructor(items: [BigInteger[], V][] = [], reversed = false) {
|
|
||||||
items.forEach(([key, val]) => {
|
|
||||||
this.set(key, val);
|
|
||||||
});
|
|
||||||
this.reversed = reversed;
|
|
||||||
}
|
|
||||||
|
|
||||||
get size() {
|
|
||||||
return Object.keys(this.root).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key: BigInteger[]) {
|
|
||||||
return this.root[arrToString(key)] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
gas(items: [BigInteger[], V][]) {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
items.forEach(([key, value]) => {
|
|
||||||
draft.root[arrToString(key)] = castDraft(value);
|
|
||||||
});
|
|
||||||
draft.generateCachedIter();
|
|
||||||
},
|
|
||||||
(patches) => {
|
|
||||||
// console.log(`gassed with ${JSON.stringify(patches, null, 2)}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key: BigInteger[], value: V) {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
draft.root[arrToString(key)] = castDraft(value);
|
|
||||||
draft.cachedIter = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
draft.cachedIter = [];
|
|
||||||
draft.root = {};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
has(key: BigInteger[]) {
|
|
||||||
return arrToString(key) in this.root;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(key: BigInteger[]) {
|
|
||||||
const result = produce(this, (draft) => {
|
|
||||||
delete draft.root[arrToString(key)];
|
|
||||||
draft.cachedIter = null;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Symbol.iterator](): IterableIterator<[BigInteger[], V]> {
|
|
||||||
let idx = 0;
|
|
||||||
const result = this.generateCachedIter();
|
|
||||||
return {
|
|
||||||
[Symbol.iterator]: this[Symbol.iterator],
|
|
||||||
next: (): IteratorResult<[BigInteger[], V]> => {
|
|
||||||
if (idx < result.length) {
|
|
||||||
return { value: result[idx++], done: false };
|
|
||||||
}
|
|
||||||
return { done: true, value: null };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
peekLargest() {
|
|
||||||
const sorted = Array.from(this);
|
|
||||||
return sorted[0] as [BigInteger[], V] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
peekSmallest() {
|
|
||||||
const sorted = Array.from(this);
|
|
||||||
return sorted[sorted.length - 1] as [BigInteger[], V] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
keys() {
|
|
||||||
return Array.from(this).map(([k,v]) => k);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateCachedIter() {
|
|
||||||
if(this.cachedIter) {
|
|
||||||
return [...this.cachedIter];
|
|
||||||
}
|
|
||||||
const result = Object.keys(this.root).map((key) => {
|
|
||||||
return [stringToArr(key), this.root[key]] as [BigInteger[], V];
|
|
||||||
}).sort(([a], [b]) => sorted(a, b, this.reversed));
|
|
||||||
this.cachedIter = result;
|
|
||||||
return [...result];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
|||||||
import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer';
|
|
||||||
import bigInt, { BigInteger } from 'big-integer';
|
|
||||||
|
|
||||||
setAutoFreeze(false);
|
|
||||||
|
|
||||||
enablePatches();
|
|
||||||
|
|
||||||
function sortBigInt(a: BigInteger, b: BigInteger) {
|
|
||||||
if (a.lt(b)) {
|
|
||||||
return 1;
|
|
||||||
} else if (a.eq(b)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class BigIntOrderedMap<V> implements Iterable<[BigInteger, V]> {
|
|
||||||
root: Record<string, V> = {}
|
|
||||||
cachedIter: [BigInteger, V][] | null = null;
|
|
||||||
[immerable] = true;
|
|
||||||
|
|
||||||
constructor(items: [BigInteger, V][] = []) {
|
|
||||||
items.forEach(([key, val]) => {
|
|
||||||
this.set(key, val);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get size() {
|
|
||||||
if(this.cachedIter) {
|
|
||||||
return this.cachedIter.length;
|
|
||||||
}
|
|
||||||
return this.generateCachedIter().length;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key: BigInteger) {
|
|
||||||
return this.root[key.toString()] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
gas(items: [BigInteger, V][]) {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
items.forEach(([key, value]) => {
|
|
||||||
draft.root[key.toString()] = castDraft(value);
|
|
||||||
});
|
|
||||||
draft.cachedIter = null;
|
|
||||||
},
|
|
||||||
(patches) => {
|
|
||||||
// console.log(`gassed with ${JSON.stringify(patches, null, 2)}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key: BigInteger, value: V) {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
draft.root[key.toString()] = castDraft(value);
|
|
||||||
draft.cachedIter = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
return produce(this, (draft) => {
|
|
||||||
draft.cachedIter = [];
|
|
||||||
draft.root = {};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
has(key: BigInteger) {
|
|
||||||
return key.toString() in this.root;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(key: BigInteger) {
|
|
||||||
const result = produce(this, (draft) => {
|
|
||||||
delete draft.root[key.toString()];
|
|
||||||
draft.cachedIter = null;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Symbol.iterator](): IterableIterator<[BigInteger, V]> {
|
|
||||||
let idx = 0;
|
|
||||||
const result = this.generateCachedIter();
|
|
||||||
return {
|
|
||||||
[Symbol.iterator]: this[Symbol.iterator],
|
|
||||||
next: (): IteratorResult<[BigInteger, V]> => {
|
|
||||||
if (idx < result.length) {
|
|
||||||
return { value: result[idx++], done: false };
|
|
||||||
}
|
|
||||||
return { done: true, value: null };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
peekLargest() {
|
|
||||||
const sorted = Array.from(this);
|
|
||||||
return sorted[0] as [BigInteger, V] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
peekSmallest() {
|
|
||||||
const sorted = Array.from(this);
|
|
||||||
return sorted[sorted.length - 1] as [BigInteger, V] | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
keys() {
|
|
||||||
return Array.from(this).map(([k,v]) => k);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateCachedIter() {
|
|
||||||
if(this.cachedIter) {
|
|
||||||
return [...this.cachedIter];
|
|
||||||
}
|
|
||||||
const result = Object.keys(this.root).map((key) => {
|
|
||||||
const num = bigInt(key);
|
|
||||||
return [num, this.root[key]] as [BigInteger, V];
|
|
||||||
}).sort(([a], [b]) => sortBigInt(a,b));
|
|
||||||
this.cachedIter = result;
|
|
||||||
return [...result];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './lib';
|
|
||||||
export * from './types';
|
|
@ -1,259 +0,0 @@
|
|||||||
import bigInt, { BigInteger } from "big-integer";
|
|
||||||
|
|
||||||
import { Resource } from "../groups/types";
|
|
||||||
import { Post, GraphNode } from "../graph/types";
|
|
||||||
|
|
||||||
const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1
|
|
||||||
|
|
||||||
const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1
|
|
||||||
|
|
||||||
function chunk<T>(arr: T[], size: number): T[][] {
|
|
||||||
let chunk: T[] = [];
|
|
||||||
let newArray = [chunk];
|
|
||||||
|
|
||||||
for (let i = 0;i < arr.length;i++) {
|
|
||||||
if (chunk.length < size) {
|
|
||||||
chunk.push(arr[i])
|
|
||||||
} else {
|
|
||||||
chunk = [arr[i]]
|
|
||||||
newArray.push(chunk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
function dropWhile<T>(arr: T[], pred: (x: T) => boolean): T[] {
|
|
||||||
const newArray = arr.slice();
|
|
||||||
|
|
||||||
for (const item of arr) {
|
|
||||||
if (pred(item)) {
|
|
||||||
newArray.shift();
|
|
||||||
} else {
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a bigint representing an urbit date, returns a unix timestamp.
|
|
||||||
*
|
|
||||||
* @param {BigInteger} da The urbit date
|
|
||||||
*
|
|
||||||
* @return {number} The unix timestamp
|
|
||||||
*/
|
|
||||||
export function daToUnix(da: BigInteger): number {
|
|
||||||
// ported from +time:enjs:format in hoon.hoon
|
|
||||||
const offset = DA_SECOND.divide(bigInt(2000));
|
|
||||||
const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH));
|
|
||||||
|
|
||||||
return Math.round(
|
|
||||||
epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a unix timestamp, returns a bigint representing an urbit date
|
|
||||||
*
|
|
||||||
* @param {number} unix The unix timestamp
|
|
||||||
*
|
|
||||||
* @return {BigInteger} The urbit date
|
|
||||||
*/
|
|
||||||
export function unixToDa(unix: number): BigInteger {
|
|
||||||
const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000));
|
|
||||||
return DA_UNIX_EPOCH.add(timeSinceEpoch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function makePatDa(patda: string): BigInteger {
|
|
||||||
return bigInt(udToDec(patda));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function udToDec(ud: string): string {
|
|
||||||
return ud.replace(/\./g, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decToUd(str: string): string {
|
|
||||||
const transform = chunk(str.split('').reverse(), 3)
|
|
||||||
.map(group => group.reverse().join(''))
|
|
||||||
.reverse()
|
|
||||||
.join('.')
|
|
||||||
return transform.replace(/^[0\.]+/g, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resourceAsPath(resource: Resource): string {
|
|
||||||
const { name, ship } = resource;
|
|
||||||
return `/ship/~${ship}/${name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uuid(): string {
|
|
||||||
let str = "0v";
|
|
||||||
str += Math.ceil(Math.random() * 8) + ".";
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
let _str = Math.ceil(Math.random() * 10000000).toString(32);
|
|
||||||
_str = ("00000" + _str).substr(-5, 5);
|
|
||||||
str += _str + ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.slice(0, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Goes from:
|
|
||||||
~2018.7.17..23.15.09..5be5 // urbit @da
|
|
||||||
To:
|
|
||||||
(javascript Date object)
|
|
||||||
*/
|
|
||||||
export function daToDate(st: string): Date {
|
|
||||||
const dub = function (n: string) {
|
|
||||||
return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString();
|
|
||||||
};
|
|
||||||
const da = st.split("..");
|
|
||||||
const bigEnd = da[0].split(".");
|
|
||||||
const lilEnd = da[1].split(".");
|
|
||||||
const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub(
|
|
||||||
lilEnd[0]
|
|
||||||
)}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`;
|
|
||||||
return new Date(ds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Goes from:
|
|
||||||
(javascript Date object)
|
|
||||||
To:
|
|
||||||
~2018.7.17..23.15.09..5be5 // urbit @da
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function dateToDa(d: Date, mil: boolean = false): string {
|
|
||||||
const fil = function (n: number) {
|
|
||||||
return n >= 10 ? n : "0" + n;
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
`~${d.getUTCFullYear()}.` +
|
|
||||||
`${d.getUTCMonth() + 1}.` +
|
|
||||||
`${fil(d.getUTCDate())}..` +
|
|
||||||
`${fil(d.getUTCHours())}.` +
|
|
||||||
`${fil(d.getUTCMinutes())}.` +
|
|
||||||
`${fil(d.getUTCSeconds())}` +
|
|
||||||
`${mil ? "..0000" : ""}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preSig(ship: string): string {
|
|
||||||
if (!ship) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ship.trim().startsWith('~')) {
|
|
||||||
return ship.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return '~'.concat(ship.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deSig(ship: string): string | null {
|
|
||||||
if (!ship) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ship.replace("~", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim patps to match dojo, chat-cli
|
|
||||||
export function cite(ship: string) {
|
|
||||||
let patp = ship,
|
|
||||||
shortened = '';
|
|
||||||
if (patp === null || patp === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (patp.startsWith('~')) {
|
|
||||||
patp = patp.substr(1);
|
|
||||||
}
|
|
||||||
// comet
|
|
||||||
if (patp.length === 56) {
|
|
||||||
shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56);
|
|
||||||
return shortened;
|
|
||||||
}
|
|
||||||
// moon
|
|
||||||
if (patp.length === 27) {
|
|
||||||
shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27);
|
|
||||||
return shortened;
|
|
||||||
}
|
|
||||||
return `~${patp}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function uxToHex(ux: string) {
|
|
||||||
if (ux.length > 2 && ux.substr(0, 2) === '0x') {
|
|
||||||
const value = ux.substr(2).replace('.', '').padStart(6, '0');
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = ux.replace('.', '').padStart(6, '0');
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hexToUx = (hex: string): string => {
|
|
||||||
const nonZeroChars = dropWhile(hex.split(''), y => y === '0');
|
|
||||||
const ux = chunk(nonZeroChars.reverse(), 4).map(x => {
|
|
||||||
return x.reverse().join('');
|
|
||||||
}).reverse().join('.') || '0';
|
|
||||||
|
|
||||||
return `0x${ux}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// encode the string into @ta-safe format, using logic from +wood.
|
|
||||||
// for example, 'some Chars!' becomes '~.some.~43.hars~21.'
|
|
||||||
//
|
|
||||||
export function stringToTa(str: string): string {
|
|
||||||
let out = "";
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
const char = str[i];
|
|
||||||
let add = "";
|
|
||||||
switch (char) {
|
|
||||||
case " ":
|
|
||||||
add = ".";
|
|
||||||
break;
|
|
||||||
case ".":
|
|
||||||
add = "~.";
|
|
||||||
break;
|
|
||||||
case "~":
|
|
||||||
add = "~~";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const charCode = str.charCodeAt(i);
|
|
||||||
if (
|
|
||||||
(charCode >= 97 && charCode <= 122) || // a-z
|
|
||||||
(charCode >= 48 && charCode <= 57) || // 0-9
|
|
||||||
char === "-"
|
|
||||||
) {
|
|
||||||
add = char;
|
|
||||||
} else {
|
|
||||||
// TODO behavior for unicode doesn't match +wood's,
|
|
||||||
// but we can probably get away with that for now.
|
|
||||||
add = "~" + charCode.toString(16) + ".";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out = out + add;
|
|
||||||
}
|
|
||||||
return "~." + out;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const buntPost = (): Post => ({
|
|
||||||
author: '',
|
|
||||||
contents: [],
|
|
||||||
hash: null,
|
|
||||||
index: '',
|
|
||||||
signatures: [],
|
|
||||||
'time-sent': 0
|
|
||||||
});
|
|
||||||
|
|
||||||
export function makeNodeMap(posts: Post[]): Record<string, GraphNode> {
|
|
||||||
const nodes: Record<string, GraphNode> = {};
|
|
||||||
posts.forEach((p: Post) => {
|
|
||||||
nodes[String(p.index)] = { children: null, post: p };
|
|
||||||
});
|
|
||||||
return nodes;
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/**
|
|
||||||
* Martian embassy
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { BigIntOrderedMap } from "./BigIntOrderedMap";
|
|
||||||
|
|
||||||
// an urbit style path rendered as string
|
|
||||||
export type Path = string;
|
|
||||||
|
|
||||||
// patp including leading sig
|
|
||||||
export type Patp = string;
|
|
||||||
|
|
||||||
// patp excluding leading sig
|
|
||||||
export type PatpNoSig = string;
|
|
||||||
|
|
||||||
// @uvH encoded string
|
|
||||||
export type Serial = string;
|
|
||||||
|
|
||||||
// jug from hoon
|
|
||||||
export type Jug<K,V> = Map<K,Set<V>>;
|
|
||||||
|
|
||||||
// name of app
|
|
||||||
export type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph' | 'groups';
|
|
||||||
|
|
||||||
export type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn';
|
|
||||||
|
|
||||||
export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete';
|
|
||||||
|
|
||||||
|
|
||||||
export type SetElement<S> = S extends Set<(infer T)> ? T : never;
|
|
||||||
export type MapKey<M> = M extends Map<(infer K), any> ? K : never;
|
|
||||||
export type MapValue<M> = M extends Map<any, (infer V)> ? V : never;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns sets into arrays and maps into objects so we can send them over the wire
|
|
||||||
*/
|
|
||||||
export type Enc<S> =
|
|
||||||
S extends Set<any> ?
|
|
||||||
Enc<SetElement<S>>[] :
|
|
||||||
S extends Map<string, any> ?
|
|
||||||
{ [s: string]: Enc<MapValue<S>> } :
|
|
||||||
S extends object ?
|
|
||||||
{ [K in keyof S]: Enc<S[K]> } :
|
|
||||||
S extends BigIntOrderedMap<infer T> ?
|
|
||||||
{ [index: string]: T } :
|
|
||||||
S;
|
|
||||||
|
|
||||||
export type Mark = string;
|
|
||||||
|
|
||||||
export interface Poke<Action> {
|
|
||||||
ship?: string; // This should be handled by the http library, but is part of the spec
|
|
||||||
app: string;
|
|
||||||
mark: Mark;
|
|
||||||
json: Action;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Scry {
|
|
||||||
app: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Thread<Action> {
|
|
||||||
inputMark: string;
|
|
||||||
outputMark: string;
|
|
||||||
threadName: string;
|
|
||||||
body: Action;
|
|
||||||
}
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,99 +0,0 @@
|
|||||||
import { Path, Poke, uxToHex, PatpNoSig } from '../lib';
|
|
||||||
import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types';
|
|
||||||
|
|
||||||
export const METADATA_UPDATE_VERSION = 2;
|
|
||||||
|
|
||||||
export const metadataAction = <T extends MetadataUpdate>(data: T, version: number = METADATA_UPDATE_VERSION): Poke<T> => ({
|
|
||||||
app: 'metadata-push-hook',
|
|
||||||
mark: `metadata-update-${version}`,
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export const add = (
|
|
||||||
ship: PatpNoSig,
|
|
||||||
appName: MdAppName,
|
|
||||||
resource: Path,
|
|
||||||
group: Path,
|
|
||||||
title: string,
|
|
||||||
description: string,
|
|
||||||
dateCreated: string,
|
|
||||||
color: string,
|
|
||||||
moduleName: string
|
|
||||||
): Poke<MetadataUpdateAdd> => metadataAction({
|
|
||||||
add: {
|
|
||||||
group,
|
|
||||||
resource: {
|
|
||||||
resource,
|
|
||||||
'app-name': appName
|
|
||||||
},
|
|
||||||
metadata: {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
color,
|
|
||||||
'date-created': dateCreated,
|
|
||||||
creator: `~${ship}`,
|
|
||||||
config: { graph: moduleName },
|
|
||||||
picture: '',
|
|
||||||
hidden: false,
|
|
||||||
preview: false,
|
|
||||||
vip: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export { add as metadataAdd };
|
|
||||||
|
|
||||||
export const remove = (
|
|
||||||
appName: MdAppName,
|
|
||||||
resource: string,
|
|
||||||
group: string
|
|
||||||
): Poke<MetadataUpdateRemove> => metadataAction<MetadataUpdateRemove>({
|
|
||||||
remove: {
|
|
||||||
group,
|
|
||||||
resource: {
|
|
||||||
resource,
|
|
||||||
'app-name': appName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export { remove as metadataRemove };
|
|
||||||
|
|
||||||
export const edit = (
|
|
||||||
association: Association,
|
|
||||||
edit: MetadataEditField
|
|
||||||
): Poke<MetadataUpdateEdit> => metadataAction<MetadataUpdateEdit>({
|
|
||||||
edit: {
|
|
||||||
group: association.group,
|
|
||||||
resource: {
|
|
||||||
resource: association.resource,
|
|
||||||
'app-name': association['app-name']
|
|
||||||
},
|
|
||||||
edit
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export { edit as metadataEdit };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated use {@link edit} instead
|
|
||||||
*/
|
|
||||||
export const update = (
|
|
||||||
association: Association,
|
|
||||||
newMetadata: Partial<Metadata>
|
|
||||||
): Poke<MetadataUpdateAdd> => {
|
|
||||||
const metadata = { ...association.metadata, ...newMetadata };
|
|
||||||
metadata.color = uxToHex(metadata.color);
|
|
||||||
return metadataAction<MetadataUpdateAdd>({
|
|
||||||
add: {
|
|
||||||
group: association.group,
|
|
||||||
resource: {
|
|
||||||
resource: association.resource,
|
|
||||||
'app-name': association['app-name']
|
|
||||||
},
|
|
||||||
metadata
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export { update as metadataUpdate };
|
|
@ -1,101 +0,0 @@
|
|||||||
import { Path, Patp } from '../lib';
|
|
||||||
|
|
||||||
export type MdAppName = 'groups' | 'graph';
|
|
||||||
|
|
||||||
export type MetadataUpdate =
|
|
||||||
MetadataUpdateInitial
|
|
||||||
| MetadataUpdateAdd
|
|
||||||
| MetadataUpdateUpdate
|
|
||||||
| MetadataUpdateRemove
|
|
||||||
| MetadataUpdateEdit;
|
|
||||||
|
|
||||||
export interface MetadataUpdateInitial {
|
|
||||||
associations: ResourceAssociations;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ResourceAssociations = {
|
|
||||||
[p in Path]: Association;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetadataUpdateAdd = {
|
|
||||||
add: AssociationPoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetadataUpdateUpdate = {
|
|
||||||
update: AssociationPoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MetadataUpdateEdit {
|
|
||||||
edit: {
|
|
||||||
resource: MdResource;
|
|
||||||
group: string;
|
|
||||||
edit: MetadataEditField;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetadataEditField = Partial<Omit<Metadata, 'config' | 'creator' | 'date-created'>>;
|
|
||||||
|
|
||||||
export type MetadataUpdateRemove = {
|
|
||||||
remove: {
|
|
||||||
resource: MdResource;
|
|
||||||
group: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MdResource {
|
|
||||||
resource: string;
|
|
||||||
'app-name': MdAppName;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MetadataUpdatePreview {
|
|
||||||
group: string;
|
|
||||||
channels: Associations;
|
|
||||||
'channel-count': number;
|
|
||||||
members: number;
|
|
||||||
metadata: Metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Associations = {
|
|
||||||
groups: AppAssociations<GroupConfig>
|
|
||||||
graph: AppAssociations<GraphConfig>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AppAssociations<C = MetadataConfig> = {
|
|
||||||
[p in Path]: Association<C>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Association<C = MetadataConfig> = MdResource & {
|
|
||||||
group: Path;
|
|
||||||
metadata: Metadata<C>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface AssociationPoke {
|
|
||||||
group: Path;
|
|
||||||
resource: MdResource;
|
|
||||||
metadata: Metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Metadata<C = MetadataConfig> {
|
|
||||||
color: string;
|
|
||||||
creator: Patp;
|
|
||||||
'date-created': string;
|
|
||||||
description: string;
|
|
||||||
title: string;
|
|
||||||
config: C;
|
|
||||||
hidden: boolean;
|
|
||||||
picture: string;
|
|
||||||
preview: boolean;
|
|
||||||
vip: PermVariation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MetadataConfig = GroupConfig | GraphConfig;
|
|
||||||
|
|
||||||
export interface GraphConfig {
|
|
||||||
graph: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GroupConfig {
|
|
||||||
group: undefined | {} | MdResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PermVariation = '' | ' ' | 'reader-comments' | 'member-metadata' | 'host-feed' | 'admin-feed';
|
|
1891
pkg/npm/api/package-lock.json
generated
1891
pkg/npm/api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@urbit/api",
|
|
||||||
"version": "2.2.0",
|
|
||||||
"description": "A library that provides bindings and types for Urbit's various userspace desks",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "ssh://git@github.com/urbit/urbit.git",
|
|
||||||
"directory": "pkg/npm/api"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"main": "dist/cjs/index.cjs",
|
|
||||||
"module": "dist/esm/index.js",
|
|
||||||
"exports": {
|
|
||||||
"require": "./dist/cjs/index.cjs",
|
|
||||||
"import": "./dist/esm/index.js"
|
|
||||||
},
|
|
||||||
"jsdelivr": "dist/urbit-api.min.js",
|
|
||||||
"unpkg": "dist/urbit-api.min.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"files": [
|
|
||||||
"dist/**"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"No test specified\" && exit 0",
|
|
||||||
"build": "npm run clean && rollup -c && npx tsc -p tsconfig.json",
|
|
||||||
"prepare": "npm run build",
|
|
||||||
"watch": "rollup -c -w",
|
|
||||||
"clean": "rm -rf dist/* types/*"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.16.0",
|
|
||||||
"big-integer": "^1.6.48",
|
|
||||||
"core-js": "^3.19.1",
|
|
||||||
"immer": "^9.0.1",
|
|
||||||
"urbit-ob": "^5.0.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.16.0",
|
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
|
||||||
"@rollup/plugin-commonjs": "^21.0.1",
|
|
||||||
"@rollup/plugin-node-resolve": "^13.0.6",
|
|
||||||
"@types/node": "^15.12.5",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.28.2",
|
|
||||||
"@typescript-eslint/parser": "^4.28.2",
|
|
||||||
"@urbit/eslint-config": "^1.0.3",
|
|
||||||
"babel-eslint": "^10.1.0",
|
|
||||||
"eslint-plugin-react": "^7.24.0",
|
|
||||||
"rollup": "^2.59.0",
|
|
||||||
"rollup-plugin-analyzer": "^4.0.0",
|
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
|
||||||
"rollup-plugin-typescript2": "^0.30.0",
|
|
||||||
"typescript": "^4.3.2"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
||||||
import commonJS from '@rollup/plugin-commonjs';
|
|
||||||
import { terser } from 'rollup-plugin-terser';
|
|
||||||
import babel from '@rollup/plugin-babel';
|
|
||||||
import typescript from 'rollup-plugin-typescript2';
|
|
||||||
import analyze from 'rollup-plugin-analyzer'
|
|
||||||
|
|
||||||
const input = ['./index.ts'];
|
|
||||||
|
|
||||||
// Skip certain warnings
|
|
||||||
function onwarn(warning) {
|
|
||||||
if (warning.code === 'THIS_IS_UNDEFINED') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(warning.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
input,
|
|
||||||
onwarn,
|
|
||||||
plugins: [
|
|
||||||
nodeResolve({
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx']
|
|
||||||
}),
|
|
||||||
commonJS(),
|
|
||||||
typescript(),
|
|
||||||
babel({
|
|
||||||
babelHelpers: 'bundled',
|
|
||||||
exclude: ['node_modules/**']
|
|
||||||
}),
|
|
||||||
terser({
|
|
||||||
ecma: 2017,
|
|
||||||
compress: true,
|
|
||||||
mangle: true
|
|
||||||
})
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
file: 'dist/urbit-api.min.js',
|
|
||||||
format: 'umd',
|
|
||||||
name: 'UrbitAPI', // this is the name of the global object
|
|
||||||
esModule: false,
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input,
|
|
||||||
onwarn,
|
|
||||||
plugins: [
|
|
||||||
nodeResolve({
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx']
|
|
||||||
}),
|
|
||||||
commonJS(),
|
|
||||||
typescript(),
|
|
||||||
analyze({
|
|
||||||
limit: 10
|
|
||||||
})
|
|
||||||
],
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
file: 'dist/esm/index.js',
|
|
||||||
format: 'esm',
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
file: 'dist/cjs/index.cjs',
|
|
||||||
format: 'cjs',
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './lib';
|
|
||||||
export * from './types';
|
|
@ -1,47 +0,0 @@
|
|||||||
import { Poke } from '../lib/types';
|
|
||||||
import { S3Update, S3UpdateAccessKeyId, S3UpdateAddBucket, S3UpdateCurrentBucket, S3UpdateEndpoint, S3UpdateRemoveBucket, S3UpdateSecretAccessKey } from './types';
|
|
||||||
|
|
||||||
const s3Action = <T extends S3Update>(
|
|
||||||
data: any
|
|
||||||
): Poke<T> => ({
|
|
||||||
app: 's3-store',
|
|
||||||
mark: 's3-action',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setCurrentBucket = (
|
|
||||||
bucket: string
|
|
||||||
): Poke<S3UpdateCurrentBucket> => s3Action({
|
|
||||||
'set-current-bucket': bucket
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addBucket = (
|
|
||||||
bucket: string
|
|
||||||
): Poke<S3UpdateAddBucket> => s3Action({
|
|
||||||
'add-bucket': bucket
|
|
||||||
});
|
|
||||||
|
|
||||||
export const removeBucket = (
|
|
||||||
bucket: string
|
|
||||||
): Poke<S3UpdateRemoveBucket> => s3Action({
|
|
||||||
'remove-bucket': bucket
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setEndpoint = (
|
|
||||||
endpoint: string
|
|
||||||
): Poke<S3UpdateEndpoint> => s3Action({
|
|
||||||
'set-endpoint': endpoint
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setAccessKeyId = (
|
|
||||||
accessKeyId: string
|
|
||||||
): Poke<S3UpdateAccessKeyId> => s3Action({
|
|
||||||
'set-access-key-id': accessKeyId
|
|
||||||
});
|
|
||||||
|
|
||||||
export const setSecretAccessKey = (
|
|
||||||
secretAccessKey: string
|
|
||||||
): Poke<S3UpdateSecretAccessKey> => s3Action({
|
|
||||||
'set-secret-access-key': secretAccessKey
|
|
||||||
});
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
|||||||
export interface S3Credentials {
|
|
||||||
endpoint: string;
|
|
||||||
accessKeyId: string;
|
|
||||||
secretAccessKey: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3Configuration {
|
|
||||||
buckets: Set<string>;
|
|
||||||
currentBucket: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3State {
|
|
||||||
configuration: S3Configuration;
|
|
||||||
credentials: S3Credentials | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateCredentials {
|
|
||||||
credentials: S3Credentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateConfiguration {
|
|
||||||
configuration: {
|
|
||||||
buckets: string[];
|
|
||||||
currentBucket: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateCurrentBucket {
|
|
||||||
setCurrentBucket: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateAddBucket {
|
|
||||||
addBucket: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateRemoveBucket {
|
|
||||||
removeBucket: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateEndpoint {
|
|
||||||
setEndpoint: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateAccessKeyId {
|
|
||||||
setAccessKeyId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface S3UpdateSecretAccessKey {
|
|
||||||
setSecretAccessKey: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type S3Update =
|
|
||||||
S3UpdateCredentials
|
|
||||||
| S3UpdateConfiguration
|
|
||||||
| S3UpdateCurrentBucket
|
|
||||||
| S3UpdateAddBucket
|
|
||||||
| S3UpdateRemoveBucket
|
|
||||||
| S3UpdateEndpoint
|
|
||||||
| S3UpdateAccessKeyId
|
|
||||||
| S3UpdateSecretAccessKey;
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,78 +0,0 @@
|
|||||||
import { Poke, Scry } from '../lib';
|
|
||||||
import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types';
|
|
||||||
|
|
||||||
export const action = <T extends SettingsUpdate>(data: T): Poke<T> => ({
|
|
||||||
app: 'settings-store',
|
|
||||||
mark: 'settings-event',
|
|
||||||
json: data
|
|
||||||
});
|
|
||||||
|
|
||||||
export const putBucket = (
|
|
||||||
desk: string,
|
|
||||||
key: Key,
|
|
||||||
bucket: Bucket
|
|
||||||
): Poke<PutBucket> => action({
|
|
||||||
'put-bucket': {
|
|
||||||
desk,
|
|
||||||
'bucket-key': key,
|
|
||||||
'bucket': bucket
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const delBucket = (
|
|
||||||
desk: string,
|
|
||||||
key: Key
|
|
||||||
): Poke<DelBucket> => action({
|
|
||||||
'del-bucket': {
|
|
||||||
desk,
|
|
||||||
'bucket-key': key
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const putEntry = (
|
|
||||||
desk: string,
|
|
||||||
bucket: Key,
|
|
||||||
key: Key,
|
|
||||||
value: Value
|
|
||||||
): Poke<PutEntry> => action({
|
|
||||||
'put-entry': {
|
|
||||||
desk,
|
|
||||||
'bucket-key': bucket,
|
|
||||||
'entry-key': key,
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const delEntry = (
|
|
||||||
desk: string,
|
|
||||||
bucket: Key,
|
|
||||||
key: Key
|
|
||||||
): Poke<DelEntry> => action({
|
|
||||||
'del-entry': {
|
|
||||||
desk,
|
|
||||||
'bucket-key': bucket,
|
|
||||||
'entry-key': key
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getAll: Scry = {
|
|
||||||
app: 'settings-store',
|
|
||||||
path: '/all'
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getBucket = (desk: string, bucket: string) => ({
|
|
||||||
app: 'settings-store',
|
|
||||||
path: `/bucket/${bucket}`
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getEntry = (desk: string, bucket: string, entry: string) => ({
|
|
||||||
app: 'settings-store',
|
|
||||||
path: `/entry/${desk}/${bucket}/${entry}`
|
|
||||||
});
|
|
||||||
|
|
||||||
export const getDeskSettings = (desk: string) => ({
|
|
||||||
app: 'settings-store',
|
|
||||||
path: `/desk/${desk}`
|
|
||||||
});
|
|
||||||
|
|
||||||
export * from './types';
|
|
@ -1,64 +0,0 @@
|
|||||||
export type Key = string;
|
|
||||||
export type Value = string | string[] | boolean | number;
|
|
||||||
export type Bucket = { [key: string]: Value; };
|
|
||||||
export type DeskSettings = { [bucket: string]: Bucket; };
|
|
||||||
export type Settings = { [desk: string]: Settings; }
|
|
||||||
|
|
||||||
export interface PutBucket {
|
|
||||||
'put-bucket': {
|
|
||||||
desk: string;
|
|
||||||
'bucket-key': Key;
|
|
||||||
'bucket': Bucket;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DelBucket {
|
|
||||||
'del-bucket': {
|
|
||||||
desk: string;
|
|
||||||
'bucket-key': Key;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PutEntry {
|
|
||||||
'put-entry': {
|
|
||||||
'bucket-key': Key;
|
|
||||||
'entry-key': Key;
|
|
||||||
'value'?: Value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DelEntry {
|
|
||||||
'del-entry': {
|
|
||||||
desk: string;
|
|
||||||
'bucket-key': Key;
|
|
||||||
'entry-key': Key;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AllData {
|
|
||||||
'all': Settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DeskData {
|
|
||||||
desk: DeskSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BucketData {
|
|
||||||
'bucket': Bucket;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EntryData {
|
|
||||||
'entry': Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SettingsUpdate =
|
|
||||||
| PutBucket
|
|
||||||
| DelBucket
|
|
||||||
| PutEntry
|
|
||||||
| DelEntry;
|
|
||||||
|
|
||||||
export type SettingsData =
|
|
||||||
| AllData
|
|
||||||
| BucketData
|
|
||||||
| EntryData
|
|
||||||
| DeskData;
|
|
@ -1,2 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
export * from './lib';
|
|
@ -1,20 +0,0 @@
|
|||||||
import { Scry } from '../../http-api/src'
|
|
||||||
import { Poke } from '../../http-api/src/types';
|
|
||||||
import { Belt, Task, SessionTask } from './types';
|
|
||||||
|
|
||||||
export const pokeTask = (session: string, task: Task): Poke<SessionTask> => ({
|
|
||||||
app: 'herm',
|
|
||||||
mark: 'herm-task',
|
|
||||||
json: { session, ...task }
|
|
||||||
});
|
|
||||||
|
|
||||||
export const pokeBelt = (
|
|
||||||
session: string,
|
|
||||||
belt: Belt
|
|
||||||
): Poke<SessionTask> => pokeTask(session, { belt });
|
|
||||||
|
|
||||||
//NOTE scry will return string[]
|
|
||||||
export const scrySessions = (): Scry => ({
|
|
||||||
app: 'herm',
|
|
||||||
path: `/sessions`
|
|
||||||
});
|
|
@ -1,61 +0,0 @@
|
|||||||
// outputs
|
|
||||||
//
|
|
||||||
|
|
||||||
export type TermUpdate =
|
|
||||||
| Blit;
|
|
||||||
|
|
||||||
export type Tint =
|
|
||||||
| null
|
|
||||||
| 'r' | 'g' | 'b' | 'c' | 'm' | 'y' | 'k' | 'w'
|
|
||||||
| { r: number, g: number, b: number };
|
|
||||||
|
|
||||||
export type Deco = null | 'br' | 'un' | 'bl';
|
|
||||||
|
|
||||||
export type Stye = {
|
|
||||||
deco: Deco[],
|
|
||||||
back: Tint,
|
|
||||||
fore: Tint
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Stub = {
|
|
||||||
stye: Stye,
|
|
||||||
text: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Blit =
|
|
||||||
| { bel: null } // make a noise
|
|
||||||
| { clr: null } // clear the screen
|
|
||||||
| { hop: number | { x: number, y: number } } // set cursor col/pos
|
|
||||||
| { klr: Stub[] } // put styled
|
|
||||||
| { mor: Blit[] } // multiple blits
|
|
||||||
| { nel: null } // newline
|
|
||||||
| { put: string[] } // put text at cursor
|
|
||||||
| { sag: { path: string, file: string } } // save to jamfile
|
|
||||||
| { sav: { path: string, file: string } } // save to file
|
|
||||||
| { url: string } // activate url
|
|
||||||
| { wyp: null } // wipe cursor line
|
|
||||||
|
|
||||||
// inputs
|
|
||||||
//
|
|
||||||
|
|
||||||
export type Bolt =
|
|
||||||
| string
|
|
||||||
| { aro: 'd' | 'l' | 'r' | 'u' }
|
|
||||||
| { bac: null }
|
|
||||||
| { del: null }
|
|
||||||
| { hit: { x: number, y: number } }
|
|
||||||
| { ret: null }
|
|
||||||
|
|
||||||
export type Belt =
|
|
||||||
| Bolt
|
|
||||||
| { mod: { mod: 'ctl' | 'met' | 'hyp', key: Bolt } }
|
|
||||||
| { txt: Array<string> }
|
|
||||||
|
|
||||||
export type Task =
|
|
||||||
| { belt: Belt }
|
|
||||||
| { blew: { w: number, h: number } }
|
|
||||||
| { hail: null }
|
|
||||||
| { open: { term: string, apps: Array<{ who: string, app: string }> } }
|
|
||||||
| { shut: null }
|
|
||||||
|
|
||||||
export type SessionTask = { session: string } & Task
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"baseUrl": ".",
|
|
||||||
"outDir": "./tmp",
|
|
||||||
"module": "ESNext",
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"target": "ESNext",
|
|
||||||
"pretty": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"declaration": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"strict": false,
|
|
||||||
"noErrorTruncation": true
|
|
||||||
},
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"./dist/**/*",
|
|
||||||
"./tmp/**/*",
|
|
||||||
"rollup.config.ts"
|
|
||||||
],
|
|
||||||
"include": ["./*.ts"]
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
const env = {
|
|
||||||
"browser": true,
|
|
||||||
"es6": true,
|
|
||||||
"node": true
|
|
||||||
};
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
"array-bracket-spacing": ["error", "never"],
|
|
||||||
"arrow-parens": [
|
|
||||||
"error",
|
|
||||||
"as-needed",
|
|
||||||
{
|
|
||||||
"requireForBlockBody": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"arrow-spacing": "error",
|
|
||||||
"@typescript-eslint/ban-ts-comment": [2,
|
|
||||||
{
|
|
||||||
'ts-expect-error': 'allow-with-description',
|
|
||||||
'ts-ignore': 'allow-with-description',
|
|
||||||
'ts-nocheck': 'allow-with-description',
|
|
||||||
'ts-check': 'allow-with-description',
|
|
||||||
minimumDescriptionLength: 3,
|
|
||||||
}],
|
|
||||||
"@typescript-eslint/ban-types": "off",
|
|
||||||
"block-spacing": ["error", "always"],
|
|
||||||
"brace-style": ["error", "1tbs"],
|
|
||||||
"camelcase": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"properties": "never"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"comma-dangle": ["error", "never"],
|
|
||||||
"eol-last": ["error", "always"],
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
||||||
"func-name-matching": "error",
|
|
||||||
"indent": [
|
|
||||||
"off",
|
|
||||||
2,
|
|
||||||
{
|
|
||||||
"ArrayExpression": "off",
|
|
||||||
"SwitchCase": 1,
|
|
||||||
"CallExpression": {
|
|
||||||
"arguments": "off"
|
|
||||||
},
|
|
||||||
"FunctionDeclaration": {
|
|
||||||
"parameters": "off"
|
|
||||||
},
|
|
||||||
"FunctionExpression": {
|
|
||||||
"parameters": "off"
|
|
||||||
},
|
|
||||||
"MemberExpression": "off",
|
|
||||||
"ObjectExpression": "off",
|
|
||||||
"ImportDeclaration": "off"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"handle-callback-err": "off",
|
|
||||||
"linebreak-style": ["error", "unix"],
|
|
||||||
"max-lines": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"max": 300,
|
|
||||||
"skipBlankLines": true,
|
|
||||||
"skipComments": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"max-lines-per-function": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"skipBlankLines": true,
|
|
||||||
"skipComments": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"max-statements-per-line": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"max": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"new-cap": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"newIsCap": true,
|
|
||||||
"capIsNew": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"new-parens": "error",
|
|
||||||
"no-buffer-constructor": "error",
|
|
||||||
"no-console": "off",
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
|
||||||
"no-extra-semi": "off",
|
|
||||||
"no-fallthrough": "off",
|
|
||||||
"no-func-assign": "off",
|
|
||||||
"no-implicit-coercion": "error",
|
|
||||||
"no-multi-assign": "error",
|
|
||||||
"no-multiple-empty-lines": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"max": 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-nested-ternary": "warn",
|
|
||||||
"no-param-reassign": "off",
|
|
||||||
"no-return-assign": "error",
|
|
||||||
"no-return-await": "off",
|
|
||||||
"no-shadow-restricted-names": "error",
|
|
||||||
"no-tabs": "error",
|
|
||||||
"no-trailing-spaces": "error",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"vars": "all",
|
|
||||||
"args": "none",
|
|
||||||
"ignoreRestSiblings": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-use-before-define": "off",
|
|
||||||
"@typescript-eslint/no-use-before-define": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"functions": false,
|
|
||||||
"classes": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-useless-escape": "off",
|
|
||||||
"no-var": "error",
|
|
||||||
"nonblock-statement-body-position": ["error", "below"],
|
|
||||||
"object-curly-spacing": ["error", "always"],
|
|
||||||
"padded-blocks": ["error", "never"],
|
|
||||||
"prefer-arrow-callback": "error",
|
|
||||||
"prefer-const": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"destructuring": "all",
|
|
||||||
"ignoreReadBeforeAssign": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"prefer-template": "off",
|
|
||||||
"quotes": ["error", "single"],
|
|
||||||
"react/display-name": "off",
|
|
||||||
"semi": ["error", "always"],
|
|
||||||
"spaced-comment": [
|
|
||||||
"error",
|
|
||||||
"always",
|
|
||||||
{
|
|
||||||
"exceptions": ["!"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"space-before-blocks": "error",
|
|
||||||
"unicode-bom": ["error", "never"],
|
|
||||||
"valid-jsdoc": "error",
|
|
||||||
"wrap-iife": ["error", "inside"],
|
|
||||||
"react/jsx-closing-bracket-location": 1,
|
|
||||||
"react/jsx-tag-spacing": 1,
|
|
||||||
"react/jsx-max-props-per-line": ["error", { "maximum": 2, "when": "multiline" }],
|
|
||||||
"react/prop-types": 0
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
"env": env,
|
|
||||||
"extends": [
|
|
||||||
"plugin:react/recommended",
|
|
||||||
"eslint:recommended",
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"react": {
|
|
||||||
"version": "^16.5.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"parser": "babel-eslint",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 10,
|
|
||||||
"requireConfigFile": false,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"root": true,
|
|
||||||
"rules": rules,
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["**/*.ts", "**/*.tsx"],
|
|
||||||
"env": env,
|
|
||||||
"extends": [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/eslint-recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaFeatures": { "jsx": true },
|
|
||||||
"ecmaVersion": 10,
|
|
||||||
"requireConfigFile": false,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["@typescript-eslint"],
|
|
||||||
"rules": {
|
|
||||||
...rules,
|
|
||||||
"valid-jsdoc": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
1873
pkg/npm/eslint-config/package-lock.json
generated
1873
pkg/npm/eslint-config/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@urbit/eslint-config",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"description": "",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "ssh://git@github.com/urbit/urbit.git",
|
|
||||||
"directory": "pkg/npm/eslint-config"
|
|
||||||
},
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {},
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"devDependencies": {
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.15.0",
|
|
||||||
"@typescript-eslint/parser": "^4.15.0",
|
|
||||||
"babel-eslint": "^10.1.0",
|
|
||||||
"eslint": "^7.26.0",
|
|
||||||
"eslint-plugin-react": "^7.22.0",
|
|
||||||
"typescript": "^4.1.5"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
"@babel/preset-typescript", //needed for .ts jest tests
|
|
||||||
[
|
|
||||||
"@babel/preset-env",
|
|
||||||
{
|
|
||||||
"targets": "> 1%",
|
|
||||||
"useBuiltIns": "usage",
|
|
||||||
"corejs": "3.19.1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
4
pkg/npm/http-api/.gitignore
vendored
4
pkg/npm/http-api/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
dist
|
|
||||||
node_modules
|
|
||||||
coverage
|
|
||||||
tmp
|
|
@ -1,21 +0,0 @@
|
|||||||
# Urbit Connector
|
|
||||||
|
|
||||||
This project allows you to connect to an [Urbit](https://urbit.org) ship via a JavaScript application.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
Check out the `example` directory for examples of how to use this code.
|
|
||||||
|
|
||||||
1. Open `example/index.html` in your browser and follow the instructions there, or
|
|
||||||
2. With a ship running in the same fashion as indicated in the file above, run `node example/index.js`
|
|
||||||
|
|
||||||
The code for either of these can be found in `src/example/browser.js` or `src/example/node.js`, depending on your context.
|
|
||||||
|
|
||||||
## Design
|
|
||||||
|
|
||||||
This library is designed to be useful for node applications that communicate with an urbit running either on the local computer or on a remote one.
|
|
||||||
|
|
||||||
The majority of its methods are asynchronous and return Promises. This is due to the non-blocking nature of JavaScript. If used in a React app, response handlers should be bound with `this` to `setState` after a message is received.
|
|
||||||
|
|
||||||
## NOTE
|
|
||||||
You must enable CORS requests on your urbit for this library to work in browser context. Use `+cors-registry` to see domains which have made requests to your urbit, and then approve the needed one, e.g. `|cors-approve http://zod.arvo.network`.
|
|
@ -1,3 +0,0 @@
|
|||||||
// import Urbit from '../../dist/browser';
|
|
||||||
|
|
||||||
// window.Urbit = Urbit;
|
|
@ -1,122 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Demo</title>
|
|
||||||
<script src="../dist/urbit-http-api.min.js"></script>
|
|
||||||
<style>
|
|
||||||
@import url('https://rsms.me/inter/inter.css');
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Source Code Pro';
|
|
||||||
src: url('https://storage.googleapis.com/media.urbit.org/fonts/scp-regular.woff');
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 70ch;
|
|
||||||
padding: 2ch;
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
}
|
|
||||||
#mylog {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
padding: 2ch;
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
font-family: 'Source Code Pro', monospace;
|
|
||||||
}
|
|
||||||
#mylog div {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.chunk {
|
|
||||||
border-bottom: 1px dashed currentColor;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<details>
|
|
||||||
<summary>Show instructions</summary>
|
|
||||||
<p>Assuming you are running a fakezod on port 8080, run</p>
|
|
||||||
<code id="instructions">|cors-approve '{window.location.origin}'</code>
|
|
||||||
<p>in its dojo.</p>
|
|
||||||
<p>
|
|
||||||
Press the button to run the code below. Output will be logged. You
|
|
||||||
should see <code>< ~zod: opening airlock</code> in your dojo. Create
|
|
||||||
a chat and send a message to see the events logged.
|
|
||||||
</p>
|
|
||||||
<pre>
|
|
||||||
window.airlock = await UrbitHttpApi.Urbit.authenticate({
|
|
||||||
ship: 'zod',
|
|
||||||
url: 'localhost:8080',
|
|
||||||
code: 'lidlut-tabwed-pillex-ridrup',
|
|
||||||
verbose: true
|
|
||||||
});
|
|
||||||
window.airlock.subscribe({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: '/updates',
|
|
||||||
event: console.log
|
|
||||||
});</pre
|
|
||||||
>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<button id="blastoff" onclick="blastOff()">Blast Off</button>
|
|
||||||
<pre id="mylog"></pre>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
var baseLogFunction = console.log;
|
|
||||||
console.log = function () {
|
|
||||||
baseLogFunction.apply(console, arguments);
|
|
||||||
var chunk = document.createElement('div');
|
|
||||||
chunk.className = 'chunk';
|
|
||||||
|
|
||||||
var args = Array.prototype.slice.call(arguments);
|
|
||||||
for (var i = 0; i < args.length; i++) {
|
|
||||||
const val =
|
|
||||||
typeof args[i] === 'string' ? args[i] : JSON.stringify(args[i]);
|
|
||||||
var node = createLogNode(val);
|
|
||||||
chunk.appendChild(node);
|
|
||||||
}
|
|
||||||
document
|
|
||||||
.querySelector('#mylog')
|
|
||||||
.insertBefore(chunk, document.querySelector('#mylog').firstChild);
|
|
||||||
};
|
|
||||||
|
|
||||||
function createLogNode(message) {
|
|
||||||
var node = document.createElement('div');
|
|
||||||
node.className = 'message';
|
|
||||||
var textNode = document.createTextNode(message);
|
|
||||||
node.appendChild(textNode);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onerror = function (message, url, linenumber) {
|
|
||||||
console.log(
|
|
||||||
'JavaScript error: ' +
|
|
||||||
message +
|
|
||||||
' on line ' +
|
|
||||||
linenumber +
|
|
||||||
' for ' +
|
|
||||||
url
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const instructions = document.getElementById('instructions');
|
|
||||||
instructions.innerText = instructions.innerText.replace(
|
|
||||||
'{window.location.origin}',
|
|
||||||
window.location.origin
|
|
||||||
);
|
|
||||||
async function blastOff() {
|
|
||||||
window.airlock = await UrbitHttpApi.Urbit.authenticate({
|
|
||||||
ship: 'zod',
|
|
||||||
url: 'localhost',
|
|
||||||
code: 'lidlut-tabwed-pillex-ridrup',
|
|
||||||
verbose: true,
|
|
||||||
});
|
|
||||||
window.airlock.subscribe({
|
|
||||||
app: 'graph-store',
|
|
||||||
path: '/updates',
|
|
||||||
event: console.log,
|
|
||||||
});
|
|
||||||
document.body.removeChild(document.getElementById('blastoff'));
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||||||
// import Urbit from '../../dist/index';
|
|
||||||
|
|
||||||
// async function blastOff() {
|
|
||||||
// const airlock = await Urbit.authenticate({
|
|
||||||
// ship: 'zod',
|
|
||||||
// url: 'localhost:8080',
|
|
||||||
// code: 'lidlut-tabwed-pillex-ridrup',
|
|
||||||
// verbose: true
|
|
||||||
// });
|
|
||||||
|
|
||||||
// airlock.subscribe('chat-view', '/primary');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// blastOff();
|
|
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
* For a detailed explanation regarding each configuration property and type check, visit:
|
|
||||||
* https://jestjs.io/docs/configuration
|
|
||||||
*/
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// All imported modules in your tests should be mocked automatically
|
|
||||||
automock: false,
|
|
||||||
|
|
||||||
// Stop running tests after `n` failures
|
|
||||||
// bail: 0,
|
|
||||||
|
|
||||||
// The directory where Jest should store its cached dependency information
|
|
||||||
// cacheDirectory: "/private/var/folders/7w/hvrpvq7978bbb9kwkbhsn6rr0000gn/T/jest_dx",
|
|
||||||
|
|
||||||
// Automatically clear mock calls and instances between every test
|
|
||||||
clearMocks: true,
|
|
||||||
|
|
||||||
// Indicates whether the coverage information should be collected while executing the test
|
|
||||||
collectCoverage: true,
|
|
||||||
|
|
||||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
|
||||||
// collectCoverageFrom: undefined,
|
|
||||||
|
|
||||||
// The directory where Jest should output its coverage files
|
|
||||||
coverageDirectory: 'coverage',
|
|
||||||
|
|
||||||
// An array of regexp pattern strings used to skip coverage collection
|
|
||||||
// coveragePathIgnorePatterns: [
|
|
||||||
// "/node_modules/"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// Indicates which provider should be used to instrument code for coverage
|
|
||||||
// coverageProvider: "babel",
|
|
||||||
|
|
||||||
// A list of reporter names that Jest uses when writing coverage reports
|
|
||||||
// coverageReporters: [
|
|
||||||
// "json",
|
|
||||||
// "text",
|
|
||||||
// "lcov",
|
|
||||||
// "clover"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An object that configures minimum threshold enforcement for coverage results
|
|
||||||
// coverageThreshold: undefined,
|
|
||||||
|
|
||||||
// A path to a custom dependency extractor
|
|
||||||
// dependencyExtractor: undefined,
|
|
||||||
|
|
||||||
// Make calling deprecated APIs throw helpful error messages
|
|
||||||
// errorOnDeprecated: false,
|
|
||||||
|
|
||||||
// Force coverage collection from ignored files using an array of glob patterns
|
|
||||||
// forceCoverageMatch: [],
|
|
||||||
|
|
||||||
// A path to a module which exports an async function that is triggered once before all test suites
|
|
||||||
// globalSetup: undefined,
|
|
||||||
|
|
||||||
// A path to a module which exports an async function that is triggered once after all test suites
|
|
||||||
// globalTeardown: undefined,
|
|
||||||
|
|
||||||
// A set of global variables that need to be available in all test environments
|
|
||||||
// globals: {},
|
|
||||||
|
|
||||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
|
||||||
maxWorkers: 1,
|
|
||||||
|
|
||||||
// An array of directory names to be searched recursively up from the requiring module's location
|
|
||||||
// moduleDirectories: [
|
|
||||||
// "node_modules"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of file extensions your modules use
|
|
||||||
// moduleFileExtensions: [
|
|
||||||
// "js",
|
|
||||||
// "jsx",
|
|
||||||
// "ts",
|
|
||||||
// "tsx",
|
|
||||||
// "json",
|
|
||||||
// "node"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
|
||||||
// moduleNameMapper: {},
|
|
||||||
|
|
||||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
|
||||||
// modulePathIgnorePatterns: [],
|
|
||||||
|
|
||||||
// Activates notifications for test results
|
|
||||||
// notify: false,
|
|
||||||
|
|
||||||
// An enum that specifies notification mode. Requires { notify: true }
|
|
||||||
// notifyMode: "failure-change",
|
|
||||||
|
|
||||||
// A preset that is used as a base for Jest's configuration
|
|
||||||
// preset: undefined,
|
|
||||||
|
|
||||||
// Run tests from one or more projects
|
|
||||||
// projects: undefined,
|
|
||||||
|
|
||||||
// Use this configuration option to add custom reporters to Jest
|
|
||||||
// reporters: undefined,
|
|
||||||
|
|
||||||
// Automatically reset mock state between every test
|
|
||||||
// resetMocks: false,
|
|
||||||
|
|
||||||
// Reset the module registry before running each individual test
|
|
||||||
// resetModules: false,
|
|
||||||
|
|
||||||
// A path to a custom resolver
|
|
||||||
// resolver: undefined,
|
|
||||||
|
|
||||||
// Automatically restore mock state between every test
|
|
||||||
// restoreMocks: false,
|
|
||||||
|
|
||||||
// The root directory that Jest should scan for tests and modules within
|
|
||||||
// rootDir: undefined,
|
|
||||||
|
|
||||||
// A list of paths to directories that Jest should use to search for files in
|
|
||||||
// roots: [
|
|
||||||
// "<rootDir>"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// Allows you to use a custom runner instead of Jest's default test runner
|
|
||||||
// runner: "jest-runner",
|
|
||||||
|
|
||||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
|
||||||
setupFiles: ['./setupEnv.js'],
|
|
||||||
|
|
||||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
|
||||||
// setupFilesAfterEnv: [],
|
|
||||||
|
|
||||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
|
||||||
// slowTestThreshold: 5,
|
|
||||||
|
|
||||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
|
||||||
// snapshotSerializers: [],
|
|
||||||
|
|
||||||
// The test environment that will be used for testing
|
|
||||||
testEnvironment: 'jsdom',
|
|
||||||
|
|
||||||
// Options that will be passed to the testEnvironment
|
|
||||||
// testEnvironmentOptions: {},
|
|
||||||
|
|
||||||
// Adds a location field to test results
|
|
||||||
// testLocationInResults: false,
|
|
||||||
|
|
||||||
// The glob patterns Jest uses to detect test files
|
|
||||||
// testMatch: [
|
|
||||||
// "**/__tests__/**/*.[jt]s?(x)",
|
|
||||||
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
|
||||||
// testPathIgnorePatterns: [
|
|
||||||
// "/node_modules/"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
|
||||||
// testRegex: [],
|
|
||||||
|
|
||||||
// This option allows the use of a custom results processor
|
|
||||||
// testResultsProcessor: undefined,
|
|
||||||
|
|
||||||
// This option allows use of a custom test runner
|
|
||||||
// testRunner: "jest-circus/runner",
|
|
||||||
|
|
||||||
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
|
|
||||||
testURL: 'http://localhost',
|
|
||||||
|
|
||||||
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
|
|
||||||
// timers: "real",
|
|
||||||
|
|
||||||
// A map from regular expressions to paths to transformers
|
|
||||||
// transform: undefined,
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
|
||||||
// transformIgnorePatterns: [
|
|
||||||
// "/node_modules/",
|
|
||||||
// "\\.pnp\\.[^\\/]+$"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
|
||||||
// unmockedModulePathPatterns: undefined,
|
|
||||||
|
|
||||||
// Indicates whether each individual test should be reported during the run
|
|
||||||
// verbose: undefined,
|
|
||||||
|
|
||||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
|
||||||
// watchPathIgnorePatterns: [],
|
|
||||||
|
|
||||||
// Whether to use watchman for file crawling
|
|
||||||
// watchman: true,
|
|
||||||
};
|
|
7854
pkg/npm/http-api/package-lock.json
generated
7854
pkg/npm/http-api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,70 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@urbit/http-api",
|
|
||||||
"version": "2.3.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"description": "Library to interact with an Urbit ship over HTTP",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "ssh://git@github.com/urbit/urbit.git",
|
|
||||||
"directory": "pkg/npm/http-api"
|
|
||||||
},
|
|
||||||
"type": "module",
|
|
||||||
"main": "dist/cjs/index.cjs",
|
|
||||||
"module": "dist/esm/index.js",
|
|
||||||
"exports": {
|
|
||||||
"require": "./dist/cjs/index.cjs",
|
|
||||||
"import": "./dist/esm/index.js"
|
|
||||||
},
|
|
||||||
"jsdelivr": "dist/urbit-http-api.min.js",
|
|
||||||
"unpkg": "dist/urbit-http-api.min.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"files": [
|
|
||||||
"dist/**"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "jest",
|
|
||||||
"build": "npm run clean && rollup -c && npx tsc -p tsconfig.json",
|
|
||||||
"prepare": "npm run build",
|
|
||||||
"watch": "rollup -c -w",
|
|
||||||
"clean": "rm -rf dist/* types/*"
|
|
||||||
},
|
|
||||||
"prettier": {
|
|
||||||
"printWidth": 80,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.15.8",
|
|
||||||
"@babel/preset-env": "^7.15.8",
|
|
||||||
"@babel/preset-typescript": "^7.16.0",
|
|
||||||
"@rollup/plugin-babel": "^5.3.0",
|
|
||||||
"@rollup/plugin-commonjs": "^21.0.1",
|
|
||||||
"@rollup/plugin-node-resolve": "^13.0.6",
|
|
||||||
"@types/browser-or-node": "^1.2.0",
|
|
||||||
"@types/eventsource": "^1.1.5",
|
|
||||||
"@types/jest": "^26.0.24",
|
|
||||||
"@types/react": "^16.9.56",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.7.0",
|
|
||||||
"@typescript-eslint/parser": "^4.7.0",
|
|
||||||
"babel-jest": "^27.0.6",
|
|
||||||
"cross-fetch": "^3.1.4",
|
|
||||||
"event-target-polyfill": "0.0.3",
|
|
||||||
"fast-text-encoding": "^1.0.3",
|
|
||||||
"jest": "^27.0.6",
|
|
||||||
"rollup": "^2.59.0",
|
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
|
||||||
"rollup-plugin-typescript2": "^0.30.0",
|
|
||||||
"typescript": "^3.9.7",
|
|
||||||
"util": "^0.12.3",
|
|
||||||
"web-streams-polyfill": "^3.0.3",
|
|
||||||
"yet-another-abortcontroller-polyfill": "0.0.4"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/runtime": "^7.12.5",
|
|
||||||
"@microsoft/fetch-event-source": "^2.0.0",
|
|
||||||
"browser-or-node": "^1.3.0",
|
|
||||||
"core-js": "^3.19.1"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
|
||||||
import commonJS from '@rollup/plugin-commonjs';
|
|
||||||
import { terser } from 'rollup-plugin-terser';
|
|
||||||
import babel from '@rollup/plugin-babel';
|
|
||||||
import typescript from 'rollup-plugin-typescript2';
|
|
||||||
|
|
||||||
const input = ['src/index.ts'];
|
|
||||||
|
|
||||||
// Skip certain warnings
|
|
||||||
function onwarn(warning) {
|
|
||||||
if (warning.code === 'THIS_IS_UNDEFINED') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(warning.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
input,
|
|
||||||
onwarn,
|
|
||||||
plugins: [
|
|
||||||
nodeResolve({
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
||||||
}),
|
|
||||||
commonJS(),
|
|
||||||
typescript(),
|
|
||||||
babel({
|
|
||||||
babelHelpers: 'bundled',
|
|
||||||
exclude: ['node_modules/**'],
|
|
||||||
}),
|
|
||||||
terser({
|
|
||||||
ecma: 2017,
|
|
||||||
compress: true,
|
|
||||||
mangle: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
output: {
|
|
||||||
file: `dist/urbit-http-api.min.js`,
|
|
||||||
format: 'umd',
|
|
||||||
name: 'UrbitHttpApi', // this is the name of the global object
|
|
||||||
esModule: false,
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
input,
|
|
||||||
onwarn,
|
|
||||||
plugins: [
|
|
||||||
nodeResolve({
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
||||||
}),
|
|
||||||
commonJS(),
|
|
||||||
typescript(),
|
|
||||||
],
|
|
||||||
output: [
|
|
||||||
{
|
|
||||||
file: 'dist/esm/index.js',
|
|
||||||
format: 'esm',
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
file: 'dist/cjs/index.cjs',
|
|
||||||
format: 'cjs',
|
|
||||||
exports: 'named',
|
|
||||||
sourcemap: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
@ -1,8 +0,0 @@
|
|||||||
require('event-target-polyfill');
|
|
||||||
require('yet-another-abortcontroller-polyfill');
|
|
||||||
require('cross-fetch/polyfill');
|
|
||||||
require('fast-text-encoding');
|
|
||||||
require('web-streams-polyfill');
|
|
||||||
|
|
||||||
global.ReadableStream = require('web-streams-polyfill').ReadableStream;
|
|
||||||
|
|
@ -1,602 +0,0 @@
|
|||||||
import { isBrowser, isNode } from 'browser-or-node';
|
|
||||||
import {
|
|
||||||
fetchEventSource,
|
|
||||||
EventSourceMessage,
|
|
||||||
} from '@microsoft/fetch-event-source';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Scry,
|
|
||||||
Thread,
|
|
||||||
AuthenticationInterface,
|
|
||||||
PokeInterface,
|
|
||||||
SubscriptionRequestInterface,
|
|
||||||
headers,
|
|
||||||
SSEOptions,
|
|
||||||
PokeHandlers,
|
|
||||||
Message,
|
|
||||||
FatalError,
|
|
||||||
} from './types';
|
|
||||||
import { hexString } from './utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class for interacting with an urbit ship, given its URL and code
|
|
||||||
*/
|
|
||||||
export class Urbit {
|
|
||||||
/**
|
|
||||||
* UID will be used for the channel: The current unix time plus a random hex string
|
|
||||||
*/
|
|
||||||
private uid: string = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lastEventId is an auto-updated index of which events have been *sent* over this channel.
|
|
||||||
* lastHeardEventId is the latest event we have heard back about.
|
|
||||||
* lastAcknowledgedEventId is the latest event we have sent an ack for.
|
|
||||||
*/
|
|
||||||
private lastEventId: number = 0;
|
|
||||||
private lastHeardEventId: number = -1;
|
|
||||||
private lastAcknowledgedEventId: number = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SSE Client is null for now; we don't want to start polling until it the channel exists
|
|
||||||
*/
|
|
||||||
private sseClientInitialized: boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cookie gets set when we log in.
|
|
||||||
*/
|
|
||||||
cookie?: string | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A registry of requestId to successFunc/failureFunc
|
|
||||||
*
|
|
||||||
* These functions are registered during a +poke and are executed
|
|
||||||
* in the onServerEvent()/onServerError() callbacks. Only one of
|
|
||||||
* the functions will be called, and the outstanding poke will be
|
|
||||||
* removed after calling the success or failure function.
|
|
||||||
*/
|
|
||||||
|
|
||||||
private outstandingPokes: Map<number, PokeHandlers> = new Map();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A registry of requestId to subscription functions.
|
|
||||||
*
|
|
||||||
* These functions are registered during a +subscribe and are
|
|
||||||
* executed in the onServerEvent()/onServerError() callbacks. The
|
|
||||||
* event function will be called whenever a new piece of data on this
|
|
||||||
* subscription is available, which may be 0, 1, or many times. The
|
|
||||||
* disconnect function may be called exactly once.
|
|
||||||
*/
|
|
||||||
private outstandingSubscriptions: Map<number, SubscriptionRequestInterface> =
|
|
||||||
new Map();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Our abort controller, used to close the connection
|
|
||||||
*/
|
|
||||||
private abort = new AbortController();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ship can be set, in which case we can do some magic stuff like send chats
|
|
||||||
*/
|
|
||||||
ship?: string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If verbose, logs output eagerly.
|
|
||||||
*/
|
|
||||||
verbose?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* number of consecutive errors in connecting to the eventsource
|
|
||||||
*/
|
|
||||||
private errorCount = 0;
|
|
||||||
|
|
||||||
onError?: (error: any) => void = null;
|
|
||||||
|
|
||||||
onRetry?: () => void = null;
|
|
||||||
|
|
||||||
onOpen?: () => void = null;
|
|
||||||
|
|
||||||
/** This is basic interpolation to get the channel URL of an instantiated Urbit connection. */
|
|
||||||
private get channelUrl(): string {
|
|
||||||
return `${this.url}/~/channel/${this.uid}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get fetchOptions(): any {
|
|
||||||
const headers: headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
if (!isBrowser) {
|
|
||||||
headers.Cookie = this.cookie;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
credentials: 'include',
|
|
||||||
accept: '*',
|
|
||||||
headers,
|
|
||||||
signal: this.abort.signal,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new Urbit connection.
|
|
||||||
*
|
|
||||||
* @param url The URL (with protocol and port) of the ship to be accessed. If
|
|
||||||
* the airlock is running in a webpage served by the ship, this should just
|
|
||||||
* be the empty string.
|
|
||||||
* @param code The access code for the ship at that address
|
|
||||||
*/
|
|
||||||
constructor(public url: string, public code?: string, public desk?: string) {
|
|
||||||
if (isBrowser) {
|
|
||||||
window.addEventListener('beforeunload', this.delete);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All-in-one hook-me-up.
|
|
||||||
*
|
|
||||||
* Given a ship, url, and code, this returns an airlock connection
|
|
||||||
* that is ready to go. It `|hi`s itself to create the channel,
|
|
||||||
* then opens the channel via EventSource.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static async authenticate({
|
|
||||||
ship,
|
|
||||||
url,
|
|
||||||
code,
|
|
||||||
verbose = false,
|
|
||||||
}: AuthenticationInterface) {
|
|
||||||
const airlock = new Urbit(url.startsWith('http') ? url : `http://${url}`, code);
|
|
||||||
airlock.verbose = verbose;
|
|
||||||
airlock.ship = ship;
|
|
||||||
await airlock.connect();
|
|
||||||
await airlock.poke({
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'helm-hi',
|
|
||||||
json: 'opening airlock',
|
|
||||||
});
|
|
||||||
await airlock.eventSource();
|
|
||||||
return airlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connects to the Urbit ship. Nothing can be done until this is called.
|
|
||||||
* That's why we roll it into this.authenticate
|
|
||||||
*/
|
|
||||||
async connect(): Promise<void> {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.log(
|
|
||||||
`password=${this.code} `,
|
|
||||||
isBrowser
|
|
||||||
? 'Connecting in browser context at ' + `${this.url}/~/login`
|
|
||||||
: 'Connecting from node context'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return fetch(`${this.url}/~/login`, {
|
|
||||||
method: 'post',
|
|
||||||
body: `password=${this.code}`,
|
|
||||||
credentials: 'include',
|
|
||||||
}).then((response) => {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.log('Received authentication response', response);
|
|
||||||
}
|
|
||||||
const cookie = response.headers.get('set-cookie');
|
|
||||||
if (!this.ship) {
|
|
||||||
this.ship = new RegExp(/urbauth-~([\w-]+)/).exec(cookie)[1];
|
|
||||||
}
|
|
||||||
if (!isBrowser) {
|
|
||||||
this.cookie = cookie;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the SSE pipe for the appropriate channel.
|
|
||||||
*/
|
|
||||||
async eventSource(): Promise<void> {
|
|
||||||
if (this.sseClientInitialized) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
if (this.lastEventId === 0) {
|
|
||||||
// Can't receive events until the channel is open,
|
|
||||||
// so poke and open then
|
|
||||||
await this.poke({
|
|
||||||
app: 'hood',
|
|
||||||
mark: 'helm-hi',
|
|
||||||
json: 'Opening API channel',
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.sseClientInitialized = true;
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const sseOptions: SSEOptions = {
|
|
||||||
headers: {},
|
|
||||||
};
|
|
||||||
if (isBrowser) {
|
|
||||||
sseOptions.withCredentials = true;
|
|
||||||
} else if (isNode) {
|
|
||||||
sseOptions.headers.Cookie = this.cookie;
|
|
||||||
}
|
|
||||||
fetchEventSource(this.channelUrl, {
|
|
||||||
...this.fetchOptions,
|
|
||||||
openWhenHidden: true,
|
|
||||||
onopen: async (response) => {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.log('Opened eventsource', response);
|
|
||||||
}
|
|
||||||
if (response.ok) {
|
|
||||||
this.errorCount = 0;
|
|
||||||
this.onOpen && this.onOpen();
|
|
||||||
resolve();
|
|
||||||
return; // everything's good
|
|
||||||
} else {
|
|
||||||
const err = new Error('failed to open eventsource');
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onmessage: (event: EventSourceMessage) => {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.log('Received SSE: ', event);
|
|
||||||
}
|
|
||||||
if (!event.id) return;
|
|
||||||
const eventId = parseInt(event.id, 10);
|
|
||||||
if (eventId <= this.lastHeardEventId) {
|
|
||||||
console.log('dropping old or out-of-order event', {
|
|
||||||
eventId, lastHeard: this.lastHeardEventId
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.lastHeardEventId = eventId;
|
|
||||||
if (eventId - this.lastAcknowledgedEventId > 20) {
|
|
||||||
this.ack(eventId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.data && JSON.parse(event.data)) {
|
|
||||||
const data: any = JSON.parse(event.data);
|
|
||||||
|
|
||||||
if (
|
|
||||||
data.response === 'poke' &&
|
|
||||||
this.outstandingPokes.has(data.id)
|
|
||||||
) {
|
|
||||||
const funcs = this.outstandingPokes.get(data.id);
|
|
||||||
if (data.hasOwnProperty('ok')) {
|
|
||||||
funcs.onSuccess();
|
|
||||||
} else if (data.hasOwnProperty('err')) {
|
|
||||||
console.error(data.err);
|
|
||||||
funcs.onError(data.err);
|
|
||||||
} else {
|
|
||||||
console.error('Invalid poke response', data);
|
|
||||||
}
|
|
||||||
this.outstandingPokes.delete(data.id);
|
|
||||||
} else if (
|
|
||||||
data.response === 'subscribe' &&
|
|
||||||
this.outstandingSubscriptions.has(data.id)
|
|
||||||
) {
|
|
||||||
const funcs = this.outstandingSubscriptions.get(data.id);
|
|
||||||
if (data.hasOwnProperty('err')) {
|
|
||||||
console.error(data.err);
|
|
||||||
funcs.err(data.err, data.id);
|
|
||||||
this.outstandingSubscriptions.delete(data.id);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
data.response === 'diff' &&
|
|
||||||
this.outstandingSubscriptions.has(data.id)
|
|
||||||
) {
|
|
||||||
const funcs = this.outstandingSubscriptions.get(data.id);
|
|
||||||
try {
|
|
||||||
funcs.event(data.json, data.mark ?? 'json');
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to call subscription event callback', e);
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
data.response === 'quit' &&
|
|
||||||
this.outstandingSubscriptions.has(data.id)
|
|
||||||
) {
|
|
||||||
const funcs = this.outstandingSubscriptions.get(data.id);
|
|
||||||
funcs.quit(data);
|
|
||||||
this.outstandingSubscriptions.delete(data.id);
|
|
||||||
} else {
|
|
||||||
console.log([...this.outstandingSubscriptions.keys()]);
|
|
||||||
console.log('Unrecognized response', data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onerror: (error) => {
|
|
||||||
console.warn(error);
|
|
||||||
if (!(error instanceof FatalError) && this.errorCount++ < 4) {
|
|
||||||
this.onRetry && this.onRetry();
|
|
||||||
return Math.pow(2, this.errorCount - 1) * 750;
|
|
||||||
}
|
|
||||||
this.onError && this.onError(error);
|
|
||||||
throw error;
|
|
||||||
},
|
|
||||||
onclose: () => {
|
|
||||||
console.log('e');
|
|
||||||
throw new Error('Ship unexpectedly closed the connection');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset airlock, abandoning current subscriptions and wiping state
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
reset() {
|
|
||||||
if (this.verbose) {
|
|
||||||
console.log('resetting');
|
|
||||||
}
|
|
||||||
this.delete();
|
|
||||||
this.abort.abort();
|
|
||||||
this.abort = new AbortController();
|
|
||||||
this.uid = `${Math.floor(Date.now() / 1000)}-${hexString(6)}`;
|
|
||||||
this.lastEventId = 0;
|
|
||||||
this.lastHeardEventId = -1;
|
|
||||||
this.lastAcknowledgedEventId = -1;
|
|
||||||
this.outstandingSubscriptions = new Map();
|
|
||||||
this.outstandingPokes = new Map();
|
|
||||||
this.sseClientInitialized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Autoincrements the next event ID for the appropriate channel.
|
|
||||||
*/
|
|
||||||
private getEventId(): number {
|
|
||||||
return ++this.lastEventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledges an event.
|
|
||||||
*
|
|
||||||
* @param eventId The event to acknowledge.
|
|
||||||
*/
|
|
||||||
private async ack(eventId: number): Promise<number | void> {
|
|
||||||
this.lastAcknowledgedEventId = eventId;
|
|
||||||
const message: Message = {
|
|
||||||
action: 'ack',
|
|
||||||
'event-id': eventId,
|
|
||||||
};
|
|
||||||
await this.sendJSONtoChannel(message);
|
|
||||||
return eventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async sendJSONtoChannel(...json: Message[]): Promise<void> {
|
|
||||||
const response = await fetch(this.channelUrl, {
|
|
||||||
...this.fetchOptions,
|
|
||||||
method: 'PUT',
|
|
||||||
body: JSON.stringify(json),
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to PUT channel');
|
|
||||||
}
|
|
||||||
if (!this.sseClientInitialized) {
|
|
||||||
await this.eventSource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a subscription, waits for a fact and then unsubscribes
|
|
||||||
*
|
|
||||||
* @param app Name of gall agent to subscribe to
|
|
||||||
* @param path Path to subscribe to
|
|
||||||
* @param timeout Optional timeout before ending subscription
|
|
||||||
*
|
|
||||||
* @returns The first fact on the subcription
|
|
||||||
*/
|
|
||||||
async subscribeOnce<T = any>(app: string, path: string, timeout?: number) {
|
|
||||||
return new Promise<T>(async (resolve, reject) => {
|
|
||||||
let done = false;
|
|
||||||
let id: number | null = null;
|
|
||||||
const quit = () => {
|
|
||||||
if (!done) {
|
|
||||||
reject('quit');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const event = (e: T) => {
|
|
||||||
if (!done) {
|
|
||||||
resolve(e);
|
|
||||||
this.unsubscribe(id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const request = { app, path, event, err: reject, quit };
|
|
||||||
|
|
||||||
id = await this.subscribe(request);
|
|
||||||
|
|
||||||
if (timeout) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!done) {
|
|
||||||
done = true;
|
|
||||||
reject('timeout');
|
|
||||||
this.unsubscribe(id);
|
|
||||||
}
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pokes a ship with data.
|
|
||||||
*
|
|
||||||
* @param app The app to poke
|
|
||||||
* @param mark The mark of the data being sent
|
|
||||||
* @param json The data to send
|
|
||||||
*/
|
|
||||||
async poke<T>(params: PokeInterface<T>): Promise<number> {
|
|
||||||
const { app, mark, json, ship, onSuccess, onError } = {
|
|
||||||
onSuccess: () => {},
|
|
||||||
onError: () => {},
|
|
||||||
ship: this.ship,
|
|
||||||
...params,
|
|
||||||
};
|
|
||||||
const message: Message = {
|
|
||||||
id: this.getEventId(),
|
|
||||||
action: 'poke',
|
|
||||||
ship,
|
|
||||||
app,
|
|
||||||
mark,
|
|
||||||
json,
|
|
||||||
};
|
|
||||||
const [send, result] = await Promise.all([
|
|
||||||
this.sendJSONtoChannel(message),
|
|
||||||
new Promise<number>((resolve, reject) => {
|
|
||||||
this.outstandingPokes.set(message.id, {
|
|
||||||
onSuccess: () => {
|
|
||||||
onSuccess();
|
|
||||||
resolve(message.id);
|
|
||||||
},
|
|
||||||
onError: (event) => {
|
|
||||||
onError(event);
|
|
||||||
reject(event.err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes to a path on an app on a ship.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param app The app to subsribe to
|
|
||||||
* @param path The path to which to subscribe
|
|
||||||
* @param handlers Handlers to deal with various events of the subscription
|
|
||||||
*/
|
|
||||||
async subscribe(params: SubscriptionRequestInterface): Promise<number> {
|
|
||||||
const { app, path, ship, err, event, quit } = {
|
|
||||||
err: () => {},
|
|
||||||
event: () => {},
|
|
||||||
quit: () => {},
|
|
||||||
ship: this.ship,
|
|
||||||
...params,
|
|
||||||
};
|
|
||||||
|
|
||||||
const message: Message = {
|
|
||||||
id: this.getEventId(),
|
|
||||||
action: 'subscribe',
|
|
||||||
ship,
|
|
||||||
app,
|
|
||||||
path,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.outstandingSubscriptions.set(message.id, {
|
|
||||||
app,
|
|
||||||
path,
|
|
||||||
err,
|
|
||||||
event,
|
|
||||||
quit,
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.sendJSONtoChannel(message);
|
|
||||||
|
|
||||||
return message.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsubscribes to a given subscription.
|
|
||||||
*
|
|
||||||
* @param subscription
|
|
||||||
*/
|
|
||||||
async unsubscribe(subscription: number) {
|
|
||||||
return this.sendJSONtoChannel({
|
|
||||||
id: this.getEventId(),
|
|
||||||
action: 'unsubscribe',
|
|
||||||
subscription,
|
|
||||||
}).then(() => {
|
|
||||||
this.outstandingSubscriptions.delete(subscription);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the connection to a channel.
|
|
||||||
*/
|
|
||||||
delete() {
|
|
||||||
if (isBrowser) {
|
|
||||||
navigator.sendBeacon(
|
|
||||||
this.channelUrl,
|
|
||||||
JSON.stringify([
|
|
||||||
{
|
|
||||||
action: 'delete',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
// this.sendMessage('delete');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scry into an gall agent at a path
|
|
||||||
*
|
|
||||||
* @typeParam T - Type of the scry result
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
*
|
|
||||||
* Equivalent to
|
|
||||||
* ```hoon
|
|
||||||
* .^(T %gx /(scot %p our)/[app]/(scot %da now)/[path]/json)
|
|
||||||
* ```
|
|
||||||
* The returned cage must have a conversion to JSON for the scry to succeed
|
|
||||||
*
|
|
||||||
* @param params The scry request
|
|
||||||
* @returns The scry result
|
|
||||||
*/
|
|
||||||
async scry<T = any>(params: Scry): Promise<T> {
|
|
||||||
const { app, path } = params;
|
|
||||||
const response = await fetch(
|
|
||||||
`${this.url}/~/scry/${app}${path}.json`,
|
|
||||||
this.fetchOptions
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
return Promise.reject(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a thread
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param inputMark The mark of the data being sent
|
|
||||||
* @param outputMark The mark of the data being returned
|
|
||||||
* @param threadName The thread to run
|
|
||||||
* @param body The data to send to the thread
|
|
||||||
* @returns The return value of the thread
|
|
||||||
*/
|
|
||||||
async thread<R, T = any>(params: Thread<T>): Promise<R> {
|
|
||||||
const {
|
|
||||||
inputMark,
|
|
||||||
outputMark,
|
|
||||||
threadName,
|
|
||||||
body,
|
|
||||||
desk = this.desk,
|
|
||||||
} = params;
|
|
||||||
if (!desk) {
|
|
||||||
throw new Error('Must supply desk to run thread from');
|
|
||||||
}
|
|
||||||
const res = await fetch(
|
|
||||||
`${this.url}/spider/${desk}/${inputMark}/${threadName}/${outputMark}.json`,
|
|
||||||
{
|
|
||||||
...this.fetchOptions,
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility function to connect to a ship that has its *.arvo.network domain configured.
|
|
||||||
*
|
|
||||||
* @param name Name of the ship e.g. zod
|
|
||||||
* @param code Code to log in
|
|
||||||
*/
|
|
||||||
static async onArvoNetwork(ship: string, code: string): Promise<Urbit> {
|
|
||||||
const url = `https://${ship}.arvo.network`;
|
|
||||||
return await Urbit.authenticate({ ship, url, code });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Urbit;
|
|
@ -1,3 +0,0 @@
|
|||||||
export * from './types';
|
|
||||||
import { Urbit } from './Urbit';
|
|
||||||
export { Urbit as default, Urbit };
|
|
@ -1,198 +0,0 @@
|
|||||||
/**
|
|
||||||
* An urbit style path, rendered as a Javascript string
|
|
||||||
* @example
|
|
||||||
* `"/updates"`
|
|
||||||
*/
|
|
||||||
export type Path = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @p including leading sig, rendered as a string
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* "~sampel-palnet"
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export type Patp = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @p not including leading sig, rendered as a string
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* "sampel-palnet"
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export type PatpNoSig = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of a clay mark, as a string
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* "graph-update"
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export type Mark = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of a gall agent, as a string
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* "graph-store"
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export type GallAgent = string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of an outgoing poke
|
|
||||||
*
|
|
||||||
* @typeParam Action - Typescript type of the data being poked
|
|
||||||
*/
|
|
||||||
export interface Poke<Action> {
|
|
||||||
/**
|
|
||||||
* Ship to poke. If left empty, the api lib will populate it with the ship that it is connected to.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
*
|
|
||||||
* This should always be the ship that you are connected to
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
ship?: PatpNoSig;
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
app: GallAgent;
|
|
||||||
/**
|
|
||||||
* Mark of the cage to be poked
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
mark: Mark;
|
|
||||||
/**
|
|
||||||
* Vase of the cage of to be poked, as JSON
|
|
||||||
*/
|
|
||||||
json: Action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of a scry request
|
|
||||||
*/
|
|
||||||
export interface Scry {
|
|
||||||
/** {@inheritDoc GallAgent} */
|
|
||||||
app: GallAgent;
|
|
||||||
/** {@inheritDoc Path} */
|
|
||||||
path: Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of a thread request
|
|
||||||
*
|
|
||||||
* @typeParam Action - Typescript type of the data being poked
|
|
||||||
*/
|
|
||||||
export interface Thread<Action> {
|
|
||||||
/**
|
|
||||||
* The mark of the input vase
|
|
||||||
*/
|
|
||||||
inputMark: Mark;
|
|
||||||
/**
|
|
||||||
* The mark of the output vase
|
|
||||||
*/
|
|
||||||
outputMark: Mark;
|
|
||||||
/**
|
|
||||||
* Name of the thread
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* "graph-add-nodes"
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
threadName: string;
|
|
||||||
/**
|
|
||||||
* Desk of thread
|
|
||||||
*/
|
|
||||||
desk?: string;
|
|
||||||
/**
|
|
||||||
* Data of the input vase
|
|
||||||
*/
|
|
||||||
body: Action;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete';
|
|
||||||
|
|
||||||
export interface PokeHandlers {
|
|
||||||
onSuccess?: () => void;
|
|
||||||
onError?: (e: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PokeInterface<T> = PokeHandlers & Poke<T>;
|
|
||||||
|
|
||||||
export interface AuthenticationInterface {
|
|
||||||
ship: string;
|
|
||||||
url: string;
|
|
||||||
code: string;
|
|
||||||
verbose?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscription event handlers
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export interface SubscriptionInterface {
|
|
||||||
/**
|
|
||||||
* Handle negative %watch-ack
|
|
||||||
*/
|
|
||||||
err?(error: any, id: string): void;
|
|
||||||
/**
|
|
||||||
* Handle %fact
|
|
||||||
*/
|
|
||||||
event?(data: any, mark: string): void;
|
|
||||||
/**
|
|
||||||
* Handle %kick
|
|
||||||
*/
|
|
||||||
quit?(data: any): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type OnceSubscriptionErr = 'quit' | 'nack' | 'timeout';
|
|
||||||
|
|
||||||
export interface SubscriptionRequestInterface extends SubscriptionInterface {
|
|
||||||
/**
|
|
||||||
* The app to subscribe to
|
|
||||||
* @example
|
|
||||||
* `"graph-store"`
|
|
||||||
*/
|
|
||||||
app: GallAgent;
|
|
||||||
/**
|
|
||||||
* The path to which to subscribe
|
|
||||||
* @example
|
|
||||||
* `"/keys"`
|
|
||||||
*/
|
|
||||||
path: Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface headers {
|
|
||||||
'Content-Type': string;
|
|
||||||
Cookie?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CustomEventHandler {
|
|
||||||
(data: any, response: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SSEOptions {
|
|
||||||
headers?: {
|
|
||||||
Cookie?: string;
|
|
||||||
};
|
|
||||||
withCredentials?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Message extends Record<string, any> {
|
|
||||||
action: Action;
|
|
||||||
id?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ResumableError extends Error {}
|
|
||||||
|
|
||||||
export class FatalError extends Error {}
|
|
@ -1,53 +0,0 @@
|
|||||||
export function camelize(str: string) {
|
|
||||||
return str
|
|
||||||
.replace(/\s(.)/g, function ($1: string) {
|
|
||||||
return $1.toUpperCase();
|
|
||||||
})
|
|
||||||
.replace(/\s/g, '')
|
|
||||||
.replace(/^(.)/, function ($1: string) {
|
|
||||||
return $1.toLowerCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function uncamelize(str: string, separator = '-') {
|
|
||||||
// Replace all capital letters by separator followed by lowercase one
|
|
||||||
var str = str.replace(/[A-Z]/g, function (letter: string) {
|
|
||||||
return separator + letter.toLowerCase();
|
|
||||||
});
|
|
||||||
return str.replace(new RegExp('^' + separator), '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a hex string of given length.
|
|
||||||
*
|
|
||||||
* Poached from StackOverflow.
|
|
||||||
*
|
|
||||||
* @param len Length of hex string to return.
|
|
||||||
*/
|
|
||||||
export function hexString(len: number): string {
|
|
||||||
const maxlen = 8;
|
|
||||||
const min = Math.pow(16, Math.min(len, maxlen) - 1);
|
|
||||||
const max = Math.pow(16, Math.min(len, maxlen)) - 1;
|
|
||||||
const n = Math.floor(Math.random() * (max - min + 1)) + min;
|
|
||||||
let r = n.toString(16);
|
|
||||||
while (r.length < len) {
|
|
||||||
r = r + hexString(len - maxlen);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a random UID.
|
|
||||||
*
|
|
||||||
* Copied from https://github.com/urbit/urbit/blob/137e4428f617c13f28ed31e520eff98d251ed3e9/pkg/interface/src/lib/util.js#L3
|
|
||||||
*/
|
|
||||||
export function uid(): string {
|
|
||||||
let str = '0v';
|
|
||||||
str += Math.ceil(Math.random() * 8) + '.';
|
|
||||||
for (let i = 0; i < 5; i++) {
|
|
||||||
let _str = Math.ceil(Math.random() * 10000000).toString(32);
|
|
||||||
_str = ('00000' + _str).substr(-5, 5);
|
|
||||||
str += _str + '.';
|
|
||||||
}
|
|
||||||
return str.slice(0, -1);
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
import Urbit from '../src';
|
|
||||||
import 'jest';
|
|
||||||
|
|
||||||
function fakeSSE(messages = [], timeout = 0) {
|
|
||||||
const ourMessages = [...messages];
|
|
||||||
const enc = new TextEncoder();
|
|
||||||
return new ReadableStream({
|
|
||||||
start(controller) {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
let message = ':\n';
|
|
||||||
if (ourMessages.length > 0) {
|
|
||||||
message = ourMessages.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
controller.enqueue(enc.encode(message));
|
|
||||||
}, 50);
|
|
||||||
|
|
||||||
if (timeout > 0) {
|
|
||||||
setTimeout(() => {
|
|
||||||
controller.close();
|
|
||||||
clearInterval(interval);
|
|
||||||
interval;
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const ship = '~sampel-palnet';
|
|
||||||
let eventId = 0;
|
|
||||||
function event(data: any) {
|
|
||||||
return `id:${eventId++}\ndata:${JSON.stringify(data)}\n\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fact(id: number, data: any) {
|
|
||||||
return event({
|
|
||||||
response: 'diff',
|
|
||||||
id,
|
|
||||||
json: data,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function ack(id: number, err = false) {
|
|
||||||
const res = err ? { err: 'Error' } : { ok: true };
|
|
||||||
return event({ id, response: 'poke', ...res });
|
|
||||||
}
|
|
||||||
const fakeFetch = (body) => () =>
|
|
||||||
Promise.resolve({
|
|
||||||
ok: true,
|
|
||||||
body: body(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const wait = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
|
||||||
|
|
||||||
process.on('unhandledRejection', (error) => {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Initialisation', () => {
|
|
||||||
let airlock: Urbit;
|
|
||||||
let fetchSpy;
|
|
||||||
beforeEach(() => {
|
|
||||||
airlock = new Urbit('', '+code');
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
fetchSpy.mockReset();
|
|
||||||
});
|
|
||||||
it('should poke & connect upon a 200', async () => {
|
|
||||||
airlock.onOpen = jest.fn();
|
|
||||||
fetchSpy = jest.spyOn(window, 'fetch');
|
|
||||||
fetchSpy
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: true, body: fakeSSE() })
|
|
||||||
)
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: true, body: fakeSSE([ack(1)]) })
|
|
||||||
);
|
|
||||||
await airlock.eventSource();
|
|
||||||
|
|
||||||
expect(airlock.onOpen).toHaveBeenCalled();
|
|
||||||
}, 500);
|
|
||||||
it('should handle failures', async () => {
|
|
||||||
fetchSpy = jest.spyOn(window, 'fetch');
|
|
||||||
airlock.onRetry = jest.fn();
|
|
||||||
airlock.onOpen = jest.fn();
|
|
||||||
fetchSpy
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: true, body: fakeSSE() })
|
|
||||||
)
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: true, body: fakeSSE([], 100) })
|
|
||||||
);
|
|
||||||
|
|
||||||
airlock.onError = jest.fn();
|
|
||||||
try {
|
|
||||||
airlock.eventSource();
|
|
||||||
await wait(200);
|
|
||||||
} catch (e) {
|
|
||||||
expect(airlock.onRetry).toHaveBeenCalled();
|
|
||||||
}
|
|
||||||
}, 300);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('subscription', () => {
|
|
||||||
let airlock: Urbit;
|
|
||||||
let fetchSpy: jest.SpyInstance;
|
|
||||||
beforeEach(() => {
|
|
||||||
eventId = 1;
|
|
||||||
});
|
|
||||||
afterEach(() => {
|
|
||||||
fetchSpy.mockReset();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should subscribe', async () => {
|
|
||||||
fetchSpy = jest.spyOn(window, 'fetch');
|
|
||||||
airlock = new Urbit('', '+code');
|
|
||||||
airlock.onOpen = jest.fn();
|
|
||||||
const params = {
|
|
||||||
app: 'app',
|
|
||||||
path: '/path',
|
|
||||||
err: jest.fn(),
|
|
||||||
event: jest.fn(),
|
|
||||||
quit: jest.fn(),
|
|
||||||
};
|
|
||||||
const firstEv = 'one';
|
|
||||||
const secondEv = 'two';
|
|
||||||
const events = (id) => [fact(id, firstEv), fact(id, secondEv)];
|
|
||||||
fetchSpy.mockImplementation(fakeFetch(() => fakeSSE(events(1))));
|
|
||||||
|
|
||||||
await airlock.subscribe(params);
|
|
||||||
await wait(600);
|
|
||||||
|
|
||||||
expect(airlock.onOpen).toBeCalled();
|
|
||||||
expect(params.event).toHaveBeenNthCalledWith(1, firstEv, 'json');
|
|
||||||
expect(params.event).toHaveBeenNthCalledWith(2, secondEv, 'json');
|
|
||||||
}, 800);
|
|
||||||
it('should poke', async () => {
|
|
||||||
fetchSpy = jest.spyOn(window, 'fetch');
|
|
||||||
airlock = new Urbit('', '+code');
|
|
||||||
airlock.onOpen = jest.fn();
|
|
||||||
fetchSpy.mockImplementation(fakeFetch(() => fakeSSE([ack(1)])));
|
|
||||||
const params = {
|
|
||||||
app: 'app',
|
|
||||||
mark: 'mark',
|
|
||||||
json: { poke: 1 },
|
|
||||||
onSuccess: jest.fn(),
|
|
||||||
onError: jest.fn(),
|
|
||||||
};
|
|
||||||
await airlock.poke(params);
|
|
||||||
await wait(300);
|
|
||||||
expect(params.onSuccess).toHaveBeenCalled();
|
|
||||||
}, 800);
|
|
||||||
|
|
||||||
it('should nack poke', async () => {
|
|
||||||
fetchSpy = jest.spyOn(window, 'fetch');
|
|
||||||
airlock = new Urbit('', '+code');
|
|
||||||
airlock.onOpen = jest.fn();
|
|
||||||
fetchSpy
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: true, body: fakeSSE() })
|
|
||||||
)
|
|
||||||
.mockImplementationOnce(() =>
|
|
||||||
Promise.resolve({ ok: false, body: fakeSSE([ack(1, true)]) })
|
|
||||||
);
|
|
||||||
|
|
||||||
const params = {
|
|
||||||
app: 'app',
|
|
||||||
mark: 'mark',
|
|
||||||
json: { poke: 1 },
|
|
||||||
onSuccess: jest.fn(),
|
|
||||||
onError: jest.fn(),
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
await airlock.poke(params);
|
|
||||||
await wait(300);
|
|
||||||
} catch (e) {
|
|
||||||
expect(true).toBe(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"exclude": ["node_modules", "dist", "tmp"],
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "./tmp",
|
|
||||||
"module": "ESNext",
|
|
||||||
"target": "ESNext",
|
|
||||||
"lib": ["ESNext", "DOM"],
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"declaration": true,
|
|
||||||
"sourceMap": true,
|
|
||||||
"strict": false,
|
|
||||||
"pretty": true,
|
|
||||||
"noImplicitAny": true,
|
|
||||||
"noErrorTruncation": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"*": ["./node_modules/@types/*", "*"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
cd pkg/npm/api
|
cd pkg/interface
|
||||||
npm install &
|
|
||||||
|
|
||||||
cd ../../interface
|
|
||||||
npm install
|
npm install
|
||||||
npm run build:prod &
|
npm run build:prod &
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user