@plitzi/sdk-server 0.38.4 → 0.38.6
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 +350 -0
- package/README.md +126 -17
- package/dist/actions.d.ts +8 -5
- package/dist/actions.js +3 -1
- package/dist/adapters/jsonAdapters.d.ts +1 -1
- package/dist/adapters/jsonAdapters.js +16 -3
- package/dist/core/configSeam.js +20 -4
- package/dist/core/createServer.js +3 -2
- package/dist/core/handlers/socialRouteHandlers.js +6 -1
- package/dist/core/http/stages/devReload.d.ts +11 -0
- package/dist/core/http/stages/devReload.js +17 -0
- package/dist/core/server/baseServer.d.ts +2 -0
- package/dist/core/server/baseServer.js +3 -0
- package/dist/core/server/pageServer.js +18 -0
- package/dist/core/services/registry.js +2 -0
- package/dist/core/services/rsc.js +1 -1
- package/dist/core/services/spaceDocument.d.ts +2 -0
- package/dist/core/services/spaceDocument.js +11 -0
- package/dist/functions-api.d.ts +6 -1
- package/dist/functionsRunner.d.ts +5 -0
- package/dist/functionsRunner.js +2 -1
- package/dist/helpers/hydrationPayload.d.ts +25 -4
- package/dist/helpers/hydrationPayload.js +36 -30
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/modules/actions/index.d.ts +11 -2
- package/dist/modules/actions/index.js +29 -7
- package/dist/modules/actions/runtime/fileKv.d.ts +28 -0
- package/dist/modules/actions/runtime/fileKv.js +95 -0
- package/dist/modules/actions/runtime/fileKv.test.d.ts +1 -0
- package/dist/modules/actions/runtime/memoryKv.d.ts +23 -0
- package/dist/modules/actions/runtime/memoryKv.js +39 -24
- package/dist/modules/actions/runtime/namespaceKv.d.ts +2 -0
- package/dist/modules/actions/runtime/namespaceKv.js +5 -3
- package/dist/modules/actions/runtime/renderResolver.d.ts +3 -2
- package/dist/modules/actions/runtime/renderResolver.js +13 -9
- package/dist/modules/actions/runtime/renderShare.d.ts +7 -24
- package/dist/modules/actions/runtime/renderShare.js +47 -13
- package/dist/modules/actions/runtime/runAction.js +15 -1
- package/dist/modules/actions/runtime/scope.js +16 -1
- package/dist/modules/actions/runtime/signing.js +4 -1
- package/dist/modules/actions/runtime/taskContext.d.ts +7 -1
- package/dist/modules/actions/runtime/taskContext.js +6 -2
- package/dist/modules/actions/tasks/registry.d.ts +3 -1
- package/dist/modules/actions/tasks/registry.js +15 -1
- package/dist/modules/actions/types.d.ts +15 -2
- package/dist/modules/functions/config.d.ts +6 -0
- package/dist/modules/functions/context.d.ts +4 -2
- package/dist/modules/functions/context.js +43 -21
- package/dist/modules/functions/load.d.ts +8 -1
- package/dist/modules/functions/load.js +8 -4
- package/dist/modules/functions/manifest.d.ts +4 -1
- package/dist/modules/functions/manifest.js +14 -2
- package/dist/modules/functions/native.d.ts +2 -1
- package/dist/modules/functions/native.js +2 -2
- package/dist/modules/functions/plugins.test.d.ts +1 -0
- package/dist/modules/functions/routes.d.ts +8 -3
- package/dist/modules/functions/routes.js +41 -21
- package/dist/modules/functions/scope.d.ts +30 -0
- package/dist/modules/functions/scope.js +28 -0
- package/dist/modules/functions/space.d.ts +10 -5
- package/dist/modules/functions/space.js +37 -15
- package/dist/modules/rsc/connectorRscData.d.ts +3 -1
- package/dist/modules/rsc/connectorRscData.js +8 -4
- package/dist/modules/rsc/handler.d.ts +3 -16
- package/dist/modules/rsc/handler.js +10 -4
- package/dist/modules/rsc/publicFileResolver.d.ts +15 -12
- package/dist/modules/rsc/publicFileResolver.js +56 -24
- package/dist/modules/rsc/resolveRscData.d.ts +3 -1
- package/dist/modules/rsc/resolveRscData.js +8 -5
- package/dist/modules/runtime/bundle.d.ts +5 -0
- package/dist/modules/runtime/bundle.js +20 -5
- package/dist/modules/sqlite/kv.d.ts +34 -0
- package/dist/modules/sqlite/kv.js +99 -0
- package/dist/modules/sqlite/kv.test.d.ts +1 -0
- package/dist/modules/ssr/Component.d.ts +2 -1
- package/dist/modules/ssr/Component.js +2 -1
- package/dist/modules/ssr/prepareRender.js +48 -6
- package/dist/modules/ssr/spaceDocument.d.ts +25 -0
- package/dist/modules/ssr/spaceDocument.js +72 -0
- package/dist/modules/ssr/spaceDocument.test.d.ts +1 -0
- package/dist/modules/ssr/testing/offlineData.d.ts +5 -0
- package/dist/modules/ssr/views/template.ejs +122 -20
- package/dist/plugins/compile.js +6 -21
- package/dist/plugins/compile.test.d.ts +1 -0
- package/dist/plugins/copy.d.ts +5 -0
- package/dist/plugins/copy.js +16 -1
- package/dist/plugins/copy.test.d.ts +1 -0
- package/dist/plugins/manager.d.ts +13 -0
- package/dist/plugins/manager.js +40 -11
- package/dist/plugins/watch.d.ts +12 -0
- package/dist/plugins/watch.js +79 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +2 -2
- package/dist/sqlite.d.ts +17 -0
- package/dist/sqlite.js +2 -0
- package/package.json +8 -3
- package/skills/plitzi-authoring/CHEATSHEET.md +4 -2
- package/skills/plitzi-authoring/SKILL.md +20 -19
- package/skills/plitzi-authoring/recipes/plugin.ts +1 -1
- package/skills/plitzi-authoring/recipes/server-data.ts +3 -3
- package/skills/plitzi-authoring/recipes/show-data.ts +3 -2
- package/skills/plitzi-authoring/recipes/typed-data.ts +1 -1
- package/skills/plitzi-authoring/reference/authoring-errors.md +8 -2
- package/skills/plitzi-authoring/reference/colours-and-motion.md +3 -1
- package/skills/plitzi-authoring/reference/data-and-visibility.md +24 -22
- package/skills/plitzi-authoring/reference/drawing.md +24 -0
- package/skills/plitzi-authoring/reference/efficiency.md +19 -2
- package/skills/plitzi-authoring/reference/flows.md +3 -0
- package/skills/plitzi-authoring/reference/layouts.md +8 -23
- package/skills/plitzi-authoring/reference/performance.md +2 -2
- package/skills/plitzi-authoring/reference/plugins.md +51 -38
- package/skills/plitzi-authoring/reference/review-checklist.md +2 -0
- package/skills/plitzi-authoring/reference/structure.md +32 -1
- package/skills/plitzi-authoring/reference/templates.md +5 -2
- package/skills/plitzi-authoring/reference/testing.md +9 -2
- package/skills/plitzi-authoring/reference/typed-sources.md +3 -1
- package/skills/plitzi-authoring/reference/validation.md +1 -1
|
@@ -9,13 +9,8 @@ custom({ id: 'arcade', renderType: 'nebulaRun', shipColor: 'amber', bind: { best
|
|
|
9
9
|
|
|
10
10
|
## Creating one
|
|
11
11
|
|
|
12
|
-
The CLI writes it, in the shape Plitzi's own elements are written in:
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npx @plitzi/cli add plugin seat-picker legend # elements of this project (src/plugins/<Name> in a CLI project)
|
|
16
|
-
npx @plitzi/cli create seat-picker --plugin # a package of its own, with a preview
|
|
17
|
-
npx @plitzi/cli pack plugin # built, with its manifest and the zip the builder takes
|
|
18
|
-
```
|
|
12
|
+
The CLI writes it, in the shape Plitzi's own elements are written in: `npx @plitzi/cli add plugin seat-picker` (a
|
|
13
|
+
package of its own and packing it: the CLI skill).
|
|
19
14
|
|
|
20
15
|
One folder, four files: `SeatPicker.tsx` (the component), `declaration.ts` (its `type`, the `triggers` it fires, the
|
|
21
16
|
`callbacks` it answers to, and the element the builder adds — data only), `Settings.tsx` (its panel in the builder), and
|
|
@@ -38,8 +33,7 @@ by the same name, and so does whatever a binding writes — which is what makes
|
|
|
38
33
|
panel edits for a plugin it has no controls for; from code, write attributes. A `settings` that is not JSON renders
|
|
39
34
|
"Settings Malformed" in the page.
|
|
40
35
|
|
|
41
|
-
Every prop is optional
|
|
42
|
-
is `undefined`, and a plugin that renders nothing then is a hole in the page.
|
|
36
|
+
Every prop is optional with a default: an attribute not authored yet, or a binding not answered yet, is `undefined`.
|
|
43
37
|
|
|
44
38
|
## The component
|
|
45
39
|
|
|
@@ -73,7 +67,36 @@ const stop = state.subscribe(next => save(next)); // called after every cha
|
|
|
73
67
|
```
|
|
74
68
|
|
|
75
69
|
`state` is the current value, `setState` replaces it (or takes an updater), `setStateByKey` writes one key,
|
|
76
|
-
`clearState` empties it, `subscribe` listens. Bindings on `state.*` re-render at once.
|
|
70
|
+
`clearState` empties it, `subscribe` listens. Bindings on `state.*` re-render at once. With the space's `keepState`
|
|
71
|
+
on ([kept state](kept-state.md)), what a plugin writes there — its layout, a choice — is back after a reload too.
|
|
72
|
+
|
|
73
|
+
## Laying out the space's elements
|
|
74
|
+
|
|
75
|
+
A plugin that arranges elements — a dock, tabs, a masonry — HOLDS them: they are its children in the space
|
|
76
|
+
(`custom({ renderType: 'dock', children: [feed, tools] })`, or dropped into it in the builder), and the component
|
|
77
|
+
places each in a box of its own, by the id it was authored under:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { elementChildren } from '@plitzi/plitzi-sdk';
|
|
81
|
+
|
|
82
|
+
{elementChildren(children).map(({ id, node }) => <section key={id} style={placed[id]}>{node}</section>)}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Never write `style` onto an element the plugin does not render: nothing promises to keep it. Its boxes share one
|
|
86
|
+
stacking context, the plugin's. `useDisplayMode()` names the breakpoint showing — `desktop`, `tablet` or `mobile` — at
|
|
87
|
+
the widths the space's styles use, instead of a width of the plugin's own.
|
|
88
|
+
|
|
89
|
+
## Its own server code
|
|
90
|
+
|
|
91
|
+
`plitzi add plugin board --server` writes `functions/index.ts` in its folder (the CLI skill). Its routes answer
|
|
92
|
+
under `/fn/plugins/board/`; the component names them, with nothing for the space to wire:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
const route = usePluginRoute('board'); // from '@plitzi/plitzi-sdk'
|
|
96
|
+
const url = route('/layout'); // undefined where no server runs code (the canvas)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Its `ctx.kv` is the plugin's own; the space's credentials and channels are not.
|
|
77
100
|
|
|
78
101
|
## Talking to other pages
|
|
79
102
|
|
|
@@ -104,13 +127,12 @@ import { useFlag } from '@plitzi/plitzi-sdk';
|
|
|
104
127
|
const newChart = useFlag('newChart'); // false for a flag the space does not declare
|
|
105
128
|
```
|
|
106
129
|
|
|
107
|
-
Gating the whole plugin needs no code: give its element `flag: 'newChart'`.
|
|
108
|
-
inside — a new mode, an extra panel.
|
|
130
|
+
Gating the whole plugin needs no code: give its element `flag: 'newChart'`.
|
|
109
131
|
|
|
110
132
|
## Drawing and animating
|
|
111
133
|
|
|
112
|
-
A canvas, WebGL or a loop of its own: `useCanvas2d`, `useWebGL`, `useWebGL2` and `useAnimationFrame` —
|
|
113
|
-
[drawing](drawing.md).
|
|
134
|
+
A canvas, WebGL or a loop of its own: `useCanvas2d`, `useWebGL`, `useWebGL2` and `useAnimationFrame` — and keeping one
|
|
135
|
+
with thousands of shapes fast — see [drawing](drawing.md).
|
|
114
136
|
|
|
115
137
|
## Registering
|
|
116
138
|
|
|
@@ -154,6 +176,10 @@ A plugin says what HAPPENED through its events (`onPick`, with the seat in the p
|
|
|
154
176
|
decide what that means — write `state`, open a modal, call a server action. Prefer that to writing `state` from inside
|
|
155
177
|
the component: the flow is visible in the space, the builder shows it, and the same act can come from a button too.
|
|
156
178
|
|
|
179
|
+
- A param declared `number` or `boolean` arrives as one, written or bound; any other arrives as written.
|
|
180
|
+
- To act when another element appears, `useElementVisible('tools')` (`@plitzi/plitzi-sdk`) — never watch classes.
|
|
181
|
+
- A name for screen readers is a prop of its own: declare `label`, write it as the root's `aria-label`.
|
|
182
|
+
|
|
157
183
|
## Behaving in the builder
|
|
158
184
|
|
|
159
185
|
The builder draws the element on its canvas while somebody edits the page: a click selects it, a drag moves it, a key
|
|
@@ -162,10 +188,21 @@ belongs to the editor.
|
|
|
162
188
|
- **Outside preview, do nothing on your own.** `usePlitziServiceContext().settings.previewMode` is `false` while the
|
|
163
189
|
page is edited. Declared interactions are already held back then; your own click handlers, timers, global listeners,
|
|
164
190
|
permission prompts and map gestures are not — gate them on `previewMode`, and still render something to select.
|
|
191
|
+
- **A drag lives in state, not in refs read while rendering** (the project's lint refuses that): keep the gesture
|
|
192
|
+
in `useState`, mirror the latest props into a ref inside an effect, and attach `pointermove` on `pointerdown`.
|
|
165
193
|
- **Never the global `window` or `document`.** The canvas is a frame of its own and the code runs in the builder's
|
|
166
194
|
window: listen, measure and go full screen through the node's own page (`ref.current.ownerDocument`, its
|
|
167
195
|
`defaultView`) or `usePlitziServiceContext().utils.getWindow()`. An `instanceof` check takes its class from there too.
|
|
168
196
|
|
|
197
|
+
## The plugin's stylesheet and the space's CSS
|
|
198
|
+
|
|
199
|
+
A plugin's stylesheet ships in a layer below the space's (`plitzi-sdk-plugin`, written by the build): the space's
|
|
200
|
+
classes and `customCss` win over it whatever their specificity, as over a built-in element's defaults.
|
|
201
|
+
|
|
202
|
+
A file a library needs whole is imported as Vite imports it, and travels inside the bundle: `worker.js?raw` is its
|
|
203
|
+
text (a worker, started from `URL.createObjectURL(new Blob([source]))`), `engine.wasm?inline` a data URI. Images and
|
|
204
|
+
fonts a stylesheet names are carried the same way.
|
|
205
|
+
|
|
169
206
|
## Components that draw into DOM they do not render
|
|
170
207
|
|
|
171
208
|
A map, a chart library, anything that positions its own markers or popups: its roots are the library's to place. Never
|
|
@@ -173,27 +210,3 @@ give them a class that sets `position` — the element falls into the page's flo
|
|
|
173
210
|
the look in the plugin's own stylesheet (imported CSS ships beside the bundle) and take colours from custom properties
|
|
174
211
|
the space sets (`--seat-accent: var(--accent)` in `customCss`); a canvas or WebGL layer resolves them through a probe
|
|
175
212
|
element with `getComputedStyle(probe).color`, again whenever `theme.resolved` changes (bind it as a prop).
|
|
176
|
-
|
|
177
|
-
## Components that draw a lot
|
|
178
|
-
|
|
179
|
-
A canvas with thousands of shapes on it — a whiteboard, a diagram, a map of points — is judged on a slower machine than
|
|
180
|
-
yours: sixty frames a second here says nothing about a four-year-old laptop. What keeps one fast is doing work in
|
|
181
|
-
proportion to what CHANGED, not to what is there:
|
|
182
|
-
|
|
183
|
-
- **Two layers.** Paint what stands still on one canvas and leave it; clear and draw the one over it every frame, with
|
|
184
|
-
only what moves: the cursor, the selection, what is being dragged.
|
|
185
|
-
- **Repaint the part that changed.** Something added, edited or removed repaints the area it was and is in, clipped,
|
|
186
|
-
with whatever reaches into it — not the whole board. A pan moves the picture already painted by whole device pixels
|
|
187
|
-
and paints the edges it uncovers.
|
|
188
|
-
- **Draw a dragged group once.** Everything picked up moves by the same amount at every step: draw it to a canvas of its
|
|
189
|
-
own when the drag begins and copy that into place after.
|
|
190
|
-
- **Cache per object, not per frame.** Treat elements as immutable and key what is derived from one — its bounds, its
|
|
191
|
-
shape, a resolved connector — on the object itself (a `WeakMap`), so nothing is worked out twice for the same thing.
|
|
192
|
-
- **Hand the space outcomes, not motion.** A stroke finished, a selection changed: a trigger each. Firing one at every
|
|
193
|
-
pointer move runs a flow and renders the page at every pointer move.
|
|
194
|
-
- **Measure with a bench, throttled.** A script that drives the real thing in a browser with the CPU slowed
|
|
195
|
-
(`Emulation.setCPUThrottlingRate`) and reports script time per frame, not only frames per second — and a test that
|
|
196
|
-
counts WORK (full repaints, strokes drawn during a drag), which holds on any machine where a timing does not.
|
|
197
|
-
|
|
198
|
-
Pizarra, the collaborative whiteboard on the platform (`pizarra.plitzi.app`), does all of it on a board of thousands
|
|
199
|
-
of elements.
|
|
@@ -9,6 +9,8 @@ of it; each line is something that has shipped broken before.
|
|
|
9
9
|
- [ ] Every **suggestion** is taken, or left for a reason you can say (the copies are about to diverge; three cards a
|
|
10
10
|
person rewords on the canvas) — and then quieted where it is written, `quiet: ['repeated-shape']`, so it stops
|
|
11
11
|
burying the ones that matter. The ones your change opened up first — [efficiency.md](efficiency.md).
|
|
12
|
+
- [ ] `npm run lint:space` is clean — no file past 400 lines, no rows of data inline, no colour that is not a token —
|
|
13
|
+
or each departure says why where it is ([structure.md](structure.md#checked-for-you)).
|
|
12
14
|
- [ ] No console errors on any page you touched.
|
|
13
15
|
|
|
14
16
|
## Nothing flashes, nothing jumps
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Structuring a space that grows
|
|
2
2
|
|
|
3
|
-
A one-screen space fits in `src/space.ts`. Past a few pages, split it by what changes together — a file per part, short
|
|
3
|
+
A one-screen space fits in `src/space/index.ts`. Past a few pages, split it by what changes together — a file per part, short
|
|
4
4
|
enough to read whole — and keep every repeated thing in exactly one place. `npx @plitzi/cli create shop --template
|
|
5
5
|
catalog` writes a complete small site in this shape (tokens, a layout, a card component, typed data, a page per file)
|
|
6
6
|
to read before writing one.
|
|
@@ -71,6 +71,30 @@ container({ id: 'quick', class: quickGrid, children: QUICK.map(item => quickCard
|
|
|
71
71
|
When items differ in ONE detail (one link needs a binding), put that detail in the item's data as an optional field
|
|
72
72
|
— never an `if (item.id === 'team')` inside the map.
|
|
73
73
|
|
|
74
|
+
## Pages of one shape are a family
|
|
75
|
+
|
|
76
|
+
Docs pages, a menu's sections, a team's profiles: the same shape, different words. Write the shape once and the pages
|
|
77
|
+
as data with `pageFamily` — it gives each page its id, slug, titles, folder and layout, and builds each body inside
|
|
78
|
+
`scope(entry.id, …)`, so the ids two pages of the family give are never one:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { pageFamily, heading, markdown } from '@plitzi/sdk-authoring';
|
|
82
|
+
import { SECTIONS } from '../data/sections'; // [{ id: 'starters', title: 'Starters', slug: 'starters', description, body }]
|
|
83
|
+
|
|
84
|
+
pages: [
|
|
85
|
+
home,
|
|
86
|
+
...pageFamily(
|
|
87
|
+
{ folder: 'menu', layout: { id: 'site', slot: 'site-slot' }, seoTitle: entry => `${entry.title} — Menu`,
|
|
88
|
+
body: entry => [heading({ id: 'title', content: entry.title }), markdown(entry.body, { id: 'body' })] },
|
|
89
|
+
SECTIONS
|
|
90
|
+
)
|
|
91
|
+
]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Adding a page is adding an entry; two entries of one id or slug are refused as any two pages are. For one shape over
|
|
95
|
+
records a visitor browses — a product, a post — a single page with a route param (`slug: 'posts/:postId'`) reading
|
|
96
|
+
the record is the answer instead: one page, as many addresses as records.
|
|
97
|
+
|
|
74
98
|
## Names
|
|
75
99
|
|
|
76
100
|
- **Ids:** `area-role` in kebab-case — `hm-traffic-title`, `docs-nav-docs-data`. Never the builder's positional
|
|
@@ -90,3 +114,10 @@ per page. It renders; it is not maintainable. When you work on such a file, leav
|
|
|
90
114
|
|
|
91
115
|
Each of those is safe to do on its own: authoring refuses anything that would not render, and the visual check shows
|
|
92
116
|
the rest.
|
|
117
|
+
|
|
118
|
+
## Checked for you
|
|
119
|
+
|
|
120
|
+
`npm run lint:space` (`plitzi lint`) reads the source for what this page asks — a file past 400 lines, pages in one
|
|
121
|
+
file, rows of data inline, a colour that is not a token, CSS copied three times, a row singled out by its id inside a
|
|
122
|
+
`map`, a minted id, a file nothing imports — at file:line, beside authoring's suggestions. Leave it clean; a departure
|
|
123
|
+
on purpose says why where it is: `// plitzi-lint-disable-next-line <code> -- why`.
|
|
@@ -26,7 +26,7 @@ characters. Only what you authored is interpolated.
|
|
|
26
26
|
|
|
27
27
|
A binding's template renders TEXT by default. For an attribute that holds a list, a number or a flag — a list's
|
|
28
28
|
`items` above all — hand over the VALUE with `returns: 'value'` (`returnMode: 'value'` on the transformer). The
|
|
29
|
-
template must be a single `{{ expression }}
|
|
29
|
+
template must be a single `{{ expression }}`, after any `{% set %}` that name its parts:
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
list({ id: 'shown', source: 'controlled',
|
|
@@ -63,7 +63,8 @@ outside the element that publishes it — each with the name it should have been
|
|
|
63
63
|
`rows|sort((a, b) => b.score - a.score)`, `rows|filter(r => r.score >= min)`, `rows|map(r => r.name)`.
|
|
64
64
|
- Tests: `is defined`, `is empty`, `is null`, `is iterable`, `is even`, `is odd`, `is same as(x)` (strict: `false` is
|
|
65
65
|
not `'false'`, `0` or an unset value), `is divisible by(n)`, and their `is not` forms. `null` and `none` are literals.
|
|
66
|
-
- Functions: `range`, `min`, `max`, `cycle`.
|
|
66
|
+
- Functions: `range`, `min`, `max`, `cycle`. `abs` is a filter (`x|abs`); floor and ceil are `x|round(0, 'floor')` and
|
|
67
|
+
`x|round(0, 'ceil')`; a clamp is `min(max(x, low), high)`.
|
|
67
68
|
- **Not supported**: `matches` (no regular expressions are evaluated — use `starts with`, `ends with`, `in`), macros,
|
|
68
69
|
`include`/`extends`, and any filter or function not listed here. `authorSpace` refuses them, and anything else the
|
|
69
70
|
interpreter would read past, rather than letting a template render a value nobody wrote.
|
|
@@ -99,6 +100,8 @@ A lookup across two sources — a row joined to the stats around it:
|
|
|
99
100
|
string stays a string however it looks — a password typed `1234` arrives as `"1234"`. Nothing is guessed from the
|
|
100
101
|
text: to convert, declare the type where the value lands (`setState`'s `type`, the action's input field). Text around
|
|
101
102
|
the tokens is text, unless it makes a JSON object or array — then it is that document (see `json_encode` above).
|
|
103
|
+
**One exception: a param that is only a JSON filter (`{{ rows|json_encode }}`) is the value it encodes** — the list,
|
|
104
|
+
not its text — so an action input receiving it is declared `json`; a `text` field refuses it (422).
|
|
102
105
|
|
|
103
106
|
## Dates
|
|
104
107
|
|
|
@@ -3,13 +3,20 @@
|
|
|
3
3
|
## One call: `inspectPage`
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
import { authorSpace, inspectPage } from '@plitzi/sdk-authoring';
|
|
6
|
+
import { answerAction, authorSpace, inspectPage, openPage } from '@plitzi/sdk-authoring';
|
|
7
7
|
|
|
8
8
|
const { handles } = authorSpace(space);
|
|
9
|
-
await page
|
|
9
|
+
await openPage(page, '/');
|
|
10
10
|
expect((await inspectPage(page, handles)).problems).toEqual([]);
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
`openPage` waits for the page to settle — loaded, and nothing asked for in half a second — counting no stream that
|
|
14
|
+
stays open: Playwright's `networkidle` never comes on a page with a realtime `channel`.
|
|
15
|
+
|
|
16
|
+
A test that would SAVE something answers that action itself, before opening the page, so it never writes the server's
|
|
17
|
+
`kv` the next test (or the developer) reads: `await answerAction(page, 'wall', { windows: [] })` — or a function of the
|
|
18
|
+
input. Every other call goes through.
|
|
19
|
+
|
|
13
20
|
It checks the open page and returns EVERY problem at once, one sentence each, naming the element and the reason:
|
|
14
21
|
|
|
15
22
|
- every element the page owes is present and visible — its own and those of the layouts around it
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Data typed by a sample
|
|
2
2
|
|
|
3
3
|
`source('site', home)` names a provider's source from a sample of its answer — the JSON file it reads, imported
|
|
4
|
-
(`import home from '
|
|
4
|
+
(`import home from '../data/home.json' with { type: 'json' }` — `src/data/`, or `public/data/` with no server). Every path is then completed by the editor
|
|
5
5
|
and checked: `site.data.hero.titel` is a type error, and refused `source-field-unknown` if it gets past the types.
|
|
6
6
|
|
|
7
7
|
```ts
|
|
@@ -18,3 +18,5 @@ apiContainer({ id: site.id, query: '/data/home.json', children: [
|
|
|
18
18
|
type-checked lint refuses an object in one).
|
|
19
19
|
- A list fed by a path hands its `row` the item typed: every field any item of the sample has.
|
|
20
20
|
- An item of a list is read by position: `site.data.sections[1]`.
|
|
21
|
+
- A provider fed by a server action publishes the action's output at its root: `actionSource('feed', sample)` types
|
|
22
|
+
it — `feed.stories`, and `feed.data` is a type error — with a sample of what the action's last step answers.
|
|
@@ -33,7 +33,7 @@ bar.
|
|
|
33
33
|
```ts
|
|
34
34
|
import { authorSpace } from '@plitzi/sdk-authoring';
|
|
35
35
|
|
|
36
|
-
import { space } from './src/space.ts';
|
|
36
|
+
import { space } from './src/space/index.ts';
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
39
|
const { schema, warnings, suggestions } = authorSpace(space, { plugins: [] /* your declarations */ });
|