Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Page properties: builders, commands and predict

Open
#133 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
55/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
api, backend, testing

Research direction

Read issue #84’s Events and Commands and IPC sections, then use the existing addBlock path as the entry point across @pbnotes/pages, pages-session.ts, pages-ipc.ts, src/shared/pages.ts, and src/preload/index.ts. Check the existing block builder, command and tests, plus pagesFold and list(page) for the expected property data. Done means the four property operations follow those patterns, preserve write order, expose properties in PagesState.showing, and pass the listed builder, command, session and store cases.

Written by the indexing model from the issue text.

Description

enhancement

Part of #84. This is the write side of the page properties domain model, all in @pbnotes/pages: the builders that make each event, the commands that check against the fold and write, and predict for writes not yet recorded. It sits on #132 (events, projection and reads). Nothing here touches the app: connecting the app to it is #142.

The design is #84's description. This ticket doesn't restate it; where they differ, #84 wins.

What already exists

  • After #132: the page.property.* events with their HANDLES entries, the Properties projection, the gate, and the reads (get, getValue, getItems, list, children).
  • The block side has the same three parts: pure builders (blockCreated and the rest), commands that check against the fold and write through PagesView.dispatch (addBlock and the rest), and predict.

What it takes

  • Builders, one per event, beside blockCreated, each returning { v, type, payload } with v from HANDLES. Pure, like the block builders: they read no clock and check nothing against a page. They are the only place a property payload is built, so a writer and a prediction always build the same bytes.
  • Commands: setProperty(view, page, path, value), unsetProperty(view, page, path), addPropertyItem(view, page, path, item) removePropertyItem(view, page, path, item), and:
    • removeProperty(view, page, path): one removed listing what view.state holds at path and under it. Nothing there appends nothing.
    • renameProperty(view, page, from, to): the writes that copy what view.state holds at and under from to to, then one removed of from, additions first. Refuses a to that already holds something, rather than merging into it.
    • They refuse what the gate would skip: a path that isn't a non-empty array of strings, a segment that is empty once trimmed, a value or item that isn't a scalar. A non-finite number matters most: JSON.stringify would write it as null, a real value. So nothing is written that folds to nothing.
    • They don't trim or normalize anything themselves; the fold does. Their checks compare the way the fold does: segments trimmed, strings in NFC.
    • A write that changes nothing appends nothing and resolves, like indentBlock with nothing above: setting the value a path already has, unsetting a path with no value, adding an item already there, removing one that isn't.
  • Prediction: predict folds property events too, so a caller can draw a write before it is recorded. Its inputs and result carry a page's properties beside its blocks. No at is needed: the projection keeps none (#84). Folding a property event twice leaves the same value and the same items, but a second item.added moves that item to the end of items, which is what "the latest item" reads. Either landed gets a case for it, or that reordering is shown to be harmless.
  • Exports and docs: the builders and commands exported from the package, and listed in packages/pages/README.md beside the block ones.

Test

All under node --test in packages/pages, with a PagesView whose dispatch folds into a held state; no app, no ledger.

  • Each builder writes v from HANDLES and the payload the schema gives, and folds through pagesFold to what the command meant.
  • Each command refuses a malformed path, value or item and appends nothing, NaN, Infinity and a " " segment among them; null and "" as a value are written.
  • Each no-op case above appends nothing, including one that differs only by trimming or NFC.
  • removeProperty lists exactly what the state holds at and under the path; folded, it leaves nothing there. renameProperty writes its additions before its removal, and a crash after the additions (only some events dispatched) leaves both keys.
  • predict over each property event, alone and mixed with block events, gives the state the fold gives; folding one that has already landed changes nothing.

Out of scope

  • The app: session, IPC, preload and PagesState (#142).
  • The table, and keeping in-flight writes for predict (#137).
  • Any meaning for an ["app", ...] key: aliases (#85), the cover (#107).
Dominant language
TypeScript
Stars
0
Forks
1
Avg merge
29m
Merged PRs (30d)
27

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from shovon/pbnotes

All issues in shovon/pbnotes

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.