@plitzi/sdk-server 0.36.1 → 0.37.0

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,75 @@
1
1
  # @plitzi/sdk-server
2
2
 
3
+ ## 0.37.0
4
+
5
+ ### Minor Changes
6
+
7
+ - - A `button` takes a `title`: shown as a tooltip, and its accessible name when it has no text of its own — an
8
+ icon-only button without one was announced as nothing. The builder's settings offer it as "Tooltip". The JSON export
9
+ is two files, `schema.json` and `style.json`, shown as tabs; each group of changes in the export folds away.
10
+
11
+ - `BindingTransformer.params` is `Record<string, string | number | boolean>`: a param the builder draws as a checkbox
12
+ (`styleVariant`'s `append`) is stored as the boolean it is and read as one, so the type now says so. The MCP compares
13
+ such a param with its catalog options as text. A `container` may be an `li`, for the rows of a list. The export
14
+ keeps every element id with `keepIds`, and the header's Publish dialog opens wider.
15
+
16
+ - **The builder exports the space on screen — on paid plans.** **Export** in the header opens a wide dialog: the
17
+ format as tabs (TypeScript in one file, TypeScript with a file per page as a `.zip`, or JSON), generated as soon as
18
+ it is picked, shown read-only in CodeMirror — beside a file list when there are several — with one row of actions,
19
+ **Copy** and **Download**. What the export tidied is a one-line note that unfolds into readable groups. On the free
20
+ plan the dialog explains what export is instead; the server refuses the code with a 402 (`limit: 'spaceExport'`)
21
+ whatever the builder shows. `useSpaceExport` is the one way into it, for anything else that needs the space as files.
22
+
23
+ - **A space document can be read back into code.** `specFromSpace(documents)` turns a `{ schema, style }` pair — a
24
+ builder export, a seed checked in as JSON — into the `SpaceSpec` that authors it, and `specToSource(spec, { exportName })`
25
+ writes that spec out as the TypeScript a person would write: one factory call per element, the attributes a type
26
+ already defaults to left out, the longhands the document stores written back as `padding: 10px 20px`, and every class
27
+ something names as a `styles()` declaration held in a variable. `split: true` writes one file per page and per layout.
28
+ `compareSpaces(expected, actual)` proves the round trip: it lists every way two pairs render differently — the tree,
29
+ the attributes, the rules that apply to each element whatever its selector is called, bindings, flows, pages, layouts
30
+ and settings — and nothing else. A selector used by one element becomes that element's own `css`; one shared, or
31
+ spelled out anywhere in the document (a `customCss` rule, a template), stays a class under its own name; an element id
32
+ nothing refers to is left out and derived again.
33
+
34
+ What an older builder left behind is repaired on the way, and every repair is reported in `corrections` rather than
35
+ made silently: element types that no longer exist (`navbar` → a `list` laid out in a row, `navbarItem` → `listItem`),
36
+ a hover stored as a class of its own (`card:hover`) folded into the class, fields and attributes no component reads,
37
+ a setting nothing reads, a link `target` of `_blank` (the component adds the underscore, so it rendered as `__blank`),
38
+ `null` or an empty list where an attribute is unset, a binding to a source nothing publishes, a flow with a step that
39
+ runs nothing, and a global callback registered on the wrong module. A CSS property the style editor cannot hold is
40
+ kept in `customCss` under the same selector, so the page still renders it.
41
+
42
+ - **What a spec can say grew to what a document holds.** A selector carries its states and variants beside its rules —
43
+ `styles('card', { css, states: { hover }, variants: { active } })`, and `states` on an element's own `css` — and the
44
+ selector cache is now written by `processSelector`, the function the style editor writes it with. An element type's
45
+ defaults (`elements`) take states, variants, per-breakpoint rules and `slots` for its other selectors (a modal's
46
+ `rootContainer`). A space declares `layouts` — shells that pages render inside, named by `layout: { id, slot }` on a
47
+ page or on another layout, with the slot checked to be inside the shell — and a page takes `keepState` and
48
+ `stateStorage`. `visible: false` starts an element hidden for a flow to reveal, and `loadStrategy` is carried through.
49
+ An element's own selector never takes the name of a declared class any more, however that class happens to be called.
50
+
51
+ - `elementAttributeNames` lists, as data, the attributes each built-in element can be authored with — `null` for one
52
+ that takes any. It is generated from the elements' attribute types (`yarn generate:attribute-names`) and a type test
53
+ fails when the two disagree. `defaultAttributes(type)` and `defaultLabel(type)` expose what a factory fills in.
54
+
55
+ - `CustomAttributes` accepts any attribute, because the component a custom element's `renderType` names reads its own
56
+ attributes off it; and `FormControlAttributes` declares `previewError`, which `withFieldValue` reads.
57
+
58
+ ### Patch Changes
59
+
60
+ - Updated dependencies
61
+ - @plitzi/plitzi-sdk@0.37.0
62
+ - @plitzi/sdk-shared@0.37.0
63
+
64
+ ## 0.36.2
65
+
66
+ ### Patch Changes
67
+
68
+ - v0.36.2
69
+ - Updated dependencies
70
+ - @plitzi/plitzi-sdk@0.36.2
71
+ - @plitzi/sdk-shared@0.36.2
72
+
3
73
  ## 0.36.1
4
74
 
5
75
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plitzi/sdk-server",
3
- "version": "0.36.1",
3
+ "version": "0.37.0",
4
4
  "license": "AGPL-3.0",
5
5
  "files": [
6
6
  "dist",
@@ -58,12 +58,12 @@
58
58
  "type": "module",
59
59
  "sideEffects": false,
60
60
  "dependencies": {
61
- "@plitzi/plitzi-sdk": "0.36.1",
62
- "@plitzi/sdk-shared": "0.36.1",
61
+ "@plitzi/plitzi-sdk": "0.37.0",
62
+ "@plitzi/sdk-shared": "0.37.0",
63
63
  "ejs": "^6.0.1",
64
64
  "esbuild": "^0.28.2",
65
65
  "jsonwebtoken": "^9.0.3",
66
- "nodemailer": "^10.0.9"
66
+ "nodemailer": "^10.0.10"
67
67
  },
68
68
  "peerDependencies": {
69
69
  "mysql2": "^3",
@@ -78,11 +78,11 @@
78
78
  "devDependencies": {
79
79
  "@types/ejs": "^3.1.5",
80
80
  "@types/jsonwebtoken": "^9.0.10",
81
- "@types/node": "^26.5.1",
82
- "@types/nodemailer": "^8.0.1",
81
+ "@types/node": "^26.6.1",
82
+ "@types/nodemailer": "^8.0.2",
83
83
  "@types/react": "^19.3.0",
84
84
  "@vitejs/plugin-react": "^6.1.1",
85
- "@vitest/coverage-v8": "^5.0.0",
85
+ "@vitest/coverage-v8": "^5.0.1",
86
86
  "eslint": "^9.39.5",
87
87
  "eslint-plugin-import": "^2.32.0",
88
88
  "mysql2": "^3.24.4",
@@ -92,7 +92,7 @@
92
92
  "typescript": "^6.0.3",
93
93
  "vite": "^8.3.0",
94
94
  "vite-plugin-dts": "^5.1.0",
95
- "vitest": "^5.0.0"
95
+ "vitest": "^5.0.1"
96
96
  },
97
97
  "scripts": {
98
98
  "prepack": "node scripts/copy-authoring-skill.mjs",
@@ -99,7 +99,11 @@ property outside the vocabulary is an error naming the correct key (`paddingTop`
99
99
  - **Fonts are declared, not assumed.** A `font-family` loads only if the space lists the face in `fonts`
100
100
  (`{ source: 'google', family: 'Fraunces', fallback: 'Georgia, serif', weights: [400, 600], styles: ['normal'] }`);
101
101
  the page server writes exactly that list into the document, and anything else renders in the fallback.
102
- - Per element TYPE defaults go in `elements: { heading: { base: …, variants: { … } } }`.
102
+ - Per element TYPE defaults go in `elements: { heading: { base: …, states: { … }, variants: { … }, slots: { … } } }`
103
+ — `slots` dresses the type's other selectors (a modal's `rootContainer`) for every element of the type.
104
+ - **`:hover` is part of the selector, not a rule in `customCss`.** `styles('card', { css: { … }, states: { hover: { … } },
105
+ variants: { active: { … } } })`, and `states` beside an element's own `css`. Written in `customCss` it renders and
106
+ then cannot be read back or edited per breakpoint.
103
107
 
104
108
  **Share a rule as a class, never as a spread.** Writing a rule set once in a `const` and spreading it into each
105
109
  element's `css` shares the source and duplicates the document — one selector per element, so re-theming the card
@@ -115,8 +119,13 @@ Accepted anywhere a class name is — `class`, a `slot`, a page's `class` — an
115
119
  names it. One name declared twice with rules that disagree is refused. `classes` at the top of the space is the
116
120
  same mechanism for what describes the space rather than one section of it.
117
121
 
118
- An element has exactly ONE base selector, so a variant is its own class over a shared plain object
119
- (`styles('button-primary', { ...base, … })`), never two classes layered on top of each other.
122
+ An element has exactly ONE base selector, so a look that never changes is its own class over a shared plain object
123
+ (`styles('button-primary', { ...base, … })`), never two classes layered on top of each other. A class's `variants`
124
+ are for what the page switches while it runs — a binding with the `styleVariant` transformer picks one.
125
+
126
+ **Shells go in `layouts`.** A header or a sidebar every page shows is a layout the pages name —
127
+ `layout: { id: 'app-shell', slot: 'main' }`, the slot being the element in the shell where the body goes — never a
128
+ copy on each page. `visible: false` starts an element hidden for a flow to reveal.
120
129
 
121
130
  ## Data
122
131
 
@@ -137,6 +146,13 @@ is the quietest failure a space can carry.
137
146
  Server-resolved sections are an `apiContainer` with `runtime: 'server'` naming a connector or an action, and a
138
147
  space that has any needs `rsc: { enabled: true }`.
139
148
 
149
+ **A provider has no box unless you give it a tag.** An `apiContainer` renders no element of its own while its
150
+ `subType` is empty — the default, the builder's "Container Tag: None" — so its children sit directly in the parent's
151
+ layout. That is usually what you want (the provider stays invisible to the layout), and it means a `class` or `css`
152
+ on it styles nothing: the `gap` you wrote between its sections is simply not there. Put the layout on the parent, or
153
+ give the provider a tag (`attributes: { subType: 'div' }`) when it should be the box. `validateSpace` — and so
154
+ `authorSpace` and the MCP — warns with `STYLE_WITHOUT_TAG`.
155
+
140
156
  **Never ask the data for a field's opposite.** Both sides of one question are `visible: 'x'` and `visible: '!x'` —
141
157
  not an `x` and a `notX` beside it in the server's answer. The `!` is the `not` transformer, which reads a boolean
142
158
  that travelled as text (`"false"`, `"0"`) and treats an empty array as false; an empty object is true. Only for a
@@ -247,6 +263,14 @@ Everything a space is held to still applies, and two more things apply because a
247
263
  `validateTemplate(template)` runs the same gate over a manifest you did not author here — one exported by the
248
264
  builder, or edited by hand — before you publish it.
249
265
 
266
+ ## From an exported JSON
267
+
268
+ Never rewrite an exported space by hand. `specFromSpace({ schema, style })` reads it into the spec that authors it,
269
+ repairing what an older builder left behind and listing each repair in `corrections`; `specToSource(spec,
270
+ { exportName })` writes that spec as factory calls; `compareSpaces(original, authorSpace(spec))` must list nothing but
271
+ what `corrections` explains. The builder's **Export** (and `POST /utils/transform-to-authoring`) does all three. Edit
272
+ the code it writes from then on, not the JSON.
273
+
250
274
  ## Rules
251
275
 
252
276
  1. **Never hand-write `flat`, element ids, `styleSelectors`, `beforeNode`/`afterNode`/`flowId`.** They are derived.