MaxBody
untyped bigintMaxBody is the longest note this realm accepts, in bytes. A bound rather than none: every byte stored here locks a storage deposit, paid by whoever signs the write and refunded to whoever signs the delete (EFFECTIVE\_GNO.md section 9.2), and an unbounded write is an unbounded state the realm carries forever.
Value
(280 <untyped> bigint)
MaxTagLen
untyped bigintMaxTagLen bounds the index key for the same reason, and small because a tag is a label rather than a sentence.
Value
(24 <untyped> bigint)
PageSize
untyped bigintPageSize is how many tags the root page shows.
Value
(20 <untyped> bigint)
MaxNotes
untyped bigintMaxNotes and MaxPerAuthor bound the WHOLE board, which MaxBody does not. A per-call length limit bounds one write and nothing else: a caller posting one-byte notes in a loop grows the store and both indexes without limit. "An unbounded container a third party can grow is an unbounded storage deposit someone is paying for" is a rule this realm exists to demonstrate, so it had better obey it. Two caps rather than one, and what each buys is narrower than it looks. MaxNotes bounds the state, which is the property this realm promises. MaxPerAuthor stops one ADDRESS, not one actor: addresses are free, so fifty fresh ones at twenty notes each still fill the board and lock everyone else out until somebody retracts. Keeping a board open to strangers needs something a griefer cannot mint for free, a deposit or an expiry, which this demo does not carry. Retracting frees a slot, so neither cap is a one-way door. MaxPerAuthor is answered by byAuthor.Count, which is the index doing the job it was added for.
Value
(1000 <untyped> bigint)
MaxPerAuthor
untyped bigintMaxNotes and MaxPerAuthor bound the WHOLE board, which MaxBody does not. A per-call length limit bounds one write and nothing else: a caller posting one-byte notes in a loop grows the store and both indexes without limit. "An unbounded container a third party can grow is an unbounded storage deposit someone is paying for" is a rule this realm exists to demonstrate, so it had better obey it. Two caps rather than one, and what each buys is narrower than it looks. MaxNotes bounds the state, which is the property this realm promises. MaxPerAuthor stops one ADDRESS, not one actor: addresses are free, so fifty fresh ones at twenty notes each still fill the board and lock everyone else out until somebody retracts. Keeping a board open to strangers needs something a griefer cannot mint for free, a deposit or an expiry, which this demo does not carry. Retracting frees a slot, so neither cap is a one-way door. MaxPerAuthor is answered by byAuthor.Count, which is the index doing the job it was added for.
Value
(20 <untyped> bigint)
note
typeValue
v0.note
notes
*v0.Store- OID
- 0736c9…fd9a:4
notes details
byTag
v0.Index- OID
- 0736c9…fd9a:8
byTag details
byAuthor
v0.Index- OID
- 0736c9…fd9a:10
byAuthor details
Post
func(tag string, body string) int64Post files a note under a tag and returns its id. The store write and both index writes happen here, in this order, in one frame. An abort anywhere in it leaves none of them applied, which is what makes three containers safe to keep apart.
- OID
- 0736c9…fd9a:11
Post details
Retract
func(id int64)Retract removes a note. Only its author may, and the store and both indexes are unwound together.
- OID
- 0736c9…fd9a:13
Retract details
caller
func() .uverse.address- OID
- 0736c9…fd9a:14
caller details
mustIndex
func(err .uverse.error)- OID
- 0736c9…fd9a:15
mustIndex details
normaliseTag
func(tag string) stringnormaliseTag lowercases and validates the tag. Validated at WRITE time rather than escaped at render time, deliberately: a tag is also an index key and a path segment, so a tag that could carry a pipe or a slash would break the table and the URL as well as the page. The charset is the narrowest thing that still reads as a label.
- OID
- 0736c9…fd9a:16
normaliseTag details
assertRoom
func(who .uverse.address)assertRoom refuses a write the board has no room for, globally or for this address. Checked before the store write, so a refusal costs the caller the gas of three reads and nothing is half-applied.
- OID
- 0736c9…fd9a:17
assertRoom details
assertBody
func(body string)- OID
- 0736c9…fd9a:18
assertBody details
realmURL
untyped stringrealmURL is this realm as gnoweb serves it. Links are absolute because the path ends in /v0: a relative "./kitindexdemo:tag/x" resolves against the parent directory to .../kitindexdemo/kitindexdemo:tag/x, which does not exist. Not derived at runtime: a Render has no cur, and CurrentRealm there is the caller. TestRealmURLMatchesTheModule pins it to the module line.
Value
"/r/moul/x/kitindexdemo/v0"
Render
func(path string) stringRender is the whole public surface. Three pages: the tag list, one tag, one author. Every row goes through ui.NewTable rather than concatenated pipes, and every caller string through ui.Cell, because a public path is immutable and a Render that ships wrong ships forever.
- OID
- 0736c9…fd9a:19
Render details
renderIndex
func(req *v0.Request) string- OID
- 0736c9…fd9a:21
renderIndex details
renderTag
func(tag string) string- OID
- 0736c9…fd9a:22
renderTag details
renderAuthor
func(addr string) string- OID
- 0736c9…fd9a:23
renderAuthor details
notesTable
func(hits []v0.ID, empty string) stringnotesTable renders a set of ids as rows, skipping any id the store no longer holds. Skipping rather than panicking: an index and a store are two containers, and a reader should see the records that exist rather than a page that aborts. Retract keeps the two in step, so a miss here means a bug worth surviving, not worth hiding.
- OID
- 0736c9…fd9a:24
notesTable details
pager
func(page int, pages int) stringpager renders the previous/next links, or nothing when there is one page.
- OID
- 0736c9…fd9a:25