yamlover 0.3.55 → 0.3.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/bin/yamlover.js +41 -4
- package/dist/agent-docs/AGENTS.md +20 -330
- package/dist/agent-docs/AGENTS.yo +621 -0
- package/dist/builtin-taxonomy/$defs/.yo/meta.yo +0 -2
- package/dist/builtin-taxonomy/$defs/annotation +3 -1
- package/dist/builtin-taxonomy/$defs/decision +34 -0
- package/dist/builtin-taxonomy/$defs/edit +60 -0
- package/dist/builtin-taxonomy/$defs/edit-answer +21 -0
- package/dist/builtin-taxonomy/$defs/edit-batch +31 -0
- package/dist/builtin-taxonomy/$defs/envelope +169 -0
- package/dist/builtin-taxonomy/$defs/event +85 -0
- package/dist/builtin-taxonomy/$defs/fragment +7 -9
- package/dist/builtin-taxonomy/$defs/link +58 -0
- package/dist/builtin-taxonomy/$defs/task +28 -19
- package/dist/builtin-taxonomy/$defs/workflow +3 -0
- package/dist/builtin-taxonomy/ontos/.yo/body.yo +7 -1
- package/dist/client/assets/{decoded-DYF3m3qY.js → decoded-Bj1qJCo_.js} +1 -1
- package/dist/client/assets/{djvu--bwAI3Ad.js → djvu-lnurzbzN.js} +1 -1
- package/dist/client/assets/{docx-rhrp57OA.js → docx-DpN_PtM8.js} +1 -1
- package/dist/client/assets/{heic-CNvQbH_2.js → heic-BqJutS0N.js} +1 -1
- package/dist/client/assets/imagemap-rdhcPlWy.js +1 -0
- package/dist/client/assets/index-0ALNONIF.js +962 -0
- package/dist/client/assets/index-BiETmvLO.css +1 -0
- package/dist/client/assets/map-Btm4SlVs.js +1 -0
- package/dist/client/assets/paged-Cjy3svw2.js +1 -0
- package/dist/client/assets/{openable-CaZBG8d8.js → panzoom-BXEAw479.js} +2 -2
- package/dist/client/assets/{pdf-CJhbTDg_.js → pdf-DvC2sbDN.js} +1 -1
- package/dist/client/assets/psd-BKmCWsdC.js +11 -0
- package/dist/client/assets/{spreadsheet-B71fTduw.js → spreadsheet-Coy5sooG.js} +1 -1
- package/dist/client/assets/tiff-IcWiNdYs.js +1 -0
- package/dist/client/assets/video-YC-ZvXg7.js +1 -0
- package/dist/client/assets/xyflow-CFNcu5cT.js +23 -0
- package/dist/client/index.html +2 -2
- package/dist/server.js +9228 -5278
- package/dist/wire/openapi.yo +935 -0
- package/package.json +6 -1
- package/dist/agent-docs/CLAUDE.md +0 -7
- package/dist/builtin-taxonomy/$defs/board +0 -15
- package/dist/client/assets/imagemap-BHOOud3m.js +0 -1
- package/dist/client/assets/index-D7Uc99a8.css +0 -1
- package/dist/client/assets/index-DDCohDX6.js +0 -759
- package/dist/client/assets/map-DRUkC_pT.js +0 -1
- package/dist/client/assets/paged-CKzW-eq6.js +0 -1
- package/dist/client/assets/psd-CPdDl_Gy.js +0 -11
- package/dist/client/assets/tiff-D6Ts7aAc.js +0 -1
- package/dist/client/assets/xyflow-DWUupXDf.js +0 -23
- /package/dist/client/assets/{openable-CIGW-MKW.css → panzoom-CIGW-MKW.css} +0 -0
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# $defs/annotation —
|
|
1
|
+
# $defs/annotation — RETIRED (docs/annotations: applications are membership bookmarks now).
|
|
2
|
+
# Kept because legacy trees still carry it — read forever, never written anew.
|
|
3
|
+
# ONE TAG APPLICATION on the host node (a whole document, or a fragment within
|
|
2
4
|
# it). It lives as an element of the host's `yamlover-annotations` array. Two forms:
|
|
3
5
|
# • parameterless — a bare tag pointer (`- *::ontos:…`): the host simply HAS this tag.
|
|
4
6
|
# • parametrized — an object carrying `tag: *::ontos:…` plus parameters (e.g. `description`).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# $defs/decision — a DECISION RECORD: a task whose work is a HUMAN'S CALL. It IS-A task (allOf:
|
|
2
|
+
# task, hence a chapter): the scalar self-value is its title, the body is the chapter's, the
|
|
3
|
+
# planning fields are the task's — and it adds the decision's own fields. When an investigation
|
|
4
|
+
# or a refinement meets a question the agent must not answer alone, the agent births one UNDER
|
|
5
|
+
# THE SECTION where the question arose (the session, the ticket being refined), assigned to the
|
|
6
|
+
# user, carrying the `question`, the `options` with their consequences, and in the body the
|
|
7
|
+
# information and links a decision needs. It LINKS the record into the board where the problem
|
|
8
|
+
# occurred: a body pointer from the task that depends on it — which by the link law makes the
|
|
9
|
+
# record that task's subtask and BLOCKER, a card on its lanes in its own state. The user decides
|
|
10
|
+
# by writing `decision` (and `decided`) and moving the record to done; the blocked task resumes.
|
|
11
|
+
#
|
|
12
|
+
# Its lifecycle is the task's (a tag application into a workflow): born `ready` — the question
|
|
13
|
+
# is prepared, it waits for the user; `done` — decided. Below the workflow's active state it
|
|
14
|
+
# never raises the task it blocks (the parent-follows law): a question waiting is not work
|
|
15
|
+
# happening. Attach with !!<*::yamlover:$defs:decision>. Format: x-yamlover-decision.
|
|
16
|
+
# Docs: docs/documents/chapter/decision.
|
|
17
|
+
allOf:
|
|
18
|
+
- *:: yamlover: $defs: task
|
|
19
|
+
type: variant
|
|
20
|
+
members:
|
|
21
|
+
question: # THE thing to decide, in one sentence — marklower
|
|
22
|
+
type: string
|
|
23
|
+
format: text/marklower
|
|
24
|
+
options: # the choices, each with its consequences — one line each
|
|
25
|
+
type: array
|
|
26
|
+
others:
|
|
27
|
+
type: string
|
|
28
|
+
format: text/marklower
|
|
29
|
+
decision: # the answer, once the user has taken it — marklower
|
|
30
|
+
type: string
|
|
31
|
+
format: text/marklower
|
|
32
|
+
decided: # when it was taken
|
|
33
|
+
type: string
|
|
34
|
+
format: date-time
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# $defs/edit — ONE SURGICAL EDIT of the tree: the element of a `POST /api/edit` batch
|
|
2
|
+
# ($defs/edit-batch) and of `POST /api/edit-text`. An edit names a node by its colon path and
|
|
3
|
+
# says what to do there; its payload is VALID INLINE YAMLOVER SOURCE (the caller escapes its own
|
|
4
|
+
# prose) and is parsed before any splice, so a malformed edit fails with the file untouched.
|
|
5
|
+
# The server splices the AUTHORED TEXT of the backing file (never a re-serialization — comments,
|
|
6
|
+
# spelling and order survive), grouped by file, one reindex per touched file. Semantics:
|
|
7
|
+
# tools/server/src/server/engine-api.ts applyEdits / editChapterSource; docs/server/wire.
|
|
8
|
+
#
|
|
9
|
+
# THE INVARIANTS an implementation holds (docs/server/editor, concrete-rules.ts, drop-policy.ts):
|
|
10
|
+
# - a payload never carries member STORAGE — a directory member is born by `concrete`/`name`,
|
|
11
|
+
# never by pasting its body into the parent; an existing node never changes concrete through
|
|
12
|
+
# an edit (a conversion is a move, `POST /api/mv`);
|
|
13
|
+
# - content inside a file document speaks that file's language; a JSON-family file takes
|
|
14
|
+
# scalar `emplace` only;
|
|
15
|
+
# - a `remove` of a member archives its storage to the parent's `.yo/.trash/` after the batch
|
|
16
|
+
# commits — deletion never destroys;
|
|
17
|
+
# - THE POSITION LAW (docs/language/partial): an `insert` before a pinned position is refused —
|
|
18
|
+
# it would renumber what the author pinned;
|
|
19
|
+
# - the `.yo/` subtree is engine-managed and read-only (`settings.yo` excepted);
|
|
20
|
+
# - the field is spelled `yamlover:` on the wire (the yo migration keeps the old spelling).
|
|
21
|
+
type: object
|
|
22
|
+
members:
|
|
23
|
+
path:
|
|
24
|
+
type: string
|
|
25
|
+
description: the colon path of the node edited (`:a:b:0`) — a key or an absolute position per segment; for `insert`, the parent (append) or a positional slot (`:a:3`, insert before it)
|
|
26
|
+
op:
|
|
27
|
+
type: string
|
|
28
|
+
description: unlist removes only an authored reference placement and preserves member storage; emplace | replace | insert | remove — `emplace` sets the entry, creating it when absent (a scalar self-value, a keyed field, a whole node); `replace` only when it exists; `insert` splices a new entry at a position (keyed with `key`); `remove` drops the entry
|
|
29
|
+
yamlover:
|
|
30
|
+
type: string
|
|
31
|
+
format: text/yamlover
|
|
32
|
+
description: the node's value as valid inline yamlover source — the payload of emplace, replace and insert
|
|
33
|
+
meta:
|
|
34
|
+
type: string
|
|
35
|
+
description: the `!!<…>` schema pointer to set on the entry; `null` drops it; omitted leaves it alone
|
|
36
|
+
concrete:
|
|
37
|
+
type: string
|
|
38
|
+
description: insert only — the storage a NEW document is born in — yamlover (inline, the default) | file/yamlover | dir/index.yo | dir/.yo | dir (a bare folder)
|
|
39
|
+
name:
|
|
40
|
+
type: string
|
|
41
|
+
description: insert only — the file or directory name when `concrete` births a document; the server uniquifies it
|
|
42
|
+
key:
|
|
43
|
+
type: string
|
|
44
|
+
description: insert only — create a KEYED entry (`key: value`) at the position; keeps authored order, where a fresh keyed emplace splices at the top of the block
|
|
45
|
+
at:
|
|
46
|
+
type: integer
|
|
47
|
+
description: scalar emplace only — the self-value line's authored position (the number of entries that precede it)
|
|
48
|
+
flat:
|
|
49
|
+
type: boolean
|
|
50
|
+
description: insert only — the payload's first row is a FLAT continuation of the key (docs/language/flattening), spliced as one line when its shape allows
|
|
51
|
+
safety:
|
|
52
|
+
type: object
|
|
53
|
+
description: optional wire-2 extension; omitted preserves legacy unguarded writes
|
|
54
|
+
members:
|
|
55
|
+
revision:
|
|
56
|
+
type: string
|
|
57
|
+
description: SHA-256 project revision from X-Yamlover-Revision on an editing read
|
|
58
|
+
operationId:
|
|
59
|
+
type: string
|
|
60
|
+
description: milliseconds-since-epoch:UUID; keep identical across retries; expires after 30 days
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# $defs/edit-answer — what `POST /api/edit` answers. 200 with `ok` when the batch folded; `path`
|
|
2
|
+
# names what was BORN (the last document created) or APPENDED (the parent's new last child), so
|
|
3
|
+
# the caller can navigate to it; 400 with `error` — the message of the first edit that could not
|
|
4
|
+
# fold — and no file touched. `POST /api/edit-text` answers `{source}` instead (the text after
|
|
5
|
+
# the batch). The `{error}` form is every route's refusal (docs/server/wire, the routes).
|
|
6
|
+
type: object
|
|
7
|
+
members:
|
|
8
|
+
ok:
|
|
9
|
+
type: boolean
|
|
10
|
+
path:
|
|
11
|
+
type: string
|
|
12
|
+
description: the created or appended node's colon path — present only when the batch created or appended something
|
|
13
|
+
error:
|
|
14
|
+
type: string
|
|
15
|
+
description: refusal or recovery conflict; 409 means stale revision or recovery required, 410 means expired identity, 428 means missing revision inside safety
|
|
16
|
+
revision:
|
|
17
|
+
type: string
|
|
18
|
+
description: post-commit project revision, present for guarded writes
|
|
19
|
+
operationId:
|
|
20
|
+
type: string
|
|
21
|
+
description: the original request identity, unchanged on replay
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# $defs/edit-batch — the body of `POST /api/edit`: a BATCH of $defs/edit, applied in order, grouped
|
|
2
|
+
# by backing file, the later edits addressed against the state the earlier ones leave (nothing is
|
|
3
|
+
# written until the whole batch folds — a batch that fails half-way leaves every file untouched).
|
|
4
|
+
# One reindex per touched file, one `diff` event each ($defs/event); a batch that births a document
|
|
5
|
+
# reindexes the tree. A bare single edit — the $defs/edit fields at the top level, no `edits` — is
|
|
6
|
+
# the same request with a batch of one. The answer is $defs/edit-answer. Spec: docs/server/wire.
|
|
7
|
+
type: object
|
|
8
|
+
members:
|
|
9
|
+
edits:
|
|
10
|
+
type: array
|
|
11
|
+
others: *:: yamlover: $defs: edit
|
|
12
|
+
safety:
|
|
13
|
+
type: object
|
|
14
|
+
description: optional wire-2 extension; omitted preserves legacy unguarded writes
|
|
15
|
+
members:
|
|
16
|
+
revision:
|
|
17
|
+
type: string
|
|
18
|
+
description: SHA-256 project revision from X-Yamlover-Revision on an editing read
|
|
19
|
+
operationId:
|
|
20
|
+
type: string
|
|
21
|
+
description: milliseconds-since-epoch:UUID; keep identical across retries; expires after 30 days
|
|
22
|
+
renames:
|
|
23
|
+
type: array
|
|
24
|
+
description: ordered key renames after edits, committed in the same recovery boundary
|
|
25
|
+
others:
|
|
26
|
+
type: object
|
|
27
|
+
members:
|
|
28
|
+
path:
|
|
29
|
+
type: string
|
|
30
|
+
key:
|
|
31
|
+
description: the new key string, or null to make an inline entry keyless
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# $defs/envelope — THE CONTENT ENVELOPE: the answer of `GET /api/content/{path}?depth=&range=`
|
|
2
|
+
# (and of `POST /api/preview`), a `text/yamlover` document whose top-level keys are the HEADER
|
|
3
|
+
# (what the store knows about the node), `source` (the node's authored text, cut at the depth
|
|
4
|
+
# and the window), `side` (the SIDECAR — what the text cannot say, keyed by fragment) and
|
|
5
|
+
# `relations` (the upstream panel). Built by tools/server/src/content-envelope.ts, read by
|
|
6
|
+
# tools/server/src/client/content.ts; the laws are the comments of the builder and the prose of
|
|
7
|
+
# docs/server/wire. Every key here is a promise of the wire (wire-version.ts): a client ignores
|
|
8
|
+
# keys it does not know; a key renamed, retyped or dropped bumps the wire.
|
|
9
|
+
type: object
|
|
10
|
+
members:
|
|
11
|
+
wire:
|
|
12
|
+
type: integer
|
|
13
|
+
description: the wire version this envelope speaks — the first key, so a saved envelope says what it pins
|
|
14
|
+
path:
|
|
15
|
+
type: string
|
|
16
|
+
description: the requested node's colon path (`:a:b:0`) — as asked; through a link (engine-tasks paths-over-link-edges) the WALKED path, the slot's
|
|
17
|
+
canonical:
|
|
18
|
+
type: string
|
|
19
|
+
description: where the node lives, when `path` walked through a link (`:host:11` → `:elsewhere:card.yo`); absent when the two coincide
|
|
20
|
+
documentPath:
|
|
21
|
+
type: string
|
|
22
|
+
description: the document (the nearest yamlover entity — a file, an index.yo, a .yo body) the node lives in
|
|
23
|
+
type:
|
|
24
|
+
type: string
|
|
25
|
+
description: the TYPE name — a scalar leaf's scalar type (null | boolean | integer | number | string), `binary`, or a container's corner of the type cube (docs/meta/facets) — map | seq | kseq (keyed + ordinal) | vmap | vseq (a self-value too) | omni
|
|
26
|
+
valueType:
|
|
27
|
+
type: string
|
|
28
|
+
description: the self-value's scalar type — null | boolean | integer | number | string | binary; absent without a value facet
|
|
29
|
+
hasKeyed:
|
|
30
|
+
type: boolean
|
|
31
|
+
hasOrdinal:
|
|
32
|
+
type: boolean
|
|
33
|
+
format:
|
|
34
|
+
type: string
|
|
35
|
+
description: the node's format when it has one (a mime, an x-yamlover-* document format)
|
|
36
|
+
concrete:
|
|
37
|
+
type: string
|
|
38
|
+
description: the storage the node lives in — yamlover | file/yamlover | dir/index.yo | dir/.yo | dir | …
|
|
39
|
+
title:
|
|
40
|
+
type: string
|
|
41
|
+
description:
|
|
42
|
+
type: string
|
|
43
|
+
size:
|
|
44
|
+
type: integer
|
|
45
|
+
description: the byte size — blob nodes only; the bytes themselves live behind `/api/blob`
|
|
46
|
+
parseError:
|
|
47
|
+
type: string
|
|
48
|
+
description: a DEGRADED node's parse error — the page below it is the fallback
|
|
49
|
+
special:
|
|
50
|
+
type: string
|
|
51
|
+
description: '`overlay` when the node lives inside a `.yo/` subtree (settings.yo excepted); `graft` when it lives inside the bundled `yamlover` self-import (IMPORTS.md §4) — both are engine-owned: read-only on the page, no row in the TOC'
|
|
52
|
+
depth:
|
|
53
|
+
anyOf: # an integer, or the token `.inf` for unlimited
|
|
54
|
+
- type: integer
|
|
55
|
+
- type: string
|
|
56
|
+
description: the document-boundary budget the answer was cut at — an integer, or `.inf` for unlimited (the default for a text document; 1 for a directory or a binary)
|
|
57
|
+
childCount:
|
|
58
|
+
type: integer
|
|
59
|
+
description: WINDOWED answers only — the node's rendered entry count
|
|
60
|
+
range:
|
|
61
|
+
type: string
|
|
62
|
+
description: WINDOWED answers only — the resolved absolute half-open window, `A-B` over rendered entry indices
|
|
63
|
+
large:
|
|
64
|
+
type: boolean
|
|
65
|
+
description: the node has more than LARGE_THRESHOLD (1000) rendered entries — a bare GET auto-windows `0-500` and browsing is read-only
|
|
66
|
+
length:
|
|
67
|
+
type: integer
|
|
68
|
+
description: SPARSE or OPEN nodes only (docs/language/partial) — the last position + 1, which is not the count when pins left gaps
|
|
69
|
+
open:
|
|
70
|
+
type: boolean
|
|
71
|
+
description: the node's last entry is a keyless postponed slot (`- *.`) — its tail is unknown
|
|
72
|
+
source:
|
|
73
|
+
type: string
|
|
74
|
+
format: text/yamlover
|
|
75
|
+
description: >-
|
|
76
|
+
the node's authored text — the merged IR subtree serialized WITH comments, members beyond the depth respelled as their pointer (`- *: name` / `name: *: name`), a window's first entry pinned at its position and a cut tail one open `- *.`; the empty text for an empty document; blobs have no text
|
|
77
|
+
side:
|
|
78
|
+
type: object
|
|
79
|
+
description: the SIDECAR — one bucket per fragment; a fragment is the continuation the client computes over the parsed source (`""` the node itself, `/key`, `/3` a rendered index, `/~` the null key, nested by `/`), so sidecar keys and client keys can never disagree
|
|
80
|
+
others:
|
|
81
|
+
type: object
|
|
82
|
+
members:
|
|
83
|
+
format:
|
|
84
|
+
type: string
|
|
85
|
+
description: the engine-derived format of the node at this fragment (extension folds, resolved tags)
|
|
86
|
+
fileText:
|
|
87
|
+
type: boolean
|
|
88
|
+
description: a whole-file text scalar — the raw IS the value; the decoder restores it
|
|
89
|
+
position:
|
|
90
|
+
type: integer
|
|
91
|
+
description: the original member position when omitted hidden entries or sparse positions differ from the visible source rank; hiding never frees an occupied position
|
|
92
|
+
anchorKey:
|
|
93
|
+
type: string
|
|
94
|
+
description: a body-positioned MEMBER (a file or directory) serialized keyless here — its storage name
|
|
95
|
+
member:
|
|
96
|
+
type: boolean
|
|
97
|
+
description: a keyed-remainder member — its key IS its storage name
|
|
98
|
+
other:
|
|
99
|
+
type: boolean
|
|
100
|
+
description: a filesystem member not placed by an existing directory body; thumbnail metadata alone does not place it. Chapter pages show unconsumed members in the Other pane while retaining them in editor IR.
|
|
101
|
+
consumed:
|
|
102
|
+
type: boolean
|
|
103
|
+
description: a keyed-remainder member that a `*` pointer deeper in the document (inside a section, at any nesting) already places — the page and the TOC draw it there, never a second time at the foot; decided by the store, so the depth window cannot hide the placing pointer
|
|
104
|
+
stub: # every member's link stub, cut or not — and a postponed branch's facets when the engine knows the node behind it
|
|
105
|
+
type: object
|
|
106
|
+
members:
|
|
107
|
+
$yamloverLink: *:: yamlover: $defs: link
|
|
108
|
+
deco:
|
|
109
|
+
type: object
|
|
110
|
+
description: a CUT member's node decorations — the comment-map bucket (anchors, tags, raw, tail) its inlined form would have carried
|
|
111
|
+
others: true
|
|
112
|
+
refPath:
|
|
113
|
+
type: string
|
|
114
|
+
description: a realized reference entry — its resolved target's path
|
|
115
|
+
refText:
|
|
116
|
+
type: string
|
|
117
|
+
description: …and the scope-correct canonical pointer spelling, framed at the holder's document
|
|
118
|
+
target: # …and the target's link stub
|
|
119
|
+
type: object
|
|
120
|
+
members:
|
|
121
|
+
$yamloverLink: *:: yamlover: $defs: link
|
|
122
|
+
via:
|
|
123
|
+
type: array
|
|
124
|
+
description: EDGE PROVENANCE (docs/language/redundant) — the authorings the engine read for this edge — `pull` (a `*` pointer entry), `push` (a `&` bookmark on the target), or both
|
|
125
|
+
others:
|
|
126
|
+
type: string
|
|
127
|
+
postponed:
|
|
128
|
+
type: boolean
|
|
129
|
+
description: a POSTPONED branch (docs/language/partial) — the slot is known, the value not loaded; also the window's open tail
|
|
130
|
+
notloaded:
|
|
131
|
+
type: boolean
|
|
132
|
+
description: a pointer into a GAP — the target position is not loaded; fetch it, never a dead link
|
|
133
|
+
bookmarked:
|
|
134
|
+
type: array
|
|
135
|
+
description: the `&` bookmarks PUSHED into this node, which the projection appends after its own entries — they exist nowhere in the authored text
|
|
136
|
+
others:
|
|
137
|
+
type: object
|
|
138
|
+
members:
|
|
139
|
+
label:
|
|
140
|
+
type: string
|
|
141
|
+
path:
|
|
142
|
+
type: string
|
|
143
|
+
text:
|
|
144
|
+
type: string
|
|
145
|
+
stub:
|
|
146
|
+
type: object
|
|
147
|
+
members:
|
|
148
|
+
$yamloverLink: *:: yamlover: $defs: link
|
|
149
|
+
via:
|
|
150
|
+
type: array
|
|
151
|
+
others:
|
|
152
|
+
type: string
|
|
153
|
+
relations:
|
|
154
|
+
type: object
|
|
155
|
+
description: 'the upstream relations panel, in the query language (wire 2): `..` is the spine parent, every other key is the minimal query that finds the holder from this node (`: ...: ?#: pet: $`, `:: ...: ?#: -: $`); each value is the holder''s link marker — its description (a duplicate key gets ` (2)`, ` (3)`, …)'
|
|
156
|
+
others:
|
|
157
|
+
type: object
|
|
158
|
+
members:
|
|
159
|
+
$yamloverLink:
|
|
160
|
+
type: object
|
|
161
|
+
$yamloverRef:
|
|
162
|
+
type: object
|
|
163
|
+
members:
|
|
164
|
+
text:
|
|
165
|
+
type: string
|
|
166
|
+
description: the pointer's canonical text WITHOUT the `*` sigil (the IR's `Pointer.raw`); the face spells the deref token, once
|
|
167
|
+
path:
|
|
168
|
+
type: string
|
|
169
|
+
description: the target path it links to — null for an unrealized (dangling or external) reference
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# $defs/event — ONE FRAME of `GET /api/events`, the server's `text/event-stream`: `data: <json>`
|
|
2
|
+
# per frame, comment lines `: connected` (on connect) and `: ping` (every 30 s) between them.
|
|
3
|
+
# Two kinds. A DIFF is what one reindex changed — after every write route, and after the
|
|
4
|
+
# watcher sees an external edit — as ROOT-RELATIVE FILE PATHS spelled as colon paths (the
|
|
5
|
+
# storage that changed, `:dir:index.yo`, `:a:.yo:body.yo`; not node paths — the client maps a
|
|
6
|
+
# file onto the branch it backs and refetches it). A TASK frame is the progress of one
|
|
7
|
+
# long-running job (indexing, hashing, thumbnails, reconciling), throttled to one every 150 ms
|
|
8
|
+
# per task, unthrottled on a state change.
|
|
9
|
+
#
|
|
10
|
+
# THE ORDER LAW: frames arrive in the order the server applied the changes; one write route
|
|
11
|
+
# yields one diff per touched file (a batch that births a document yields one tree-wide diff).
|
|
12
|
+
# THE RESYNC LAW (2026-09-07): there is still no replay — a client that missed frames must refetch
|
|
13
|
+
# — but it can now tell WHETHER it missed any. A HELLO frame opens every connection, naming the
|
|
14
|
+
# server `instance` and the number of change frames it has broadcast (`seq`); each diff carries the
|
|
15
|
+
# `seq` it is. A reconnect (the `open` after the first) whose greeting names the same instance and
|
|
16
|
+
# the same count missed nothing and may keep everything it holds; a different instance (a restart —
|
|
17
|
+
# a fresh process counts from zero), a higher count, or no greeting at all means everything loaded
|
|
18
|
+
# is stale: drop the document store, refetch the tree. `GET /api/tasks` is the snapshot of tasks in
|
|
19
|
+
# flight for a fresh page. Source: tools/server/src/server/engine-api.ts broadcast, tasks.ts;
|
|
20
|
+
# docs/server/wire.
|
|
21
|
+
type: object
|
|
22
|
+
members:
|
|
23
|
+
type:
|
|
24
|
+
type: string
|
|
25
|
+
description: hello | diff | task
|
|
26
|
+
instance:
|
|
27
|
+
type: string
|
|
28
|
+
description: hello — this server process's identity; a change of it means a restart, so nothing loaded may be trusted
|
|
29
|
+
seq:
|
|
30
|
+
type: integer
|
|
31
|
+
description: hello — change frames broadcast so far; diff — which one this frame is. A reconnect compares them (THE RESYNC LAW above)
|
|
32
|
+
added:
|
|
33
|
+
type: array
|
|
34
|
+
description: diff — files the reindex found new
|
|
35
|
+
others:
|
|
36
|
+
type: string
|
|
37
|
+
changed:
|
|
38
|
+
type: array
|
|
39
|
+
description: diff — files whose content changed
|
|
40
|
+
others:
|
|
41
|
+
type: string
|
|
42
|
+
removed:
|
|
43
|
+
type: array
|
|
44
|
+
description: diff — files gone
|
|
45
|
+
others:
|
|
46
|
+
type: string
|
|
47
|
+
moved:
|
|
48
|
+
type: array
|
|
49
|
+
description: diff — moves the reindex inferred (a removed file whose content reappeared elsewhere)
|
|
50
|
+
others:
|
|
51
|
+
type: object
|
|
52
|
+
members:
|
|
53
|
+
from:
|
|
54
|
+
type: string
|
|
55
|
+
to:
|
|
56
|
+
type: string
|
|
57
|
+
task:
|
|
58
|
+
type: object
|
|
59
|
+
description: task — the job's state
|
|
60
|
+
members:
|
|
61
|
+
id:
|
|
62
|
+
type: string
|
|
63
|
+
label:
|
|
64
|
+
type: string
|
|
65
|
+
state:
|
|
66
|
+
type: string
|
|
67
|
+
description: running | done | error
|
|
68
|
+
progress:
|
|
69
|
+
type: object
|
|
70
|
+
members:
|
|
71
|
+
done:
|
|
72
|
+
type: integer
|
|
73
|
+
total:
|
|
74
|
+
type: integer
|
|
75
|
+
description: absent — indeterminate (an activity bar, not a percent)
|
|
76
|
+
message:
|
|
77
|
+
type: string
|
|
78
|
+
description: human-readable detail — the current path, "writing index…"
|
|
79
|
+
startedAt:
|
|
80
|
+
type: integer
|
|
81
|
+
description: epoch milliseconds
|
|
82
|
+
finishedAt:
|
|
83
|
+
type: integer
|
|
84
|
+
error:
|
|
85
|
+
type: string
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# $defs/fragment — a user-marked REGION inside a document (the locate/highlight data only; no
|
|
2
|
-
#
|
|
3
|
-
# slug. `type` selects the locator: a text quote {type:text, exact,
|
|
4
|
-
# pdf / djvu rect {type:rect|pdf|djvu, x,y,w,h (pdf/djvu add page)},
|
|
5
|
-
# {type:map, n,s,e,w (geographic edges)}. Image-like fragments also carry an
|
|
6
|
-
# of the region (a sidecar blob, referenced by a `*` pointer). A fragment
|
|
7
|
-
#
|
|
2
|
+
# color). Stored under the host node's `.yo: fragments:` mapping (the legacy `yo:` spelling is
|
|
3
|
+
# read forever), keyed by a slug. `type` selects the locator: a text quote {type:text, exact,
|
|
4
|
+
# prefix, suffix}, an image / pdf / djvu rect {type:rect|pdf|djvu, x,y,w,h (pdf/djvu add page)},
|
|
5
|
+
# or a map box {type:map, n,s,e,w (geographic edges)}. Image-like fragments also carry an
|
|
6
|
+
# `image` — a PNG crop of the region (a sidecar blob, referenced by a `*` pointer). A fragment
|
|
7
|
+
# is tagged by MEMBERSHIP BOOKMARKS (`&…:-` own-line, docs/annotations/applications).
|
|
8
|
+
# Attach with the tag !!<*::yamlover/$defs/fragment>.
|
|
8
9
|
type: object
|
|
9
10
|
format: x-yamlover-fragment
|
|
10
11
|
members:
|
|
@@ -39,6 +40,3 @@ members:
|
|
|
39
40
|
description: A PNG crop of the region (image-like fragments only); a sidecar blob by pointer
|
|
40
41
|
created:
|
|
41
42
|
type: string
|
|
42
|
-
yamlover-annotations:
|
|
43
|
-
type: array
|
|
44
|
-
others: *:: yamlover: $defs: annotation
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# $defs/link — a LINK STUB: the navigable summary of a node the wire hands over INSTEAD of the
|
|
2
|
+
# node itself — a depth-cut member, a postponed branch's facets, a resolved reference's target,
|
|
3
|
+
# a TOC row. One shape everywhere (engine-api.ts linkMarker), always wrapped as the value of a
|
|
4
|
+
# `$yamloverLink` key (`stub: {$yamloverLink: {...}}`) so a consumer can tell a stub from data. The client draws an icon, a title and a count from it and fetches the
|
|
5
|
+
# node when the reader opens it. Spec: docs/server/wire (the content envelope).
|
|
6
|
+
type: object
|
|
7
|
+
members:
|
|
8
|
+
kind:
|
|
9
|
+
type: string
|
|
10
|
+
description: the DISPLAY kind — scalar | binary | object | array | mix | omni
|
|
11
|
+
type:
|
|
12
|
+
type: string
|
|
13
|
+
description: the TYPE name — a scalar leaf's scalar type (null | boolean | integer | number | string), `binary`, or a container's corner of the type cube (docs/meta/facets) — map | seq | kseq (keyed + ordinal) | vmap | vseq (a self-value too) | omni
|
|
14
|
+
valueType:
|
|
15
|
+
type: string
|
|
16
|
+
description: the self-value's scalar type — null | boolean | integer | number | string | binary; absent when the node has no value facet
|
|
17
|
+
hasKeyed:
|
|
18
|
+
type: boolean
|
|
19
|
+
hasOrdinal:
|
|
20
|
+
type: boolean
|
|
21
|
+
path:
|
|
22
|
+
type: string
|
|
23
|
+
description: the node's colon path
|
|
24
|
+
format:
|
|
25
|
+
type: string
|
|
26
|
+
description: the node's format (a mime, an x-yamlover-* document format) when it has one
|
|
27
|
+
yo:
|
|
28
|
+
type: boolean
|
|
29
|
+
description: '`!!yo` — exempt from the enclosing schema'
|
|
30
|
+
concrete:
|
|
31
|
+
type: string
|
|
32
|
+
description: the storage the node lives in — yamlover | file/yamlover | dir/index.yo | dir/.yo | dir | …
|
|
33
|
+
hasChildren:
|
|
34
|
+
type: boolean
|
|
35
|
+
description: for a chapter or a task, whether it has a subchapter; else whether it owns visible members
|
|
36
|
+
title:
|
|
37
|
+
type: string
|
|
38
|
+
size:
|
|
39
|
+
type: integer
|
|
40
|
+
description: the byte size (binary nodes)
|
|
41
|
+
value:
|
|
42
|
+
description: the scalar self-value, for the link label (scalar and omni nodes); a long whole-file text is truncated
|
|
43
|
+
valueTruncated:
|
|
44
|
+
type: boolean
|
|
45
|
+
valueLength:
|
|
46
|
+
type: integer
|
|
47
|
+
count:
|
|
48
|
+
type: integer
|
|
49
|
+
description: the owned members — items and fields, reverse members excluded (container nodes)
|
|
50
|
+
color:
|
|
51
|
+
type: string
|
|
52
|
+
description: a tag's color (onto nodes)
|
|
53
|
+
preview:
|
|
54
|
+
type: string
|
|
55
|
+
description: the path of a fragment's PNG crop (fragment nodes)
|
|
56
|
+
flow:
|
|
57
|
+
type: string
|
|
58
|
+
description: 'a GLIMPSE of the node — its first element in one line of flow yamlover, nested first elements, `…` for the rest, long strings cut (every link marker built with the document in hand; flow-preview.ts)'
|
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
# $defs/task — a unit of work (a ticket), or a
|
|
2
|
-
# the chapter schema (`allOf: [*chapter]`), inheriting the FULLY-OMNI shape — the
|
|
3
|
-
# SELF-VALUE is the title (no `title:` key), `description` stays keyed — and the
|
|
4
|
-
# body,
|
|
5
|
-
#
|
|
6
|
-
# It carries NO `state` field: a task's lifecycle position is a TAG APPLICATION
|
|
7
|
-
# (`yamlover-annotations`) into a workflow taxonomy ($defs/workflow), so the whole tag / board
|
|
8
|
-
# machinery is reused. Every planning field is optional — defaults-never-constraints: an
|
|
9
|
-
# untouched task is just a titled note. Attach with !!<*yamlover:$defs:task>. Spec: ../TICKETS.md.
|
|
1
|
+
# $defs/task — a unit of work (a ticket), a study card, or a BOARD of such. A task IS-A chapter:
|
|
2
|
+
# it EXTENDS the chapter schema (`allOf: [*chapter]`), inheriting the FULLY-OMNI shape — the
|
|
3
|
+
# scalar SELF-VALUE is the title (no `title:` key), `description` stays keyed — and the
|
|
4
|
+
# positional body, and adds a few OPTIONAL planning fields. Defaults-never-constraints: an
|
|
5
|
+
# untouched task is just a titled note.
|
|
10
6
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
7
|
+
# SUBTASKS are the task's keyless body members that are tasks BY THEIR OWN DECLARATION: an inline
|
|
8
|
+
# container tagged `!!<*yamlover:$defs:task>`, a DIRECTORY task's `- *: slug.yo` file/dir member
|
|
9
|
+
# whose own document carries the task tag (or a keyed-only member the body never names — the
|
|
10
|
+
# chapter member law). An UNTAGGED container in a task body is a plain SUBCHAPTER, exactly as in
|
|
11
|
+
# a chapter — the body union is the inherited chapter one (`chapter | table | bullets | numbered
|
|
12
|
+
# | chunk`), never narrowed: a task is a section that can be tagged, not a body that turns
|
|
13
|
+
# every section into a ticket (rule changed 2026-08-29; before, the own `others:` narrowed the
|
|
14
|
+
# body to `task | chunk`). A pointer body element to a task ELSEWHERE (`- *..: slug.yo`,
|
|
15
|
+
# `- *:: …`) makes that task a subtask of this one too — a BLOCKER: the link is the DAG edge,
|
|
16
|
+
# the linked task's storage stays where it is (docs/documents/chapter/task). A task with subtasks IS a board: its lanes are the workflow states
|
|
17
|
+
# its subtasks carry, in workflow order; `workflow:` only adds empty lanes for states no subtask
|
|
18
|
+
# has yet; the UI's saved layout lives under the hidden `.yo: lanes:` overlay (machine-owned,
|
|
19
|
+
# POST /api/board, written on demand — never by opening a page).
|
|
20
|
+
#
|
|
21
|
+
# It carries NO `state` field: a task's lifecycle position is a TAG APPLICATION (a membership
|
|
22
|
+
# bookmark, `&::yamlover:ontos:workflow:dev:ready:-`) into a $defs/workflow, so the whole tag /
|
|
23
|
+
# board machinery is reused. The retired `!!<*yamlover:$defs:board>` tag still READS as this
|
|
24
|
+
# schema (engine/yed alias). Attach with !!<*yamlover:$defs:task>. Spec: ../TICKETS.md,
|
|
25
|
+
# docs/documents/chapter/task.
|
|
14
26
|
allOf:
|
|
15
27
|
- *:: yamlover: $defs: chapter
|
|
16
28
|
type: variant
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- *:: yamlover: $defs: chunk # a content block
|
|
29
|
+
# NO own `others:` — the body is the chapter's (allOf): subchapters, tagged blocks, chunks. A
|
|
30
|
+
# subtask enters ONLY by its explicit tag (a tagged element is exempt from the sweep — its tag
|
|
31
|
+
# decides, docs/documents/chapter/schema); the sweep never makes a task out of a section.
|
|
21
32
|
members:
|
|
22
33
|
priority: # free ordinal: low | normal | high | urgent (advisory)
|
|
23
34
|
type: string
|
|
@@ -26,8 +37,6 @@ members:
|
|
|
26
37
|
format: date-time
|
|
27
38
|
assignee: # a name, or a pointer to a person / agent node
|
|
28
39
|
type: string
|
|
29
|
-
depends: # "blocked-by" edges → other tasks (ref; the dependency DAG)
|
|
30
|
-
type: array
|
|
31
|
-
others: *:: yamlover: $defs: task
|
|
32
40
|
estimate: # free: "2h", "3pt"
|
|
33
41
|
type: string
|
|
42
|
+
workflow: *:: yamlover: $defs: onto # optional ref → the workflow whose states add EMPTY lanes
|
|
@@ -15,4 +15,7 @@ value: # the workflow's description (it
|
|
|
15
15
|
format: text/marklower
|
|
16
16
|
members:
|
|
17
17
|
initial: *:: yamlover: $defs: onto # ref → the start state
|
|
18
|
+
active: *:: yamlover: $defs: onto # ref → the state that says WORK IS HAPPENING: a parent whose
|
|
19
|
+
# subtask reached it (or any later state) is raised to it
|
|
20
|
+
# (docs/documents/chapter/task, the parent-follows law)
|
|
18
21
|
others: *:: yamlover: $defs: onto # every other key is a STATE (a plain tag)
|
|
@@ -28,15 +28,21 @@ fifth tag: !!<*::yamlover:$defs:onto>
|
|
|
28
28
|
workflow: Lifecycles — task/ticket state machines
|
|
29
29
|
dev: !!<*yamlover:$defs:workflow> Software task lifecycle
|
|
30
30
|
initial: *::yamlover:ontos:workflow:dev:backlog
|
|
31
|
+
active: *::yamlover:ontos:workflow:dev:in-progress
|
|
31
32
|
backlog: Captured, not yet refined
|
|
32
33
|
color: "#9399b2"
|
|
33
34
|
next: *::yamlover:ontos:workflow:dev:ready
|
|
34
35
|
ready: Refined, ready to pick up
|
|
35
36
|
color: "#89b4fa"
|
|
36
37
|
next: *::yamlover:ontos:workflow:dev:in-progress
|
|
37
|
-
in-progress: Being worked
|
|
38
|
+
in-progress: Being worked
|
|
38
39
|
color: "#fab387"
|
|
39
40
|
next:
|
|
41
|
+
- *::yamlover:ontos:workflow:dev:review
|
|
42
|
+
- *::yamlover:ontos:workflow:dev:cancelled
|
|
43
|
+
review: Under review — tests, checks, a second look
|
|
44
|
+
color: "#f9e2af"
|
|
45
|
+
next:
|
|
40
46
|
- *::yamlover:ontos:workflow:dev:done
|
|
41
47
|
- *::yamlover:ontos:workflow:dev:cancelled
|
|
42
48
|
done: Completed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as f,b as d,j as o}from"./index-
|
|
1
|
+
import{r as f,b as d,j as o}from"./index-0ALNONIF.js";import{StaticImageChunk as h,PanZoomImage as x}from"./imagemap-rdhcPlWy.js";function E({node:t,label:a,decode:s,chunk:e}){const[r,i]=f.useState([]),[g,u]=f.useState(null);return f.useEffect(()=>{let n=!1;const c=[];return i([]),u(null),(async()=>{const l=await fetch(d(t.path)).then(m=>m.arrayBuffer()),p=await s(l);if(!n){for(const m of p)c.push(URL.createObjectURL(m));n||i(c)}})().catch(l=>!n&&u(String(l.message||l))),()=>{n=!0,c.forEach(URL.revokeObjectURL)}},[t.path]),g?o.jsxs("div",{className:"error",children:[a,": ",g]}):r.length?o.jsx(o.Fragment,{children:r.map((n,c)=>e?o.jsx(h,{src:n,path:t.path,onNavigate:e.onNavigate},c):o.jsx(x,{src:n,className:"filemap fileimagemap",fill:r.length===1},c))}):o.jsxs("div",{className:"loading",children:["decoding ",a,"…"]})}async function w(t,a,s){const e=document.createElement("canvas");e.width=a,e.height=s;const r=e.getContext("2d");if(!r)throw new Error("no 2d context");const i=r.createImageData(a,s);return i.data.set(t),r.putImageData(i,0,0),b(e)}function b(t){return new Promise((a,s)=>t.toBlob(e=>e?a(e):s(new Error("canvas export failed")),"image/png"))}export{E as D,b as c,w as r};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as u,u as te,a as ne,e as oe,c as re,D as W,b as se,j as d,f as ae}from"./index-
|
|
1
|
+
import{r as u,u as te,a as ne,e as oe,c as re,D as W,b as se,j as d,f as ae}from"./index-0ALNONIF.js";import{u as ce,a as ie}from"./paged-Cjy3svw2.js";const le=""+new URL("djvu-Ci0lFKxE.js",import.meta.url).href;let X=null;function ue(){return window.DjVu?Promise.resolve(window.DjVu):(X??=new Promise((s,c)=>{const i=document.createElement("script");i.src=le,i.onload=()=>window.DjVu?s(window.DjVu):c(new Error("DjVu failed to load")),i.onerror=()=>c(new Error("could not load djvu.js")),document.head.appendChild(i)}),X)}let v=null,Y=null,_=null;const m=new Map,S=new Map,de=6,Q=1500;async function he(s,c){const i=await ue();return v??=new i.Worker,c!==Y&&(Y=c,m.clear(),S.clear(),_=(async()=>(await v.createDocument(s),Number(await v.doc.getPagesQuantity().run())||0))()),_}async function ge(s,c){const i=Math.max(1,Math.round(s.height*c/s.width)),w=await createImageBitmap(s,{resizeWidth:c,resizeHeight:i,resizeQuality:"medium"}),g=document.createElement("canvas");g.width=c,g.height=i;const x=g.getContext("2d");return x.drawImage(w,0,0),w.close(),x.getImageData(0,0,c,i)}function fe(s){const c=m.get(s);if(c)return m.delete(s),m.set(s,c),Promise.resolve(c);const i=S.get(s);if(i)return i;const w=(async()=>{const[g,x,y,A]=await v.run(v.doc.getPage(s).getImageData(),v.doc.getPage(s).getNormalizedTextZones(),v.doc.getPage(s).getWidth(),v.doc.getPage(s).getHeight()),b=Number(y)||g.width,N=Number(A)||g.height,j={image:b>Q?await ge(g,Q):g,zones:Array.isArray(x)?x:[],w:b,h:N};for(S.delete(s),m.set(s,j);m.size>de;)m.delete(m.keys().next().value);return j})();return S.set(s,w),w}const p=s=>Number(s)||0;function pe({image:s}){const c=u.useRef(null);return u.useLayoutEffect(()=>{const i=c.current;i&&(i.width=s.width,i.height=s.height,i.getContext("2d")?.putImageData(s,0,0))},[s]),d.jsx("canvas",{className:"djvu-page",ref:c})}function xe({node:s}){const c=u.useRef(null),[i,w]=u.useState(0),[g,x]=u.useState(1),[y,A]=u.useState(0),[b,N]=u.useState(null),[f,j]=u.useState(null),[E,B]=u.useState(()=>new Set),[D,P]=u.useState(()=>new Map),T=u.useRef(new Map),V=te(s.path),{openCreate:H,openEdit:Z,palette:q,preview:R}=ne(V,s.path),O=V.annotations.filter(e=>e.selector?.type==="djvu").map(e=>({page:p(e.selector.page)||1,x:p(e.selector.x),y:p(e.selector.y),w:p(e.selector.w),h:p(e.selector.h),title:e.description,color:re(e),ann:oe(e)?e:void 0})),U=R?.color??W;if(R?.selector.type==="djvu"){const e=R.selector;O.push({page:p(e.page)||1,x:p(e.x),y:p(e.y),w:p(e.w),h:p(e.h),color:R.color})}const C=u.useRef(new Map),z=ce(c,()=>{const e=[];for(let n=1;n<=i;n++){const t=C.current.get(n);t&&e.push(t)}return e},i>0&&y>0);ie(c);const F=u.useRef(z);F.current=z,u.useLayoutEffect(()=>{z.restoreAnchor()},[g]),u.useEffect(()=>{const e=c.current;e&&!e.closest(".chunk-body")&&e.focus({preventScroll:!0})},[]),u.useLayoutEffect(()=>{const e=c.current;if(!e)return;const n=new ResizeObserver(([t])=>A(t.contentRect.width));return n.observe(e),()=>n.disconnect()},[]);const k=Math.min(y,1e3)*g;u.useEffect(()=>{const e=c.current;if(!e)return;let n=!1,t=0;const o=a=>{(a.ctrlKey||a.altKey||a.metaKey)&&(a.preventDefault(),n||(F.current.captureAnchor(),n=!0),clearTimeout(t),t=window.setTimeout(()=>n=!1,250),x(h=>Math.min(5,Math.max(.4,h*(a.deltaY<0?1.1:1/1.1)))))};return e.addEventListener("wheel",o,{passive:!1}),()=>{e.removeEventListener("wheel",o),clearTimeout(t)}},[]),u.useEffect(()=>{let e=!1;return w(0),N(null),B(new Set),P(new Map),C.current.clear(),T.current.clear(),(async()=>{const n=await fetch(se(s.path)).then(o=>o.arrayBuffer()),t=await he(n,s.path);e||w(t)})().catch(n=>!e&&N(String(n.message||n))),()=>{e=!0}},[s.path]),u.useEffect(()=>{if(!i)return;const e=new IntersectionObserver(n=>{B(t=>{const o=new Set(t);for(const a of n){const h=Number(a.target.dataset.page);a.isIntersecting?o.add(h):o.delete(h)}return o.size===t.size&&[...o].every(a=>t.has(a))?t:o})},{root:c.current,rootMargin:"2000px 0px"});for(const n of C.current.values())e.observe(n);return()=>e.disconnect()},[i,y>0]),u.useEffect(()=>{let e=!0;return E.forEach(n=>{D.has(n)||fe(n).then(t=>{T.current.set(n,{w:t.w,h:t.h}),e&&P(o=>new Map(o).set(n,t))}).catch(()=>{})}),P(n=>{let t=!1;const o=new Map(n);for(const a of o.keys())E.has(a)||(o.delete(a),t=!0);return t?o:n}),()=>{e=!1}},[E]);const G=()=>{const e=window.getSelection();if(!e||e.isCollapsed||!e.anchorNode)return;const t=(e.anchorNode.nodeType===1?e.anchorNode:e.anchorNode.parentElement)?.closest(".djvu-page-wrap");if(!t||!c.current?.contains(t))return;const o=Number(t.dataset.page),a=t.getBoundingClientRect(),h=a.width/(D.get(o)?.w||1);if(!h)return;const l=e.getRangeAt(0).getBoundingClientRect();l.width<2||l.height<2||H({type:"djvu",page:o,x:Math.round((l.left-a.left)/h),y:Math.round((l.top-a.top)/h),w:Math.round(l.width/h),h:Math.round(l.height/h)},{x:l.left,y:l.bottom+6})},I=(e,n)=>n.getBoundingClientRect().width/(D.get(e)?.w||1),J=(e,n)=>{const t=n.currentTarget.getBoundingClientRect(),o=I(e,n.currentTarget);j({page:e,x0:(n.clientX-t.left)/o,y0:(n.clientY-t.top)/o,x1:(n.clientX-t.left)/o,y1:(n.clientY-t.top)/o})},$=(e,n)=>{const t=n.currentTarget.getBoundingClientRect(),o=I(e,n.currentTarget);j(a=>a&&{...a,x1:(n.clientX-t.left)/o,y1:(n.clientY-t.top)/o})},ee=(e,n)=>{const t=f;if(j(null),!t||t.page!==e)return;const o=I(e,n.currentTarget),a=Math.min(t.x0,t.x1),h=Math.min(t.y0,t.y1),l=Math.abs(t.x1-t.x0),r=Math.abs(t.y1-t.y0);if(l*o<3||r*o<3)return;const M=n.currentTarget.getBoundingClientRect();H({type:"djvu",page:e,x:Math.round(a),y:Math.round(h),w:Math.round(l),h:Math.round(r)},{x:M.left+a*o,y:M.top+(h+r)*o+6})};return b?d.jsxs("div",{className:"error",children:["djvu: ",b]}):d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"filedjvu yo-zoomable",ref:c,tabIndex:0,onMouseUp:G,children:[i===0&&d.jsx("div",{className:"loading",children:"opening djvu…"}),y>0&&Array.from({length:i},(e,n)=>{const t=n+1,o=E.has(t)?D.get(t):void 0,a=T.current.get(t),h=k*(a?a.h/a.w:Math.SQRT2),l=o?k/o.w:0;return d.jsx("div",{className:"djvu-page-wrap","data-page":t,ref:r=>{r?C.current.set(t,r):C.current.delete(t)},style:{width:k,height:o?void 0:h},children:o?d.jsxs(d.Fragment,{children:[d.jsx(pe,{image:o.image}),o.zones.length>0?d.jsx("div",{className:"djvu-textlayer",children:o.zones.map((r,M)=>d.jsx("span",{style:{left:r.x*l,top:r.y*l,width:r.width*l,height:r.height*l,fontSize:r.height*l},children:r.text},M))}):d.jsx("div",{className:"djvu-marquee",onMouseDown:r=>J(t,r),onMouseMove:r=>$(t,r),onMouseUp:r=>ee(t,r),children:f?.page===t&&d.jsx("div",{className:"djvu-region",style:{left:Math.min(f.x0,f.x1)*l,top:Math.min(f.y0,f.y1)*l,width:Math.abs(f.x1-f.x0)*l,height:Math.abs(f.y1-f.y0)*l,borderColor:U,background:U+"2e"}})}),O.filter(r=>r.page===t).map((r,M)=>{const K=r.color||W;return d.jsx("div",{id:r.ann?.fragmentSlug?ae(s.path,r.ann.fragmentSlug):void 0,className:"djvu-region"+(r.ann?" editable":""),title:r.ann?r.title||"click to recolor or delete":r.title,onClick:r.ann?L=>{L.stopPropagation(),Z(r.ann,{x:L.clientX,y:L.clientY})}:void 0,style:{left:r.x*l,top:r.y*l,width:r.w*l,height:r.h*l,borderColor:K,background:K+"2e"}},M)})]}):d.jsx("div",{className:"djvu-placeholder",children:E.has(t)?"decoding…":""})},n)})]}),q]})}export{xe as DjvuView};
|