@antelopejs/interface-dms-builder 0.0.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.
@@ -0,0 +1,140 @@
1
+ # Drafts and Preview
2
+
3
+ ## Overview
4
+
5
+ The per-block operations — `AddBlock`, `ConfigureBlock`, `MoveBlock`, `RemoveBlock` — each rewrite the page file, typecheck the project and write to disk. That is the right shape for an agent applying one edit at a time, and the wrong shape for an editor: a visual builder holds a whole page in memory, and replaying twenty edits at save time would mean twenty typechecks and twenty chances to stop half way.
6
+
7
+ `SetPageBlocks` is the declarative counterpart. You hand it the page's whole block tree and it writes that tree: one transaction, one typecheck, one `changes` list. `PreviewLayout` is its read-only twin — it serializes a draft through the real `dms-base` factories so you can render it without writing anything.
8
+
9
+ ```typescript
10
+ import {
11
+ PreviewLayout,
12
+ SetPageBlocks,
13
+ } from "@antelopejs/interface-dms-builder";
14
+ ```
15
+
16
+ ## Describe a Draft
17
+
18
+ `PageDraft` is a page as you want it written.
19
+
20
+ | Field | Type | Description |
21
+ | --- | --- | --- |
22
+ | `page` | `Partial<EditablePageMeta>` | Metadata to patch alongside the blocks. Omit to leave it alone. |
23
+ | `blocks` | `BlockDraft[]` | The top-level blocks, in the order they should appear. |
24
+
25
+ `BlockDraft` is one block:
26
+
27
+ | Field | Type | Description |
28
+ | --- | --- | --- |
29
+ | `name` | `string` | Static key (top-level) or `.child()` id (nested). Must be a valid identifier. |
30
+ | `type` | `string` | A `BlockTypeDescriptor.type` from the catalog. Ignored when `preserve` is set. |
31
+ | `config` | `Record<string, unknown>` | The factory's options. |
32
+ | `slot` | `string` | The slot the block sits in. |
33
+ | `meta` | `Record<string, unknown>` | Child metadata emitted with `slot` — `{ colSpan: 2 }` on a grid child. |
34
+ | `controller` | `ResourceRef` | Required for a controller-leading type such as `TableView`. |
35
+ | `children` | `BlockDraft[]` | Nested blocks, in `.child()` order. |
36
+ | `preserve` | `boolean` | Write the block back exactly as it stands on disk. |
37
+
38
+ ## Carry an Opaque Block Through a Write
39
+
40
+ A whole-tree write has to answer for blocks the builder can read but not rewrite: a `CustomComponent`, a block behind a computed expression, anything `GetPageStructure` reported with `editable: false`. `preserve` is that answer — the block is matched by name among its siblings and its source text is written back untouched.
41
+
42
+ Round-tripping a page therefore means keeping every block you did not edit, marking the opaque ones:
43
+
44
+ ```typescript
45
+ import {
46
+ GetPageStructure,
47
+ SetPageBlocks,
48
+ } from "@antelopejs/interface-dms-builder";
49
+
50
+ const structure = await GetPageStructure("/dashboard");
51
+ if (structure.ok) {
52
+ const blocks = structure.data.blocks.map((block) =>
53
+ block.editable
54
+ ? { name: block.name, type: block.type as string, config: block.config }
55
+ : { name: block.name, preserve: true },
56
+ );
57
+ await SetPageBlocks("/dashboard", { blocks }, {
58
+ expectedVersion: structure.data.version,
59
+ });
60
+ }
61
+ ```
62
+
63
+ A `preserve` block whose name matches nothing on disk is rejected with `invalid_config`.
64
+
65
+ ## Write a Whole Page
66
+
67
+ ```typescript
68
+ const result = await SetPageBlocks(
69
+ "/dashboard",
70
+ {
71
+ page: { displayName: "Revenue" },
72
+ blocks: [
73
+ {
74
+ name: "kpis",
75
+ type: "Grid",
76
+ config: { gap: "1rem" },
77
+ children: [
78
+ {
79
+ name: "row",
80
+ type: "GridRow",
81
+ children: [
82
+ {
83
+ name: "revenue",
84
+ type: "KpiCard",
85
+ config: { title: "Revenue", valueFormat: "currency" },
86
+ meta: { colSpan: 2 },
87
+ },
88
+ ],
89
+ },
90
+ ],
91
+ },
92
+ ],
93
+ },
94
+ { expectedVersion: "8826e812c4f58d51" },
95
+ );
96
+ ```
97
+
98
+ On success the result carries the staged `changes` and the page's new `version`, ready to be passed as the next `expectedVersion`.
99
+
100
+ Blocks absent from the draft are removed. Static members that are not blocks are left where they are, and named imports nothing references any more are dropped, so a page shrinks cleanly rather than accumulating dead imports.
101
+
102
+ `$expr` is refused anywhere in a draft: a whole-tree write stays structured, and arbitrary code would defeat the guarantee. `$dataType`, `$ref` and `$block` are all accepted — see [Value Encodings](./7.values.md).
103
+
104
+ ## Read the Failures
105
+
106
+ `SetPageBlocks` validates the whole draft before touching anything, so one call reports every problem at once, each addressed by a JSON pointer into the draft:
107
+
108
+ | Pointer | Cause |
109
+ | --- | --- |
110
+ | `/blocks/1/name` | Not a valid identifier, or a duplicate among its siblings. |
111
+ | `/blocks/2/type` | Unknown block type, or a child a container does not accept. |
112
+ | `/blocks/0/controller` | A controller-leading type without one, or a controller on a type that takes none. |
113
+ | `/blocks/3/config/title` | `$expr` inside a config value. |
114
+
115
+ Beyond `invalid_config`, the write fails the same way the per-block operations do: `stale` when `expectedVersion` no longer matches, `typecheck_failed` when the emitted source does not compile — and then nothing is written. See [Results and Errors](./8.results-and-errors.md).
116
+
117
+ ## Preview a Draft
118
+
119
+ `PreviewLayout` serializes a draft the way the runtime would, by calling the same `dms-base` factories the emitted source would call. Nothing is typechecked and nothing reaches disk, so it is cheap enough to run on every edit.
120
+
121
+ ```typescript
122
+ const preview = await PreviewLayout("/dashboard", draft);
123
+ if (preview.ok) {
124
+ const grid = preview.data.components.kpis; // ComponentPreview
125
+ }
126
+ ```
127
+
128
+ `PageLayoutPreview` holds:
129
+
130
+ | Field | Type | Description |
131
+ | --- | --- | --- |
132
+ | `components` | `Record<string, ComponentPreview>` | The serialized tree, keyed by top-level block name — the shape the DMS frontend renders. |
133
+ | `degraded` | `BlockPath[]` | Blocks the preview could not build faithfully. |
134
+
135
+ A block lands in `degraded` when the preview cannot reach what the running page holds: a controller-leading block such as `TableView` (the DataAPI class lives in the app, not in the builder), a `$ref`, an `$expr`, a `preserve` block (which the draft does not describe), or a factory that threw. Render the last known-good layout for those rather than trusting the preview.
136
+
137
+ ## Next Steps
138
+
139
+ - [Results and Errors](./8.results-and-errors.md) - Branch on `OpResult` and handle `stale`
140
+ - [Catalog](./3.catalog.md) - The block types, their schemas and their defaults
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@antelopejs/interface-dms-builder",
3
+ "version": "0.0.1",
4
+ "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/AntelopeJS/dms-builder.git"
8
+ },
9
+ "files": [
10
+ "LICENSE",
11
+ "README.md",
12
+ "dist",
13
+ "docs"
14
+ ],
15
+ "main": "dist/index.js",
16
+ "types": "dist/index.d.ts",
17
+ "typesVersions": {
18
+ "*": {
19
+ "dist/*": [
20
+ "dist/*",
21
+ "dist/*/index.d.ts"
22
+ ],
23
+ "*": [
24
+ "dist/*",
25
+ "dist/*/index.d.ts"
26
+ ]
27
+ }
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./*": {
35
+ "types": "./dist/*.d.ts",
36
+ "default": "./dist/*.js"
37
+ },
38
+ "./dist": {
39
+ "types": "./dist/index.d.ts"
40
+ },
41
+ "./dist/*": {
42
+ "types": "./dist/*.d.ts"
43
+ },
44
+ "./package.json": "./package.json"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "provenance": true,
49
+ "registry": "https://registry.npmjs.org/"
50
+ },
51
+ "devDependencies": {
52
+ "@antelopejs/interface-core": "^0.0.12",
53
+ "release-it": "^19.2.4",
54
+ "release-it-changelogen": "^0.1.0",
55
+ "rimraf": "^6.1.3",
56
+ "typescript": "^5.9.3"
57
+ },
58
+ "peerDependencies": {
59
+ "@antelopejs/interface-core": ">=0.0.12 <1.0.0"
60
+ },
61
+ "antelopeJs": {},
62
+ "scripts": {
63
+ "build": "rimraf dist && tsc -p tsconfig.build.json",
64
+ "typecheck": "tsc -p tsconfig.json",
65
+ "release": "release-it"
66
+ }
67
+ }