@plitzi/sdk-server 0.33.2 → 0.34.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.
Files changed (274) hide show
  1. package/CHANGELOG.md +54 -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 +259 -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,259 @@
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
+ - **Breakpoints are ranges, not a cascade.** `tablet` is 48–64rem and `mobile` is below 48rem, and each inherits
96
+ only from `desktop` — a rule written for `tablet` never reaches a phone. A grid that collapses to one column at
97
+ tablet and should stay collapsed says so in `mobile` too. `authorSpace` warns (`tablet-rule-skips-mobile`) when it
98
+ does not.
99
+ - **Fonts are declared, not assumed.** A `font-family` loads only if the space lists the face in `fonts`
100
+ (`{ source: 'google', family: 'Fraunces', fallback: 'Georgia, serif', weights: [400, 600], styles: ['normal'] }`);
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: { … } } }`.
103
+
104
+ **Share a rule as a class, never as a spread.** Writing a rule set once in a `const` and spreading it into each
105
+ element's `css` shares the source and duplicates the document — one selector per element, so re-theming the card
106
+ in the builder re-themes one card. `styles()` declares the class where it is used and writes it once:
107
+
108
+ ```ts
109
+ const card = styles('card', { padding: '24px', 'border-radius': '12px', 'background-color': 'var(--surface)' });
110
+
111
+ container({ class: card, children: [ … ] });
112
+ ```
113
+
114
+ Accepted anywhere a class name is — `class`, a `slot`, a page's `class` — and collected from wherever the tree
115
+ names it. One name declared twice with rules that disagree is refused. `classes` at the top of the space is the
116
+ same mechanism for what describes the space rather than one section of it.
117
+
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.
120
+
121
+ ## Data
122
+
123
+ ```ts
124
+ heading({ bind: { content: 'posts.title' } }) // short form: attributes
125
+ paragraph({ visible: 'posts.hasPosts' }) // on screen only while this is true
126
+ paragraph({ visible: '!posts.hasPosts' }) // …and its inverse
127
+ container({ bind: [{ to: 'content', source: 'x.y', transformers: [ … ] }] }) // full form
128
+ ```
129
+
130
+ **A source names the id you gave the element** — `'posts.title'`, `'postList.item.cover'` — and the prefix is
131
+ filled in. Only half of a source name is yours: the other half is the kind of source the ELEMENT publishes, and it
132
+ is not always the word you can see (a `form` publishes under `apiContainer`). The four globals — `variables`,
133
+ `navigation`, `auth`, `state` — are named as themselves. A full name still works and is checked the same way: a
134
+ prefix that does not match the element, or a name nothing answers to, is refused when the space is authored. It
135
+ is the quietest failure a space can carry.
136
+
137
+ Server-resolved sections are an `apiContainer` with `runtime: 'server'` naming a connector or an action, and a
138
+ space that has any needs `rsc: { enabled: true }`.
139
+
140
+ **Never ask the data for a field's opposite.** Both sides of one question are `visible: 'x'` and `visible: '!x'` —
141
+ not an `x` and a `notX` beside it in the server's answer. The `!` is the `not` transformer, which reads a boolean
142
+ that travelled as text (`"false"`, `"0"`) and treats an empty array as false; an empty object is true. Only for a
143
+ real inverse — a three-state condition (`Boolean(post) && !canEdit`) still belongs where the data is made.
144
+
145
+ ## Flows
146
+
147
+ ```ts
148
+ button({
149
+ id: 'cta',
150
+ content: 'Get a quote',
151
+ flows: [[
152
+ onClick(),
153
+ named('quote', runServerAction({ actionId: 'shipping-quote', input: '{"city":"Berlin"}', mode: 'await' })),
154
+ setState({ key: 'quote', type: 'text', value: '{{quote.output.summary}}' })
155
+ ]]
156
+ })
157
+ ```
158
+
159
+ Use the step builders — they answer the three things that go wrong silently:
160
+
161
+ - **Where a step runs.** A global callback registers under its source MODULE (`state`, `auth`, `actions`), an
162
+ element callback under an element's id, a utility under nothing. The builders fill it in; a trigger and an
163
+ untargeted `updateElement` are filled with the element the flow was declared on.
164
+ - **Which `setState`.** `setState(…)` writes `runtime.state.<key>`; `updateElement(…)` changes one element's own
165
+ attribute or state. Different params, different node kind. Each has a flip-it counterpart storing the opposite
166
+ of what is there, which is how expand/collapse is ONE step on ONE trigger: `toggleState({ key })` for app state,
167
+ and `toggleElement({ category: 'state', key: 'visibility' }, 'panel')` to show/hide an element (the second
168
+ argument is the element it acts on; omitted, it acts on the one the flow is declared on). Never two branches
169
+ under opposite `when` guards — those read the state as it was when the flow STARTED, so they run a click behind.
170
+ - **What it takes.** Params are typed from the same declaration the builder's own panel is drawn from.
171
+
172
+ `named(id, step)` is how a later step reads an earlier one — the flow scope is keyed by node id, so
173
+ `{{quote.output.summary}}` resolves only when that step is called `quote`. `mode: 'await'` is what puts a run's
174
+ answer in the scope at all, and it is the default.
175
+
176
+ **Pass `input` as an object, not as a line of JSON text.** Both are accepted, and the text form fails silently: an
177
+ interpolated value carrying a quotation mark or a newline — a post body, a comment — makes it unparseable, and
178
+ unparseable input posts `{}` rather than refusing.
179
+
180
+ A flow is a list and never a tree, so "only if" is expressed on the step:
181
+
182
+ ```ts
183
+ whenSucceeded('quote', navigate({ urlType: 'internal', url: '{{quote.output.url}}' })),
184
+ whenFailed('quote', setState({ key: 'notice', type: 'text', value: '{{quote.reason}}' })),
185
+ when({ field: 'state.count', operator: '>', value: 3 }, addNotification({ content: 'Enough' }))
186
+ ```
187
+
188
+ `whenFailed` matches every outcome that is not `completed` — a run also comes back `skipped` or `aborted`, and
189
+ matching only `failed` is how those two end up doing nothing.
190
+
191
+ ## What gets refused
192
+
193
+ `authorSpace` throws rather than hand back a space that would not render:
194
+
195
+ - a CSS property the style editor could not read back
196
+ - a `class` or a `slot` naming a class the space does not declare (the error names the one you probably meant)
197
+ - an element asking for a shared class AND rules of its own — an element has one base selector
198
+ - one class name declared twice with rules that disagree
199
+ - a binding source naming an element nothing answers to, or one whose prefix is not what that element publishes
200
+ - a name that shadows a global data source (`variables`, `navigation`, `auth`, `state`)
201
+ - a step target naming an element that is not there
202
+ - two elements answering to one name, a broken flow chain, an orphan, a cycle
203
+ - a global callback on the wrong module — or on none — and a utility given one. A global callback registers under
204
+ its SOURCE MODULE (`auth`, `state`, `actions`), and the pair is what the runtime resolves a step by, so naming
205
+ either half wrong is a control that does nothing at all with no error anywhere. An action no built-in source
206
+ declares comes back in `warnings` instead of throwing, because a plugin may register a module of its own.
207
+
208
+ Those last checks need the vocabulary, which only the composed package has. Import `authorSpace` from
209
+ `@plitzi/sdk-authoring` — not straight from `@plitzi/sdk-schema` — and you get them.
210
+
211
+ For documents you did not author here — an export from the builder, a JSON edited by hand — run the same gate
212
+ before serving it:
213
+
214
+ ```ts
215
+ const { valid, errors, warnings } = validateSpace({ schema, style });
216
+ ```
217
+
218
+ ## Templates
219
+
220
+ A template is not a space: it is ONE subtree, the style that dresses it and a name, published as a JSON someone
221
+ fetches by URL and drags onto a canvas you will never see.
222
+
223
+ ```ts
224
+ import { authorTemplate } from '@plitzi/sdk-authoring';
225
+
226
+ const { template, warnings } = authorTemplate({
227
+ name: 'Pricing card',
228
+ description: 'A price, a list of features and a call to action.',
229
+ classes: { card: { padding: '24px', 'border-radius': '12px', 'background-color': 'var(--surface)' } },
230
+ root: container({ class: 'card', children: [heading('$19', { subType: 'h3' }), button({ content: 'Start' })] })
231
+ });
232
+
233
+ await writeFile('pricing-card.json', JSON.stringify(template, null, 2));
234
+ ```
235
+
236
+ Host that file and add it to a space's resources as an `application/json` — nothing else is required of you.
237
+
238
+ Everything a space is held to still applies, and two more things apply because a template LEAVES its space:
239
+
240
+ - **Everything it names, it carries.** A class declared in the space it was cut from does not travel; the element
241
+ keeps the class name, finds no rules wherever it is dropped, and renders unstyled. Declare in `classes` (or with
242
+ `styles()`) every rule the subtree names — `validateTemplate` warns about a name the manifest does not carry.
243
+ - **A binding may not point outside the subtree.** A source names an element by id, so binding to a provider
244
+ that stayed behind is dead on arrival — refused. Bring the provider (the `apiContainer`, the `form`) into the
245
+ template, or bind to one of the globals: `variables`, `navigation`, `auth`, `state`.
246
+
247
+ `validateTemplate(template)` runs the same gate over a manifest you did not author here — one exported by the
248
+ builder, or edited by hand — before you publish it.
249
+
250
+ ## Rules
251
+
252
+ 1. **Never hand-write `flat`, element ids, `styleSelectors`, `beforeNode`/`afterNode`/`flowId`.** They are derived.
253
+ Writing them is how a space half-renders with nothing reporting why.
254
+ 2. **Name what is referred to.** `id` on any element a binding, a step or a pager addresses.
255
+ 3. **Read the error.** Every refusal above names the element, the class or the property at fault; it is a bug in
256
+ the declaration, not a reason to work around the check.
257
+ 4. **Ids are stable.** They are hashes of the path that produced them, so re-authoring an unchanged space writes
258
+ byte-identical documents — a seed can re-run and a diff stays readable.
259
+ 5. **`warnings` is returned, not printed.** Read it if the space is generated in a build.