@plitzi/sdk-server 0.33.1 → 0.34.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.
Files changed (274) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +283 -8
  3. package/dist/actions.d.ts +62 -0
  4. package/dist/actions.js +12 -0
  5. package/dist/adapters/cloudAdapters.d.ts +72 -0
  6. package/dist/adapters/cloudAdapters.js +303 -0
  7. package/dist/adapters/space/index.d.ts +93 -0
  8. package/dist/adapters/space/index.js +122 -0
  9. package/dist/adapters/space/resolvers.d.ts +69 -0
  10. package/dist/adapters/space/resolvers.js +79 -0
  11. package/dist/adapters/space/space.test.d.ts +1 -0
  12. package/dist/adapters/space/types.d.ts +64 -0
  13. package/dist/adapters/space/types.js +41 -0
  14. package/dist/auth.d.ts +50 -0
  15. package/dist/auth.js +19 -0
  16. package/dist/core/auth/api.d.ts +400 -11
  17. package/dist/core/auth/api.js +1044 -50
  18. package/dist/core/auth/createAuth.d.ts +135 -30
  19. package/dist/core/auth/createAuth.js +96 -24
  20. package/dist/core/auth/credentials.d.ts +9 -3
  21. package/dist/core/auth/credentials.js +10 -4
  22. package/dist/core/auth/csrf.d.ts +89 -0
  23. package/dist/core/auth/csrf.js +234 -0
  24. package/dist/core/auth/csrf.test.d.ts +1 -0
  25. package/dist/core/auth/identity.d.ts +6 -0
  26. package/dist/core/auth/identity.js +37 -8
  27. package/dist/core/auth/lifecycle.test.d.ts +1 -0
  28. package/dist/core/auth/oauth/index.d.ts +8 -0
  29. package/dist/core/auth/oauth/index.js +13 -15
  30. package/dist/core/auth/passwords.d.ts +15 -0
  31. package/dist/core/auth/passwords.js +32 -0
  32. package/dist/core/auth/redirects.d.ts +18 -0
  33. package/dist/core/auth/redirects.js +31 -0
  34. package/dist/core/auth/redirects.test.d.ts +1 -0
  35. package/dist/core/auth/routes.d.ts +4 -2
  36. package/dist/core/auth/routes.js +234 -9
  37. package/dist/core/auth/session.d.ts +11 -0
  38. package/dist/core/auth/session.js +1 -1
  39. package/dist/core/auth/spaceTokens.d.ts +38 -2
  40. package/dist/core/auth/spaceTokens.js +54 -2
  41. package/dist/core/auth/throttle.d.ts +5 -0
  42. package/dist/core/auth/throttle.js +81 -0
  43. package/dist/core/auth/throttle.test.d.ts +1 -0
  44. package/dist/core/auth/tokens.d.ts +83 -12
  45. package/dist/core/auth/tokens.js +51 -9
  46. package/dist/core/auth/totp.d.ts +48 -0
  47. package/dist/core/auth/totp.js +118 -0
  48. package/dist/core/auth/totp.test.d.ts +1 -0
  49. package/dist/core/createServer.d.ts +0 -6
  50. package/dist/core/createServer.js +35 -3
  51. package/dist/core/fontStore.d.ts +33 -0
  52. package/dist/core/fontStore.js +53 -0
  53. package/dist/core/fontStore.test.d.ts +1 -0
  54. package/dist/core/handlers/authMiddleware.js +1 -1
  55. package/dist/core/handlers/authRouteHandlers.d.ts +9 -1
  56. package/dist/core/handlers/authRouteHandlers.js +4 -3
  57. package/dist/core/handlers/csrfMiddleware.d.ts +20 -0
  58. package/dist/core/handlers/csrfMiddleware.js +32 -0
  59. package/dist/core/handlers/oauthRouteHandlers.d.ts +46 -0
  60. package/dist/core/handlers/oauthRouteHandlers.js +159 -0
  61. package/dist/core/handlers/socialRouteHandlers.d.ts +40 -0
  62. package/dist/core/handlers/socialRouteHandlers.js +129 -0
  63. package/dist/core/handlers/socialRouteHandlers.test.d.ts +1 -0
  64. package/dist/core/handlers/types.d.ts +22 -5
  65. package/dist/core/health.d.ts +11 -1
  66. package/dist/core/health.js +27 -3
  67. package/dist/core/http/dispatcher.d.ts +1 -1
  68. package/dist/core/http/dispatcher.js +20 -1
  69. package/dist/core/http/stages/authApi.js +1 -1
  70. package/dist/core/http/stages/fontAssets.d.ts +9 -0
  71. package/dist/core/http/stages/fontAssets.js +27 -0
  72. package/dist/core/http/stages/oauth.d.ts +19 -0
  73. package/dist/core/http/stages/oauth.js +118 -0
  74. package/dist/core/http/types.d.ts +12 -0
  75. package/dist/core/oauth/authorize.d.ts +22 -0
  76. package/dist/core/oauth/authorize.js +254 -0
  77. package/dist/core/oauth/authorize.test.d.ts +1 -0
  78. package/dist/core/oauth/challenge.d.ts +11 -0
  79. package/dist/core/oauth/challenge.js +33 -0
  80. package/dist/core/oauth/consentPage.d.ts +12 -0
  81. package/dist/core/oauth/consentPage.js +131 -0
  82. package/dist/core/oauth/metadata.d.ts +41 -0
  83. package/dist/core/oauth/metadata.js +71 -0
  84. package/dist/core/oauth/params.d.ts +5 -0
  85. package/dist/core/oauth/params.js +5 -0
  86. package/dist/core/oauth/pkce.d.ts +6 -0
  87. package/dist/core/oauth/pkce.js +15 -0
  88. package/dist/core/oauth/records.d.ts +72 -0
  89. package/dist/core/oauth/records.js +49 -0
  90. package/dist/core/oauth/register.d.ts +5 -0
  91. package/dist/core/oauth/register.js +55 -0
  92. package/dist/core/oauth/respond.d.ts +21 -0
  93. package/dist/core/oauth/respond.js +59 -0
  94. package/dist/core/oauth/token.d.ts +14 -0
  95. package/dist/core/oauth/token.js +130 -0
  96. package/dist/core/previewToken.d.ts +20 -0
  97. package/dist/core/previewToken.js +29 -1
  98. package/dist/core/server/pageServer.js +4 -1
  99. package/dist/core/services/action.d.ts +6 -4
  100. package/dist/core/services/action.js +103 -10
  101. package/dist/core/services/registry.js +2 -0
  102. package/dist/core/services/resolve.d.ts +8 -0
  103. package/dist/core/services/resolve.js +12 -1
  104. package/dist/core/staticFiles.js +1 -2
  105. package/dist/handlers.d.ts +7 -1
  106. package/dist/handlers.js +4 -1
  107. package/dist/helpers/buildResponseHelpers.d.ts +8 -0
  108. package/dist/helpers/buildResponseHelpers.js +9 -1
  109. package/dist/helpers/buildServerInfo.d.ts +8 -3
  110. package/dist/helpers/buildServerInfo.js +18 -14
  111. package/dist/helpers/cache/keys.d.ts +13 -0
  112. package/dist/helpers/cache/keys.js +12 -1
  113. package/dist/helpers/onAbort.d.ts +12 -0
  114. package/dist/helpers/onAbort.js +22 -0
  115. package/dist/helpers/onAbort.test.d.ts +1 -0
  116. package/dist/helpers/outboundGuard.d.ts +27 -0
  117. package/dist/helpers/outboundGuard.js +49 -0
  118. package/dist/helpers/outboundGuard.test.d.ts +1 -0
  119. package/dist/helpers/serverLog.d.ts +6 -3
  120. package/dist/helpers/serverLog.js +20 -3
  121. package/dist/index.d.ts +6 -0
  122. package/dist/index.js +9 -4
  123. package/dist/kernel.d.ts +5 -22
  124. package/dist/kernel.js +1 -14
  125. package/dist/modules/actions/{handler.js → connectorWrite.js} +5 -2
  126. package/dist/modules/actions/connectorWrite.test.d.ts +1 -0
  127. package/dist/modules/actions/index.d.ts +40 -0
  128. package/dist/modules/actions/index.js +46 -0
  129. package/dist/modules/actions/moduleFor.d.ts +3 -0
  130. package/dist/modules/actions/moduleFor.js +35 -0
  131. package/dist/modules/actions/moduleFor.test.d.ts +1 -0
  132. package/dist/modules/actions/runtime/check.d.ts +24 -0
  133. package/dist/modules/actions/runtime/check.js +111 -0
  134. package/dist/modules/actions/runtime/check.test.d.ts +1 -0
  135. package/dist/modules/actions/runtime/errors.d.ts +11 -0
  136. package/dist/modules/actions/runtime/errors.js +17 -0
  137. package/dist/modules/actions/runtime/guards.d.ts +126 -0
  138. package/dist/modules/actions/runtime/guards.js +246 -0
  139. package/dist/modules/actions/runtime/guards.test.d.ts +1 -0
  140. package/dist/modules/actions/runtime/kvStore.d.ts +27 -0
  141. package/dist/modules/actions/runtime/kvStore.js +41 -0
  142. package/dist/modules/actions/runtime/kvStore.test.d.ts +1 -0
  143. package/dist/modules/actions/runtime/limits.d.ts +11 -0
  144. package/dist/modules/actions/runtime/limits.js +35 -0
  145. package/dist/modules/actions/runtime/memoryKv.d.ts +2 -0
  146. package/dist/modules/actions/runtime/memoryKv.js +77 -0
  147. package/dist/modules/actions/runtime/namespaceKv.d.ts +9 -0
  148. package/dist/modules/actions/runtime/namespaceKv.js +19 -0
  149. package/dist/modules/actions/runtime/precheck.d.ts +27 -0
  150. package/dist/modules/actions/runtime/precheck.js +45 -0
  151. package/dist/modules/actions/runtime/renderResolver.d.ts +15 -0
  152. package/dist/modules/actions/runtime/renderResolver.js +130 -0
  153. package/dist/modules/actions/runtime/renderResolver.test.d.ts +1 -0
  154. package/dist/modules/actions/runtime/renderShare.d.ts +29 -0
  155. package/dist/modules/actions/runtime/renderShare.js +36 -0
  156. package/dist/modules/actions/runtime/renderShare.test.d.ts +1 -0
  157. package/dist/modules/actions/runtime/report.d.ts +14 -0
  158. package/dist/modules/actions/runtime/report.js +22 -0
  159. package/dist/modules/actions/runtime/runAction.d.ts +12 -0
  160. package/dist/modules/actions/runtime/runAction.js +405 -0
  161. package/dist/modules/actions/runtime/runAction.test.d.ts +1 -0
  162. package/dist/modules/actions/runtime/runLogger.d.ts +31 -0
  163. package/dist/modules/actions/runtime/runLogger.js +66 -0
  164. package/dist/modules/actions/runtime/runLogger.test.d.ts +1 -0
  165. package/dist/modules/actions/runtime/schedule.d.ts +35 -0
  166. package/dist/modules/actions/runtime/schedule.js +76 -0
  167. package/dist/modules/actions/runtime/schedule.test.d.ts +1 -0
  168. package/dist/modules/actions/runtime/scope.d.ts +40 -0
  169. package/dist/modules/actions/runtime/scope.js +103 -0
  170. package/dist/modules/actions/runtime/triggers.d.ts +12 -0
  171. package/dist/modules/actions/runtime/triggers.js +14 -0
  172. package/dist/modules/actions/taskCatalog.d.ts +26 -0
  173. package/dist/modules/actions/taskCatalog.js +24 -0
  174. package/dist/modules/actions/taskCatalog.test.d.ts +1 -0
  175. package/dist/modules/actions/tasks/auth.d.ts +2 -0
  176. package/dist/modules/actions/tasks/auth.js +40 -0
  177. package/dist/modules/actions/tasks/builtins.d.ts +8 -0
  178. package/dist/modules/actions/tasks/builtins.js +24 -0
  179. package/dist/modules/actions/tasks/connector.d.ts +2 -0
  180. package/dist/modules/actions/tasks/connector.js +141 -0
  181. package/dist/modules/actions/tasks/db.d.ts +2 -0
  182. package/dist/modules/actions/tasks/db.js +59 -0
  183. package/dist/modules/actions/tasks/db.test.d.ts +1 -0
  184. package/dist/modules/actions/tasks/flow.d.ts +3 -0
  185. package/dist/modules/actions/tasks/flow.js +109 -0
  186. package/dist/modules/actions/tasks/helpers.d.ts +16 -0
  187. package/dist/modules/actions/tasks/helpers.js +30 -0
  188. package/dist/modules/actions/tasks/http.d.ts +2 -0
  189. package/dist/modules/actions/tasks/http.js +111 -0
  190. package/dist/modules/actions/tasks/http.test.d.ts +1 -0
  191. package/dist/modules/actions/tasks/kv.d.ts +2 -0
  192. package/dist/modules/actions/tasks/kv.js +102 -0
  193. package/dist/modules/actions/tasks/kv.test.d.ts +1 -0
  194. package/dist/modules/actions/tasks/registry.d.ts +10 -0
  195. package/dist/modules/actions/tasks/registry.js +36 -0
  196. package/dist/modules/actions/tasks/transform.d.ts +2 -0
  197. package/dist/modules/actions/tasks/transform.js +34 -0
  198. package/dist/modules/actions/transport/callHandler.d.ts +24 -0
  199. package/dist/modules/actions/transport/callHandler.js +233 -0
  200. package/dist/modules/actions/transport/callHandler.test.d.ts +1 -0
  201. package/dist/modules/actions/transport/cancelHandler.d.ts +23 -0
  202. package/dist/modules/actions/transport/cancelHandler.js +23 -0
  203. package/dist/modules/actions/transport/catalogHandler.d.ts +18 -0
  204. package/dist/modules/actions/transport/catalogHandler.js +21 -0
  205. package/dist/modules/actions/transport/stream.d.ts +23 -0
  206. package/dist/modules/actions/transport/stream.js +100 -0
  207. package/dist/modules/actions/transport/verifySignature.d.ts +16 -0
  208. package/dist/modules/actions/transport/verifySignature.js +72 -0
  209. package/dist/modules/actions/transport/webhookHandler.d.ts +25 -0
  210. package/dist/modules/actions/transport/webhookHandler.js +206 -0
  211. package/dist/modules/actions/transport/webhookHandler.test.d.ts +1 -0
  212. package/dist/modules/actions/types.d.ts +234 -0
  213. package/dist/modules/connectors/engine.js +4 -1
  214. package/dist/modules/connectors/resolver.d.ts +10 -2
  215. package/dist/modules/connectors/resolver.js +8 -3
  216. package/dist/modules/mysql/accounts.d.ts +5 -0
  217. package/dist/modules/mysql/accounts.js +365 -0
  218. package/dist/modules/mysql/accounts.test.d.ts +1 -0
  219. package/dist/modules/mysql/admin.d.ts +58 -0
  220. package/dist/modules/mysql/admin.js +133 -0
  221. package/dist/modules/mysql/config.d.ts +82 -0
  222. package/dist/modules/mysql/config.js +30 -0
  223. package/dist/modules/mysql/identities.d.ts +35 -0
  224. package/dist/modules/mysql/identities.js +43 -0
  225. package/dist/modules/mysql/index.d.ts +67 -0
  226. package/dist/modules/mysql/index.js +62 -0
  227. package/dist/modules/mysql/pool.d.ts +3 -0
  228. package/dist/modules/mysql/pool.js +88 -0
  229. package/dist/modules/mysql/query.d.ts +12 -0
  230. package/dist/modules/mysql/query.js +21 -0
  231. package/dist/modules/mysql/schema.d.ts +43 -0
  232. package/dist/modules/mysql/schema.js +340 -0
  233. package/dist/modules/mysql/schema.test.d.ts +1 -0
  234. package/dist/modules/mysql/sessions.d.ts +33 -0
  235. package/dist/modules/mysql/sessions.js +46 -0
  236. package/dist/modules/mysql/spaceTokens.d.ts +11 -0
  237. package/dist/modules/mysql/spaceTokens.js +59 -0
  238. package/dist/modules/mysql/store.integration.test.d.ts +1 -0
  239. package/dist/modules/rsc/connectorRscData.d.ts +25 -0
  240. package/dist/modules/rsc/connectorRscData.js +51 -0
  241. package/dist/modules/rsc/connectorRscData.test.d.ts +1 -0
  242. package/dist/modules/rsc/handler.js +16 -3
  243. package/dist/modules/rsc/matchRscPage.d.ts +14 -0
  244. package/dist/modules/rsc/matchRscPage.js +26 -0
  245. package/dist/modules/rsc/resolveRscData.d.ts +14 -1
  246. package/dist/modules/rsc/resolveRscData.js +23 -34
  247. package/dist/modules/ssr/Component.d.ts +6 -2
  248. package/dist/modules/ssr/Component.js +3 -1
  249. package/dist/modules/ssr/draftSession.test.d.ts +1 -0
  250. package/dist/modules/ssr/handler.js +15 -2
  251. package/dist/modules/ssr/loadPluginComponents.js +22 -5
  252. package/dist/modules/ssr/prepareRender.js +87 -8
  253. package/dist/modules/ssr/prepareRender.test.d.ts +1 -0
  254. package/dist/modules/ssr/preview.d.ts +21 -8
  255. package/dist/modules/ssr/preview.js +38 -14
  256. package/dist/modules/ssr/registerExternalPlugins.js +2 -2
  257. package/dist/modules/ssr/resolvePageSeo.d.ts +18 -0
  258. package/dist/modules/ssr/resolvePageSeo.js +26 -0
  259. package/dist/modules/ssr/resolvePageSeo.test.d.ts +1 -0
  260. package/dist/modules/ssr/template.test.d.ts +1 -0
  261. package/dist/modules/ssr/views/template.ejs +71 -5
  262. package/dist/mysql.d.ts +26 -0
  263. package/dist/mysql.js +4 -0
  264. package/dist/oauth.d.ts +24 -0
  265. package/dist/oauth.js +10 -0
  266. package/dist/plugins/compile.d.ts +1 -0
  267. package/dist/plugins/compile.js +37 -3
  268. package/dist/plugins/manager.d.ts +40 -0
  269. package/dist/plugins/manager.js +113 -13
  270. package/dist/plugins/manager.test.d.ts +1 -0
  271. package/package.json +43 -14
  272. package/skills/plitzi-authoring/SKILL.md +252 -0
  273. /package/dist/{modules/actions/handler.test.d.ts → adapters/cloudAdapters.test.d.ts} +0 -0
  274. /package/dist/modules/actions/{handler.d.ts → connectorWrite.d.ts} +0 -0
@@ -0,0 +1,252 @@
1
+ ---
2
+ name: plitzi-authoring
3
+ description: >-
4
+ Write a Plitzi space or a publishable template in TypeScript — pages, elements, CSS, data bindings and flows —
5
+ instead of hand-writing schema JSON. Use whenever the task is to create, extend or re-theme a space: adding a
6
+ page or a section, styling one, binding an element to server data, wiring what happens on click, authoring a
7
+ template to host, or turning an exported JSON into something maintainable.
8
+ ---
9
+
10
+ # Authoring Plitzi spaces
11
+
12
+ A Plitzi space is two documents — a schema and a style — of deeply cross-referenced ids. **Do not write them by
13
+ hand.** Every id, class name, parent/root link, breakpoint map and interaction chain is derived from a much
14
+ smaller declaration, and the surface that derives them also refuses a declaration that would not render.
15
+
16
+ ```ts
17
+ import { authorSpace, container, heading, text } from '@plitzi/sdk-authoring';
18
+
19
+ const { schema, style, warnings } = authorSpace({
20
+ name: 'My space',
21
+ permanentUrl: 'my-space',
22
+ classes: { page: { desktop: { display: 'flex', 'flex-direction': 'column', padding: '96px 24px', gap: '16px' } } },
23
+ pages: [
24
+ { name: 'Home', slug: '', class: 'page', body: [heading('Hello', { subType: 'h1' }), text('A paragraph.')] }
25
+ ]
26
+ });
27
+ ```
28
+
29
+ Serve it with the adapters the page server already takes:
30
+
31
+ ```ts
32
+ createServer({ port: 3001, adapters: createJsonAdapters({ offlineData: { schema, style } }) });
33
+ ```
34
+
35
+ One package, and it installs nothing: `@plitzi/sdk-authoring` has an empty dependency tree, no React and nothing
36
+ that touches a browser, so a seed, a migration, a build script or a project that only publishes templates depends
37
+ on it alone.
38
+
39
+ ## The types are the reference
40
+
41
+ Every factory, spec field and step builder carries its documentation in the published `.d.ts`. Read it rather
42
+ than guessing — `node_modules/@plitzi/sdk-authoring/dist/index.d.ts` is the whole surface in one file. Attribute
43
+ types come from each element's own component, so an editor completes them and a wrong value is a compile error.
44
+
45
+ ## Elements
46
+
47
+ One factory per element, named after it. Attributes and the authoring fields go in ONE flat object:
48
+
49
+ ```ts
50
+ heading({ content: 'Fieldnotes', subType: 'h2', class: 'title' })
51
+ image({ src: '/fox.jpg', alt: 'A fox', css: { 'aspect-ratio': '3/2' } })
52
+ container({ class: 'card', children: [ … ] })
53
+ text('Wildlife, close up') // a string is the content
54
+ container([hero, grid]) // an array is the children
55
+ ```
56
+
57
+ | Authoring field | What it does |
58
+ | --- | --- |
59
+ | `id` | the ONE name this element answers to — its key in the document, a binding's source, a step's target. **Name anything something else refers to**: a derived `<type>-<n>` is positional |
60
+ | `class` | a shared class: a name from the space's `classes`, or a `styles()` declaration. Exclusive with `css` |
61
+ | `css` | rules of this element's own: one set, or one per breakpoint (`{ desktop, tablet, mobile }`) |
62
+ | `variant` | a style variant of the element's own vocabulary |
63
+ | `slots` | a class for one of the element's OTHER selectors — a form control's `input`, `label`, `error` |
64
+ | `bind` | where a value comes from |
65
+ | `visible` | show it only while this source is true; `!source` for the inverse |
66
+ | `flows` | what happens on click, on submit, on load |
67
+ | `runtime` | `'server'` resolves this element's data on the server |
68
+ | `children` | the tree |
69
+ | `meta` | `meta.label` is the element's name in the builder's tree |
70
+
71
+ Anything else in the object is an **attribute**. `label` belongs to the attribute (a link and a form control both
72
+ have one); the builder's name for the element is `meta.label`.
73
+
74
+ A type this SDK does not ship — a plugin, one the deployment brings — is authored the same way:
75
+
76
+ ```ts
77
+ const speciesStatus = defineElement<{ status?: string }>({ type: 'speciesStatus', content: { … } });
78
+ element<{ status?: string }>('speciesStatus', { status: 'vulnerable' }); // or one at a time
79
+ elementsFromManifest(manifest); // or a whole plugin manifest
80
+ ```
81
+
82
+ ## Style
83
+
84
+ Write CSS the way you write CSS, shorthands included — they are expanded before they reach the document, because
85
+ Plitzi's style editor reads a closed list of longhand properties:
86
+
87
+ ```ts
88
+ css({ padding: '96px 24px', border: '1px solid var(--line)', 'border-radius': '12px' })
89
+ ```
90
+
91
+ You rarely call `css` yourself: `authorSpace` runs every rule set through it. What you get is the refusal — a
92
+ property outside the vocabulary is an error naming the correct key (`paddingTop` → `padding-top`).
93
+
94
+ - `column(gap, extra?)`, `row(gap, extra?)`, `grid(columns, gap, extra?)` for the three layouts every space repeats.
95
+ - Per element TYPE defaults go in `elements: { heading: { base: …, variants: { … } } }`.
96
+
97
+ **Share a rule as a class, never as a spread.** Writing a rule set once in a `const` and spreading it into each
98
+ element's `css` shares the source and duplicates the document — one selector per element, so re-theming the card
99
+ in the builder re-themes one card. `styles()` declares the class where it is used and writes it once:
100
+
101
+ ```ts
102
+ const card = styles('card', { padding: '24px', 'border-radius': '12px', 'background-color': 'var(--surface)' });
103
+
104
+ container({ class: card, children: [ … ] });
105
+ ```
106
+
107
+ Accepted anywhere a class name is — `class`, a `slot`, a page's `class` — and collected from wherever the tree
108
+ names it. One name declared twice with rules that disagree is refused. `classes` at the top of the space is the
109
+ same mechanism for what describes the space rather than one section of it.
110
+
111
+ An element has exactly ONE base selector, so a variant is its own class over a shared plain object
112
+ (`styles('button-primary', { ...base, … })`), never two classes layered on top of each other.
113
+
114
+ ## Data
115
+
116
+ ```ts
117
+ heading({ bind: { content: 'posts.title' } }) // short form: attributes
118
+ paragraph({ visible: 'posts.hasPosts' }) // on screen only while this is true
119
+ paragraph({ visible: '!posts.hasPosts' }) // …and its inverse
120
+ container({ bind: [{ to: 'content', source: 'x.y', transformers: [ … ] }] }) // full form
121
+ ```
122
+
123
+ **A source names the id you gave the element** — `'posts.title'`, `'postList.item.cover'` — and the prefix is
124
+ filled in. Only half of a source name is yours: the other half is the kind of source the ELEMENT publishes, and it
125
+ is not always the word you can see (a `form` publishes under `apiContainer`). The four globals — `variables`,
126
+ `navigation`, `auth`, `state` — are named as themselves. A full name still works and is checked the same way: a
127
+ prefix that does not match the element, or a name nothing answers to, is refused when the space is authored. It
128
+ is the quietest failure a space can carry.
129
+
130
+ Server-resolved sections are an `apiContainer` with `runtime: 'server'` naming a connector or an action, and a
131
+ space that has any needs `rsc: { enabled: true }`.
132
+
133
+ **Never ask the data for a field's opposite.** Both sides of one question are `visible: 'x'` and `visible: '!x'` —
134
+ not an `x` and a `notX` beside it in the server's answer. The `!` is the `not` transformer, which reads a boolean
135
+ that travelled as text (`"false"`, `"0"`) and treats an empty array as false; an empty object is true. Only for a
136
+ real inverse — a three-state condition (`Boolean(post) && !canEdit`) still belongs where the data is made.
137
+
138
+ ## Flows
139
+
140
+ ```ts
141
+ button({
142
+ id: 'cta',
143
+ content: 'Get a quote',
144
+ flows: [[
145
+ onClick(),
146
+ named('quote', runServerAction({ actionId: 'shipping-quote', input: '{"city":"Berlin"}', mode: 'await' })),
147
+ setState({ key: 'quote', type: 'text', value: '{{quote.output.summary}}' })
148
+ ]]
149
+ })
150
+ ```
151
+
152
+ Use the step builders — they answer the three things that go wrong silently:
153
+
154
+ - **Where a step runs.** A global callback registers under its source MODULE (`state`, `auth`, `actions`), an
155
+ element callback under an element's id, a utility under nothing. The builders fill it in; a trigger and an
156
+ untargeted `updateElement` are filled with the element the flow was declared on.
157
+ - **Which `setState`.** `setState(…)` writes `runtime.state.<key>`; `updateElement(…)` changes one element's own
158
+ attribute or state. Different params, different node kind. Each has a flip-it counterpart storing the opposite
159
+ of what is there, which is how expand/collapse is ONE step on ONE trigger: `toggleState({ key })` for app state,
160
+ and `toggleElement({ category: 'state', key: 'visibility' }, 'panel')` to show/hide an element (the second
161
+ argument is the element it acts on; omitted, it acts on the one the flow is declared on). Never two branches
162
+ under opposite `when` guards — those read the state as it was when the flow STARTED, so they run a click behind.
163
+ - **What it takes.** Params are typed from the same declaration the builder's own panel is drawn from.
164
+
165
+ `named(id, step)` is how a later step reads an earlier one — the flow scope is keyed by node id, so
166
+ `{{quote.output.summary}}` resolves only when that step is called `quote`. `mode: 'await'` is what puts a run's
167
+ answer in the scope at all, and it is the default.
168
+
169
+ **Pass `input` as an object, not as a line of JSON text.** Both are accepted, and the text form fails silently: an
170
+ interpolated value carrying a quotation mark or a newline — a post body, a comment — makes it unparseable, and
171
+ unparseable input posts `{}` rather than refusing.
172
+
173
+ A flow is a list and never a tree, so "only if" is expressed on the step:
174
+
175
+ ```ts
176
+ whenSucceeded('quote', navigate({ urlType: 'internal', url: '{{quote.output.url}}' })),
177
+ whenFailed('quote', setState({ key: 'notice', type: 'text', value: '{{quote.reason}}' })),
178
+ when({ field: 'state.count', operator: '>', value: 3 }, addNotification({ content: 'Enough' }))
179
+ ```
180
+
181
+ `whenFailed` matches every outcome that is not `completed` — a run also comes back `skipped` or `aborted`, and
182
+ matching only `failed` is how those two end up doing nothing.
183
+
184
+ ## What gets refused
185
+
186
+ `authorSpace` throws rather than hand back a space that would not render:
187
+
188
+ - a CSS property the style editor could not read back
189
+ - a `class` or a `slot` naming a class the space does not declare (the error names the one you probably meant)
190
+ - an element asking for a shared class AND rules of its own — an element has one base selector
191
+ - one class name declared twice with rules that disagree
192
+ - a binding source naming an element nothing answers to, or one whose prefix is not what that element publishes
193
+ - a name that shadows a global data source (`variables`, `navigation`, `auth`, `state`)
194
+ - a step target naming an element that is not there
195
+ - two elements answering to one name, a broken flow chain, an orphan, a cycle
196
+ - a global callback on the wrong module — or on none — and a utility given one. A global callback registers under
197
+ its SOURCE MODULE (`auth`, `state`, `actions`), and the pair is what the runtime resolves a step by, so naming
198
+ either half wrong is a control that does nothing at all with no error anywhere. An action no built-in source
199
+ declares comes back in `warnings` instead of throwing, because a plugin may register a module of its own.
200
+
201
+ Those last checks need the vocabulary, which only the composed package has. Import `authorSpace` from
202
+ `@plitzi/sdk-authoring` — not straight from `@plitzi/sdk-schema` — and you get them.
203
+
204
+ For documents you did not author here — an export from the builder, a JSON edited by hand — run the same gate
205
+ before serving it:
206
+
207
+ ```ts
208
+ const { valid, errors, warnings } = validateSpace({ schema, style });
209
+ ```
210
+
211
+ ## Templates
212
+
213
+ A template is not a space: it is ONE subtree, the style that dresses it and a name, published as a JSON someone
214
+ fetches by URL and drags onto a canvas you will never see.
215
+
216
+ ```ts
217
+ import { authorTemplate } from '@plitzi/sdk-authoring';
218
+
219
+ const { template, warnings } = authorTemplate({
220
+ name: 'Pricing card',
221
+ description: 'A price, a list of features and a call to action.',
222
+ classes: { card: { padding: '24px', 'border-radius': '12px', 'background-color': 'var(--surface)' } },
223
+ root: container({ class: 'card', children: [heading('$19', { subType: 'h3' }), button({ content: 'Start' })] })
224
+ });
225
+
226
+ await writeFile('pricing-card.json', JSON.stringify(template, null, 2));
227
+ ```
228
+
229
+ Host that file and add it to a space's resources as an `application/json` — nothing else is required of you.
230
+
231
+ Everything a space is held to still applies, and two more things apply because a template LEAVES its space:
232
+
233
+ - **Everything it names, it carries.** A class declared in the space it was cut from does not travel; the element
234
+ keeps the class name, finds no rules wherever it is dropped, and renders unstyled. Declare in `classes` (or with
235
+ `styles()`) every rule the subtree names — `validateTemplate` warns about a name the manifest does not carry.
236
+ - **A binding may not point outside the subtree.** A source names an element by id, so binding to a provider
237
+ that stayed behind is dead on arrival — refused. Bring the provider (the `apiContainer`, the `form`) into the
238
+ template, or bind to one of the globals: `variables`, `navigation`, `auth`, `state`.
239
+
240
+ `validateTemplate(template)` runs the same gate over a manifest you did not author here — one exported by the
241
+ builder, or edited by hand — before you publish it.
242
+
243
+ ## Rules
244
+
245
+ 1. **Never hand-write `flat`, element ids, `styleSelectors`, `beforeNode`/`afterNode`/`flowId`.** They are derived.
246
+ Writing them is how a space half-renders with nothing reporting why.
247
+ 2. **Name what is referred to.** `id` on any element a binding, a step or a pager addresses.
248
+ 3. **Read the error.** Every refusal above names the element, the class or the property at fault; it is a bug in
249
+ the declaration, not a reason to work around the check.
250
+ 4. **Ids are stable.** They are hashes of the path that produced them, so re-authoring an unchanged space writes
251
+ byte-identical documents — a seed can re-run and a diff stays readable.
252
+ 5. **`warnings` is returned, not printed.** Read it if the space is generated in a build.