Skip to content

TipTap → BlockNote editor migration (0312) - #496

Merged
crs48 merged 25 commits into
mainfrom
claude/0312-tiptap-to-blocknote-editor-migration
Jul 13, 2026
Merged

TipTap → BlockNote editor migration (0312)#496
crs48 merged 25 commits into
mainfrom
claude/0312-tiptap-to-blocknote-editor-migration

Conversation

@crs48

@crs48 crs48 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

Implements exploration 0312: replaces the entire TipTap-based rich-text editor with a BlockNote-based one (overturning 0297's rejection now that document back-compat is waived — prerelease, breaking OK).

Net: −33k lines. The Yjs/LWW persistence path is unchanged; documents move to a new content-v4 fragment (BlockNote schema) with a lazy, lossy legacy import from the old content fragment.

What changed

  • New packages/editor/src/blocknote/ layer: XNetEditor (BlockNoteView + Yjs collab bound to the node's Y.Doc), custom specs — mention/hashtag/wikilink/inlineMath inline content, callout/embed/pageEmbed/databaseEmbed/taskViewEmbed/mermaid/richLink blocks, aiGenerated style — suggestion controllers for / @ # [[ (multi-char trigger is native), sender-side URL paste → embed/rich-link card (0295), lazy legacy import, Block-JSON walkers preserving the 0168/0169 mention/tag contracts, block-id-keyed page tasks.
  • All surfaces swapped: web + Electron PageView, TaskInlineEditor, canvas inline page surface, MeetingsSurface (meeting notes append BlockNote structure, round-trip-verified), Expo WebView embed, devtools seed docs.
  • EditorContribution re-typed (breaking, major): BlockNote specs + slash items instead of TipTap extensions; 0205 schema-skew guard now checks contributed spec names against the statically bundled set.
  • AI page-markdown surface reads/writes content-v4 fragments (mode blocknote-yjs, breaking); 1,000-page byte-stability roundtrip gate still green.
  • Fragment readers (query search, hub indexer, rich-text cells, history, blob-CID scan) read content-v4 first with legacy fallback and render the new inline atoms as text.
  • Deleted: RichTextEditor, FloatingToolbar, slash menu, suggestion popups, emoji menu, live preview, markdown source mode, document-compat, all TipTap extensions/NodeViews and @tiptap/* deps (~33k lines). Comments are editor-decoupled: node-backed panel threads stay (0276); in-document marks retired (ThreadStore deferred).
  • Found & fixed en route: a stale duplicate prosemirror-transform@1.10.5 (no Transaction.changedRange) would have crashed BlockNote at mount — pinned to ^1.12.0 via pnpm override, caught by the new two-peer convergence test.

Consciously dropped

Obsidian-style live syntax preview and the markdown source mode (BlockNote is WYSIWYG-first; markdown stays as shortcuts/paste/export).

Validation

  • Root vitest: 961/961 files, 10,145+ tests green (includes new convergence/round-trip, legacy import, doc-walker, search extractor, AI roundtrip, seed suites)
  • Web production build passes the PWA workbox gate (main chunk 5.0 MB + 1.1 MB editor-vendor split)
  • e2e editor specs rewritten against BlockNote DOM (CI editor-ux lane)
  • Zero @tiptap/ imports remain
  • Known pre-existing blocker (not this PR): fresh dev databases crash with no such column: p.tiebreak_key (0305 fallout, reproduced on unmodified main) — filed separately

🤖 Generated with Claude Code

xNet Test added 19 commits July 13, 2026 14:11
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…(0312)

New packages/editor/src/blocknote layer: XNetEditor bound to the node
Y.Doc via the content-v4 fragment (Yjs collab unchanged), custom specs
(mention/hashtag/wikilink/inlineMath inline, callout/embed/pageEmbed/
databaseEmbed/taskViewEmbed/mermaid/richLink blocks, aiGenerated style),
suggestion controllers for / @ # [[, sender-side URL paste to embed or
rich-link card (0295), lazy legacy TipTap-fragment import via a
dependency-free Yjs walker, and Block-JSON walkers preserving the
0168/0169 mention/tag contracts and block-id-keyed page tasks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…p extensions (0312)

BREAKING CHANGE: EditorContribution.extension/toolbar are gone; plugins
now contribute blockSpecs/inlineContentSpecs/styleSpecs (opaque, keyed by
spec name) plus behavior-only slashMenuItems. The 0205 schema-skew guard
now flags any contributed spec name not statically bundled in the host
editor schema (XNET_SCHEMA_SPEC_NAMES). @tiptap/core dependency dropped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…ragment (0312)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
… to content-v4 (0312)

apps/web: Editor/PageView/TaskInlineEditor on BlockNote; write-through
task metadata retired (hosted tasks lock assignee/due-date to the doc);
mermaid plugin contributes behavior only; dead toolbar/wikilink shims
deleted. Readers: query search extractor, hub search indexer, database
rich-text cells, history, and blob-cid scan all read content-v4 first
with legacy fallback and render mention/hashtag/wikilink/inlineMath
atoms as text. packages/react gains useMergedEditorContributions with
the 0205 skew guard over bundled spec names. Root vitest inlines
@blocknote/@Mantine ESM for jsdom suites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…eads)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…nt-v4 fragments (0312)

New ai-surface/page-fragment module: Yjs walkers converting the
content-v4 BlockNote fragment to markdown (legacy content fallback) and
a bounded md-to-fragment writer with unique blockContainer ids; adapter
mode renamed tiptap-yjs to blocknote-yjs (breaking). linkify header now
mirrors BlockNote's link policy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…ing notes append BlockNote blocks (0312)

Electron comments read nodes directly (inline anchors retired);
enhance-append writes blockGroup/blockContainer structure into
content-v4 (round-trip-verified against BlockNote's own serializer)
with legacy-content read fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…face on XNetEditor (0312)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Removes RichTextEditor, FloatingToolbar, EditorToolbar, SlashMenu,
suggestion popups, EmojiMenu, LinkTargetMenu, EditorSurface, live
preview, markdown structural editing, document-compat, extension tiers,
all TipTap extensions and NodeViews, the vendored toolbar UI kit, the
legacy Y.Text core editor, and every @tiptap/* dependency. usePageComments
is now editor-decoupled (panel threads only). New XNetEditor stories
replace the RichTextEditor stories; root barrel exports only pure
document utilities.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…r (0312)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…k; inline @blocknote for electron vitest (0312)

Keeps every precached file under the PWA workbox 6MB ceiling (main
chunk 6.2MB -> 5.0MB + 1.1MB editor-vendor).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
…prosemirror-transform (0312)

The convergence test exposed a real crash: prosemirror-state resolved a
stale duplicate prosemirror-transform@1.10.5 without Transaction
changedRange (BlockNote 0.51 calls it at mount) — pinned via pnpm
override to ^1.12.0. Editor vitest project inlines @blocknote/@tiptap
for a single prosemirror instance. Validation checklist annotated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 19:13 — with GitHub Actions Inactive
xNet Test added 2 commits July 13, 2026 21:27
…m, e2e harness on XNetEditor (0312)

- prettier --write over the 19 files CI flagged
- ci.yml editor-ux unit step points at the blocknote test files (old
  chrome tests were deleted with the TipTap removal)
- storybook plugins shim exports the spec-based schema-safety guard
- tests/e2e harness mounts XNetEditor (RichTextEditor is gone) — this
  was the sync-matrix web convergence timeout
- drop stale @xnetjs/editor/extensions vitest alias

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 19:31 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Preview removed for PR #496.

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🖼️ UI changes in this PR

Components

🆕 Editor/XNetEditor — Empty

Editor/XNetEditor — Empty

🆕 Editor/XNetEditor — Legacy Import

Editor/XNetEditor — Legacy Import

🆕 Editor/XNetEditor — Read Only

Editor/XNetEditor — Read Only

Interactions

🎬 Create a page and use the editor

Create a page and use the editor

▶ Watch MP4

Auto-captured by CI · run. Informational — not a blocking check.

github-actions Bot added a commit that referenced this pull request Jul 13, 2026
…groups (0312)

Three defects found by running the editor-ux/sync-matrix e2e suites
against the real app:

- useCreateBlockNote depended on per-render host callback identities,
  recreating the editor every parent render — focus dropped ~11ms after
  landing and typed input vanished. Host callbacks now flow through
  refs; creation deps are schema/fragment/awareness only.
- @blocknote/mantine resolved @mantine/core 9, which renders React 19
  style context elements — under React 18 they become legacy Consumers
  and crash with 'render is not a function'. Pinned @mantine/core+hooks 8
  (both allowed by @blocknote/mantine's peer range).
- Custom slash items appended after the defaults made their groups
  non-contiguous, duplicating React keys on group headers; items are
  regrouped before filtering.

editor-ux specs now select with the pointer (BlockNote opens the
formatting toolbar on pointer selection, not shift+arrow).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 20:12 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: xNet Test <test@xnet.dev>
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 20:22 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 20:47 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
@crs48
crs48 temporarily deployed to pr-496 July 13, 2026 20:58 — with GitHub Actions Inactive
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
@crs48
crs48 merged commit be14229 into main Jul 13, 2026
23 checks passed
@crs48
crs48 deleted the claude/0312-tiptap-to-blocknote-editor-migration branch July 13, 2026 21:07
github-actions Bot added a commit that referenced this pull request Jul 13, 2026
crs48 added a commit that referenced this pull request Jul 15, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @xnetjs/plugins@2.0.0

### Major Changes

- [#496](#496)
[`6a5a15e`](6a5a15e)
Thanks [@crs48](https://github.com/crs48)! - AI page-markdown surface
re-targeted to the BlockNote editor (exploration 0312).
- **Breaking**: the page-markdown apply adapter mode `'tiptap-yjs'` is
renamed
to `'blocknote-yjs'` in `AiPageMarkdownApplyAdapterResult['mode']` and
    `AiPageMarkdownApplyResult['mode']`. Adapters that returned
`mode: 'tiptap-yjs'` must return `'blocknote-yjs'` (or
`'yjs'`/`'custom'`).
  - New Yjs-fragment ↔ markdown conversion for BlockNote (`content-v4`)
documents, dependency-light (walks the Yjs XML tree directly, no
editor/DOM):
    - `xnetPageFragmentToMarkdown(doc)` reads the BlockNote fragment
(paragraph/heading/lists/check items/code/quote/callout/table + inline
`mention`/`hashtag`/`wikilink`/`inlineMath` atoms), falling back to the
      legacy TipTap `content` fragment when `content-v4` is empty
(`blockNoteFragmentToMarkdown` / `legacyFragmentToMarkdown` are also
      exported).
    - `replaceXNetPageFragmentWithMarkdown(doc, markdown)` writes the AI
markdown subset (paragraphs, headings, bullet/numbered/check lists with
nesting, fenced code, quotes, callouts, wikilinks) as BlockNote PM XML —
`blockGroup > blockContainer` (unique `id` per block) wrappers — in one
      Yjs transaction.
- `createBlockNotePageMarkdownAdapter({ resolveDoc })` packages both as
an
      `AiPageMarkdownApplyAdapter` (plus `readMarkdown`) for
`xnet_apply_page_markdown`, replacing the TipTap-era document bridge.
    - `XNET_PAGE_FRAGMENT_FIELD` (`'content-v4'`) and
      `XNET_PAGE_LEGACY_FRAGMENT_FIELD` (`'content'`) constants.
  - `@xnetjs/plugins` now depends on `yjs`; the unused `@tiptap/core`
    devDependency is gone.

- [#496](#496)
[`2a7b80f`](2a7b80f)
Thanks [@crs48](https://github.com/crs48)! - `EditorContribution`
carries BlockNote specs instead of TipTap extensions (exploration 0312).
- **Breaking**: `EditorContribution.extension` (TipTap `Extension`) and
`EditorContribution.toolbar` (`ToolbarContribution`, removed entirely)
are
    gone. Plugins now contribute `blockSpecs` / `inlineContentSpecs` /
    `styleSpecs` (opaque BlockNote spec objects keyed by spec name) plus
    behavior-only `slashMenuItems`.
  - **Breaking**: the editor schema-skew guard is spec-based —
`isSchemaDefiningExtension` is replaced by
`isSchemaDefiningContribution`,
and `findEditorSchemaRisks` / `warnOnEditorSchemaRisks` take the host's
statically bundled spec names and flag any contributed spec outside that
    set (0205 invariant: schema specs must be identical across all
    collaborators or Yjs silently drops content).
  - `SlashCommandContext.editor` is now a BlockNote editor instance.
  - The `@tiptap/core` dependency is removed.

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/abuse@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/data@2.0.0

### Minor Changes

- [#496](#496)
[`85c9700`](85c9700)
Thanks [@crs48](https://github.com/crs48)! - Yjs fragment readers
understand the BlockNote document schema (exploration 0312).

Documents now live in the `content-v4` fragment using BlockNote's
ProseMirror
shape (`blockGroup > blockContainer > blockContent`); the legacy TipTap
`content` fragment remains readable as a fallback until each doc is
lazily
  imported.
- `@xnetjs/data`: `getRichTextPlainText` extracts text from
BlockNote-shaped
rich-text cells, including the new inline atoms (`mention` → `@label`,
`hashtag` → `#name`, `wikilink` → title, `inlineMath` → latex), while
still
    reading legacy TipTap-shaped cells.
- `@xnetjs/history`: version-diff text extraction prefers `content-v4`
(legacy
`content` fallback) and renders BlockNote inline atoms as readable text.
  - `@xnetjs/react`: new `useMergedEditorContributions` /
`mergeEditorContributions` (+ `MergedEditorContributions` type) collect
plugin-contributed BlockNote
`blockSpecs`/`inlineContentSpecs`/`styleSpecs`
    and slash menu items from the plugin registry, running the editor
schema-skew guard (`warnOnEditorSchemaRisks`) against the host's
statically
    bundled spec names and excluding un-bundled (skew-hazard) specs.
  - `@xnetjs/runtime`: blob-CID retention scanning now also walks the
    `content-v4` and `content` fragments, so blobs referenced from page
    documents are discovered.

- [#523](#523)
[`a91f278`](a91f278)
Thanks [@crs48](https://github.com/crs48)! - Drafts P2/P3 (exploration
0329): Patchwork-style branching on the change log.
- `@xnetjs/data`: `Draft` node schema (`DRAFT_SCHEMA_IRI`, entries map,
no
nesting); `NodeStore` draft overlay — `setCheckedOutDraft` swaps member
reads to clone content under original ids, redirects member writes to
clones with lazy copy-on-write, mirrors clone change events to
original-id
subscribers, and exposes `getRaw` for overlay-free reads; device-local
    draft privacy set (`markDraftPrivate`/`isDraftPrivate`).
- `@xnetjs/history`: draft lifecycle (`createDraft`, `forkNodeIntoDraft`
—
signed snapshot-create + pinned fork point + Yjs blob fork with state
    vector, `discardDraft`, `listDrafts`, never-fork policy); merge
(`threeWayPropertyMerge`, `mergeDraft` — one merger-signed squash batch
    with draft-born promotion via temp ids, relation remapping, deletion
    conflict cards, idempotent Yjs delta lane, provenance) and
    `refreshDraftFromMain` (floating drafts).
  - `@xnetjs/runtime`: `NodeStoreSyncProvider` gains a `shouldPublish`
predicate; the personal node-sync room excludes draft-private nodes, and
    draft privacy is rehydrated before sync starts.

- [#523](#523)
[`dd956e5`](dd956e5)
Thanks [@crs48](https://github.com/crs48)! - Drafts UI plumbing
(exploration 0329 P2/P3).
- `@xnetjs/react`: new `useDraft(hostId)` hook (hooks sub-barrel)
binding the
draft engine and the NodeStore checkout overlay — list/create open
drafts
    for a host, `checkout` (content-swap reads + lazy copy-on-write via
    `onMissingMember` → `forkNodeIntoDraft`), `returnToMain`, `discard`
    (leaves the checkout first), `merge` (merger-signed squash; returns
    conflict cards), `refresh` (fold main into the draft; pauses on
    conflicts), `setReviewRequested`, and `computeReview` — per-property
three-way review cards (base at fork vs main now vs draft now) plus Yjs
document-differs indicators, computed without applying anything.
Database
    hosts widen the member scope to their row nodes. Re-exports
    `DraftMergeConflict`, `MergeDraftResult`, `RefreshDraftResult` for
    consumers.
- `@xnetjs/data`: the `Draft` schema gains an optional `reviewRequested`
    checkbox (default `false`) — the P4 request-surfacing flag the
    Inbox/Requests surface lists open drafts by.

- [#499](#499)
[`e4cb876`](e4cb876)
Thanks [@crs48](https://github.com/crs48)! - Add the `DebugReport`
schema (`DebugReportSchema`, `type DebugReport`) for
first-party crash/debug-report triage nodes (exploration 0315). Reports
carry
code-level diagnostics only, group by fingerprint, and inherit access
from their
  diagnostics Space via the standard space cascade.

- [#523](#523)
[`0f7ef43`](0f7ef43)
Thanks [@crs48](https://github.com/crs48)! - Time Machine P1
(exploration 0329): frontiers, checkpoints, pins, prune horizon, scope
timelines, production Yjs snapshot capture, and a React scrub hook.
- `@xnetjs/history`: new `Frontier` primitive (hash-anchored per-node
positions:
    `captureFrontier`, `frontierAtWallTime`, `frontierTarget`,
`materializeAtFrontier`, Yjs snapshot refs + pin keys); named
checkpoints
(`createCheckpoint`, `listCheckpoints`, `deleteCheckpoint`,
`pinFrontier`,
    `restoreToFrontier`); `ScopeTimeline`/`ScopeScrubCache` generalizing
    `SchemaTimeline` to arbitrary node sets; `HistoryHorizonError` +
`HistoryEngine.getHorizon` — targets below the prune horizon now fail
loudly
    instead of silently remapping to the wrong change.
- `@xnetjs/data`: `Checkpoint` node schema (`CHECKPOINT_SCHEMA_IRI`);
pin
    registry on storage adapters (`NodeStorageAdapter.pins`, `PinEntry`,
`PinRegistry`) protecting pinned changes and Yjs snapshots from pruning
and
    eviction (memory + SQLite implementations).
  - `@xnetjs/sqlite`: `pinned_changes` table (additive migration).
- `@xnetjs/runtime`: Yjs history snapshots are now captured on
production doc
persists (throttled session-boundary/min-interval capture in NodePool).
- `@xnetjs/react`: new `useTimeMachine` hook (hooks sub-barrel) binding
a
scrubber UI to the merged scope timeline: position/step navigation,
preview +
property diff at the scrub position, named versions, one-transaction
restore,
    and history-horizon reporting.

### Patch Changes

- [#498](#498)
[`e2e78cd`](e2e78cd)
Thanks [@crs48](https://github.com/crs48)! - Fix "no such column:
p.tiebreak_key" on databases created before schema v8. The
`tiebreak_key` column repair now runs before the first `node_properties`
read
(`getNode`/`getNodes`/`listNodes`/`queryNodes`), not just before writes
— a
fresh session that opened a document page hit the missing column on its
first
hydrate query before any write could trigger the lazy guard. Also adds
the
missing v8 entry to `SCHEMA_MIGRATIONS` (`ALTER TABLE node_properties
ADD
COLUMN tiebreak_key TEXT`).
- Updated dependencies
[[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/sqlite@2.0.0
  - @xnetjs/storage@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/history@2.0.0

### Minor Changes

- [#496](#496)
[`85c9700`](85c9700)
Thanks [@crs48](https://github.com/crs48)! - Yjs fragment readers
understand the BlockNote document schema (exploration 0312).

Documents now live in the `content-v4` fragment using BlockNote's
ProseMirror
shape (`blockGroup > blockContainer > blockContent`); the legacy TipTap
`content` fragment remains readable as a fallback until each doc is
lazily
  imported.
- `@xnetjs/data`: `getRichTextPlainText` extracts text from
BlockNote-shaped
rich-text cells, including the new inline atoms (`mention` → `@label`,
`hashtag` → `#name`, `wikilink` → title, `inlineMath` → latex), while
still
    reading legacy TipTap-shaped cells.
- `@xnetjs/history`: version-diff text extraction prefers `content-v4`
(legacy
`content` fallback) and renders BlockNote inline atoms as readable text.
  - `@xnetjs/react`: new `useMergedEditorContributions` /
`mergeEditorContributions` (+ `MergedEditorContributions` type) collect
plugin-contributed BlockNote
`blockSpecs`/`inlineContentSpecs`/`styleSpecs`
    and slash menu items from the plugin registry, running the editor
schema-skew guard (`warnOnEditorSchemaRisks`) against the host's
statically
    bundled spec names and excluding un-bundled (skew-hazard) specs.
  - `@xnetjs/runtime`: blob-CID retention scanning now also walks the
    `content-v4` and `content` fragments, so blobs referenced from page
    documents are discovered.

- [#523](#523)
[`a91f278`](a91f278)
Thanks [@crs48](https://github.com/crs48)! - Drafts P2/P3 (exploration
0329): Patchwork-style branching on the change log.
- `@xnetjs/data`: `Draft` node schema (`DRAFT_SCHEMA_IRI`, entries map,
no
nesting); `NodeStore` draft overlay — `setCheckedOutDraft` swaps member
reads to clone content under original ids, redirects member writes to
clones with lazy copy-on-write, mirrors clone change events to
original-id
subscribers, and exposes `getRaw` for overlay-free reads; device-local
    draft privacy set (`markDraftPrivate`/`isDraftPrivate`).
- `@xnetjs/history`: draft lifecycle (`createDraft`, `forkNodeIntoDraft`
—
signed snapshot-create + pinned fork point + Yjs blob fork with state
    vector, `discardDraft`, `listDrafts`, never-fork policy); merge
(`threeWayPropertyMerge`, `mergeDraft` — one merger-signed squash batch
    with draft-born promotion via temp ids, relation remapping, deletion
    conflict cards, idempotent Yjs delta lane, provenance) and
    `refreshDraftFromMain` (floating drafts).
  - `@xnetjs/runtime`: `NodeStoreSyncProvider` gains a `shouldPublish`
predicate; the personal node-sync room excludes draft-private nodes, and
    draft privacy is rehydrated before sync starts.

- [#523](#523)
[`0f7ef43`](0f7ef43)
Thanks [@crs48](https://github.com/crs48)! - Time Machine P1
(exploration 0329): frontiers, checkpoints, pins, prune horizon, scope
timelines, production Yjs snapshot capture, and a React scrub hook.
- `@xnetjs/history`: new `Frontier` primitive (hash-anchored per-node
positions:
    `captureFrontier`, `frontierAtWallTime`, `frontierTarget`,
`materializeAtFrontier`, Yjs snapshot refs + pin keys); named
checkpoints
(`createCheckpoint`, `listCheckpoints`, `deleteCheckpoint`,
`pinFrontier`,
    `restoreToFrontier`); `ScopeTimeline`/`ScopeScrubCache` generalizing
    `SchemaTimeline` to arbitrary node sets; `HistoryHorizonError` +
`HistoryEngine.getHorizon` — targets below the prune horizon now fail
loudly
    instead of silently remapping to the wrong change.
- `@xnetjs/data`: `Checkpoint` node schema (`CHECKPOINT_SCHEMA_IRI`);
pin
    registry on storage adapters (`NodeStorageAdapter.pins`, `PinEntry`,
`PinRegistry`) protecting pinned changes and Yjs snapshots from pruning
and
    eviction (memory + SQLite implementations).
  - `@xnetjs/sqlite`: `pinned_changes` table (additive migration).
- `@xnetjs/runtime`: Yjs history snapshots are now captured on
production doc
persists (throttled session-boundary/min-interval capture in NodePool).
- `@xnetjs/react`: new `useTimeMachine` hook (hooks sub-barrel) binding
a
scrubber UI to the merged scope timeline: position/step navigation,
preview +
property diff at the scrub position, named versions, one-transaction
restore,
    and history-horizon reporting.

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/react@2.0.0

### Minor Changes

- [#496](#496)
[`85c9700`](85c9700)
Thanks [@crs48](https://github.com/crs48)! - Yjs fragment readers
understand the BlockNote document schema (exploration 0312).

Documents now live in the `content-v4` fragment using BlockNote's
ProseMirror
shape (`blockGroup > blockContainer > blockContent`); the legacy TipTap
`content` fragment remains readable as a fallback until each doc is
lazily
  imported.
- `@xnetjs/data`: `getRichTextPlainText` extracts text from
BlockNote-shaped
rich-text cells, including the new inline atoms (`mention` → `@label`,
`hashtag` → `#name`, `wikilink` → title, `inlineMath` → latex), while
still
    reading legacy TipTap-shaped cells.
- `@xnetjs/history`: version-diff text extraction prefers `content-v4`
(legacy
`content` fallback) and renders BlockNote inline atoms as readable text.
  - `@xnetjs/react`: new `useMergedEditorContributions` /
`mergeEditorContributions` (+ `MergedEditorContributions` type) collect
plugin-contributed BlockNote
`blockSpecs`/`inlineContentSpecs`/`styleSpecs`
    and slash menu items from the plugin registry, running the editor
schema-skew guard (`warnOnEditorSchemaRisks`) against the host's
statically
    bundled spec names and excluding un-bundled (skew-hazard) specs.
  - `@xnetjs/runtime`: blob-CID retention scanning now also walks the
    `content-v4` and `content` fragments, so blobs referenced from page
    documents are discovered.

- [#523](#523)
[`dd956e5`](dd956e5)
Thanks [@crs48](https://github.com/crs48)! - Drafts UI plumbing
(exploration 0329 P2/P3).
- `@xnetjs/react`: new `useDraft(hostId)` hook (hooks sub-barrel)
binding the
draft engine and the NodeStore checkout overlay — list/create open
drafts
    for a host, `checkout` (content-swap reads + lazy copy-on-write via
    `onMissingMember` → `forkNodeIntoDraft`), `returnToMain`, `discard`
    (leaves the checkout first), `merge` (merger-signed squash; returns
    conflict cards), `refresh` (fold main into the draft; pauses on
    conflicts), `setReviewRequested`, and `computeReview` — per-property
three-way review cards (base at fork vs main now vs draft now) plus Yjs
document-differs indicators, computed without applying anything.
Database
    hosts widen the member scope to their row nodes. Re-exports
    `DraftMergeConflict`, `MergeDraftResult`, `RefreshDraftResult` for
    consumers.
- `@xnetjs/data`: the `Draft` schema gains an optional `reviewRequested`
    checkbox (default `false`) — the P4 request-surfacing flag the
    Inbox/Requests surface lists open drafts by.

- [#523](#523)
[`0f7ef43`](0f7ef43)
Thanks [@crs48](https://github.com/crs48)! - Time Machine P1
(exploration 0329): frontiers, checkpoints, pins, prune horizon, scope
timelines, production Yjs snapshot capture, and a React scrub hook.
- `@xnetjs/history`: new `Frontier` primitive (hash-anchored per-node
positions:
    `captureFrontier`, `frontierAtWallTime`, `frontierTarget`,
`materializeAtFrontier`, Yjs snapshot refs + pin keys); named
checkpoints
(`createCheckpoint`, `listCheckpoints`, `deleteCheckpoint`,
`pinFrontier`,
    `restoreToFrontier`); `ScopeTimeline`/`ScopeScrubCache` generalizing
    `SchemaTimeline` to arbitrary node sets; `HistoryHorizonError` +
`HistoryEngine.getHorizon` — targets below the prune horizon now fail
loudly
    instead of silently remapping to the wrong change.
- `@xnetjs/data`: `Checkpoint` node schema (`CHECKPOINT_SCHEMA_IRI`);
pin
    registry on storage adapters (`NodeStorageAdapter.pins`, `PinEntry`,
`PinRegistry`) protecting pinned changes and Yjs snapshots from pruning
and
    eviction (memory + SQLite implementations).
  - `@xnetjs/sqlite`: `pinned_changes` table (additive migration).
- `@xnetjs/runtime`: Yjs history snapshots are now captured on
production doc
persists (throttled session-boundary/min-interval capture in NodePool).
- `@xnetjs/react`: new `useTimeMachine` hook (hooks sub-barrel) binding
a
scrubber UI to the merged scope timeline: position/step navigation,
preview +
property diff at the scrub position, named versions, one-transaction
restore,
    and history-horizon reporting.

### Patch Changes

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
  - @xnetjs/history@2.0.0
  - @xnetjs/runtime@0.5.0
  - @xnetjs/data-bridge@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/runtime@0.5.0

### Minor Changes

- [#523](#523)
[`a91f278`](a91f278)
Thanks [@crs48](https://github.com/crs48)! - Drafts P2/P3 (exploration
0329): Patchwork-style branching on the change log.
- `@xnetjs/data`: `Draft` node schema (`DRAFT_SCHEMA_IRI`, entries map,
no
nesting); `NodeStore` draft overlay — `setCheckedOutDraft` swaps member
reads to clone content under original ids, redirects member writes to
clones with lazy copy-on-write, mirrors clone change events to
original-id
subscribers, and exposes `getRaw` for overlay-free reads; device-local
    draft privacy set (`markDraftPrivate`/`isDraftPrivate`).
- `@xnetjs/history`: draft lifecycle (`createDraft`, `forkNodeIntoDraft`
—
signed snapshot-create + pinned fork point + Yjs blob fork with state
    vector, `discardDraft`, `listDrafts`, never-fork policy); merge
(`threeWayPropertyMerge`, `mergeDraft` — one merger-signed squash batch
    with draft-born promotion via temp ids, relation remapping, deletion
    conflict cards, idempotent Yjs delta lane, provenance) and
    `refreshDraftFromMain` (floating drafts).
  - `@xnetjs/runtime`: `NodeStoreSyncProvider` gains a `shouldPublish`
predicate; the personal node-sync room excludes draft-private nodes, and
    draft privacy is rehydrated before sync starts.

- [#523](#523)
[`0f7ef43`](0f7ef43)
Thanks [@crs48](https://github.com/crs48)! - Time Machine P1
(exploration 0329): frontiers, checkpoints, pins, prune horizon, scope
timelines, production Yjs snapshot capture, and a React scrub hook.
- `@xnetjs/history`: new `Frontier` primitive (hash-anchored per-node
positions:
    `captureFrontier`, `frontierAtWallTime`, `frontierTarget`,
`materializeAtFrontier`, Yjs snapshot refs + pin keys); named
checkpoints
(`createCheckpoint`, `listCheckpoints`, `deleteCheckpoint`,
`pinFrontier`,
    `restoreToFrontier`); `ScopeTimeline`/`ScopeScrubCache` generalizing
    `SchemaTimeline` to arbitrary node sets; `HistoryHorizonError` +
`HistoryEngine.getHorizon` — targets below the prune horizon now fail
loudly
    instead of silently remapping to the wrong change.
- `@xnetjs/data`: `Checkpoint` node schema (`CHECKPOINT_SCHEMA_IRI`);
pin
    registry on storage adapters (`NodeStorageAdapter.pins`, `PinEntry`,
`PinRegistry`) protecting pinned changes and Yjs snapshots from pruning
and
    eviction (memory + SQLite implementations).
  - `@xnetjs/sqlite`: `pinned_changes` table (additive migration).
- `@xnetjs/runtime`: Yjs history snapshots are now captured on
production doc
persists (throttled session-boundary/min-interval capture in NodePool).
- `@xnetjs/react`: new `useTimeMachine` hook (hooks sub-barrel) binding
a
scrubber UI to the merged scope timeline: position/step navigation,
preview +
property diff at the scrub position, named versions, one-transaction
restore,
    and history-horizon reporting.

### Patch Changes

- [#496](#496)
[`85c9700`](85c9700)
Thanks [@crs48](https://github.com/crs48)! - Yjs fragment readers
understand the BlockNote document schema (exploration 0312).

Documents now live in the `content-v4` fragment using BlockNote's
ProseMirror
shape (`blockGroup > blockContainer > blockContent`); the legacy TipTap
`content` fragment remains readable as a fallback until each doc is
lazily
  imported.
- `@xnetjs/data`: `getRichTextPlainText` extracts text from
BlockNote-shaped
rich-text cells, including the new inline atoms (`mention` → `@label`,
`hashtag` → `#name`, `wikilink` → title, `inlineMath` → latex), while
still
    reading legacy TipTap-shaped cells.
- `@xnetjs/history`: version-diff text extraction prefers `content-v4`
(legacy
`content` fallback) and renders BlockNote inline atoms as readable text.
  - `@xnetjs/react`: new `useMergedEditorContributions` /
`mergeEditorContributions` (+ `MergedEditorContributions` type) collect
plugin-contributed BlockNote
`blockSpecs`/`inlineContentSpecs`/`styleSpecs`
    and slash menu items from the plugin registry, running the editor
schema-skew guard (`warnOnEditorSchemaRisks`) against the host's
statically
    bundled spec names and excluding un-bundled (skew-hazard) specs.
  - `@xnetjs/runtime`: blob-CID retention scanning now also walks the
    `content-v4` and `content` fragments, so blobs referenced from page
    documents are discovered.

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
  - @xnetjs/history@2.0.0
  - @xnetjs/data-bridge@2.0.0
  - @xnetjs/storage@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/sqlite@2.0.0

### Minor Changes

- [#523](#523)
[`0f7ef43`](0f7ef43)
Thanks [@crs48](https://github.com/crs48)! - Time Machine P1
(exploration 0329): frontiers, checkpoints, pins, prune horizon, scope
timelines, production Yjs snapshot capture, and a React scrub hook.
- `@xnetjs/history`: new `Frontier` primitive (hash-anchored per-node
positions:
    `captureFrontier`, `frontierAtWallTime`, `frontierTarget`,
`materializeAtFrontier`, Yjs snapshot refs + pin keys); named
checkpoints
(`createCheckpoint`, `listCheckpoints`, `deleteCheckpoint`,
`pinFrontier`,
    `restoreToFrontier`); `ScopeTimeline`/`ScopeScrubCache` generalizing
    `SchemaTimeline` to arbitrary node sets; `HistoryHorizonError` +
`HistoryEngine.getHorizon` — targets below the prune horizon now fail
loudly
    instead of silently remapping to the wrong change.
- `@xnetjs/data`: `Checkpoint` node schema (`CHECKPOINT_SCHEMA_IRI`);
pin
    registry on storage adapters (`NodeStorageAdapter.pins`, `PinEntry`,
`PinRegistry`) protecting pinned changes and Yjs snapshots from pruning
and
    eviction (memory + SQLite implementations).
  - `@xnetjs/sqlite`: `pinned_changes` table (additive migration).
- `@xnetjs/runtime`: Yjs history snapshots are now captured on
production doc
persists (throttled session-boundary/min-interval capture in NodePool).
- `@xnetjs/react`: new `useTimeMachine` hook (hooks sub-barrel) binding
a
scrubber UI to the merged scope timeline: position/step navigation,
preview +
property diff at the scrub position, named versions, one-transaction
restore,
    and history-horizon reporting.

### Patch Changes

- [#498](#498)
[`e2e78cd`](e2e78cd)
Thanks [@crs48](https://github.com/crs48)! - Fix "no such column:
p.tiebreak_key" on databases created before schema v8. The
`tiebreak_key` column repair now runs before the first `node_properties`
read
(`getNode`/`getNodes`/`listNodes`/`queryNodes`), not just before writes
— a
fresh session that opened a document page hit the missing column on its
first
hydrate query before any write could trigger the lazy guard. Also adds
the
missing v8 entry to `SCHEMA_MIGRATIONS` (`ALTER TABLE node_properties
ADD
COLUMN tiebreak_key TEXT`).
## @xnetjs/abuse@2.0.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
## @xnetjs/cli@0.1.7

### Patch Changes

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
  - @xnetjs/runtime@0.5.0
  - @xnetjs/sqlite@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/crypto@2.0.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/core@2.0.0
## @xnetjs/data-bridge@2.0.0

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/sqlite@2.0.0
  - @xnetjs/sync@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/identity@2.0.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/storage@2.0.0

### Patch Changes

- Updated dependencies
[[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/sqlite@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/sync@2.0.0

### Patch Changes

- Updated dependencies []:
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## @xnetjs/core@2.0.0


## xnet-cloud@0.0.18

### Patch Changes

- Updated dependencies []:
  - @xnetjs/telemetry@0.0.1
  - @xnetjs/cloud@0.0.1
  - @xnetjs/crypto@2.0.0
  - @xnetjs/core@2.0.0
## xnet-demos@0.1.2

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/react@2.0.0
  - @xnetjs/devtools@0.1.0
  - @xnetjs/identity@2.0.0
## @xnetjs/brain@0.0.19

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/vectors@0.0.1
## @xnetjs/comms@0.0.19

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/crypto@2.0.0
## @xnetjs/dashboard@0.0.19

### Patch Changes

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
  - @xnetjs/react@2.0.0
  - @xnetjs/social@0.0.19
## @xnetjs/labs@0.0.19

### Patch Changes

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
## @xnetjs/licenses@0.0.19

### Patch Changes

- Updated dependencies []:
  - @xnetjs/crypto@2.0.0
## @xnetjs/maps@0.0.19

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
## @xnetjs/meetings@0.0.12

### Patch Changes

- Updated dependencies
[[`6a5a15e`](6a5a15e),
[`2a7b80f`](2a7b80f),
[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/plugins@2.0.0
  - @xnetjs/data@2.0.0
## @xnetjs/server@0.0.18

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/data-bridge@2.0.0
  - @xnetjs/identity@2.0.0
  - @xnetjs/crypto@2.0.0
## @xnetjs/social@0.0.19

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
  - @xnetjs/crypto@2.0.0
## @xnetjs/unreal@0.0.19

### Patch Changes

- Updated dependencies
[[`85c9700`](85c9700),
[`a91f278`](a91f278),
[`dd956e5`](dd956e5),
[`e4cb876`](e4cb876),
[`e2e78cd`](e2e78cd),
[`0f7ef43`](0f7ef43)]:
  - @xnetjs/data@2.0.0
## xnet-desktop@2.0.0

Desktop shell release riding the @xnetjs/core 2.0.0 train.
Desktop-specific changes are not tracked here; see the core packages'
changelogs for what shipped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant