@plitzi/sdk-shared 0.38.10 → 0.38.12

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 (39) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/dist/actions/validateDocument.mjs +2 -1
  3. package/dist/authoring/declare.d.ts +152 -2
  4. package/dist/authoring/declare.mjs +95 -2
  5. package/dist/authoring/index.mjs +5 -5
  6. package/dist/dataSource/getBindingsDetails.mjs +20 -20
  7. package/dist/dataSource/hooks/useRegisterSource.mjs +31 -18
  8. package/dist/helpers/generateFacade.mjs +16 -12
  9. package/dist/helpers/index.mjs +2 -2
  10. package/dist/helpers/utils.d.ts +1 -1
  11. package/dist/helpers/utils.mjs +1 -1
  12. package/dist/hooks/index.d.ts +3 -3
  13. package/dist/hooks/index.mjs +2 -2
  14. package/dist/hooks/usePlitzi.d.ts +32 -0
  15. package/dist/hooks/{usePlitziServiceContext.mjs → usePlitzi.mjs} +3 -3
  16. package/dist/index.mjs +3 -3
  17. package/dist/plugins/PluginsContext.d.ts +3 -0
  18. package/dist/plugins/PluginsContext.mjs +4 -0
  19. package/dist/project/paths.d.ts +1 -1
  20. package/dist/realtime/client.d.ts +6 -3
  21. package/dist/realtime/client.mjs +19 -17
  22. package/dist/realtime/index.d.ts +1 -1
  23. package/dist/realtime/index.mjs +4 -4
  24. package/dist/realtime/presence.mjs +1 -1
  25. package/dist/realtime/topics.d.ts +6 -0
  26. package/dist/realtime/topics.mjs +2 -2
  27. package/dist/store/index.d.ts +33 -33
  28. package/dist/style/styleTarget.mjs +28 -27
  29. package/dist/style/useElementSize.d.ts +16 -0
  30. package/dist/style/useElementSize.mjs +20 -0
  31. package/dist/types/ActionTypes.d.ts +19 -3
  32. package/dist/types/DataSourceTypes.d.ts +7 -2
  33. package/dist/types/EventBridgeTypes.d.ts +2 -1
  34. package/dist/types/InteractionTypes.d.ts +42 -4
  35. package/dist/types/RealtimeTypes.d.ts +14 -1
  36. package/dist/types/ServerTypes.d.ts +6 -1
  37. package/dist/websockets/RTCodec.d.ts +6 -1
  38. package/package.json +13 -5
  39. package/dist/hooks/usePlitziServiceContext.d.ts +0 -38
package/CHANGELOG.md CHANGED
@@ -1,5 +1,284 @@
1
1
  # @plitzi/sdk-shared
2
2
 
3
+ ## 0.38.12
4
+
5
+ ### Patch Changes
6
+
7
+ - 1301338: ## Builder
8
+
9
+ - **Icons in the canvas again** (`@plitzi/plitzi-builder`): the canvas inlined the SDK's Font Awesome sheet into its
10
+ `<style>`, where the sheet's `url(webfonts/…)` resolved against the editor's URL — a `srcdoc` frame takes it as its
11
+ base — so every icon was a 404 under `/spaces/<space>/webfonts/` and drew as an empty box. Only the Vite dev server,
12
+ which rewrites the URL, hid it. The canvas and the element preview now link the sheet from where the host serves it:
13
+ a new prop, `sdkIconsStylePath`, the one the host already gives the pages it renders
14
+ (`/sdk-assets/plitzi-sdk-icons.css` for sdk-server). Absent, the canvas links no icon sheet.
15
+
16
+ ## Plugins
17
+ - **A plugin's other elements, hosted by `custom`** (`@plitzi/sdk-elements`): `custom({ renderType: 'jamDisc' })` on a
18
+ space with a plugin installed whose main element is another (`plitzi plugin pack` of several folders: the first is the
19
+ plugin, the rest go in it) rendered "Custom Component jamDisc Not Found" — the page registers only the plugin's main
20
+ element, and a `custom` host looked nowhere else. It now loads the type from the installed plugin that packs it, as
21
+ an element of the type itself always did, so the two ways the docs give to place a plugin's element are the same
22
+ everywhere: in a project `plitzi create` wrote, and once the project is on Plitzi.
23
+ - **One way to place a plugin's element** (`@plitzi/sdk-authoring`, `@plitzi/cli`, docs): from its declaration,
24
+ `const seatPicker = defineElement(declaration)` then `seatPicker({ id, … })` — typed by what it
25
+ declares, and the element the builder adds when somebody drops it. The welcome space `plitzi create` writes, the
26
+ plugin package's preview, `plitzi plugin add` and `plitzi explain` all write it so (the template's
27
+ `PluginHostOptions` now takes the plugin's `type` and `declaration: { from, attributes? }`; `custom`/`element` hosting
28
+ is gone). `pluginFolders(folder)` (`@plitzi/sdk-authoring/node`) reads each plugin with the folder it is in;
29
+ `pluginDeclarations` is built on it. A `custom({ renderType })` naming a plugin the space was handed the declaration
30
+ of is offered the declaration instead — suggestion `plugin-custom-host`. `custom` stays for a component registered
31
+ by name with no declaration. The skills, the CLI README, the MCP guide, `docs/en` and the website say the same.
32
+ - **`definePlugin`** (`@plitzi/sdk-authoring/plugin`, a new entry of 3 KB with nothing else in it): a plugin's
33
+ declaration written from what only it can say —
34
+ `definePlugin<SeatPickerAttributes>()({ type, label, attributes, triggers, callbacks })` — and every other field
35
+ at the default all plugins share (the builder's gestures, the catalogue entry, each attribute bindable, an empty
36
+ style). It answers the whole declaration, branded with its attributes, so `defineElement(declaration)` is typed
37
+ without a generic. `plitzi plugin add` and `create --plugin` write declarations with it (about a third of the lines).
38
+ - **`usePluginTrigger(declaration)`** (`@plitzi/plitzi-sdk`): fires a plugin's declared event on its element — the
39
+ event name and what each hands a flow typed off the declaration's `preview` — on a live page only. The hook every
40
+ plugin wrote for itself (and `plugin add` generated as `use<Name>Events`) is gone from the scaffold.
41
+ - **Attributes as the types their defaults are** (`@plitzi/sdk-elements`): a plugin's attribute bound from text — a
42
+ state, a row, a channel message — reaches its component as the number or the flag its declared default is (`'112'`
43
+ as 112, `'true'` as true). A plugin no longer types its props `number | string` and parses them.
44
+
45
+ ## Server actions and functions
46
+ - **Task params with rules** (`@plitzi/sdk-server`, `@plitzi/sdk-shared`): a task declares `required`, a text's
47
+ `maxLength` and a number's `min`/`max`, and the runner refuses a call that breaks any of them — every rule broken at
48
+ once, in the words the page shows (`Title is required; Seconds is at most 300`) — before the code runs. A `text` param
49
+ bound to a number arrives as its digits. The manifest keeps the rules, so the platform's sandbox checks the same.
50
+ - **`taskAction(task, { trigger })`** (`@plitzi/sdk-authoring`): the action that runs one of the space's tasks and
51
+ answers its result, derived from the task — its id (`<namespace>-<action>`), name, description and input (the task's
52
+ params, once). An action of more than one step is still `defineAction`.
53
+ - **`ctx.rateLimit(bucket, { …, refuse })`**: past the limit the call is refused with those words instead of answering
54
+ `allowed: false` for the code to check — natively and in the sandbox.
55
+
56
+ ## Authoring
57
+ - **`runServerActionOrNotify(id, params, fallback)`**: a server action run and the notice the visitor reads when it
58
+ fails — the action's own refusal, or the fallback — as two steps to spread into a flow.
59
+ - **`repeated-shape` reads what copies bind**: copies whose bindings read their data in different forms (a count, a
60
+ total of a quota) and copies holding a provider resolved on the server (found by its own id) are no longer offered
61
+ as one component.
62
+ - **`element-color-inherited`** (suggestion): `elements` giving a heading, a text, a link… `color: inherit` or the
63
+ page's own colour. **A link inherits the page's colour** (`@plitzi/plitzi-sdk`, `@plitzi/sdk-elements`) rather than
64
+ holding the SDK's grey — the same by default, and the space's palette inside a card that is a link. The template
65
+ every space starts from writes its colours once, on the page.
66
+
67
+ ## Fixes
68
+ - **A dialog opened with an id** (`@plitzi/sdk-elements`): `openDialog('dialog', '{{ row.id }}')` reads the id as its
69
+ `content`, as `openModal` already did — a numeric id parsed as the number and the dialog's bindings read nothing.
70
+ - **A select's chevron** (`@plitzi/plitzi-sdk`): a drawn chevron in the field's own colour, sized by its type, in place
71
+ of the `▼` glyph — and laid out in the box, so it ends where the box's padding begins whatever that padding is, and
72
+ the chosen option stops short of it instead of running under it. A disabled select's is faded.
73
+ - **Every element has its settings** (`@plitzi/plitzi-builder`, `@plitzi/sdk-elements`): the builder found none for
74
+ `tabContainerHeader` (registered under a misspelt type), `themeToggle`, `dropdownPopup`, `loading` and `notFound`.
75
+ The theme toggle's panel sets its mode, its labels and whether it offers "System"; the registry is typed by element
76
+ type and must hold one for each.
77
+ - **A plugin's panel** (`@plitzi/cli`): `plitzi doctor` warns of a plugin with no `Settings.tsx`, or one its entry never
78
+ passes as `pluginSettings` (`plugin-settings-missing`); the example `create` writes has its panel, as every element
79
+ `plugin add` writes does, and the panels it generates are laid out as the project's Prettier lays them out.
80
+ - **A refused or failed run reaches `onFlowError` in every mode** (`@plitzi/sdk-interactions`): an awaited server
81
+ action the server refused fired no `onFlowError` on the element that started it, as `detached` and `stream` ones do
82
+ — a board rolling its edits back on a refusal never did; and a run answered `status: 'failed'` fired `onFlowEnd`
83
+ (detached) or nothing (awaited) rather than `onFlowError`.
84
+ - **A source renamed** (`@plitzi/sdk-shared`): the binding picker lists a provider, a form or a modal by the name its
85
+ element has now, not the one it had when it mounted.
86
+ - **A text's words in the builder** (`@plitzi/sdk-elements`): a `paragraph`, `text` or `heading` whose `content` is
87
+ `0` shows `0` while editing too, not its placeholder; one bound to nothing shows nothing rather than `null`.
88
+ - **Built-in declarations** (`@plitzi/sdk-shared`): `elementDeclaration` fills in what every element shares — the
89
+ builder's gestures, Plitzi's catalogue entry, a visible element with no bindings, its style named by its label —
90
+ from the defaults `definePlugin` uses; each element's declaration says only what is its own (a third of the lines).
91
+
92
+ ## Typed for plugins and hosts
93
+ - **`usePlitzi()` and `PlitziProvider`** (`@plitzi/sdk-shared/hooks/usePlitzi`, `@plitzi/plitzi-sdk`): what were
94
+ `usePlitziServiceContext()` and `PlitziServiceProvider` (and `PlitziServiceContextValue`, now `PlitziContextValue`),
95
+ holding only what the host rendering a space knows — `settings`, `root`, `utils`. Its `contexts` and
96
+ `customContexts` are gone: every context it carried is a shared one already, imported from its own module
97
+ (`@plitzi/sdk-interactions/InteractionsContext`, `@plitzi/sdk-shared/network/NetworkContext`…), and
98
+ `PluginsContext` moves to `@plitzi/sdk-shared/plugins/PluginsContext` beside the others.
99
+ - **`InteractionsManagerApi`** (`@plitzi/sdk-shared`): the interactions manager as everything outside
100
+ `@plitzi/sdk-interactions` reaches it, declared where every package can name it and implemented by
101
+ `InteractionsManager`, so `use(InteractionsContext)` is typed — `interactionTrigger`, `createChildManager`… — where it
102
+ was `any`.
103
+ - **`getPathsFromObject`** (`@plitzi/sdk-shared/helpers/utils`), spelt right; `getPathsFromObeject` is gone.
104
+ - **`ElementWords` places itself** (`@plitzi/sdk-elements`): `contentPlacement` and the element's children, so a button
105
+ and a link write their words once.
106
+
107
+ ## 0.38.11
108
+
109
+ ### Patch Changes
110
+
111
+ - cadf70a: - **`server.cache.invalidate` drops what a page is rendered from** (`@plitzi/sdk-server`): the pages, the RSC answers
112
+ and the schema data they are rendered from go together. It dropped the pages alone, and the next request rendered
113
+ the same page again from the schema still cached under the same key — a publish that invalidated the space changed
114
+ nothing until the schema's TTL ran out. `clear()` and `size` cover the three. A filter on `hostname` drops the schema
115
+ data too, which belongs to no one host. `server.cache` is `null` only when nothing is cached (`cacheTtlMs: 0` and
116
+ `rsc.cacheTtlMs: 0`).
117
+
118
+ ## Style inspector
119
+ - **Finds a property** (`@plitzi/sdk-style`): a search above the categories narrows them to the ones that edit what was
120
+ typed — a CSS name in any order of its words (`border radius` finds the four corners), a category's title, or a
121
+ common word for it (`bg`, `rounded`) — opens them, and shows the advanced rows when the match lives there. Escape
122
+ clears it. The categories' properties live in one list (`categoryKeys.ts`) that the dots, the advanced hint and the
123
+ search all read.
124
+ - **Rows that fit**: a section with more than two controls puts its label above them and lays them out in as many
125
+ columns as the panel is wide, instead of one row where every label was cut (`Appearan…`, `Cell Spaci…`, the five
126
+ scroll-snap controls). A row's label column is 80px.
127
+ - **Where a value comes from, said quietly**: the label's tint keeps its four meanings — set here, from a token, bound
128
+ to data, inherited — without the solid blocks of colour; hovering says which (an inherited one names its selector and
129
+ breakpoint) and that a click resets it, the click shows it by striking the label through. The footer's info icon
130
+ holds the legend, and its arrow folds every category.
131
+ - **What is being edited**: an "Editing … › Hover" line under the pickers whenever the rules being written are not the
132
+ selector's plain ones, with a button back to them. Ancestor, pseudo-element and condition fold behind a toggle —
133
+ never while one is in use.
134
+ - The class being edited is the panel's one strong mark (violet), the element's type defaults a softer one; the tools'
135
+ tabs fit the panel and are reachable from the keyboard.
136
+
137
+ - **Lists edited in a popover, all alike**: box and text shadows, transforms, transitions and filters share one row
138
+ (the CSS it writes, a swatch, a remove button) and one popover (a title, a close button, Escape, the focus moved
139
+ into it). What none of them could read is now kept and edited as text instead of being replaced with a default — a
140
+ token for the whole value, `drop-shadow(…)`, `url(#…)`.
141
+ - **Values read the way CSS writes them**: a shadow with two, three or four lengths and its color on either end;
142
+ `rgba(…)` inside text shadows and filters no longer split; negative shadow offsets accepted; a transition with any
143
+ of its parts left out; brightness, contrast and saturation past 1. Transition presets are written as CSS — the
144
+ preset names (`easeInQuad`) made the browser drop the whole declaration — the curve can be dragged into one of your
145
+ own, and the preview stops with the editor. `font-color` (not CSS) became `color`.
146
+ - **Background layers keep what they hold**: a repeating gradient (now a switch), a radial gradient's explicit size, a
147
+ token or `image-set()` as a layer (a "Custom (CSS)" layer), a one-value position read as CSS reads it (`20%` is
148
+ `20% center`), lists shorter than the layers repeated as CSS repeats them, an unset repeat read as tiling, two-position
149
+ stops, negative angles — every one of them was rewritten on the next edit of any layer. Defaults are no longer
150
+ written back, and "Token values" no longer bakes resolved tokens into the layers.
151
+ - **A layer's editor in two halves** — what it draws, then where it goes (size, position, tile, attachment, clip,
152
+ which now offers `text`). The gradient's stops sit on one bar, each a handle that drags or moves with the arrow keys;
153
+ the stop's color and position below it. Previews and swatches resolve the space's tokens.
154
+ - Spacing tells margin (dashed, outside) from padding; Border's sides are labelled and readable in the dark theme; a
155
+ class's menu says what each action does to whom; the Style Manager opens at a size that holds both columns.
156
+
157
+ ## Builder
158
+ - **Shortcuts**: `?` shows every shortcut the builder answers to — the same list the "Nothing selected" card teaches
159
+ from — and ⌘\ / Ctrl+\ hides both side panels for the canvas alone and brings back the ones that were open. Both
160
+ work with the canvas focused.
161
+ - **Panels keep their width**: each side panel opens at the width it was left at; the right one starts at 380px.
162
+ - **Text no smaller than 11px** across the builder's panels (it went down to 10px in fifty places).
163
+
164
+ ## Realtime
165
+ - **A page hears what it sent when it asks to** (`@plitzi/sdk-shared`, `@plitzi/sdk-server`, `@plitzi/sdk-elements`):
166
+ `publishOn('room', 'react', data, { echo: true })`, `useChannel().publish(type, data, { echo: true })` and the
167
+ channel's `publish` callback (`echo`) hand the message back to the page that sent it too, once the server took it —
168
+ stamped like everyone's, with `echo: true`, its `from` the channel's `me`. Without it a page still never hears its
169
+ own messages, and the docs said "every page on its topic hears it": they now say every OTHER page. Presence never
170
+ echoes.
171
+ - **A topic is opened only once it names one** (`@plitzi/sdk-elements`): `useChannel` — and so the `channel` element —
172
+ opens a topic only when a channel of the space covers it, by the same `matchChannel` the server decides by. A topic
173
+ written from data that has not arrived (`room:` while its provider loads, or its template still as text) asked the
174
+ server for both, was refused with a 403 and a console error on every load, and is now waited for.
175
+ - **Pages that watch** (`@plitzi/sdk-server`, `@plitzi/cli`): a connection whose page carries the `plitzi-observer`
176
+ cookie hears its topics and says nothing on them — no `$join`, no presence, its publishes taken and dropped.
177
+ `page check`, `page shot` and `verify` load pages that way, so checking a live site is no longer a visitor walking
178
+ into a room (`X walked in`, a member more in every picture). `--presence` takes part as a visitor does.
179
+
180
+ ## Authoring
181
+ - **`template-in-value`** (refused): a `{{ }}` inside an attribute that is an object or a list — a provider's
182
+ `input`, a list's `items`, a plugin's settings — is never evaluated: only an attribute that is text is interpolated,
183
+ and the page server reads attributes as saved. A provider's `input` also replaced the route param of the same name
184
+ the action was already given, so `input: { room: '{{ navigation.routeParams.room }}' }` reached the task as `""` and
185
+ the page answered 404; its refusal says the action is handed the page's route and query params already. Anything
186
+ else is a binding on the attribute. `mockData`, a sample, is not held to it.
187
+ - **Rules on top of a class need no `id`** (`class: [card, { gap: '6px' }]`): they are named after the id the element
188
+ is given, written or not. `modifier-without-id` is gone; a one-off tweak no longer needs a name nothing reads.
189
+ - **Typed list rows have `inTemplate`**, as untyped ones do, and `bindTemplate`, `visibleWhen`, `hiddenWhen` and
190
+ `variantFrom` take a typed source's path as well as a name: turning a list typed broke every template of its rows.
191
+ - **`when({ field, operator: 'empty' })`** takes no `value` (nor `notEmpty`), as flows.md recommends; it did not
192
+ type-check.
193
+ - **Data-driven colours**: a style binding on a custom property (`{ to: '--who', category: 'style' }`) is written as
194
+ named — it was camel-cased into `who` — so a class reads `var(--who, var(--muted))`. A style binding's value carrying
195
+ `;` or braces is not written: the page server writes inline styles as text, and such a value added declarations of
196
+ its own. `binding-target-unknown` on `style` or a CSS property says to bind it in the `style` category.
197
+ - `unknown-attribute` for `decorative` on an `svg` or a `fontAwesome` says what it means: without a `label` it is
198
+ already hidden from screen readers.
199
+
200
+ - **A folder nobody declared says where to declare it**: `folder-undeclared` (a page, a layout, a folder's parent)
201
+ ends with `pageFolders: [{ id, name }]` on the space, and with the line of the `pageFamily` that wrote the page. A
202
+ folder starts its pages' addresses (`/docs/quickstart`), so a misspelt one is never declared on the author's behalf.
203
+ The skill's `pageFamily` example declares its folder.
204
+ - **A tag is an element**: a `subType` this element has not but another has — `container({ subType: 'ol' })` — names
205
+ that element (`list({ subType: 'ol' })`) instead of the value two letters away (`dl`). Read off the elements'
206
+ declarations, for every element and tag.
207
+ - **A `pageFamily`'s body is written once**: `repeated-shape` and `repeated-on-pages` no longer count the same part of
208
+ each page of one family as copies — they were offering a component for exactly what the docs recommend. Copies within
209
+ one page, or across pages written one by one, are still offered.
210
+ - **Colour emoji are not text to `page check`**: a character painted in its own colours (🎲, `❤️`, a keycap, a ZWJ
211
+ sequence) is left out of the contrast measure, which compared `color` with the tile behind it and failed `verify`
212
+ in the theme whose text colour was close to the tile. A symbol drawn as text (✓, ★) is still measured.
213
+
214
+ - **`declared-callback-target`** (refused): a value beside `on` in `declaredCallback(…, { on, date })` — written as
215
+ `openModal`'s target reads — was read nowhere, and the step ran without it. Refused, with the `params` it goes in
216
+ (`{ on: 'calendar', params: { date } }`) and whether it is one of the callback's declared params.
217
+ - The skill's list rows show the typed form beside the untyped one: with `items` typed by a sample, `r.item` is a path
218
+ (`from: r.item.title`), not text to put in a template string.
219
+ - **`slot-not-class`** (refused): rules written in place in a slot — `slots: { error: [fieldError, { color }] }`, past
220
+ the type in JavaScript or a spec rebuilt from JSON — were taken for a declaration with no rules, and `authorSpace`
221
+ failed later with `Cannot read properties of undefined (reading 'desktop')`, naming nothing. Refused where the slot
222
+ is written, naming the slot and the element, with the `styles()` declaration to hand instead.
223
+
224
+ ## CLI
225
+ - **`page shot --click` (and `--clip`, `--wait-for`, `--scroll-to`, `--steps`) takes any selector**: a value that is
226
+ not an element's name (letters, digits, `-`, `_`) is a selector, CSS or Playwright's own (`button:has-text("Orbit")`).
227
+ It was wrapped as a name, and an invalid selector ended the command with Playwright's stack trace; it is now refused
228
+ with the reason.
229
+
230
+ - **`plitzi functions add <package>`**: a package the functions use comes with them, as a function carries its
231
+ dependencies. Installed in the project, it is bundled (web APIs only, minified, its licence kept) into
232
+ `src/functions/vendor/<package>.js`, with a `.d.ts` re-exporting the installed package's types, imported as
233
+ `./vendor/<package>.js` and pushed, built and run with the rest — nothing is resolved anywhere else, so the builder,
234
+ the sandbox and the push are unchanged. A package that reaches Node (`fs`, `node:*`) is refused, naming what it
235
+ reached; one past the functions' 1 MB is too; one that reads `process`/`Buffer` is warned about. The build's refusal
236
+ of a package import now names the command.
237
+ - **`page shot` targets**: a bare word is an element's name, or — no element named so — a tag (`textarea`); resolved on
238
+ the loaded page for `--click`, `--clip`, `--scroll-to`, `--wait-for` and `--steps`. In `--steps`, `type` takes a
239
+ quoted element with spaces (`type ".panel textarea" hola`) — it was cut at its first space and typed the rest — and
240
+ fails when the click leaves no field focused, rather than sending the keys to the page's shortcuts.
241
+
242
+ ## Server
243
+ - **`server.listen()` resolves once the port answers** (`@plitzi/sdk-server`) — in a fleet, once the first worker
244
+ does. `serveProject` writes `tmp/dev-server.json` and says `pages on …` after it, not on the line after `listen`:
245
+ for about 0.4 s a tool trusting the line (CI, Playwright's `webServer`, `page check`) was refused. A port it cannot
246
+ take still ends the process, or goes to `onListenError`, and the promise is then never resolved.
247
+ - **Runs set for later** (`@plitzi/sdk-server`, `@plitzi/sdk-shared`, `@plitzi/sdk-authoring`, `@plitzi/plitzi-builder`):
248
+ a turn that runs out, a bot's move, a hold that lapses — one run starting one of the space's actions in N seconds,
249
+ whether or not a page is still open. The action says it may be with a **`later` trigger** (no access rule: the run
250
+ that set it was let in); a flow sets it with `flow.later { action, in, input, key }`, a function with
251
+ `ctx.later({ … })`, and `flow.cancelLater` / `ctx.cancelLater(key)` drops it. A `key` names it: set again under the
252
+ same key, the one still waiting is replaced — the newer of two set at once, on every replica — and a running one is
253
+ left. It is a job of the queue schedules use: due by the store's clock (0 s to 30 days, about a second late at most),
254
+ once across replicas, retried, shown in Automations → Queue. Refused before anything is queued, with why: no `later`
255
+ trigger, one switched off, a time out of range, a key that is not one, a server with no jobs. A plugin's functions
256
+ set none. `ActionJobQueue` gains `cancelPending({ spaceId, key, olderThan? })` and jobs a `key`: the memory, Mongo
257
+ and MySQL queues implement it, and the shared contract tests it. **MySQL**: `action_jobs` gains `job_key` (and the
258
+ `action_jobs_key` index), added on first use; with `createTables: false`, run that statement of
259
+ `mysqlJobSchemaUpgrades()`. A queue of a deployment's own implements `cancelPending` (`09-schedules` shows one).
260
+ - **A project's `kv` file has one holder** (`@plitzi/sdk-server`): `createFileKv` takes `<file>.lock` with its pid;
261
+ a second process — another `npm start`, a `--watch` left running — is refused, naming the first (`the server of
262
+ "orbita", on port 8080`) instead of both writing their whole map over each other's changes, and a lock whose process
263
+ is gone is taken over. `close()` writes what is pending and lets go. A server with `workers` opens the file once, in
264
+ the primary, and its workers reach it through the fleet (`fleetKv`): each used to open a copy of its own.
265
+ - **A self-hosted project's credentials** (`@plitzi/sdk-server`, `@plitzi/cli`): `serveProject` answers
266
+ `getCredential` from `PLITZI_CREDENTIALS` in `.env` — one JSON object, credential id → its keys — so
267
+ `ctx.fetch({ credential })`, a connector and an `http.request` step work on the project's own server, not only in
268
+ `functions dev`. The same variable for both (it was `PLITZI_FUNCTIONS_CREDENTIALS`, read by the CLI alone); a value
269
+ that is not that object is refused with how to write it, instead of every credential going missing.
270
+ - **`HOST` beyond loopback says where to open it**: with `HOST=0.0.0.0`, `serveProject` prints the machine's network
271
+ addresses — what a tablet on the same Wi-Fi opens — and that anyone on that network can. `.env.example` names `HOST`
272
+ and `PLITZI_CREDENTIALS`.
273
+
274
+ ## SDK
275
+ - **`useElementSize(ref)`** (`@plitzi/plitzi-sdk`): the size a plugin's own box is drawn at, followed as it changes —
276
+ what `useDisplayMode()` cannot say: a tablet held upright is `mobile` by the window and still a week wide by the
277
+ plugin's box. `undefined` until measured, so the server's page and the hydrated one agree. The breakpoints are
278
+ unchanged.
279
+ - The functions docs say how a task's `params` types (how the builder edits them: `codemirror-json`) and an action's
280
+ `input` types (what the value is: `json`) correspond.
281
+
3
282
  ## 0.38.10
4
283
 
5
284
  ### Patch Changes
@@ -18,6 +18,7 @@ var s = [
18
18
  "call",
19
19
  "webhook",
20
20
  "schedule",
21
+ "later",
21
22
  "render",
22
23
  "custom"
23
24
  ], u = ["sha256", "sha1"], d = /* @__PURE__ */ new Set([
@@ -78,7 +79,7 @@ var s = [
78
79
  message: "is not valid JSON"
79
80
  }) : h(e, `${g}.params.input`, d);
80
81
  }
81
- if (_ !== "schedule") {
82
+ if (_ !== "schedule" && _ !== "later") {
82
83
  if (!p(v.access) || !c.includes(v.access)) d.push({
83
84
  path: `${g}.params.access`,
84
85
  message: "must say who may start a run this way",
@@ -1,6 +1,7 @@
1
- import { InteractionCallback } from '../types/InteractionTypes';
1
+ import { InteractionCallback, InteractionCallbackPreviews } from '../types/InteractionTypes';
2
2
  import { PluginBuilder, PluginSchema } from '../types/PluginTypes';
3
3
  import { ElementDefinition } from '../types/SchemaTypes';
4
+ import { DisplayMode, StyleAttributes } from '../types/StyleTypes';
4
5
  /**
5
6
  * How an element says what it can be authored with.
6
7
  *
@@ -148,5 +149,154 @@ export type AuthorableAttributes<Props, Injected extends keyof Props = never> =
148
149
  export declare const valuesOf: <T extends string>() => <const V extends readonly T[]>(values: V & ([Exclude<T, V[number]>] extends [never] ? unknown : {
149
150
  readonly missing: Exclude<T, V[number]>;
150
151
  })) => readonly string[];
151
- export declare const elementDeclaration: <A>() => <const D extends ElementDeclarationData>(declaration: D) => D & ElementAttributesBrand<A>;
152
+ /** What a built-in element writes in its declaration's `content`: what is its own — the rest is filled in. */
153
+ export interface ElementContentSpec {
154
+ attributes: Record<string, unknown>;
155
+ /** Left out: `type` (the declaration's), no bindings, visible, and the `base` style selector beside its own. */
156
+ definition: Omit<Partial<ElementDefinition>, 'type' | 'rootId' | 'parentId' | 'interactions' | 'runtime' | 'styleSelectors'> & {
157
+ label: string;
158
+ /** What the element is for, in a sentence: the builder shows it, and an agent reads it to choose the element. */
159
+ description?: string;
160
+ styleSelectors?: Record<string, string>;
161
+ };
162
+ /** Left out, every gesture, and children of any type. */
163
+ builder?: PluginBuilder;
164
+ /** Its place in the catalogue; the rest is Plitzi's own entry. */
165
+ market: {
166
+ category: string;
167
+ icon: string;
168
+ };
169
+ /** Left out: named by its label, for desktop. */
170
+ defaultStyle: {
171
+ name?: string;
172
+ displayMode?: DisplayMode;
173
+ style: StyleAttributes;
174
+ /** A style of its own for each `subType` — a heading's `h1`… — written whole. */
175
+ subTypes?: Record<string, {
176
+ name: string;
177
+ displayMode: DisplayMode;
178
+ style: StyleAttributes;
179
+ }>;
180
+ };
181
+ settings?: Record<string, string | number | boolean>;
182
+ }
183
+ /** What {@link elementDeclaration} takes: the declaration as written, `content` holding only what is the element's. */
184
+ export interface ElementDeclarationSpec extends Omit<ElementDeclarationData, 'content'> {
185
+ content: ElementContentSpec;
186
+ }
187
+ /** What {@link elementDeclaration} fills in, typed as the declaration then carries it. */
188
+ export interface ElementContentDefaults {
189
+ definition: {
190
+ type: string;
191
+ bindings: NonNullable<ElementDefinition['bindings']>;
192
+ initialState: Record<string, unknown>;
193
+ styleSelectors: Record<string, string> & {
194
+ base: string;
195
+ };
196
+ };
197
+ builder: Required<PluginBuilder>;
198
+ market: {
199
+ owner: string;
200
+ verified: boolean;
201
+ license: string;
202
+ website: string;
203
+ backgroundColor: string;
204
+ };
205
+ defaultStyle: {
206
+ name: string;
207
+ displayMode: DisplayMode;
208
+ };
209
+ settings: Record<string, string | number | boolean>;
210
+ }
211
+ /** A built-in element's whole declaration: what it wrote, what was filled in, and the attributes it accepts. */
212
+ export type DeclaredElement<D extends ElementDeclarationSpec, A> = D & {
213
+ content: ElementContentDefaults;
214
+ } & ElementAttributesBrand<A>;
215
+ /**
216
+ * A built-in element's declaration, written from what is its own — its type, words, attributes, style, place in the
217
+ * catalogue — with the rest at the defaults every element shares: the builder's gestures, Plitzi's catalogue entry,
218
+ * a visible element with no bindings, its style named by its label.
219
+ *
220
+ * Called twice, as {@link definePlugin} is: the first call takes the attributes the element accepts, the second the
221
+ * declaration.
222
+ */
223
+ export declare const elementDeclaration: <A>() => <const D extends ElementDeclarationSpec>(declaration: D) => DeclaredElement<D, A>;
224
+ /** An event a plugin fires, as {@link definePlugin} takes it: what a flow it starts reads (`preview`) — the rest derived. */
225
+ export type PluginTriggerSpec = {
226
+ /** Left out, the event's name in words: `onEdit` is "On Edit". */
227
+ title?: string;
228
+ /** What a flow started by it reads, `{ ops: '' }` — and so what the plugin hands it (`usePluginTrigger`). */
229
+ preview?: InteractionCallbackPreviews;
230
+ params?: InteractionCallback['params'];
231
+ };
232
+ /** An action a plugin answers, as {@link definePlugin} takes it: its params — the rest derived. */
233
+ export type PluginCallbackSpec = {
234
+ title?: string;
235
+ params?: InteractionCallback['params'];
236
+ };
237
+ type PluginContent<A extends object> = PluginDeclaration<A>['content'];
238
+ /** What a plugin is, said once: {@link definePlugin} writes the rest of its declaration from it. */
239
+ export interface PluginSpec<A extends object, T extends Record<string, PluginTriggerSpec>, C extends Record<string, PluginCallbackSpec>> extends Omit<ElementDeclarationData, 'type' | 'triggers' | 'callbacks' | 'content'> {
240
+ /** What a space names it by — the element type. Renaming it orphans every one. */
241
+ type: string;
242
+ /** What the builder's catalogue calls it. */
243
+ label: string;
244
+ /** What it is for, in a sentence: the builder shows it, and an agent reads it to choose the element. */
245
+ description?: string;
246
+ /** Its starting attributes: the component's defaults. */
247
+ attributes: A;
248
+ triggers?: T;
249
+ callbacks?: C;
250
+ /** What the builder lets a person do with it. Left out, every gesture, and no children. */
251
+ builder?: PluginBuilder;
252
+ /** How the catalogue shows it. Left out, under its label, by nobody, MIT. */
253
+ market?: Partial<PluginContent<A>['market']>;
254
+ /** The attributes a data source may be pointed at. Left out, every one. */
255
+ bindable?: readonly (keyof A & string)[];
256
+ /** Its style before anybody styles it. */
257
+ style?: PluginSchema['defaultStyle']['style'];
258
+ /** More of the element's definition — children it starts with (`items`), its style selectors. */
259
+ definition?: Partial<PluginContent<A>['definition']>;
260
+ settings?: PluginContent<A>['settings'];
261
+ }
262
+ /** A plugin's events and actions as its declaration carries them: each named by its key, its preview kept as written. */
263
+ export type DeclaredTriggers<T extends Record<string, PluginTriggerSpec>> = {
264
+ [K in keyof T & string]: Omit<InteractionCallback, 'action' | 'preview'> & {
265
+ action: K;
266
+ preview: T[K]['preview'] extends object ? T[K]['preview'] : Record<string, never>;
267
+ };
268
+ };
269
+ export type DeclaredCallbacks<C extends Record<string, PluginCallbackSpec>> = {
270
+ [K in keyof C & string]: Omit<InteractionCallback, 'action'> & {
271
+ action: K;
272
+ };
273
+ };
274
+ /** What {@link definePlugin} answers: the declaration, its events and actions named, and its attributes in its type. */
275
+ export type DefinedPlugin<A extends object, T extends Record<string, PluginTriggerSpec>, C extends Record<string, PluginCallbackSpec>> = Omit<PluginDeclaration<A>, 'triggers' | 'callbacks'> & {
276
+ triggers: DeclaredTriggers<T>;
277
+ callbacks: DeclaredCallbacks<C>;
278
+ } & ElementAttributesBrand<A>;
279
+ /**
280
+ * A plugin's declaration, written from what only it can say — its type, its words, its attributes, what it fires and
281
+ * answers — with everything else at the default every plugin shares: the builder's gestures, the catalogue entry, a
282
+ * bindable attribute for each one, an empty style.
283
+ *
284
+ * ```ts
285
+ * export default definePlugin<SeatPickerAttributes>()({
286
+ * type: 'seatPicker',
287
+ * label: 'Seat Picker',
288
+ * description: 'Picks a seat from a plan.',
289
+ * attributes: { start: 0, label: 'Seats' },
290
+ * triggers: { onPick: { preview: { seat: '' } } },
291
+ * callbacks: { reset: {} }
292
+ * });
293
+ * ```
294
+ *
295
+ * Called twice, as `elementDeclaration` is: the first call takes the attributes the element accepts (its component's
296
+ * props, minus what the runtime supplies), which TypeScript cannot read off defaults that leave some out; the second the
297
+ * rest, whose events it reads as written. The whole declaration comes back — what the build writes into the manifest
298
+ * and the builder reads — branded with the attributes, so `defineElement(declaration)` authors the element typed
299
+ * without being told.
300
+ */
301
+ export declare const definePlugin: <A extends object>() => <const T extends Record<string, PluginTriggerSpec> = never, const C extends Record<string, PluginCallbackSpec> = never>({ type, label, description, attributes, triggers, callbacks, builder, market, bindable, style, definition, settings, ...rest }: PluginSpec<A, T, C>) => DefinedPlugin<A, T, C>;
152
302
  export {};
@@ -1,4 +1,97 @@
1
1
  //#region src/authoring/declare.ts
2
- var e = () => (e) => e, t = () => (e) => e;
2
+ var e = () => (e) => e, t = () => ({
3
+ canDelete: !0,
4
+ canSelect: !0,
5
+ canDragDrop: !0,
6
+ canMove: !0,
7
+ canSnippet: !0,
8
+ itemsAllowed: [],
9
+ itemsNotAllowed: []
10
+ }), n = (e, t) => ({
11
+ type: e,
12
+ bindings: {},
13
+ initialState: { visibility: !0 },
14
+ ...t,
15
+ styleSelectors: {
16
+ base: "",
17
+ ...t.styleSelectors
18
+ }
19
+ }), r = () => (e) => {
20
+ let { definition: r, builder: i, market: a, defaultStyle: o, settings: s } = e.content;
21
+ return {
22
+ ...e,
23
+ content: {
24
+ ...e.content,
25
+ definition: n(e.type, r),
26
+ builder: {
27
+ ...t(),
28
+ ...i
29
+ },
30
+ market: {
31
+ owner: "Plitzi",
32
+ verified: !0,
33
+ license: "MIT",
34
+ website: "https://plitzi.com",
35
+ backgroundColor: "#4422ee",
36
+ ...a
37
+ },
38
+ defaultStyle: {
39
+ name: r.label,
40
+ displayMode: "desktop",
41
+ ...o
42
+ },
43
+ settings: s ?? {}
44
+ }
45
+ };
46
+ }, i = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (e) => e.toUpperCase()), a = () => ({ type: e, label: r, description: a, attributes: o, triggers: s, callbacks: c, builder: l, market: u, bindable: d, style: f, definition: p, settings: m, ...h }) => {
47
+ let g = (e, t, n) => ({
48
+ action: t,
49
+ title: n.title ?? i(t),
50
+ type: e,
51
+ params: n.params ?? {},
52
+ ...e === "trigger" ? { preview: n.preview ?? {} } : {}
53
+ }), _ = d ?? Object.keys(o);
54
+ return {
55
+ ...h,
56
+ type: e,
57
+ triggers: Object.fromEntries(Object.entries(s ?? {}).map(([e, t]) => [e, g("trigger", e, t)])),
58
+ callbacks: Object.fromEntries(Object.entries(c ?? {}).map(([e, t]) => [e, g("callback", e, t)])),
59
+ content: {
60
+ attributes: o,
61
+ definition: n(e, {
62
+ label: r,
63
+ ...a ? { description: a } : {},
64
+ items: [],
65
+ ...p
66
+ }),
67
+ builder: {
68
+ ...t(),
69
+ ...l
70
+ },
71
+ market: {
72
+ category: r,
73
+ owner: "",
74
+ license: "MIT",
75
+ website: "",
76
+ backgroundColor: "#4422ee",
77
+ icon: "",
78
+ ...u
79
+ },
80
+ defaultStyle: {
81
+ name: r,
82
+ displayMode: "desktop",
83
+ style: f ?? { base: { default: {} } },
84
+ bindingsAllowed: {
85
+ attributes: _.map((e) => ({
86
+ path: e,
87
+ label: i(e)
88
+ })),
89
+ initialState: []
90
+ }
91
+ },
92
+ settings: m ?? {}
93
+ }
94
+ };
95
+ };
3
96
  //#endregion
4
- export { t as elementDeclaration, e as valuesOf };
97
+ export { a as definePlugin, r as elementDeclaration, e as valuesOf };
@@ -1,6 +1,6 @@
1
1
  import { toBuilderParams as e, toInteractionCallback as t, toInteractionCallbacks as n } from "./builder.mjs";
2
- import { elementDeclaration as r, valuesOf as i } from "./declare.mjs";
3
- import { BUILTIN_PARAM_TYPES as a, hiddenParams as o, invalidParams as s, missingRequiredParams as c, reconcileParams as l } from "./paramSpec.mjs";
4
- import { BUILTIN_ELEMENT_CALLBACKS as u, SCROLL_CALLBACKS as d, applyElementCallback as f, getElementCallback as p } from "./elementCallbacks.mjs";
5
- import { spaceCallbacks as m } from "./spaceCallbacks.mjs";
6
- export { u as BUILTIN_ELEMENT_CALLBACKS, a as BUILTIN_PARAM_TYPES, d as SCROLL_CALLBACKS, f as applyElementCallback, r as elementDeclaration, p as getElementCallback, o as hiddenParams, s as invalidParams, c as missingRequiredParams, l as reconcileParams, m as spaceCallbacks, e as toBuilderParams, t as toInteractionCallback, n as toInteractionCallbacks, i as valuesOf };
2
+ import { definePlugin as r, elementDeclaration as i, valuesOf as a } from "./declare.mjs";
3
+ import { BUILTIN_PARAM_TYPES as o, hiddenParams as s, invalidParams as c, missingRequiredParams as l, reconcileParams as u } from "./paramSpec.mjs";
4
+ import { BUILTIN_ELEMENT_CALLBACKS as d, SCROLL_CALLBACKS as f, applyElementCallback as p, getElementCallback as m } from "./elementCallbacks.mjs";
5
+ import { spaceCallbacks as h } from "./spaceCallbacks.mjs";
6
+ export { d as BUILTIN_ELEMENT_CALLBACKS, o as BUILTIN_PARAM_TYPES, f as SCROLL_CALLBACKS, p as applyElementCallback, r as definePlugin, i as elementDeclaration, m as getElementCallback, s as hiddenParams, c as invalidParams, l as missingRequiredParams, u as reconcileParams, h as spaceCallbacks, e as toBuilderParams, t as toInteractionCallback, n as toInteractionCallbacks, a as valuesOf };
@@ -11,35 +11,35 @@ var c = (e, t, n, r, a) => {
11
11
  fromValue: t ? i(e, t) : void 0,
12
12
  toValue: i(n, o, t ? i(e, t) : void 0)
13
13
  };
14
- }, l = (l, u, d = {}) => {
15
- let { attributes: f, definition: p } = u, { bindings: m } = p;
16
- return !m || typeof m == "object" && !Object.keys(m).length ? {
17
- attributes: f,
14
+ }, l = (e) => typeof e == "number" || typeof e == "string" && !/[;{}<>]/.test(e), u = (u, d, f = {}) => {
15
+ let { attributes: p, definition: m } = d, { bindings: h } = m;
16
+ return !h || typeof h == "object" && !Object.keys(h).length ? {
17
+ attributes: p,
18
18
  style: {},
19
- definition: p
19
+ definition: m
20
20
  } : s({
21
- attributes: f,
22
- style: d,
23
- definition: p
21
+ attributes: p,
22
+ style: f,
23
+ definition: m
24
24
  }, (s) => {
25
- Object.keys(m).forEach((u) => {
26
- m[u] && Array.isArray(m[u]) && m[u].length && m[u].forEach((d) => {
27
- let { source: f, transformers: p, when: m, enabled: h = !0 } = d, { to: g } = d;
28
- if (!g || m && !o(m, l, !1, !0) || !h) return;
29
- u === "style" && (g = r(g));
30
- let { fromValue: _, toValue: v } = c(l, f, s, u, g), y = _;
31
- p && Array.isArray(p) && p.length > 0 && p.forEach((e) => {
25
+ Object.keys(h).forEach((d) => {
26
+ h[d] && Array.isArray(h[d]) && h[d].length && h[d].forEach((f) => {
27
+ let { source: p, transformers: m, when: h, enabled: g = !0 } = f, { to: _ } = f;
28
+ if (!_ || h && !o(h, u, !1, !0) || !g) return;
29
+ d === "style" && !_.startsWith("--") && (_ = r(_));
30
+ let { fromValue: v, toValue: y } = c(u, p, s, d, _), b = v;
31
+ m && Array.isArray(m) && m.length > 0 && m.forEach((e) => {
32
32
  let { action: r, params: i, enabled: a = !0 } = e;
33
33
  if (!a) return;
34
34
  let o = t[r];
35
- o && (y = o.callback(y, n(o, i) ?? {}, s, {
36
- ...l,
37
- sourceTo: v
35
+ o && (b = o.callback(b, n(o, i) ?? {}, s, {
36
+ ...u,
37
+ sourceTo: y
38
38
  }));
39
- }), u === "initialState" && g === "visibility" && f && i(l, f) !== void 0 && (y = e(y)), (typeof y == "boolean" || typeof y == "number" || y) && (u === "initialState" ? a(s, `definition.${u}.${g}`, y) : a(s, `${u}.${g}`, y));
39
+ }), d === "initialState" && _ === "visibility" && p && i(u, p) !== void 0 && (b = e(b)), (d !== "style" || l(b)) && (typeof b == "boolean" || typeof b == "number" || b) && (d === "initialState" ? a(s, `definition.${d}.${_}`, b) : a(s, `${d}.${_}`, b));
40
40
  });
41
41
  });
42
42
  });
43
43
  };
44
44
  //#endregion
45
- export { l as default };
45
+ export { u as default };