Repository navigation
feat: page history - #8
Merged
Merged
Conversation
auxa-m45
referenced
this pull request
in auxa-m45/docmost
Apr 13, 2025
Refines audio progress interaction
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 25, 2026
docmost#159) Third tree-sync finding (docmost#8). On a socket reconnect after a missed-events gap (laptop sleep / wifi blip), the resync only invalidated the ROOT sidebar query; a move/rename/delete that happened INSIDE an already-loaded, expanded branch was never reflected — the branch stayed stale until the user manually interacted. (The #2 fix reconciles the root level; this covers the deeper loaded branches.) - `treeModel.reconcileChildren(tree, parentId, fresh)`: replace a loaded branch's DIRECT children with the authoritative fresh set (drop removed, add new, reorder to server) while PRESERVING each surviving child's already-loaded grandchildren, so deeper expansion is not collapsed. An unloaded branch (children === undefined) is left untouched (lazy-load fetches it fresh). - `loadedOpenBranchIds(tree, openIds)`: the branches a reconnect should refresh (open AND loaded). `fetchAllAncestorChildren(..., { fresh: true })` bypasses the 30-min sidebar cache so the reconcile sees current data (handler-order independent). - space-tree: on socket `connect`, re-fetch + reconcile each open loaded branch of the active space (space-switch-guarded; an unloaded branch is skipped). Tests: reconcileChildren (drop/add/reorder + preserve grandchildren + unloaded no-op) and loadedOpenBranchIds (open+loaded only, skip unloaded, nested). The pure logic is unit-tested; the live socket-reconnect round-trip is not browser-automated (simulating a reconnect gap is impractical) — sidebar render + expand were smoke-tested with no regression. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jun 26, 2026
…cmost#207) getPageBreadCrumbs (ancestor CTE) and forceDelete (descendant CTE) used withRecursive + unionAll with no CYCLE clause or depth cap. If a parent/child cycle already exists in the data (e.g. one slipped in via the docmost#7 TOCTOU race), both queries loop forever — hang / statement timeout. Worse, the move guard itself runs the ancestor CTE, so a cycle would disable the very guard meant to prevent it (docmost#207 docmost#8). Add a depth counter bounded by MAX_PAGE_TREE_DEPTH to both recursive CTEs; the walk stops at the cap, so a cycle yields a bounded result instead of hanging. Real page trees are only a few levels deep, so the cap never truncates a legitimate result. getPageBreadCrumbs selects an explicit column list (not selectAll) so the internal depth counter never leaks into the breadcrumb shape. Adds an integration test that seeds an A<->B cycle directly and asserts both getPageBreadCrumbs and forceDelete return bounded / complete under a short connection-level statement_timeout instead of hanging. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 4, 2026
…ocmost#293 canon docmost#9) Move paragraph/heading textAlign off the HTML-wrapper form (<p style="text-align:…"> / <hN style=…>) onto a trailing attached HTML comment on the block line: `text <!--attrs {"textAlign":"center"}-->`. This keeps the readable markdown block form (plain `text` / `## Title`) while preserving alignment losslessly. "left"/null stay bare (no churn). Adds a reusable attached-comment primitive (attached-comment.ts) that docmost#4 (image) and docmost#8 (media) will reuse: - attachedCommentFor(name, json) -> `<!--name {compact-json}-->`, escaping any `--` pair inside the JSON as -- so the payload can never close the comment early; - parseAttachedComment(data) with grammar `^\s*([A-Za-z][\w-]*)(?:\s+({…}))?\s*$` whose name excludes `:`, so envelope comments (docmost:meta / docmost:comments) never match — fail-open on anything malformed. On import, applyAttachedComments runs AFTER marked.parse but BEFORE generateJSON (parse5 drops comments), re-expressing the attrs comment as an inline text-align style on the parent block, then removing the comment node. Guards: emit only when there is a visible element to attach to — paragraph requires non-empty text, heading requires non-empty headingText (symmetry: an empty aligned heading stays bare `##`, no orphan comment). Goldens in markdown-converter-golden/gaps updated deliberately to the attached-comment form (assertions stay strict: exact output + lossless round-trip). New textalign.test.ts (19 tests) covers center/right/justify on paragraph and heading, byte-stable re-export, and fail-open branches. Raw-HTML containers (columns/cells/callout via blockToHtml) keep the inline text-align form intentionally — comments are dropped inside raw HTML. package vitest: 462 passed | 1 expected-fail; tsc clean. git-sync: 268 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 4, 2026
…omment (docmost#293 canon docmost#8) Ten media/embed node types move their TOP-LEVEL serialization off raw schema HTML onto a readable markdown target plus an always-emitted discriminator comment whose NAME selects the node type. The schema-HTML form is retained on the raw-HTML/columns path (comments are dropped by the DOM parse stage there). image-form <!--name …--> youtube, video, audio, drawio, excalidraw link-form [text](src)<!--name …--> pdf, attachment, embed (text=filename/provider) standalone <!--pageembed …--> / <!--transclusion …--> pageEmbed, transclusionReference The comment NAME is the node-type discriminator and is ALWAYS emitted, even when the attr JSON is empty (`<!--youtube-->`), so a bare `` is never mistaken for an `image` and a bare `[t](u)` stays a plain link — no URL-sniffing. src rides in the markdown target; every other non-default attr (incl. the id links attachmentId/sourcePageId/transclusionId) rides in the comment JSON (stable key order, numerics stringified, align="center" omitted). New src/lib/media-html.ts: byte-exact builders reproducing the schema HTML each old processNode case returned. Both the serializer's raw-HTML path (blockToHtml, now de-delegated from `return processNode(block)` to explicit per-type cases) and the importer call these, so serialize and parse cannot drift. Import (applyCommentDirectives): image-form binds the preceding <img> (src from it), link-form the preceding <a> (src=href, text=filename/provider), standalone replaces the comment (same leading-doc-level handling as docmost#5). Each rebuilds the schema element via the media-html builder, then swaps it in; the empty-<p> hoist is absorbed by stripEmptyParagraphs. Fail-open: wrong element/position/name or malformed JSON -> inert, no throw. Link-form visible text is escaped (escapeLinkText) for the FULL set of CommonMark inline-active punctuation (\ ` * _ ~ [ ] < & ! ( )), not just [ ] \: the label is parsed as inline content, so a filename/provider like `report *v2*.pdf` or `.pdf` would otherwise lose the markup (or fragment the parse) when the importer reads a.textContent back — a data-loss regression vs the old data-attachment-name form. Adversarial round-trip fixtures lock byte- and value-stability for emphasis/code/strike/autolink/entity/image markers and nested-link names. Tests: new media-comments.test.ts (40 cases: per-type exact md + lossless byte-stable round-trip incl. id links, minimal-node discriminator-still-emitted, in-column schema-HTML form, discriminator integrity, fail-open, active-punct filenames). Goldens in media-roundtrip / markdown-converter-golden / markdown-converter / diagram-roundtrip updated to the md+comment form (columns stay schema-HTML). The former known-limitation image-diagrams fixture is now byte- AND canonically-stable (canon docmost#8 omits the diagram align="center" default) and was promoted from an it.fails into the green corpus (11-image-diagrams.json). git-sync stabilize.test.ts: the "diagram materializes data-align=center" fixpoint moved into a column (where the raw-HTML asymmetry still holds), since top level is now byte-stable. package vitest: 540 passed; tsc clean. git-sync: 268 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 5, 2026
…ENTS.md
Adds a testing guide covering how to verify features against a running stand:
drive the behaviour under test through the browser (not the API), verify
out-of-band in the DB/git, and the non-obvious traps. Notably the page has two
ProseMirror editors — [aria-label='Page title'] (non-collab) and
[aria-label='Page content'] (the collab body); querySelector('.ProseMirror')
returns the title, so tests must target the body editor and wait ~10s for the
hocuspocus store debounce. Links the new doc from AGENTS.md next to dev-stand.md
and adds a matching gotcha docmost#8 to dev-stand.md.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 17, 2026
…я базы (docmost#626 регресс) docmost#626 завёл имя IndexedDB-базы page.<scope>.<pageId> и по ошибке передал его же в HocuspocusProvider.name. Сервер резолвит страницу как documentName.split('.')[1] (collaboration.util.getPageId), поэтому из неймспейснутого имени достаётся SCOPE, а не pageId → findById не находит страницу → каждое авторизованное collab- соединение отклоняется. На :develop совместное редактирование сломано. Разведено: pageYdocRoomName(pageId)=page.<pageId> — ТОЛЬКО в HocuspocusProvider.name; имя IndexedDB-базы (pageYdocName, скоуп-неймспейснутое) — везде остальное (изоляция локального контента на общем устройстве). Regression-тест мирроит серверный getPageId-контракт: room резолвится в pageId, а скоуп-имя — в scope (и НЕ в pageId). Ревью docmost#626 это пропустило — не было integration-теста на резолв комнаты с реальным scope (AGENTS.md rule docmost#8). Инвариант №1 фазы Ф4 (docmost#640); хотфикс вперёд Ф4. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Jul 20, 2026
…cmost#690 review F-1/F-2) Round 1 review (docmost#690 PR A). The code was confirmed correct — these add coverage for two security-critical DB-observable properties (ARCH docmost#8) that were untested. F-1 (CASCADE): create a personal server (with an encrypted headersEnc blob) for a user, delete the user, assert the row is GONE from findByIdRaw AND from the admin listByWorkspace scope — proving ON DELETE CASCADE destroys it (with its secret), not promotes it to an admin row. F-2 (re-SSRF on update): create a valid personal server, then update it to a blocked loopback URL -> 400 AND the stored url is unchanged (rejected update persisted nothing) — defense-in-depth on url-change. Non-vacuous: flipping the FK to ON DELETE SET NULL and disabling the update assertMcpUrlAllowed branch reddens exactly these two (other 6 stay green). Test only, no product change. Integration 8/8 against real Postgres. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
vvzvlad
pushed a commit
to vvzvlad/gitmost
that referenced
this pull request
Aug 2, 2026
…ost#681) editor_tx_ms only measures the synchronous ProseMirror transaction and is blind to the React re-render/paint that follows a keystroke. Add editor_key_latency_ms = the full keydown->next-paint duration, captured with a PerformanceObserver on the Event Timing entry type. - vitals.ts: a passive PerformanceObserver({type:"event", durationThreshold:16, buffered:false}), wrapped in the same commented try/catch graceful-degrade as the longtask observer (inv docmost#10). A single filter reportEditorKeyLatency() keeps name==="keydown" && live .ProseMirror focus, reporting entry.duration through the existing reportClientMetric sink (self-gated by isVitalsActive). editor_tx_ms is untouched. - client ALLOWED_NAMES + reportClientMetric union + server ALLOWED_METRIC_NAMES: the metric name declared in all three lockstep sites (inv docmost#7), each guarded. - 6 client tests drive the REAL filter through real jsdom focus + a wiring test proving the observer is installed with the right options and connected to the filter (inv docmost#8); 1 server validator test asserts the name is accepted. Closes docmost#681
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.