AO made in Svelte. Mobile-first, Tor Browser-first, manual first
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
16 KiB

// Every card has a color, right now only five preset colors exist (they can be renamed with the glossary and recolored with CSS)
export type Color = 'red' | 'yellow' | 'green' | 'purple' | 'blue' | 'black'
// The regions or areas within a card
// There are four main zones within a card: the priorities,
// the optional pinboard (grid/pyramid/rune),the subTasks (main pile), and completed cards
export type CardZone =
| 'card' // The card itself, the whole card
| 'priorities' // The card's priorities section (right card drawer)
| 'grid' // A pinboard that can be added to the card (shows on card)
| 'subTasks' // The main pile of subcards within this card (bottom card drawer)
| 'completed' // Checked-off tasks archived when discarded (viewable in priorities card drawer)
| 'context' // The context area above a card that contains the card history (cards can be dragged from here)
| 'discard' // The background of the page behind the card, where cards can be dropped to discard
| 'panel' // Any other unspecified side panel where cards can be dragged out of (to copy, not move, the card)
| 'gifts' // The gifts area at the top left of the member card where cards you receive accumulate.
| 'stash' // The stashed cards area of the card (right card drawer)
// A card's pinboard can be in one of three styles
export type PinboardStyle = 'grid' | 'pyramid' | 'rune'
// The global left sidebar can open and display one of these tabs at a time
export type LeftSidebarTab =
| 'hub'
| 'gifts'
| 'guilds'
| 'members'
| 'calendar'
| 'bounties'
| 'manual'
| 'search'
| 'deck'
// The global right sidebar can display one of these Bull tabs
export type RightSidebarTab = 'resources' | 'p2p' | 'crypto' | 'membership'
// The right side of a card displays these tabs, which can be clicked to open the corresponding card drawer
export type CardTab = 'priorities' | 'timecube' | 'lightning'
// When a member gifts/sends/passes a card to another member, the cards .pass array holds an array of passes
// The 0th element holds the memberId of the sender, and the 1st element holds the memberId of the recipient
export type CardPass = string[2]
// Definition of an AO
export interface AoState {
session: string
token: string
loggedIn: boolean
user: string
ao: ConnectedAo[]
sessions: Session[]
members: Member[]
tasks: Task[]
resources: Resource[]
memes: Meme[]
socketState?: string
protectedRouteRedirectPath?: string
bookings?: Booking[] // Used on server to track calendar events on a timer
cash: {
address: string
alias: string
currency: string
spot: number
rent: number
cap: number
quorum: number
pay_index: number
usedTxIds: number[]
outputs: Output[]
channels: Channel[]
info: SatInfo
}
loader?: {
token: string
session: string
connected: string
connectionError: string
reqStatus: string
lastPing: number
}
}
// An AO serves its members, who each have an account on the AO server.
export interface Member {
type: 'member-created' // The event is added directly to the database so it has this as an artifact, could filter on member-created and remove here
name: string // The name of the member
memberId: string // The unique UUID of the member
address: string // ???
active: number // The member's active status. Number increases each consecutive active month.
balance: number // Member's point balance
badges: [] // Badges that the member has collected
tickers: Ticker[] // Customizable list of crypto tickers on the member's right sidebar
info: {} // ???
timestamp: number // When the member was created
lastUsed: number // Last time the member logged in, used a resource, or barked
muted: boolean // Whether the member has sound effects turned on or off (sound effects not currently implemented)
priorityMode: boolean // Whether the member has activated Priority Mode, which shows the first priority above its parent card
fob: string // The member can enter a fob ID number from a physical fob, saved here for when they tap
potentials: Signature[] // List of potential actions built up on the member (not currently in use)
banned: boolean // True if the member is currently banned (member continues to exist)
draft: string // The member's currently-saved draft (also saved on client)
tutorial?: boolean // Whether the member has completed the initial interactive tour of the AO
p0wned?: boolean // Whether the member has had their password reset (changes to false when they set it themselves)
phone?: string // Phone number used for Signal notifications
}
// A member can create and collect cards. The words 'card' and 'task' are used as synonyms, because the AO is meant for action.
export interface Task {
taskId: string // ao-react: Random UUID | ao-3: CRC-32 hash of the content
name: string // The text of the card, the main content. Can be plain text, Markdown, or HTML and JavaScript (optimized for injection).
color: Color // Color of the card as a word | Future: Could be any color word or hex code paired with a word naming the color
deck: string[] // *Array of memberIds of members who grabbed and are holding the card in their deck
guild: string | boolean // Optional guild / pin / tag title for the card. This is editable (unlike cards currently). Guild cards are indexed in Guilds sidebar on left. (Value of 'true' could mean that guild name equals card text [not implemented yet].)
address: string // Mainnet bitcoin address for this card (generated by calling address)
bolt11?: string // Lightning network bitcoin address for this carde (generated by calling invoice-created)
payment_hash: string //
book?: Booking // Book/schedule this card as an event on the calendar
priorities: string[] // *Array of taskIds of cards prioritized within this card
subTasks: string[] // *Array of taskIds of cards within this card
completed: string[] // *Array of taskIds of checked-off completed cards within this cards. Cards saved here when discarded with any checkmarks on them.
pinboard?: Pinboard | null // *Pinboard object containing pinboard properties
pins?: Pin[] // *New way of doing the Grid, Pyramid, and upcoming Rune layouts for the card
parents: string[] // *List of this cards parents, ought to be kept updated by mutations.
claimed: string[] // Lists of taskIds who have checked this card (thus claiming the bounty)
claimInterval?: number // Automatic uncheck timer in milliseconds [this feature will change to uncheck the cards within]
//uncheckInterval // Rename of claimInterval to be rolled out
uncheckThisCard?: boolean // Unchecks this card every uncheckInterval if true
uncheckPriorities?: boolean // Unchecks prioritized cards every uncheckInterval if true
uncheckPinned?: boolean // Unchecks pinned cards every uncheckInterval if true (maybe could combine with uncheckPriorities)
dimChecked?: boolean // If true, checked cards on the pinboard and in the priorities list will display visually dimmed to make tasking easier
signed: Signature[] // Members can explicitly sign cards to endorse them (future option to counter-sign as -1 is already built-in)
passed: string[][] // Array of [senderMemberId, receiverMemberId] pairs of pending gifts sent to the receiving member. Cleared when opened.
giftCount?: number // Count of unopened gift cards that ought to be kept automatically updated, for showing this number ot other members
lastClaimed: number // The last time someone checked this card off (Unix timestamp)
allocations: Allocation[] // List of points temporarily allocated to this card from parent cards, making this card a claimable bounty
boost: number // Bonus points on the card (?)
goal?: number // Optional points goal shows after the current number of points on a card, e.g., 8/10 points raised in the crowdfund.
highlights: number[]
seen: UserSeen[] // Array of events marking the first (?) or most recent (?) time they looked at the card. Used for unread markers.
timelog?: LabourTime[] // Arary of timelog events on the card
created: number // When the card was created (Unix timestamp)
showChatroom?: boolean // Whether or not to show the chatroom tab. Only allowed on cards with a .guild set for simplicity and transparency's sake.
avatars?: AvatarLocation[] // When a member joins a chatroom, it shows they are "at" that card. | Future: Little avator icons that can be moved from card to card or clicked to follow.
memberships?: Membership[] // Members can "join" a card as members. The first member is automatically Level 2 and can boss the Level 1's around. You can decrease your level and lose your power.
showStash?: boolean // Whether or not to show the stash tab. Only allowed on cards with a .guild set for simplicity and transparency's sake.
stash?: {
// *Stash of more cards associated with this card. Members have access to stashes of their level and below.
[key: number]: string[] // Each numbered stash level contains a list of taskIds of cards stored in that stash level.
}
unionHours?: number // Number of estimated hours for the task
unionSkill?: number // Skill level required for the task (0-5)
unionHazard?: number // Hazard level for the task (0-5)
loadedFromServer?: boolean // True if the card has been loaded from the server, false if empty placeholder taskId object
stars?: number // Can be simple number or later a Rating[]
touches?: number // New feature to count number of time a card was handled, to identify popular cards and personal hotspots.
aoGridToolDoNotUpdateUI?: boolean // Rendering hack, maybe this can be improved and removed
// *These properties contain taskIds of cards that are within or closely associated with this card, for the purposes of search, content buffering, etc.
}
// A booked/scheduled event or resource
export interface Booking {
memberId: string // The member that scheduled the event (?)
startTs: number // The start of the event (Unix timestamp)
endTs: number // The end time of the event. Optional—but if omitted behavior is undefined. (Unix timestamp)
}
// An AO can connect to another AO over tor to send cards
export interface ConnectedAo {
name?: string
address: string
outboundSecret: false | string
inboundSecret: string
lastContact: number
links: string[]
}
// Hardware devices can be connected to the AO as resources over LAN. Resources can be activated in the Bull (right sidebar).
export interface Resource {
resourceId: string // UUID of the resource
name: string
charged: number // How many points it costs to use the resource each time
secret: string // ???
trackStock: boolean // If true, the resource will track its inventory
stock: number // Simple numeric tracking of inventory stock, works for most things
}
// Files detected in the ~/.ao/memes folder are each loaded as a Meme
export interface Meme {
memeId: string // UUID that matches the corresponding taskId of the card that is created in lockstep with the Meme object.
filename: string // Just the filename and extension, not the path
hash: string // Hash of the file
filetype: string
}
// Cordinates of a card on a pinboard or in a list of cards
export interface Coords {
x?: number
y: number
}
// Specifies a card taskId at a given location at a specific location within another card.
// For pinboard locations, .coords must coordinates for the current pinboard type
// For stashed cards, .level specifies which stash level the card is stored in
export interface CardLocation {
taskId?: string // Optional because sometimes a CardLocation is used to described a location where a card will be played/placed
inId?: string
zone?: CardZone // Optional because sometimes a CardLocation describes a card that is not in any location yet
level?: number
coords?: Coords
}
// An atomic card play, defining a card to remove (from) and a card to place (to)
export interface CardPlay {
from: CardLocation
to: CardLocation
}
// Defines the dimensions and other properties of a spread or layout of cards.
// Could be expanded or inherited from to create new types of spreads such as a freeform canvas or non-euclidian pinboard.
export interface Pinboard {
spread: PinboardStyle
height: number
width?: number
size: number // Size of squares, roughly in ems
}
// A card pinned to a pinboard
// Pinboards set to rune layout only use x (y always 0)
export interface Pin {
taskId: string
y: number
x?: number
}
// A guild can temporarily allocate some of its points to a task in its priorities
// Anyone who checks off the task will claim the points on it, including all its allocations
// Allocated points are actually moved from the parent card at the time (in state) and moved back if the card is deprioritized
// All mutations related to moving points around must be perfect to prevent double spend issues
export interface Allocation {
type?: string
taskId: string
allocatedId: string
amount: number
blame?: string
}
// A member may sign a card with a positive (1, default), neutral (0), or opposing (-1) opinion, or instead sign with a note/comment
// This can be used for votes, upvotes/downvotes (and maybe reaction emojis? reactions could replace signing)
export interface Signature {
memberId: string
timestamp: Date
opinion: number | string
}
// A member may rate a card 0-5 stars
export interface Rating {
memberId: string
stars: number
}
// A card is marked when a member sees it for the first time. Used to mark unread cards (feature currently inactive).
export interface UserSeen {
memberId: string
timestamp: Date
}
// Log of one duration of time to the timelog on a card
export interface LabourTime {
memberId: string
taskId: string
inId: string
start: number
stop: number
}
// Each member has an "avatar" (currently no icon yet) that can be placed on a card to show your location to other members.
// When you join a chatroom on a card, you automatically hop your avatar to that card (task-visited event).
export interface AvatarLocation {
memberId: string
timestamp: number
area: number
}
// Members can join guilds. Members of a guild have a numeric level.
// Each level has a stash of cards that only members of that level or above can edit.
// Members of higher levels can change the level of members with the same or lower levels.
// The system is stupid and you can increase your own level too low and lose your power, or too high and mess up the stash.
export interface Membership {
memberId: string
level: number
}
// Members can add tickers in the sidebar, which show the exchange rate between a 'from' and 'to' currency (three-letter currency abbreviation)
export interface Ticker {
from: string
to: string
}
export interface Output {
value: number
}
export interface Channel {
channel_sat: number
channel_total_sat: number
}
// A browser session object
export interface Session {
type: 'session-created' // Event is added directly to the database, this is an artifact of that
session: string // Session string?
ownerId: string // MemeberId of the session owner
timestamp: Date // When the session was created
}
export interface LightningChannel {
peer_id?: any
funding_txid?: any
state?: any
connected?: boolean
channel_total_sat: number
channel_sat: number
}
export interface SatInfo {
channels?: LightningChannel[]
mempool?: { sampleTxns: any[]; size: any; bytes: any }
blockheight?: number
blockfo?: any
id?: any
outputs?: any[]
address?: { address: string }[]
}
export interface SearchResults {
query: string
page: number
missions: Task[]
members: Task[]
tasks: Task[]
all: Task[]
length: number
}
export const emptySearchResults = {
missions: [],
members: [],
tasks: [],
all: [],
length: 0,
}