From 7cce60896e2d88fa88f6305481722a7e344f8b4d Mon Sep 17 00:00:00 2001 From: tomholford Date: Fri, 19 May 2023 13:18:33 -0700 Subject: [PATCH 1/8] gear: import from @urbit/api - copied lib and types from @urbit/api repo to gear/ - migrated webterm types (see: urbit/webterm#3) - rename S3 --> Storage --- gear/contacts/index.ts | 2 + gear/contacts/lib.ts | 109 ++++++ gear/contacts/types.ts | 82 +++++ gear/deps.d.ts | 8 + gear/docket/index.ts | 2 + gear/docket/lib.ts | 65 ++++ gear/docket/types.ts | 135 ++++++++ gear/graph/index.ts | 2 + gear/graph/lib.ts | 534 ++++++++++++++++++++++++++++++ gear/graph/types.ts | 94 ++++++ gear/groups/index.ts | 2 + gear/groups/lib.ts | 226 +++++++++++++ gear/groups/types.ts | 2 + gear/groups/update.ts | 175 ++++++++++ gear/groups/view.ts | 30 ++ gear/hark/index.ts | 2 + gear/hark/lib.ts | 163 +++++++++ gear/hark/types.ts | 58 ++++ gear/hood/index.ts | 2 + gear/hood/lib.ts | 127 +++++++ gear/hood/types.ts | 208 ++++++++++++ gear/index.ts | 28 ++ gear/invite/index.ts | 2 + gear/invite/lib.ts | 28 ++ gear/invite/types.ts | 75 +++++ gear/lib/BigIntArrayOrderedMap.ts | 152 +++++++++ gear/lib/BigIntOrderedMap.ts | 117 +++++++ gear/lib/index.ts | 2 + gear/lib/lib.ts | 259 +++++++++++++++ gear/lib/types.ts | 67 ++++ gear/metadata/index.ts | 2 + gear/metadata/lib.ts | 99 ++++++ gear/metadata/types.ts | 101 ++++++ gear/settings/index.ts | 2 + gear/settings/lib.ts | 78 +++++ gear/settings/types.ts | 64 ++++ gear/storage/index.ts | 2 + gear/storage/lib.ts | 47 +++ gear/storage/types.ts | 60 ++++ 39 files changed, 3213 insertions(+) create mode 100644 gear/contacts/index.ts create mode 100644 gear/contacts/lib.ts create mode 100644 gear/contacts/types.ts create mode 100644 gear/deps.d.ts create mode 100644 gear/docket/index.ts create mode 100644 gear/docket/lib.ts create mode 100644 gear/docket/types.ts create mode 100644 gear/graph/index.ts create mode 100644 gear/graph/lib.ts create mode 100644 gear/graph/types.ts create mode 100644 gear/groups/index.ts create mode 100644 gear/groups/lib.ts create mode 100644 gear/groups/types.ts create mode 100644 gear/groups/update.ts create mode 100644 gear/groups/view.ts create mode 100644 gear/hark/index.ts create mode 100644 gear/hark/lib.ts create mode 100644 gear/hark/types.ts create mode 100644 gear/hood/index.ts create mode 100644 gear/hood/lib.ts create mode 100644 gear/hood/types.ts create mode 100644 gear/index.ts create mode 100644 gear/invite/index.ts create mode 100644 gear/invite/lib.ts create mode 100644 gear/invite/types.ts create mode 100644 gear/lib/BigIntArrayOrderedMap.ts create mode 100644 gear/lib/BigIntOrderedMap.ts create mode 100644 gear/lib/index.ts create mode 100644 gear/lib/lib.ts create mode 100644 gear/lib/types.ts create mode 100644 gear/metadata/index.ts create mode 100644 gear/metadata/lib.ts create mode 100644 gear/metadata/types.ts create mode 100644 gear/settings/index.ts create mode 100644 gear/settings/lib.ts create mode 100644 gear/settings/types.ts create mode 100644 gear/storage/index.ts create mode 100644 gear/storage/lib.ts create mode 100644 gear/storage/types.ts diff --git a/gear/contacts/index.ts b/gear/contacts/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/contacts/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/contacts/lib.ts b/gear/contacts/lib.ts new file mode 100644 index 00000000..26b08c6b --- /dev/null +++ b/gear/contacts/lib.ts @@ -0,0 +1,109 @@ + +import { Patp, Poke, Scry } from '../lib'; +import { + Contact, + ContactUpdateAdd, + ContactUpdateEdit, + ContactUpdateRemove, + ContactEditField, + ContactShare, + ContactUpdate, + ContactUpdateAllowShips, + ContactUpdateAllowGroup, + ContactUpdateSetPublic +} from './types'; + +export const CONTACT_UPDATE_VERSION = 0; + +const storeAction = (data: T, version: number = CONTACT_UPDATE_VERSION): Poke => ({ + app: 'contact-store', + mark: `contact-update-${version}`, + json: data +}); + +export { storeAction as contactStoreAction }; + +export const addContact = (ship: Patp, contact: Contact): Poke => { + contact['last-updated'] = Date.now(); + + return storeAction({ + add: { ship, contact } + }); +}; + +export const removeContact = (ship: Patp): Poke => + storeAction({ + remove: { ship } + }); + +export const share = (recipient: Patp, version: number = CONTACT_UPDATE_VERSION): Poke => ({ + app: 'contact-push-hook', + mark: 'contact-share', + json: { share: recipient } +}); + +export const editContact = ( + ship: Patp, + editField: ContactEditField +): Poke => + storeAction({ + edit: { + ship, + 'edit-field': editField, + timestamp: Date.now() + } + }); + +export const allowShips = ( + ships: Patp[] +): Poke => storeAction({ + allow: { + ships + } +}); + +export const allowGroup = ( + ship: string, + name: string +): Poke => storeAction({ + allow: { + group: { ship, name } + } +}); + +export const setPublic = ( + setPublic: any +): Poke => { + return storeAction({ + 'set-public': setPublic + }); +}; + +export const retrieve = ( + ship: string +) => { + const resource = { ship, name: '' }; + return { + app: 'contact-pull-hook', + mark: 'pull-hook-action', + json: { + add: { + resource, + ship + } + } + }; +}; + +export const fetchIsAllowed = ( + entity: string, + name: string, + ship: string, + personal: boolean +): Scry => { + const isPersonal = personal ? 'true' : 'false'; + return { + app: 'contact-store', + path: `/is-allowed/${entity}/${name}/${ship}/${isPersonal}` + }; +}; diff --git a/gear/contacts/types.ts b/gear/contacts/types.ts new file mode 100644 index 00000000..201aa243 --- /dev/null +++ b/gear/contacts/types.ts @@ -0,0 +1,82 @@ +import { Path, Patp } from '../lib'; +import { Resource } from '../groups'; + +export type ContactUpdate = + | ContactUpdateAdd + | ContactUpdateRemove + | ContactUpdateEdit + | ContactUpdateInitial + | ContactUpdateAllowGroup + | ContactUpdateAllowShips + | ContactUpdateSetPublic; + + export interface ContactUpdateAdd { + add: { + ship: Patp; + contact: Contact; + }; +} + +export interface ContactUpdateRemove { + remove: { + ship: Patp; + }; +} + +export interface ContactUpdateEdit { + edit: { + ship: Patp; + 'edit-field': ContactEditField; + timestamp: number; + }; +} + +export interface ContactUpdateAllowShips { + allow: { + ships: Patp[]; + } +} + +export interface ContactUpdateAllowGroup { + allow: { + group: Resource; + } +} + +export interface ContactUpdateSetPublic { + 'set-public': boolean; +} + +export interface ContactShare { + share: Patp; +} + +export interface ContactUpdateInitial { + initial: Rolodex; +} + +export type Rolodex = { + [p in Patp]: Contact; +}; + +export type Contacts = Rolodex; + +export interface Contact { + nickname: string; + bio: string; + status: string; + color: string; + avatar: string | null; + cover: string | null; + groups: Path[]; + 'last-updated': number; +} + +type ContactKeys = keyof Contact; + +export type ContactEditFieldPrim = Exclude; + +export type ContactEditField = Partial> & { + 'add-group'?: Resource; + 'remove-group'?: Resource; +}; diff --git a/gear/deps.d.ts b/gear/deps.d.ts new file mode 100644 index 00000000..0099f33f --- /dev/null +++ b/gear/deps.d.ts @@ -0,0 +1,8 @@ + +declare module 'urbit-ob' { + + /** + * Convert a @p-encoded string to a decimal-encoded string. + */ + function patp2dec(name: string): string +} diff --git a/gear/docket/index.ts b/gear/docket/index.ts new file mode 100644 index 00000000..e06143cf --- /dev/null +++ b/gear/docket/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/gear/docket/lib.ts b/gear/docket/lib.ts new file mode 100644 index 00000000..f5c3e255 --- /dev/null +++ b/gear/docket/lib.ts @@ -0,0 +1,65 @@ +import { Poke, Scry } from '../lib'; +import { Chad } from './types'; + +export function chadIsRunning(chad: Chad) { + return 'glob' in chad || 'site' in chad; +} + +export const scryCharges: Scry = { + app: 'docket', + path: '/charges' +}; + +export const scryDockets: Scry = { + app: 'docket', + path: '/dockets' +}; + +export const scryTreaties: Scry = { + app: 'treaty', + path: '/treaties' +}; + +export const scryDefaultAlly: Scry = { + app: 'treaty', + path: '/default-ally' +}; + +export const scryAllies: Scry = { + app: 'treaty', + path: '/allies' +}; + +export const scryAllyTreaties = (ship: string): Scry => ({ + app: 'treaty', + path: `/treaties/${ship}` +}); + +/** + * Uninstall a desk, and remove docket + */ +export function docketUninstall(desk: string): Poke { + return { + app: 'docket', + mark: 'docket-uninstall', + json: desk + }; +} + +export function docketInstall(ship: string, desk: string): Poke { + return { + app: 'docket', + mark: 'docket-install', + json: `${ship}/${desk}` + }; +} + +export function allyShip(ship: string): Poke { + return { + app: 'treaty', + mark: 'ally-update-0', + json: { + add: ship + } + }; +} diff --git a/gear/docket/types.ts b/gear/docket/types.ts new file mode 100644 index 00000000..c35399b5 --- /dev/null +++ b/gear/docket/types.ts @@ -0,0 +1,135 @@ +import { Cass } from '../hood'; +export type DeskStatus = 'active' | 'suspended'; + +export type DocketHref = DocketHrefSite | DocketHrefGlob; + +export interface DocketHrefGlob { + glob: { + base: string; + + } +} + +export interface DocketHrefSite { + site: string; +} + +export interface Docket { + title: string; + info?: string; + color: string; + href: DocketHref; + website: string; + license: string; + version: string; + image?: string; +} + +export interface Charge extends Docket { + chad: Chad; +} + +export type Chad = HungChad | GlobChad | SiteChad | InstallChad | SuspendChad; + +export interface HungChad { + hung: string; +} + +export interface GlobChad { + glob: null; +} +export interface SiteChad { + site: null; +} +export interface InstallChad { + install: null; + +} +export interface SuspendChad { + suspend: null; +} + +export interface Treaty extends Docket { + ship: string; + desk: string; + cass: Cass; + hash: string; +} + +export interface Charges { + [desk: string]: Charge; +} + +export interface Treaties { + [ref: string]: Treaty; +} + +export type Charter = string[]; + +export interface Allies { + [ship: string]: Charter; +} + +export interface Provider { + shipName: string; + nickname?: string; + status?: string; +} + +export type ChargeUpdate = ChargeUpdateInitial | ChargeUpdateAdd | ChargeUpdateDel; + +export interface ChargeUpdateInitial { + initial: { + [desk: string]: Charge; + } +} + +export interface ChargeUpdateAdd { + 'add-charge': { + desk: string; + charge: Charge; + } +} + +export interface ChargeUpdateDel { + 'del-charge': string; +} + +export type AllyUpdate = AllyUpdateIni | AllyUpdateAdd | AllyUpdateDel | AllyUpdateNew; + +export interface AllyUpdateIni { + ini: { + [ship: string]: string[]; + } +} + +export interface AllyUpdateAdd { + add: string; +} + +export interface AllyUpdateDel { + del: string; +} + +export interface AllyUpdateNew { + new: { + ship: string; + alliance: string[]; + } +} + +export type TreatyUpdate = TreatyUpdateIni | TreatyUpdateAdd | TreatyUpdateDel; + +export interface TreatyUpdateIni { + ini: { + [foreignDesk: string]: Treaty; + } +} + +export interface TreatyUpdateAdd { + add: Treaty; +} + +export interface TreatyUpdateDel { + del: string; +} diff --git a/gear/graph/index.ts b/gear/graph/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/gear/graph/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/gear/graph/lib.ts b/gear/graph/lib.ts new file mode 100644 index 00000000..ce187df6 --- /dev/null +++ b/gear/graph/lib.ts @@ -0,0 +1,534 @@ +import { GroupPolicy, makeResource, Resource, resourceFromPath } from '../groups'; + +import { decToUd, deSig, unixToDa, Scry } from '../lib'; +import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; +import { Content, GraphChildrenPoke, GraphNode, GraphNodePoke, Post } from './types'; +import { patp2dec } from 'urbit-ob'; + +export const GRAPH_UPDATE_VERSION = 3; + +export const createBlankNodeWithChildPost = ( + ship: PatpNoSig, + parentIndex = '', + childIndex = '', + contents: Content[] +): GraphNodePoke => { + const date = unixToDa(Date.now()).toString(); + const nodeIndex = parentIndex + '/' + date; + + const childGraph: GraphChildrenPoke = {}; + childGraph[childIndex] = { + post: { + author: `~${ship}`, + index: nodeIndex + '/' + childIndex, + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }, + children: null + }; + + return { + post: { + author: `~${ship}`, + index: nodeIndex, + 'time-sent': Date.now(), + contents: [], + hash: null, + signatures: [] + }, + children: childGraph + }; +}; + +export const markPending = (nodes: any): any => { + Object.keys(nodes).forEach((key) => { + nodes[key].post.author = deSig(nodes[key].post.author); + nodes[key].post.pending = true; + if (nodes[key].children) { + nodes[key].children = markPending(nodes[key].children); + } + }); + return nodes; +}; + +export const createPost = ( + ship: PatpNoSig, + contents: Content[], + parentIndex = '', + childIndex = 'DATE_PLACEHOLDER' +): Post => { + if (childIndex === 'DATE_PLACEHOLDER') { + childIndex = unixToDa(Date.now()).toString(); + } + return { + author: `~${ship}`, + index: parentIndex + '/' + childIndex, + 'time-sent': Date.now(), + contents, + hash: null, + signatures: [] + }; +}; + +function moduleToMark(mod: string): string | undefined { + if(mod === 'link') { + return 'graph-validator-link'; + } + if(mod === 'publish') { + return 'graph-validator-publish'; + } + if(mod === 'chat') { + return 'graph-validator-chat'; + } + return undefined; +} + +const storeAction = (data: T, version: number = GRAPH_UPDATE_VERSION): Poke => ({ + app: 'graph-store', + mark: `graph-update-${version}`, + json: data +}); + +export { storeAction as graphStoreAction }; + +const viewAction = (threadName: string, action: T): Thread => ({ + inputMark: 'graph-view-action', + outputMark: 'json', + threadName, + body: action +}); + +export { viewAction as graphViewAction }; + +const hookAction = (data: T, version: number = GRAPH_UPDATE_VERSION): Poke => ({ + app: 'graph-push-hook', + mark: `graph-update-${version}`, + json: data +}); + +const dmAction = (data: T): Poke => ({ + app: 'dm-hook', + mark: 'dm-hook-action', + json: data +}); + +export { hookAction as graphHookAction }; + +export const createManagedGraph = ( + ship: PatpNoSig, + name: string, + title: string, + description: string, + group: Path, + mod: string +): Thread => { + const associated = { group: resourceFromPath(group) }; + const resource = makeResource(`~${ship}`, name); + + return viewAction('graph-create', { + create: { + resource, + title, + description, + associated, + module: mod, + mark: moduleToMark(mod) + } + }); +}; + +export const createUnmanagedGraph = ( + ship: PatpNoSig, + name: string, + title: string, + description: string, + policy: Enc, + mod: string +): Thread => viewAction('graph-create', { + create: { + resource: makeResource(`~${ship}`, name), + title, + description, + associated: { policy }, + module: mod, + mark: moduleToMark(mod) + } +}); + +export const joinGraph = ( + ship: Patp, + name: string +): Thread => viewAction('graph-join', { + join: { + resource: makeResource(ship, name), + ship + } +}); + +export const deleteGraph = ( + ship: PatpNoSig, + name: string +): Thread => viewAction('graph-delete', { + 'delete': { + resource: makeResource(`~${ship}`, name) + } +}); + +export const leaveGraph = ( + ship: Patp, + name: string +): Thread => viewAction('graph-leave', { + 'leave': { + resource: makeResource(ship, name) + } +}); + +export const groupifyGraph = ( + ship: Patp, + name: string, + toPath?: string +): Thread => { + const resource = makeResource(ship, name); + const to = toPath && resourceFromPath(toPath); + + return viewAction('graph-groupify', { + groupify: { + resource, + to + } + }); +}; + +export const evalCord = ( + cord: string +): Thread => { + return ({ + inputMark: 'graph-view-action', + outputMark: 'tang', + threadName: 'graph-eval', + body: { + eval: cord + } + }); +}; + +export const addGraph = ( + ship: Patp, + name: string, + graph: any, + mark: any +): Poke => { + return storeAction({ + 'add-graph': { + resource: { ship, name }, + graph, + mark + } + }); +}; + +export const addNodes = ( + ship: Patp, + name: string, + nodes: Object +): Thread => ({ + inputMark: `graph-update-${GRAPH_UPDATE_VERSION}`, + outputMark: 'graph-view-action', + threadName: 'graph-add-nodes', + body: { + 'add-nodes': { + resource: { ship, name }, + nodes + } + } +}); + +export const addPost = ( + ship: Patp, + name: string, + post: Post +): Thread => { + const nodes: Record = {}; + nodes[post.index] = { + post, + children: null + }; + return addNodes(ship, name, nodes); +}; + +export const addNode = ( + ship: Patp, + name: string, + node: GraphNodePoke +): Thread => { + const nodes: Record = {}; + nodes[node.post.index] = node; + + return addNodes(ship, name, nodes); +}; + +export const createGroupFeed = ( + group: Resource, + vip: any = '' +): Thread => ({ + inputMark: 'graph-view-action', + outputMark: 'resource', + threadName: 'graph-create-group-feed', + body: { + 'create-group-feed': { + resource: group, + vip + } + } +}); + +export const disableGroupFeed = ( + group: Resource +): Thread => ({ + inputMark: 'graph-view-action', + outputMark: 'json', + threadName: 'graph-disable-group-feed', + body: { + 'disable-group-feed': { + resource: group + } + } +}); + +/** + * Set dm-hook to screen new DMs or not + * + */ +export const setScreen = (screen: boolean): Poke => dmAction({ screen }); + +/** + * Accept a pending DM request + * + * @param ship the ship to accept + */ +export const acceptDm = (ship: string) => dmAction({ + accept: ship +}); + +/** + * Decline a pending DM request + * + * @param ship the ship to accept + */ +export const declineDm = (ship: string) => dmAction({ + decline: ship +}); + +/** + * Remove posts from a set of indices + * + */ +export const removePosts = ( + ship: Patp, + name: string, + indices: string[] +): Poke => hookAction({ + 'remove-posts': { + resource: { ship, name }, + indices + } +}); + +/** + * Remove a DM message from our inbox + * + * @remarks + * This does not remove the message from the recipients inbox + */ +export const removeDmMessage = ( + our: Patp, + index: string +): Poke => ({ + app: 'graph-store', + mark: `graph-update-${GRAPH_UPDATE_VERSION}`, + json: { + 'remove-posts': { + resource: { ship: our, name: 'dm-inbox' }, + indices: [index] + } + } +}); + +/** + * Send a DM to a ship + * + * @param our sender + * @param ship recipient + * @param contents contents of message + */ +export const addDmMessage = (our: PatpNoSig, ship: Patp, contents: Content[]): Poke => { + const post = createPost(our, contents, `/${patp2dec(ship)}`); + const node: GraphNode = { + post, + children: null + }; + return { + app: 'dm-hook', + mark: `graph-update-${GRAPH_UPDATE_VERSION}`, + json: { + 'add-nodes': { + resource: { ship: `~${our}`, name: 'dm-inbox' }, + nodes: { + [post.index]: node + } + } + } + }; +}; + +const encodeIndex = (idx: string) => idx.split('/').map(decToUd).join('/'); + +/** + * Fetch all graph keys + */ +export const getKeys = (): Scry => ({ + app: 'graph-store', + path: '/keys' +}); + +/** + * Fetch newest (larger keys) nodes in a graph under some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getNewest = ( + ship: string, + name: string, + count: number, + index = '' +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings` + + `/newest/lone/${count}${encodeIndex(index)}` +}); + +/** + * Fetch nodes in a graph that are older (key is smaller) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getOlderSiblings = ( + ship: string, + name: string, + count: number, + index: string +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings/older/lone/${count}${encodeIndex(index)}` +}); + +/** + * Fetch nodes in a graph that are younger (key is larger) and direct + * siblings of some index + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param index index to query + */ +export const getYoungerSiblings = ( + ship: string, + name: string, + count: number, + index: string +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings/newer/lone/${count}${encodeIndex(index)}` +}); + +/** + * Fetch all nodes in a graph under some index, without loading children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + */ +export const getShallowChildren = (ship: string, name: string, index = '') => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/children/lone/~/~${encodeIndex(index)}` +}); + +/** + * Fetch newest nodes in a graph as a flat map, including children, + * optionally starting at a specified key + * + * @param ship ship of graph + * @param name name of graph + * @param count number of nodes to load + * @param start key to start at + * + */ +export const getDeepOlderThan = ( + ship: string, + name: string, + count: number, + start = '' +) => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/siblings` + + `/${start.length > 0 ? 'older' : 'newest'}` + + `/kith/${count}${encodeIndex(start)}` +}); + +/** + * Fetch a flat map of a nodes ancestors and firstborn children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export const getFirstborn = ( + ship: string, + name: string, + index: string +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/firstborn${encodeIndex(index)}` +}); + +/** + * Fetch a single node, and all it's children + * + * @param ship ship of graph + * @param name name of graph + * @param index index to query + * + */ +export const getNode = ( + ship: string, + name: string, + index: string +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}/node/index/kith${encodeIndex(index)}` +}); + +/** + * Fetch entire graph + * + * @param ship ship of graph + * @param name name of graph + * + */ +export const getGraph = ( + ship: string, + name: string +): Scry => ({ + app: 'graph-store', + path: `/graph/${ship}/${name}` +}); diff --git a/gear/graph/types.ts b/gear/graph/types.ts new file mode 100644 index 00000000..2e8816a3 --- /dev/null +++ b/gear/graph/types.ts @@ -0,0 +1,94 @@ +import { Patp } from '../lib'; +import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; +import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap'; + +export interface TextContent { + text: string; +} +export interface UrlContent { + url: string; +} +export interface CodeContent { + code: { + expression: string; + output: string[] | undefined; + } +} + +export interface ReferenceContent { + reference: AppReference | GraphReference | GroupReference; +} + +export interface GraphReference { + graph: { + graph: string; + group: string; + index: string; + } +} + +export interface GroupReference { + group: string; +} + +export interface AppReference { + app: { + ship: string; + desk: string; + path: string; + } +} + +export interface MentionContent { + mention: string; + emphasis?: 'bold' | 'italic'; +} +export type Content = + | TextContent + | UrlContent + | CodeContent + | ReferenceContent + | MentionContent; + +export interface Post { + author: Patp; + contents: Content[]; + hash: string | null; + index: string; + pending?: boolean; + signatures: string[]; + 'time-sent': number; +} + +export interface GraphNodePoke { + post: Post; + children: GraphChildrenPoke | null; +} + +export interface GraphChildrenPoke { + [k: string]: GraphNodePoke; +} + +export interface GraphNode { + children: Graph | null; + post: Post; +} + +export interface FlatGraphNode { + children: null; + post: Post; +} + +export type Graph = BigIntOrderedMap; + +export type Graphs = { [rid: string]: Graph }; + +export type FlatGraph = BigIntArrayOrderedMap; + +export type FlatGraphs = { [rid: string]: FlatGraph }; + +export type ThreadGraphs = { + [rid: string]: { + [index: string]: FlatGraph; + } +}; diff --git a/gear/groups/index.ts b/gear/groups/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/groups/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/groups/lib.ts b/gear/groups/lib.ts new file mode 100644 index 00000000..7e93ad3a --- /dev/null +++ b/gear/groups/lib.ts @@ -0,0 +1,226 @@ +import { deSig } from '../index'; +import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; +import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types'; +import { GroupUpdate } from './update'; + +export const GROUP_UPDATE_VERSION = 0; + +export const proxyAction = (data: T, version: number = GROUP_UPDATE_VERSION): Poke => ({ + app: 'group-push-hook', + mark: `group-update-${version}`, + json: data +}); + +const storeAction = (data: T, version: number = GROUP_UPDATE_VERSION): Poke => ({ + app: 'group-store', + mark: `group-update-${version}`, + json: data +}); + +export { storeAction as groupStoreAction }; + +const viewAction = (data: T): Poke => ({ + app: 'group-view', + mark: 'group-view-action', + json: data +}); + +export { viewAction as groupViewAction }; + +export const viewThread = (thread: string, action: T): Thread => ({ + inputMark: 'group-view-action', + outputMark: 'json', + threadName: thread, + body: action +}); + +export const removeMembers = ( + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + removeMembers: { + resource, + ships + } +}); + +export const addTag = ( + resource: Resource, + tag: Tag, + ships: Patp[] +): Poke => proxyAction({ + addTag: { + resource, + tag, + ships + } +}); + +export const removeTag = ( + tag: Tag, + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + removeTag: { + tag, + resource, + ships + } +}); + +export const addMembers = ( + resource: Resource, + ships: PatpNoSig[] +): Poke => proxyAction({ + addMembers: { + resource, + ships + } +}); + +export const removeGroup = ( + resource: Resource +): Poke => storeAction({ + removeGroup: { + resource + } +}); + +export const changePolicy = ( + resource: Resource, + diff: Enc +): Poke> => proxyAction({ + changePolicy: { + resource, + diff + } +}); + +export const join = ( + ship: string, + name: string, + app: "groups" | "graph", + autojoin: boolean, + share: boolean +): Poke => viewAction({ + join: { + resource: makeResource(ship, name), + ship, + shareContact: share || false, + app, + autojoin + } +}); + +export const createGroup = ( + name: string, + policy: Enc, + title: string, + description: string +): Thread => viewThread('group-create', { + create: { + name, + policy, + title, + description + } +}); + +export const deleteGroup = ( + ship: string, + name: string +): Thread => viewThread('group-delete', { + remove: makeResource(ship, name) +}); + +export const leaveGroup = ( + ship: string, + name: string +): Thread => viewThread('group-leave', { + leave: makeResource(ship, name) +}); + +export const invite = ( + ship: string, + name: string, + ships: Patp[], + description: string +): Thread => viewThread('group-invite', { + invite: { + resource: makeResource(ship, name), + ships, + description + } +}); + +export const abortJoin = ( + resource: string +): Poke => viewAction({ + abort: resource +}); + +export const roleTags = ['janitor', 'moderator', 'admin']; +// TODO make this type better? + +export const groupBunts = { + group: (): Group => ({ members: [], tags: { role: {} }, hidden: false, policy: groupBunts.policy() }), + policy: (): GroupPolicy => ({ open: { banned: [], banRanks: [] } }) +}; + +export const joinError = ['no-perms', 'strange', 'abort'] as const; +export const joinResult = ['done', ...joinError] as const; +export const joinLoad = ['start', 'added', 'metadata'] as const; +export const joinProgress = [...joinLoad, ...joinResult] as const; + +export function roleForShip( + group: Group, + ship: PatpNoSig +): RoleTags | undefined { + return roleTags.reduce((currRole, role) => { + const roleShips = group?.tags?.role?.[role]; + return roleShips && roleShips.includes(ship) ? role : currRole; + }, undefined as RoleTags | undefined); +}; + +export function resourceFromPath(path: Path): Resource { + const [, , ship, name] = path.split('/'); + return { ship, name }; +} + +export function makeResource(ship: string, name: string) { + return { ship, name }; +} + +export const isWriter = (group: Group, resource: string, ship: string) => { + const graph = group?.tags?.graph; + const writers: string[] | undefined = graph && (graph[resource] as any)?.writers; + const admins = group?.tags?.role?.admin ?? []; + if (typeof writers === 'undefined') { + return true; + } else { + return [...writers].includes(ship) || admins.includes(ship); + } +}; + +export function isChannelAdmin( + group: Group, + resource: string, + ship: string +): boolean { + const role = roleForShip(group, deSig(ship)); + + return ( + isHost(resource, ship) || + role === 'admin' || + role === 'moderator' + ); +} + +export function isHost( + resource: string, + ship: string +): boolean { + const [, , host] = resource.split('/'); + + return ship === host; +} diff --git a/gear/groups/types.ts b/gear/groups/types.ts new file mode 100644 index 00000000..6197c4f9 --- /dev/null +++ b/gear/groups/types.ts @@ -0,0 +1,2 @@ +export * from './update'; +export * from './view'; \ No newline at end of file diff --git a/gear/groups/update.ts b/gear/groups/update.ts new file mode 100644 index 00000000..a25c9a63 --- /dev/null +++ b/gear/groups/update.ts @@ -0,0 +1,175 @@ +import { PatpNoSig, Path, ShipRank, Enc } from '../lib'; +import { roleTags } from './index'; + +export type RoleTags = typeof roleTags[number]; +interface RoleTag { + tag: 'admin' | 'moderator' | 'janitor'; +} + +interface AppTag { + app: string; + resource: string; + tag: string; +} + +export type Tag = AppTag | RoleTag; + +export interface InvitePolicy { + invite: { + pending: PatpNoSig[]; + }; +} + +export interface OpenPolicy { + open: { + banned: PatpNoSig[]; + banRanks: ShipRank[]; + }; +} + +export interface Resource { + name: string; + ship: PatpNoSig; +} + +export type OpenPolicyDiff = + | AllowRanksDiff + | BanRanksDiff + | AllowShipsDiff + | BanShipsDiff; + +export interface AllowRanksDiff { + allowRanks: ShipRank[]; +} + +export interface BanRanksDiff { + banRanks: ShipRank[]; +} + +export interface AllowShipsDiff { + allowShips: PatpNoSig[]; +} + +export interface BanShipsDiff { + banShips: PatpNoSig[]; +} + +export type InvitePolicyDiff = AddInvitesDiff | RemoveInvitesDiff; + +export interface AddInvitesDiff { + addInvites: PatpNoSig[]; +} + +export interface RemoveInvitesDiff { + removeInvites: PatpNoSig[]; +} + +export interface ReplacePolicyDiff { + replace: GroupPolicy; +} + +export type GroupPolicyDiff = + | { open: OpenPolicyDiff } + | { invite: InvitePolicyDiff } + | ReplacePolicyDiff; + +export type GroupPolicy = OpenPolicy | InvitePolicy; + +export interface TaggedShips { + [tag: string]: PatpNoSig[]; +} + +export interface Tags { + role: TaggedShips; + [app: string]: TaggedShips; +} + +export interface Group { + members: PatpNoSig[]; + tags: Tags; + policy: GroupPolicy; + hidden: boolean; +} + +export type Groups = { + [p in Path]: Group; +}; + +export interface GroupUpdateInitial { + initial: Enc; +} + +export interface GroupUpdateAddGroup { + addGroup: { + resource: Resource; + policy: Enc; + hidden: boolean; + }; +} + +export interface GroupUpdateAddMembers { + addMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} + +export interface GroupUpdateRemoveMembers { + removeMembers: { + ships: PatpNoSig[]; + resource: Resource; + }; +} + +export interface GroupUpdateAddTag { + addTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} + +export interface GroupUpdateRemoveTag { + removeTag: { + tag: Tag; + resource: Resource; + ships: PatpNoSig[]; + }; +} + +export interface GroupUpdateChangePolicy { + changePolicy: { resource: Resource; diff: GroupPolicyDiff }; +} + +export interface GroupUpdateRemoveGroup { + removeGroup: { + resource: Resource; + }; +} + +export interface GroupUpdateExpose { + expose: { + resource: Resource; + }; +} + +export interface GroupUpdateInitialGroup { + initialGroup: { + resource: Resource; + group: Enc; + }; +} + +export type GroupUpdate = + | GroupUpdateInitial + | GroupUpdateAddGroup + | GroupUpdateAddMembers + | GroupUpdateRemoveMembers + | GroupUpdateAddTag + | GroupUpdateRemoveTag + | GroupUpdateChangePolicy + | GroupUpdateRemoveGroup + | GroupUpdateExpose + | GroupUpdateInitialGroup; + +export type GroupAction = Omit; diff --git a/gear/groups/view.ts b/gear/groups/view.ts new file mode 100644 index 00000000..c6e432b2 --- /dev/null +++ b/gear/groups/view.ts @@ -0,0 +1,30 @@ +import { joinError, joinProgress, joinResult } from "."; +import {Patp} from "../lib"; + +export type JoinError = typeof joinError[number]; + +export type JoinResult = typeof joinResult[number]; + + +export type JoinProgress = typeof joinProgress[number]; + +export interface JoinRequest { + /** + * Whether to display the join request or not + */ + hidden: boolean; + /** + * Timestamp of when the request started + */ + started: number; + ship: Patp; + progress: JoinProgress; + shareContact: boolean; + autojoin: boolean; + app: 'graph' | 'groups'; + invite: string[]; +} + +export interface JoinRequests { + [rid: string]: JoinRequest; +} diff --git a/gear/hark/index.ts b/gear/hark/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/hark/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/hark/lib.ts b/gear/hark/lib.ts new file mode 100644 index 00000000..a470c671 --- /dev/null +++ b/gear/hark/lib.ts @@ -0,0 +1,163 @@ +import { BigInteger } from 'big-integer'; + +import { Poke } from '../lib/types'; +import { + HarkBin, + HarkBinId, + HarkBody, + HarkLid, + HarkPlace +} from './types'; +import { decToUd } from '../lib'; + +export const harkAction = (data: T): Poke => ({ + app: 'hark-store', + mark: 'hark-action', + json: data +}); + +const graphHookAction = (data: T): Poke => ({ + app: 'hark-graph-hook', + mark: 'hark-graph-hook-action', + json: data +}); + +export { graphHookAction as harkGraphHookAction }; + +const groupHookAction = (data: T): Poke => ({ + app: 'hark-group-hook', + mark: 'hark-group-hook-action', + json: data +}); + +export { groupHookAction as harkGroupHookAction }; + +export const actOnNotification = ( + frond: string, + intTime: BigInteger, + bin: HarkBin +): Poke => + harkAction({ + [frond]: { + time: decToUd(intTime.toString()), + bin + } + }); + +export const setMentions = (mentions: boolean): Poke => + graphHookAction({ + 'set-mentions': mentions + }); + +export const setWatchOnSelf = (watchSelf: boolean): Poke => + graphHookAction({ + 'set-watch-on-self': watchSelf + }); + +export const setDoNotDisturb = (dnd: boolean): Poke => + harkAction({ + 'set-dnd': dnd + }); + +export const addNote = (bin: HarkBin, body: HarkBody) => + harkAction({ + 'add-note': { + bin, + body + } + }); + +export const archive = (bin: HarkBin, lid: HarkLid): Poke => + harkAction({ + archive: { + lid, + bin + } + }); + +export const opened = harkAction({ + opened: null +}); + +export const markCountAsRead = (place: HarkPlace): Poke => + harkAction({ + 'read-count': place + }); + +export const markEachAsRead = ( + place: HarkPlace, + path: string +): Poke => + harkAction({ + 'read-each': { + place, + path + } + }); + +export const seen = () => harkAction({ seen: null }); + +export const readAll = harkAction({ 'read-all': null }); +export const archiveAll = harkAction({ 'archive-all': null }); + +export const ignoreGroup = (group: string): Poke => + groupHookAction({ + ignore: group + }); + +export const ignoreGraph = (graph: string, index: string): Poke => + graphHookAction({ + ignore: { + graph, + index + } + }); + +export const listenGroup = (group: string): Poke => + groupHookAction({ + listen: group + }); + +export const listenGraph = (graph: string, index: string): Poke => + graphHookAction({ + listen: { + graph, + index + } + }); + +/** + * Read all graphs belonging to a particular group + */ +export const readGroup = (group: string) => + harkAction({ + 'read-group': group + }); + +/** + * Read all unreads in a graph + */ +export const readGraph = (graph: string) => + harkAction({ + 'read-graph': graph + }); + +export function harkBinToId(bin: HarkBin): HarkBinId { + const { place, path } = bin; + return `${place.desk}${place.path}${path}`; +} + +export function harkBinEq(a: HarkBin, b: HarkBin): boolean { + return ( + a.place.path === b.place.path && + a.place.desk === b.place.desk && + a.path === b.path + ); +} + +export function harkLidToId(lid: HarkLid): string { + if('time' in lid) { + return `archive-${lid.time}`; + } + return Object.keys(lid)[0]; +} diff --git a/gear/hark/types.ts b/gear/hark/types.ts new file mode 100644 index 00000000..e52912cb --- /dev/null +++ b/gear/hark/types.ts @@ -0,0 +1,58 @@ + +export interface HarkStats { + count: number; + each: string[]; + last: number; +} + +export interface Timebox { + [binId: string]: Notification; +} + +export type HarkContent = { ship: string; } | { text: string; }; + +export interface HarkBody { + title: HarkContent[]; + time: number; + content: HarkContent[]; + link: string; + binned: string; +} + +export interface HarkPlace { + desk: string; + path: string; +} + +export interface HarkBin { + path: string; + place: HarkPlace; +} + +export type HarkLid = + { unseen: null; } +| { seen: null; } +| { time: string; }; + +export type HarkBinId = string; +export interface Notification { + bin: HarkBin; + time: number; + body: HarkBody[]; +} + +export interface NotificationGraphConfig { + watchOnSelf: boolean; + mentions: boolean; + watching: WatchedIndex[] +} + +export interface Unreads { + [path: string]: HarkStats; +} + +interface WatchedIndex { + graph: string; + index: string; +} +export type GroupNotificationsConfig = string[]; diff --git a/gear/hood/index.ts b/gear/hood/index.ts new file mode 100644 index 00000000..e06143cf --- /dev/null +++ b/gear/hood/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; diff --git a/gear/hood/lib.ts b/gear/hood/lib.ts new file mode 100644 index 00000000..02d86868 --- /dev/null +++ b/gear/hood/lib.ts @@ -0,0 +1,127 @@ +import { Poke, Scry } from '../lib'; +import { Pike } from './types'; + +export const getPikes: Scry = { + app: 'hood', + path: '/kiln/pikes' +}; + +/** + * Install a foreign desk + */ +export function kilnInstall( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-install', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Sync with a foreign desk + */ +export function kilnSync( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-sync', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Unsync with a foreign desk + */ +export function kilnUnsync( + ship: string, + desk: string, + local?: string +): Poke { + return { + app: 'hood', + mark: 'kiln-unsync', + json: { + ship, + desk, + local: local || desk + } + }; +} + +/** + * Uninstall a desk + */ +export function kilnUninstall( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-uninstall', + json: desk + }; +} + +export function kilnSuspend( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-suspend', + json: desk + }; +} + +export function kilnRevive( + desk: string +): Poke { + return { + app: 'hood', + mark: 'kiln-revive', + json: desk + }; +} + +export function kilnBump(): Poke { + return { + app: 'hood', + mark: 'kiln-bump', + json: null, + }; +} + +export function kilnPause(desk: string) { + return { + app: 'hood', + mark: 'kiln-pause', + json: desk + }; +} + +export function kilnResume(desk: string) { + return { + app: 'hood', + mark: 'kiln-resume', + json: desk + }; +} + +export const scryLag: Scry = ({ app: 'hood', path: '/kiln/lag' }); + +export function getPikePublisher(pike: Pike) { + return pike.sync?.ship; +} diff --git a/gear/hood/types.ts b/gear/hood/types.ts new file mode 100644 index 00000000..17676b47 --- /dev/null +++ b/gear/hood/types.ts @@ -0,0 +1,208 @@ + +/** + * A pending commit, awaiting a future kelvin version + */ +interface Woof { + aeon: number; + weft: Weft; +} + +interface Rein { + /** + * Agents not in manifest that should be running + */ + add: string[]; + /** + * Agents in manifest that should not be running + */ + sub: string[]; +} + +export interface Rail { + /** + * Original publisher of desk, if available + */ + publisher: string | null; + /** + * Ship of foreign vat + */ + ship: string; + /** + * Desk of foreign vat + */ + desk: string; + /** + * Aeon (version number) that we currently have synced + */ + aeon: number; + next: Woof[]; + paused: boolean; +} + +/** + * A tracker of a foreign {@link Vat} + * + */ +export interface Arak { + rein: Rein; + rail: Rail | null; +} + +/** + * A component's kelvin version + */ +export interface Weft { + /** + * Name of the component + * + * @remarks + * Usually %zuse, %hoon, or %lull + */ + name: string; + /** + * Kelvin version + * + */ + kelvin: number; +} + +export interface KilnDiffBlock { + block: { + desk: string; + arak: Arak; + weft: Weft; + blockers: string[]; + }; +} + +export interface KilnDiffReset { + reset: { + desk: string; + arak: Arak; + }; +} + +export interface KilnDiffMerge { + merge: { + desk: string; + arak: Arak; + }; +} + +export interface KilnDiffMergeSunk { + 'merge-sunk': { + desk: string; + arak: Arak; + tang: string; + }; +} + +export interface KilnDiffMergeFail { + 'merge-fail': { + desk: string; + arak: Arak; + tang: string; + }; +} + +export type KilnDiff = + | KilnDiffBlock + | KilnDiffReset + | KilnDiffMerge + | KilnDiffMergeSunk + | KilnDiffMergeFail; + +/** + * Cases for revision + * + */ +export interface Cass { + /** + * Revision number + */ + ud: number; + /** + * Timestamp of revision, as stringifed `@da` + * + * @remarks + * If \@da is outside valid positive unix timestamp, value will be zero + */ + da: string; +} + +/** + * A local desk installation + */ +export interface Vat { + /** + * Desk that this Vat describes + */ + desk: string; + /** + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` + */ + hash: string; + /** + * Current revision + */ + cass: Cass; + /** + * Foreign sync + */ + arak: Arak; +} + +export interface Vats { + [desk: string]: Vat; +} +/** + * TODO: crisp one-liner describing a Pike + */ +export interface Pike { + /** + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` + */ + hash: string; + sync: { + /** + * Source desk for this Pike + */ + desk: string; + /** + * Source ship for this Pike + */ + ship: string; + } | null; + /** + * {@link Weft}s associated with this Pike + */ + wefts: Weft[]; + /** + * how live is this pike? + * + * live - app is running + * held - app is not running, but is trying to run. this state can be entered + * in two main ways: + * - when installing an app but it hasn't finished downloading (or it did + * but failed to install for some reason) + * - when user forced a kelvin upgrade by suspending desks. + * dead - app is not running + */ + zest: "live" | "dead" | "held"; +} + +export interface Pikes { + [desk: string]: Pike; +} diff --git a/gear/index.ts b/gear/index.ts new file mode 100644 index 00000000..d3f28beb --- /dev/null +++ b/gear/index.ts @@ -0,0 +1,28 @@ +export * from './contacts'; +export * as contacts from './contacts'; +export * from './graph'; +export * as graph from './graph'; +export * from './groups'; +export * as groups from './groups'; +export * from './hark'; +export * as hark from './hark'; +export * from './invite'; +// this conflicts with /groups/lib invite +// export * as invite from './invite'; +export * from './metadata'; +export * as metadata from './metadata'; +export * from './settings'; +export * as settings from './settings'; +export * from './s3'; +export * as s3 from './s3'; +export * from './lib'; +export * from './lib/BigIntOrderedMap'; +export * from './lib/BigIntArrayOrderedMap'; +export * as hood from './hood'; +export * from './hood'; +export * as docket from './docket'; +export * from './docket'; + +// TODO: Userspace Permissions +// export * from './permissions'; +// export * as permissions from './permissions'; diff --git a/gear/invite/index.ts b/gear/invite/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/invite/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/invite/lib.ts b/gear/invite/lib.ts new file mode 100644 index 00000000..a5a5ca94 --- /dev/null +++ b/gear/invite/lib.ts @@ -0,0 +1,28 @@ +import { Poke, Serial } from "../lib"; +import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types"; + +export const inviteAction = (data: T): Poke => ({ + app: 'invite-store', + mark: 'invite-action', + json: data +}); + +export const accept = ( + app: string, + uid: Serial +): Poke => inviteAction({ + accept: { + term: app, + uid + } +}); + +export const decline = ( + app: string, + uid: Serial +): Poke => inviteAction({ + decline: { + term: app, + uid + } +}); diff --git a/gear/invite/types.ts b/gear/invite/types.ts new file mode 100644 index 00000000..b3515bb4 --- /dev/null +++ b/gear/invite/types.ts @@ -0,0 +1,75 @@ +import { Serial, PatpNoSig, Path } from '../lib'; +import { Resource } from "../groups"; + +export type InviteUpdate = + InviteUpdateInitial +| InviteUpdateCreate +| InviteUpdateDelete +| InviteUpdateInvite +| InviteUpdateAccept +| InviteUpdateAccepted +| InviteUpdateDecline; + +export interface InviteUpdateAccept { + accept: { + term: string; + uid: Serial; + } +} + +export interface InviteUpdateInitial { + initial: Invites; +} + +export interface InviteUpdateCreate { + create: { + term: string; + }; +} + +export interface InviteUpdateDelete { + delete: { + term: string; + }; +} + +export interface InviteUpdateInvite { + invite: { + term: string; + uid: Serial; + invite: Invite; + }; +} + +export interface InviteUpdateAccepted { + accepted: { + term: string; + uid: Serial; + }; +} + +export interface InviteUpdateDecline { + decline: { + term: string; + uid: Serial; + }; +} + +// actual datastructures + + +export type Invites = { + [p in Path]: AppInvites; +}; + +export type AppInvites = { + [s in Serial]: Invite; +}; + +export interface Invite { + app: string; + recipient: PatpNoSig; + resource: Resource; + ship: PatpNoSig; + text: string; +} diff --git a/gear/lib/BigIntArrayOrderedMap.ts b/gear/lib/BigIntArrayOrderedMap.ts new file mode 100644 index 00000000..79e998c5 --- /dev/null +++ b/gear/lib/BigIntArrayOrderedMap.ts @@ -0,0 +1,152 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +export function stringToArr(str: string) { + return str.split('/').slice(1).map((ind) => { + return bigInt(ind); + }); +} + +export function arrToString(arr: BigInteger[]) { + let string = ''; + arr.forEach((key) => { + string = string + `/${key.toString()}`; + }); + return string; +} + +function sorted(a: BigInteger[], b: BigInteger[], reversed = false) { + const getSort = sortBigIntArr(a, b); + if (reversed) { + return getSort * -1; + } else { + return getSort; + } +} + +export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) { + const aLen = a.length; + const bLen = b.length; + + const aCop = a.slice(0); + const bCop = b.slice(0); + aCop.reverse(); + bCop.reverse(); + + let i = 0; + while (i < aLen && i < bLen) { + if (aCop[i].lt(bCop[i])) { + return 1; + } else if (aCop[i].gt(bCop[i])) { + return -1; + } else { + i++; + } + } + + return bLen - aLen; +} + +export class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { + root: Record = {} + cachedIter: [BigInteger[], V][] | null = null; + [immerable] = true; + reversed = false; + + constructor(items: [BigInteger[], V][] = [], reversed = false) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + this.reversed = reversed; + } + + get size() { + return Object.keys(this.root).length; + } + + get(key: BigInteger[]) { + return this.root[arrToString(key)] ?? null; + } + + gas(items: [BigInteger[], V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[arrToString(key)] = castDraft(value); + }); + draft.generateCachedIter(); + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger[], value: V) { + return produce(this, (draft) => { + draft.root[arrToString(key)] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger[]) { + return arrToString(key) in this.root; + } + + delete(key: BigInteger[]) { + const result = produce(this, (draft) => { + delete draft.root[arrToString(key)]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger[], V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger[], V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger[], V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger[], V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + return [stringToArr(key), this.root[key]] as [BigInteger[], V]; + }).sort(([a], [b]) => sorted(a, b, this.reversed)); + this.cachedIter = result; + return [...result]; + } +} + diff --git a/gear/lib/BigIntOrderedMap.ts b/gear/lib/BigIntOrderedMap.ts new file mode 100644 index 00000000..5e3661d1 --- /dev/null +++ b/gear/lib/BigIntOrderedMap.ts @@ -0,0 +1,117 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +function sortBigInt(a: BigInteger, b: BigInteger) { + if (a.lt(b)) { + return 1; + } else if (a.eq(b)) { + return 0; + } else { + return -1; + } +} +export class BigIntOrderedMap implements Iterable<[BigInteger, V]> { + root: Record = {} + cachedIter: [BigInteger, V][] | null = null; + [immerable] = true; + + constructor(items: [BigInteger, V][] = []) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + } + + get size() { + if(this.cachedIter) { + return this.cachedIter.length; + } + return this.generateCachedIter().length; + } + + get(key: BigInteger) { + return this.root[key.toString()] ?? null; + } + + gas(items: [BigInteger, V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[key.toString()] = castDraft(value); + }); + draft.cachedIter = null; + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger, value: V) { + return produce(this, (draft) => { + draft.root[key.toString()] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger) { + return key.toString() in this.root; + } + + delete(key: BigInteger) { + const result = produce(this, (draft) => { + delete draft.root[key.toString()]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger, V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger, V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger, V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger, V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + const num = bigInt(key); + return [num, this.root[key]] as [BigInteger, V]; + }).sort(([a], [b]) => sortBigInt(a,b)); + this.cachedIter = result; + return [...result]; + } +} + diff --git a/gear/lib/index.ts b/gear/lib/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/gear/lib/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/gear/lib/lib.ts b/gear/lib/lib.ts new file mode 100644 index 00000000..c57d0a25 --- /dev/null +++ b/gear/lib/lib.ts @@ -0,0 +1,259 @@ +import bigInt, { BigInteger } from "big-integer"; + +import { Resource } from "../groups/types"; +import { Post, GraphNode } from "../graph/types"; + +const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1 + +const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1 + +function chunk(arr: T[], size: number): T[][] { + let chunk: T[] = []; + let newArray = [chunk]; + + for (let i = 0;i < arr.length;i++) { + if (chunk.length < size) { + chunk.push(arr[i]) + } else { + chunk = [arr[i]] + newArray.push(chunk) + } + } + + return newArray; +} + +function dropWhile(arr: T[], pred: (x: T) => boolean): T[] { + const newArray = arr.slice(); + + for (const item of arr) { + if (pred(item)) { + newArray.shift(); + } else { + return newArray; + } + } + + return newArray; +} + +/** + * Given a bigint representing an urbit date, returns a unix timestamp. + * + * @param {BigInteger} da The urbit date + * + * @return {number} The unix timestamp + */ +export function daToUnix(da: BigInteger): number { + // ported from +time:enjs:format in hoon.hoon + const offset = DA_SECOND.divide(bigInt(2000)); + const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH)); + + return Math.round( + epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber() + ); +} + +/** + * Given a unix timestamp, returns a bigint representing an urbit date + * + * @param {number} unix The unix timestamp + * + * @return {BigInteger} The urbit date + */ +export function unixToDa(unix: number): BigInteger { + const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000)); + return DA_UNIX_EPOCH.add(timeSinceEpoch); +} + + +export function makePatDa(patda: string): BigInteger { + return bigInt(udToDec(patda)); +} + +export function udToDec(ud: string): string { + return ud.replace(/\./g, ""); +} + +export function decToUd(str: string): string { + const transform = chunk(str.split('').reverse(), 3) + .map(group => group.reverse().join('')) + .reverse() + .join('.') + return transform.replace(/^[0\.]+/g, ''); +} + +export function resourceAsPath(resource: Resource): string { + const { name, ship } = resource; + return `/ship/~${ship}/${name}`; +} + +export function uuid(): string { + let str = "0v"; + str += Math.ceil(Math.random() * 8) + "."; + for (let i = 0; i < 5; i++) { + let _str = Math.ceil(Math.random() * 10000000).toString(32); + _str = ("00000" + _str).substr(-5, 5); + str += _str + "."; + } + + return str.slice(0, -1); +} + +/* + Goes from: + ~2018.7.17..23.15.09..5be5 // urbit @da + To: + (javascript Date object) +*/ +export function daToDate(st: string): Date { + const dub = function (n: string) { + return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString(); + }; + const da = st.split(".."); + const bigEnd = da[0].split("."); + const lilEnd = da[1].split("."); + const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub( + lilEnd[0] + )}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; + return new Date(ds); +} + +/* + Goes from: + (javascript Date object) + To: + ~2018.7.17..23.15.09..5be5 // urbit @da +*/ + +export function dateToDa(d: Date, mil: boolean = false): string { + const fil = function (n: number) { + return n >= 10 ? n : "0" + n; + }; + return ( + `~${d.getUTCFullYear()}.` + + `${d.getUTCMonth() + 1}.` + + `${fil(d.getUTCDate())}..` + + `${fil(d.getUTCHours())}.` + + `${fil(d.getUTCMinutes())}.` + + `${fil(d.getUTCSeconds())}` + + `${mil ? "..0000" : ""}` + ); +} + +export function preSig(ship: string): string { + if (!ship) { + return ''; + } + + if (ship.trim().startsWith('~')) { + return ship.trim(); + } + + return '~'.concat(ship.trim()); +} + +export function deSig(ship: string): string | null { + if (!ship) { + return null; + } + return ship.replace("~", ""); +} + +// trim patps to match dojo, chat-cli +export function cite(ship: string) { + let patp = ship, + shortened = ''; + if (patp === null || patp === '') { + return null; + } + if (patp.startsWith('~')) { + patp = patp.substr(1); + } + // comet + if (patp.length === 56) { + shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56); + return shortened; + } + // moon + if (patp.length === 27) { + shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27); + return shortened; + } + return `~${patp}`; +} + + +export function uxToHex(ux: string) { + if (ux.length > 2 && ux.substr(0, 2) === '0x') { + const value = ux.substr(2).replace('.', '').padStart(6, '0'); + return value; + } + + const value = ux.replace('.', '').padStart(6, '0'); + return value; +} + +export const hexToUx = (hex: string): string => { + const nonZeroChars = dropWhile(hex.split(''), y => y === '0'); + const ux = chunk(nonZeroChars.reverse(), 4).map(x => { + return x.reverse().join(''); + }).reverse().join('.') || '0'; + + return `0x${ux}`; +}; + + +// encode the string into @ta-safe format, using logic from +wood. +// for example, 'some Chars!' becomes '~.some.~43.hars~21.' +// +export function stringToTa(str: string): string { + let out = ""; + for (let i = 0; i < str.length; i++) { + const char = str[i]; + let add = ""; + switch (char) { + case " ": + add = "."; + break; + case ".": + add = "~."; + break; + case "~": + add = "~~"; + break; + default: + const charCode = str.charCodeAt(i); + if ( + (charCode >= 97 && charCode <= 122) || // a-z + (charCode >= 48 && charCode <= 57) || // 0-9 + char === "-" + ) { + add = char; + } else { + // TODO behavior for unicode doesn't match +wood's, + // but we can probably get away with that for now. + add = "~" + charCode.toString(16) + "."; + } + } + out = out + add; + } + return "~." + out; +} + +export const buntPost = (): Post => ({ + author: '', + contents: [], + hash: null, + index: '', + signatures: [], + 'time-sent': 0 +}); + +export function makeNodeMap(posts: Post[]): Record { + const nodes: Record = {}; + posts.forEach((p: Post) => { + nodes[String(p.index)] = { children: null, post: p }; + }); + return nodes; +} diff --git a/gear/lib/types.ts b/gear/lib/types.ts new file mode 100644 index 00000000..4c701ea9 --- /dev/null +++ b/gear/lib/types.ts @@ -0,0 +1,67 @@ +/** + * Martian embassy + */ + +import { BigIntOrderedMap } from "./BigIntOrderedMap"; + +// an urbit style path rendered as string +export type Path = string; + +// patp including leading sig +export type Patp = string; + +// patp excluding leading sig +export type PatpNoSig = string; + +// @uvH encoded string +export type Serial = string; + +// jug from hoon +export type Jug = Map>; + +// name of app +export type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph' | 'groups'; + +export type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; + +export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; + + +export type SetElement = S extends Set<(infer T)> ? T : never; +export type MapKey = M extends Map<(infer K), any> ? K : never; +export type MapValue = M extends Map ? V : never; + +/** + * Turns sets into arrays and maps into objects so we can send them over the wire + */ +export type Enc = + S extends Set ? + Enc>[] : + S extends Map ? + { [s: string]: Enc> } : + S extends object ? + { [K in keyof S]: Enc } : + S extends BigIntOrderedMap ? + { [index: string]: T } : + S; + +export type Mark = string; + +export interface Poke { + ship?: string; // This should be handled by the http library, but is part of the spec + app: string; + mark: Mark; + json: Action; +} + +export interface Scry { + app: string; + path: string; +} + +export interface Thread { + inputMark: string; + outputMark: string; + threadName: string; + body: Action; +} diff --git a/gear/metadata/index.ts b/gear/metadata/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/metadata/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/metadata/lib.ts b/gear/metadata/lib.ts new file mode 100644 index 00000000..ace81e8a --- /dev/null +++ b/gear/metadata/lib.ts @@ -0,0 +1,99 @@ +import { Path, Poke, uxToHex, PatpNoSig } from '../lib'; +import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types'; + +export const METADATA_UPDATE_VERSION = 2; + +export const metadataAction = (data: T, version: number = METADATA_UPDATE_VERSION): Poke => ({ + app: 'metadata-push-hook', + mark: `metadata-update-${version}`, + json: data +}); + +export const add = ( + ship: PatpNoSig, + appName: MdAppName, + resource: Path, + group: Path, + title: string, + description: string, + dateCreated: string, + color: string, + moduleName: string +): Poke => metadataAction({ + add: { + group, + resource: { + resource, + 'app-name': appName + }, + metadata: { + title, + description, + color, + 'date-created': dateCreated, + creator: `~${ship}`, + config: { graph: moduleName }, + picture: '', + hidden: false, + preview: false, + vip: '' + } + } +}); + +export { add as metadataAdd }; + +export const remove = ( + appName: MdAppName, + resource: string, + group: string +): Poke => metadataAction({ + remove: { + group, + resource: { + resource, + 'app-name': appName + } + } +}); + +export { remove as metadataRemove }; + +export const edit = ( + association: Association, + edit: MetadataEditField +): Poke => metadataAction({ + edit: { + group: association.group, + resource: { + resource: association.resource, + 'app-name': association['app-name'] + }, + edit + } +}); + +export { edit as metadataEdit }; + +/** + * @deprecated use {@link edit} instead + */ +export const update = ( + association: Association, + newMetadata: Partial +): Poke => { + const metadata = { ...association.metadata, ...newMetadata }; + metadata.color = uxToHex(metadata.color); + return metadataAction({ + add: { + group: association.group, + resource: { + resource: association.resource, + 'app-name': association['app-name'] + }, + metadata + } + }); +}; + +export { update as metadataUpdate }; diff --git a/gear/metadata/types.ts b/gear/metadata/types.ts new file mode 100644 index 00000000..828c83b1 --- /dev/null +++ b/gear/metadata/types.ts @@ -0,0 +1,101 @@ +import { Path, Patp } from '../lib'; + +export type MdAppName = 'groups' | 'graph'; + +export type MetadataUpdate = + MetadataUpdateInitial +| MetadataUpdateAdd +| MetadataUpdateUpdate +| MetadataUpdateRemove +| MetadataUpdateEdit; + +export interface MetadataUpdateInitial { + associations: ResourceAssociations; +} + +export type ResourceAssociations = { + [p in Path]: Association; +} + +export type MetadataUpdateAdd = { + add: AssociationPoke; +} + +export type MetadataUpdateUpdate = { + update: AssociationPoke; +} + +export interface MetadataUpdateEdit { + edit: { + resource: MdResource; + group: string; + edit: MetadataEditField; + } +} + +export type MetadataEditField = Partial>; + +export type MetadataUpdateRemove = { + remove: { + resource: MdResource; + group: string; + } +} + +export interface MdResource { + resource: string; + 'app-name': MdAppName; +} + +export interface MetadataUpdatePreview { + group: string; + channels: Associations; + 'channel-count': number; + members: number; + metadata: Metadata; +} + +export type Associations = { + groups: AppAssociations + graph: AppAssociations; +} + +export type AppAssociations = { + [p in Path]: Association; +} + +export type Association = MdResource & { + group: Path; + metadata: Metadata; +}; + +export interface AssociationPoke { + group: Path; + resource: MdResource; + metadata: Metadata; +} + +export interface Metadata { + color: string; + creator: Patp; + 'date-created': string; + description: string; + title: string; + config: C; + hidden: boolean; + picture: string; + preview: boolean; + vip: PermVariation; +} + +export type MetadataConfig = GroupConfig | GraphConfig; + +export interface GraphConfig { + graph: string; +} + +export interface GroupConfig { + group: undefined | {} | MdResource; +} + +export type PermVariation = '' | ' ' | 'reader-comments' | 'member-metadata' | 'host-feed' | 'admin-feed'; diff --git a/gear/settings/index.ts b/gear/settings/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/gear/settings/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/gear/settings/lib.ts b/gear/settings/lib.ts new file mode 100644 index 00000000..94fca9d5 --- /dev/null +++ b/gear/settings/lib.ts @@ -0,0 +1,78 @@ +import { Poke, Scry } from '../lib'; +import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types'; + +export const action = (data: T): Poke => ({ + app: 'settings-store', + mark: 'settings-event', + json: data +}); + +export const putBucket = ( + desk: string, + key: Key, + bucket: Bucket +): Poke => action({ + 'put-bucket': { + desk, + 'bucket-key': key, + 'bucket': bucket + } +}); + +export const delBucket = ( + desk: string, + key: Key +): Poke => action({ + 'del-bucket': { + desk, + 'bucket-key': key + } +}); + +export const putEntry = ( + desk: string, + bucket: Key, + key: Key, + value: Value +): Poke => action({ + 'put-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key, + value: value + } +}); + +export const delEntry = ( + desk: string, + bucket: Key, + key: Key +): Poke => action({ + 'del-entry': { + desk, + 'bucket-key': bucket, + 'entry-key': key + } +}); + +export const getAll: Scry = { + app: 'settings-store', + path: '/all' +}; + +export const getBucket = (desk: string, bucket: string) => ({ + app: 'settings-store', + path: `/bucket/${bucket}` +}); + +export const getEntry = (desk: string, bucket: string, entry: string) => ({ + app: 'settings-store', + path: `/entry/${desk}/${bucket}/${entry}` +}); + +export const getDeskSettings = (desk: string) => ({ + app: 'settings-store', + path: `/desk/${desk}` +}); + +export * from './types'; diff --git a/gear/settings/types.ts b/gear/settings/types.ts new file mode 100644 index 00000000..af02c70b --- /dev/null +++ b/gear/settings/types.ts @@ -0,0 +1,64 @@ +export type Key = string; +export type Value = string | string[] | boolean | number; +export type Bucket = { [key: string]: Value; }; +export type DeskSettings = { [bucket: string]: Bucket; }; +export type Settings = { [desk: string]: Settings; } + +export interface PutBucket { + 'put-bucket': { + desk: string; + 'bucket-key': Key; + 'bucket': Bucket; + }; +} + +export interface DelBucket { + 'del-bucket': { + desk: string; + 'bucket-key': Key; + }; +} + +export interface PutEntry { + 'put-entry': { + 'bucket-key': Key; + 'entry-key': Key; + 'value'?: Value; + }; +} + +export interface DelEntry { + 'del-entry': { + desk: string; + 'bucket-key': Key; + 'entry-key': Key; + }; +} + +export interface AllData { + 'all': Settings; +} + +export interface DeskData { + desk: DeskSettings; +} + +export interface BucketData { + 'bucket': Bucket; +} + +export interface EntryData { + 'entry': Value; +} + +export type SettingsUpdate = + | PutBucket + | DelBucket + | PutEntry + | DelEntry; + +export type SettingsData = + | AllData + | BucketData + | EntryData + | DeskData; diff --git a/gear/storage/index.ts b/gear/storage/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/gear/storage/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/gear/storage/lib.ts b/gear/storage/lib.ts new file mode 100644 index 00000000..165789ea --- /dev/null +++ b/gear/storage/lib.ts @@ -0,0 +1,47 @@ +import { Poke } from '../lib/types'; +import { StorageUpdate, StorageUpdateCurrentBucket, StorageUpdateAddBucket, StorageUpdateRemoveBucket, StorageUpdateEndpoint, StorageUpdateAccessKeyId, StorageUpdateSecretAccessKey } from './types'; + +const s3Action = ( + data: any +): Poke => ({ + app: 's3-store', + mark: 's3-action', + json: data +}); + +export const setCurrentBucket = ( + bucket: string +): Poke => s3Action({ + 'set-current-bucket': bucket +}); + +export const addBucket = ( + bucket: string +): Poke => s3Action({ + 'add-bucket': bucket +}); + +export const removeBucket = ( + bucket: string +): Poke => s3Action({ + 'remove-bucket': bucket +}); + +export const setEndpoint = ( + endpoint: string +): Poke => s3Action({ + 'set-endpoint': endpoint +}); + +export const setAccessKeyId = ( + accessKeyId: string +): Poke => s3Action({ + 'set-access-key-id': accessKeyId +}); + +export const setSecretAccessKey = ( + secretAccessKey: string +): Poke => s3Action({ + 'set-secret-access-key': secretAccessKey +}); + diff --git a/gear/storage/types.ts b/gear/storage/types.ts new file mode 100644 index 00000000..6c5cb93e --- /dev/null +++ b/gear/storage/types.ts @@ -0,0 +1,60 @@ +export interface StorageCredentials { + endpoint: string; + accessKeyId: string; + secretAccessKey: string; +} + +export interface StorageConfiguration { + buckets: Set; + currentBucket: string; +} + +export interface StorageState { + configuration: StorageConfiguration; + credentials: StorageCredentials | null; +} + +export interface StorageUpdateCredentials { + credentials: StorageCredentials; +} + +export interface StorageUpdateConfiguration { + configuration: { + buckets: string[]; + currentBucket: string; + } +} + +export interface StorageUpdateCurrentBucket { + setCurrentBucket: string; +} + +export interface StorageUpdateAddBucket { + addBucket: string; +} + +export interface StorageUpdateRemoveBucket { + removeBucket: string; +} + +export interface StorageUpdateEndpoint { + setEndpoint: string; +} + +export interface StorageUpdateAccessKeyId { + setAccessKeyId: string; +} + +export interface StorageUpdateSecretAccessKey { + setSecretAccessKey: string; +} + +export type StorageUpdate = + StorageUpdateCredentials +| StorageUpdateConfiguration +| StorageUpdateCurrentBucket +| StorageUpdateAddBucket +| StorageUpdateRemoveBucket +| StorageUpdateEndpoint +| StorageUpdateAccessKeyId +| StorageUpdateSecretAccessKey; From dc4b752adccdee3071933dcfe32a91ad5f367dbd Mon Sep 17 00:00:00 2001 From: tomholford Date: Fri, 19 May 2023 14:30:06 -0700 Subject: [PATCH 2/8] devex: move to ui/, remove graph and lib also uninstall @urbit/api --- gear/graph/lib.ts | 534 ----------------------- gear/graph/types.ts | 94 ---- gear/lib/BigIntArrayOrderedMap.ts | 152 ------- gear/lib/BigIntOrderedMap.ts | 117 ----- gear/lib/index.ts | 2 - gear/lib/lib.ts | 259 ----------- gear/lib/types.ts | 67 --- gear/storage/index.ts | 2 - {gear => ui/gear}/contacts/index.ts | 0 {gear => ui/gear}/contacts/lib.ts | 0 {gear => ui/gear}/contacts/types.ts | 0 {gear => ui/gear}/deps.d.ts | 0 {gear => ui/gear}/docket/index.ts | 0 {gear => ui/gear}/docket/lib.ts | 0 {gear => ui/gear}/docket/types.ts | 0 {gear => ui/gear}/groups/index.ts | 0 {gear => ui/gear}/groups/lib.ts | 0 {gear => ui/gear}/groups/types.ts | 0 {gear => ui/gear}/groups/update.ts | 0 {gear => ui/gear}/groups/view.ts | 0 {gear => ui/gear}/hark/index.ts | 0 {gear => ui/gear}/hark/lib.ts | 0 {gear => ui/gear}/hark/types.ts | 0 {gear => ui/gear}/hood/index.ts | 0 {gear => ui/gear}/hood/lib.ts | 0 {gear => ui/gear}/hood/types.ts | 0 {gear => ui/gear}/index.ts | 6 +- {gear => ui/gear}/invite/index.ts | 0 {gear => ui/gear}/invite/lib.ts | 0 {gear => ui/gear}/invite/types.ts | 0 {gear => ui/gear}/metadata/index.ts | 0 {gear => ui/gear}/metadata/lib.ts | 0 {gear => ui/gear}/metadata/types.ts | 0 {gear => ui/gear}/settings/index.ts | 0 {gear => ui/gear}/settings/lib.ts | 0 {gear => ui/gear}/settings/types.ts | 0 {gear/graph => ui/gear/storage}/index.ts | 0 {gear => ui/gear}/storage/lib.ts | 0 {gear => ui/gear}/storage/types.ts | 0 ui/package-lock.json | 25 -- ui/package.json | 1 - ui/src/state/storage/index.ts | 4 +- 42 files changed, 4 insertions(+), 1259 deletions(-) delete mode 100644 gear/graph/lib.ts delete mode 100644 gear/graph/types.ts delete mode 100644 gear/lib/BigIntArrayOrderedMap.ts delete mode 100644 gear/lib/BigIntOrderedMap.ts delete mode 100644 gear/lib/index.ts delete mode 100644 gear/lib/lib.ts delete mode 100644 gear/lib/types.ts delete mode 100644 gear/storage/index.ts rename {gear => ui/gear}/contacts/index.ts (100%) rename {gear => ui/gear}/contacts/lib.ts (100%) rename {gear => ui/gear}/contacts/types.ts (100%) rename {gear => ui/gear}/deps.d.ts (100%) rename {gear => ui/gear}/docket/index.ts (100%) rename {gear => ui/gear}/docket/lib.ts (100%) rename {gear => ui/gear}/docket/types.ts (100%) rename {gear => ui/gear}/groups/index.ts (100%) rename {gear => ui/gear}/groups/lib.ts (100%) rename {gear => ui/gear}/groups/types.ts (100%) rename {gear => ui/gear}/groups/update.ts (100%) rename {gear => ui/gear}/groups/view.ts (100%) rename {gear => ui/gear}/hark/index.ts (100%) rename {gear => ui/gear}/hark/lib.ts (100%) rename {gear => ui/gear}/hark/types.ts (100%) rename {gear => ui/gear}/hood/index.ts (100%) rename {gear => ui/gear}/hood/lib.ts (100%) rename {gear => ui/gear}/hood/types.ts (100%) rename {gear => ui/gear}/index.ts (87%) rename {gear => ui/gear}/invite/index.ts (100%) rename {gear => ui/gear}/invite/lib.ts (100%) rename {gear => ui/gear}/invite/types.ts (100%) rename {gear => ui/gear}/metadata/index.ts (100%) rename {gear => ui/gear}/metadata/lib.ts (100%) rename {gear => ui/gear}/metadata/types.ts (100%) rename {gear => ui/gear}/settings/index.ts (100%) rename {gear => ui/gear}/settings/lib.ts (100%) rename {gear => ui/gear}/settings/types.ts (100%) rename {gear/graph => ui/gear/storage}/index.ts (100%) rename {gear => ui/gear}/storage/lib.ts (100%) rename {gear => ui/gear}/storage/types.ts (100%) diff --git a/gear/graph/lib.ts b/gear/graph/lib.ts deleted file mode 100644 index ce187df6..00000000 --- a/gear/graph/lib.ts +++ /dev/null @@ -1,534 +0,0 @@ -import { GroupPolicy, makeResource, Resource, resourceFromPath } from '../groups'; - -import { decToUd, deSig, unixToDa, Scry } from '../lib'; -import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; -import { Content, GraphChildrenPoke, GraphNode, GraphNodePoke, Post } from './types'; -import { patp2dec } from 'urbit-ob'; - -export const GRAPH_UPDATE_VERSION = 3; - -export const createBlankNodeWithChildPost = ( - ship: PatpNoSig, - parentIndex = '', - childIndex = '', - contents: Content[] -): GraphNodePoke => { - const date = unixToDa(Date.now()).toString(); - const nodeIndex = parentIndex + '/' + date; - - const childGraph: GraphChildrenPoke = {}; - childGraph[childIndex] = { - post: { - author: `~${ship}`, - index: nodeIndex + '/' + childIndex, - 'time-sent': Date.now(), - contents, - hash: null, - signatures: [] - }, - children: null - }; - - return { - post: { - author: `~${ship}`, - index: nodeIndex, - 'time-sent': Date.now(), - contents: [], - hash: null, - signatures: [] - }, - children: childGraph - }; -}; - -export const markPending = (nodes: any): any => { - Object.keys(nodes).forEach((key) => { - nodes[key].post.author = deSig(nodes[key].post.author); - nodes[key].post.pending = true; - if (nodes[key].children) { - nodes[key].children = markPending(nodes[key].children); - } - }); - return nodes; -}; - -export const createPost = ( - ship: PatpNoSig, - contents: Content[], - parentIndex = '', - childIndex = 'DATE_PLACEHOLDER' -): Post => { - if (childIndex === 'DATE_PLACEHOLDER') { - childIndex = unixToDa(Date.now()).toString(); - } - return { - author: `~${ship}`, - index: parentIndex + '/' + childIndex, - 'time-sent': Date.now(), - contents, - hash: null, - signatures: [] - }; -}; - -function moduleToMark(mod: string): string | undefined { - if(mod === 'link') { - return 'graph-validator-link'; - } - if(mod === 'publish') { - return 'graph-validator-publish'; - } - if(mod === 'chat') { - return 'graph-validator-chat'; - } - return undefined; -} - -const storeAction = (data: T, version: number = GRAPH_UPDATE_VERSION): Poke => ({ - app: 'graph-store', - mark: `graph-update-${version}`, - json: data -}); - -export { storeAction as graphStoreAction }; - -const viewAction = (threadName: string, action: T): Thread => ({ - inputMark: 'graph-view-action', - outputMark: 'json', - threadName, - body: action -}); - -export { viewAction as graphViewAction }; - -const hookAction = (data: T, version: number = GRAPH_UPDATE_VERSION): Poke => ({ - app: 'graph-push-hook', - mark: `graph-update-${version}`, - json: data -}); - -const dmAction = (data: T): Poke => ({ - app: 'dm-hook', - mark: 'dm-hook-action', - json: data -}); - -export { hookAction as graphHookAction }; - -export const createManagedGraph = ( - ship: PatpNoSig, - name: string, - title: string, - description: string, - group: Path, - mod: string -): Thread => { - const associated = { group: resourceFromPath(group) }; - const resource = makeResource(`~${ship}`, name); - - return viewAction('graph-create', { - create: { - resource, - title, - description, - associated, - module: mod, - mark: moduleToMark(mod) - } - }); -}; - -export const createUnmanagedGraph = ( - ship: PatpNoSig, - name: string, - title: string, - description: string, - policy: Enc, - mod: string -): Thread => viewAction('graph-create', { - create: { - resource: makeResource(`~${ship}`, name), - title, - description, - associated: { policy }, - module: mod, - mark: moduleToMark(mod) - } -}); - -export const joinGraph = ( - ship: Patp, - name: string -): Thread => viewAction('graph-join', { - join: { - resource: makeResource(ship, name), - ship - } -}); - -export const deleteGraph = ( - ship: PatpNoSig, - name: string -): Thread => viewAction('graph-delete', { - 'delete': { - resource: makeResource(`~${ship}`, name) - } -}); - -export const leaveGraph = ( - ship: Patp, - name: string -): Thread => viewAction('graph-leave', { - 'leave': { - resource: makeResource(ship, name) - } -}); - -export const groupifyGraph = ( - ship: Patp, - name: string, - toPath?: string -): Thread => { - const resource = makeResource(ship, name); - const to = toPath && resourceFromPath(toPath); - - return viewAction('graph-groupify', { - groupify: { - resource, - to - } - }); -}; - -export const evalCord = ( - cord: string -): Thread => { - return ({ - inputMark: 'graph-view-action', - outputMark: 'tang', - threadName: 'graph-eval', - body: { - eval: cord - } - }); -}; - -export const addGraph = ( - ship: Patp, - name: string, - graph: any, - mark: any -): Poke => { - return storeAction({ - 'add-graph': { - resource: { ship, name }, - graph, - mark - } - }); -}; - -export const addNodes = ( - ship: Patp, - name: string, - nodes: Object -): Thread => ({ - inputMark: `graph-update-${GRAPH_UPDATE_VERSION}`, - outputMark: 'graph-view-action', - threadName: 'graph-add-nodes', - body: { - 'add-nodes': { - resource: { ship, name }, - nodes - } - } -}); - -export const addPost = ( - ship: Patp, - name: string, - post: Post -): Thread => { - const nodes: Record = {}; - nodes[post.index] = { - post, - children: null - }; - return addNodes(ship, name, nodes); -}; - -export const addNode = ( - ship: Patp, - name: string, - node: GraphNodePoke -): Thread => { - const nodes: Record = {}; - nodes[node.post.index] = node; - - return addNodes(ship, name, nodes); -}; - -export const createGroupFeed = ( - group: Resource, - vip: any = '' -): Thread => ({ - inputMark: 'graph-view-action', - outputMark: 'resource', - threadName: 'graph-create-group-feed', - body: { - 'create-group-feed': { - resource: group, - vip - } - } -}); - -export const disableGroupFeed = ( - group: Resource -): Thread => ({ - inputMark: 'graph-view-action', - outputMark: 'json', - threadName: 'graph-disable-group-feed', - body: { - 'disable-group-feed': { - resource: group - } - } -}); - -/** - * Set dm-hook to screen new DMs or not - * - */ -export const setScreen = (screen: boolean): Poke => dmAction({ screen }); - -/** - * Accept a pending DM request - * - * @param ship the ship to accept - */ -export const acceptDm = (ship: string) => dmAction({ - accept: ship -}); - -/** - * Decline a pending DM request - * - * @param ship the ship to accept - */ -export const declineDm = (ship: string) => dmAction({ - decline: ship -}); - -/** - * Remove posts from a set of indices - * - */ -export const removePosts = ( - ship: Patp, - name: string, - indices: string[] -): Poke => hookAction({ - 'remove-posts': { - resource: { ship, name }, - indices - } -}); - -/** - * Remove a DM message from our inbox - * - * @remarks - * This does not remove the message from the recipients inbox - */ -export const removeDmMessage = ( - our: Patp, - index: string -): Poke => ({ - app: 'graph-store', - mark: `graph-update-${GRAPH_UPDATE_VERSION}`, - json: { - 'remove-posts': { - resource: { ship: our, name: 'dm-inbox' }, - indices: [index] - } - } -}); - -/** - * Send a DM to a ship - * - * @param our sender - * @param ship recipient - * @param contents contents of message - */ -export const addDmMessage = (our: PatpNoSig, ship: Patp, contents: Content[]): Poke => { - const post = createPost(our, contents, `/${patp2dec(ship)}`); - const node: GraphNode = { - post, - children: null - }; - return { - app: 'dm-hook', - mark: `graph-update-${GRAPH_UPDATE_VERSION}`, - json: { - 'add-nodes': { - resource: { ship: `~${our}`, name: 'dm-inbox' }, - nodes: { - [post.index]: node - } - } - } - }; -}; - -const encodeIndex = (idx: string) => idx.split('/').map(decToUd).join('/'); - -/** - * Fetch all graph keys - */ -export const getKeys = (): Scry => ({ - app: 'graph-store', - path: '/keys' -}); - -/** - * Fetch newest (larger keys) nodes in a graph under some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getNewest = ( - ship: string, - name: string, - count: number, - index = '' -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings` + - `/newest/lone/${count}${encodeIndex(index)}` -}); - -/** - * Fetch nodes in a graph that are older (key is smaller) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getOlderSiblings = ( - ship: string, - name: string, - count: number, - index: string -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings/older/lone/${count}${encodeIndex(index)}` -}); - -/** - * Fetch nodes in a graph that are younger (key is larger) and direct - * siblings of some index - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param index index to query - */ -export const getYoungerSiblings = ( - ship: string, - name: string, - count: number, - index: string -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings/newer/lone/${count}${encodeIndex(index)}` -}); - -/** - * Fetch all nodes in a graph under some index, without loading children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - */ -export const getShallowChildren = (ship: string, name: string, index = '') => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/children/lone/~/~${encodeIndex(index)}` -}); - -/** - * Fetch newest nodes in a graph as a flat map, including children, - * optionally starting at a specified key - * - * @param ship ship of graph - * @param name name of graph - * @param count number of nodes to load - * @param start key to start at - * - */ -export const getDeepOlderThan = ( - ship: string, - name: string, - count: number, - start = '' -) => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/siblings` + - `/${start.length > 0 ? 'older' : 'newest'}` + - `/kith/${count}${encodeIndex(start)}` -}); - -/** - * Fetch a flat map of a nodes ancestors and firstborn children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export const getFirstborn = ( - ship: string, - name: string, - index: string -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/firstborn${encodeIndex(index)}` -}); - -/** - * Fetch a single node, and all it's children - * - * @param ship ship of graph - * @param name name of graph - * @param index index to query - * - */ -export const getNode = ( - ship: string, - name: string, - index: string -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}/node/index/kith${encodeIndex(index)}` -}); - -/** - * Fetch entire graph - * - * @param ship ship of graph - * @param name name of graph - * - */ -export const getGraph = ( - ship: string, - name: string -): Scry => ({ - app: 'graph-store', - path: `/graph/${ship}/${name}` -}); diff --git a/gear/graph/types.ts b/gear/graph/types.ts deleted file mode 100644 index 2e8816a3..00000000 --- a/gear/graph/types.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Patp } from '../lib'; -import { BigIntOrderedMap } from '../lib/BigIntOrderedMap'; -import { BigIntArrayOrderedMap } from '../lib/BigIntArrayOrderedMap'; - -export interface TextContent { - text: string; -} -export interface UrlContent { - url: string; -} -export interface CodeContent { - code: { - expression: string; - output: string[] | undefined; - } -} - -export interface ReferenceContent { - reference: AppReference | GraphReference | GroupReference; -} - -export interface GraphReference { - graph: { - graph: string; - group: string; - index: string; - } -} - -export interface GroupReference { - group: string; -} - -export interface AppReference { - app: { - ship: string; - desk: string; - path: string; - } -} - -export interface MentionContent { - mention: string; - emphasis?: 'bold' | 'italic'; -} -export type Content = - | TextContent - | UrlContent - | CodeContent - | ReferenceContent - | MentionContent; - -export interface Post { - author: Patp; - contents: Content[]; - hash: string | null; - index: string; - pending?: boolean; - signatures: string[]; - 'time-sent': number; -} - -export interface GraphNodePoke { - post: Post; - children: GraphChildrenPoke | null; -} - -export interface GraphChildrenPoke { - [k: string]: GraphNodePoke; -} - -export interface GraphNode { - children: Graph | null; - post: Post; -} - -export interface FlatGraphNode { - children: null; - post: Post; -} - -export type Graph = BigIntOrderedMap; - -export type Graphs = { [rid: string]: Graph }; - -export type FlatGraph = BigIntArrayOrderedMap; - -export type FlatGraphs = { [rid: string]: FlatGraph }; - -export type ThreadGraphs = { - [rid: string]: { - [index: string]: FlatGraph; - } -}; diff --git a/gear/lib/BigIntArrayOrderedMap.ts b/gear/lib/BigIntArrayOrderedMap.ts deleted file mode 100644 index 79e998c5..00000000 --- a/gear/lib/BigIntArrayOrderedMap.ts +++ /dev/null @@ -1,152 +0,0 @@ -import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; -import bigInt, { BigInteger } from 'big-integer'; - -setAutoFreeze(false); - -enablePatches(); - -export function stringToArr(str: string) { - return str.split('/').slice(1).map((ind) => { - return bigInt(ind); - }); -} - -export function arrToString(arr: BigInteger[]) { - let string = ''; - arr.forEach((key) => { - string = string + `/${key.toString()}`; - }); - return string; -} - -function sorted(a: BigInteger[], b: BigInteger[], reversed = false) { - const getSort = sortBigIntArr(a, b); - if (reversed) { - return getSort * -1; - } else { - return getSort; - } -} - -export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) { - const aLen = a.length; - const bLen = b.length; - - const aCop = a.slice(0); - const bCop = b.slice(0); - aCop.reverse(); - bCop.reverse(); - - let i = 0; - while (i < aLen && i < bLen) { - if (aCop[i].lt(bCop[i])) { - return 1; - } else if (aCop[i].gt(bCop[i])) { - return -1; - } else { - i++; - } - } - - return bLen - aLen; -} - -export class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { - root: Record = {} - cachedIter: [BigInteger[], V][] | null = null; - [immerable] = true; - reversed = false; - - constructor(items: [BigInteger[], V][] = [], reversed = false) { - items.forEach(([key, val]) => { - this.set(key, val); - }); - this.reversed = reversed; - } - - get size() { - return Object.keys(this.root).length; - } - - get(key: BigInteger[]) { - return this.root[arrToString(key)] ?? null; - } - - gas(items: [BigInteger[], V][]) { - return produce(this, (draft) => { - items.forEach(([key, value]) => { - draft.root[arrToString(key)] = castDraft(value); - }); - draft.generateCachedIter(); - }, - (patches) => { - // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); - }); - } - - set(key: BigInteger[], value: V) { - return produce(this, (draft) => { - draft.root[arrToString(key)] = castDraft(value); - draft.cachedIter = null; - }); - } - - clear() { - return produce(this, (draft) => { - draft.cachedIter = []; - draft.root = {}; - }); - } - - has(key: BigInteger[]) { - return arrToString(key) in this.root; - } - - delete(key: BigInteger[]) { - const result = produce(this, (draft) => { - delete draft.root[arrToString(key)]; - draft.cachedIter = null; - }); - return result; - } - - [Symbol.iterator](): IterableIterator<[BigInteger[], V]> { - let idx = 0; - const result = this.generateCachedIter(); - return { - [Symbol.iterator]: this[Symbol.iterator], - next: (): IteratorResult<[BigInteger[], V]> => { - if (idx < result.length) { - return { value: result[idx++], done: false }; - } - return { done: true, value: null }; - } - }; - } - - peekLargest() { - const sorted = Array.from(this); - return sorted[0] as [BigInteger[], V] | null; - } - - peekSmallest() { - const sorted = Array.from(this); - return sorted[sorted.length - 1] as [BigInteger[], V] | null; - } - - keys() { - return Array.from(this).map(([k,v]) => k); - } - - generateCachedIter() { - if(this.cachedIter) { - return [...this.cachedIter]; - } - const result = Object.keys(this.root).map((key) => { - return [stringToArr(key), this.root[key]] as [BigInteger[], V]; - }).sort(([a], [b]) => sorted(a, b, this.reversed)); - this.cachedIter = result; - return [...result]; - } -} - diff --git a/gear/lib/BigIntOrderedMap.ts b/gear/lib/BigIntOrderedMap.ts deleted file mode 100644 index 5e3661d1..00000000 --- a/gear/lib/BigIntOrderedMap.ts +++ /dev/null @@ -1,117 +0,0 @@ -import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; -import bigInt, { BigInteger } from 'big-integer'; - -setAutoFreeze(false); - -enablePatches(); - -function sortBigInt(a: BigInteger, b: BigInteger) { - if (a.lt(b)) { - return 1; - } else if (a.eq(b)) { - return 0; - } else { - return -1; - } -} -export class BigIntOrderedMap implements Iterable<[BigInteger, V]> { - root: Record = {} - cachedIter: [BigInteger, V][] | null = null; - [immerable] = true; - - constructor(items: [BigInteger, V][] = []) { - items.forEach(([key, val]) => { - this.set(key, val); - }); - } - - get size() { - if(this.cachedIter) { - return this.cachedIter.length; - } - return this.generateCachedIter().length; - } - - get(key: BigInteger) { - return this.root[key.toString()] ?? null; - } - - gas(items: [BigInteger, V][]) { - return produce(this, (draft) => { - items.forEach(([key, value]) => { - draft.root[key.toString()] = castDraft(value); - }); - draft.cachedIter = null; - }, - (patches) => { - // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); - }); - } - - set(key: BigInteger, value: V) { - return produce(this, (draft) => { - draft.root[key.toString()] = castDraft(value); - draft.cachedIter = null; - }); - } - - clear() { - return produce(this, (draft) => { - draft.cachedIter = []; - draft.root = {}; - }); - } - - has(key: BigInteger) { - return key.toString() in this.root; - } - - delete(key: BigInteger) { - const result = produce(this, (draft) => { - delete draft.root[key.toString()]; - draft.cachedIter = null; - }); - return result; - } - - [Symbol.iterator](): IterableIterator<[BigInteger, V]> { - let idx = 0; - const result = this.generateCachedIter(); - return { - [Symbol.iterator]: this[Symbol.iterator], - next: (): IteratorResult<[BigInteger, V]> => { - if (idx < result.length) { - return { value: result[idx++], done: false }; - } - return { done: true, value: null }; - } - }; - } - - peekLargest() { - const sorted = Array.from(this); - return sorted[0] as [BigInteger, V] | null; - } - - peekSmallest() { - const sorted = Array.from(this); - return sorted[sorted.length - 1] as [BigInteger, V] | null; - } - - keys() { - return Array.from(this).map(([k,v]) => k); - } - - generateCachedIter() { - if(this.cachedIter) { - return [...this.cachedIter]; - } - const result = Object.keys(this.root).map((key) => { - const num = bigInt(key); - return [num, this.root[key]] as [BigInteger, V]; - }).sort(([a], [b]) => sortBigInt(a,b)); - this.cachedIter = result; - return [...result]; - } -} - diff --git a/gear/lib/index.ts b/gear/lib/index.ts deleted file mode 100644 index 4fed660f..00000000 --- a/gear/lib/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; \ No newline at end of file diff --git a/gear/lib/lib.ts b/gear/lib/lib.ts deleted file mode 100644 index c57d0a25..00000000 --- a/gear/lib/lib.ts +++ /dev/null @@ -1,259 +0,0 @@ -import bigInt, { BigInteger } from "big-integer"; - -import { Resource } from "../groups/types"; -import { Post, GraphNode } from "../graph/types"; - -const DA_UNIX_EPOCH = bigInt("170141184475152167957503069145530368000"); // `@ud` ~1970.1.1 - -const DA_SECOND = bigInt("18446744073709551616"); // `@ud` ~s1 - -function chunk(arr: T[], size: number): T[][] { - let chunk: T[] = []; - let newArray = [chunk]; - - for (let i = 0;i < arr.length;i++) { - if (chunk.length < size) { - chunk.push(arr[i]) - } else { - chunk = [arr[i]] - newArray.push(chunk) - } - } - - return newArray; -} - -function dropWhile(arr: T[], pred: (x: T) => boolean): T[] { - const newArray = arr.slice(); - - for (const item of arr) { - if (pred(item)) { - newArray.shift(); - } else { - return newArray; - } - } - - return newArray; -} - -/** - * Given a bigint representing an urbit date, returns a unix timestamp. - * - * @param {BigInteger} da The urbit date - * - * @return {number} The unix timestamp - */ -export function daToUnix(da: BigInteger): number { - // ported from +time:enjs:format in hoon.hoon - const offset = DA_SECOND.divide(bigInt(2000)); - const epochAdjusted = offset.add(da.subtract(DA_UNIX_EPOCH)); - - return Math.round( - epochAdjusted.multiply(bigInt(1000)).divide(DA_SECOND).toJSNumber() - ); -} - -/** - * Given a unix timestamp, returns a bigint representing an urbit date - * - * @param {number} unix The unix timestamp - * - * @return {BigInteger} The urbit date - */ -export function unixToDa(unix: number): BigInteger { - const timeSinceEpoch = bigInt(unix).multiply(DA_SECOND).divide(bigInt(1000)); - return DA_UNIX_EPOCH.add(timeSinceEpoch); -} - - -export function makePatDa(patda: string): BigInteger { - return bigInt(udToDec(patda)); -} - -export function udToDec(ud: string): string { - return ud.replace(/\./g, ""); -} - -export function decToUd(str: string): string { - const transform = chunk(str.split('').reverse(), 3) - .map(group => group.reverse().join('')) - .reverse() - .join('.') - return transform.replace(/^[0\.]+/g, ''); -} - -export function resourceAsPath(resource: Resource): string { - const { name, ship } = resource; - return `/ship/~${ship}/${name}`; -} - -export function uuid(): string { - let str = "0v"; - str += Math.ceil(Math.random() * 8) + "."; - for (let i = 0; i < 5; i++) { - let _str = Math.ceil(Math.random() * 10000000).toString(32); - _str = ("00000" + _str).substr(-5, 5); - str += _str + "."; - } - - return str.slice(0, -1); -} - -/* - Goes from: - ~2018.7.17..23.15.09..5be5 // urbit @da - To: - (javascript Date object) -*/ -export function daToDate(st: string): Date { - const dub = function (n: string) { - return parseInt(n) < 10 ? "0" + parseInt(n) : n.toString(); - }; - const da = st.split(".."); - const bigEnd = da[0].split("."); - const lilEnd = da[1].split("."); - const ds = `${bigEnd[0].slice(1)}-${dub(bigEnd[1])}-${dub(bigEnd[2])}T${dub( - lilEnd[0] - )}:${dub(lilEnd[1])}:${dub(lilEnd[2])}Z`; - return new Date(ds); -} - -/* - Goes from: - (javascript Date object) - To: - ~2018.7.17..23.15.09..5be5 // urbit @da -*/ - -export function dateToDa(d: Date, mil: boolean = false): string { - const fil = function (n: number) { - return n >= 10 ? n : "0" + n; - }; - return ( - `~${d.getUTCFullYear()}.` + - `${d.getUTCMonth() + 1}.` + - `${fil(d.getUTCDate())}..` + - `${fil(d.getUTCHours())}.` + - `${fil(d.getUTCMinutes())}.` + - `${fil(d.getUTCSeconds())}` + - `${mil ? "..0000" : ""}` - ); -} - -export function preSig(ship: string): string { - if (!ship) { - return ''; - } - - if (ship.trim().startsWith('~')) { - return ship.trim(); - } - - return '~'.concat(ship.trim()); -} - -export function deSig(ship: string): string | null { - if (!ship) { - return null; - } - return ship.replace("~", ""); -} - -// trim patps to match dojo, chat-cli -export function cite(ship: string) { - let patp = ship, - shortened = ''; - if (patp === null || patp === '') { - return null; - } - if (patp.startsWith('~')) { - patp = patp.substr(1); - } - // comet - if (patp.length === 56) { - shortened = '~' + patp.slice(0, 6) + '_' + patp.slice(50, 56); - return shortened; - } - // moon - if (patp.length === 27) { - shortened = '~' + patp.slice(14, 20) + '^' + patp.slice(21, 27); - return shortened; - } - return `~${patp}`; -} - - -export function uxToHex(ux: string) { - if (ux.length > 2 && ux.substr(0, 2) === '0x') { - const value = ux.substr(2).replace('.', '').padStart(6, '0'); - return value; - } - - const value = ux.replace('.', '').padStart(6, '0'); - return value; -} - -export const hexToUx = (hex: string): string => { - const nonZeroChars = dropWhile(hex.split(''), y => y === '0'); - const ux = chunk(nonZeroChars.reverse(), 4).map(x => { - return x.reverse().join(''); - }).reverse().join('.') || '0'; - - return `0x${ux}`; -}; - - -// encode the string into @ta-safe format, using logic from +wood. -// for example, 'some Chars!' becomes '~.some.~43.hars~21.' -// -export function stringToTa(str: string): string { - let out = ""; - for (let i = 0; i < str.length; i++) { - const char = str[i]; - let add = ""; - switch (char) { - case " ": - add = "."; - break; - case ".": - add = "~."; - break; - case "~": - add = "~~"; - break; - default: - const charCode = str.charCodeAt(i); - if ( - (charCode >= 97 && charCode <= 122) || // a-z - (charCode >= 48 && charCode <= 57) || // 0-9 - char === "-" - ) { - add = char; - } else { - // TODO behavior for unicode doesn't match +wood's, - // but we can probably get away with that for now. - add = "~" + charCode.toString(16) + "."; - } - } - out = out + add; - } - return "~." + out; -} - -export const buntPost = (): Post => ({ - author: '', - contents: [], - hash: null, - index: '', - signatures: [], - 'time-sent': 0 -}); - -export function makeNodeMap(posts: Post[]): Record { - const nodes: Record = {}; - posts.forEach((p: Post) => { - nodes[String(p.index)] = { children: null, post: p }; - }); - return nodes; -} diff --git a/gear/lib/types.ts b/gear/lib/types.ts deleted file mode 100644 index 4c701ea9..00000000 --- a/gear/lib/types.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Martian embassy - */ - -import { BigIntOrderedMap } from "./BigIntOrderedMap"; - -// an urbit style path rendered as string -export type Path = string; - -// patp including leading sig -export type Patp = string; - -// patp excluding leading sig -export type PatpNoSig = string; - -// @uvH encoded string -export type Serial = string; - -// jug from hoon -export type Jug = Map>; - -// name of app -export type AppName = 'chat' | 'link' | 'contacts' | 'publish' | 'graph' | 'groups'; - -export type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; - -export type Action = 'poke' | 'subscribe' | 'ack' | 'unsubscribe' | 'delete'; - - -export type SetElement = S extends Set<(infer T)> ? T : never; -export type MapKey = M extends Map<(infer K), any> ? K : never; -export type MapValue = M extends Map ? V : never; - -/** - * Turns sets into arrays and maps into objects so we can send them over the wire - */ -export type Enc = - S extends Set ? - Enc>[] : - S extends Map ? - { [s: string]: Enc> } : - S extends object ? - { [K in keyof S]: Enc } : - S extends BigIntOrderedMap ? - { [index: string]: T } : - S; - -export type Mark = string; - -export interface Poke { - ship?: string; // This should be handled by the http library, but is part of the spec - app: string; - mark: Mark; - json: Action; -} - -export interface Scry { - app: string; - path: string; -} - -export interface Thread { - inputMark: string; - outputMark: string; - threadName: string; - body: Action; -} diff --git a/gear/storage/index.ts b/gear/storage/index.ts deleted file mode 100644 index 4fed660f..00000000 --- a/gear/storage/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib'; -export * from './types'; \ No newline at end of file diff --git a/gear/contacts/index.ts b/ui/gear/contacts/index.ts similarity index 100% rename from gear/contacts/index.ts rename to ui/gear/contacts/index.ts diff --git a/gear/contacts/lib.ts b/ui/gear/contacts/lib.ts similarity index 100% rename from gear/contacts/lib.ts rename to ui/gear/contacts/lib.ts diff --git a/gear/contacts/types.ts b/ui/gear/contacts/types.ts similarity index 100% rename from gear/contacts/types.ts rename to ui/gear/contacts/types.ts diff --git a/gear/deps.d.ts b/ui/gear/deps.d.ts similarity index 100% rename from gear/deps.d.ts rename to ui/gear/deps.d.ts diff --git a/gear/docket/index.ts b/ui/gear/docket/index.ts similarity index 100% rename from gear/docket/index.ts rename to ui/gear/docket/index.ts diff --git a/gear/docket/lib.ts b/ui/gear/docket/lib.ts similarity index 100% rename from gear/docket/lib.ts rename to ui/gear/docket/lib.ts diff --git a/gear/docket/types.ts b/ui/gear/docket/types.ts similarity index 100% rename from gear/docket/types.ts rename to ui/gear/docket/types.ts diff --git a/gear/groups/index.ts b/ui/gear/groups/index.ts similarity index 100% rename from gear/groups/index.ts rename to ui/gear/groups/index.ts diff --git a/gear/groups/lib.ts b/ui/gear/groups/lib.ts similarity index 100% rename from gear/groups/lib.ts rename to ui/gear/groups/lib.ts diff --git a/gear/groups/types.ts b/ui/gear/groups/types.ts similarity index 100% rename from gear/groups/types.ts rename to ui/gear/groups/types.ts diff --git a/gear/groups/update.ts b/ui/gear/groups/update.ts similarity index 100% rename from gear/groups/update.ts rename to ui/gear/groups/update.ts diff --git a/gear/groups/view.ts b/ui/gear/groups/view.ts similarity index 100% rename from gear/groups/view.ts rename to ui/gear/groups/view.ts diff --git a/gear/hark/index.ts b/ui/gear/hark/index.ts similarity index 100% rename from gear/hark/index.ts rename to ui/gear/hark/index.ts diff --git a/gear/hark/lib.ts b/ui/gear/hark/lib.ts similarity index 100% rename from gear/hark/lib.ts rename to ui/gear/hark/lib.ts diff --git a/gear/hark/types.ts b/ui/gear/hark/types.ts similarity index 100% rename from gear/hark/types.ts rename to ui/gear/hark/types.ts diff --git a/gear/hood/index.ts b/ui/gear/hood/index.ts similarity index 100% rename from gear/hood/index.ts rename to ui/gear/hood/index.ts diff --git a/gear/hood/lib.ts b/ui/gear/hood/lib.ts similarity index 100% rename from gear/hood/lib.ts rename to ui/gear/hood/lib.ts diff --git a/gear/hood/types.ts b/ui/gear/hood/types.ts similarity index 100% rename from gear/hood/types.ts rename to ui/gear/hood/types.ts diff --git a/gear/index.ts b/ui/gear/index.ts similarity index 87% rename from gear/index.ts rename to ui/gear/index.ts index d3f28beb..6111e0c8 100644 --- a/gear/index.ts +++ b/ui/gear/index.ts @@ -1,7 +1,5 @@ export * from './contacts'; export * as contacts from './contacts'; -export * from './graph'; -export * as graph from './graph'; export * from './groups'; export * as groups from './groups'; export * from './hark'; @@ -13,8 +11,8 @@ export * from './metadata'; export * as metadata from './metadata'; export * from './settings'; export * as settings from './settings'; -export * from './s3'; -export * as s3 from './s3'; +export * from './storage'; +export * as storage from './storage'; export * from './lib'; export * from './lib/BigIntOrderedMap'; export * from './lib/BigIntArrayOrderedMap'; diff --git a/gear/invite/index.ts b/ui/gear/invite/index.ts similarity index 100% rename from gear/invite/index.ts rename to ui/gear/invite/index.ts diff --git a/gear/invite/lib.ts b/ui/gear/invite/lib.ts similarity index 100% rename from gear/invite/lib.ts rename to ui/gear/invite/lib.ts diff --git a/gear/invite/types.ts b/ui/gear/invite/types.ts similarity index 100% rename from gear/invite/types.ts rename to ui/gear/invite/types.ts diff --git a/gear/metadata/index.ts b/ui/gear/metadata/index.ts similarity index 100% rename from gear/metadata/index.ts rename to ui/gear/metadata/index.ts diff --git a/gear/metadata/lib.ts b/ui/gear/metadata/lib.ts similarity index 100% rename from gear/metadata/lib.ts rename to ui/gear/metadata/lib.ts diff --git a/gear/metadata/types.ts b/ui/gear/metadata/types.ts similarity index 100% rename from gear/metadata/types.ts rename to ui/gear/metadata/types.ts diff --git a/gear/settings/index.ts b/ui/gear/settings/index.ts similarity index 100% rename from gear/settings/index.ts rename to ui/gear/settings/index.ts diff --git a/gear/settings/lib.ts b/ui/gear/settings/lib.ts similarity index 100% rename from gear/settings/lib.ts rename to ui/gear/settings/lib.ts diff --git a/gear/settings/types.ts b/ui/gear/settings/types.ts similarity index 100% rename from gear/settings/types.ts rename to ui/gear/settings/types.ts diff --git a/gear/graph/index.ts b/ui/gear/storage/index.ts similarity index 100% rename from gear/graph/index.ts rename to ui/gear/storage/index.ts diff --git a/gear/storage/lib.ts b/ui/gear/storage/lib.ts similarity index 100% rename from gear/storage/lib.ts rename to ui/gear/storage/lib.ts diff --git a/gear/storage/types.ts b/ui/gear/storage/types.ts similarity index 100% rename from gear/storage/types.ts rename to ui/gear/storage/types.ts diff --git a/ui/package-lock.json b/ui/package-lock.json index e45681e4..7a33ab63 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -23,7 +23,6 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/api": "^2.2.0", "@urbit/http-api": "^2.4.5-debug", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", @@ -2402,18 +2401,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@urbit/api": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz", - "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==", - "dependencies": { - "@babel/runtime": "^7.16.0", - "big-integer": "^1.6.48", - "core-js": "^3.19.1", - "immer": "^9.0.1", - "urbit-ob": "^5.0.1" - } - }, "node_modules/@urbit/http-api": { "version": "2.4.5-debug", "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", @@ -10520,18 +10507,6 @@ "eslint-visitor-keys": "^2.0.0" } }, - "@urbit/api": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@urbit/api/-/api-2.2.0.tgz", - "integrity": "sha512-W8kP9OT6yOK62n+4yCPO3i9QqU5xriLvZQ9WYW4SAV7ktbSrGuf2kmYbnoqfA/NybIs9Q/MbFkPewrz4XJ96Ag==", - "requires": { - "@babel/runtime": "^7.16.0", - "big-integer": "^1.6.48", - "core-js": "^3.19.1", - "immer": "^9.0.1", - "urbit-ob": "^5.0.1" - } - }, "@urbit/http-api": { "version": "2.4.5-debug", "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", diff --git a/ui/package.json b/ui/package.json index 8d8d006d..2367e7cf 100644 --- a/ui/package.json +++ b/ui/package.json @@ -33,7 +33,6 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/api": "^2.2.0", "@urbit/http-api": "^2.4.5-debug", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", diff --git a/ui/src/state/storage/index.ts b/ui/src/state/storage/index.ts index 430ee8ce..8d649d28 100644 --- a/ui/src/state/storage/index.ts +++ b/ui/src/state/storage/index.ts @@ -7,7 +7,7 @@ import { reduceStateN, BaseState, } from '../base'; -import { S3Credentials } from '@urbit/api'; +import { StorageCredentials } from '../../../'; enableMapSet(); @@ -22,7 +22,7 @@ export interface BaseStorageState { currentBucket: string; region: string; }; - credentials: S3Credentials | null; + credentials: StorageCredentials | null; }; [ref: string]: unknown; } From 46f223d510af687d47a1ca949144ccbc2d388f6a Mon Sep 17 00:00:00 2001 From: tomholford Date: Mon, 22 May 2023 18:45:01 -0700 Subject: [PATCH 3/8] gear: move to src/ --- ui/{ => src}/gear/contacts/index.ts | 0 ui/{ => src}/gear/contacts/lib.ts | 0 ui/{ => src}/gear/contacts/types.ts | 0 ui/{ => src}/gear/deps.d.ts | 0 ui/{ => src}/gear/docket/index.ts | 0 ui/{ => src}/gear/docket/lib.ts | 0 ui/{ => src}/gear/docket/types.ts | 0 ui/{ => src}/gear/groups/index.ts | 0 ui/{ => src}/gear/groups/lib.ts | 0 ui/{ => src}/gear/groups/types.ts | 0 ui/{ => src}/gear/groups/update.ts | 0 ui/{ => src}/gear/groups/view.ts | 0 ui/{ => src}/gear/hark/index.ts | 0 ui/{ => src}/gear/hark/lib.ts | 0 ui/{ => src}/gear/hark/types.ts | 0 ui/{ => src}/gear/hood/index.ts | 0 ui/{ => src}/gear/hood/lib.ts | 0 ui/{ => src}/gear/hood/types.ts | 0 ui/{ => src}/gear/index.ts | 3 --- ui/{ => src}/gear/invite/index.ts | 0 ui/{ => src}/gear/invite/lib.ts | 0 ui/{ => src}/gear/invite/types.ts | 0 ui/{ => src}/gear/metadata/index.ts | 0 ui/{ => src}/gear/metadata/lib.ts | 0 ui/{ => src}/gear/metadata/types.ts | 0 ui/{ => src}/gear/settings/index.ts | 0 ui/{ => src}/gear/settings/lib.ts | 0 ui/{ => src}/gear/settings/types.ts | 0 ui/{ => src}/gear/storage/index.ts | 0 ui/{ => src}/gear/storage/lib.ts | 2 +- ui/{ => src}/gear/storage/types.ts | 0 ui/src/state/storage/index.ts | 2 +- 32 files changed, 2 insertions(+), 5 deletions(-) rename ui/{ => src}/gear/contacts/index.ts (100%) rename ui/{ => src}/gear/contacts/lib.ts (100%) rename ui/{ => src}/gear/contacts/types.ts (100%) rename ui/{ => src}/gear/deps.d.ts (100%) rename ui/{ => src}/gear/docket/index.ts (100%) rename ui/{ => src}/gear/docket/lib.ts (100%) rename ui/{ => src}/gear/docket/types.ts (100%) rename ui/{ => src}/gear/groups/index.ts (100%) rename ui/{ => src}/gear/groups/lib.ts (100%) rename ui/{ => src}/gear/groups/types.ts (100%) rename ui/{ => src}/gear/groups/update.ts (100%) rename ui/{ => src}/gear/groups/view.ts (100%) rename ui/{ => src}/gear/hark/index.ts (100%) rename ui/{ => src}/gear/hark/lib.ts (100%) rename ui/{ => src}/gear/hark/types.ts (100%) rename ui/{ => src}/gear/hood/index.ts (100%) rename ui/{ => src}/gear/hood/lib.ts (100%) rename ui/{ => src}/gear/hood/types.ts (100%) rename ui/{ => src}/gear/index.ts (87%) rename ui/{ => src}/gear/invite/index.ts (100%) rename ui/{ => src}/gear/invite/lib.ts (100%) rename ui/{ => src}/gear/invite/types.ts (100%) rename ui/{ => src}/gear/metadata/index.ts (100%) rename ui/{ => src}/gear/metadata/lib.ts (100%) rename ui/{ => src}/gear/metadata/types.ts (100%) rename ui/{ => src}/gear/settings/index.ts (100%) rename ui/{ => src}/gear/settings/lib.ts (100%) rename ui/{ => src}/gear/settings/types.ts (100%) rename ui/{ => src}/gear/storage/index.ts (100%) rename ui/{ => src}/gear/storage/lib.ts (96%) rename ui/{ => src}/gear/storage/types.ts (100%) diff --git a/ui/gear/contacts/index.ts b/ui/src/gear/contacts/index.ts similarity index 100% rename from ui/gear/contacts/index.ts rename to ui/src/gear/contacts/index.ts diff --git a/ui/gear/contacts/lib.ts b/ui/src/gear/contacts/lib.ts similarity index 100% rename from ui/gear/contacts/lib.ts rename to ui/src/gear/contacts/lib.ts diff --git a/ui/gear/contacts/types.ts b/ui/src/gear/contacts/types.ts similarity index 100% rename from ui/gear/contacts/types.ts rename to ui/src/gear/contacts/types.ts diff --git a/ui/gear/deps.d.ts b/ui/src/gear/deps.d.ts similarity index 100% rename from ui/gear/deps.d.ts rename to ui/src/gear/deps.d.ts diff --git a/ui/gear/docket/index.ts b/ui/src/gear/docket/index.ts similarity index 100% rename from ui/gear/docket/index.ts rename to ui/src/gear/docket/index.ts diff --git a/ui/gear/docket/lib.ts b/ui/src/gear/docket/lib.ts similarity index 100% rename from ui/gear/docket/lib.ts rename to ui/src/gear/docket/lib.ts diff --git a/ui/gear/docket/types.ts b/ui/src/gear/docket/types.ts similarity index 100% rename from ui/gear/docket/types.ts rename to ui/src/gear/docket/types.ts diff --git a/ui/gear/groups/index.ts b/ui/src/gear/groups/index.ts similarity index 100% rename from ui/gear/groups/index.ts rename to ui/src/gear/groups/index.ts diff --git a/ui/gear/groups/lib.ts b/ui/src/gear/groups/lib.ts similarity index 100% rename from ui/gear/groups/lib.ts rename to ui/src/gear/groups/lib.ts diff --git a/ui/gear/groups/types.ts b/ui/src/gear/groups/types.ts similarity index 100% rename from ui/gear/groups/types.ts rename to ui/src/gear/groups/types.ts diff --git a/ui/gear/groups/update.ts b/ui/src/gear/groups/update.ts similarity index 100% rename from ui/gear/groups/update.ts rename to ui/src/gear/groups/update.ts diff --git a/ui/gear/groups/view.ts b/ui/src/gear/groups/view.ts similarity index 100% rename from ui/gear/groups/view.ts rename to ui/src/gear/groups/view.ts diff --git a/ui/gear/hark/index.ts b/ui/src/gear/hark/index.ts similarity index 100% rename from ui/gear/hark/index.ts rename to ui/src/gear/hark/index.ts diff --git a/ui/gear/hark/lib.ts b/ui/src/gear/hark/lib.ts similarity index 100% rename from ui/gear/hark/lib.ts rename to ui/src/gear/hark/lib.ts diff --git a/ui/gear/hark/types.ts b/ui/src/gear/hark/types.ts similarity index 100% rename from ui/gear/hark/types.ts rename to ui/src/gear/hark/types.ts diff --git a/ui/gear/hood/index.ts b/ui/src/gear/hood/index.ts similarity index 100% rename from ui/gear/hood/index.ts rename to ui/src/gear/hood/index.ts diff --git a/ui/gear/hood/lib.ts b/ui/src/gear/hood/lib.ts similarity index 100% rename from ui/gear/hood/lib.ts rename to ui/src/gear/hood/lib.ts diff --git a/ui/gear/hood/types.ts b/ui/src/gear/hood/types.ts similarity index 100% rename from ui/gear/hood/types.ts rename to ui/src/gear/hood/types.ts diff --git a/ui/gear/index.ts b/ui/src/gear/index.ts similarity index 87% rename from ui/gear/index.ts rename to ui/src/gear/index.ts index 6111e0c8..9ea47738 100644 --- a/ui/gear/index.ts +++ b/ui/src/gear/index.ts @@ -13,9 +13,6 @@ export * from './settings'; export * as settings from './settings'; export * from './storage'; export * as storage from './storage'; -export * from './lib'; -export * from './lib/BigIntOrderedMap'; -export * from './lib/BigIntArrayOrderedMap'; export * as hood from './hood'; export * from './hood'; export * as docket from './docket'; diff --git a/ui/gear/invite/index.ts b/ui/src/gear/invite/index.ts similarity index 100% rename from ui/gear/invite/index.ts rename to ui/src/gear/invite/index.ts diff --git a/ui/gear/invite/lib.ts b/ui/src/gear/invite/lib.ts similarity index 100% rename from ui/gear/invite/lib.ts rename to ui/src/gear/invite/lib.ts diff --git a/ui/gear/invite/types.ts b/ui/src/gear/invite/types.ts similarity index 100% rename from ui/gear/invite/types.ts rename to ui/src/gear/invite/types.ts diff --git a/ui/gear/metadata/index.ts b/ui/src/gear/metadata/index.ts similarity index 100% rename from ui/gear/metadata/index.ts rename to ui/src/gear/metadata/index.ts diff --git a/ui/gear/metadata/lib.ts b/ui/src/gear/metadata/lib.ts similarity index 100% rename from ui/gear/metadata/lib.ts rename to ui/src/gear/metadata/lib.ts diff --git a/ui/gear/metadata/types.ts b/ui/src/gear/metadata/types.ts similarity index 100% rename from ui/gear/metadata/types.ts rename to ui/src/gear/metadata/types.ts diff --git a/ui/gear/settings/index.ts b/ui/src/gear/settings/index.ts similarity index 100% rename from ui/gear/settings/index.ts rename to ui/src/gear/settings/index.ts diff --git a/ui/gear/settings/lib.ts b/ui/src/gear/settings/lib.ts similarity index 100% rename from ui/gear/settings/lib.ts rename to ui/src/gear/settings/lib.ts diff --git a/ui/gear/settings/types.ts b/ui/src/gear/settings/types.ts similarity index 100% rename from ui/gear/settings/types.ts rename to ui/src/gear/settings/types.ts diff --git a/ui/gear/storage/index.ts b/ui/src/gear/storage/index.ts similarity index 100% rename from ui/gear/storage/index.ts rename to ui/src/gear/storage/index.ts diff --git a/ui/gear/storage/lib.ts b/ui/src/gear/storage/lib.ts similarity index 96% rename from ui/gear/storage/lib.ts rename to ui/src/gear/storage/lib.ts index 165789ea..0a11d8db 100644 --- a/ui/gear/storage/lib.ts +++ b/ui/src/gear/storage/lib.ts @@ -1,4 +1,4 @@ -import { Poke } from '../lib/types'; +import { Poke } from '@urbit/http-api'; import { StorageUpdate, StorageUpdateCurrentBucket, StorageUpdateAddBucket, StorageUpdateRemoveBucket, StorageUpdateEndpoint, StorageUpdateAccessKeyId, StorageUpdateSecretAccessKey } from './types'; const s3Action = ( diff --git a/ui/gear/storage/types.ts b/ui/src/gear/storage/types.ts similarity index 100% rename from ui/gear/storage/types.ts rename to ui/src/gear/storage/types.ts diff --git a/ui/src/state/storage/index.ts b/ui/src/state/storage/index.ts index 8d649d28..6f714fc6 100644 --- a/ui/src/state/storage/index.ts +++ b/ui/src/state/storage/index.ts @@ -7,7 +7,7 @@ import { reduceStateN, BaseState, } from '../base'; -import { StorageCredentials } from '../../../'; +import { StorageCredentials } from '@/gear'; enableMapSet(); From 34bd8e858c1938db4978e7b06e5ceb73e25831af Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 24 May 2023 20:57:43 -0700 Subject: [PATCH 4/8] meta: deprecated old pkgs; add new - remove @urbit/api - remove @urbit/http-api - remove urbit-ob - add @urbit/aura - add urbit/js-http-api (via github repo) - remove all references to @urbit/api - replace with references to @/gear for most types, @urbit/aura for helpers, and js-http-api for network types (via the github repo; replace with npm package when published) --- ui/package-lock.json | 85 ++++------ ui/package.json | 4 +- ui/src/api.ts | 2 +- ui/src/components/AppInfo.tsx | 2 +- ui/src/components/Avatar.tsx | 2 +- ui/src/components/DocketImage.tsx | 2 +- ui/src/components/PikeMeta.tsx | 2 +- ui/src/components/ProviderLink.tsx | 2 +- ui/src/components/ProviderList.tsx | 2 +- ui/src/components/ShipName.tsx | 2 +- ui/src/components/TreatyMeta.tsx | 5 +- ui/src/gear/contacts/lib.ts | 2 +- ui/src/gear/contacts/types.ts | 2 +- ui/src/gear/deps.d.ts | 8 - ui/src/gear/docket/lib.ts | 2 +- ui/src/gear/groups/lib.ts | 5 +- ui/src/gear/groups/update.ts | 3 +- ui/src/gear/groups/view.ts | 2 +- ui/src/gear/hark/lib.ts | 6 +- ui/src/gear/hood/lib.ts | 2 +- ui/src/gear/index.ts | 2 + ui/src/gear/invite/lib.ts | 3 +- ui/src/gear/invite/types.ts | 3 +- ui/src/gear/metadata/lib.ts | 5 +- ui/src/gear/metadata/types.ts | 2 +- ui/src/gear/settings/lib.ts | 2 +- ui/src/gear/storage/lib.ts | 2 +- ui/src/gear/utils/BigIntArrayOrderedMap.ts | 151 ++++++++++++++++++ ui/src/gear/utils/BigIntOrderedMap.ts | 116 ++++++++++++++ ui/src/gear/utils/index.ts | 2 + ui/src/gear/utils/lib.ts | 1 + ui/src/gear/utils/types.ts | 25 +++ ui/src/global.d.ts | 4 - ui/src/logic/useSystemUpdate.tsx | 2 +- ui/src/logic/utils.ts | 9 +- ui/src/main.tsx | 2 +- ui/src/mocks/mockContacts.ts | 2 +- ui/src/nav/SystemMenu.tsx | 2 +- ui/src/nav/notifications/Notification.tsx | 2 +- ui/src/nav/search/Apps.tsx | 2 +- ui/src/nav/search/Providers.tsx | 12 +- ui/src/pages/PermalinkRoutes.tsx | 2 +- ui/src/preferences/StoragePrefs.tsx | 2 +- .../preferences/about-system/AboutSystem.tsx | 2 +- .../about-system/UpdatePreferences.tsx | 1 - ui/src/state/base.ts | 3 +- ui/src/state/contact.ts | 3 +- ui/src/state/docket.ts | 2 +- ui/src/state/kiln.ts | 2 +- ui/src/state/mock-data.ts | 4 +- ui/src/state/settings.ts | 4 +- ui/src/state/storage/reducer.ts | 20 +-- ui/src/tiles/Tile.tsx | 2 +- ui/src/tiles/TileMenu.tsx | 2 +- 54 files changed, 404 insertions(+), 138 deletions(-) create mode 100644 ui/src/gear/utils/BigIntArrayOrderedMap.ts create mode 100644 ui/src/gear/utils/BigIntOrderedMap.ts create mode 100644 ui/src/gear/utils/index.ts create mode 100644 ui/src/gear/utils/lib.ts create mode 100644 ui/src/gear/utils/types.ts diff --git a/ui/package-lock.json b/ui/package-lock.json index 7a33ab63..93ef648f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -23,7 +23,8 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/http-api": "^2.4.5-debug", + "@urbit/aura": "^1.0.0", + "@urbit/js-http-api": "git+https://github.com/urbit/js-http-api", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", @@ -48,7 +49,6 @@ "react-hook-form": "^7.38.0", "react-router-dom": "^5.2.0", "slugify": "^1.6.0", - "urbit-ob": "^5.0.1", "zustand": "^3.7.2" }, "devDependencies": { @@ -2401,10 +2401,23 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@urbit/http-api": { - "version": "2.4.5-debug", - "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", - "integrity": "sha512-kMzQwNlrObEz4tEg90nlPRW69Tf+9rD3iIK/JgvsG3423x9oa4rFXobnFKBphXR/5bqd5vR41RoMFN7mqEfDgQ==", + "node_modules/@urbit/aura": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@urbit/aura/-/aura-1.0.0.tgz", + "integrity": "sha512-IeP3uoDzZ0Rpn345auXK0y/BCcXTmpgAlOPbgf7n4eD35h56OnSoit1kuXKA21sWE19gFjK/wqZcz5ULjz2ADg==", + "engines": { + "node": ">=16", + "npm": ">=8" + }, + "peerDependencies": { + "big-integer": "^1.6.51" + } + }, + "node_modules/@urbit/js-http-api": { + "name": "@urbit/http-api", + "version": "3.0.0", + "resolved": "git+ssh://git@github.com/urbit/js-http-api.git#25c3f8f73bd8d6edfd4d5b9feffcfe27585e1ddf", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "browser-or-node": "^1.3.0", @@ -2882,8 +2895,9 @@ "license": "MIT" }, "node_modules/big-integer": { - "version": "1.6.49", - "license": "Unlicense", + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "engines": { "node": ">=0.6" } @@ -2896,10 +2910,6 @@ "node": ">=8" } }, - "node_modules/bn.js": { - "version": "4.12.0", - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "1.1.11", "dev": true, @@ -6094,19 +6104,11 @@ "version": "4.17.21", "license": "MIT" }, - "node_modules/lodash.chunk": { - "version": "4.2.0", - "license": "MIT" - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "dev": true, "license": "MIT" }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "dev": true, @@ -8437,15 +8439,6 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, - "node_modules/urbit-ob": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.8", - "lodash.chunk": "^4.2.0", - "lodash.isequal": "^4.5.0" - } - }, "node_modules/uri-js": { "version": "4.4.1", "dev": true, @@ -10507,10 +10500,15 @@ "eslint-visitor-keys": "^2.0.0" } }, - "@urbit/http-api": { - "version": "2.4.5-debug", - "resolved": "https://registry.npmjs.org/@urbit/http-api/-/http-api-2.4.5-debug.tgz", - "integrity": "sha512-kMzQwNlrObEz4tEg90nlPRW69Tf+9rD3iIK/JgvsG3423x9oa4rFXobnFKBphXR/5bqd5vR41RoMFN7mqEfDgQ==", + "@urbit/aura": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@urbit/aura/-/aura-1.0.0.tgz", + "integrity": "sha512-IeP3uoDzZ0Rpn345auXK0y/BCcXTmpgAlOPbgf7n4eD35h56OnSoit1kuXKA21sWE19gFjK/wqZcz5ULjz2ADg==", + "requires": {} + }, + "@urbit/js-http-api": { + "version": "git+ssh://git@github.com/urbit/js-http-api.git#25c3f8f73bd8d6edfd4d5b9feffcfe27585e1ddf", + "from": "@urbit/js-http-api@git+https://github.com/urbit/js-http-api", "requires": { "@babel/runtime": "^7.12.5", "browser-or-node": "^1.3.0", @@ -10810,15 +10808,14 @@ "dev": true }, "big-integer": { - "version": "1.6.49" + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==" }, "binary-extensions": { "version": "2.2.0", "dev": true }, - "bn.js": { - "version": "4.12.0" - }, "brace-expansion": { "version": "1.1.11", "dev": true, @@ -12885,16 +12882,10 @@ "lodash": { "version": "4.17.21" }, - "lodash.chunk": { - "version": "4.2.0" - }, "lodash.clonedeep": { "version": "4.5.0", "dev": true }, - "lodash.isequal": { - "version": "4.5.0" - }, "lodash.merge": { "version": "4.6.2", "dev": true @@ -14325,14 +14316,6 @@ } } }, - "urbit-ob": { - "version": "5.0.1", - "requires": { - "bn.js": "^4.11.8", - "lodash.chunk": "^4.2.0", - "lodash.isequal": "^4.5.0" - } - }, "uri-js": { "version": "4.4.1", "dev": true, diff --git a/ui/package.json b/ui/package.json index 2367e7cf..33a16304 100644 --- a/ui/package.json +++ b/ui/package.json @@ -33,7 +33,8 @@ "@tlon/sigil-js": "^1.4.4", "@tloncorp/mock-http-api": "^1.2.0", "@types/lodash": "^4.14.172", - "@urbit/http-api": "^2.4.5-debug", + "@urbit/aura": "^1.0.0", + "@urbit/js-http-api": "git+https://github.com/urbit/js-http-api", "big-integer": "^1.6.48", "browser-cookies": "^1.2.0", "classnames": "^2.3.1", @@ -58,7 +59,6 @@ "react-hook-form": "^7.38.0", "react-router-dom": "^5.2.0", "slugify": "^1.6.0", - "urbit-ob": "^5.0.1", "zustand": "^3.7.2" }, "devDependencies": { diff --git a/ui/src/api.ts b/ui/src/api.ts index bc7815f4..381d819d 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -6,7 +6,7 @@ import Urbit, { Thread, UrbitHttpApiEvent, UrbitHttpApiEventType, -} from '@urbit/http-api'; +} from '@urbit/js-http-api'; import _ from 'lodash'; import { useLocalState } from '@/state/local'; import useSchedulerStore from './state/scheduler'; diff --git a/ui/src/components/AppInfo.tsx b/ui/src/components/AppInfo.tsx index b0003299..ad3a9c84 100644 --- a/ui/src/components/AppInfo.tsx +++ b/ui/src/components/AppInfo.tsx @@ -1,4 +1,4 @@ -import { chadIsRunning, Pike, Treaty } from '@urbit/api'; +import { chadIsRunning, Pike, Treaty } from '@/gear'; import clipboardCopy from 'clipboard-copy'; import React, { FC, useCallback, useState } from 'react'; import cn from 'classnames'; diff --git a/ui/src/components/Avatar.tsx b/ui/src/components/Avatar.tsx index 35e7174e..dbea5e1b 100644 --- a/ui/src/components/Avatar.tsx +++ b/ui/src/components/Avatar.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React, { useMemo } from 'react'; import { sigil, reactRenderer } from '@tlon/sigil-js'; -import { deSig } from '@urbit/api'; +import { deSig } from '@urbit/aura'; import { darken, lighten, parseToHsla } from 'color2k'; import { useCurrentTheme } from '../state/local'; import { normalizeUrbitColor } from '@/logic/utils'; diff --git a/ui/src/components/DocketImage.tsx b/ui/src/components/DocketImage.tsx index 68212342..8ee86237 100644 --- a/ui/src/components/DocketImage.tsx +++ b/ui/src/components/DocketImage.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Docket } from '@urbit/api'; +import { Docket } from '@/gear'; import cn from 'classnames'; import { useTileColor } from '../tiles/useTileColor'; diff --git a/ui/src/components/PikeMeta.tsx b/ui/src/components/PikeMeta.tsx index 5877fbfa..4e3d9a54 100644 --- a/ui/src/components/PikeMeta.tsx +++ b/ui/src/components/PikeMeta.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Pike } from '@urbit/api'; +import { Pike } from '@/gear'; import { Attribute } from './Attribute'; diff --git a/ui/src/components/ProviderLink.tsx b/ui/src/components/ProviderLink.tsx index 702ff7a4..2e2a179f 100644 --- a/ui/src/components/ProviderLink.tsx +++ b/ui/src/components/ProviderLink.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import { Link, LinkProps } from 'react-router-dom'; -import { Provider } from '@urbit/api'; +import { Provider } from '@/gear'; import { ShipName } from './ShipName'; import { Avatar, AvatarSizes } from './Avatar'; import { Contact } from '@/types/contact'; diff --git a/ui/src/components/ProviderList.tsx b/ui/src/components/ProviderList.tsx index 61674b13..abd5e29b 100644 --- a/ui/src/components/ProviderList.tsx +++ b/ui/src/components/ProviderList.tsx @@ -1,5 +1,5 @@ import React, { MouseEvent, useCallback } from 'react'; -import { Provider } from '@urbit/api'; +import { Provider } from '@/gear'; import classNames from 'classnames'; import { MatchItem } from '../nav/Nav'; import { useRecentsStore } from '../nav/search/Home'; diff --git a/ui/src/components/ShipName.tsx b/ui/src/components/ShipName.tsx index 0342508a..b767c69a 100644 --- a/ui/src/components/ShipName.tsx +++ b/ui/src/components/ShipName.tsx @@ -1,4 +1,4 @@ -import { cite } from '@urbit/api'; +import { cite } from '@urbit/aura'; import React, { HTMLAttributes } from 'react'; import { useCalm } from '../state/settings'; import { useContact } from '../state/contact'; diff --git a/ui/src/components/TreatyMeta.tsx b/ui/src/components/TreatyMeta.tsx index 00974bb7..36185d3a 100644 --- a/ui/src/components/TreatyMeta.tsx +++ b/ui/src/components/TreatyMeta.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { daToDate, Treaty } from '@urbit/api'; +import { daToUnix, parseDa } from '@urbit/aura' +import { Treaty } from '@/gear'; import moment from 'moment'; import { Attribute } from './Attribute'; @@ -15,7 +16,7 @@ export function TreatyMeta(props: { treaty: Treaty }) { {ship}/{desk} - {moment(daToDate(cass.da)).format('YYYY.MM.DD')} + {moment(daToUnix(parseDa(cass.da))).format('YYYY.MM.DD')} {meta.map((d) => ( diff --git a/ui/src/gear/contacts/lib.ts b/ui/src/gear/contacts/lib.ts index 26b08c6b..7c024a2c 100644 --- a/ui/src/gear/contacts/lib.ts +++ b/ui/src/gear/contacts/lib.ts @@ -1,5 +1,5 @@ -import { Patp, Poke, Scry } from '../lib'; +import { Patp, Poke, Scry } from '@urbit/js-http-api'; import { Contact, ContactUpdateAdd, diff --git a/ui/src/gear/contacts/types.ts b/ui/src/gear/contacts/types.ts index 201aa243..75aa943c 100644 --- a/ui/src/gear/contacts/types.ts +++ b/ui/src/gear/contacts/types.ts @@ -1,4 +1,4 @@ -import { Path, Patp } from '../lib'; +import { Path, Patp } from '@urbit/js-http-api'; import { Resource } from '../groups'; export type ContactUpdate = diff --git a/ui/src/gear/deps.d.ts b/ui/src/gear/deps.d.ts index 0099f33f..e69de29b 100644 --- a/ui/src/gear/deps.d.ts +++ b/ui/src/gear/deps.d.ts @@ -1,8 +0,0 @@ - -declare module 'urbit-ob' { - - /** - * Convert a @p-encoded string to a decimal-encoded string. - */ - function patp2dec(name: string): string -} diff --git a/ui/src/gear/docket/lib.ts b/ui/src/gear/docket/lib.ts index f5c3e255..ebdce211 100644 --- a/ui/src/gear/docket/lib.ts +++ b/ui/src/gear/docket/lib.ts @@ -1,4 +1,4 @@ -import { Poke, Scry } from '../lib'; +import { Poke, Scry } from '@urbit/js-http-api'; import { Chad } from './types'; export function chadIsRunning(chad: Chad) { diff --git a/ui/src/gear/groups/lib.ts b/ui/src/gear/groups/lib.ts index 7e93ad3a..2d5d2d50 100644 --- a/ui/src/gear/groups/lib.ts +++ b/ui/src/gear/groups/lib.ts @@ -1,5 +1,6 @@ -import { deSig } from '../index'; -import { Enc, Path, Patp, PatpNoSig, Poke, Thread } from '../lib/types'; +import { deSig } from '@urbit/aura'; +import { Path, Patp, PatpNoSig, Poke, Thread } from '@urbit/js-http-api'; +import { Enc } from '@/gear'; import { Group, GroupPolicy, GroupPolicyDiff, GroupUpdateAddMembers, GroupUpdateAddTag, GroupUpdateChangePolicy, GroupUpdateRemoveGroup, GroupUpdateRemoveMembers, GroupUpdateRemoveTag, Resource, RoleTags, Tag } from './types'; import { GroupUpdate } from './update'; diff --git a/ui/src/gear/groups/update.ts b/ui/src/gear/groups/update.ts index a25c9a63..a5f025a1 100644 --- a/ui/src/gear/groups/update.ts +++ b/ui/src/gear/groups/update.ts @@ -1,4 +1,5 @@ -import { PatpNoSig, Path, ShipRank, Enc } from '../lib'; +import { PatpNoSig, Path } from '@urbit/js-http-api'; +import { ShipRank, Enc } from '@/gear'; import { roleTags } from './index'; export type RoleTags = typeof roleTags[number]; diff --git a/ui/src/gear/groups/view.ts b/ui/src/gear/groups/view.ts index c6e432b2..dced81d1 100644 --- a/ui/src/gear/groups/view.ts +++ b/ui/src/gear/groups/view.ts @@ -1,5 +1,5 @@ import { joinError, joinProgress, joinResult } from "."; -import {Patp} from "../lib"; +import { Patp } from '@urbit/js-http-api'; export type JoinError = typeof joinError[number]; diff --git a/ui/src/gear/hark/lib.ts b/ui/src/gear/hark/lib.ts index a470c671..e7f081db 100644 --- a/ui/src/gear/hark/lib.ts +++ b/ui/src/gear/hark/lib.ts @@ -1,6 +1,6 @@ import { BigInteger } from 'big-integer'; -import { Poke } from '../lib/types'; +import { Poke } from '@urbit/js-http-api'; import { HarkBin, HarkBinId, @@ -8,7 +8,7 @@ import { HarkLid, HarkPlace } from './types'; -import { decToUd } from '../lib'; +import { parseUd } from '@urbit/aura'; export const harkAction = (data: T): Poke => ({ app: 'hark-store', @@ -39,7 +39,7 @@ export const actOnNotification = ( ): Poke => harkAction({ [frond]: { - time: decToUd(intTime.toString()), + time: parseUd(intTime.toString()), bin } }); diff --git a/ui/src/gear/hood/lib.ts b/ui/src/gear/hood/lib.ts index 02d86868..346980a6 100644 --- a/ui/src/gear/hood/lib.ts +++ b/ui/src/gear/hood/lib.ts @@ -1,4 +1,4 @@ -import { Poke, Scry } from '../lib'; +import { Poke, Scry } from '@urbit/js-http-api'; import { Pike } from './types'; export const getPikes: Scry = { diff --git a/ui/src/gear/index.ts b/ui/src/gear/index.ts index 9ea47738..50825f78 100644 --- a/ui/src/gear/index.ts +++ b/ui/src/gear/index.ts @@ -17,6 +17,8 @@ export * as hood from './hood'; export * from './hood'; export * as docket from './docket'; export * from './docket'; +export * as utils from './utils'; +export * from './utils'; // TODO: Userspace Permissions // export * from './permissions'; diff --git a/ui/src/gear/invite/lib.ts b/ui/src/gear/invite/lib.ts index a5a5ca94..885ef787 100644 --- a/ui/src/gear/invite/lib.ts +++ b/ui/src/gear/invite/lib.ts @@ -1,4 +1,5 @@ -import { Poke, Serial } from "../lib"; +import { Poke } from '@urbit/js-http-api'; +import { Serial } from '@/gear'; import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types"; export const inviteAction = (data: T): Poke => ({ diff --git a/ui/src/gear/invite/types.ts b/ui/src/gear/invite/types.ts index b3515bb4..e0e95745 100644 --- a/ui/src/gear/invite/types.ts +++ b/ui/src/gear/invite/types.ts @@ -1,4 +1,5 @@ -import { Serial, PatpNoSig, Path } from '../lib'; +import { PatpNoSig, Path } from '@urbit/js-http-api'; +import { Serial } from '@/gear'; import { Resource } from "../groups"; export type InviteUpdate = diff --git a/ui/src/gear/metadata/lib.ts b/ui/src/gear/metadata/lib.ts index ace81e8a..64b91fc7 100644 --- a/ui/src/gear/metadata/lib.ts +++ b/ui/src/gear/metadata/lib.ts @@ -1,4 +1,5 @@ -import { Path, Poke, uxToHex, PatpNoSig } from '../lib'; +import { parseUx } from '@urbit/aura'; +import { Path, Poke, PatpNoSig } from '@urbit/js-http-api'; import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types'; export const METADATA_UPDATE_VERSION = 2; @@ -83,7 +84,7 @@ export const update = ( newMetadata: Partial ): Poke => { const metadata = { ...association.metadata, ...newMetadata }; - metadata.color = uxToHex(metadata.color); + metadata.color = parseUx(metadata.color); return metadataAction({ add: { group: association.group, diff --git a/ui/src/gear/metadata/types.ts b/ui/src/gear/metadata/types.ts index 828c83b1..0d83135c 100644 --- a/ui/src/gear/metadata/types.ts +++ b/ui/src/gear/metadata/types.ts @@ -1,4 +1,4 @@ -import { Path, Patp } from '../lib'; +import { Path, Patp } from '@urbit/js-http-api'; export type MdAppName = 'groups' | 'graph'; diff --git a/ui/src/gear/settings/lib.ts b/ui/src/gear/settings/lib.ts index 94fca9d5..7a868ec2 100644 --- a/ui/src/gear/settings/lib.ts +++ b/ui/src/gear/settings/lib.ts @@ -1,4 +1,4 @@ -import { Poke, Scry } from '../lib'; +import { Poke, Scry } from '@urbit/js-http-api'; import { PutBucket, Key, Bucket, DelBucket, Value, PutEntry, DelEntry, SettingsUpdate } from './types'; export const action = (data: T): Poke => ({ diff --git a/ui/src/gear/storage/lib.ts b/ui/src/gear/storage/lib.ts index 0a11d8db..dd8106b9 100644 --- a/ui/src/gear/storage/lib.ts +++ b/ui/src/gear/storage/lib.ts @@ -1,4 +1,4 @@ -import { Poke } from '@urbit/http-api'; +import { Poke } from '@urbit/js-http-api'; import { StorageUpdate, StorageUpdateCurrentBucket, StorageUpdateAddBucket, StorageUpdateRemoveBucket, StorageUpdateEndpoint, StorageUpdateAccessKeyId, StorageUpdateSecretAccessKey } from './types'; const s3Action = ( diff --git a/ui/src/gear/utils/BigIntArrayOrderedMap.ts b/ui/src/gear/utils/BigIntArrayOrderedMap.ts new file mode 100644 index 00000000..dcd1ec37 --- /dev/null +++ b/ui/src/gear/utils/BigIntArrayOrderedMap.ts @@ -0,0 +1,151 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +export function stringToArr(str: string) { + return str.split('/').slice(1).map((ind) => { + return bigInt(ind); + }); +} + +export function arrToString(arr: BigInteger[]) { + let string = ''; + arr.forEach((key) => { + string = string + `/${key.toString()}`; + }); + return string; +} + +function sorted(a: BigInteger[], b: BigInteger[], reversed = false) { + const getSort = sortBigIntArr(a, b); + if (reversed) { + return getSort * -1; + } else { + return getSort; + } +} + +export function sortBigIntArr(a: BigInteger[], b: BigInteger[]) { + const aLen = a.length; + const bLen = b.length; + + const aCop = a.slice(0); + const bCop = b.slice(0); + aCop.reverse(); + bCop.reverse(); + + let i = 0; + while (i < aLen && i < bLen) { + if (aCop[i].lt(bCop[i])) { + return 1; + } else if (aCop[i].gt(bCop[i])) { + return -1; + } else { + i++; + } + } + + return bLen - aLen; +} + +export class BigIntArrayOrderedMap implements Iterable<[BigInteger[], V]> { + root: Record = {} + cachedIter: [BigInteger[], V][] | null = null; + [immerable] = true; + reversed = false; + + constructor(items: [BigInteger[], V][] = [], reversed = false) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + this.reversed = reversed; + } + + get size() { + return Object.keys(this.root).length; + } + + get(key: BigInteger[]) { + return this.root[arrToString(key)] ?? null; + } + + gas(items: [BigInteger[], V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[arrToString(key)] = castDraft(value); + }); + draft.generateCachedIter(); + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger[], value: V) { + return produce(this, (draft) => { + draft.root[arrToString(key)] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger[]) { + return arrToString(key) in this.root; + } + + delete(key: BigInteger[]) { + const result = produce(this, (draft) => { + delete draft.root[arrToString(key)]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger[], V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger[], V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger[], V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger[], V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + return [stringToArr(key), this.root[key]] as [BigInteger[], V]; + }).sort(([a], [b]) => sorted(a, b, this.reversed)); + this.cachedIter = result; + return [...result]; + } +} diff --git a/ui/src/gear/utils/BigIntOrderedMap.ts b/ui/src/gear/utils/BigIntOrderedMap.ts new file mode 100644 index 00000000..621c2e11 --- /dev/null +++ b/ui/src/gear/utils/BigIntOrderedMap.ts @@ -0,0 +1,116 @@ +import produce, { immerable, castDraft, setAutoFreeze, enablePatches } from 'immer'; +import bigInt, { BigInteger } from 'big-integer'; + +setAutoFreeze(false); + +enablePatches(); + +function sortBigInt(a: BigInteger, b: BigInteger) { + if (a.lt(b)) { + return 1; + } else if (a.eq(b)) { + return 0; + } else { + return -1; + } +} +export class BigIntOrderedMap implements Iterable<[BigInteger, V]> { + root: Record = {} + cachedIter: [BigInteger, V][] | null = null; + [immerable] = true; + + constructor(items: [BigInteger, V][] = []) { + items.forEach(([key, val]) => { + this.set(key, val); + }); + } + + get size() { + if(this.cachedIter) { + return this.cachedIter.length; + } + return this.generateCachedIter().length; + } + + get(key: BigInteger) { + return this.root[key.toString()] ?? null; + } + + gas(items: [BigInteger, V][]) { + return produce(this, (draft) => { + items.forEach(([key, value]) => { + draft.root[key.toString()] = castDraft(value); + }); + draft.cachedIter = null; + }, + (patches) => { + // console.log(`gassed with ${JSON.stringify(patches, null, 2)}`); + }); + } + + set(key: BigInteger, value: V) { + return produce(this, (draft) => { + draft.root[key.toString()] = castDraft(value); + draft.cachedIter = null; + }); + } + + clear() { + return produce(this, (draft) => { + draft.cachedIter = []; + draft.root = {}; + }); + } + + has(key: BigInteger) { + return key.toString() in this.root; + } + + delete(key: BigInteger) { + const result = produce(this, (draft) => { + delete draft.root[key.toString()]; + draft.cachedIter = null; + }); + return result; + } + + [Symbol.iterator](): IterableIterator<[BigInteger, V]> { + let idx = 0; + const result = this.generateCachedIter(); + return { + [Symbol.iterator]: this[Symbol.iterator], + next: (): IteratorResult<[BigInteger, V]> => { + if (idx < result.length) { + return { value: result[idx++], done: false }; + } + return { done: true, value: null }; + } + }; + } + + peekLargest() { + const sorted = Array.from(this); + return sorted[0] as [BigInteger, V] | null; + } + + peekSmallest() { + const sorted = Array.from(this); + return sorted[sorted.length - 1] as [BigInteger, V] | null; + } + + keys() { + return Array.from(this).map(([k,v]) => k); + } + + generateCachedIter() { + if(this.cachedIter) { + return [...this.cachedIter]; + } + const result = Object.keys(this.root).map((key) => { + const num = bigInt(key); + return [num, this.root[key]] as [BigInteger, V]; + }).sort(([a], [b]) => sortBigInt(a,b)); + this.cachedIter = result; + return [...result]; + } +} diff --git a/ui/src/gear/utils/index.ts b/ui/src/gear/utils/index.ts new file mode 100644 index 00000000..4fed660f --- /dev/null +++ b/ui/src/gear/utils/index.ts @@ -0,0 +1,2 @@ +export * from './lib'; +export * from './types'; \ No newline at end of file diff --git a/ui/src/gear/utils/lib.ts b/ui/src/gear/utils/lib.ts new file mode 100644 index 00000000..693da49f --- /dev/null +++ b/ui/src/gear/utils/lib.ts @@ -0,0 +1 @@ +export {} \ No newline at end of file diff --git a/ui/src/gear/utils/types.ts b/ui/src/gear/utils/types.ts new file mode 100644 index 00000000..84116f36 --- /dev/null +++ b/ui/src/gear/utils/types.ts @@ -0,0 +1,25 @@ +import { BigIntOrderedMap } from "./BigIntOrderedMap"; + +export type SetElement = S extends Set<(infer T)> ? T : never; +export type MapKey = M extends Map<(infer K), any> ? K : never; +export type MapValue = M extends Map ? V : never; + +/** + * Turns sets into arrays and maps into objects so we can send them over the wire + */ +export type Enc = + S extends Set ? + Enc>[] : + S extends Map ? + { [s: string]: Enc> } : + S extends object ? + { [K in keyof S]: Enc } : + S extends BigIntOrderedMap ? + { [index: string]: T } : + S; + + +export type ShipRank = 'czar' | 'king' | 'duke' | 'earl' | 'pawn'; + +// @uvH encoded string +export type Serial = string; diff --git a/ui/src/global.d.ts b/ui/src/global.d.ts index ce5215a8..ecefe09c 100644 --- a/ui/src/global.d.ts +++ b/ui/src/global.d.ts @@ -1,7 +1,3 @@ -declare module 'urbit-ob' { - export function isValidPatp(patp: string): boolean; -} - type Stringified = string & { [P in keyof T]: { '_ value': T[P] }; diff --git a/ui/src/logic/useSystemUpdate.tsx b/ui/src/logic/useSystemUpdate.tsx index 223f78b2..3ebad797 100644 --- a/ui/src/logic/useSystemUpdate.tsx +++ b/ui/src/logic/useSystemUpdate.tsx @@ -1,4 +1,4 @@ -import { kilnBump, Pike } from '@urbit/api'; +import { kilnBump, Pike } from '@/gear'; import { partition, pick } from 'lodash'; import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; diff --git a/ui/src/logic/utils.ts b/ui/src/logic/utils.ts index 6138b104..7db872ff 100644 --- a/ui/src/logic/utils.ts +++ b/ui/src/logic/utils.ts @@ -1,6 +1,6 @@ import { Yarn, isYarnEmph, isYarnShip } from '@/types/hark'; import { findLast } from 'lodash'; -import { Docket, DocketHref, Treaty } from '@urbit/api'; +import { Docket, DocketHref, Treaty } from '@/gear'; import { hsla, parseToHsla, parseToRgba } from 'color2k'; import _ from 'lodash'; import { differenceInDays, endOfToday, format } from 'date-fns'; @@ -44,13 +44,6 @@ export function handleDropdownLink( }; } -export function deSig(ship: string): string { - if (!ship) { - return ''; - } - return ship.replace('~', ''); -} - export function normalizeUrbitColor(color: string): string { if (color.startsWith('#')) { return color; diff --git a/ui/src/main.tsx b/ui/src/main.tsx index 736b6dad..8444e279 100644 --- a/ui/src/main.tsx +++ b/ui/src/main.tsx @@ -1,4 +1,4 @@ -import { preSig } from '@urbit/api'; +import { preSig } from '@urbit/aura'; import cookies from 'browser-cookies'; import React from 'react'; import ReactDOM from 'react-dom'; diff --git a/ui/src/mocks/mockContacts.ts b/ui/src/mocks/mockContacts.ts index d4a93607..3270acfe 100644 --- a/ui/src/mocks/mockContacts.ts +++ b/ui/src/mocks/mockContacts.ts @@ -1,4 +1,4 @@ -import { Rolodex } from '@urbit/api'; +import { Rolodex } from '@/gear'; const mockContacts: Rolodex = { '~finned-palmer': { diff --git a/ui/src/nav/SystemMenu.tsx b/ui/src/nav/SystemMenu.tsx index 5dd8259a..0884f762 100644 --- a/ui/src/nav/SystemMenu.tsx +++ b/ui/src/nav/SystemMenu.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import clipboardCopy from 'clipboard-copy'; import React, { HTMLAttributes, useCallback, useState } from 'react'; import { Link, Route, useHistory } from 'react-router-dom'; -import { Pike } from '@urbit/api'; +import { Pike } from '@/gear'; import { Adjust } from '../components/icons/Adjust'; import { usePike } from '../state/kiln'; import { disableDefault, handleDropdownLink } from '@/logic/utils'; diff --git a/ui/src/nav/notifications/Notification.tsx b/ui/src/nav/notifications/Notification.tsx index 683d81ba..2808e691 100644 --- a/ui/src/nav/notifications/Notification.tsx +++ b/ui/src/nav/notifications/Notification.tsx @@ -12,7 +12,7 @@ import { ShipName } from '../../components/ShipName'; import { DeskLink } from '../../components/DeskLink'; import { DocketImage } from '../../components/DocketImage'; import GroupAvatar from '../../components/GroupAvatar'; -import { Charge } from '@urbit/api'; +import { Charge } from '@/gear'; import { useSawRopeMutation } from '@/state/hark'; interface NotificationProps { diff --git a/ui/src/nav/search/Apps.tsx b/ui/src/nav/search/Apps.tsx index 7bcb7d64..5b255bf7 100644 --- a/ui/src/nav/search/Apps.tsx +++ b/ui/src/nav/search/Apps.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useMemo } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import fuzzy from 'fuzzy'; -import { Treaty } from '@urbit/api'; +import { Treaty } from '@/gear'; import { ShipName } from '../../components/ShipName'; import { useAllyTreaties } from '../../state/docket'; import { useAppSearchStore } from '../Nav'; diff --git a/ui/src/nav/search/Providers.tsx b/ui/src/nav/search/Providers.tsx index f861844c..39748166 100644 --- a/ui/src/nav/search/Providers.tsx +++ b/ui/src/nav/search/Providers.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useMemo } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import fuzzy from 'fuzzy'; -import { Provider, deSig } from '@urbit/api'; -import * as ob from 'urbit-ob'; +import { deSig, isValidPatp } from '@urbit/aura'; +import { Provider } from '@/gear'; import { MatchItem, useAppSearchStore } from '../Nav'; import { useAllies, useCharges } from '../../state/docket'; import { ProviderList } from '../../components/ProviderList'; @@ -59,14 +59,14 @@ export const Providers = ({ match }: ProvidersProps) => { ); const patp = `~${deSig(search) || ''}`; - const isValidPatp = ob.isValidPatp(patp); + const isValid = isValidPatp(patp); const results = useMemo(() => { if (!allies) { return []; } const exact = - isValidPatp && !Object.keys(allies).includes(patp) + isValid && !Object.keys(allies).includes(patp) ? [ { shipName: patp, @@ -109,7 +109,7 @@ export const Providers = ({ match }: ProvidersProps) => { })) : []; - const newProviderMatches = isValidPatp + const newProviderMatches = isValid ? [ { url: `/search/${patp}/apps`, @@ -128,7 +128,7 @@ export const Providers = ({ match }: ProvidersProps) => { ), }); } - }, [results, patp, isValidPatp]); + }, [results, patp, isValid]); return (
; -const credentials = (json: S3Update, state: StorageState): StorageState => { +const credentials = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'credentials', false); if (data) { state.s3.credentials = data; @@ -13,7 +13,7 @@ const credentials = (json: S3Update, state: StorageState): StorageState => { return state; }; -const configuration = (json: S3Update, state: StorageState): StorageState => { +const configuration = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'configuration', false); if (data) { state.s3.configuration = { @@ -25,7 +25,7 @@ const configuration = (json: S3Update, state: StorageState): StorageState => { return state; }; -const currentBucket = (json: S3Update, state: StorageState): StorageState => { +const currentBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setCurrentBucket', false); if (data && state.s3) { state.s3.configuration.currentBucket = data; @@ -33,7 +33,7 @@ const currentBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const region = (json: S3Update, state: StorageState): StorageState => { +const region = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setRegion', false); if (data && state.s3) { state.s3.configuration.region = data; @@ -41,7 +41,7 @@ const region = (json: S3Update, state: StorageState): StorageState => { return state; }; -const addBucket = (json: S3Update, state: StorageState): StorageState => { +const addBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'addBucket', false); if (data) { state.s3.configuration.buckets = state.s3.configuration.buckets.add(data); @@ -49,7 +49,7 @@ const addBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const removeBucket = (json: S3Update, state: StorageState): StorageState => { +const removeBucket = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'removeBucket', false); if (data) { state.s3.configuration.buckets.delete(data); @@ -57,7 +57,7 @@ const removeBucket = (json: S3Update, state: StorageState): StorageState => { return state; }; -const endpoint = (json: S3Update, state: StorageState): StorageState => { +const endpoint = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setEndpoint', false); if (data && state.s3.credentials) { state.s3.credentials.endpoint = data; @@ -65,7 +65,7 @@ const endpoint = (json: S3Update, state: StorageState): StorageState => { return state; }; -const accessKeyId = (json: S3Update, state: StorageState): StorageState => { +const accessKeyId = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setAccessKeyId', false); if (data && state.s3.credentials) { state.s3.credentials.accessKeyId = data; @@ -73,7 +73,7 @@ const accessKeyId = (json: S3Update, state: StorageState): StorageState => { return state; }; -const secretAccessKey = (json: S3Update, state: StorageState): StorageState => { +const secretAccessKey = (json: StorageUpdate, state: StorageState): StorageState => { const data = _.get(json, 'setSecretAccessKey', false); if (data && state.s3.credentials) { state.s3.credentials.secretAccessKey = data; diff --git a/ui/src/tiles/Tile.tsx b/ui/src/tiles/Tile.tsx index e9d5848f..2fcce08d 100644 --- a/ui/src/tiles/Tile.tsx +++ b/ui/src/tiles/Tile.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React, { FunctionComponent } from 'react'; import { useDrag } from 'react-dnd'; -import { chadIsRunning } from '@urbit/api'; +import { chadIsRunning } from '@/gear'; import { TileMenu } from './TileMenu'; import { Spinner } from '../components/Spinner'; import { getAppHref } from '@/logic/utils'; diff --git a/ui/src/tiles/TileMenu.tsx b/ui/src/tiles/TileMenu.tsx index bd6d1f90..2df238aa 100644 --- a/ui/src/tiles/TileMenu.tsx +++ b/ui/src/tiles/TileMenu.tsx @@ -2,7 +2,7 @@ import React, { ReactElement, useCallback, useState } from 'react'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import classNames from 'classnames'; import { Link } from 'react-router-dom'; -import { Chad, chadIsRunning } from '@urbit/api'; +import { Chad, chadIsRunning } from '@/gear'; import useDocketState from '../state/docket'; import { disableDefault, handleDropdownLink } from '@/logic/utils'; import { useMedia } from '../logic/useMedia'; From 81b884562efd392b4dbfbc71b5641fb529a15877 Mon Sep 17 00:00:00 2001 From: tomholford Date: Wed, 24 May 2023 23:17:27 -0700 Subject: [PATCH 5/8] meta: remove unused gear pkgs --- ui/src/gear/index.ts | 5 -- ui/src/gear/invite/index.ts | 2 - ui/src/gear/invite/lib.ts | 29 ---------- ui/src/gear/invite/types.ts | 76 ------------------------- ui/src/gear/metadata/index.ts | 2 - ui/src/gear/metadata/lib.ts | 100 --------------------------------- ui/src/gear/metadata/types.ts | 101 ---------------------------------- 7 files changed, 315 deletions(-) delete mode 100644 ui/src/gear/invite/index.ts delete mode 100644 ui/src/gear/invite/lib.ts delete mode 100644 ui/src/gear/invite/types.ts delete mode 100644 ui/src/gear/metadata/index.ts delete mode 100644 ui/src/gear/metadata/lib.ts delete mode 100644 ui/src/gear/metadata/types.ts diff --git a/ui/src/gear/index.ts b/ui/src/gear/index.ts index 50825f78..d3b8aea0 100644 --- a/ui/src/gear/index.ts +++ b/ui/src/gear/index.ts @@ -4,11 +4,6 @@ export * from './groups'; export * as groups from './groups'; export * from './hark'; export * as hark from './hark'; -export * from './invite'; -// this conflicts with /groups/lib invite -// export * as invite from './invite'; -export * from './metadata'; -export * as metadata from './metadata'; export * from './settings'; export * as settings from './settings'; export * from './storage'; diff --git a/ui/src/gear/invite/index.ts b/ui/src/gear/invite/index.ts deleted file mode 100644 index 341e8171..00000000 --- a/ui/src/gear/invite/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/invite/lib.ts b/ui/src/gear/invite/lib.ts deleted file mode 100644 index 885ef787..00000000 --- a/ui/src/gear/invite/lib.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Poke } from '@urbit/js-http-api'; -import { Serial } from '@/gear'; -import { InviteUpdate, InviteUpdateAccept, InviteUpdateDecline } from "./types"; - -export const inviteAction = (data: T): Poke => ({ - app: 'invite-store', - mark: 'invite-action', - json: data -}); - -export const accept = ( - app: string, - uid: Serial -): Poke => inviteAction({ - accept: { - term: app, - uid - } -}); - -export const decline = ( - app: string, - uid: Serial -): Poke => inviteAction({ - decline: { - term: app, - uid - } -}); diff --git a/ui/src/gear/invite/types.ts b/ui/src/gear/invite/types.ts deleted file mode 100644 index e0e95745..00000000 --- a/ui/src/gear/invite/types.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { PatpNoSig, Path } from '@urbit/js-http-api'; -import { Serial } from '@/gear'; -import { Resource } from "../groups"; - -export type InviteUpdate = - InviteUpdateInitial -| InviteUpdateCreate -| InviteUpdateDelete -| InviteUpdateInvite -| InviteUpdateAccept -| InviteUpdateAccepted -| InviteUpdateDecline; - -export interface InviteUpdateAccept { - accept: { - term: string; - uid: Serial; - } -} - -export interface InviteUpdateInitial { - initial: Invites; -} - -export interface InviteUpdateCreate { - create: { - term: string; - }; -} - -export interface InviteUpdateDelete { - delete: { - term: string; - }; -} - -export interface InviteUpdateInvite { - invite: { - term: string; - uid: Serial; - invite: Invite; - }; -} - -export interface InviteUpdateAccepted { - accepted: { - term: string; - uid: Serial; - }; -} - -export interface InviteUpdateDecline { - decline: { - term: string; - uid: Serial; - }; -} - -// actual datastructures - - -export type Invites = { - [p in Path]: AppInvites; -}; - -export type AppInvites = { - [s in Serial]: Invite; -}; - -export interface Invite { - app: string; - recipient: PatpNoSig; - resource: Resource; - ship: PatpNoSig; - text: string; -} diff --git a/ui/src/gear/metadata/index.ts b/ui/src/gear/metadata/index.ts deleted file mode 100644 index 341e8171..00000000 --- a/ui/src/gear/metadata/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './types'; -export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/metadata/lib.ts b/ui/src/gear/metadata/lib.ts deleted file mode 100644 index 64b91fc7..00000000 --- a/ui/src/gear/metadata/lib.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { parseUx } from '@urbit/aura'; -import { Path, Poke, PatpNoSig } from '@urbit/js-http-api'; -import { MdAppName, Association, Metadata, MetadataUpdate, MetadataUpdateAdd, MetadataUpdateRemove, MetadataEditField, MetadataUpdateEdit } from './types'; - -export const METADATA_UPDATE_VERSION = 2; - -export const metadataAction = (data: T, version: number = METADATA_UPDATE_VERSION): Poke => ({ - app: 'metadata-push-hook', - mark: `metadata-update-${version}`, - json: data -}); - -export const add = ( - ship: PatpNoSig, - appName: MdAppName, - resource: Path, - group: Path, - title: string, - description: string, - dateCreated: string, - color: string, - moduleName: string -): Poke => metadataAction({ - add: { - group, - resource: { - resource, - 'app-name': appName - }, - metadata: { - title, - description, - color, - 'date-created': dateCreated, - creator: `~${ship}`, - config: { graph: moduleName }, - picture: '', - hidden: false, - preview: false, - vip: '' - } - } -}); - -export { add as metadataAdd }; - -export const remove = ( - appName: MdAppName, - resource: string, - group: string -): Poke => metadataAction({ - remove: { - group, - resource: { - resource, - 'app-name': appName - } - } -}); - -export { remove as metadataRemove }; - -export const edit = ( - association: Association, - edit: MetadataEditField -): Poke => metadataAction({ - edit: { - group: association.group, - resource: { - resource: association.resource, - 'app-name': association['app-name'] - }, - edit - } -}); - -export { edit as metadataEdit }; - -/** - * @deprecated use {@link edit} instead - */ -export const update = ( - association: Association, - newMetadata: Partial -): Poke => { - const metadata = { ...association.metadata, ...newMetadata }; - metadata.color = parseUx(metadata.color); - return metadataAction({ - add: { - group: association.group, - resource: { - resource: association.resource, - 'app-name': association['app-name'] - }, - metadata - } - }); -}; - -export { update as metadataUpdate }; diff --git a/ui/src/gear/metadata/types.ts b/ui/src/gear/metadata/types.ts deleted file mode 100644 index 0d83135c..00000000 --- a/ui/src/gear/metadata/types.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Path, Patp } from '@urbit/js-http-api'; - -export type MdAppName = 'groups' | 'graph'; - -export type MetadataUpdate = - MetadataUpdateInitial -| MetadataUpdateAdd -| MetadataUpdateUpdate -| MetadataUpdateRemove -| MetadataUpdateEdit; - -export interface MetadataUpdateInitial { - associations: ResourceAssociations; -} - -export type ResourceAssociations = { - [p in Path]: Association; -} - -export type MetadataUpdateAdd = { - add: AssociationPoke; -} - -export type MetadataUpdateUpdate = { - update: AssociationPoke; -} - -export interface MetadataUpdateEdit { - edit: { - resource: MdResource; - group: string; - edit: MetadataEditField; - } -} - -export type MetadataEditField = Partial>; - -export type MetadataUpdateRemove = { - remove: { - resource: MdResource; - group: string; - } -} - -export interface MdResource { - resource: string; - 'app-name': MdAppName; -} - -export interface MetadataUpdatePreview { - group: string; - channels: Associations; - 'channel-count': number; - members: number; - metadata: Metadata; -} - -export type Associations = { - groups: AppAssociations - graph: AppAssociations; -} - -export type AppAssociations = { - [p in Path]: Association; -} - -export type Association = MdResource & { - group: Path; - metadata: Metadata; -}; - -export interface AssociationPoke { - group: Path; - resource: MdResource; - metadata: Metadata; -} - -export interface Metadata { - color: string; - creator: Patp; - 'date-created': string; - description: string; - title: string; - config: C; - hidden: boolean; - picture: string; - preview: boolean; - vip: PermVariation; -} - -export type MetadataConfig = GroupConfig | GraphConfig; - -export interface GraphConfig { - graph: string; -} - -export interface GroupConfig { - group: undefined | {} | MdResource; -} - -export type PermVariation = '' | ' ' | 'reader-comments' | 'member-metadata' | 'host-feed' | 'admin-feed'; From 4284d1e6f6719183611968fa93d12f0658f6474f Mon Sep 17 00:00:00 2001 From: tomholford Date: Fri, 26 May 2023 12:20:54 -0700 Subject: [PATCH 6/8] gear: initial draft of Permissions interface --- ui/src/gear/hood/types.ts | 34 +++++++++++++------ ui/src/gear/index.ts | 12 +++---- ui/src/gear/permissions/index.ts | 2 ++ ui/src/gear/permissions/lib.ts | 1 + ui/src/gear/permissions/types.ts | 58 ++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 ui/src/gear/permissions/index.ts create mode 100644 ui/src/gear/permissions/lib.ts create mode 100644 ui/src/gear/permissions/types.ts diff --git a/ui/src/gear/hood/types.ts b/ui/src/gear/hood/types.ts index 17676b47..61e1817a 100644 --- a/ui/src/gear/hood/types.ts +++ b/ui/src/gear/hood/types.ts @@ -1,3 +1,4 @@ +import { Perm } from "../permissions"; /** * A pending commit, awaiting a future kelvin version @@ -161,20 +162,15 @@ export interface Vat { export interface Vats { [desk: string]: Vat; } + /** * TODO: crisp one-liner describing a Pike */ export interface Pike { /** - * Hash of the desk, rendered as `@uv` - * - * @remarks - * Equivalent to - * ```hoon - * .^(@uv %cz /=desk=) - * ``` + * The sync source ship and desk for this Pike + * */ - hash: string; sync: { /** * Source desk for this Pike @@ -186,9 +182,15 @@ export interface Pike { ship: string; } | null; /** - * {@link Weft}s associated with this Pike + * Hash of the desk, rendered as `@uv` + * + * @remarks + * Equivalent to + * ```hoon + * .^(@uv %cz /=desk=) + * ``` */ - wefts: Weft[]; + hash: string; /** * how live is this pike? * @@ -201,6 +203,18 @@ export interface Pike { * dead - app is not running */ zest: "live" | "dead" | "held"; + /** + * {@link Weft}s associated with this Pike + */ + wefts: Weft[]; + /** + * {@link Perm}s granted to this Pike + */ + perms: Perm[]; + /** + * {@link Perm}s that this Pike lacks; required to run + */ + lacks: Perm[]; } export interface Pikes { diff --git a/ui/src/gear/index.ts b/ui/src/gear/index.ts index d3b8aea0..823bf045 100644 --- a/ui/src/gear/index.ts +++ b/ui/src/gear/index.ts @@ -8,13 +8,11 @@ export * from './settings'; export * as settings from './settings'; export * from './storage'; export * as storage from './storage'; -export * as hood from './hood'; export * from './hood'; -export * as docket from './docket'; +export * as hood from './hood'; export * from './docket'; -export * as utils from './utils'; +export * as docket from './docket'; export * from './utils'; - -// TODO: Userspace Permissions -// export * from './permissions'; -// export * as permissions from './permissions'; +export * as utils from './utils'; +export * from './permissions'; +export * as permissions from './permissions'; diff --git a/ui/src/gear/permissions/index.ts b/ui/src/gear/permissions/index.ts new file mode 100644 index 00000000..341e8171 --- /dev/null +++ b/ui/src/gear/permissions/index.ts @@ -0,0 +1,2 @@ +export * from './types'; +export * from './lib'; \ No newline at end of file diff --git a/ui/src/gear/permissions/lib.ts b/ui/src/gear/permissions/lib.ts new file mode 100644 index 00000000..693da49f --- /dev/null +++ b/ui/src/gear/permissions/lib.ts @@ -0,0 +1 @@ +export {} \ No newline at end of file diff --git a/ui/src/gear/permissions/types.ts b/ui/src/gear/permissions/types.ts new file mode 100644 index 00000000..296427a5 --- /dev/null +++ b/ui/src/gear/permissions/types.ts @@ -0,0 +1,58 @@ +/** + * A server identity + */ +type Dude = string; + +/** + * path - ship desk case spur + */ +type Spur = string; + +/** + * TODO + */ +interface Burr { + desk: string | null; + spur: Spur; +} + +/** + * TODO + */ +interface Spar { + care: string | null; + burr: Burr; +} + +interface PokePerm { + "write": { + jump: boolean; + dude: Dude | null; + } +} + +interface SubscribePerm { + "watch": { + jump: boolean; + dude: Dude | null; + path: string; + } +} + +interface ScryPerm { + "reads": { + vane: string; + spar: Spar; + } +} + +interface PressPerm { + "press": { + spur: Spur; + } +} + +/** + * A system permission + */ +export type Perm = PokePerm | SubscribePerm | ScryPerm | PressPerm; From 5ca77c14824f86fe2a4f3cb6b0a2082aa7d99e7c Mon Sep 17 00:00:00 2001 From: tomholford Date: Fri, 26 May 2023 14:58:02 -0700 Subject: [PATCH 7/8] gear: perms type descriptions from palfun --- ui/src/gear/hood/types.ts | 2 +- ui/src/gear/permissions/types.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/gear/hood/types.ts b/ui/src/gear/hood/types.ts index 61e1817a..d39110f4 100644 --- a/ui/src/gear/hood/types.ts +++ b/ui/src/gear/hood/types.ts @@ -164,7 +164,7 @@ export interface Vats { } /** - * TODO: crisp one-liner describing a Pike + * Update config & status for desk */ export interface Pike { /** diff --git a/ui/src/gear/permissions/types.ts b/ui/src/gear/permissions/types.ts index 296427a5..1a073623 100644 --- a/ui/src/gear/permissions/types.ts +++ b/ui/src/gear/permissions/types.ts @@ -9,7 +9,7 @@ type Dude = string; type Spur = string; /** - * TODO + * specific or any desk, at or under spur prefix */ interface Burr { desk: string | null; @@ -17,7 +17,7 @@ interface Burr { } /** - * TODO + * burr with specific or any care */ interface Spar { care: string | null; From 61c8ace03f9494466b92b549ec6a1180581b3960 Mon Sep 17 00:00:00 2001 From: tomholford Date: Thu, 1 Jun 2023 15:06:08 -0700 Subject: [PATCH 8/8] gear: add new Treaty types - Treaty now supports Seal --- ui/src/gear/docket/types.ts | 25 +++++++++++++++ ui/src/gear/permissions/types.ts | 30 ++++++++++++++++++ ui/src/state/mock-data.ts | 54 +++++++++++++++++++++++++++----- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/ui/src/gear/docket/types.ts b/ui/src/gear/docket/types.ts index c35399b5..9603ff38 100644 --- a/ui/src/gear/docket/types.ts +++ b/ui/src/gear/docket/types.ts @@ -49,11 +49,36 @@ export interface SuspendChad { suspend: null; } +// desk/lib/treaty.hoon +type Vane = 'ames' | 'behn' | 'clay' | 'dill' | 'eyre' | 'gall' | 'iris' | 'jael' | 'khan'; + +type Tail = { + jump?: boolean; + care?: string | null; + desk?: string | null; + dude?: string | null; + path?: string | null; + ship?: string | null; + spur?: string | null; + vane?: string | null; +} | null; + +interface SealPerm { + vane: Vane | null; + name: string; + hoon: string; + tail: Tail; +} + +export type Seal = SealPerm[]; + export interface Treaty extends Docket { ship: string; desk: string; cass: Cass; hash: string; + bill: string[]; + seal: Seal; } export interface Charges { diff --git a/ui/src/gear/permissions/types.ts b/ui/src/gear/permissions/types.ts index 1a073623..4956b3ba 100644 --- a/ui/src/gear/permissions/types.ts +++ b/ui/src/gear/permissions/types.ts @@ -56,3 +56,33 @@ interface PressPerm { * A system permission */ export type Perm = PokePerm | SubscribePerm | ScryPerm | PressPerm; + +/** + * Per lib/perms.hoon, Passport is intended for consumption by permission + * management frontends. + */ +export interface Passport { + /** + * Categorized perms + */ + rad: Perm[]; + /** + * Dangerous perms + */ + sys: Perm[]; + /** + * All apps perms + */ + any: Perm[]; + /** + * Unknown app perms + */ + new: Perm[]; + /** + * Specific app perms + */ + app: { + app: string; + pes: Perm[]; + }[]; +} diff --git a/ui/src/state/mock-data.ts b/ui/src/state/mock-data.ts index d3b3be2b..8f8ee9e3 100644 --- a/ui/src/state/mock-data.ts +++ b/ui/src/state/mock-data.ts @@ -12,12 +12,42 @@ import { Contacts, Timebox, harkBinToId, - Pikes + Pikes, + Seal } from '@/gear'; import _ from 'lodash'; import systemUrl from '../assets/system.png'; -export const appMetaData: Pick = { +const coinFlip = () => Math.random() > 0.5; + +const makeSeal: () => Seal = () => { + return [ + // write perm + { + vane: null, + name: 'write', + hoon: '[%write & %some-agent]', + tail: { + dude: null, + jump: coinFlip() + } + }, + // reads perm + { + vane: null, + name: 'reads', + hoon: '[%reads %g `%u `%settings-store /]', + tail: { + vane: 'gall', + care: 'u', + desk: 'landscape', + spur: '/', + } + } + ] +} + +export const appMetaData: Pick = { cass: { da: '~2021.9.13..05.41.04..ae65', ud: 1 @@ -25,7 +55,9 @@ export const appMetaData: Pick ({ glob: { base } }); @@ -345,7 +377,9 @@ export const mockPikes: Pikes = { sync: null, zest: 'dead', wefts: [], - hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0' + hash: '0v19.q7u27.omps3.fbhf4.53rai.co157.pben7.pu94n.63v4p.3kcb7.iafj0', + perms: [], + lacks: [], }, garden: { sync: { @@ -354,7 +388,9 @@ export const mockPikes: Pikes = { }, zest: 'live', wefts: [], - hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m' + hash: '0v18.hbbs6.onu15.skjkv.qrfgl.vf4oo.0igo5.2q0d3.6r3r8.2dkmo.oa04m', + perms: [], + lacks: [], }, landscape: { sync: { @@ -363,12 +399,16 @@ export const mockPikes: Pikes = { }, zest: 'live', wefts: [], - hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo' + hash: '0v1t.qln8k.cskmt.cn6lv.gu335.jfba6.kte90.iqqn3.aj67b.t389a.8imuo', + perms: [], + lacks: [], }, base: { sync: null, zest: 'live', wefts: [], - hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid' + hash: '0v1e.b5auh.6u82i.hqk1r.22kli.4ubef.a1cbo.3g532.6l49k.g0i8e.t6eid', + perms: [], + lacks: [], } };