Merge branch 'release/next-js' into ed/create-channel-icon-fix

This commit is contained in:
édouard 2021-05-09 13:36:11 -04:00 committed by GitHub
commit 79b0dccf3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
368 changed files with 10399 additions and 8270 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f6b5e33e573818120051651c1182163527edbbe0dff0eb6591e12a55cfccb273
size 10486101
oid sha256:90dd5f5b2821f1a057c053b141e1143f019193c8dd7da41b39b0a3799e0fda5a
size 10999106

View File

@ -82,6 +82,8 @@ haskell-nix.stackProject {
urbit-king.components.tests.urbit-king-tests.testFlags =
[ "--brass-pill=${brass.lfs}" ];
lmdb.components.library.libs = lib.mkForce [ lmdb ];
};
}];
}

View File

@ -169,7 +169,7 @@
::
%fact
?+ p.cage.sign ~|([dap.bowl %bad-sub-mark wire p.cage.sign] !!)
%graph-update-1
%graph-update-2
%- on-graph-update:tc
!<(update:graph q.cage.sign)
==
@ -401,12 +401,16 @@
:: +read-post: add envelope to state and show it to user
::
++ read-post
|= [=target =index:post =post:post]
|= [=target =index:post =maybe-post:graph]
^- (quip card _session)
:- (show-post:sh-out target post)
%_ session
history [[target index] history.session]
count +(count.session)
?- -.maybe-post
%| [~ session]
%&
:- (show-post:sh-out target p.maybe-post)
%_ session
history [[target index] history.session]
count +(count.session)
==
==
::
++ notice-remove
@ -758,15 +762,15 @@
::TODO move creation into lib?
%^ act %out-message
%graph-push-hook
:- %graph-update-1
:- %graph-update-2
!> ^- update:graph
:- now.bowl
:+ %add-nodes audience
%- ~(put by *(map index:post node:graph))
:- ~[now.bowl]
:_ *internal-graph:graph
^- post:post
[our-self ~[now.bowl] now.bowl [msg]~ ~ ~]
^- maybe-post:graph
[%& `post:post`[our-self ~[now.bowl] now.bowl [msg]~ ~ ~]]
:: +eval: run hoon, send code and result as message
::
:: this double-virtualizes and clams to disable .^ for security reasons
@ -890,10 +894,12 @@
=/ =uid:post (snag index history)
=/ =node:graph (got-node:libgraph uid)
=. audience resource.uid
?: ?=(%| -.post.node)
[~ state]
:_ put-ses
^- (list card)
:~ (print:sh-out ['?' ' ' number])
(effect:sh-out ~(render-activate mr resource.uid post.node))
(effect:sh-out ~(render-activate mr resource.uid p.post.node))
prompt:sh-out
==
--

View File

@ -154,7 +154,7 @@
++ poke-graph-store
|= =update:graph-store
^- card
(poke-our %graph-store %graph-update-1 !>(update))
(poke-our %graph-store %graph-update-2 !>(update))
::
++ nobody
^- @p

View File

@ -1,334 +1,28 @@
:: chat-store [landscape]:
:: chat-store [landscape]: deprecated
::
:: data store that holds linear sequences of chat messages
::
/- *group, store=chat-store
/+ default-agent, verb, dbug, group-store,
graph-store, resource, *migrate, grpl=group, mdl=metadata
~% %chat-store-top ..part ~
/- store=chat-store
/+ default-agent
|%
+$ card card:agent:gall
+$ versioned-state
$% state-0
state-1
state-2
state-3
state-4
==
::
+$ state-0 [%0 =inbox:store]
+$ state-1 [%1 =inbox:store]
+$ state-2 [%2 =inbox:store]
+$ state-3 [%3 =inbox:store]
+$ state-4 [%4 =inbox:store]
+$ admin-action
$% [%trim ~]
[%migrate-graph ~]
==
--
::
=| state-4
=* state -
::
%- agent:dbug
%+ verb |
^- agent:gall
=<
~% %chat-store-agent-core ..peek-x-envelopes ~
|_ =bowl:gall
+* this .
chat-core +>
cc ~(. chat-core bowl)
def ~(. (default-agent this %|) bowl)
::
++ on-init on-init:def
++ on-save !>(state)
++ on-load
|= old-vase=vase
^- (quip card _this)
|^
=/ old !<(versioned-state old-vase)
=| cards=(list card)
|-
^- (quip card _this)
?- -.old
%4 [cards this(state old)]
::
%3
=. cards :_(cards (poke-admin %migrate-graph ~))
$(old [%4 inbox.old])
::
%2
=/ =inbox:store
(migrate-path-map:group-store inbox.old)
=/ kick-paths
%~ tap in
%+ roll
~(val by sup.bowl)
|= [[=ship sub=path] subs=(set path)]
^- (set path)
?. ?=([@ @ *] sub)
subs
?. &(=(%mailbox i.sub) =('~' i.t.sub))
subs
(~(put in subs) sub)
=? cards ?=(^ kick-paths)
:_ cards
[%give %kick kick-paths ~]
$(old [%3 inbox])
::
?(%0 %1) $(old (old-to-2 inbox.old))
::
==
++ poke-admin
|= =admin-action
^- card
[%pass / %agent [our dap]:bowl %poke noun+!>(admin-action)]
::
++ old-to-2
|= =inbox:store
^- state-2
:- %2
%- ~(run by inbox)
|= =mailbox:store
^- mailbox:store
[config.mailbox (flop envelopes.mailbox)]
--
::
++ on-poke
~/ %chat-store-poke
|= [=mark =vase]
^- (quip card _this)
?> (team:title our.bowl src.bowl)
=^ cards state
?+ mark (on-poke:def mark vase)
%noun (poke-noun:cc !<(admin-action vase))
%import (poke-import:cc q.vase)
==
[cards this]
::
++ on-watch on-watch:def
++ on-leave on-leave:def
++ on-peek
~/ %chat-store-peek
|= =path
^- (unit (unit cage))
?+ path (on-peek:def path)
[%x %all ~] ``noun+!>(inbox)
[%x %keys ~] ``noun+!>(~(key by inbox))
[%x %envelopes *] (peek-x-envelopes:cc t.t.path)
[%x %mailbox *]
?~ t.t.path
~
``noun+!>((~(get by inbox) t.t.path))
::
[%x %config *]
?~ t.t.path
~
=/ mailbox (~(get by inbox) t.t.path)
?~ mailbox
~
``noun+!>(config.u.mailbox)
::
[%x %export ~]
``noun+!>(state)
==
::
++ on-agent on-agent:def
++ on-arvo on-arvo:def
++ on-fail on-fail:def
--
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
::
~% %chat-store-library ..card ~
|_ bol=bowl:gall
++ met ~(. mdl bol)
++ grp ~(. grpl bol)
++ on-init on-init:def
++ on-save !>(~)
++ on-load
|= old-vase=vase
^- (quip card _this)
[~ this]
::
++ peek-x-envelopes
|= pax=path
^- (unit (unit [%noun vase]))
?+ pax ~
[@ @ *]
=/ mail-path t.t.pax
=/ mailbox (~(get by inbox) mail-path)
?~ mailbox
[~ ~ %noun !>(~)]
=* envelopes envelopes.u.mailbox
=/ sign-test=[?(%neg %pos) @]
%- need
%+ rush i.pax
;~ pose
%+ cook
|= n=@
[%neg n]
;~(pfix hep dem:ag)
::
%+ cook
|= n=@
[%pos n]
dem:ag
==
=* length length.config.u.mailbox
=* start +.sign-test
?: =(-.sign-test %neg)
?: (gth start length)
[~ ~ %noun !>(envelopes)]
[~ ~ %noun !>((swag [(sub length start) start] envelopes))]
::
=/ end (slav %ud i.t.pax)
?. (lte start end)
~
=. end ?:((lth end length) end length)
[~ ~ %noun !>((swag [start (sub end start)] envelopes))]
==
::
++ poke-noun
|= nou=admin-action
^- (quip card _state)
?: ?=([%migrate-graph ~] nou)
:_ state
(migrate-inbox inbox)
~& %trimming-chat-store
:- ~
%_ state
inbox
%- ~(urn by inbox)
|= [=path mailbox:store]
^- mailbox:store
=/ [a=* out=(list envelope:store)]
%+ roll envelopes
|= $: =envelope:store
o=[[hav=(set serial:store) curr=@] out=(list envelope:store)]
==
?: (~(has in hav.o) uid.envelope)
[[hav.o curr.o] out.o]
:-
^- [(set serial:store) @]
[(~(put in hav.o) uid.envelope) +(curr.o)]
^- (list envelope:store)
[envelope(number curr.o) out.o]
=/ len (lent out)
~? !=(len (lent envelopes)) [path [%old (lent envelopes)] [%new len]]
[[len len] (flop out)]
==
::
++ poke-import
|= arc=*
^- (quip card _state)
=/ sty=state-4 [%4 (remake-map ;;((tree [path mailbox:store]) +.arc))]
:_ sty
(migrate-inbox inbox.sty)
::
++ update-subscribers
|= [pax=path =update:store]
^- (list card)
[%give %fact ~[pax] %chat-update !>(update)]~
::
++ send-diff
|= [pax=path upd=update:store]
^- (list card)
%- zing
:~ (update-subscribers /all upd)
(update-subscribers /updates upd)
(update-subscribers [%mailbox pax] upd)
?. |(|(=(%read -.upd) =(%message -.upd)) =(%messages -.upd))
~
?. |(=(%create -.upd) =(%delete -.upd))
~
(update-subscribers /keys upd)
==
::
++ migrate-inbox
|= =inbox:store
^- (list card)
%- zing
(turn ~(tap by inbox) mailbox-to-updates)
::
++ add-graph
|= [rid=resource =mailbox:store]
%- poke-graph-store
:- now.bol
:+ %add-graph rid
:- (mailbox-to-graph mailbox)
[`%graph-validator-chat %.y]
::
++ archive-graph
|= rid=resource
%- poke-graph-store
[now.bol %archive-graph rid]
::
++ nobody
^- @p
(bex 128)
::
++ path-to-resource
|= =path
^- resource
?. ?=([@ @ ~] path)
nobody^(spat path)
=/ m-ship=(unit ship)
(slaw %p i.path)
?~ m-ship
nobody^(spat path)
[u.m-ship i.t.path]
::
++ mailbox-to-updates
|= [=path =mailbox:store]
^- (list card)
=/ app-rid=resource
(path-to-resource path)
=/ group-rid=resource
(fall (peek-group:met %graph app-rid) [nobody %bad-group])
=/ group=(unit group)
(scry-group:grp group-rid)
:- (add-graph app-rid mailbox)
?~ group (archive-graph app-rid)^~
?. &(=(~ members.u.group) hidden.u.group) ~
~& >>> "archiving {<app-rid>}"
:~ (archive-graph app-rid)
(remove-group group-rid)
==
::
++ remove-group
|= group=resource
^- card
=- [%pass / %agent [our.bol %group-store] %poke -]
group-update-0+!>([%remove-group group ~])
::
++ poke-graph-store
|= =update:graph-store
^- card
[%pass / %agent [our.bol %graph-store] %poke %graph-update-1 !>(update)]
::
++ letter-to-contents
|= =letter:store
^- (list content:graph-store)
:_ ~
?. ?=(%me -.letter)
letter
[%text narrative.letter]
::
++ envelope-to-node
|= =envelope:store
^- [atom:graph-store node:graph-store]
=/ contents=(list content:graph-store)
(letter-to-contents letter.envelope)
=/ =index:graph-store
[when.envelope ~]
=, envelope
:- when.envelope
:_ [%empty ~]
^- post:graph-store
:* author
index
when
contents
~ ~
==
::
++ mailbox-to-graph
|= =mailbox:store
^- graph:graph-store
%+ gas:orm:graph-store *graph:graph-store
(turn envelopes.mailbox envelope-to-node)
++ on-poke on-poke:def
++ on-watch on-watch:def
++ on-leave on-leave:def
++ on-peek on-peek:def
++ on-agent on-agent:def
++ on-arvo on-arvo:def
++ on-fail on-fail:def
--

View File

@ -5,7 +5,7 @@
/- glob
/+ default-agent, verb, dbug
|%
++ hash 0v3.g6u13.haedt.jt4hd.61ek5.6t30q
++ hash 0v7.k043v.fjsi2.bpm4g.0ekbj.566c4 :: DO NOT MOVE FROM LINE 8
+$ state-0 [%0 hash=@uv glob=(unit (each glob:glob tid=@ta))]
+$ all-states
$% state-0

View File

@ -9,7 +9,7 @@
update:store
%graph-update
%graph-push-hook
1 1
2 2
%.n
==
--
@ -41,7 +41,7 @@
%- (slog leaf+"nacked {<resource>}" tang)
:_ this
?. (~(has in get-keys:gra) resource) ~
=- [%pass /pull-nack %agent [our.bowl %graph-store] %poke %graph-update-1 -]~
=- [%pass /pull-nack %agent [our.bowl %graph-store] %poke %graph-update-2 -]~
!> ^- update:store
[now.bowl [%archive-graph resource]]
::

View File

@ -12,16 +12,19 @@
update:store
%graph-update
%graph-pull-hook
1 1
2 2
==
::
+$ agent (push-hook:push-hook config)
::
+$ state-null ~
+$ state-zero [%0 marks=(set mark)]
+$ state-one [%1 ~]
+$ versioned-state
$@ state-null
state-zero
$% state-zero
state-one
==
--
::
%- agent:dbug
@ -30,13 +33,14 @@
%- (agent:push-hook config)
^- agent
=-
=| state-zero
=| state-one
=* state -
|_ =bowl:gall
+* this .
def ~(. (default-agent this %|) bowl)
grp ~(. group bowl)
gra ~(. graph bowl)
met ~(. mdl bowl)
hc ~(. hook-core bowl)
::
++ on-init on-init:def
@ -46,7 +50,9 @@
=+ !<(old=versioned-state vase)
=? old ?=(~ old)
[%0 ~]
?> ?=(%0 -.old)
=? old ?=(%0 -.old)
[%1 ~]
?> ?=(%1 -.old)
`this(state old)
::
++ on-poke on-poke:def
@ -58,17 +64,10 @@
|= [=wire =sign-arvo]
^- (quip card _this)
?+ wire (on-arvo:def wire sign-arvo)
:: XX: no longer necessary
::
[%perms @ @ ~]
?> ?=(?(%add %remove) i.t.t.wire)
=* mark i.t.wire
:_ this
(build-permissions:hc mark i.t.t.wire %next)^~
::
[%transform-add @ ~]
=* mark i.t.wire
:_ this
(build-transform-add:hc mark %next)^~
[%perms @ @ ~] [~ this]
[%transform-add @ ~] [~ this]
==
::
++ on-fail on-fail:def
@ -134,6 +133,8 @@
|= $: [=index:store =node:store]
[indices=(set index:store) lis=(list [index:store node:store])]
==
~| "cannot put a deleted post into %add-nodes {<post.node>}"
?> ?=(%& -.post.node)
=/ l (lent index)
=/ parent-modified=?
%- ~(rep in indices)
@ -144,12 +145,12 @@
%.n
=((swag [0 k] index) i)
=/ [ind=index:store =post:store]
(transform index post.node now.bowl parent-modified)
(transform index p.post.node now.bowl parent-modified)
:- (~(put in indices) index)
(snoc lis [ind node(post post)])
(snoc lis [ind node(p.post post)])
--
::
%remove-nodes
%remove-posts
?. (is-allowed-remove:hc resource.q.update indices.q.update)
~
`vas
@ -173,7 +174,8 @@
++ initial-watch
|= [=path =resource:res]
^- vase
?> (is-allowed:hc resource)
|^
?> (is-allowed resource)
!> ^- update:store
?~ path
:: new subscribe
@ -186,22 +188,19 @@
=/ =time (slav %da i.path)
=/ =update-log:store (get-update-log-subset:gra resource time)
[now.bowl [%run-updates resource update-log]]
::
++ is-allowed
|= =resource:res
=/ group-res=resource:res
(need (peek-group:met %graph resource))
(is-member:grp src.bowl group-res)
--
::
++ take-update
|= =vase
^- [(list card) agent]
=/ =update:store !<(update:store vase)
?+ -.q.update [~ this]
%add-graph
?~ mark.q.update `this
=* mark u.mark.q.update
?: (~(has in marks) mark) `this
:_ this(marks (~(put in marks) mark))
:~ (build-permissions:hc mark %add %sing)
(build-permissions:hc mark %remove %sing)
(build-transform-add:hc mark %sing)
==
::
%remove-graph
:_ this
[%give %kick ~[resource+(en-path:res resource.q.update)] ~]~
@ -211,6 +210,7 @@
[%give %kick ~[resource+(en-path:res resource.q.update)] ~]~
==
--
::
^| ^= hook-core
|_ =bowl:gall
+* grp ~(. group bowl)
@ -223,28 +223,22 @@
/[care]/(scot %p our.bowl)/[desk]/(scot %da now.bowl)
path
::
++ perm-mark-name
|= perm=@t
^- @t
(cat 3 'graph-permissions-' perm)
::
++ perm-mark
|= [=resource:res perm=@t vip=vip-metadata:metadata =indexed-post:store]
^- permissions:store
|^
=- (check vip)
!< check=$-(vip-metadata:metadata permissions:store)
%. !>(indexed-post)
=/ mark (get-mark:gra resource)
?~ mark |=(=vase !>([%no %no %no]))
.^(tube:clay (scry %cc %home /[u.mark]/(perm-mark-name perm)))
::
++ add-mark
|= [=resource:res vip=vip-metadata:metadata =indexed-post:store]
(perm-mark resource %add vip indexed-post)
::
++ remove-mark
|= [=resource:res vip=vip-metadata:metadata =indexed-post:store]
(perm-mark resource %remove vip indexed-post)
::
++ perm-mark-name
|= perm=@t
^- @t
(cat 3 'graph-permissions-' perm)
--
::
++ get-permission
|= [=permissions:store is-admin=? writers=(set ship)]
@ -257,12 +251,6 @@
writer.permissions
reader.permissions
::
++ is-allowed
|= =resource:res
=/ group-res=resource:res
(need (peek-group:met %graph resource))
(is-member:grp src.bowl group-res)
::
++ get-roles-writers-variation
|= =resource:res
^- (unit [is-admin=? writers=(set ship) vip=vip-metadata:metadata])
@ -281,22 +269,27 @@
++ node-to-indexed-post
|= =node:store
^- indexed-post:store
=* index index.post.node
[(snag (dec (lent index)) index) post.node]
?> ?=(%& -.post.node)
=* index index.p.post.node
[(snag (dec (lent index)) index) p.post.node]
::
++ is-allowed-add
|= [=resource:res nodes=(map index:store node:store)]
^- ?
|^
%- (bond |.(%.n))
%+ biff (get-roles-writers-variation resource)
|= [is-admin=? writers=(set ship) vip=vip-metadata:metadata]
^- (unit ?)
%- some
%+ levy ~(tap by nodes)
|= [=index:store =node:store]
=/ parent-index=index:store
(scag (dec (lent index)) index)
?: (~(has by nodes) parent-index) %.y
?. =(author.post.node src.bowl)
?: ?=(%| -.post.node)
%.n
?. =(author.p.post.node src.bowl)
%.n
=/ =permissions:store
%^ add-mark resource vip
@ -310,20 +303,30 @@
%self
=/ parent-node=node:store
(got-node:gra resource parent-index)
=(author.post.parent-node src.bowl)
?: ?=(%| -.post.parent-node)
%.n
=(author.p.post.parent-node src.bowl)
==
::
++ add-mark
|= [=resource:res vip=vip-metadata:metadata =indexed-post:store]
(perm-mark resource %add vip indexed-post)
--
::
++ is-allowed-remove
|= [=resource:res indices=(set index:store)]
^- ?
|^
%- (bond |.(%.n))
%+ biff (get-roles-writers-variation resource)
|= [is-admin=? writers=(set ship) vip=vip-metadata:metadata]
%- some
%+ levy ~(tap by indices)
|= =index:store
^- ?
=/ =node:store
(got-node:gra resource index)
?: ?=(%| -.post.node) %.n
=/ =permissions:store
%^ remove-mark resource vip
(node-to-indexed-post node)
@ -332,23 +335,12 @@
?- permission-level
%yes %.y
%no %.n
%self =(author.post.node src.bowl)
%self =(author.p.post.node src.bowl)
==
::
++ build-permissions
|= [=mark kind=?(%add %remove) mode=?(%sing %next)]
^- card
=/ =wire /perms/[mark]/[kind]
=/ =mood:clay [%c da+now.bowl /[mark]/(perm-mark-name kind)]
=/ =rave:clay ?:(?=(%sing mode) [mode mood] [mode mood])
[%pass wire %arvo %c %warp our.bowl %home `rave]
::
++ build-transform-add
|= [=mark mode=?(%sing %next)]
^- card
=/ =wire /transform-add/[mark]
=/ =mood:clay [%c da+now.bowl /[mark]/transform-add-nodes]
=/ =rave:clay ?:(?=(%sing mode) [mode mood] [mode mood])
[%pass wire %arvo %c %warp our.bowl %home `rave]
::
++ remove-mark
|= [=resource:res vip=vip-metadata:metadata =indexed-post:store]
(perm-mark resource %remove vip indexed-post)
--
--

View File

@ -1,29 +1,26 @@
:: graph-store [landscape]
::
::
/+ store=graph-store, sigs=signatures, res=resource, default-agent, dbug, verb,
*migrate
/+ store=graph-store, sigs=signatures, res=resource, default-agent, dbug, verb
~% %graph-store-top ..part ~
|%
+$ card card:agent:gall
+$ versioned-state
$% state-0
state-1
state-2
state-3
$% [%0 network:zero:store]
[%1 network:zero:store]
[%2 network:zero:store]
[%3 network:one:store]
[%4 network:store]
state-5
==
::
+$ state-0 [%0 network:zero:store]
+$ state-1 [%1 network:zero:store]
+$ state-2 [%2 network:zero:store]
+$ state-3 [%3 network:store]
::
+$ state-5 [%5 network:store]
++ orm orm:store
++ orm-log orm-log:store
+$ debug-input [%validate-graph =resource:store]
--
::
=| state-3
=| state-5
=* state -
::
%- agent:dbug
@ -41,19 +38,18 @@
^- (quip card _this)
=+ !<(old=versioned-state old-vase)
=| cards=(list card)
|^
|-
?- -.old
%0
%0
=* zro zero-load:upgrade:store
%_ $
-.old %1
cards cards
validators.old validators.old
::
graphs.old
%- ~(run by graphs.old)
|= [=graph:zero:store q=(unit mark)]
^- [graph:zero:store (unit mark)]
:- (convert-unix-timestamped-graph:zero-load graph)
:- (convert-unix-timestamped-graph:zro graph)
?^ q q
`%graph-validator-link
::
@ -63,138 +59,57 @@
==
::
%1
=* zro zero-load:upgrade:store
%_ $
-.old %2
graphs.old (~(run by graphs.old) change-revision-graph:zero-load)
graphs.old (~(run by graphs.old) change-revision-graph:zro)
::
update-logs.old
%- ~(run by update-logs.old)
|=(a=* *update-log:zero:store)
==
::
%2
%2
=* upg upgrade:store
%_ $
-.old %3
update-logs.old (~(run by update-logs.old) update-log-to-one:store)
graphs.old (~(run by graphs.old) marked-graph-to-one:store)
archive.old (~(run by archive.old) marked-graph-to-one:store)
update-logs.old (~(run by update-logs.old) update-log-to-one:upg)
graphs.old (~(run by graphs.old) marked-graph-to-one:upg)
archive.old (~(run by archive.old) marked-graph-to-one:upg)
==
::
%3 [cards this(state old)]
==
%3
=* upg upgrade:store
%_ $
-.old %4
graphs.old (~(run by graphs.old) marked-graph-to-two:upg)
archive.old (~(run by archive.old) marked-graph-to-two:upg)
tag-queries.old *tag-queries:store
validators.old ~
::
update-logs.old
%- ~(run by update-logs.old)
|=(a=* *update-log:store)
==
::
++ zero-load
:: =* infinitely recurses
=, store=zero:store
=, orm=orm:zero:store
=, orm-log=orm-log:zero:store
|%
++ change-revision-graph
|= [=graph:store q=(unit mark)]
^- [graph:store (unit mark)]
|^
:_ q
?+ q graph
[~ %graph-validator-link] convert-links
[~ %graph-validator-publish] convert-publish
==
::
++ convert-links
%+ gas:orm *graph:store
%+ turn (tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:: top-level
::
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^atom =node:store]
^- [^^atom node:store]
:: existing comments get turned into containers for revisions
::
:^ atom
post.node(contents ~, hash ~)
%graph
%+ gas:orm *graph:store
:_ ~ :- %0
:_ [%empty ~]
post.node(index (snoc index.post.node atom), hash ~)
::
++ convert-publish
%+ gas:orm *graph:store
%+ turn (tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:: top-level
::
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^atom =node:store]
^- [^^atom node:store]
:: existing container for publish note revisions
::
?+ atom !!
%1 [atom node]
%2
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^^atom =node:store]
^- [^^^atom node:store]
:+ atom post.node(contents ~, hash ~)
:- %graph
%+ gas:orm *graph:store
:_ ~ :- %1
:_ [%empty ~]
post.node(index (snoc index.post.node atom), hash ~)
==
--
::
++ maybe-unix-to-da
|= =atom
^- @
:: (bex 127) is roughly 226AD
?. (lte atom (bex 127))
atom
(add ~1970.1.1 (div (mul ~s1 atom) 1.000))
%4
%_ $
-.old %5
::
++ convert-unix-timestamped-node
|= =node:store
^- node:store
=. index.post.node
(convert-unix-timestamped-index index.post.node)
?. ?=(%graph -.children.node)
node
:+ post.node
%graph
(convert-unix-timestamped-graph p.children.node)
::
++ convert-unix-timestamped-index
|= =index:store
(turn index maybe-unix-to-da)
::
++ convert-unix-timestamped-graph
|= =graph:store
%+ gas:orm *graph:store
%+ turn
(tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:- (maybe-unix-to-da atom)
(convert-unix-timestamped-node node)
--
--
update-logs.old
%- ~(gas by *update-logs:store)
%+ turn ~(tap by graphs.old)
|= [=resource:store =graph:store mar=(unit mark)]
:- resource
=/ log (~(got by update-logs.old) resource)
?. =(~ log) log
=/ =logged-update:store
[now.bowl %add-graph resource graph mar %.y]
(gas:orm-log ~ [now.bowl logged-update] ~)
==
::
%5 [cards this(state old)]
==
::
++ on-watch
~/ %graph-store-watch
@ -213,7 +128,7 @@
++ give
|= =action:store
^- (list card)
[%give %fact ~ [%graph-update-1 !>([now.bowl action])]]~
[%give %fact ~ [%graph-update-2 !>([now.bowl action])]]~
--
::
++ on-poke
@ -224,7 +139,7 @@
?> (team:title our.bowl src.bowl)
=^ cards state
?+ mark (on-poke:def mark vase)
%graph-update-1 (graph-update !<(update:store vase))
%graph-update-2 (graph-update !<(update:store vase))
%noun (debug !<(debug-input vase))
%import (poke-import q.vase)
==
@ -239,7 +154,7 @@
%add-graph (add-graph p.update +.q.update)
%remove-graph (remove-graph +.q.update)
%add-nodes (add-nodes p.update +.q.update)
%remove-nodes (remove-nodes p.update +.q.update)
%remove-posts (remove-posts p.update +.q.update)
%add-signatures (add-signatures p.update +.q.update)
%remove-signatures (remove-signatures p.update +.q.update)
%add-tag (add-tag +.q.update)
@ -319,27 +234,27 @@
++ check-for-duplicates
|= [=graph:store nodes=(set index:store)]
^- ?
=/ node-list ~(tap in nodes)
|-
?~ node-list %.n
?: (has-node graph i.node-list) %.y
$(node-list t.node-list)
::
++ has-node
|= [=graph:store =index:store]
^- ?
=/ node=(unit node:store) ~
|-
?~ index
?=(^ node)
?~ t.index
?=(^ (get:orm graph i.index))
=. node (get:orm graph i.index)
?~ node %.n
?- -.children.u.node
%empty %.n
%graph $(graph p.children.u.node, index t.index)
==
|^
%+ lien ~(tap in nodes)
|= =index:store
(has-node graph index)
::
++ has-node
|= [=graph:store =index:store]
^- ?
=/ node=(unit node:store) ~
|-
?~ index
?=(^ node)
?~ t.index
?=(^ (get:orm graph i.index))
=. node (get:orm graph i.index)
?~ node %.n
?- -.children.u.node
%empty %.n
%graph $(graph p.children.u.node, index t.index)
==
--
::
++ sort-nodes
|= nodes=(map index:store node:store)
@ -382,8 +297,10 @@
:: add child
::
?~ t.index
=* p post.node
?~ hash.p node(signatures.post *signatures:store)
~| "cannot add deleted post"
?> ?=(%& -.post.node)
=* p p.post.node
?~ hash.p node(signatures.p.post *signatures:store)
=/ =validated-portion:store
[parent-hash author.p time-sent.p contents.p]
=/ =hash:store `@ux`(sham validated-portion)
@ -402,8 +319,14 @@
^- internal-graph:store
:- %graph
%_ $
index t.index
parent-hash hash.post.parent
index t.index
::
parent-hash
?- -.post.parent
%| `p.post.parent
%& hash.p.post.parent
==
::
graph
?: ?=(%graph -.children.parent)
p.children.parent
@ -412,7 +335,7 @@
==
--
::
++ remove-nodes
++ remove-posts
|= [=time =resource:store indices=(set index:store)]
^- (quip card _state)
|^
@ -420,82 +343,83 @@
(~(got by graphs) resource)
=/ =update-log:store (~(got by update-logs) resource)
=. update-log
(put:orm-log update-log time [time [%remove-nodes resource indices]])
=/ [affected-indices=(set index:store) new-graph=graph:store]
(remove-indices resource graph (sort ~(tap in indices) by-lent))
::
:- (give [/updates]~ [%remove-nodes resource (~(uni in indices) affected-indices)])
(put:orm-log update-log time [time [%remove-posts resource indices]])
:- (give [/updates]~ [%remove-posts resource indices])
%_ state
update-logs (~(put by update-logs) resource update-log)
update-logs (~(put by update-logs) resource update-log)
::
graphs
%+ ~(put by graphs)
resource
[new-graph mark]
:_ mark
%^ remove-indices
resource
graph
(sort ~(tap in indices) by-lent)
==
::
:: we always want to remove the deepest node first,
:: so we don't remove parents before children
++ by-lent
|* [a=(list) b=(list)]
^- ?
(gth (lent a) (lent b))
::
++ remove-indices
=| affected=(set index:store)
|= [=resource:store =graph:store indices=(list index:store)]
^- [(set index:store) graph:store]
?~ indices [affected graph]
=^ new-affected graph
(remove-index graph i.indices)
^- graph:store
?~ indices graph
%_ $
indices t.indices
affected (~(uni in affected) new-affected)
==
::
++ get-descendants
|= =graph:store
=| indices=(list index:store)
=/ nodes (tap:orm:store graph)
%- ~(gas in *(set index:store))
|- =* tap-nodes $
^+ indices
%- zing
%+ turn nodes
|= [atom =node:store]
^- (list index:store)
%+ welp
index.post.node^~
?. ?=(%graph -.children.node)
~
%_ tap-nodes
nodes (tap:orm p.children.node)
indices t.indices
graph (remove-index graph i.indices)
==
::
++ remove-index
=| indices=(set index:store)
=| parent-hash=(unit hash:store)
|= [=graph:store =index:store]
^- [(set index:store) graph:store]
?~ index [indices graph]
^- graph:store
?~ index graph
=* atom i.index
%^ put:orm
graph
atom
:: last index in list
::
?~ t.index
=^ rm-node graph (del:orm graph atom)
?~ rm-node `graph
?. ?=(%graph -.children.u.rm-node)
`graph
=/ new-indices
(get-descendants p.children.u.rm-node)
[(~(uni in indices) new-indices) graph]
=/ =node:store
=/ =node:store
~| "cannot remove index that does not exist {<index>}"
(need (get:orm graph atom))
%_ node
post
~| "cannot remove post that has already been removed"
?> ?=(%& -.post.node)
=* p p.post.node
^- maybe-post:store
:- %|
?~ hash.p
=/ =validated-portion:store
[parent-hash author.p time-sent.p contents.p]
`@ux`(sham validated-portion)
u.hash.p
==
:: recurse children
::
=/ parent=node:store
~| "parent index does not exist to remove a node from!"
(need (get:orm graph atom))
~| "child index does not exist to remove a node from!"
?> ?=(%graph -.children.node)
=^ new-indices p.children.node
$(graph p.children.node, index t.index)
:- (~(uni in indices) new-indices)
(put:orm graph atom node)
?> ?=(%graph -.children.parent)
%_ parent
p.children
%_ $
index t.index
graph p.children.parent
::
parent-hash
?- -.post.parent
%| `p.post.parent
%& hash.p.post.parent
==
==
==
--
::
++ add-signatures
@ -531,11 +455,13 @@
graph
atom
?~ t.index
~| "cannot add signatures to a deleted post"
?> ?=(%& -.post.node)
~| "cannot add signatures to a node missing a hash"
?> ?=(^ hash.post.node)
?> ?=(^ hash.p.post.node)
~| "signatures did not match public keys!"
?> (are-signatures-valid:sigs our.bowl signatures u.hash.post.node now.bowl)
node(signatures.post (~(uni in signatures) signatures.post.node))
?> (are-signatures-valid:sigs our.bowl signatures u.hash.p.post.node now.bowl)
node(signatures.p.post (~(uni in signatures) signatures.p.post.node))
~| "child graph does not exist to add signatures to!"
?> ?=(%graph -.children.node)
node(p.children $(graph p.children.node, index t.index))
@ -576,28 +502,29 @@
graph
atom
?~ t.index
node(signatures.post (~(dif in signatures) signatures.post.node))
~| "cannot add signatures to a deleted post"
?> ?=(%& -.post.node)
node(signatures.p.post (~(dif in signatures) signatures.p.post.node))
~| "child graph does not exist to add signatures to!"
?> ?=(%graph -.children.node)
node(p.children $(graph p.children.node, index t.index))
--
::
++ add-tag
|= [=term =resource:store]
|= [=term =uid:store]
^- (quip card _state)
?> (~(has by graphs) resource)
:- (give [/updates /tags ~] [%add-tag term resource])
?> (~(has by graphs) resource.uid)
:- (give [/updates /tags ~] [%add-tag term uid])
%_ state
tag-queries (~(put ju tag-queries) term resource)
tag-queries (~(put ju tag-queries) term uid)
==
::
++ remove-tag
|= [=term =resource:store]
|= [=term =uid:store]
^- (quip card _state)
?> (~(has by graphs) resource)
:- (give [/updates /tags ~] [%remove-tag term resource])
:- (give [/updates /tags ~] [%remove-tag term uid])
%_ state
tag-queries (~(del ju tag-queries) term resource)
tag-queries (~(del ju tag-queries) term uid)
==
::
++ archive-graph
@ -610,10 +537,6 @@
archive (~(put by archive) resource (~(got by graphs) resource))
graphs (~(del by graphs) resource)
update-logs (~(del by update-logs) resource)
tag-queries
%- ~(run by tag-queries)
|= =resources:store
(~(del in resources) resource)
==
::
++ unarchive-graph
@ -648,7 +571,7 @@
?- -.q.update
%add-graph update(resource.q resource)
%add-nodes update(resource.q resource)
%remove-nodes update(resource.q resource)
%remove-posts update(resource.q resource)
%add-signatures update(resource.uid.q resource)
%remove-signatures update(resource.uid.q resource)
==
@ -657,7 +580,7 @@
++ give
|= [paths=(list path) update=action:store]
^- (list card)
[%give %fact paths [%graph-update-1 !>([now.bowl update])]]~
[%give %fact paths [%graph-update-2 !>([now.bowl update])]]~
--
::
++ debug
@ -682,7 +605,10 @@
%+ roll (tap:orm graph)
|= [[=atom =node:store] out=?]
^- ?
?& ?=(^ (vale:dais [atom post.node]))
?& ?| ?=(%| -.post.node)
?=(^ (vale:dais [atom p.post.node]))
==
::
?- -.children.node
%empty %.y
%graph ^$(graph p.children.node)
@ -691,155 +617,7 @@
++ poke-import
|= arc=*
^- (quip card _state)
|^
=/ sty=state-3 [%3 (remake-network ;;(tree-network +.arc))]
:_ sty
%+ turn ~(tap by graphs.sty)
|= [rid=resource:store =marked-graph:store]
^- card
?: =(our.bowl entity.rid)
=/ =cage [%push-hook-action !>([%add rid])]
[%pass / %agent [our.bowl %graph-push-hook] %poke cage]
(try-rejoin rid 0)
::
+$ tree-network
$: graphs=tree-graphs
tag-queries=(tree [term (tree resource:store)])
update-logs=tree-update-logs
archive=tree-graphs
validators=(tree ^mark)
==
+$ tree-graphs (tree [resource:store tree-marked-graph])
+$ tree-marked-graph [p=tree-graph q=(unit ^mark)]
+$ tree-graph (tree [atom tree-node])
+$ tree-node [post=tree-post children=tree-internal-graph]
+$ tree-internal-graph
$~ [%empty ~]
$% [%graph p=tree-graph]
[%empty ~]
==
+$ tree-update-logs (tree [resource:store tree-update-log])
+$ tree-update-log (tree [time tree-logged-update])
+$ tree-logged-update
$: p=time
$= q
$% [%add-graph =resource:store =tree-graph mark=(unit ^mark) ow=?]
[%add-nodes =resource:store nodes=(tree [index:store tree-node])]
[%remove-nodes =resource:store indices=(tree index:store)]
[%add-signatures =uid:store signatures=tree-signatures]
[%remove-signatures =uid:store signatures=tree-signatures]
==
==
+$ tree-signatures (tree signature:store)
+$ tree-post
$: author=ship
=index:store
time-sent=time
contents=(list content:store)
hash=(unit hash:store)
signatures=tree-signatures
==
::
++ remake-network
|= t=tree-network
^- network:store
:* (remake-graphs graphs.t)
(remake-jug tag-queries.t)
(remake-update-logs update-logs.t)
(remake-graphs archive.t)
(remake-set validators.t)
==
::
++ remake-graphs
|= t=tree-graphs
^- graphs:store
%- remake-map
(~(run by t) remake-marked-graph)
::
++ remake-marked-graph
|= t=tree-marked-graph
^- marked-graph:store
[(remake-graph p.t) q.t]
::
++ remake-graph
|= t=tree-graph
^- graph:store
%+ gas:orm *graph:store
%+ turn ~(tap by t)
|= [a=atom tn=tree-node]
^- [atom node:store]
[a (remake-node tn)]
::
++ remake-internal-graph
|= t=tree-internal-graph
^- internal-graph:store
?: ?=(%empty -.t)
[%empty ~]
[%graph (remake-graph p.t)]
::
++ remake-node
|= t=tree-node
^- node:store
:- (remake-post post.t)
(remake-internal-graph children.t)
::
++ remake-update-logs
|= t=tree-update-logs
^- update-logs:store
%- remake-map
(~(run by t) remake-update-log)
::
++ remake-update-log
|= t=tree-update-log
^- update-log:store
=/ ulm ((ordered-map time logged-update:store) gth)
%+ gas:ulm *update-log:store
%+ turn ~(tap by t)
|= [=time tlu=tree-logged-update]
^- [^time logged-update:store]
[time (remake-logged-update tlu)]
::
++ remake-logged-update
|= t=tree-logged-update
^- logged-update:store
:- p.t
?- -.q.t
%add-graph
:* %add-graph
resource.q.t
(remake-graph tree-graph.q.t)
mark.q.t
ow.q.t
==
::
%add-nodes
:- %add-nodes
:- resource.q.t
%- remake-map
(~(run by nodes.q.t) remake-node)
::
%remove-nodes
[%remove-nodes resource.q.t (remake-set indices.q.t)]
::
%add-signatures
[%add-signatures uid.q.t (remake-set signatures.q.t)]
::
%remove-signatures
[%remove-signatures uid.q.t (remake-set signatures.q.t)]
==
::
++ remake-post
|= t=tree-post
^- post:store
t(signatures (remake-set signatures.t))
--
::
++ try-rejoin
|= [rid=resource:store nack-count=@]
^- card
=/ res-path (en-path:res rid)
=/ wire [%try-rejoin (scot %ud nack-count) res-path]
[%pass wire %agent [entity.rid %graph-push-hook] %watch resource+res-path]
(import:store arc our.bowl)
--
::
++ on-peek
@ -858,15 +636,15 @@
``noun+!>(q.u.result)
::
[%x %keys ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%keys ~(key by graphs)]])
::
[%x %tags ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%tags ~(key by tag-queries)]])
::
[%x %tag-queries ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!>(`update:store`[now.bowl [%tag-queries tag-queries]])
::
[%x %graph @ @ ~]
@ -875,7 +653,7 @@
=/ result=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ result [~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
[%add-graph [ship term] `graph:store`p.u.result q.u.result %.y]
@ -890,7 +668,7 @@
?~ result
~& no-archived-graph+[ship term]
[~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
[%add-graph [ship term] `graph:store`p.u.result q.u.result %.y]
@ -906,7 +684,7 @@
=/ graph=(unit marked-graph:store)
(~(get by graphs) [ship term])
?~ graph [~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
@ -933,7 +711,7 @@
(turn t.t.t.t.path (cury slav %ud))
=/ node=(unit node:store) (get-node ship term index)
?~ node [~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
@ -952,7 +730,7 @@
=/ graph
(get-node-children ship term parent)
?~ graph [~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
@ -982,7 +760,7 @@
=/ children
(get-node-children ship term index)
?~ children [~ ~]
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes
@ -1008,7 +786,7 @@
?- -.children.u.node
%empty [~ ~]
%graph
:- ~ :- ~ :- %graph-update-1
:- ~ :- ~ :- %graph-update-2
!> ^- update:store
:- now.bowl
:+ %add-nodes

View File

@ -24,7 +24,6 @@
watch-on-self=_&
==
::
::
++ scry
|* [[our=@p now=@da] =mold p=path]
?> ?=(^ p)
@ -37,7 +36,6 @@
%^ scry [our now]
tube:clay
/cc/[desk]/[mark]/notification-kind
::
--
::
=| state-1
@ -126,15 +124,15 @@
::
++ poke-noun
|= non=*
?> ?=(%rewatch-dms non)
=/ graphs=(list resource)
~(tap in get-keys:gra)
:- ~
%_ state
watching
%- ~(gas in watching)
(murn graphs |=(rid=resource ?:((should-watch:ha rid) `[rid ~] ~)))
==
[~ state]
:: ?> ?=(%rewatch-dms non)
:: =/ graphs=(list resource)
:: ~(tap in get-keys:gra)
:: %_ state
:: watching
:: %- ~(gas in watching)
:: (murn graphs |=(rid=resource ?:((should-watch:ha rid) `[rid ~] ~)))
:: ==
::
++ hark-graph-hook-action
|= =action:hook
@ -182,7 +180,7 @@
~[watch-graph:ha]
::
%fact
?. ?=(%graph-update-1 p.cage.sign)
?. ?=(%graph-update-2 p.cage.sign)
(on-agent:def wire sign)
=^ cards state
(graph-update !<(update:graph-store q.cage.sign))
@ -197,18 +195,20 @@
::
?(%remove-graph %archive-graph)
(remove-graph resource.q.update)
::
%remove-nodes
(remove-nodes resource.q.update indices.q.update)
::
::
%remove-posts
(remove-posts resource.q.update indices.q.update)
::
%add-nodes
=* rid resource.q.update
(check-nodes ~(val by nodes.q.update) rid)
=/ assoc=(unit association:metadata)
(peek-association:met %graph rid)
(check-nodes ~(val by nodes.q.update) rid assoc)
==
:: this is awful, but notification kind should always switch
:: on the index, so hopefully doesn't matter
:: TODO: rethink this
++ remove-nodes
++ remove-posts
|= [rid=resource indices=(set index:graph-store)]
=/ to-remove
%- ~(gas by *(set [resource index:graph-store]))
@ -257,31 +257,30 @@
(get-graph-mop:gra rid)
=/ node=(unit node:graph-store)
(bind (peek:orm:graph-store graph) |=([@ =node:graph-store] node))
=/ assoc=(unit association:metadata)
(peek-association:met %graph rid)
=^ cards state
(check-nodes (drop node) rid)
?. (should-watch:ha rid)
(check-nodes (drop node) rid assoc)
?. (should-watch:ha rid assoc)
[cards state]
:_ state(watching (~(put in watching) [rid ~]))
(weld cards (give:ha ~[/updates] %listen [rid ~]))
::
::
++ check-nodes
|= $: nodes=(list node:graph-store)
rid=resource
assoc=(unit association:metadata)
==
=/ group=(unit resource)
(peek-group:met %graph rid)
?~ group
~& no-group+rid
?~ assoc
~& no-assoc+rid
`state
=/ metadatum=(unit metadatum:metadata)
(peek-metadatum:met %graph rid)
?~ metadatum `state
=* group group.u.assoc
=* metadatum metadatum.u.assoc
=/ module=term
?: ?=(%empty -.config.u.metadatum) %$
?: ?=(%group -.config.u.metadatum) %$
module.config.u.metadatum
abet:check:(abed:handle-update:ha rid nodes u.group module)
?: ?=(%empty -.config.metadatum) %$
?: ?=(%group -.config.metadatum) %$
module.config.metadatum
abet:check:(abed:handle-update:ha rid nodes group module)
--
::
++ on-peek on-peek:def
@ -343,12 +342,11 @@
$(contents t.contents)
::
++ should-watch
|= rid=resource
|= [rid=resource assoc=(unit association:metadata)]
^- ?
=/ group-rid=(unit resource)
(peek-group:met %graph rid)
?~ group-rid %.n
?| !(is-managed:grp u.group-rid)
?~ assoc
%.n
?| !(is-managed:grp group.u.assoc)
&(watch-on-self =(our.bowl entity.rid))
==
::
@ -367,7 +365,9 @@
update-core(rid r, updates upds, group grp, module mod)
::
++ get-conversion
(^get-conversion rid)
:: LA: this tube should be cached in %hark-graph-hook state
:: instead of just trying to keep it warm, as the scry overhead is large
~+ (^get-conversion rid)
::
++ abet
^- (quip card _state)
@ -417,30 +417,34 @@
|= =node:graph-store
^+ update-core
=. update-core (check-node-children node)
?: ?=(%| -.post.node)
update-core
=* pos p.post.node
=+ !< notif-kind=(unit notif-kind:hook)
(get-conversion !>([0 post.node]))
%- get-conversion
!>(`indexed-post:graph-store`[0 pos])
?~ notif-kind
update-core
=/ desc=@t
?: (is-mention contents.post.node)
?: (is-mention contents.pos)
%mention
name.u.notif-kind
=* not-kind u.notif-kind
=/ parent=index:post
(scag parent.index-len.not-kind index.post.node)
(scag parent.index-len.not-kind index.pos)
=/ notif-index=index:store
[%graph group rid module desc parent]
?: =(our.bowl author.post.node)
?: =(our.bowl author.pos)
(self-post node notif-index not-kind)
=. update-core
(update-unread-count not-kind notif-index [time-sent index]:post.node)
(update-unread-count not-kind notif-index [time-sent index]:pos)
=? update-core
?| =(desc %mention)
(~(has in watching) [rid parent])
==
=/ =contents:store
[%graph (limo post.node ~)]
(add-unread notif-index [time-sent.post.node %.n contents])
[%graph (limo pos ~)]
(add-unread notif-index [time-sent.pos %.n contents])
update-core
::
++ update-unread-count
@ -459,19 +463,19 @@
=notif-kind:hook
==
^+ update-core
?> ?=(%& -.post.node)
=/ =stats-index:store
(to-stats-index:store index)
=. update-core
(hark %seen-index time-sent.post.node stats-index)
(hark %seen-index time-sent.p.post.node stats-index)
=? update-core ?=(%count mode.notif-kind)
(hark %read-count stats-index)
=? update-core watch-on-self
(new-watch index.post.node [watch-for index-len]:notif-kind)
(new-watch index.p.post.node [watch-for index-len]:notif-kind)
update-core
::
++ add-unread
|= [=index:store =notification:store]
(hark %add-note index notification)
::
--
--

View File

@ -202,7 +202,7 @@
++ convert-graph-contents-4
|= con=(list post:post-zero:post)
^- (list post:post)
(turn con post-to-one:graph-store)
(turn con post-to-one:upgrade:graph-store)
::
++ convert-notifications-3
|= old=notifications:state-two:store

View File

@ -24,6 +24,6 @@
<div id="portal-root"></div>
<script src="/~landscape/js/channel.js"></script>
<script src="/~landscape/js/session.js"></script>
<script src="/~landscape/js/bundle/index.59e682153138f604d358.js"></script>
<script src="/~landscape/js/bundle/index.0a121973708299f6b966.js"></script>
</body>
</html>

View File

@ -5,6 +5,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[=resource mark=(unit mark) overwrite=? ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%add-graph resource (gas:orm ~ ~) mark overwrite]]

View File

@ -12,9 +12,9 @@
contents.post contents
==
::
:- %graph-update-1
:- %graph-update-2
^- update
:- now
:+ %add-nodes [our name]
%- ~(gas by *(map index node))
~[[[now]~ [post [%empty ~]]]]
~[[[now]~ [[%& post] [%empty ~]]]]

View File

@ -5,6 +5,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[[=resource =index] =signatures ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%add-signatures [resource index] signatures]]

View File

@ -3,8 +3,8 @@
/- *graph-store
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[=term =resource ~] ~]
[[=term =uid ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%add-tag term resource]]
[now [%add-tag term uid]]

View File

@ -5,6 +5,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[=resource ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%archive-graph resource]]

View File

@ -4,7 +4,7 @@
|= $: [now=@da eny=@uvJ bec=beak]
[[=ship graph=term ~] ~]
==
:- %graph-update-1
:- %graph-update-2
=/ our (scot %p p.bec)
=/ wen (scot %da now)
=/ who (scot %p ship)

View File

@ -4,6 +4,6 @@
|= $: [now=@da eny=@uvJ bec=beak]
[[graph=term =path ~] ~]
==
:- %graph-update-1
:- %graph-update-2
=- ~& update=- -
.^(=update:graph-store %cx path)

View File

@ -5,6 +5,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[=resource ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%remove-graph resource]]

View File

@ -1,10 +1,10 @@
:: graph-store|remove-nodes: remove nodes from a graph at indices
:: graph-store|remove-posts: remove nodes from a graph at indices
::
/- *graph-store
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[=resource indices=(set index) ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%remove-nodes resource indices]]
[now [%remove-posts resource indices]]

View File

@ -6,6 +6,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[[=resource =index] =signatures ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%remove-signatures [resource index] signatures]]

View File

@ -3,8 +3,8 @@
/- *graph-store
:- %say
|= $: [now=@da eny=@uvJ =beak]
[[=term =resource ~] ~]
[[=term =uid ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%remove-tag term resource]]
[now [%remove-tag term uid]]

View File

@ -5,6 +5,6 @@
|= $: [now=@da eny=@uvJ =beak]
[[=resource ~] ~]
==
:- %graph-update-1
:- %graph-update-2
^- update
[now [%unarchive-graph resource]]

View File

@ -3,15 +3,14 @@
:::: /hoon/code/hood/gen
::
/? 310
::
::::
::
:- %say
/- *sole
/+ *generators
:- %ask
|= $: [now=@da eny=@uvJ bec=beak]
[arg=?(~ [%reset ~]) ~]
==
=* our p.bec
:- %helm-code
^- (sole-result [%helm-code ?(~ %reset)])
?~ arg
=/ code=tape
%+ slag 1
@ -20,11 +19,23 @@
=/ step=tape
%+ scow %ud
.^(@ud %j /(scot %p our)/step/(scot %da now)/(scot %p our))
%- %- slog
:~ [%leaf code]
[%leaf (weld "current step=" step)]
[%leaf "use |code %reset to invalidate this and generate a new code"]
==
~
::
%+ print 'use |code %reset to invalidate this and generate a new code'
%+ print leaf+(weld "current step=" step)
%+ print leaf+code
(produce [%helm-code ~])
::
?> =(%reset -.arg)
%reset
%+ print 'continue?'
%+ print 'warning: resetting your code closes all web sessions'
%+ prompt
[%& %project "y/n: "]
%+ parse
;~ pose
(cold %.y (mask "yY"))
(cold %.n (mask "nN"))
==
|= reset=?
?. reset
no-product
(produce [%helm-code %reset])

View File

@ -67,7 +67,7 @@
=/ real=(set resource:re)
=/ upd=update:ga
%+ scry update:ga
[%x %graph-store /keys/graph-update-1]
[%x %graph-store /keys/graph-update-2]
?> ?=(%keys -.q.upd)
resources.q.upd
:: count activity per channel
@ -92,8 +92,11 @@
:- (lent week)
%~ wyt in
%+ roll week
|= [[* [author=ship *] *] a=(set ship)]
(~(put in a) author)
|= [[* mp=maybe-post:ga *] a=(set ship)]
?- -.mp
%| a
%& (~(put in a) author.p.mp)
==
:: render results
::
:- (tac 'the date is ' (scot %da now))

View File

@ -1,105 +1,10 @@
/- sur=graph-store, pos=post
/+ res=resource
/+ res=resource, migrate
=< [sur .]
=< [pos .]
=, sur
=, pos
|%
::
++ update-log-to-one
|= =update-log:zero
^- ^update-log
%+ gas:orm-log *^update-log
%+ turn (tap:orm-log:zero update-log)
|= [=time =logged-update:zero]
:- time
:- p.logged-update
(logged-update-to-one q.logged-update)
::
++ logged-update-to-one
|= upd=logged-update-0:zero
?+ -.upd upd
%add-graph upd(graph (graph-to-one graph.upd))
%add-nodes upd(nodes (~(run by nodes.upd) node-to-one))
==
::
++ node-to-one
|= =node:zero
(node:(upgrade ,post:zero ,post) node post-to-one)
::
++ graph-to-one
|= =graph:zero
(graph:(upgrade ,post:zero ,post) graph post-to-one)
::
++ marked-graph-to-one
|= [=graph:zero m=(unit mark)]
[(graph-to-one graph) m]
::
++ post-to-one
|= p=post:zero
^- post
p(contents (contents-to-one contents.p))
::
++ contents-to-one
|= cs=(list content:zero)
^- (list content)
%+ murn cs
|= =content:zero
^- (unit ^content)
?: ?=(%reference -.content) ~
`content
::
++ upgrade
|* [in-pst=mold out-pst=mold]
=>
|%
++ in-orm
((ordered-map atom in-node) gth)
+$ in-node
[post=in-pst children=in-internal-graph]
+$ in-graph
((mop atom in-node) gth)
+$ in-internal-graph
$~ [%empty ~]
$% [%graph p=in-graph]
[%empty ~]
==
::
++ out-orm
((ordered-map atom out-node) gth)
+$ out-node
[post=out-pst children=out-internal-graph]
+$ out-graph
((mop atom out-node) gth)
+$ out-internal-graph
$~ [%empty ~]
$% [%graph p=out-graph]
[%empty ~]
==
--
|%
::
++ graph
|= $: gra=in-graph
fn=$-(in-pst out-pst)
==
^- out-graph
%+ gas:out-orm *out-graph
^- (list [atom out-node])
%+ turn (tap:in-orm gra)
|= [a=atom n=in-node]
^- [atom out-node]
[a (node n fn)]
::
++ node
|= [nod=in-node fn=$-(in-pst out-pst)]
^- out-node
:- (fn post.nod)
^- out-internal-graph
?: ?=(%empty -.children.nod)
[%empty ~]
[%graph (graph p.children.nod fn)]
--
:: NOTE: move these functions to zuse
++ nu :: parse number as hex
|= jon=json
@ -212,6 +117,14 @@
s+(enjs-path:res grp)
--
::
++ maybe-post
|= mp=^maybe-post
^- json
?- -.mp
%| s+(scot %ux p.mp)
%& (post p.mp)
==
::
++ post
|= p=^post
^- json
@ -252,8 +165,8 @@
[%nodes (nodes nodes.upd)]
==
::
%remove-nodes
:- %remove-nodes
%remove-posts
:- %remove-posts
%- pairs
:~ [%resource (enjs:res resource.upd)]
[%indices (indices indices.upd)]
@ -277,14 +190,14 @@
:- %add-tag
%- pairs
:~ [%term s+term.upd]
[%resource (enjs:res resource.upd)]
[%uid (uid uid.upd)]
==
::
%remove-tag
:- %remove-tag
%- pairs
:~ [%term s+term.upd]
[%resource (enjs:res resource.upd)]
[%uid (uid uid.upd)]
==
::
%archive-graph
@ -306,9 +219,9 @@
:- %tag-queries
%- pairs
%+ turn ~(tap by tag-queries.upd)
|= [=term =resources]
|= [=term uids=(set ^uid)]
^- [cord json]
[term [%a (turn ~(tap in resources) enjs:res)]]
[term [%a (turn ~(tap in uids) uid)]]
==
::
++ graph
@ -328,7 +241,7 @@
|= n=^node
^- json
%- pairs
:~ [%post (post post.n)]
:~ [%post (maybe-post post.n)]
:- %children
?- -.children.n
%empty ~
@ -336,7 +249,6 @@
==
==
::
::
++ nodes
|= m=(map ^index ^node)
^- json
@ -370,7 +282,7 @@
++ decode
%- of
:~ [%add-nodes add-nodes]
[%remove-nodes remove-nodes]
[%remove-posts remove-posts]
[%add-signatures add-signatures]
[%remove-signatures remove-signatures]
::
@ -422,7 +334,7 @@
::
++ node
%- ot
:~ [%post post]
:~ [%post maybe-post]
[%children internal-graph]
==
::
@ -433,6 +345,15 @@
[%empty ~]
[%graph (graph jon)]
::
++ maybe-post
|= jon=json
^- ^maybe-post
?~ jon !!
?+ -.jon !!
%s [%| (nu jon)]
%o [%& (post jon)]
==
::
++ post
%- ot
:~ [%author (su ;~(pfix sig fed:ag))]
@ -489,9 +410,8 @@
:~ expression+so
output+tang
==
::
++ remove-nodes
++ remove-posts
%- ot
:~ [%resource dejs:res]
[%indices (as index)]
@ -527,13 +447,13 @@
++ add-tag
%- ot
:~ [%term so]
[%resource dejs:res]
[%uid uid]
==
::
++ remove-tag
%- ot
:~ [%term so]
[%resource dejs:res]
[%uid uid]
==
::
++ keys
@ -568,4 +488,391 @@
*signatures
==
--
::
++ upgrade
|%
::
:: +two
::
++ marked-graph-to-two
|= [=graph:one m=(unit mark)]
[(graph-to-two graph) m]
::
++ graph-to-two
|= =graph:one
(graph:(upgrade ,post:one ,maybe-post) graph post-to-two)
::
++ post-to-two
|= p=post:one
^- maybe-post
[%& p]
::
::
:: +one
::
++ update-log-to-one
|= =update-log:zero
^- update-log:one
%+ gas:orm-log:one *update-log:one
%+ turn (tap:orm-log:zero update-log)
|= [=time =logged-update:zero]
^- [^time logged-update:one]
:- time
:- p.logged-update
(logged-update-to-one q.logged-update)
::
++ logged-update-to-one
|= upd=logged-update-0:zero
^- logged-action:one
?+ -.upd upd
%add-graph upd(graph (graph-to-one graph.upd))
%add-nodes upd(nodes (~(run by nodes.upd) node-to-one))
==
::
++ node-to-one
|= =node:zero
(node:(upgrade ,post:zero ,post) node post-to-one)
::
++ graph-to-one
|= =graph:zero
(graph:(upgrade ,post:zero ,post) graph post-to-one)
::
++ marked-graph-to-one
|= [=graph:zero m=(unit mark)]
[(graph-to-one graph) m]
::
++ post-to-one
|= p=post:zero
^- post
p(contents (contents-to-one contents.p))
::
++ contents-to-one
|= cs=(list content:zero)
^- (list content)
%+ murn cs
|= =content:zero
^- (unit ^content)
?: ?=(%reference -.content) ~
`content
::
++ upgrade
|* [in-pst=mold out-pst=mold]
=>
|%
++ in-orm
((ordered-map atom in-node) gth)
+$ in-node
[post=in-pst children=in-internal-graph]
+$ in-graph
((mop atom in-node) gth)
+$ in-internal-graph
$~ [%empty ~]
$% [%graph p=in-graph]
[%empty ~]
==
::
++ out-orm
((ordered-map atom out-node) gth)
+$ out-node
[post=out-pst children=out-internal-graph]
+$ out-graph
((mop atom out-node) gth)
+$ out-internal-graph
$~ [%empty ~]
$% [%graph p=out-graph]
[%empty ~]
==
--
|%
::
++ graph
|= $: gra=in-graph
fn=$-(in-pst out-pst)
==
^- out-graph
%+ gas:out-orm *out-graph
^- (list [atom out-node])
%+ turn (tap:in-orm gra)
|= [a=atom n=in-node]
^- [atom out-node]
[a (node n fn)]
::
++ node
|= [nod=in-node fn=$-(in-pst out-pst)]
^- out-node
:- (fn post.nod)
^- out-internal-graph
?: ?=(%empty -.children.nod)
[%empty ~]
[%graph (graph p.children.nod fn)]
--
::
++ zero-load
:: =* infinitely recurses
=, store=zero
=, orm=orm:zero
=, orm-log=orm-log:zero
|%
++ change-revision-graph
|= [=graph:store q=(unit mark)]
^- [graph:store (unit mark)]
|^
:_ q
?+ q graph
[~ %graph-validator-link] convert-links
[~ %graph-validator-publish] convert-publish
==
::
++ convert-links
%+ gas:orm *graph:store
%+ turn (tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:: top-level
::
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^atom =node:store]
^- [^^atom node:store]
:: existing comments get turned into containers for revisions
::
:^ atom
post.node(contents ~, hash ~)
%graph
%+ gas:orm *graph:store
:_ ~ :- %0
:_ [%empty ~]
post.node(index (snoc index.post.node atom), hash ~)
::
++ convert-publish
%+ gas:orm *graph:store
%+ turn (tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:: top-level
::
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^atom =node:store]
^- [^^atom node:store]
:: existing container for publish note revisions
::
?+ atom !!
%1 [atom node]
%2
:+ atom post.node
?: ?=(%empty -.children.node)
[%empty ~]
:- %graph
%+ gas:orm *graph:store
%+ turn (tap:orm p.children.node)
|= [=^^atom =node:store]
^- [^^^atom node:store]
:+ atom post.node(contents ~, hash ~)
:- %graph
%+ gas:orm *graph:store
:_ ~ :- %1
:_ [%empty ~]
post.node(index (snoc index.post.node atom), hash ~)
==
--
::
++ maybe-unix-to-da
|= =atom
^- @
:: (bex 127) is roughly 226AD
?. (lte atom (bex 127))
atom
(add ~1970.1.1 (div (mul ~s1 atom) 1.000))
::
++ convert-unix-timestamped-node
|= =node:store
^- node:store
=. index.post.node
(convert-unix-timestamped-index index.post.node)
?. ?=(%graph -.children.node)
node
:+ post.node
%graph
(convert-unix-timestamped-graph p.children.node)
::
++ convert-unix-timestamped-index
|= =index:store
(turn index maybe-unix-to-da)
::
++ convert-unix-timestamped-graph
|= =graph:store
%+ gas:orm *graph:store
%+ turn
(tap:orm graph)
|= [=atom =node:store]
^- [^atom node:store]
:- (maybe-unix-to-da atom)
(convert-unix-timestamped-node node)
--
--
++ import
|= [arc=* our=ship]
^- (quip card:agent:gall [%5 network])
|^
=/ sty [%5 (remake-network ;;(tree-network +.arc))]
:_ sty
%+ turn ~(tap by graphs.sty)
|= [rid=resource =marked-graph]
^- card:agent:gall
?: =(our entity.rid)
=/ =cage [%push-hook-action !>([%add rid])]
[%pass / %agent [our %graph-push-hook] %poke cage]
(try-rejoin rid 0)
::
+$ tree-network
$: graphs=tree-graphs
tag-queries=(tree [term (tree uid)])
update-logs=tree-update-logs
archive=tree-graphs
~
==
+$ tree-graphs (tree [resource tree-marked-graph])
+$ tree-marked-graph [p=tree-graph q=(unit ^mark)]
+$ tree-graph (tree [atom tree-node])
+$ tree-node [post=tree-maybe-post children=tree-internal-graph]
+$ tree-internal-graph
$~ [%empty ~]
$% [%graph p=tree-graph]
[%empty ~]
==
+$ tree-update-logs (tree [resource tree-update-log])
+$ tree-update-log (tree [time tree-logged-update])
+$ tree-logged-update
$: p=time
$= q
$% [%add-graph =resource =tree-graph mark=(unit ^mark) ow=?]
[%add-nodes =resource nodes=(tree [index tree-node])]
[%remove-posts =resource indices=(tree index)]
[%add-signatures =uid signatures=tree-signatures]
[%remove-signatures =uid signatures=tree-signatures]
==
==
+$ tree-signatures (tree signature)
+$ tree-maybe-post (each tree-post hash)
+$ tree-post
$: author=ship
=index
time-sent=time
contents=(list content)
hash=(unit hash)
signatures=tree-signatures
==
::
++ remake-network
|= t=tree-network
^- network
:* (remake-graphs graphs.t)
(remake-jug:migrate tag-queries.t)
(remake-update-logs update-logs.t)
(remake-graphs archive.t)
~
==
::
++ remake-graphs
|= t=tree-graphs
^- graphs
%- remake-map:migrate
(~(run by t) remake-marked-graph)
::
++ remake-marked-graph
|= t=tree-marked-graph
^- marked-graph
[(remake-graph p.t) q.t]
::
++ remake-graph
|= t=tree-graph
^- graph
%+ gas:orm *graph
%+ turn ~(tap by t)
|= [a=atom tn=tree-node]
^- [atom node]
[a (remake-node tn)]
::
++ remake-internal-graph
|= t=tree-internal-graph
^- internal-graph
?: ?=(%empty -.t)
[%empty ~]
[%graph (remake-graph p.t)]
::
++ remake-node
|= t=tree-node
^- node
:- (remake-post post.t)
(remake-internal-graph children.t)
::
++ remake-update-logs
|= t=tree-update-logs
^- update-logs
%- remake-map:migrate
(~(run by t) remake-update-log)
::
++ remake-update-log
|= t=tree-update-log
^- update-log
=/ ulm ((ordered-map time logged-update) gth)
%+ gas:ulm *update-log
%+ turn ~(tap by t)
|= [=time tlu=tree-logged-update]
^- [^time logged-update]
[time (remake-logged-update tlu)]
::
++ remake-logged-update
|= t=tree-logged-update
^- logged-update
:- p.t
?- -.q.t
%add-graph
:* %add-graph
resource.q.t
(remake-graph tree-graph.q.t)
mark.q.t
ow.q.t
==
::
%add-nodes
:- %add-nodes
:- resource.q.t
%- remake-map:migrate
(~(run by nodes.q.t) remake-node)
::
%remove-posts
[%remove-posts resource.q.t (remake-set:migrate indices.q.t)]
::
%add-signatures
[%add-signatures uid.q.t (remake-set:migrate signatures.q.t)]
::
%remove-signatures
[%remove-signatures uid.q.t (remake-set:migrate signatures.q.t)]
==
::
++ remake-post
|= t=tree-maybe-post
^- maybe-post
?- -.t
%| t
%& t(signatures.p (remake-set:migrate signatures.p.t))
==
::
++ try-rejoin
|= [rid=resource nack-count=@]
^- card:agent:gall
=/ res-path (en-path:res rid)
=/ wire [%try-rejoin (scot %ud nack-count) res-path]
[%pass wire %agent [entity.rid %graph-push-hook] %watch resource+res-path]
--
--

View File

@ -19,7 +19,7 @@
%add-graph ~[resource.q.update]
%remove-graph ~[resource.q.update]
%add-nodes ~[resource.q.update]
%remove-nodes ~[resource.q.update]
%remove-posts ~[resource.q.update]
%add-signatures ~[resource.uid.q.update]
%remove-signatures ~[resource.uid.q.update]
%archive-graph ~[resource.q.update]
@ -76,6 +76,7 @@
++ get-graph
|= res=resource
^- update:store
=- -(p *time)
%+ scry-for update:store
/graph/(scot %p entity.res)/[name.res]
::

View File

@ -90,7 +90,12 @@
$: tracking=(map resource track)
inner-state=vase
==
::
+$ base-state-3
$: prev-version=@ud
prev-min-version=@ud
base-state-2
==
::
+$ state-0 [%0 base-state-0]
::
@ -100,12 +105,24 @@
::
+$ state-3 [%3 base-state-2]
::
+$ state-4 [%4 base-state-3]
::
+$ versioned-state
$% state-0
state-1
state-2
state-3
state-4
==
:: +diplomatic: only renegotiate if versions changed
::
:: If %.n please leave note as to why renegotiation necessary
::
:: - Fixing incorrectly held unversioned subscriptions
::
++ diplomatic
^- ?
%.n
::
++ default
|* [pull-hook=* =config]
@ -198,7 +215,7 @@
++ agent
|* =config
|= =(pull-hook config)
=| state-3
=| state-4
=* state -
^- agent:gall
=<
@ -224,13 +241,21 @@
=| cards=(list card:agent:gall)
|^
?- -.old
%3
%4
=^ og-cards pull-hook
(on-load:og inner-state.old)
=. state old
=/ kick=(list card)
?: ?& =(min-version.config prev-min-version.old)
=(version.config prev-version.old)
diplomatic
==
~
(poke-self:pass kick+!>(%kick))^~
:_ this
:(weld cards og-cards (poke-self:pass kick+!>(%kick))^~)
:(weld cards og-cards kick)
::
%3 $(old [%4 0 0 +.old])
%2 $(old (state-to-3 old))
%1 $(old [%2 +.old ~])
%0 !! :: pre-breach
@ -255,8 +280,10 @@
::
++ on-save
^- vase
=. inner-state
on-save:og
=: inner-state on-save:og
prev-min-version min-version.config
prev-version version.config
==
!>(state)
::
++ on-poke
@ -422,6 +449,7 @@
?~ tan tr-core
?. versioned
(tr-ap-og:tr-cleanup |.((on-pull-nack:og rid u.tan)))
%- (slog leaf+"versioned nack for {<rid>} in {<dap.bowl>}" u.tan)
=/ pax
(kick-mule:virt rid |.((on-pull-kick:og rid)))
?~ pax tr-failed-kick
@ -446,18 +474,18 @@
:: subscription
tr-core
(tr-suspend-pub-ver min-version.config)
=/ =vase
=/ =^cage
(convert-to:ver cage)
=/ =wire
(make-wire /store)
=+ resources=(~(gas in *(set resource)) (resource-for-update:og vase))
=+ resources=(~(gas in *(set resource)) (resource-for-update:og q.cage))
?> ?| no-validate.config
?& (check-src resources)
(~(has in resources) rid)
== ==
=/ =mark
(append-version:ver version.config)
(tr-emit (~(poke-our pass wire) store-name.config mark vase))
(tr-emit (~(poke-our pass wire) store-name.config cage))
--
::
++ tr-kick
@ -472,6 +500,7 @@
::
++ tr-add
|= [s=^ship r=resource]
?< =(s our.bowl)
=: ship s
rid r
status [%active ~]

View File

@ -57,14 +57,32 @@
inner-state=vase
==
::
+$ base-state-1
$: prev-version=@ud
prev-min-version=@ud
base-state-0
==
::
+$ state-0 [%0 base-state-0]
::
+$ state-1 [%1 base-state-0]
+$ state-2 [%2 base-state-1]
::
+$ versioned-state
$% state-0
state-1
state-2
==
:: +diplomatic: only renegotiate if versions changed
::
:: If %.n please leave note as to why renegotiation necessary
::
:: - Fixing incorrectly held unversioned subscriptions
::
++ diplomatic
^- ?
%.n
::
++ push-hook
|* =config
$_ ^|
@ -153,7 +171,7 @@
++ agent
|* =config
|= =(push-hook config)
=| state-1
=| state-2
=* state -
^- agent:gall
=<
@ -179,16 +197,21 @@
=| cards=(list card:agent:gall)
|^
?- -.old
%1
%2
=^ og-cards push-hook
(on-load:og inner-state.old)
=/ old-subs
find-old-subs
(find-old-subs [prev-version prev-min-version]:old)
=/ version-cards
:- (fact:io version+!>(version.config) /version ~)
?~ old-subs ~
(kick:io old-subs)^~
[:(weld cards og-cards version-cards) this(state old)]
::
%1
%_ $
old [%2 0 0 +.old]
==
::
::
%0
@ -205,6 +228,13 @@
==
::
++ find-old-subs
|= [prev-min-version=@ud prev-version=@ud]
?: ?& =(min-version.config prev-min-version)
=(prev-version version.config)
diplomatic
==
:: bail on kick if we didn't change versions
~
%~ tap in
%+ roll
~(val by sup.bowl)
@ -230,8 +260,10 @@
--
::
++ on-save
=. inner-state
on-save:og
=: prev-version version.config
prev-min-version min-version.config
inner-state on-save:og
==
!>(state)
::
++ on-poke
@ -270,23 +302,21 @@
?. (supported:ver mark)
:_ this
(fact-init-kick:io version+!>(min-version.config))
=/ =vase
(convert-to:ver mark (initial-watch:og t.t.t.t.t.t.path resource))
:_ this
[%give %fact ~ mark vase]~
=- [%give %fact ~ -]~
(convert-to:ver mark (initial-watch:og t.t.t.t.t.t.path resource))
::
++ unversioned
?> ?=([%ship @ @ *] t.path)
?. =(min-version.config 0)
~& >>> "unversioned req from: {<src.bowl>}, nooping"
`this
=/ =resource
(de-path:resource t.path)
=/ =vase
%+ convert-to:ver update-mark.config
=/ =vase
(initial-watch:og t.t.t.t.path resource)
:_ this
[%give %fact ~ update-mark.config vase]~
?. =(min-version.config 0)
~& >>> "unversioned req from: {<src.bowl>}, nooping"
~
[%give %fact ~ (convert-to:ver update-mark.config vase)]~
--
::
++ on-agent
@ -440,10 +470,7 @@
|= [fact-ver=@ud paths=(set path)]
=/ =mark
(append-version:ver fact-ver)
=/ =^cage
:- mark
(convert-from:ver mark q.cage)
(fact:io cage ~(tap in paths))
(fact:io (convert-from:ver mark q.cage) ~(tap in paths))
:: TODO: deprecate
++ unversioned
?. =(min-version.config 0) ~
@ -453,18 +480,15 @@
%- ~(gas in *(set path))
(turn (incoming-subscriptions prefix) tail)
?: =(0 ~(wyt in unversioned)) ~
=/ =^cage
:- update-mark.config
(convert-from:ver update-mark.config q.cage)
(fact:io cage ~(tap in unversioned))^~
(fact:io (convert-from:ver update-mark.config q.cage) ~(tap in unversioned))^~
--
::
++ forward-update
|= =cage
^- (list card:agent:gall)
=- lis
=/ vas
(convert-to:ver cage)
=/ vas=vase
q:(convert-to:ver cage)
%+ roll (resource-for-update q.cage)
|= [rid=resource [lis=(list card:agent:gall) tf-vas=(unit vase)]]
^- [(list card:agent:gall) (unit vase)]

View File

@ -29,11 +29,12 @@
&((gte ver min) (lte ver version))
::
++ convert-to
|= =cage
^- vase
?: =(p.cage current-version)
q.cage
((tube-to p.cage) q.cage)
|= [=mark =vase]
^- cage
:- current-version
?: =(mark current-version)
vase
((tube-to mark) vase)
::
++ tube-to
|= =mark
@ -44,10 +45,11 @@
.^(tube:clay %cc (scry:io %home /[current-version]/[mark]))
::
++ convert-from
|= =cage
^- vase
?: =(p.cage current-version)
q.cage
((tube-from p.cage) q.cage)
|= [=mark =vase]
^- cage
:- mark
?: =(mark current-version)
vase
((tube-from mark) vase)
--

View File

@ -1,19 +1,17 @@
/+ *graph-store
=* as-octs as-octs:mimes:html
::
|_ upd=update
|_ upd=update:one
++ grad %noun
++ grow
|%
++ noun upd
++ json (update:enjs upd)
++ mime [/application/x-urb-graph-update (as-octs (jam upd))]
--
::
++ grab
|%
++ noun update
++ json update:dejs
++ noun update:one
++ mime |=([* =octs] ;;(update (cue q.octs)))
--
--

View File

@ -0,0 +1,19 @@
/+ *graph-store
=* as-octs as-octs:mimes:html
::
|_ upd=update
++ grad %noun
++ grow
|%
++ noun upd
++ json (update:enjs upd)
++ mime [/application/x-urb-graph-update (as-octs (jam upd))]
--
::
++ grab
|%
++ noun update
++ json update:dejs
++ mime |=([* =octs] ;;(update (cue q.octs)))
--
--

View File

@ -1,5 +1,61 @@
/- *post
|%
+$ graph ((mop atom node) gth)
+$ marked-graph [p=graph q=(unit mark)]
::
+$ maybe-post (each post hash)
+$ node [post=maybe-post children=internal-graph]
+$ graphs (map resource marked-graph)
::
+$ tag-queries (jug term uid)
::
+$ update-log ((mop time logged-update) gth)
+$ update-logs (map resource update-log)
::
+$ internal-graph
$~ [%empty ~]
$% [%graph p=graph]
[%empty ~]
==
::
+$ network
$: =graphs
=tag-queries
=update-logs
archive=graphs
~
==
::
+$ update [p=time q=action]
::
+$ logged-update [p=time q=logged-action]
::
+$ logged-action
$% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
[%add-nodes =resource nodes=(map index node)]
[%remove-posts =resource indices=(set index)]
[%add-signatures =uid =signatures]
[%remove-signatures =uid =signatures]
==
::
+$ action
$% logged-action
[%remove-graph =resource]
::
[%add-tag =term =uid]
[%remove-tag =term =uid]
::
[%archive-graph =resource]
[%unarchive-graph =resource]
[%run-updates =resource =update-log]
::
:: NOTE: cannot be sent as pokes
::
[%keys =resources]
[%tags tags=(set term)]
[%tag-queries =tag-queries]
==
::
+$ permissions
[admin=permission-level writer=permission-level reader=permission-level]
@ -13,11 +69,75 @@
+$ permission-level
?(%no %self %yes)
::
:: %graph-store types version 1
::
++ one
|%
++ orm ((ordered-map atom node) gth)
++ orm-log ((ordered-map time logged-update) gth)
::
+$ graph ((mop atom node) gth)
+$ marked-graph [p=graph q=(unit mark)]
::
+$ node [=post children=internal-graph]
+$ graphs (map resource marked-graph)
::
+$ tag-queries (jug term resource)
::
+$ update-log ((mop time logged-update) gth)
+$ update-logs (map resource update-log)
::
+$ internal-graph
$~ [%empty ~]
$% [%graph p=graph]
[%empty ~]
==
::
+$ network
$: =graphs
=tag-queries
=update-logs
archive=graphs
validators=(set mark)
==
::
+$ update [p=time q=action]
::
+$ logged-update [p=time q=logged-action]
::
+$ logged-action
$% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
[%add-nodes =resource nodes=(map index node)]
[%remove-nodes =resource indices=(set index)]
[%add-signatures =uid =signatures]
[%remove-signatures =uid =signatures]
==
::
+$ action
$% logged-action
[%remove-graph =resource]
::
[%add-tag =term =resource]
[%remove-tag =term =resource]
::
[%archive-graph =resource]
[%unarchive-graph =resource]
[%run-updates =resource =update-log]
::
:: NOTE: cannot be sent as pokes
::
[%keys =resources]
[%tags tags=(set term)]
[%tag-queries =tag-queries]
==
--
::
:: %graph-store types version 0
::
++ zero
=< [. post-zero]
=, post-zero
|%
::
++ orm ((ordered-map atom node) gth)
++ orm-log ((ordered-map time logged-update) gth)
::
@ -81,61 +201,4 @@
[%tag-queries =tag-queries]
==
--
+$ graph ((mop atom node) gth)
+$ marked-graph [p=graph q=(unit mark)]
::
+$ node [=post children=internal-graph]
+$ graphs (map resource marked-graph)
::
+$ tag-queries (jug term resource)
::
+$ update-log ((mop time logged-update) gth)
+$ update-logs (map resource update-log)
::
::
+$ internal-graph
$~ [%empty ~]
$% [%graph p=graph]
[%empty ~]
==
::
+$ network
$: =graphs
=tag-queries
=update-logs
archive=graphs
validators=(set mark)
==
::
+$ update [p=time q=action]
::
+$ logged-update [p=time q=logged-action]
::
+$ logged-action
$% [%add-graph =resource =graph mark=(unit mark) overwrite=?]
[%add-nodes =resource nodes=(map index node)]
[%remove-nodes =resource indices=(set index)]
[%add-signatures =uid =signatures]
[%remove-signatures =uid =signatures]
==
::
+$ action
$% logged-action
[%remove-graph =resource]
::
[%add-tag =term =resource]
[%remove-tag =term =resource]
::
[%archive-graph =resource]
[%unarchive-graph =resource]
[%run-updates =resource =update-log]
::
:: NOTE: cannot be sent as pokes
::
[%keys =resources]
[%tags tags=(set term)]
[%tag-queries =tag-queries]
==
--

View File

@ -1,27 +1,5 @@
/- *resource
|%
::
++ post-zero
|%
::
+$ content
$% [%text text=cord]
[%mention =ship]
[%url url=cord]
[%code expression=cord output=(list tank)]
[%reference =uid]
==
::
+$ post
$: author=ship
=index
time-sent=time
contents=(list content)
hash=(unit hash)
=signatures
==
--
+$ index (list atom)
+$ uid [=resource =index]
::
@ -60,4 +38,25 @@
[%code expression=cord output=(list tank)]
[%reference =reference]
==
::
++ post-zero
|%
::
+$ content
$% [%text text=cord]
[%mention =ship]
[%url url=cord]
[%code expression=cord output=(list tank)]
[%reference =uid]
==
::
+$ post
$: author=ship
=index
time-sent=time
contents=(list content)
hash=(unit hash)
=signatures
==
--
--

View File

@ -32,7 +32,7 @@
=/ hashes (nodes-to-pending-indices nodes.q.update)
;< ~ bind:m
%^ poke-our %graph-push-hook
%graph-update-1
%graph-update-2
!>(update)
(pure:m !>(`action:graph-view`[%pending-indices hashes]))
::
@ -75,7 +75,8 @@
^- [index:store node:store]
=* loop $
:- index
=* p post.node
?> ?=(%& -.post.node)
=* p p.post.node
=/ =hash:store
=- `@ux`(sham -)
:^ ?^ parent-hash
@ -85,9 +86,9 @@
time-sent.p
contents.p
%_ node
hash.post `hash
hash.p.post `hash
::
signatures.post
signatures.p.post
%- ~(gas in *signatures:store)
[(sign:sig our.bowl now.bowl hash)]~
::
@ -115,7 +116,8 @@
?: ?=([@ ~] index)
~
=/ node (got-deep:gra graph (snip `(list atom)`index))
hash.post.node
?> ?=(%& -.post.node)
hash.p.post.node
::
++ nodes-to-pending-indices
|= nodes=(map index:store node:store)
@ -124,6 +126,7 @@
%+ turn ~(tap by nodes)
|= [=index:store =node:store]
^- [hash:store index:store]
?> ?=(^ hash.post.node)
[u.hash.post.node index]
?> ?=(%& -.post.node)
?> ?=(^ hash.p.post.node)
[u.hash.p.post.node index]
--

View File

@ -39,7 +39,7 @@
==
;< ~ bind:m
%+ poke-our %graph-store
:- %graph-update-1
:- %graph-update-2
!> ^- update:graph
[now.bowl %add-graph feed-rid *graph:graph `%graph-validator-post %&]
;< ~ bind:m

View File

@ -54,7 +54,7 @@
=/ =update:graph
[now.bowl %add-graph rid.action *graph:graph mark.action overwrite]
;< ~ bind:m
(poke-our %graph-store graph-update-1+!>(update))
(poke-our %graph-store graph-update-2+!>(update))
;< ~ bind:m
(poke-our %graph-push-hook %push-hook-action !>([%add rid.action]))
::

View File

@ -36,7 +36,7 @@
^- form:m
;< =bowl:spider bind:m get-bowl:strandio
;< ~ bind:m
(poke-our %graph-store %graph-update-1 !>([now.bowl %remove-graph rid]))
(poke-our %graph-store %graph-update-2 !>([now.bowl %remove-graph rid]))
;< ~ bind:m
(poke-our %graph-push-hook %push-hook-action !>([%remove rid]))
;< ~ bind:m

View File

@ -40,7 +40,7 @@
?: ?=([~ ^] feed.config.metadatum)
;< ~ bind:m
%+ poke-our %graph-store
:- %graph-update-1
:- %graph-update-2
!> ^- update:graph
[now.bowl [%archive-graph resource.u.u.feed.config.metadatum]]
(pure:m !>(~))

View File

@ -39,7 +39,7 @@
;< ~ bind:m
(poke-our %graph-pull-hook %pull-hook-action !>([%remove rid]))
;< ~ bind:m
(poke-our %graph-store %graph-update-1 !>([now [%remove-graph rid]]))
(poke-our %graph-store %graph-update-2 !>([now [%remove-graph rid]]))
(pure:m ~)
--
::

View File

@ -17,7 +17,7 @@
;< =bowl:spider bind:m get-bowl:strandio
:: unarchive graph and share it
;< ~ bind:m
(poke-our %graph-store %graph-update-1 !>([now.bowl %unarchive-graph rid]))
(poke-our %graph-store %graph-update-2 !>([now.bowl %unarchive-graph rid]))
;< ~ bind:m
(poke-our %graph-push-hook %push-hook-action !>([%add rid]))
::

View File

@ -70,7 +70,7 @@
;< ~ bind:m
%+ raw-poke
[our.bowl %graph-store]
:- %graph-update-1
:- %graph-update-2
!> ^- update:gra
[now.bowl [%archive-graph app-resource]]
;< ~ bind:m

View File

@ -12,9 +12,9 @@
|= [our=@p wen=@da rid=resource body=cord id=@]
=/ =index:post [id]~
=/ =post:post [our index wen [%text body]~ ~ ~]
=/ =node:graph-store [post %empty ~]
=/ =node:graph-store [[%& post] %empty ~]
=/ act=update:graph-store [wen %add-nodes rid (my [index node] ~)]
(poke-app our %graph-push-hook %graph-update-1 act)
(poke-app our %graph-push-hook %graph-update-2 act)
--
::
^- thread:spider

View File

@ -12,9 +12,9 @@
|= [our=@p wen=@da rid=resource body=cord id=@]
=/ =index:post [id]~
=/ =post:post [our index wen [%text body]~ ~ ~]
=/ =node:graph-store [post %empty ~]
=/ =node:graph-store [[%& post] %empty ~]
=/ act=update:graph-store [wen %add-nodes rid (my [index node] ~)]
(poke-app our %graph-push-hook %graph-update-1 act)
(poke-app our %graph-push-hook %graph-update-2 act)
--
::
^- thread:spider

View File

@ -25,12 +25,13 @@ The first two options result in Urbit attempting to boot either the ship named b
In consequence, it is safe to remove the container and start a new container which mounts the same volume, e.g. to upgrade the version of the urbit binary by running a later container version. It is also possible to stop the container and then move the pier away e.g. to a location where you will run it directly with the Urbit binary.
### Ports
The image includes `EXPOSE` directives for TCP port 80 and UDP port 34343. Port `80` is used for Urbit's HTTP interface for both [Landscape](https://urbit.org/docs/glossary/landscape/) and for [API calls](https://urbit.org/using/integrating-api/) to the ship. Port `34343` is used by [Ames](https://urbit.org/docs/glossary/ames/) for ship-to-ship communication.
The image includes `EXPOSE` directives for TCP port 80 and UDP port 34343. Port `80` is used for Urbit's HTTP interface for both [Landscape](https://urbit.org/docs/glossary/landscape/) and for [API calls](https://urbit.org/using/integrating-api/) to the ship. Port `34343` is set by default to be used by [Ames](https://urbit.org/docs/glossary/ames/) for ship-to-ship communication.
You can either pass the `-P` flag to docker to map ports directly to the corresponding ports on the host, or map them individually with `-p` flags. For local testing the latter is often convenient, for instance to remap port 80 to an unprivileged port.
You can either pass the `-P` flag to docker to map ports directly to the corresponding ports on the host, or map them individually with `-p` flags. For local testing the latter is often convenient, for instance to remap port 80 to an unprivileged port.
You should be able to use port mapping for most purposes but you can force Ames to use a custom port.
`--port=$AMES_PORT` can be passed as an argument to the `docker start` command. Passing `--port=13436` for example, would use port 13436.
For best performance, you must map the Ames UDP port to the *same* port on the host. If you map to a different port Ames will not be able to make direct connections and your network performance may suffer somewhat. Note that using the same port is required for direct connections but is not by itself sufficient for them. If you are behind a NAT router or the host is not on a public IP address or you are firewalled, you may not achive direct connections regardless.
For this purpose you can force Ames to use a custom port. `/bin/start-urbit --port=$AMES_PORT` can be passed as an argument to the `docker start` command. Passing `/bin/start-urbit --port=13436` for example, would use port 13436. You must pass the name of the start script `/bin/start-urbit` in order to also pass arguments, if this is omitted your container will not start.
### Examples
Creating a volume for ~sampel=palnet:
@ -38,23 +39,23 @@ Creating a volume for ~sampel=palnet:
docker volume create sampel-palnet
```
Copying key to sampel-palnet's volume (assumes default docker location)
Copying key to sampel-palnet's volume (assumes default docker location):
```
sudo cp ~/sampel-palnet.key /var/lib/docker/volumes/sampel-palnet/_data/sampel-palnet.key
```
Using that volume and launching ~sampel-palnet on host port 8080 with Ames talking on host port 27000:
Using that volume and launching ~sampel-palnet on host port 8080 with Ames talking on the default host port 34343:
```
docker run -d -p 8080:80 -p 27000:34343/udp --name sampel-palnet \
docker run -d -p 8080:80 -p 34343:34343/udp --name sampel-palnet \
--mount type=volume,source=sampel-palnet,destination=/urbit \
tloncorp/urbit
```
Using host port 8088 with Ames talking on host port 23232 while forcing Ames to start internally on port 13436:
Using host port 8088 with Ames talking on host port 23232:
```
docker run -d -p 8088:80 -p 23232:13436/udp --name sampel-palnet \
docker run -d -p 8088:80 -p 23232:23232/udp --name sampel-palnet \
--mount type=volume,source=sampel-palnet,destination=/urbit \
tloncorp/urbit --port=13436
tloncorp/urbit /bin/start-urbit --port=23232
```
### Getting and resetting the Landscape +code

View File

@ -25,10 +25,10 @@ module Urbit.Arvo.Common
import Urbit.Prelude
import Control.Monad.Fail (fail)
import Data.Bits
import Data.Serialize
import qualified Network.HTTP.Types.Method as H
import qualified Network.Socket as N
import qualified Urbit.Ob as Ob
@ -159,6 +159,19 @@ deriveNoun ''JsonNode
-- Ames Destinations -------------------------------------------------
serializeToNoun :: Serialize a => a -> Noun
serializeToNoun = A . bytesAtom . encode
serializeParseNoun :: Serialize a => String -> Int -> Noun -> Parser a
serializeParseNoun desc len = named (pack desc) . \case
A (atomBytes -> bs)
-- Atoms lose leading 0s, but since lsb, these become trailing NULs
| length bs <= len -> case decode $ bs <> replicate (len - length bs) 0 of
Right aa -> pure aa
Left msg -> fail msg
| otherwise -> fail ("putative " <> desc <> " " <> show bs <> " too long")
C{} -> fail ("unexpected cell in " <> desc)
newtype Patp a = Patp { unPatp :: a }
deriving newtype (Eq, Ord, Enum, Real, Integral, Num, ToNoun, FromNoun)
@ -167,17 +180,29 @@ newtype Port = Port { unPort :: Word16 }
deriving newtype (Eq, Ord, Show, Enum, Real, Integral, Num, ToNoun, FromNoun)
-- @if
newtype Ipv4 = Ipv4 { unIpv4 :: Word32 }
deriving newtype (Eq, Ord, Enum, Real, Integral, Num, ToNoun, FromNoun)
newtype Ipv4 = Ipv4 { unIpv4 :: N.HostAddress }
deriving newtype (Eq, Ord, Enum)
instance Serialize Ipv4 where
get = (\a b c d -> Ipv4 $ N.tupleToHostAddress $ (d, c, b, a))
<$> getWord8 <*> getWord8 <*> getWord8 <*> getWord8
put (Ipv4 (N.hostAddressToTuple -> (a, b, c, d))) = for_ [d, c, b, a] putWord8
instance ToNoun Ipv4 where
toNoun = serializeToNoun
instance FromNoun Ipv4 where
parseNoun = serializeParseNoun "Ipv4" 4
instance Show Ipv4 where
show (Ipv4 i) =
show ((shiftR i 24) .&. 0xff) ++ "." ++
show ((shiftR i 16) .&. 0xff) ++ "." ++
show ((shiftR i 8) .&. 0xff) ++ "." ++
show (i .&. 0xff)
show (Ipv4 (N.hostAddressToTuple -> (a, b, c, d))) =
show a ++ "." ++
show b ++ "." ++
show c ++ "." ++
show d
-- @is
-- should probably use hostAddress6ToTuple here, but no one uses it right now
newtype Ipv6 = Ipv6 { unIpv6 :: Word128 }
deriving newtype (Eq, Ord, Show, Enum, Real, Integral, Num, ToNoun, FromNoun)
@ -190,21 +215,14 @@ data AmesAddress = AAIpv4 Ipv4 Port
deriving (Eq, Ord, Show)
instance Serialize AmesAddress where
get = AAIpv4 <$> (Ipv4 <$> getWord32le) <*> (Port <$> getWord16le)
put (AAIpv4 (Ipv4 ip) (Port port)) = putWord32le ip >> putWord16le port
get = AAIpv4 <$> get <*> (Port <$> getWord16le)
put (AAIpv4 ip (Port port)) = put ip >> putWord16le port
instance FromNoun AmesAddress where
parseNoun = named "AmesAddress" . \case
A (atomBytes -> bs)
-- Atoms lose leading 0s, but since lsb, these become trailing NULs
| length bs <= 6 -> case decode $ bs <> replicate (6 - length bs) 0 of
Right aa -> pure aa
Left msg -> fail msg
| otherwise -> fail ("putative address " <> show bs <> " too long")
C{} -> fail "unexpected cell in ames address"
parseNoun = serializeParseNoun "AmesAddress" 6
instance ToNoun AmesAddress where
toNoun = A . bytesAtom . encode
toNoun = serializeToNoun
type AmesDest = Each Galaxy AmesAddress

View File

@ -80,10 +80,6 @@ data ShipClass
muk :: ByteString -> Word20
muk bs = mugBS bs .&. (2 ^ 20 - 1)
-- XX check this
getAmesAddress :: Get AmesAddress
getAmesAddress = AAIpv4 <$> (Ipv4 <$> getWord32le) <*> (Port <$> getWord16le)
putAmesAddress :: Putter AmesAddress
putAmesAddress = \case
AAIpv4 (Ipv4 ip) (Port port) -> putWord32le ip >> putWord16le port
@ -104,7 +100,7 @@ instance Serialize Packet where
guard isAmes
pktOrigin <- if isRelayed
then Just <$> getAmesAddress
then Just <$> get
else pure Nothing
-- body
@ -157,9 +153,10 @@ instance Serialize Packet where
putWord32le head
case pktOrigin of
Just o -> putAmesAddress o
Just o -> put o
Nothing -> pure ()
putByteString body
where
putShipGetRank s@(Ship (LargeKey p q)) = case () of
_ | s < 2 ^ 16 -> (0, putWord16le $ fromIntegral s) -- lord

View File

@ -4,8 +4,12 @@
1. Opens a UDP socket and makes sure that it stays open.
- If can't open the port, wait and try again repeatedly.
- If there is an error reading or writting from the open socket,
close it and open another.
- If there is an error reading to or writing from the open socket,
close it and open another, making sure, however, to reuse the
same port
NOTE: It's not clear what, if anything, closing and reopening
the socket does. We're keeping this behavior out of conservatism
until we understand it better.
2. Receives packets from the socket.
@ -158,7 +162,7 @@ realUdpServ
-> HostAddress
-> AmesStat
-> RIO e UdpServ
realUdpServ por hos sat = do
realUdpServ startPort hos sat = do
logInfo $ displayShow ("AMES", "UDP", "Starting real UDP server.")
env <- ask
@ -202,23 +206,30 @@ realUdpServ por hos sat = do
did <- atomically (tryWriteTBQueue qSend (a, b))
when (did == False) $ do
logWarn "AMES: UDP: Dropping outbound packet because queue is full."
let opener por = do
logInfo $ displayShow $ ("AMES", "UDP", "Trying to open socket, port",)
por
sk <- forceBind por hos
sn <- io $ getSocketName sk
sp <- io $ socketPort sk
logInfo $ displayShow $ ("AMES", "UDP", "Got socket", sn, sp)
tOpen <- async $ forever $ do
sk <- forceBind por hos
sn <- io $ getSocketName sk
let waitForRelease = do
atomically (writeTVar vSock (Just sk))
broken <- atomically (takeTMVar vFail)
logWarn "AMES: UDP: Closing broken socket."
io (close broken)
let waitForRelease = do
atomically (writeTVar vSock (Just sk))
broken <- atomically (takeTMVar vFail)
logWarn "AMES: UDP: Closing broken socket."
io (close broken)
case sn of
(SockAddrInet boundPort _) ->
-- When we're on IPv4, maybe port forward at the NAT.
rwith (requestPortAccess $ fromIntegral boundPort) $
\() -> waitForRelease
_ -> waitForRelease
case sn of
(SockAddrInet boundPort _) ->
-- When we're on IPv4, maybe port forward at the NAT.
rwith (requestPortAccess $ fromIntegral boundPort) $
\() -> waitForRelease
_ -> waitForRelease
opener sp
tOpen <- async $ opener startPort
tSend <- async $ forever $ join $ atomically $ do
(adr, byt) <- readTBQueue qSend

View File

@ -37,12 +37,12 @@ textPlain = Path [(MkKnot "text"), (MkKnot "plain")]
-- | Filter for dotfiles, tempfiles and backup files.
validClaySyncPath :: FilePath -> Bool
validClaySyncPath fp = hasPeriod && notTildeFile && notDotHash && notDoubleHash
validClaySyncPath fp = hasPeriod && notTildeFile && notDotFile && notDoubleHash
where
fileName = takeFileName fp
hasPeriod = elem '.' fileName
notTildeFile = not $ "~" `isSuffixOf` fileName
notDotHash = not $ ".#" `isPrefixOf` fileName
notDotFile = not $ "." `isPrefixOf` fileName
notDoubleHash =
not $ ("#" `isPrefixOf` fileName) && ("#" `isSuffixOf` fileName)

View File

@ -1,5 +1,5 @@
name: urbit-king
version: 1.3
version: 1.5
license: MIT
license-file: LICENSE
data-files:

View File

@ -1,3 +1,3 @@
module.exports = {
extends: "@urbit"
};
extends: '@urbit'
};

File diff suppressed because it is too large Load Diff

View File

@ -8,9 +8,10 @@
"@reach/disclosure": "^0.10.5",
"@reach/menu-button": "^0.10.5",
"@reach/tabs": "^0.10.5",
"@react-spring/web": "^9.1.1",
"@tlon/indigo-dark": "^1.0.6",
"@tlon/indigo-light": "^1.0.7",
"@tlon/indigo-react": "^1.2.21",
"@tlon/indigo-react": "^1.2.22",
"@tlon/sigil-js": "^1.4.3",
"@urbit/api": "file:../npm/api",
"any-ascii": "^0.1.7",
@ -23,7 +24,6 @@
"formik": "^2.1.5",
"immer": "^8.0.1",
"lodash": "^4.17.20",
"markdown-to-jsx": "^6.11.4",
"moment": "^2.29.1",
"mousetrap": "^1.6.5",
"mousetrap-global-bind": "^1.1.0",
@ -38,15 +38,18 @@
"react-markdown": "^4.3.1",
"react-oembed-container": "^1.0.0",
"react-router-dom": "^5.2.0",
"react-use-gesture": "^9.1.3",
"react-virtuoso": "^0.20.3",
"react-visibility-sensor": "^5.1.1",
"remark": "^12.0.0",
"remark-breaks": "^2.0.1",
"remark-disable-tokenizers": "^1.0.24",
"remark-disable-tokenizers": "1.1.0",
"stacktrace-js": "^2.0.2",
"style-loader": "^1.3.0",
"styled-components": "^5.1.1",
"styled-system": "^5.1.5",
"suncalc": "^1.8.0",
"unist-util-visit": "^3.0.0",
"urbit-ob": "^5.0.1",
"workbox-core": "^6.0.2",
"workbox-precaching": "^6.0.2",

View File

@ -1,9 +1,7 @@
import './wdyr';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import './register-sw';
import App from './views/App';
import './wdyr';
ReactDOM.render(<App />, document.getElementById('root'));

View File

@ -1,5 +1,5 @@
import { Path, Patp } from '@urbit/api';
import _ from 'lodash';
import { Patp, Path } from '@urbit/api';
import BaseStore from '../store/base';
export default class BaseApi<S extends object = {}> {

View File

@ -1,7 +1,8 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Patp } from '@urbit/api';
import { ContactEdit } from '@urbit/api/contacts';
import { ContactEditField } from '@urbit/api/contacts';
import _ from 'lodash';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class ContactsApi extends BaseApi<StoreState> {
add(ship: Patp, contact: any) {
@ -13,7 +14,7 @@ export default class ContactsApi extends BaseApi<StoreState> {
return this.storeAction({ remove: { ship } });
}
edit(ship: Patp, editField: ContactEdit) {
edit(ship: Patp, editField: ContactEditField) {
/* editField can be...
{nickname: ''}
{email: ''}
@ -73,6 +74,28 @@ export default class ContactsApi extends BaseApi<StoreState> {
);
}
async disallowedShipsForOurContact(ships: string[]): Promise<string[]> {
return _.compact(
await Promise.all(
ships.map(
async (s) => {
const ship = `~${s}`;
if(s === window.ship) {
return null;
}
const allowed = await this.fetchIsAllowed(
`~${window.ship}`,
'personal',
ship,
true
);
return allowed ? null : ship;
}
)
)
);
}
retrieve(ship: string) {
const resource = { ship, name: '' };
return this.action('contact-pull-hook', 'pull-hook-action', {

View File

@ -1,7 +1,5 @@
import type { StoreState } from '../store/type';
import BaseApi from './base';
import type {StoreState} from '../store/type';
import type {GcpToken} from '../../types/gcp-state';
export default class GcpApi extends BaseApi<StoreState> {
// Does not touch the store; use the value manually.
@ -18,4 +16,4 @@ export default class GcpApi extends BaseApi<StoreState> {
});
});
}
};
}

View File

@ -1,17 +1,17 @@
import { Patp } from '@urbit/api';
import BaseApi from './base';
import { StoreState } from '../store/type';
import GlobalStore from '../store/store';
import LocalApi from './local';
import InviteApi from './invite';
import MetadataApi from './metadata';
import { StoreState } from '../store/type';
import BaseApi from './base';
import ContactsApi from './contacts';
import GroupsApi from './groups';
import LaunchApi from './launch';
import GraphApi from './graph';
import S3Api from './s3';
import GcpApi from './gcp';
import GraphApi from './graph';
import GroupsApi from './groups';
import { HarkApi } from './hark';
import InviteApi from './invite';
import LaunchApi from './launch';
import LocalApi from './local';
import MetadataApi from './metadata';
import S3Api from './s3';
import SettingsApi from './settings';
export default class GlobalApi extends BaseApi<StoreState> {

View File

@ -1,10 +1,9 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Patp, Path, Resource } from '@urbit/api';
import { Content, Enc, GraphNode, GroupPolicy, Path, Patp, Post, Resource } from '@urbit/api';
import _ from 'lodash';
import { decToUd, deSig, resourceAsPath, unixToDa } from '~/logic/lib/util';
import { makeResource, resourceFromPath } from '../lib/group';
import { GroupPolicy, Enc, Post, Content } from '@urbit/api';
import { numToUd, unixToDa, decToUd, deSig, resourceAsPath } from '~/logic/lib/util';
import { StoreState } from '../store/type';
import BaseApi from './base';
export const createBlankNodeWithChildPost = (
parentIndex = '',
@ -83,7 +82,7 @@ export default class GraphApi extends BaseApi<StoreState> {
joiningGraphs = new Set<string>();
private storeAction(action: any): Promise<any> {
return this.action('graph-store', 'graph-update-1', action);
return this.action('graph-store', 'graph-update-2', action);
}
private viewAction(threadName: string, action: any) {
@ -91,7 +90,7 @@ export default class GraphApi extends BaseApi<StoreState> {
}
private hookAction(ship: Patp, action: any): Promise<any> {
return this.action('graph-push-hook', 'graph-update-1', action);
return this.action('graph-push-hook', 'graph-update-2', action);
}
createManagedGraph(
@ -185,13 +184,12 @@ export default class GraphApi extends BaseApi<StoreState> {
});
}
eval(cord: string) {
eval(cord: string): Promise<string[] | undefined> {
return this.spider('graph-view-action', 'tang', 'graph-eval', {
eval: cord
});
}
addGraph(ship: Patp, name: string, graph: any, mark: any) {
return this.storeAction({
'add-graph': {
@ -211,7 +209,7 @@ export default class GraphApi extends BaseApi<StoreState> {
return this.addNodes(ship, name, nodes);
}
addNode(ship: Patp, name: string, node: Object) {
addNode(ship: Patp, name: string, node: GraphNode) {
const nodes = {};
nodes[node.post.index] = node;
@ -227,7 +225,7 @@ export default class GraphApi extends BaseApi<StoreState> {
};
const pendingPromise = this.spider(
'graph-update-1',
'graph-update-2',
'graph-view-action',
'graph-add-nodes',
action
@ -265,7 +263,7 @@ export default class GraphApi extends BaseApi<StoreState> {
'resource',
'graph-create-group-feed',
{
"create-group-feed": { resource: group, vip }
'create-group-feed': { resource: group, vip }
}
);
return resource;
@ -277,15 +275,14 @@ export default class GraphApi extends BaseApi<StoreState> {
'json',
'graph-disable-group-feed',
{
"disable-group-feed": { resource: group }
'disable-group-feed': { resource: group }
}
);
}
removeNodes(ship: Patp, name: string, indices: string[]) {
removePosts(ship: Patp, name: string, indices: string[]) {
return this.hookAction(ship, {
'remove-nodes': {
'remove-posts': {
resource: { ship, name },
indices
}
@ -369,7 +366,7 @@ export default class GraphApi extends BaseApi<StoreState> {
const node = data['graph-update'];
this.store.handleEvent({
data: {
"graph-update-loose": node
'graph-update-loose': node
}
});
}

View File

@ -1,14 +1,14 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Path, Patp, Enc } from '@urbit/api';
import { Enc, Patp } from '@urbit/api';
import {
GroupAction,
GroupPolicy,
Resource,
Tag,
GroupPolicyDiff
GroupPolicyDiff, Resource,
Tag
} from '@urbit/api/groups';
import { makeResource } from '../lib/group';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class GroupsApi extends BaseApi<StoreState> {
remove(resource: Resource, ships: Patp[]) {

View File

@ -1,10 +1,10 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { dateToDa, decToUd } from '../lib/util';
import { NotifIndex, IndexedNotification, Association, GraphNotifDescription } from '@urbit/api';
import { Association, GraphNotifDescription, IndexedNotification, NotifIndex } from '@urbit/api';
import { BigInteger } from 'big-integer';
import { getParentIndex } from '../lib/notification';
import { dateToDa, decToUd } from '../lib/util';
import useHarkState from '../state/hark';
import { StoreState } from '../store/type';
import BaseApi from './base';
function getHarkSize() {
return useHarkState.getState().notifications.size ?? 0;
@ -75,7 +75,6 @@ export class HarkApi extends BaseApi<StoreState> {
graph: {
graph: association.resource,
group: association.group,
module: association.metadata.module,
description,
index: parent
} }

View File

@ -1,6 +1,6 @@
import BaseApi from './base';
import { Serial } from '@urbit/api';
import { StoreState } from '../store/type';
import { Serial, Path } from '@urbit/api';
import BaseApi from './base';
export default class InviteApi extends BaseApi<StoreState> {
accept(app: string, uid: Serial) {

View File

@ -1,5 +1,5 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class LaunchApi extends BaseApi<StoreState> {
add(name: string, tile = { basic : { title: '', linkedUrl: '', iconUrl: '' } }) {

View File

@ -1,5 +1,5 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class LocalApi extends BaseApi<StoreState> {
getBaseHash() {
@ -7,8 +7,4 @@ export default class LocalApi extends BaseApi<StoreState> {
this.store.handleEvent({ data: { baseHash } });
});
}
dehydrate() {
this.store.dehydrate();
}
}

View File

@ -1,8 +1,8 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Path, Patp, Association, Metadata, MetadataUpdatePreview } from '@urbit/api';
import { Association, Metadata, MetadataUpdatePreview, Path } from '@urbit/api';
import { uxToHex } from '../lib/util';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class MetadataApi extends BaseApi<StoreState> {
metadataAdd(appName: string, resource: Path, group: Path, title: string, description: string, dateCreated: string, color: string, moduleName: string) {

View File

@ -1,6 +1,5 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { S3Update } from '../../types/s3-update';
import BaseApi from './base';
export default class S3Api extends BaseApi<StoreState> {
setCurrentBucket(bucket: string) {

View File

@ -1,12 +1,13 @@
import BaseApi from './base';
import { StoreState } from '../store/type';
import { Key,
Value,
Bucket
import {
Bucket, Key,
SettingsUpdate, Value
} from '@urbit/api/settings';
import { StoreState } from '../store/type';
import BaseApi from './base';
export default class SettingsApi extends BaseApi<StoreState> {
private storeAction(action: SettingsEvent): Promise<any> {
private storeAction(action: SettingsUpdate): Promise<any> {
return this.action('settings-store', 'settings-event', action);
}
@ -47,14 +48,14 @@ export default class SettingsApi extends BaseApi<StoreState> {
}
async getAll() {
const { all } = await this.scry("settings-store", "/all");
this.store.handleEvent({data:
{"settings-data": { all } }
const { all } = await this.scry('settings-store', '/all');
this.store.handleEvent({ data:
{ 'settings-data': { all } }
});
}
async getBucket(bucket: Key) {
const data = await this.scry('settings-store', `/bucket/${bucket}`);
const data: Record<string, unknown> = await this.scry('settings-store', `/bucket/${bucket}`);
this.store.handleEvent({ data: { 'settings-data': {
'bucket-key': bucket,
'bucket': data.bucket
@ -62,7 +63,7 @@ export default class SettingsApi extends BaseApi<StoreState> {
}
async getEntry(bucket: Key, entry: Key) {
const data = await this.scry('settings-store', `/entry/${bucket}/${entry}`);
const data: Record<string, unknown> = await this.scry('settings-store', `/entry/${bucket}/${entry}`);
this.store.handleEvent({ data: { 'settings-data': {
'bucket-key': bucket,
'entry-key': entry,

View File

@ -7,14 +7,12 @@
//
import querystring from 'querystring';
import {
StorageAcl,
StorageClient,
StorageUpload,
UploadParams,
UploadResult
} from './StorageClient';
const ENDPOINT = 'storage.googleapis.com';
class GcpUpload implements StorageUpload {
@ -27,7 +25,7 @@ class GcpUpload implements StorageUpload {
}
async promise(): Promise<UploadResult> {
const {Bucket, Key, ContentType, Body} = this.#params;
const { Bucket, Key, ContentType, Body } = this.#params;
const urlParams = {
uploadType: 'media',
name: Key,
@ -50,7 +48,7 @@ class GcpUpload implements StorageUpload {
console.error('GcpClient server error', await response.json());
throw new Error(`GcpClient: response ${response.status}`);
}
return {Location: `https://${ENDPOINT}/${Bucket}/${Key}`};
return { Location: `https://${ENDPOINT}/${Bucket}/${Key}` };
}
}

View File

@ -1,14 +1,13 @@
// Defines a StorageClient interface interoperable between S3 and GCP Storage.
//
// XX kind of gross. S3 needs 'public-read', GCP needs 'publicRead'.
// Rather than write a wrapper around S3, we offer this field here, which
// should always be passed, and will be replaced by 'publicRead' in the
// GCP client.
export enum StorageAcl {
PublicRead = 'public-read'
};
}
export interface UploadParams {
Bucket: string; // the bucket to upload the object to
@ -16,17 +15,17 @@ export interface UploadParams {
ContentType: string; // the object's mime-type
ACL: StorageAcl; // ACL, always 'public-read'
Body: File; // the object itself
};
}
export interface UploadResult {
Location: string;
};
}
// Extra layer of indirection used by S3 client.
export interface StorageUpload {
promise(): Promise<UploadResult>;
};
}
export interface StorageClient {
upload(params: UploadParams): StorageUpload;
};
}

View File

@ -1,4 +1,4 @@
import bigInt, { BigInteger } from 'big-integer';
import { BigInteger } from 'big-integer';
export function max(a: BigInteger, b: BigInteger) {
return a.gt(b) ? a : b;

View File

@ -1,4 +1,4 @@
import React from "react";
import React from 'react';
export type SubmitHandler = () => Promise<any>;
interface IFormGroupContext {
@ -12,7 +12,7 @@ const fallback: IFormGroupContext = {
addSubmit: () => {},
onDirty: () => {},
onErrors: () => {},
submitAll: () => Promise.resolve(),
submitAll: () => Promise.resolve()
};
export const FormGroupContext = React.createContext(fallback);

View File

@ -15,7 +15,6 @@
import GlobalApi from '../api/global';
import useStorageState from '../state/storage';
class GcpManager {
#api: GlobalApi | null = null;
@ -59,15 +58,15 @@ class GcpManager {
this.start();
}
#consecutiveFailures: number = 0;
#configured: boolean = false;
#consecutiveFailures = 0;
#configured = false;
private refreshLoop() {
if (!this.#configured) {
this.#api!.gcp.isConfigured()
.then((configured) => {
if (configured === undefined) {
throw new Error("can't check whether GCP is configured?");
throw new Error('can\'t check whether GCP is configured?');
}
this.#configured = configured;
if (this.#configured) {

View File

@ -1,7 +1,6 @@
import { Path, PatpNoSig } from '@urbit/api';
import { Group, Resource, roleTags, RoleTags } from '@urbit/api/groups';
import _ from 'lodash';
import { roleTags, RoleTags, Group, Resource } from '@urbit/api/groups';
import { PatpNoSig, Path } from '@urbit/api';
import { deSig } from './util';
export function roleForShip(
group: Group,

View File

@ -1,6 +1,6 @@
import { IndexedNotification, NotificationGraphConfig, Unreads } from '@urbit/api';
import bigInt, { BigInteger } from 'big-integer';
import f from 'lodash/fp';
import { Unreads, NotificationGraphConfig } from '@urbit/api';
export function getLastSeen(
unreads: Unreads,
@ -36,11 +36,24 @@ export function getNotificationCount(
}
export function isWatching(
config: NotificationGraphConfig,
config: NotificationGraphConfig,
graph: string,
index = "/"
index = '/'
) {
return !!config.watching.find(
return Boolean(config.watching.find(
watch => watch.graph === graph && watch.index === index
);
));
}
export function getNotificationKey(time: BigInteger, notification: IndexedNotification): string {
const base = time.toString();
if('graph' in notification.index) {
const { graph, index } = notification.index.graph;
return `${base}-${graph}-${index}`;
} else if('group' in notification.index) {
const { group } = notification.index.group;
return `${base}-${group}`;
}
return `${base}-unknown`;
}

View File

@ -1,9 +1,9 @@
import { useState, useEffect } from 'react';
import { useEffect, useState } from 'react';
export function useIdlingState() {
const [idling, setIdling] = useState(false);
useEffect(() => {
useEffect(() => {
function blur() {
setIdling(true);
}
@ -16,7 +16,7 @@ export function useIdlingState() {
return () => {
window.removeEventListener('blur', blur);
window.removeEventListener('focus', focus);
}
};
}, []);
return idling;

View File

@ -1,15 +1,15 @@
import useLocalState, { LocalState } from "~/logic/state/local";
import useSettingsState from "~/logic/state/settings";
import GlobalApi from "../api/global";
import { BackgroundConfig, RemoteContentPolicy } from "~/types";
import useLocalState from '~/logic/state/local';
import useSettingsState from '~/logic/state/settings';
import { BackgroundConfig, RemoteContentPolicy } from '~/types';
import GlobalApi from '../api/global';
const getBackgroundString = (bg: BackgroundConfig) => {
if (bg?.type === "url") {
if (bg?.type === 'url') {
return bg.url;
} else if (bg?.type === "color") {
} else if (bg?.type === 'color') {
return bg.color;
} else {
return "";
return '';
}
};
@ -18,17 +18,17 @@ export function useMigrateSettings(api: GlobalApi) {
const { display, remoteContentPolicy, calm } = useSettingsState();
return async () => {
let promises: Promise<any>[] = [];
const promises: Promise<any>[] = [];
if (local.hideAvatars !== calm.hideAvatars) {
promises.push(
api.settings.putEntry("calm", "hideAvatars", local.hideAvatars)
api.settings.putEntry('calm', 'hideAvatars', local.hideAvatars)
);
}
if (local.hideNicknames !== calm.hideNicknames) {
promises.push(
api.settings.putEntry("calm", "hideNicknames", local.hideNicknames)
api.settings.putEntry('calm', 'hideNicknames', local.hideNicknames)
);
}
@ -38,15 +38,15 @@ export function useMigrateSettings(api: GlobalApi) {
) {
promises.push(
api.settings.putEntry(
"display",
"background",
'display',
'background',
getBackgroundString(local.background)
)
);
promises.push(
api.settings.putEntry(
"display",
"backgroundType",
'display',
'backgroundType',
local.background?.type
)
);
@ -57,12 +57,12 @@ export function useMigrateSettings(api: GlobalApi) {
const localVal = local.remoteContentPolicy[key];
if (localVal !== remoteContentPolicy[key]) {
promises.push(
api.settings.putEntry("remoteContentPolicy", key, localVal)
api.settings.putEntry('remoteContentPolicy', key, localVal)
);
}
});
await Promise.all(promises);
localStorage.removeItem("localReducer");
localStorage.removeItem('localReducer');
};
}

View File

@ -1,4 +1,4 @@
import { GraphNotifIndex, GraphNotificationContents } from '@urbit/api';
import { GraphNotificationContents, GraphNotifIndex } from '@urbit/api';
export function getParentIndex(
idx: GraphNotifIndex,

View File

@ -1,5 +1,5 @@
import { cite } from '~/logic/lib/util';
import { isChannelAdmin } from '~/logic/lib/group';
import { cite } from '~/logic/lib/util';
const makeIndexes = () => new Map([
['ships', []],
@ -23,7 +23,7 @@ const result = function(title, link, app, host) {
const shipIndex = function(contacts) {
const ships = [];
Object.keys(contacts).map((e) => {
return ships.push(result(e, `/~profile/${e}`, 'profile', contacts[e]?.status || ""));
return ships.push(result(e, `/~profile/${e}`, 'profile', contacts[e]?.status || ''));
});
return ships;
};
@ -38,11 +38,11 @@ const commandIndex = function (currentGroup, groups, associations) {
? (association.metadata.vip === 'member-metadata' || isChannelAdmin(group, currentGroup))
: !currentGroup; // home workspace or hasn't loaded
const workspace = currentGroup || '/home';
commands.push(result(`Groups: Create`, `/~landscape/new`, 'Groups', null));
commands.push(result('Groups: Create', '/~landscape/new', 'Groups', null));
if (canAdd) {
commands.push(result(`Channel: Create`, `/~landscape${workspace}/new`, 'Groups', null));
commands.push(result('Channel: Create', `/~landscape${workspace}/new`, 'Groups', null));
}
commands.push(result(`Groups: Join`, `/~landscape/join`, 'Groups', null));
commands.push(result('Groups: Join', '/~landscape/join', 'Groups', null));
return commands;
};
@ -80,7 +80,7 @@ const otherIndex = function(config) {
logout: result('Log Out', '/~/logout', 'logout', null)
};
other.push(result('Tutorial', '/?tutorial=true', 'tutorial', null));
for(let cat of config.categories) {
for(const cat of config.categories) {
if(idx[cat]) {
other.push(idx[cat]);
}
@ -102,7 +102,7 @@ export default function index(contacts, associations, apps, currentGroup, groups
}).map((e) => {
// iterate through each app's metadata object
Object.keys(associations[e])
.filter((association) => !associations?.[e]?.[association]?.metadata?.hidden)
.filter(association => !associations?.[e]?.[association]?.metadata?.hidden)
.map((association) => {
const each = associations[e][association];
let title = each.resource;

View File

@ -1,15 +1,12 @@
import {
Association,
resourceFromPath,
Group,
ReferenceContent,
} from "@urbit/api";
ReferenceContent, resourceFromPath
} from '@urbit/api';
export function getPermalinkForGraph(
group: string,
graph: string,
index = ""
index = ''
) {
const groupLink = getPermalinkForAssociatedGroup(group);
const { ship, name } = resourceFromPath(graph);
@ -21,16 +18,15 @@ function getPermalinkForAssociatedGroup(group: string) {
return `web+urbitgraph://group/${ship}/${name}`;
}
type Permalink = GraphPermalink | GroupPermalink;
interface GroupPermalink {
type: "group";
type: 'group';
group: string;
link: string;
}
interface GraphPermalink {
type: "graph";
export interface GraphPermalink {
type: 'graph';
link: string;
graph: string;
group: string;
@ -43,16 +39,16 @@ function parseGraphPermalink(
segments: string[]
): GraphPermalink | null {
const [kind, ship, name, ...index] = segments;
if (kind !== "graph") {
if (kind !== 'graph') {
return null;
}
const graph = `/ship/${ship}/${name}`;
return {
type: "graph",
type: 'graph',
link: link.slice(16),
graph,
group,
index: `/${index.join("/")}`,
index: `/${index.join('/')}`
};
}
@ -64,7 +60,7 @@ export function permalinkToReference(link: Permalink): ReferenceContent {
group: link.group,
index: link.index
}
}
};
return { reference };
} else {
const reference = {
@ -89,22 +85,22 @@ export function referenceToPermalink({ reference }: ReferenceContent): Permalink
type: 'group',
link,
...reference
}
};
}
}
export function parsePermalink(url: string): Permalink | null {
const [kind, ...rest] = url.slice(17).split("/");
if (kind === "group") {
const [kind, ...rest] = url.slice(17).split('/');
if (kind === 'group') {
const [ship, name, ...graph] = rest;
const group = `/ship/${ship}/${name}`;
if (graph.length > 0) {
return parseGraphPermalink(url, group, graph);
}
return {
type: "group",
type: 'group',
group,
link: url.slice(11),
link: url.slice(11)
};
}
return null;

View File

@ -1,7 +1,7 @@
const ua = window.navigator.userAgent;
export const IS_IOS = ua.includes('iPhone');
export const IS_IOS = ua.includes('iPhone') || ua.includes('iPad');
export const IS_SAFARI = ua.includes('Safari') && !ua.includes('Chrome');

View File

@ -1,4 +1,4 @@
import { Post, GraphNode } from '@urbit/api';
import { GraphNode, Post } from '@urbit/api';
export const buntPost = (): Post => ({
author: '',

View File

@ -1,8 +1,9 @@
import { Post, GraphNode, TextContent } from '@urbit/api';
import { Content, GraphNode, Post, TextContent } from '@urbit/api';
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import bigInt, { BigInteger } from 'big-integer';
import { buntPost } from '~/logic/lib/post';
import { unixToDa } from '~/logic/lib/util';
import BigIntOrderedMap from "@urbit/api/lib/BigIntOrderedMap";
import bigInt, { BigInteger } from 'big-integer';
import tokenizeMessage from './tokenizeMessage';
export function newPost(
title: string,
@ -19,13 +20,15 @@ export function newPost(
signatures: []
};
const tokenisedBody = tokenizeMessage(body);
const revContainer: Post = { ...root, index: root.index + '/1' };
const commentsContainer = { ...root, index: root.index + '/2' };
const firstRevision: Post = {
...revContainer,
index: revContainer.index + '/1',
contents: [{ text: title }, { text: body }]
contents: [{ text: title }, ...tokenisedBody]
};
const nodes = {
@ -54,11 +57,12 @@ export function newPost(
export function editPost(rev: number, noteId: BigInteger, title: string, body: string) {
const now = Date.now();
const tokenisedBody = tokenizeMessage(body);
const newRev: Post = {
author: `~${window.ship}`,
index: `/${noteId.toString()}/1/${rev}`,
'time-sent': now,
contents: [{ text: title }, { text: body }],
contents: [{ text: title }, ...tokenisedBody],
hash: null,
signatures: []
};
@ -73,8 +77,8 @@ export function editPost(rev: number, noteId: BigInteger, title: string, body: s
}
export function getLatestRevision(node: GraphNode): [number, string, string, Post] {
const revs = node.children?.get(bigInt(1));
const empty = [1, '', '', buntPost()] as [number, string, string, Post];
const revs = node.children?.get(bigInt(1));
if(!revs) {
return empty;
}
@ -85,8 +89,9 @@ export function getLatestRevision(node: GraphNode): [number, string, string, Pos
if (!rev) {
return empty;
}
const [title, body] = rev.post.contents as TextContent[];
return [revNum.toJSNumber(), title.text, body.text, rev.post];
const title = rev.post.contents[0];
const body = rev.post.contents.slice(1);
return [revNum.toJSNumber(), title.text, body, rev.post];
}
export function getLatestCommentRevision(node: GraphNode): [number, Post] {
@ -113,10 +118,12 @@ export function getComments(node: GraphNode): GraphNode {
return comments;
}
export function getSnippet(body: string) {
const newlineIdx = body.indexOf('\n', 2);
const end = newlineIdx > -1 ? newlineIdx : body.length;
const start = body.substr(0, end);
export function getSnippet(body: Content[]) {
const firstContent = body
.filter((c: Content): c is TextContent => 'text' in c).map(c => c.text)[0] ?? '';
const newlineIdx = firstContent.indexOf('\n', 2);
const end = newlineIdx > -1 ? newlineIdx : firstContent.length;
const start = firstContent.substr(0, end);
return (start === body || start.startsWith('![')) ? start : `${start}...`;
return (start === firstContent || firstContent.startsWith('![')) ? start : `${start}...`;
}

View File

@ -1,6 +1,6 @@
import React, { memo } from 'react';
import { sigil, reactRenderer } from '@tlon/sigil-js';
import { Box } from '@tlon/indigo-react';
import { reactRenderer, sigil } from '@tlon/sigil-js';
import React, { memo } from 'react';
export const foregroundFromBackground = (background) => {
const rgb = {

View File

@ -1,31 +1,43 @@
import urbitOb from 'urbit-ob';
import { parsePermalink, permalinkToReference } from "~/logic/lib/permalinks";
import { parsePermalink, permalinkToReference } from '~/logic/lib/permalinks';
const URL_REGEX = new RegExp(String(/^(([\w\-\+]+:\/\/)[-a-zA-Z0-9:@;?&=\/%\+\.\*!'\(\),\$_\{\}\^~\[\]`#|]+\w)/.source));
const GROUP_REGEX = new RegExp(String(/^~[-a-z_]+\/[-a-z]+/.source));
const isUrl = (string) => {
try {
return URL_REGEX.test(string);
} catch (e) {
return false;
}
}
};
const isRef = (str) => {
return isUrl(str) && str.startsWith("web+urbitgraph://");
return isUrl(str) && str.startsWith('web+urbitgraph://');
};
const isGroup = str => {
try {
return GROUP_REGEX.test(str);
} catch (e) {
return false;
}
}
const convertToGroupRef = (group) => `web+urbitgraph://group/${group}`;
const tokenizeMessage = (text) => {
let messages = [];
let message = [];
// by line
let currTextBlock = [];
let isInCodeBlock = false;
let endOfCodeBlock = false;
text.split(/\r?\n/).forEach((line, index) => {
if (index !== 0) {
message.push('\n');
}
// by space
let currTextLine = [];
// A line of backticks enters and exits a codeblock
if (line.startsWith('```')) {
if (line.trim().startsWith('```')) {
// But we need to check if we've ended a codeblock
endOfCodeBlock = isInCodeBlock;
isInCodeBlock = (!isInCodeBlock);
@ -34,9 +46,13 @@ const tokenizeMessage = (text) => {
}
if (isInCodeBlock || endOfCodeBlock) {
message.push(line);
currTextLine = [line];
} else {
line.split(/\s/).forEach((str) => {
const words = line.split(/\s/);
words.forEach((word, idx) => {
const str = isGroup(word) ? convertToGroupRef(word) : word;
const last = words.length - 1 === idx;
if (
(str.startsWith('`') && str !== '`')
|| (str === '`' && !isInCodeBlock)
@ -50,9 +66,12 @@ const tokenizeMessage = (text) => {
}
if(isRef(str) && !isInCodeBlock) {
if (message.length > 0) {
if (currTextLine.length > 0 || currTextBlock.length > 0) {
// If we're in the middle of a message, add it to the stack and reset
messages.push({ text: message.join(' ') });
currTextLine.push('');
messages.push({ text: currTextBlock.join('\n') + currTextLine.join(' ') });
currTextBlock = last ? [''] : [];
currTextLine = [];
}
const link = parsePermalink(str);
if(!link) {
@ -61,34 +80,39 @@ const tokenizeMessage = (text) => {
const reference = permalinkToReference(link);
messages.push(reference);
}
message = [];
currTextLine = [];
} else if (isUrl(str) && !isInCodeBlock) {
if (message.length > 0) {
if (currTextLine.length > 0 || currTextBlock.length > 0) {
// If we're in the middle of a message, add it to the stack and reset
messages.push({ text: message.join(' ') });
message = [];
currTextLine.push('');
messages.push({ text: currTextBlock.join('\n') + currTextLine.join(' ') });
currTextBlock = last ? [''] : [];
currTextLine = [];
}
messages.push({ url: str });
message = [];
currTextLine = [];
} else if(urbitOb.isValidPatp(str) && !isInCodeBlock) {
if (message.length > 0) {
if (currTextLine.length > 0 || currTextBlock.length > 0) {
// If we're in the middle of a message, add it to the stack and reset
messages.push({ text: message.join(' ') });
message = [];
currTextLine.push('');
messages.push({ text: currTextBlock.join('\n') + currTextLine.join(' ') });
currTextBlock = last ? [''] : [];
currTextLine = [];
}
messages.push({ mention: str });
message = [];
currTextLine = [];
} else {
message.push(str);
currTextLine.push(str);
}
});
}
currTextBlock.push(currTextLine.join(' '))
});
if (message.length) {
if (currTextBlock.length) {
// Add any remaining message
messages.push({ text: message.join(' ') });
messages.push({ text: currTextBlock.join('\n') });
}
return messages;
};

View File

@ -1,6 +1,6 @@
import { Associations } from '@urbit/api';
import { TutorialProgress } from '~/types';
import { AlignX, AlignY } from '~/logic/lib/relativePosition';
import { TutorialProgress } from '~/types';
import { Direction } from '~/views/components/Triangle';
export const MODAL_WIDTH = 256;
@ -92,7 +92,7 @@ export const progressDetails: Record<TutorialProgress, StepDetail> = {
alignY: 'top',
arrow: 'East',
offsetX: MODAL_WIDTH + 24,
offsetY: 80,
offsetY: 80
},
channels: {
title: 'Channels',
@ -157,17 +157,17 @@ export const progressDetails: Record<TutorialProgress, StepDetail> = {
alignX: 'right',
arrow: 'South',
offsetX: -300 + MODAL_WIDTH / 2,
offsetY: -4,
offsetY: -4
},
leap: {
title: 'Leap',
description:
'Leap allows you to go to a specific channel, message, collection, profile or group simply by typing in a command or selecting a shortcut from the dropdown menu.',
url: `/~profile/~${window.ship}`,
alignY: "top",
alignX: "left",
arrow: "North",
alignY: 'top',
alignX: 'left',
arrow: 'North',
offsetX: 76,
offsetY: -48,
},
offsetY: -48
}
};

View File

@ -1,7 +1,7 @@
import { writeText } from "./util";
import { useCallback, useState, useMemo } from "react";
import { useCallback, useMemo, useState } from 'react';
import { writeText } from './util';
export function useCopy(copied: string, display: string) {
export function useCopy(copied: string, display?: string) {
const [didCopy, setDidCopy] = useState(false);
const doCopy = useCallback(() => {
writeText(copied);
@ -11,9 +11,9 @@ export function useCopy(copied: string, display: string) {
}, 2000);
}, [copied]);
const copyDisplay = useMemo(() => (didCopy ? "Copied" : display), [
const copyDisplay = useMemo(() => (didCopy ? 'Copied' : display), [
didCopy,
display,
display
]);
return { copyDisplay, doCopy, didCopy };

View File

@ -1,4 +1,4 @@
import { useState, useCallback, useMemo, useEffect } from 'react';
import { useCallback, useEffect, useState } from 'react';
function validateDragEvent(e: DragEvent): FileList | File[] | true | null {
const files: File[] = [];

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useMemo, useCallback } from 'react';
import { useCallback, useState } from 'react';
export function useDropdown<C>(
candidates: C[],

View File

@ -1,5 +1,5 @@
import { useEffect, RefObject, useRef, useState } from 'react';
import _ from 'lodash';
import { RefObject, useEffect, useState } from 'react';
import usePreviousValue from './usePreviousValue';
export function distanceToBottom(el: HTMLElement) {

View File

@ -1,4 +1,4 @@
import { useState, useCallback, useEffect } from 'react';
import { useCallback, useEffect, useState } from 'react';
function retrieve<T>(key: string, initial: T): T {
const s = localStorage.getItem(key);

View File

@ -1,15 +1,13 @@
import { Box } from '@tlon/indigo-react';
import React, {
useState,
ReactNode,
useCallback,
useMemo,
useRef
useRef, useState
} from 'react';
import { Box } from '@tlon/indigo-react';
import { PropFunc } from '~/types';
import { ModalOverlay } from '~/views/components/ModalOverlay';
import { Portal } from '~/views/components/Portal';
import { PropFunc } from '~/types';
type ModalFunc = (dismiss: () => void) => JSX.Element;
interface UseModalProps {

View File

@ -1,4 +1,4 @@
import { useEffect, RefObject } from 'react';
import { RefObject, useEffect } from 'react';
export function useOutsideClick(
ref: RefObject<HTMLElement | null | undefined>,

View File

@ -1,6 +1,6 @@
import { useMemo, useCallback } from "react";
import { useLocation } from "react-router-dom";
import _ from "lodash";
import _ from 'lodash';
import { useCallback, useMemo } from 'react';
import { useLocation } from 'react-router-dom';
function mergeQuery(search: URLSearchParams, added: Record<string, string>) {
_.forIn(added, (v, k) => {
@ -32,7 +32,7 @@ export function useQuery() {
mergeQuery(q, params);
return {
pathname: path,
search: q.toString(),
search: q.toString()
};
},
[search, pathname]
@ -41,6 +41,6 @@ export function useQuery() {
return {
query,
appendQuery,
toQuery,
toQuery
};
}

View File

@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import {unstable_batchedUpdates} from "react-dom";
import { useEffect, useState } from 'react';
import { unstable_batchedUpdates } from 'react-dom';
export type IOInstance<I, P, O> = (
input: I
@ -29,7 +29,7 @@ export function useRunIO<I, O>(
});
useEffect(() => {
reject(new Error("useRunIO: key changed"));
reject(new Error('useRunIO: key changed'));
setDone(false);
setOutput(null);
}, [key]);

View File

@ -1,4 +1,4 @@
import { MouseEvent, useCallback, useState, useEffect } from 'react';
import { MouseEvent, useCallback, useEffect, useState } from 'react';
export type AsyncClickableState = 'waiting' | 'error' | 'loading' | 'success';
export function useStatelessAsyncClickable(

View File

@ -1,22 +1,16 @@
import { useCallback, useMemo, useEffect, useRef, useState } from 'react';
import {
GcpState,
S3State,
StorageState
} from '../../types';
import S3 from 'aws-sdk/clients/s3';
import GcpClient from './GcpClient';
import { StorageClient, StorageAcl } from './StorageClient';
import { dateToDa, deSig } from './util';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import useStorageState from '../state/storage';
import GcpClient from './GcpClient';
import { StorageAcl, StorageClient } from './StorageClient';
import { dateToDa, deSig } from './util';
export interface IuseStorage {
canUpload: boolean;
upload: (file: File, bucket: string) => Promise<string>;
uploadDefault: (file: File) => Promise<string>;
uploading: boolean;
promptUpload: () => Promise<unknown>;
promptUpload: () => Promise<string>;
}
const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
@ -54,7 +48,7 @@ const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
);
const upload = useCallback(
async (file: File, bucket: string) => {
async (file: File, bucket: string): Promise<string> => {
if (client.current === null) {
throw new Error('Storage not ready');
}
@ -83,7 +77,7 @@ const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
[client, setUploading]
);
const uploadDefault = useCallback(async (file: File) => {
const uploadDefault = useCallback(async (file: File): Promise<string> => {
if (s3.configuration.currentBucket === '') {
throw new Error('current bucket not set');
}
@ -91,7 +85,7 @@ const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
}, [s3, upload]);
const promptUpload = useCallback(
() => {
(): Promise<string> => {
return new Promise((resolve, reject) => {
const fileSelector = document.createElement('input');
fileSelector.setAttribute('type', 'file');
@ -101,10 +95,10 @@ const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
const files = fileSelector.files;
if (!files || files.length <= 0) {
reject();
return;
} else {
uploadDefault(files[0]).then(resolve);
document.body.removeChild(fileSelector);
}
uploadDefault(files[0]).then(resolve);
document.body.removeChild(fileSelector);
});
document.body.appendChild(fileSelector);
fileSelector.click();
@ -113,7 +107,7 @@ const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {
[uploadDefault]
);
return {canUpload, upload, uploadDefault, uploading, promptUpload};
return { canUpload, upload, uploadDefault, uploading, promptUpload };
};
export default useStorage;

View File

@ -1,10 +1,10 @@
import { useState, useCallback } from "react";
import { useCallback, useState } from 'react';
export function useToggleState(initial: boolean) {
const [state, setState] = useState(initial);
const toggle = useCallback(() => {
setState((s) => !s);
setState(s => !s);
}, [setState]);
return [state, toggle] as const;

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react';
import { useCallback, useEffect, useState } from 'react';
export function useWaitForProps<P>(props: P, timeout = 0) {
const [resolve, setResolve] = useState<() => void>(() => () => {});

View File

@ -1,15 +1,13 @@
import { useEffect, useState, useCallback, useMemo } from 'react';
import _ from 'lodash';
import f, { compose, memoize } from 'lodash/fp';
import bigInt, { BigInteger } from 'big-integer';
/* eslint-disable max-lines */
import { Association, Contact } from '@urbit/api';
import useLocalState from '../state/local';
import produce, { enableMapSet } from 'immer';
import useSettingsState from '../state/settings';
import { State, UseStore } from 'zustand';
import { Cage } from '~/types/cage';
import { BaseState } from '../state/base';
import anyAscii from 'any-ascii';
import bigInt, { BigInteger } from 'big-integer';
import { enableMapSet } from 'immer';
import _ from 'lodash';
import f from 'lodash/fp';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { IconRef } from '~/types';
import useSettingsState from '../state/settings';
enableMapSet();
@ -24,7 +22,9 @@ export const MOMENT_CALENDAR_DATE = {
sameElse: '~YYYY.M.D'
};
export const getModuleIcon = (mod: string) => {
export type GraphModule = 'link' | 'post' | 'chat' | 'publish';
export const getModuleIcon = (mod: GraphModule): IconRef => {
if (mod === 'link') {
return 'Collection';
}
@ -33,7 +33,7 @@ export const getModuleIcon = (mod: string) => {
return 'Dashboard';
}
return _.capitalize(mod);
return _.capitalize(mod) as IconRef;
};
export function wait(ms: number) {
@ -172,9 +172,9 @@ export function dateToDa(d: Date, mil = false) {
);
}
export function deSig(ship: string) {
export function deSig(ship: string): string {
if (!ship) {
return null;
return '';
}
return ship.replace('~', '');
}
@ -201,7 +201,7 @@ export const hexToUx = (hex) => {
return `0x${ux}`;
};
export function writeText(str: string) {
export function writeText(str: string | null): Promise<void> {
return new Promise<void>((resolve, reject) => {
const range = document.createRange();
range.selectNodeContents(document.body);
@ -226,11 +226,11 @@ export function writeText(str: string) {
}
// trim patps to match dojo, chat-cli
export function cite(ship: string) {
export function cite(ship: string): string {
let patp = ship,
shortened = '';
if (patp === null || patp === '') {
return null;
return '';
}
if (patp.startsWith('~')) {
patp = patp.substr(1);
@ -400,7 +400,7 @@ export function pluralize(text: string, isPlural = false, vowel = false) {
export function useShowNickname(contact: Contact | null, hide?: boolean): boolean {
const hideState = useSettingsState(state => state.calm.hideNicknames);
const hideNicknames = typeof hide !== 'undefined' ? hide : hideState;
return !!(contact && contact.nickname && !hideNicknames);
return Boolean(contact && contact.nickname && !hideNicknames);
}
interface useHoveringInterface {
@ -413,19 +413,18 @@ interface useHoveringInterface {
export const useHovering = (): useHoveringInterface => {
const [hovering, setHovering] = useState(false);
const onMouseOver = useCallback(() => setHovering(true), [])
const onMouseLeave = useCallback(() => setHovering(false), [])
const onMouseOver = useCallback(() => setHovering(true), []);
const onMouseLeave = useCallback(() => setHovering(false), []);
const bind = useMemo(() => ({
onMouseOver,
onMouseLeave,
onMouseLeave
}), [onMouseLeave, onMouseOver]);
return useMemo(() => ({ hovering, bind }), [hovering, bind]);
};
const DM_REGEX = /ship\/~([a-z]|-)*\/dm--/;
export function getItemTitle(association: Association) {
export function getItemTitle(association: Association): string {
if (DM_REGEX.test(association.resource)) {
const [, , ship, name] = association.resource.split('/');
if (ship.slice(1) === window.ship) {
@ -433,6 +432,6 @@ export function getItemTitle(association: Association) {
}
return cite(ship);
}
return association.metadata.title || association.resource;
return association.metadata.title ?? association.resource ?? '';
}

Some files were not shown because too many files have changed in this diff Show More