@atom.io/template-preact-svg-editor 0.1.0 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atom.io/template-preact-svg-editor
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - bb1d8de: Expose reusable contour, convergence, Domain, and editor-model modules for collaborative consumers while retaining the local Bezier editor. Harden subpath reordering against selective-undo holes. Report rejection using each contour edit's own submission receipt so another edit or accepted broadcast cannot overwrite its outcome.
8
+
9
+ Use the standalone `@atom.io/react`, `@atom.io/realtime`, and `@atom.io/eslint-plugin` packages. Build with TypeScript 7 while providing TypeScript 6 for ESLint's compiler API. Pin dprint 0.64.1 to distrust the compromised eMudhra certificates when downloading formatter plugins.
10
+ - Updated dependencies [bb1d8de]
11
+ - Updated dependencies [aa30b42]
12
+ - Updated dependencies [bb1d8de]
13
+ - atom.io@0.54.0
14
+ - @atom.io/realtime@0.1.0
15
+ - @atom.io/react@0.1.0
16
+
3
17
  ## 0.1.0
4
18
 
5
19
  ### Minor Changes
@@ -0,0 +1,132 @@
1
+ # Collaborative SVG Model Decisions
2
+
3
+ This template is the model-level fixture beneath Atom.io's collaborative vector
4
+ design vertical. The same ordinary atoms, families, selectors, and transactions
5
+ remain useful in a local editor and are now registered directly in a public
6
+ Mosaic Domain.
7
+
8
+ ## Durable Shape
9
+
10
+ Path order, path entities, subpath order, subpath entities, nodes, and edges are
11
+ separate ordinary Atom.io states. Drawing is a selector projection. There is no
12
+ SVG registry in the renderer or in realtime core.
13
+
14
+ Order members use rational ranks and immutable, idempotent operations. Concurrent
15
+ placements at the same rank use stable entry identity as their tie-breaker.
16
+ Geometry and entity members use deterministic last-operation-wins registers.
17
+ Both reducers are independent of delivery order, reject operation-ID collisions,
18
+ and publish strict Zod schemas for the future MOS-11 member-model hook.
19
+ Register receipts remain in the fixture state so that reuse of a superseded
20
+ operation ID still fails closed regardless of delivery order. The reducers and
21
+ their Standard-Schema operation boundaries register directly with the public
22
+ Domain member-model API. Bounding retained receipts is deliberately reserved
23
+ for MOS-16 model-aware compaction.
24
+
25
+ The local structural operations are transactions. Import validates the complete
26
+ fixture before writing. Insert, delete, split, and reorder update every required
27
+ member and its order state within one observable settlement. The invariant
28
+ selector reports duplicate references, absent entities, wrong ownership, absent
29
+ node or edge registers, and invalid close-node pairs.
30
+
31
+ ## Gesture and Presence Boundary
32
+
33
+ One pointer-down creates one actor/session-scoped gesture identity backed by a
34
+ logical clock. All member operations produced by that gesture derive stable,
35
+ totally ordered operation identities from it.
36
+
37
+ Pointer moves update only ephemeral presence in SVG document coordinates. The
38
+ ordinary drawing selector projects that preview for immediate feedback. Pointer-up
39
+ coalesces the entire drag into one durable geometry transaction; cancellation
40
+ drops the presence and writes nothing durable. Rejection still releases local
41
+ pointer and presence state. A disconnect can therefore expire the preview rather
42
+ than leaving partially committed geometry.
43
+
44
+ DOM references, the actual pointer-capture owner, active drag, zoom, pan,
45
+ selection, and workspace state have explicit local atoms. Presence is keyed by
46
+ logical actor and session, so concurrent sessions for one identity cannot
47
+ overwrite or clear each other. It carries a logical resource target and
48
+ coordinates, never a DOM identity or client viewport coordinate.
49
+
50
+ ## Why This Takes Its Own Path
51
+
52
+ The public Mosaic Domain contract classifies and addresses members, and its
53
+ atomic heterogeneous batches invoke registered per-member convergence models.
54
+ This fixture plugs synchronous pure reducers and Standard-Schema-compatible
55
+ operation schemas into those public seams without inventing a private batch
56
+ envelope or registration system.
57
+
58
+ The current `OList` transceiver is intentionally not used for collaborative
59
+ ordering. Its index-based mutations are useful locally but do not by themselves
60
+ converge when concurrent operations arrive in different orders. Rational order
61
+ operations make the required contention behavior executable while remaining
62
+ ordinary atom values.
63
+
64
+ ## Domain Batches and Observation
65
+
66
+ `svg-domain.ts` registers path order, paths, subpath order, subpaths, nodes, and
67
+ edges as durable Domain members with their public value models. Import, insert,
68
+ delete, split, reorder, and coalesced geometry commits plan explicit public
69
+ member operations and submit one heterogeneous batch carrying the stable gesture
70
+ ID. The application does not maintain a parallel registry.
71
+
72
+ Complete preflight precedes a single Store settlement. A rejected final member
73
+ therefore rolls back the whole optimistic gesture, and the invariant selector
74
+ never observes an accepted subpath order entry without its entity, node, and
75
+ edge. Duplicate delivery is idempotent. Offline work remains a complete pending
76
+ batch and replays after recovery.
77
+
78
+ Independent node families settle independently. Same-node register operations
79
+ retain immutable receipts and choose by stable operation identity, so arrival
80
+ order and a durable mutex do not affect the result.
81
+
82
+ ## Selective Compensation
83
+
84
+ Undo does not rewind an Atom.io timeline. Each reducer can accept a compensation
85
+ receipt naming exact earlier operation IDs to hide. The editor records only its
86
+ own successfully submitted gestures and appends all receipts for one undo in one
87
+ new batch. Later foreign operations remain candidates and therefore remain
88
+ visible.
89
+
90
+ Every Domain operation also carries its claimed actor. The member model compares
91
+ that actor with authenticated batch context and permits compensation targets only
92
+ when their retained receipt belongs to the same actor. A client cannot construct
93
+ a compensating batch that hides another participant's work.
94
+
95
+ ## Generic Presence Innovation
96
+
97
+ MOS-11 supplied durable batching but no public ephemeral controller. This work
98
+ adds a generic Mosaic Domain presence protocol, client, server, and Socket.IO
99
+ adapter rather than hiding an SVG-specific event channel in the template.
100
+
101
+ Presence addresses public ephemeral members and passes their Standard Schema
102
+ boundary. The server binds authorship to the authenticated actor and session,
103
+ requires a monotonically increasing session sequence, and retains cleared
104
+ session cursors so a delayed update cannot resurrect a preview. One physical
105
+ presence address has one live actor-session owner; separate sessions for one
106
+ actor use separate family keys and cannot overwrite or clear each other.
107
+
108
+ Payload size, update rate, live session count, client queue, server queue, and
109
+ socket request queue are bounded. Disconnect and expiry publish monotonic clear
110
+ envelopes, do not append durable history, and expose cleanup subscriptions plus
111
+ an explicit quiescent-session retirement hook for future residency work.
112
+
113
+ The SVG projection carries only logical target identity and document
114
+ coordinates. DOM nodes, pointer capture, active drag, viewport, zoom, and
115
+ workspace state remain local atoms. Pointer moves update ephemeral presence;
116
+ pointer-up contributes at most one durable geometry operation.
117
+ Presence publication is advisory: a transient transport failure updates the
118
+ controller's status but never aborts a local drag or its durable commit. Disposing
119
+ the controller immediately removes every ephemeral projection it owns, so a
120
+ recreated client cannot briefly display a cursor or preview from its predecessor.
121
+
122
+ ## Executable Conformance and Remaining Gates
123
+
124
+ The local suite covers every structural planner, settled invariants, independent
125
+ and contended geometry, malicious foreign compensation, whole-batch rejection,
126
+ offline replay, and selective undo. The `@atom.io/realtime/testing` suite drives
127
+ real Socket.IO clients through the public Domain, server, client, batch, and
128
+ presence seams. It covers duplicate delivery, final-member rejection, offline
129
+ replay, same-node contention, and disconnect during drag.
130
+
131
+ Partial residency, checkpoint recovery, and process restart remain explicitly
132
+ gated on MOS-12 and MOS-13. The canonical multiplayer renderer remains MOS-23.
package/README.md CHANGED
@@ -1,13 +1,26 @@
1
1
  # Preact SVG Editor
2
2
 
3
- A Preact + Vite starter that uses `atom.io` to model an editable SVG path.
3
+ A Preact + Vite starter that uses `atom.io` to model an editable SVG path. Its
4
+ state model is also the local conformance foundation for collaborative vector
5
+ editing with Mosaic Domains.
4
6
 
5
7
  ## What It Shows
6
8
 
7
- - atom families for keyed path nodes, edges, and subpaths
8
- - selector families for deriving SVG path data from small pieces of state
9
- - transactions for resetting and rebuilding the drawing in one user action
10
- - `useAtomicRef` for keeping a DOM ref available to atom.io logic
9
+ - ordinary atoms and atom families for path order, paths, subpath order,
10
+ subpaths, nodes, and edges
11
+ - deterministic sequence and register reducers with strict operation schemas
12
+ - selector families that derive SVG path data from the ordinary state graph
13
+ - atomic transactions for import, insert, delete, split, reorder, and geometry
14
+ gestures
15
+ - public Mosaic Domain registration and heterogeneous batch planners for every
16
+ structural gesture
17
+ - deterministic same-node contention, offline replay, duplicate delivery,
18
+ whole-batch rejection, and actor-selective compensation
19
+ - actor/session-scoped logical-coordinate drag presence with one durable commit
20
+ at pointer-up
21
+ - explicit local-only workspace, viewport, DOM reference, pointer capture, and
22
+ active-drag state
23
+ - `useAtomicRef` for keeping the local SVG element available to atom.io logic
11
24
 
12
25
  ## Run It
13
26
 
@@ -26,14 +39,34 @@ npm run preview
26
39
 
27
40
  Run `npm run lint` before committing. It enforces ESLint, type-aware Oxlint, React hook call-order correctness, and TypeScript with zero warnings. Run `npm run fmt:check` in CI and `npm run fmt` to apply the pinned dprint configuration locally.
28
41
 
42
+ Run the model conformance tests:
43
+
44
+ ```sh
45
+ npm test
46
+ ```
47
+
48
+ ## Quality Checks
49
+
50
+ Run `npm run lint` before committing. It enforces ESLint, type-aware Oxlint, and TypeScript with zero warnings. Run `npm run fmt:check` in CI and `npm run fmt` to apply the pinned dprint configuration locally.
51
+
29
52
  ## Where To Look
30
53
 
31
54
  - `src/index.tsx`: Preact entry point and resource links.
32
- - `src/BezierPlayground.tsx`: the atom.io state model and SVG editor UI.
55
+ - `src/svg-convergence.ts`: pure convergent sequence/register schemas and
56
+ reducers.
57
+ - `src/svg-editor-state.ts`: the durable graph, local/ephemeral boundaries,
58
+ selectors, transactions, and gesture identities.
59
+ - `src/svg-domain.ts`: public Domain registration, structural batch planning,
60
+ presence projection, and actor-selective compensating batches.
61
+ - `src/BezierPlayground.tsx`: the Preact renderer and pointer adapter.
62
+ - `COLLABORATION.md`: correctness decisions, innovations, and remaining
63
+ persistence gates.
33
64
  - `src/style.css`: layout and editor styling.
34
65
 
35
- ## Next Ideas
66
+ ## Realtime Boundary
36
67
 
37
- - Add undo and redo with an atom.io timeline.
38
- - Persist the SVG path to local storage.
39
- - Export the current drawing as an `.svg` file.
68
+ The reusable model fixture now synchronizes through public Mosaic Domain batch
69
+ and presence APIs. The visible playground intentionally remains a small local
70
+ renderer; MOS-23 consumes this fixture in the canonical realtime vector-editor
71
+ template. Partial residency, checkpoints, and process restart remain gated on
72
+ MOS-12 and MOS-13 rather than being simulated by application state.
package/eslint.config.ts CHANGED
@@ -1,6 +1,6 @@
1
+ import AtomIOPlugin from "@atom.io/eslint-plugin"
1
2
  import { default as TypeScriptPlugin } from "@typescript-eslint/eslint-plugin"
2
3
  import * as parser from "@typescript-eslint/parser"
3
- import AtomIOPlugin from "atom.io/eslint-plugin"
4
4
  import type { Linter } from "eslint"
5
5
  import * as ImportPlugin from "eslint-plugin-import-x"
6
6
  import { default as SimpleImportSortPlugin } from "eslint-plugin-simple-import-sort"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atom.io/template-preact-svg-editor",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/jeremybanka/atom.io.git",
@@ -8,28 +8,40 @@
8
8
  },
9
9
  "license": "Apache-2.0",
10
10
  "type": "module",
11
+ "exports": {
12
+ "./contour": "./src/svg-contour.ts",
13
+ "./convergence": "./src/svg-convergence.ts",
14
+ "./domain": "./src/svg-domain.ts",
15
+ "./model": "./src/svg-editor-state.ts"
16
+ },
11
17
  "dependencies": {
12
- "atom.io": "0.53.3",
13
- "preact": "11.0.0",
18
+ "@atom.io/react": "0.1.0",
19
+ "@atom.io/realtime": "0.1.0",
20
+ "atom.io": "0.54.0",
21
+ "preact": "11.0.1",
14
22
  "react": "npm:@preact/compat@18.3.2",
15
- "react-dom": "npm:@preact/compat@18.3.2"
23
+ "react-dom": "npm:@preact/compat@18.3.2",
24
+ "zod": "4.6.7"
16
25
  },
17
26
  "devDependencies": {
18
- "@dprint/json": "0.25.0",
19
- "@dprint/markdown": "0.24.0",
20
- "@dprint/oxc": "0.42.0",
27
+ "@atom.io/eslint-plugin": "0.1.0",
28
+ "@dprint/json": "0.25.2",
29
+ "@dprint/markdown": "0.28.0",
30
+ "@dprint/oxc": "0.47.0",
21
31
  "@preact/preset-vite": "2.10.6",
22
- "@typescript-eslint/eslint-plugin": "8.71.0",
23
- "@typescript-eslint/parser": "8.71.0",
24
- "dprint": "0.58.0",
32
+ "@typescript-eslint/eslint-plugin": "8.72.0",
33
+ "@typescript-eslint/parser": "8.72.0",
34
+ "@typescript/native": "npm:typescript@7.0.2",
35
+ "dprint": "0.64.1",
25
36
  "dprint-plugin-malva": "0.16.0",
26
- "eslint": "10.11.0",
37
+ "eslint": "10.13.0",
27
38
  "eslint-plugin-import-x": "4.17.1",
28
39
  "eslint-plugin-simple-import-sort": "14.0.0",
29
- "oxlint": "1.86.0",
30
- "oxlint-tsgolint": "7.0.2003",
31
- "typescript": "7.0.2",
32
- "vite": "8.3.1"
40
+ "oxlint": "1.89.0",
41
+ "oxlint-tsgolint": "7.0.2004",
42
+ "typescript": "npm:@typescript/typescript6@6.0.2",
43
+ "vite": "8.3.5",
44
+ "vitest": "5.0.5"
33
45
  },
34
46
  "publishConfig": {
35
47
  "access": "public"
@@ -43,6 +55,8 @@
43
55
  "lint:eslint": "eslint --max-warnings 0 .",
44
56
  "lint:oxlint": "oxlint --deny-warnings .",
45
57
  "lint:types": "tsc -b",
46
- "preview": "vite preview"
58
+ "preview": "vite preview",
59
+ "test": "vitest run",
60
+ "test:once": "vitest run"
47
61
  }
48
62
  }