@plitzi/sdk-shared 0.38.8 → 0.38.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,148 @@
1
1
  # @plitzi/sdk-shared
2
2
 
3
+ ## 0.38.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 200da2f: - **`focus-on-field-box`** (`@plitzi/sdk-authoring`): a warning for a `focus` or `focus-visible` state on a text
8
+ field's or a select's `input` slot. That slot is the box the field is drawn in, a `<div>` that never takes focus, so
9
+ the rule was never seen and a keyboard user tabbing to the field found no ring. The fix it names: `'focus-within'` on
10
+ the same class, or the state on the `field` slot.
11
+ - **`modalContainer` says how it is laid out** (`@plitzi/sdk-elements`): its description now names its slots and how
12
+ they sit — the dim layer and the dialog side by side, not one inside the other; the dialog centred by `top`/`left`
13
+ 50% and a `translate`. A space styled the dim layer as a flex container to place the dialog, which moved nothing.
14
+ - **A field shows where the keyboard is** (`@plitzi/plitzi-sdk`, `@plitzi/sdk-elements`): a text field's or a select's
15
+ box is ringed (`2px solid currentColor`) while the field inside has keyboard focus, and a textarea while it has. No
16
+ text field or select showed any focus at all: the box had `outline: none`, and the field inherited it. One class of
17
+ specificity, so whatever a space writes about the outline wins; never in the builder's canvas, where the selection is
18
+ the ring. The field no longer inherits the box's outline — the box draws it.
19
+ - **The dim layer of a modal and a dialog is `rgb(0 0 0 / 50%)`** (`@plitzi/plitzi-sdk`, `@plitzi/sdk-elements`), not
20
+ black at `opacity: 0.5`: the default looks the same, and a colour a space gives the layer is drawn as it is — it was
21
+ halved. A space that set its own colour sees it darker: the one it wrote.
22
+ - **`required-message-unused`** (`@plitzi/sdk-authoring`): a warning for a `requiredMessage` on a field nothing requires —
23
+ since 0.38.9 a field is optional unless `required: true`, so the message is never shown and an empty answer is sent.
24
+ The formControl's description, the cheat sheet and the forms recipe say the default.
25
+ - **A page's title can say its record** (`@plitzi/sdk-shared`, `@plitzi/sdk-server`, `@plitzi/sdk-elements`,
26
+ `@plitzi/sdk-authoring`): `seoTitle` and `seoDescription` may be templates over the page's `runtime: 'server'`
27
+ providers (its layouts' too) and `navigation` — `'{{ apiContainer_post.title }} — Blog'`. The server evaluates them
28
+ as it writes the head, from the answers it already has; the browser evaluates the same over `rsc.data`, so the tab
29
+ follows a navigation from record to record. One that reads anything else — a browser provider, `state` — is refused
30
+ (`page-template`): it was written into the head as it was, braces included. A declaration's `serverTemplates` names
31
+ the attributes the page server evaluates against a context of its own (a page's title and description, a provider's
32
+ `notFound`): the element runtime leaves them as written — interpolated where the page renders, a `|default(…)`
33
+ resolved to its fallback before the head could read the providers — and the authoring lint reads the same list.
34
+ - **A page says when its address shows nothing** (`@plitzi/sdk-server`, `@plitzi/sdk-authoring`): `notFound` on the
35
+ page, one expression over the same answers its title reads — `"{{ not (apiContainer_feed.topics|find('slug',
36
+ navigation.routeParams.slug)) }}"` — sends it with status 404, rendered as written. A provider's own `notFound` reads
37
+ only its answer, and one in a layout is every page's: a record read from the layout had no way to say it was not
38
+ there, and the page answered 200.
39
+ - **The Export keeps the flows of a plugin hosted by `custom`** (`@plitzi/sdk-authoring`): `specFromSpace` judged such
40
+ an element by `custom`'s own triggers and callbacks, and dropped a flow on the component's event (`onChange` on an
41
+ editor) as one "a custom never fires" — the space read back was not the space written.
42
+ - **`page check` reads every word on the page, in the colour the browser paints it** (`@plitzi/sdk-authoring`): what a
43
+ plugin draws inside an element of the space is measured too, named by the element and a selector; the measure is
44
+ WCAG's contrast (under 2:1 is unreadable), not "nearly the same colour"; and a colour the browser answers as
45
+ `oklch()`, `oklab()` or `color(srgb …)` — every token and every `color-mix()` — is read as that, where it was read as
46
+ `rgb()` numbers and came out near black. A plugin's dark-on-dark status line passed as "nothing wrong".
47
+ - **`verify` checks every theme the space can be painted in** (`@plitzi/cli`): light and dark, unless the space says
48
+ light only — "48 checks at 1440 and 390 px, light and dark". A page unreadable in the dark theme passed in the light
49
+ one; a failure names the theme it was found in.
50
+ - **`plitzi upgrade` says where fields became optional** (`@plitzi/cli`): for a project last upgraded before 0.38.9,
51
+ each `formControl(…)` with no `required`, at its file and line — said, never written. And a `.gitkeep` is asked for
52
+ only in a folder with nothing else in it: `upgrade` wrote one beside code, and `doctor` called it missing once deleted
53
+ as AGENTS.md asks ("nothing unused") — the three now say the same.
54
+ - **`devMode` and `devReload` are the project's** (`@plitzi/sdk-server`): `src/config/serverOptions.ts` may set them,
55
+ over `NODE_ENV`, which they still follow when left out. A deployment started without `NODE_ENV` (a container's `CMD`)
56
+ says `devMode: false`, and a public action answers with its output alone.
57
+ - **`page shot --from load`** (`@plitzi/cli`): `--frames` start as soon as the page's HTML is in, not once it settles —
58
+ an entrance that plays while the page loads had ended before the first picture.
59
+ - **`heavy-animation` says where each animation is** (`@plitzi/sdk-authoring`): the class and its variant, state or
60
+ slot — or the `customCss` rule — and writes the fix against that selector. It said "in `customCss`" for an animation
61
+ declared on a class's variant, and offered `.glow`, a class no space has.
62
+ - **`page shot --steps`** (`@plitzi/cli`): an interaction played step by step — `click`, `type`, `press`, `wait`,
63
+ `wait-for`, `shot [label]`, `frames <n> [ms]`, separated by `;` or written in a file (`@file`) — each picture labelled
64
+ with its step and the time since the first, and said when nothing changed since the one before. A queue filling, a
65
+ restart, an opening frame by frame took a Playwright script of the project's own. Targets take Playwright's selectors
66
+ too (`text=Saved`).
67
+ - **A space's task may take a `number` param** (`@plitzi/sdk-server`): saved functions refused it ("a type the builder
68
+ cannot draw") while a project's server ran it, so code that worked self-hosted failed on the platform — and the
69
+ builder draws one, a callback's. A step's params now arrive as the types the task declares, on every server: a
70
+ `number` written as text is the number, a `boolean` written `'true'` is `true`, as the browser reads a callback's.
71
+ - **`page shot --as <username>`** (`@plitzi/cli`): signs in first, as `page check --as` does, the password from
72
+ `PLITZI_CHECK_PASSWORD` in `.env`. A page for signed-in visitors was pictured as the sign-in page it sent the browser
73
+ to, without a word; `page shot` now says when the page sent it elsewhere, and that the picture is of that page.
74
+ - **A capture is of the page at rest** (`@plitzi/sdk-mcp`): the local screenshot client takes every picture with
75
+ `prefers-reduced-motion: reduce`, as the browser pod now does — the declared motion and a space's own keyframes that
76
+ honour the query are shown finished. A splash still covering its page, or an arrival caught halfway, was what a
77
+ thumbnail or a `plitzi_look` showed of a page that animates as it loads.
78
+ - **The server renders in the visitor's theme, not only the class** (`@plitzi/sdk-shared`): `ThemeProvider` set the
79
+ starting theme from a layout effect, which never runs on a server, so a page was drawn from the theme store's own
80
+ start — `{{ theme.resolved }}` was `light` under a `<html class="dark">`, and whatever named the scheme (a picture's
81
+ address, a `when` rule) was swapped for the other one as the page hydrated. The theme a host supplies (the cookie) is
82
+ now the server's snapshot of the store, and the hydration's; the shared store is never written on the server.
83
+
84
+ ## 0.38.9
85
+
86
+ ### Patch Changes
87
+
88
+ - 64f4cd6: - **`unusedPort()`** (`@plitzi/sdk-server`): a port the system has just handed out, for a test to listen on. The
89
+ package's own tests and `@plitzi/sdk-mcp`'s listened on fixed ports in the ephemeral range (393xx), which any
90
+ outgoing connection of a test running beside them could take: CI failed with `EADDRINUSE` on runs with nothing
91
+ wrong. Every one now listens on a port the system gives it.
92
+ - **Brotli at quality 5** (`@plitzi/sdk-server`): `compression.brotliQuality`, for a page rendered for one request, is
93
+ 5 (was 2). At 2 a 220 KB page came out larger than gzip — 36 KB against 31 — and at 5 it is 29 KB, for the CPU gzip
94
+ spends; on half a core ~0.1 ms a page.
95
+ - **`verify` checks the pages for signed-in visitors** (`@plitzi/cli`): a page that sends the browser to sign in is
96
+ checked again signed in as the account `.env` names — `PLITZI_CHECK_USER`, `PLITZI_CHECK_PASSWORD` (the environment
97
+ wins over `.env`). With none named, `verify` says how. `page check --as` reads the password from `.env` too, and
98
+ `page check` takes several pages, in one browser.
99
+ - **An address that shows nothing answers 404** (`@plitzi/sdk-shared`, `@plitzi/plitzi-sdk`, `@plitzi/sdk-server`):
100
+ one no page answers was sent to the home page with a 302 — every typo read as the home page. A page whose slug is
101
+ `'*'` is now the space's page for it, sent with status 404 (a folder may have its own; the deepest wins), and a page
102
+ gated off by a flag shows it too. Never kept in the page cache: an address asked for at random filled it. Only a slug
103
+ that IS `'*'`: a page answering a subtree by its own (`spaces/:spaceId/update/*`) stays a page like any other.
104
+ - **`authorSpace` gives a space with no `'*'` page a plain one** (`@plitzi/sdk-authoring`), in the home page's layout,
105
+ and says so: suggestion `not-found-page`. The project templates carry their own.
106
+ - **`notFound` on a server provider** (`@plitzi/sdk-elements`, `@plitzi/sdk-server`): an expression against its answer
107
+ (`{{ source.found == false }}`); when it is true the page is sent with status 404, rendered as written. Refused on a
108
+ browser provider (`not-found-in-browser`) and when it is not one expression (`not-found-not-a-template`).
109
+ - **`page check` and `verify` know a page sent with 404** (`@plitzi/cli`): it is said, not failed; the space's `'*'`
110
+ page is checked at an address no page has, and fails if it is not sent with 404.
111
+ - **A form field draws no background of its own** (`@plitzi/sdk-elements`): the `<input>` inside a form control's box
112
+ (`field`) took `background-color: inherit`, and painted a translucent box colour a second time — a darker box inside
113
+ the padding (Tremor's search). It is `transparent`: the box shows through it.
114
+ - **`space lint` offers `quiet` only where there is an element to put it on** (`@plitzi/cli`): a suggestion about what
115
+ the space lacks — `not-found-page` — is answered by writing it.
116
+ - **`feedback --previous`** (`@plitzi/cli`): the brief says what to do when an earlier report's link no longer opens —
117
+ say so, and ask the person for the highest id it had.
118
+ - **`start:prod` runs in production by itself** (`@plitzi/cli`): `NODE_ENV=production node …`. Without the variable a
119
+ deployed project was a development server — dev tools on, and every public action answering its `steps` and `trace`
120
+ (each step's result, what the `output` was meant to leave out). `doctor` says a `start:prod` that does not
121
+ (`start-prod-not-production`); `plitzi upgrade --write` rewrites the script.
122
+ - **A project's `ActionRefusal` reaches the flow** (`@plitzi/sdk-server`): a functions bundle carries its own copy of the
123
+ class, so `instanceof` never knew it and the run lost its reason (`{{ x.error }}` empty). Told apart by name now.
124
+ - **Plugins are not remounted after hydration** (`@plitzi/sdk-elements`): the registry wrapped each plugin again when
125
+ the host handed it over again, a new component type every time — the server's HTML thrown away, entrances replayed,
126
+ effects run twice. Each plugin component is wrapped once.
127
+ - **`start:dev` survives a space that does not author** (`@plitzi/sdk-server`): a restart while the space had an error
128
+ died, and fixing the space woke nothing. It comes up answering every page with what is wrong (503), and loads the
129
+ space the first time a save authors.
130
+ - **`page check` sees what is cut off at the screen's edge** (`@plitzi/sdk-authoring`, `@plitzi/cli`): a link or words an
131
+ ancestor hides past the viewport, which no sideways scroll shows (`cut-off`).
132
+ - **`page shot --click <element...> --sheet`** (`@plitzi/cli`): elements clicked in order — a name or a CSS selector,
133
+ inside a plugin too — pictured after each (`--frames`/`--every`), with how much changed, and every picture on one
134
+ contact sheet. The dev tools' badge is no longer in a picture: its shadow root is marked (`@plitzi/sdk-dev-tools`).
135
+ - **`formControl` is optional unless it says `required: true`** (`@plitzi/sdk-elements`), as an HTML field is. A field
136
+ left without `required` in an older space was required, and is not now.
137
+ - **`text({ decorative })`, `list({ label })`** (`@plitzi/sdk-elements`); **`writing-mode`, `text-orientation`** in the
138
+ CSS vocabulary (`@plitzi/sdk-shared`).
139
+ - **`unused-token` reads the plugins' stylesheets** (`@plitzi/sdk-authoring`): `authorSpace`'s `stylesheets`, which
140
+ `projectAuthoring` fills with every `.css` under `src/plugins/` — a token only a plugin used was said to be unused.
141
+ - **`id-taken` on a provider placed on two pages points at the layout they share** (`@plitzi/sdk-authoring`), not at
142
+ `scope()`, which renamed its source and every template reading it.
143
+ - **The welcome template's tokens keep their names** (`@plitzi/sdk-authoring`): `satisfies`, not an annotation, so
144
+ `tokens(variables).card` typechecks as the cheatsheet teaches.
145
+
3
146
  ## 0.38.8
4
147
 
5
148
  ### Patch Changes
@@ -67,6 +67,14 @@ export interface ElementDeclarationData {
67
67
  * `plitzi page check`), which would otherwise wait for it to be on screen and report it hidden.
68
68
  */
69
69
  drawsNothing?: boolean;
70
+ /**
71
+ * The attributes the page server evaluates against a context of its own, never where the element renders: a
72
+ * provider's `notFound`, read against its answer; a page's title and description, read against its server providers.
73
+ * Interpolated in the element's own scope they resolved to nothing — a `|default(…)` to its fallback — before the
74
+ * reader that has their names could see them. Read by the element runtime, which leaves them as written, and by the
75
+ * authoring lint, which holds them to that context.
76
+ */
77
+ serverTemplates?: readonly string[];
70
78
  content?: {
71
79
  attributes?: Record<string, unknown>;
72
80
  definition?: {
package/dist/index.mjs CHANGED
@@ -70,27 +70,27 @@ import jn from "./schema/SchemaContext.mjs";
70
70
  import { ANCHOR_PATTERN as Mn, anchorOf as Nn, isAnchor as Pn, uniqueAnchor as Fn } from "./schema/anchor.mjs";
71
71
  import { COMPONENT_PROPS_SOURCE as In, EMPTY_SCHEMA as Ln, VARIABLE_REGEX as Rn } from "./schema/schemaConstants.mjs";
72
72
  import { findLayoutCycle as zn, resolveLayoutChain as Bn } from "./schema/layoutChain.mjs";
73
- import { collectServerElements as Vn, hasServerElements as Hn } from "./schema/serverElements.mjs";
74
- import { isSnippet as Un } from "./schema/snippet.mjs";
75
- import Wn from "./network/NetworkContext.mjs";
76
- import Gn from "./network/NetworkInternalContext.mjs";
77
- import { elementFromWire as Kn, schemaFromWire as qn, schemaToWire as Jn } from "./schema/wire.mjs";
78
- import { SpaceEvents as Yn, spaceEventSchemas as Xn, validateSpaceEvent as Zn } from "./network/spaceEvents.mjs";
79
- import Qn from "./network/graphql/builder/Mutations/index.mjs";
80
- import $n from "./network/graphql/builder/Queries/index.mjs";
81
- import er from "./network/graphql/builder/Subscriptions/index.mjs";
82
- import tr from "./network/graphql/sdk/Mutations/index.mjs";
83
- import nr from "./network/graphql/sdk/Queries/index.mjs";
84
- import rr, { RTEvent as ir, RTEventCloseCode as ar, getInstance as or, isRTEvent as sr, isRTEventCloseCode as cr, setInstance as lr } from "./websockets/RTCodec.mjs";
85
- import { THEME_CLASSES as ur, THEME_COOKIE_NAME as dr, applyThemeClass as fr, isTheme as pr, readThemeCookie as mr, themeFromCookies as hr, writeThemeCookie as gr } from "./theme/themeCookie.mjs";
86
- import _r, { createThemeState as vr, createThemeStore as yr, resolveScheme as br, setAreaTheme as xr, setMachineScheme as Sr, setThemeMode as Cr, themeFor as wr } from "./theme/themeStore.mjs";
87
- import { useThemeStore as Tr } from "./theme/ThemeScope.mjs";
88
- import Er from "./theme/ThemeProvider.mjs";
89
- import Dr, { SPACE_THEME_AREA as Or } from "./theme/useTheme.mjs";
90
- import kr from "./server/actions/useActionsSync.mjs";
91
- import Ar, { cancelRsc as jr, currentRscLocation as Mr, releaseRscRequests as Nr, rscDataPath as Pr } from "./server/rsc/refreshRsc.mjs";
92
- import Fr from "./server/rsc/useRscRefresh.mjs";
93
- import Ir from "./server/rsc/useRscSync.mjs";
94
- import { PAINTED_STATE_BUDGET as Lr, clearPaintedEntry as Rr, paintedEntryFromCookies as zr, paintedKeys as Br, paintedStateCookieName as Vr, paintedStateFor as Hr, pickPainted as Ur, readPaintedEntry as Wr, writePaintedEntry as Gr } from "./state/paintedState.mjs";
95
- import { runtimeStatePersist as Kr, stateOwner as qr } from "./state/runtimeStatePersist.mjs";
96
- export { Mn as ANCHOR_PATTERN, x as BODYLESS_METHODS, y as BuilderContext, Qn as BuilderMutations, $n as BuilderQueries, In as COMPONENT_PROPS_SOURCE, N as COMPUTED_GLOBALS, S as CONNECTOR_HTTP_METHODS, an as CONTENT_PSEUDOS, mn as CURRENT_SELECTOR, Me as ComponentContext, C as DEFAULT_READ_ENDPOINT, Te as DEV_TOOLS_ATTRIBUTE, St as DISPLAY_MODES, gt as DISPLAY_MODE_MIN_WIDTH, we as DevToolsContext, w as EMPTY_RESPONSE_METHODS, Ln as EMPTY_SCHEMA, ft as EMPTY_STYLE_SCHEMA, hn as EXPANDED_SELECTOR, Ne as FLAG_GATE_PATTERN, Ue as FLAG_LAYERS, Pe as FLAG_NAME_PATTERN, Ft as FontValidationError, on as GENERATED_PSEUDOS, P as GLOBAL_SOURCES, gn as HIDDEN_CLASS, Ee as HIDE_DEV_TOOLS_CSS, ee as INTERVAL_TRIGGER, zt as LAYOUT_GRIDS, m as MAX_PARAM_PASSES, te as MIN_INTERVAL_MS, Yt as MOTION_CONDITIONS, Wn as NetworkContext, Gn as NetworkInternalContext, Lr as PAINTED_STATE_BUDGET, _n as PARENT_ANCESTOR, yt as PLUGIN_CSS_LAYER, sn as PSEUDO_PROPERTIES, oe as ParamsFromURL, ke as PlitziConsole, ot as PlitziServiceContext, st as PlitziServiceProvider, T as READ_ENDPOINT_NAMES, rr as RTCodec, ir as RTEvent, ar as RTEventCloseCode, bt as RUNTIME_CSS_LAYER, Ht as RUNTIME_STYLE_ID, Or as SPACE_THEME_AREA, Xt as STYLE_CONDITION_LABELS, Zt as STYLE_MOTION_CONDITIONS, cn as STYLE_PSEUDOS, ln as STYLE_PSEUDO_LABELS, vn as STYLE_STATES, yn as STYLE_STATE_LABELS, Tt as SYSTEM_FONTS, jn as SchemaContext, tr as SdkMutations, nr as SdkQueries, er as SpaceEventSubscription, Yn as SpaceEvents, pt as StyleBindingsAllowed, lt as StyleVariableCategory, ur as THEME_CLASSES, dr as THEME_COOKIE_NAME, Er as ThemeProvider, Rn as VARIABLE_REGEX, a as VISITOR_NAME, ct as WHILE_RUNNING_MODES, E as WRITE_ENDPOINT_NAMES, Nn as anchorOf, fr as applyThemeClass, t as authFailureFromResponse, Et as availableFonts, mt as baseDefaultValue, jr as cancelRsc, Qt as canonicalCondition, o as checkVisitorRoles, Rr as clearPaintedEntry, Vn as collectServerElements, $t as conditionAtRule, en as conditionLabel, tn as conditionOfAtRule, k as connectorPresets, D as connectorTokens, b as contexts, B as cookieFromHeader, Ae as createStoreDevToolsLogger, vr as createThemeState, yr as createThemeStore, Mr as currentRscLocation, De as debugCookieName, se as delay, Xe as describeChange, $e as diffSchema, et as diffStyle, he as disableReactDevTools, _t as displayModeAt, vt as displayModeWidthRem, V as documentCookies, Kn as elementFromWire, H as elementOf, A as emptyManifest, ce as emptyObject, F as evaluateComputed, ae as evaluateRuleGroup, Lt as fallbackForFamily, Dt as familiesInCss, L as fetchManifest, Ze as fieldChanges, c as filters, zn as findLayoutCycle, We as flagUserFromSSR, Ge as flagValues, Le as flagsCookieName, Ot as fontFamilyStack, wt as fontLinkAssets, kt as fontUrlResolver, Rt as fontsFromCss, At as fontsToHead, Re as forcedFlagsFromCookies, K as formatDate, q as formatDateUTC, J as formatFromNow, Y as formatUTCToLocal, R as generateFacade, ve as getBindingsDetails, O as getConnectorTokens, le as getDisplayName, X as getDurationMs, or as getInstance, ue as getKeyDecoded, de as getPathsFromObeject, ye as getSourceName, jt as googleCss2Url, Mt as googleTextSubsetUrl, Ke as hasConditions, Hn as hasServerElements, f as hasTemplateSyntax, p as hasValidToken, fe as hexToRGB, bn as inCascadeOrder, xt as inPluginLayer, ht as inheritableAttributesBase, g as inspectTemplate, ne as intervalOf, Pn as isAnchor, j as isConnectorManifestDraft, un as isContentValue, re as isDate, Ct as isDisplayMode, U as isElementTarget, Fe as isFlagName, pe as isInViewport, Oe as isInteractionFlow, xn as isKnownState, W as isNodeTarget, Sn as isParentAncestor, sr as isRTEvent, cr as isRTEventCloseCode, e as isRecord, Nt as isSafeFontUrl, Ie as isSchemaFlag, Un as isSnippet, Cn as isStartingState, nn as isStyleCondition, dn as isStylePseudo, Tn as isStyleRules, ut as isStyleVariableCategory, pr as isTheme, ie as isUserEdit, Z as isValidFormat, tt as jsonCopy, Bt as layoutGridCss, Vt as layoutGridLook, I as liveSources, me as makeId, Ut as markStyleCache, Kt as mergeSnippetStyle, G as nodeOf, n as onAuthFailure, je as pConsole, zr as paintedEntryFromCookies, Br as paintedKeys, Vr as paintedStateCookieName, Hr as paintedStateFor, rn as parseContainerCondition, Q as parseDate, ze as parseFlagList, It as parseSpaceFont, qe as passesFlagGate, Ur as pickPainted, Pt as primaryFamily, l as processTwig, u as processTwigParam, d as processTwigValue, fn as pseudoHonours, pn as pseudoSuffix, Wr as readPaintedEntry, mr as readThemeCookie, Ar as refreshRsc, Nr as releaseRscRequests, r as reportAuthFailure, Je as resolveFlags, Bn as resolveLayoutChain, br as resolveScheme, h as resolveStepParam, Se as resolveVariables, Pr as rscDataPath, Kr as runtimeStatePersist, i as sameRegistrableDomain, qt as sameSelector, nt as sameValue, qn as schemaFromWire, Jn as schemaToWire, Jt as selectorsOf, Be as serializeFlagList, xr as setAreaTheme, En as setAtKeys, lr as setInstance, Sr as setMachineScheme, Cr as setThemeMode, Xn as spaceEventSchemas, qr as stateOwner, wn as stateSuffix, Wt as styleCacheFromDocument, Gt as styleCacheTravelsInDocument, dt as styleConstants, Dn as styleTargetKeys, On as styleTargetProblem, kn as styleTargetRules, z as syntaxHighlight, _ as templatePaths, v as templateRootNames, wr as themeFor, hr as themeFromCookies, _r as themeStore, $ as toUnixSeconds, Ye as undeclaredFlagOverrides, Fn as uniqueAnchor, Qe as uniqueLines, kr as useActionsSync, rt as useFontHead, it as useNetwork, at as usePlitziServiceContext, be as useRegisterSource, Ce as useResolvedVariables, Fr as useRscRefresh, Ir as useRscSync, xe as useStableValue, Dr as useTheme, Tr as useThemeStore, ge as utility, _e as utilityOptions, M as validateConnectorManifest, Zn as validateSpaceEvent, An as valueAtKeys, s as visitorAccess, Ve as withForcedFlag, He as writeForcedFlags, Gr as writePaintedEntry, gr as writeThemeCookie };
73
+ import { collectServerElements as Vn, hasServerElements as Hn, notFoundProvider as Un, pageNotFound as Wn, pageSeoText as Gn, pageServerContext as Kn } from "./schema/serverElements.mjs";
74
+ import { isSnippet as qn } from "./schema/snippet.mjs";
75
+ import Jn from "./network/NetworkContext.mjs";
76
+ import Yn from "./network/NetworkInternalContext.mjs";
77
+ import { elementFromWire as Xn, schemaFromWire as Zn, schemaToWire as Qn } from "./schema/wire.mjs";
78
+ import { SpaceEvents as $n, spaceEventSchemas as er, validateSpaceEvent as tr } from "./network/spaceEvents.mjs";
79
+ import nr from "./network/graphql/builder/Mutations/index.mjs";
80
+ import rr from "./network/graphql/builder/Queries/index.mjs";
81
+ import ir from "./network/graphql/builder/Subscriptions/index.mjs";
82
+ import ar from "./network/graphql/sdk/Mutations/index.mjs";
83
+ import or from "./network/graphql/sdk/Queries/index.mjs";
84
+ import sr, { RTEvent as cr, RTEventCloseCode as lr, getInstance as ur, isRTEvent as dr, isRTEventCloseCode as fr, setInstance as pr } from "./websockets/RTCodec.mjs";
85
+ import { THEME_CLASSES as mr, THEME_COOKIE_NAME as hr, applyThemeClass as gr, isTheme as _r, readThemeCookie as vr, themeFromCookies as yr, writeThemeCookie as br } from "./theme/themeCookie.mjs";
86
+ import xr, { createThemeState as Sr, createThemeStore as Cr, resolveScheme as wr, setAreaTheme as Tr, setMachineScheme as Er, setThemeMode as Dr, startingThemeState as Or, themeFor as kr } from "./theme/themeStore.mjs";
87
+ import { ThemeStartContext as Ar, useThemeState as jr, useThemeStore as Mr } from "./theme/ThemeScope.mjs";
88
+ import Nr from "./theme/ThemeProvider.mjs";
89
+ import Pr, { SPACE_THEME_AREA as Fr } from "./theme/useTheme.mjs";
90
+ import Ir from "./server/actions/useActionsSync.mjs";
91
+ import Lr, { cancelRsc as Rr, currentRscLocation as zr, releaseRscRequests as Br, rscDataPath as Vr } from "./server/rsc/refreshRsc.mjs";
92
+ import Hr from "./server/rsc/useRscRefresh.mjs";
93
+ import Ur from "./server/rsc/useRscSync.mjs";
94
+ import { PAINTED_STATE_BUDGET as Wr, clearPaintedEntry as Gr, paintedEntryFromCookies as Kr, paintedKeys as qr, paintedStateCookieName as Jr, paintedStateFor as Yr, pickPainted as Xr, readPaintedEntry as Zr, writePaintedEntry as Qr } from "./state/paintedState.mjs";
95
+ import { runtimeStatePersist as $r, stateOwner as ei } from "./state/runtimeStatePersist.mjs";
96
+ export { Mn as ANCHOR_PATTERN, x as BODYLESS_METHODS, y as BuilderContext, nr as BuilderMutations, rr as BuilderQueries, In as COMPONENT_PROPS_SOURCE, N as COMPUTED_GLOBALS, S as CONNECTOR_HTTP_METHODS, an as CONTENT_PSEUDOS, mn as CURRENT_SELECTOR, Me as ComponentContext, C as DEFAULT_READ_ENDPOINT, Te as DEV_TOOLS_ATTRIBUTE, St as DISPLAY_MODES, gt as DISPLAY_MODE_MIN_WIDTH, we as DevToolsContext, w as EMPTY_RESPONSE_METHODS, Ln as EMPTY_SCHEMA, ft as EMPTY_STYLE_SCHEMA, hn as EXPANDED_SELECTOR, Ne as FLAG_GATE_PATTERN, Ue as FLAG_LAYERS, Pe as FLAG_NAME_PATTERN, Ft as FontValidationError, on as GENERATED_PSEUDOS, P as GLOBAL_SOURCES, gn as HIDDEN_CLASS, Ee as HIDE_DEV_TOOLS_CSS, ee as INTERVAL_TRIGGER, zt as LAYOUT_GRIDS, m as MAX_PARAM_PASSES, te as MIN_INTERVAL_MS, Yt as MOTION_CONDITIONS, Jn as NetworkContext, Yn as NetworkInternalContext, Wr as PAINTED_STATE_BUDGET, _n as PARENT_ANCESTOR, yt as PLUGIN_CSS_LAYER, sn as PSEUDO_PROPERTIES, oe as ParamsFromURL, ke as PlitziConsole, ot as PlitziServiceContext, st as PlitziServiceProvider, T as READ_ENDPOINT_NAMES, sr as RTCodec, cr as RTEvent, lr as RTEventCloseCode, bt as RUNTIME_CSS_LAYER, Ht as RUNTIME_STYLE_ID, Fr as SPACE_THEME_AREA, Xt as STYLE_CONDITION_LABELS, Zt as STYLE_MOTION_CONDITIONS, cn as STYLE_PSEUDOS, ln as STYLE_PSEUDO_LABELS, vn as STYLE_STATES, yn as STYLE_STATE_LABELS, Tt as SYSTEM_FONTS, jn as SchemaContext, ar as SdkMutations, or as SdkQueries, ir as SpaceEventSubscription, $n as SpaceEvents, pt as StyleBindingsAllowed, lt as StyleVariableCategory, mr as THEME_CLASSES, hr as THEME_COOKIE_NAME, Nr as ThemeProvider, Ar as ThemeStartContext, Rn as VARIABLE_REGEX, a as VISITOR_NAME, ct as WHILE_RUNNING_MODES, E as WRITE_ENDPOINT_NAMES, Nn as anchorOf, gr as applyThemeClass, t as authFailureFromResponse, Et as availableFonts, mt as baseDefaultValue, Rr as cancelRsc, Qt as canonicalCondition, o as checkVisitorRoles, Gr as clearPaintedEntry, Vn as collectServerElements, $t as conditionAtRule, en as conditionLabel, tn as conditionOfAtRule, k as connectorPresets, D as connectorTokens, b as contexts, B as cookieFromHeader, Ae as createStoreDevToolsLogger, Sr as createThemeState, Cr as createThemeStore, zr as currentRscLocation, De as debugCookieName, se as delay, Xe as describeChange, $e as diffSchema, et as diffStyle, he as disableReactDevTools, _t as displayModeAt, vt as displayModeWidthRem, V as documentCookies, Xn as elementFromWire, H as elementOf, A as emptyManifest, ce as emptyObject, F as evaluateComputed, ae as evaluateRuleGroup, Lt as fallbackForFamily, Dt as familiesInCss, L as fetchManifest, Ze as fieldChanges, c as filters, zn as findLayoutCycle, We as flagUserFromSSR, Ge as flagValues, Le as flagsCookieName, Ot as fontFamilyStack, wt as fontLinkAssets, kt as fontUrlResolver, Rt as fontsFromCss, At as fontsToHead, Re as forcedFlagsFromCookies, K as formatDate, q as formatDateUTC, J as formatFromNow, Y as formatUTCToLocal, R as generateFacade, ve as getBindingsDetails, O as getConnectorTokens, le as getDisplayName, X as getDurationMs, ur as getInstance, ue as getKeyDecoded, de as getPathsFromObeject, ye as getSourceName, jt as googleCss2Url, Mt as googleTextSubsetUrl, Ke as hasConditions, Hn as hasServerElements, f as hasTemplateSyntax, p as hasValidToken, fe as hexToRGB, bn as inCascadeOrder, xt as inPluginLayer, ht as inheritableAttributesBase, g as inspectTemplate, ne as intervalOf, Pn as isAnchor, j as isConnectorManifestDraft, un as isContentValue, re as isDate, Ct as isDisplayMode, U as isElementTarget, Fe as isFlagName, pe as isInViewport, Oe as isInteractionFlow, xn as isKnownState, W as isNodeTarget, Sn as isParentAncestor, dr as isRTEvent, fr as isRTEventCloseCode, e as isRecord, Nt as isSafeFontUrl, Ie as isSchemaFlag, qn as isSnippet, Cn as isStartingState, nn as isStyleCondition, dn as isStylePseudo, Tn as isStyleRules, ut as isStyleVariableCategory, _r as isTheme, ie as isUserEdit, Z as isValidFormat, tt as jsonCopy, Bt as layoutGridCss, Vt as layoutGridLook, I as liveSources, me as makeId, Ut as markStyleCache, Kt as mergeSnippetStyle, G as nodeOf, Un as notFoundProvider, n as onAuthFailure, je as pConsole, Wn as pageNotFound, Gn as pageSeoText, Kn as pageServerContext, Kr as paintedEntryFromCookies, qr as paintedKeys, Jr as paintedStateCookieName, Yr as paintedStateFor, rn as parseContainerCondition, Q as parseDate, ze as parseFlagList, It as parseSpaceFont, qe as passesFlagGate, Xr as pickPainted, Pt as primaryFamily, l as processTwig, u as processTwigParam, d as processTwigValue, fn as pseudoHonours, pn as pseudoSuffix, Zr as readPaintedEntry, vr as readThemeCookie, Lr as refreshRsc, Br as releaseRscRequests, r as reportAuthFailure, Je as resolveFlags, Bn as resolveLayoutChain, wr as resolveScheme, h as resolveStepParam, Se as resolveVariables, Vr as rscDataPath, $r as runtimeStatePersist, i as sameRegistrableDomain, qt as sameSelector, nt as sameValue, Zn as schemaFromWire, Qn as schemaToWire, Jt as selectorsOf, Be as serializeFlagList, Tr as setAreaTheme, En as setAtKeys, pr as setInstance, Er as setMachineScheme, Dr as setThemeMode, er as spaceEventSchemas, Or as startingThemeState, ei as stateOwner, wn as stateSuffix, Wt as styleCacheFromDocument, Gt as styleCacheTravelsInDocument, dt as styleConstants, Dn as styleTargetKeys, On as styleTargetProblem, kn as styleTargetRules, z as syntaxHighlight, _ as templatePaths, v as templateRootNames, kr as themeFor, yr as themeFromCookies, xr as themeStore, $ as toUnixSeconds, Ye as undeclaredFlagOverrides, Fn as uniqueAnchor, Qe as uniqueLines, Ir as useActionsSync, rt as useFontHead, it as useNetwork, at as usePlitziServiceContext, be as useRegisterSource, Ce as useResolvedVariables, Hr as useRscRefresh, Ur as useRscSync, xe as useStableValue, Pr as useTheme, jr as useThemeState, Mr as useThemeStore, ge as utility, _e as utilityOptions, M as validateConnectorManifest, tr as validateSpaceEvent, An as valueAtKeys, s as visitorAccess, Ve as withForcedFlag, He as writeForcedFlags, Qr as writePaintedEntry, br as writeThemeCookie };
@@ -1,4 +1,4 @@
1
1
  export { matchPath } from './matchPath';
2
- export { getPageFullPath, getPaths, isAbsoluteUrl, isPageAuthored, matchRoutePath, getRouteParams, getSlugParams, navigationTarget } from './routes';
2
+ export { getPageFullPath, getPaths, isAbsoluteUrl, isPageAuthored, matchRoutePath, notFoundPageFor, getRouteParams, getSlugParams, navigationTarget, NOT_FOUND_SLUG } from './routes';
3
3
  export type { PathMatch, PathPattern } from './matchPath';
4
4
  export type { NavigationAccessLevel, NavigationAction, Path } from './routes';
@@ -1,3 +1,3 @@
1
1
  import { matchPath as e } from "./matchPath.mjs";
2
- import { getPageFullPath as t, getPaths as n, getRouteParams as r, getSlugParams as i, isAbsoluteUrl as a, isPageAuthored as o, matchRoutePath as s, navigationTarget as c } from "./routes.mjs";
3
- export { t as getPageFullPath, n as getPaths, r as getRouteParams, i as getSlugParams, a as isAbsoluteUrl, o as isPageAuthored, e as matchPath, s as matchRoutePath, c as navigationTarget };
2
+ import { NOT_FOUND_SLUG as t, getPageFullPath as n, getPaths as r, getRouteParams as i, getSlugParams as a, isAbsoluteUrl as o, isPageAuthored as s, matchRoutePath as c, navigationTarget as l, notFoundPageFor as u } from "./routes.mjs";
3
+ export { t as NOT_FOUND_SLUG, n as getPageFullPath, r as getPaths, i as getRouteParams, a as getSlugParams, o as isAbsoluteUrl, s as isPageAuthored, e as matchPath, c as matchRoutePath, l as navigationTarget, u as notFoundPageFor };
@@ -11,6 +11,12 @@ export type Path = {
11
11
  path: string;
12
12
  unauthorizedBehaviour?: NavigationAction;
13
13
  unauthorizedPageRedirect?: string;
14
+ /**
15
+ * A path of the space's "not found" page — a page whose slug is `*`, the page of every address under its folder that
16
+ * no other page answers — sent with status 404. Not every path ending in `*`: `update/*` is a page of its own that
17
+ * answers a whole subtree.
18
+ */
19
+ notFound?: true;
14
20
  };
15
21
  /**
16
22
  * Does this name another origin, rather than somewhere in this space?
@@ -20,6 +26,8 @@ export type Path = {
20
26
  * external would turn a typo into an off-site redirect.
21
27
  */
22
28
  export declare const isAbsoluteUrl: (url: string) => boolean;
29
+ /** The slug of the space's "not found" page: the page of every address under its folder that no other page answers. */
30
+ export declare const NOT_FOUND_SLUG = "*";
23
31
  declare function getPageFullPath(pages: Record<string, Element>, pageFolders: PageFolder[], pageId: string, asString: true): string;
24
32
  declare function getPageFullPath(pages: Record<string, Element>, pageFolders: PageFolder[], pageId: string, asString?: false): Record<string, string>;
25
33
  /**
@@ -31,7 +39,7 @@ declare function getPageFullPath(pages: Record<string, Element>, pageFolders: Pa
31
39
  */
32
40
  declare const navigationTarget: (pages: Record<string, Element>, pageFolders: PageFolder[], target: string) => string;
33
41
  declare const isPageAuthored: (accessLevel?: NavigationAccessLevel, authenticated?: boolean, previewMode?: boolean) => boolean;
34
- declare const getPaths: (pages?: Record<string, Element>, pageFolders?: PageFolder[], authenticated?: boolean, basePath?: string, previewMode?: boolean, strictMode?: boolean) => Path[];
42
+ declare const getPaths: (pages?: Record<string, Element>, pageFolders?: PageFolder[], authenticated?: boolean, basePath?: string, previewMode?: boolean) => Path[];
35
43
  declare const matchRoutePath: (paths: Path[], pathName: string, authenticated: boolean) => {
36
44
  action: {
37
45
  type: "authenticated" | "accessDenied" | "redirect" | "notFound" | "normal";
@@ -40,7 +48,9 @@ declare const matchRoutePath: (paths: Path[], pathName: string, authenticated: b
40
48
  pathMatch?: PathMatch;
41
49
  pageId?: string;
42
50
  };
51
+ /** The space's "not found" page for an address — its deepest folder's, or the space's — when it declares one. */
52
+ declare const notFoundPageFor: (paths: Path[], pathName: string) => string | undefined;
43
53
  declare const getRouteParams: (path: string) => string[];
44
54
  /** The params a page's slug declares, in either spelling a slug accepts: `post/{{slug}}` and `:spaceId/update`. */
45
55
  declare const getSlugParams: (slug: string) => string[];
46
- export { getPageFullPath, getPaths, matchRoutePath, isPageAuthored, getRouteParams, getSlugParams, navigationTarget };
56
+ export { getPageFullPath, getPaths, matchRoutePath, notFoundPageFor, isPageAuthored, getRouteParams, getSlugParams, navigationTarget };
@@ -1,76 +1,63 @@
1
1
  import { matchPath as e } from "./matchPath.mjs";
2
2
  //#region src/navigation/routes.ts
3
- var t = (e) => /^https?:\/\//i.test(e), n = (e) => t(e) || e.includes("{{"), r = (e) => e.replaceAll(/\/+/g, "/"), i = (e) => r(e.replace(/{{([a-zA-Z0-9-_:*/]+)}}/gi, ":$1")), a = (e, t) => {
3
+ var t = (e) => /^https?:\/\//i.test(e), n = "*", r = (e) => t(e) || e.includes("{{"), i = (e) => e.replaceAll(/\/+/g, "/"), a = (e) => i(e.replace(/{{([a-zA-Z0-9-_:*/]+)}}/gi, ":$1")), o = (e, t) => {
4
4
  if (!t || !e[t]) return "";
5
5
  let { slug: n, parentId: r } = e[t];
6
- return r ? `${a(e, r)}/${n}` : n;
6
+ return r ? `${o(e, r)}/${n}` : n;
7
7
  };
8
- function o(e, t, n, o = !1) {
8
+ function s(e, t, n, r = !1) {
9
9
  let s = n.replace(/^\/+/, ""), { slug: c = "", folder: l, default: u } = e[s]?.attributes ?? {
10
10
  slug: s,
11
11
  folder: "",
12
12
  default: !1
13
13
  };
14
- if (u && !o) return {
14
+ if (u && !r) return {
15
15
  "/": n,
16
16
  [`/${n}`]: n
17
17
  };
18
- if (u && o) return "/";
19
- if (!l && !o) return {
20
- [i(`/${c}`)]: n,
21
- [i(`/${n}`)]: n
18
+ if (u && r) return "/";
19
+ if (!l && !r) return {
20
+ [a(`/${c}`)]: n,
21
+ [a(`/${n}`)]: n
22
22
  };
23
- if (!l && o) return r(`/${c}`);
24
- if (!t.find((e) => e.id === l)) return o ? r(`/${c}`) : {
25
- [i(`/${c}`)]: n,
26
- [i(`/${n}`)]: n
23
+ if (!l && r) return i(`/${c}`);
24
+ if (!t.find((e) => e.id === l)) return r ? i(`/${c}`) : {
25
+ [a(`/${c}`)]: n,
26
+ [a(`/${n}`)]: n
27
27
  };
28
- let d = [a(t.reduce((e, t) => ({
28
+ let d = [o(t.reduce((e, t) => ({
29
29
  ...e,
30
30
  [t.id]: t
31
31
  }), {}), l), c].filter(Boolean).join("/");
32
- return o ? r(`/${d}`) : {
33
- [i(`/${d}`)]: n,
34
- [i(`/${n}`)]: n
32
+ return r ? i(`/${d}`) : {
33
+ [a(`/${d}`)]: n,
34
+ [a(`/${n}`)]: n
35
35
  };
36
36
  }
37
- var s = (e, t, n) => {
37
+ var c = (e, t, n) => {
38
38
  let r = n.indexOf("#");
39
- if (r > 0) return `${s(e, t, n.slice(0, r))}${n.slice(r)}`;
39
+ if (r > 0) return `${c(e, t, n.slice(0, r))}${n.slice(r)}`;
40
40
  let i = e[n];
41
41
  if (!i) return n;
42
- let { slug: a, default: c } = i.attributes;
43
- return typeof a == "string" ? o(e, t, n, !0) : c ? "/" : `/${n}`;
44
- }, c = (e, t, n = !0) => !e || !n || t === void 0 || t && e === "authenticated" || !t && e === "public" ? !0 : t && e === "public" ? !1 : !e, l = (e = {}, t = [], r, i = "", a = !0, s = !0) => {
45
- let l = Object.keys(e).reduce((s, l) => {
46
- let { attributes: { accessLevel: u, enabled: d = !0, unauthorizedBehaviour: f } } = e[l], p = e[l].attributes.unauthorizedPageRedirect;
47
- if (!d && a) return s;
48
- p &&= n(p) ? p : o(e, t, p, !0);
49
- let m = o(e, t, l), h = Object.keys(m).map((e) => ({
50
- pageId: l,
51
- path: `${i}${e}`.replaceAll("//", "/"),
52
- accessLevel: u,
53
- enabled: d,
54
- isRaw: `/${l}` === e,
55
- unauthorizedBehaviour: f,
56
- unauthorizedPageRedirect: p,
57
- hasAccess: c(u, r, a)
58
- }));
59
- return [...s, ...h];
60
- }, []).filter((e) => e.path !== "*" || e.hasAccess).sort((e, t) => e.path === t.path ? e.accessLevel === "authenticated" ? -1 : 1 : e.path > t.path ? -1 : 1);
61
- if (!l.find((e) => e.path === "*") && !s) {
62
- let e = l.find((e) => e.path === "/" && e.hasAccess);
63
- e && e.unauthorizedBehaviour === "redirect" && e.unauthorizedPageRedirect && l.push({
64
- ...e,
65
- path: "*",
66
- hasAccess: !1,
67
- isRaw: !0,
68
- unauthorizedBehaviour: "redirect",
69
- unauthorizedPageRedirect: "/"
70
- });
71
- }
72
- return l;
73
- }, u = (t, n, r) => {
42
+ let { slug: a, default: o } = i.attributes;
43
+ return typeof a == "string" ? s(e, t, n, !0) : o ? "/" : `/${n}`;
44
+ }, l = (e, t, n = !0) => !e || !n || t === void 0 || t && e === "authenticated" || !t && e === "public" ? !0 : t && e === "public" ? !1 : !e, u = (e = {}, t = [], n, i = "", a = !0) => Object.keys(e).reduce((o, c) => {
45
+ let { attributes: { accessLevel: u, enabled: d = !0, unauthorizedBehaviour: f } } = e[c], p = e[c].attributes.unauthorizedPageRedirect;
46
+ if (!d && a) return o;
47
+ p &&= r(p) ? p : s(e, t, p, !0);
48
+ let m = s(e, t, c), h = e[c].attributes.slug === "*", g = Object.keys(m).map((e) => ({
49
+ pageId: c,
50
+ path: `${i}${e}`.replaceAll("//", "/"),
51
+ accessLevel: u,
52
+ enabled: d,
53
+ isRaw: `/${c}` === e,
54
+ unauthorizedBehaviour: f,
55
+ unauthorizedPageRedirect: p,
56
+ hasAccess: l(u, n, a),
57
+ ...h ? { notFound: !0 } : {}
58
+ }));
59
+ return [...o, ...g];
60
+ }, []).sort((e, t) => !!e.notFound == !!t.notFound ? e.path === t.path ? e.accessLevel === "authenticated" ? -1 : 1 : e.path > t.path ? -1 : 1 : e.notFound ? 1 : -1), d = (t, n, r) => {
74
61
  if (!n) return {
75
62
  action: {
76
63
  type: "accessDenied",
@@ -90,35 +77,28 @@ var s = (e, t, n) => {
90
77
  pageId: t.pageId
91
78
  });
92
79
  });
93
- let a = i.find(({ path: { accessLevel: e } }) => e === "authenticated" && r || e === "public" && !r || !e);
94
- if (a ||= i.find(({ path: { accessLevel: e } }) => e === "authenticated" && !r || e === "public" && r), !a && t.find((e) => e.path === "/" && e.hasAccess)) return {
95
- action: {
96
- type: "redirect",
97
- path: "/"
98
- },
99
- pathMatch: void 0
100
- };
101
- if (!a) return {
80
+ let a = (e) => e.find(({ path: { accessLevel: e } }) => e === "authenticated" && r || e === "public" && !r || !e) ?? e.find(({ path: { accessLevel: e } }) => e === "authenticated" && !r || e === "public" && r), o = a(i.filter(({ path: e }) => !e.notFound)) ?? a(i.filter(({ path: e }) => e.notFound));
81
+ if (!o) return {
102
82
  action: {
103
83
  type: "notFound",
104
84
  path: void 0
105
85
  },
106
86
  pathMatch: void 0
107
87
  };
108
- let { pageId: o, matchResult: s, path: { hasAccess: c, unauthorizedBehaviour: l, unauthorizedPageRedirect: u } } = a;
109
- return !c && l === "redirect" && u ? {
88
+ let { pageId: s, matchResult: c, path: { hasAccess: l, unauthorizedBehaviour: u, unauthorizedPageRedirect: d, notFound: f } } = o;
89
+ return !l && u === "redirect" && d ? {
110
90
  action: {
111
91
  type: "redirect",
112
- path: u
92
+ path: d
113
93
  },
114
94
  pathMatch: void 0
115
- } : c ? {
95
+ } : l ? {
116
96
  action: {
117
- type: "normal",
97
+ type: f ? "notFound" : "normal",
118
98
  path: void 0
119
99
  },
120
- pathMatch: s,
121
- pageId: o
100
+ pathMatch: c,
101
+ pageId: s
122
102
  } : {
123
103
  action: {
124
104
  type: "accessDenied",
@@ -126,6 +106,9 @@ var s = (e, t, n) => {
126
106
  },
127
107
  pathMatch: void 0
128
108
  };
129
- }, d = (e) => !e || typeof e != "string" ? [] : (e.match(/:[a-zA-Z0-9-_:*]+/gim) || []).map((e) => e.replace(":", "")), f = (e) => d(i(e));
109
+ }, f = (t, n) => t.find((t) => t.hasAccess && t.notFound && e({
110
+ path: t.path,
111
+ end: !0
112
+ }, n))?.pageId, p = (e) => !e || typeof e != "string" ? [] : (e.match(/:[a-zA-Z0-9-_:*]+/gim) || []).map((e) => e.replace(":", "")), m = (e) => p(a(e));
130
113
  //#endregion
131
- export { o as getPageFullPath, l as getPaths, d as getRouteParams, f as getSlugParams, t as isAbsoluteUrl, c as isPageAuthored, u as matchRoutePath, s as navigationTarget };
114
+ export { n as NOT_FOUND_SLUG, s as getPageFullPath, u as getPaths, p as getRouteParams, m as getSlugParams, t as isAbsoluteUrl, l as isPageAuthored, d as matchRoutePath, c as navigationTarget, f as notFoundPageFor };
@@ -2,6 +2,6 @@ import e from "./SchemaContext.mjs";
2
2
  import { ANCHOR_PATTERN as t, anchorOf as n, isAnchor as r, uniqueAnchor as i } from "./anchor.mjs";
3
3
  import { COMPONENT_PROPS_SOURCE as a, EMPTY_SCHEMA as o, VARIABLE_REGEX as s } from "./schemaConstants.mjs";
4
4
  import { findLayoutCycle as c, resolveLayoutChain as l } from "./layoutChain.mjs";
5
- import { collectServerElements as u, hasServerElements as d } from "./serverElements.mjs";
6
- import { isSnippet as f } from "./snippet.mjs";
7
- export { t as ANCHOR_PATTERN, a as COMPONENT_PROPS_SOURCE, o as EMPTY_SCHEMA, e as SchemaContext, s as VARIABLE_REGEX, n as anchorOf, u as collectServerElements, c as findLayoutCycle, d as hasServerElements, r as isAnchor, f as isSnippet, l as resolveLayoutChain, i as uniqueAnchor };
5
+ import { collectServerElements as u, hasServerElements as d, notFoundProvider as f, pageNotFound as p, pageSeoText as m, pageServerContext as h } from "./serverElements.mjs";
6
+ import { isSnippet as g } from "./snippet.mjs";
7
+ export { t as ANCHOR_PATTERN, a as COMPONENT_PROPS_SOURCE, o as EMPTY_SCHEMA, e as SchemaContext, s as VARIABLE_REGEX, n as anchorOf, u as collectServerElements, c as findLayoutCycle, d as hasServerElements, r as isAnchor, g as isSnippet, f as notFoundProvider, p as pageNotFound, m as pageSeoText, h as pageServerContext, l as resolveLayoutChain, i as uniqueAnchor };
@@ -20,6 +20,38 @@ import { Element, Schema } from '../types';
20
20
  * Given the flags as they resolved, an element gated off by one is skipped with its whole subtree — it will not be
21
21
  * rendered, so nothing in it wants data, and resolving it would put a feature that is off into the payload anyway.
22
22
  */
23
- export declare const collectServerElements: (schema: Schema, pageId: string | undefined, ids?: string[], flags?: Record<string, boolean>) => Element[];
23
+ export declare const collectServerElements: (schema: Pick<Schema, "flat">, pageId: string | undefined, ids?: string[], flags?: Record<string, boolean>) => Element[];
24
24
  /** Whether anything on this page consumes server data at all — the question both RSC gates actually ask. */
25
25
  export declare const hasServerElements: (schema: Schema, pageId: string | undefined, flags?: Record<string, boolean>) => boolean;
26
+ /** Where the visitor is: what a template on the server reads beside the page's data, as `navigation`. */
27
+ export type ServerNavigation = {
28
+ routeParams: Record<string, unknown>;
29
+ queryParams: Record<string, unknown>;
30
+ };
31
+ /**
32
+ * The server provider of a page whose answer says the address shows nothing — its `notFound`, a template against
33
+ * that answer (`{{ source.found == false }}`) — by id; the page is then sent with status 404, rendered as written.
34
+ *
35
+ * Only `true` counts: a template that does not evaluate comes back as its own text, and a typo must leave the page
36
+ * found rather than turn every visit into a 404.
37
+ */
38
+ export declare const notFoundProvider: (elements: Element[], serverData: Record<string, unknown>, navigation: ServerNavigation) => string | undefined;
39
+ /**
40
+ * What a page's own templates read — its title, its description, its `notFound`: every server provider of the page and
41
+ * of the shells around it, by the name its descendants read it by (`apiContainer_capsule`), with its answer — and
42
+ * `navigation`. The server has both before it writes the head, and the browser has the same answer in `rsc.data`, so
43
+ * the two write one title.
44
+ */
45
+ export declare const pageServerContext: (elements: Element[], serverData: Record<string, unknown>, navigation: ServerNavigation) => Record<string, unknown>;
46
+ /**
47
+ * A page's title or description as the head carries it: its words, or its template evaluated against
48
+ * `pageServerContext`. Blank, or a template that did not evaluate — it comes back as its own text — is nothing, and the
49
+ * deployment's own title stays: braces never reach a tab or a link preview.
50
+ */
51
+ export declare const pageSeoText: (value: unknown, context: Record<string, unknown>) => string | undefined;
52
+ /**
53
+ * Whether a page's own `notFound` — a template over `pageServerContext` — says the address shows nothing: a record
54
+ * read by a provider the page shares with others, in its layout, which cannot say it for any one page itself. Only
55
+ * `true` counts, as for a provider's.
56
+ */
57
+ export declare const pageNotFound: (template: unknown, context: Record<string, unknown>) => boolean;
@@ -1,20 +1,35 @@
1
- import { passesFlagGate as e } from "../flags/resolveFlags.mjs";
2
- import { resolveLayoutChain as t } from "./layoutChain.mjs";
1
+ import { processTwigValue as e } from "../helpers/twigWrapper/processTwig/processTwig.mjs";
2
+ import t from "../dataSource/helpers/getSourceName.mjs";
3
+ import { passesFlagGate as n } from "../flags/resolveFlags.mjs";
4
+ import { resolveLayoutChain as r } from "./layoutChain.mjs";
3
5
  //#region src/schema/serverElements.ts
4
- var n = (n, r, i, a) => {
5
- if (r === void 0) return [];
6
- let o = i ? new Set(i) : void 0, s = [], c = /* @__PURE__ */ new Set(), l = n.flat[r], u = (e) => typeof e == "string" ? e : "", d = [r, ...l ? t((e) => n.flat[e], u(l.attributes.layout), u(l.attributes.layoutContainer)).map((e) => e.layout) : []];
6
+ var i = (e, t, i, a) => {
7
+ if (t === void 0) return [];
8
+ let o = i ? new Set(i) : void 0, s = [], c = /* @__PURE__ */ new Set(), l = e.flat[t], u = (e) => typeof e == "string" ? e : "", d = [t, ...l ? r((t) => e.flat[t], u(l.attributes.layout), u(l.attributes.layoutContainer)).map((e) => e.layout) : []];
7
9
  for (; d.length > 0;) {
8
10
  let t = d.pop();
9
11
  if (t === void 0 || c.has(t)) continue;
10
12
  c.add(t);
11
- let r = n.flat[t];
12
- if (!r || a && !e(r.definition.flag, a)) continue;
13
+ let r = e.flat[t];
14
+ if (!r || a && !n(r.definition.flag, a)) continue;
13
15
  r.definition.runtime === "server" && (!o || o.has(r.id)) && s.push(r);
14
16
  let { items: i } = r.definition;
15
17
  i && d.push(...i);
16
18
  }
17
19
  return s;
18
- }, r = (e, t, r) => n(e, t, void 0, r).length > 0;
20
+ }, a = (e, t, n) => i(e, t, void 0, n).length > 0, o = (t, n, r) => t.find((t) => {
21
+ let i = t.attributes.notFound;
22
+ return typeof i == "string" && i !== "" && Object.hasOwn(n, t.id) && e(i, {
23
+ source: n[t.id],
24
+ navigation: r
25
+ }) === !0;
26
+ })?.id, s = (e, n, r) => ({
27
+ ...Object.fromEntries(e.filter((e) => Object.hasOwn(n, e.id)).map((e) => [t(e.definition.type, e.id), n[e.id]])),
28
+ navigation: r
29
+ }), c = /\{[{%]/, l = (t, n) => {
30
+ if (typeof t != "string") return;
31
+ let r = c.test(t) ? e(t, n) : t, i = typeof r == "string" || typeof r == "number" ? String(r).trim() : "";
32
+ return i === "" || c.test(i) ? void 0 : i;
33
+ }, u = (t, n) => typeof t == "string" && t !== "" && e(t, n) === !0;
19
34
  //#endregion
20
- export { n as collectServerElements, r as hasServerElements };
35
+ export { i as collectServerElements, a as hasServerElements, o as notFoundProvider, u as pageNotFound, l as pageSeoText, s as pageServerContext };
@@ -178,6 +178,8 @@ declare const styleConstants: {
178
178
  readonly TEXT_INDENT: "text-indent";
179
179
  readonly TEXT_TRANSFORM: "text-transform";
180
180
  readonly DIRECTION: "direction";
181
+ readonly WRITING_MODE: "writing-mode";
182
+ readonly TEXT_ORIENTATION: "text-orientation";
181
183
  readonly WHITE_SPACE: "white-space";
182
184
  readonly TEXT_WRAP: "text-wrap";
183
185
  readonly WORD_BREAK: "word-break";
@@ -199,8 +201,8 @@ declare const styleConstants: {
199
201
  };
200
202
  export declare const inheritableAttributesBase: StyleCategory[];
201
203
  export declare const StyleBindingsAllowed: {
202
- path: "color" | "cursor" | "filter" | "fill" | "display" | "flex-wrap" | "flex-direction" | "align-items" | "justify-items" | "justify-content" | "align-content" | "row-gap" | "column-gap" | "grid-row-gap" | "grid-column-gap" | "grid-template-areas" | "grid-template-columns" | "grid-template-rows" | "grid-auto-flow" | "grid-auto-rows" | "grid-auto-columns" | "grid-row-start" | "grid-column-start" | "grid-row-end" | "grid-column-end" | "align-self" | "justify-self" | "order" | "flex-grow" | "flex-shrink" | "flex-basis" | "list-style" | "list-style-type" | "list-style-position" | "list-style-image" | "background-color" | "background-image" | "background-position" | "background-size" | "background-repeat" | "background-origin" | "background-clip" | "background-attachment" | "background-blend-mode" | "mask-image" | "mask-size" | "mask-position" | "mask-repeat" | "mask-composite" | "-webkit-mask-image" | "border-top-style" | "border-top-width" | "border-top-color" | "border-bottom-style" | "border-bottom-width" | "border-bottom-color" | "border-left-style" | "border-left-width" | "border-left-color" | "border-right-style" | "border-right-width" | "border-right-color" | "border-top-left-radius" | "border-top-right-radius" | "border-bottom-left-radius" | "border-bottom-right-radius" | "border-collapse" | "border-spacing" | "table-layout" | "opacity" | "visibility" | "transition" | "transition-property" | "transition-duration" | "transition-timing-function" | "transition-delay" | "transition-behavior" | "animation" | "animation-name" | "animation-duration" | "animation-timing-function" | "animation-delay" | "animation-iteration-count" | "animation-direction" | "animation-fill-mode" | "animation-play-state" | "animation-timeline" | "animation-range" | "box-shadow" | "backdrop-filter" | "mix-blend-mode" | "isolation" | "clip-path" | "transform" | "transform-origin" | "translate" | "rotate" | "scale" | "transform-style" | "perspective" | "perspective-origin" | "backface-visibility" | "will-change" | "outline-width" | "outline-style" | "outline-color" | "outline-offset" | "pointer-events" | "user-select" | "touch-action" | "resize" | "appearance" | "scroll-behavior" | "overscroll-behavior" | "scroll-snap-type" | "scroll-snap-align" | "scroll-snap-stop" | "scroll-padding-top" | "scroll-margin-top" | "accent-color" | "caret-color" | "color-scheme" | "content" | "position" | "float" | "clear" | "z-index" | "top" | "bottom" | "left" | "right" | "box-sizing" | "aspect-ratio" | "width" | "height" | "min-width" | "min-height" | "max-width" | "max-height" | "overflow" | "overflow-x" | "overflow-y" | "scrollbar-width" | "scrollbar-color" | "container-type" | "container-name" | "object-fit" | "object-position" | "column-width" | "column-count" | "margin-top" | "margin-bottom" | "margin-left" | "margin-right" | "padding-top" | "padding-bottom" | "padding-left" | "padding-right" | "font-family" | "font-weight" | "font-size" | "line-height" | "text-align" | "font-style" | "font-variant" | "font-variant-numeric" | "font-feature-settings" | "text-decoration" | "text-decoration-line" | "text-decoration-color" | "text-decoration-style" | "text-decoration-thickness" | "text-underline-offset" | "letter-spacing" | "word-spacing" | "text-indent" | "text-transform" | "direction" | "white-space" | "text-wrap" | "word-break" | "overflow-wrap" | "hyphens" | "vertical-align" | "text-overflow" | "text-shadow" | "line-clamp" | "-webkit-line-clamp" | "-webkit-box-orient" | "-webkit-text-fill-color" | "-webkit-background-clip" | "box-decoration-break" | "-webkit-box-decoration-break" | "stroke" | "stroke-width";
203
- label: "color" | "cursor" | "filter" | "fill" | "display" | "flex-wrap" | "flex-direction" | "align-items" | "justify-items" | "justify-content" | "align-content" | "row-gap" | "column-gap" | "grid-row-gap" | "grid-column-gap" | "grid-template-areas" | "grid-template-columns" | "grid-template-rows" | "grid-auto-flow" | "grid-auto-rows" | "grid-auto-columns" | "grid-row-start" | "grid-column-start" | "grid-row-end" | "grid-column-end" | "align-self" | "justify-self" | "order" | "flex-grow" | "flex-shrink" | "flex-basis" | "list-style" | "list-style-type" | "list-style-position" | "list-style-image" | "background-color" | "background-image" | "background-position" | "background-size" | "background-repeat" | "background-origin" | "background-clip" | "background-attachment" | "background-blend-mode" | "mask-image" | "mask-size" | "mask-position" | "mask-repeat" | "mask-composite" | "-webkit-mask-image" | "border-top-style" | "border-top-width" | "border-top-color" | "border-bottom-style" | "border-bottom-width" | "border-bottom-color" | "border-left-style" | "border-left-width" | "border-left-color" | "border-right-style" | "border-right-width" | "border-right-color" | "border-top-left-radius" | "border-top-right-radius" | "border-bottom-left-radius" | "border-bottom-right-radius" | "border-collapse" | "border-spacing" | "table-layout" | "opacity" | "visibility" | "transition" | "transition-property" | "transition-duration" | "transition-timing-function" | "transition-delay" | "transition-behavior" | "animation" | "animation-name" | "animation-duration" | "animation-timing-function" | "animation-delay" | "animation-iteration-count" | "animation-direction" | "animation-fill-mode" | "animation-play-state" | "animation-timeline" | "animation-range" | "box-shadow" | "backdrop-filter" | "mix-blend-mode" | "isolation" | "clip-path" | "transform" | "transform-origin" | "translate" | "rotate" | "scale" | "transform-style" | "perspective" | "perspective-origin" | "backface-visibility" | "will-change" | "outline-width" | "outline-style" | "outline-color" | "outline-offset" | "pointer-events" | "user-select" | "touch-action" | "resize" | "appearance" | "scroll-behavior" | "overscroll-behavior" | "scroll-snap-type" | "scroll-snap-align" | "scroll-snap-stop" | "scroll-padding-top" | "scroll-margin-top" | "accent-color" | "caret-color" | "color-scheme" | "content" | "position" | "float" | "clear" | "z-index" | "top" | "bottom" | "left" | "right" | "box-sizing" | "aspect-ratio" | "width" | "height" | "min-width" | "min-height" | "max-width" | "max-height" | "overflow" | "overflow-x" | "overflow-y" | "scrollbar-width" | "scrollbar-color" | "container-type" | "container-name" | "object-fit" | "object-position" | "column-width" | "column-count" | "margin-top" | "margin-bottom" | "margin-left" | "margin-right" | "padding-top" | "padding-bottom" | "padding-left" | "padding-right" | "font-family" | "font-weight" | "font-size" | "line-height" | "text-align" | "font-style" | "font-variant" | "font-variant-numeric" | "font-feature-settings" | "text-decoration" | "text-decoration-line" | "text-decoration-color" | "text-decoration-style" | "text-decoration-thickness" | "text-underline-offset" | "letter-spacing" | "word-spacing" | "text-indent" | "text-transform" | "direction" | "white-space" | "text-wrap" | "word-break" | "overflow-wrap" | "hyphens" | "vertical-align" | "text-overflow" | "text-shadow" | "line-clamp" | "-webkit-line-clamp" | "-webkit-box-orient" | "-webkit-text-fill-color" | "-webkit-background-clip" | "box-decoration-break" | "-webkit-box-decoration-break" | "stroke" | "stroke-width";
204
+ path: "color" | "cursor" | "filter" | "fill" | "display" | "flex-wrap" | "flex-direction" | "align-items" | "justify-items" | "justify-content" | "align-content" | "row-gap" | "column-gap" | "grid-row-gap" | "grid-column-gap" | "grid-template-areas" | "grid-template-columns" | "grid-template-rows" | "grid-auto-flow" | "grid-auto-rows" | "grid-auto-columns" | "grid-row-start" | "grid-column-start" | "grid-row-end" | "grid-column-end" | "align-self" | "justify-self" | "order" | "flex-grow" | "flex-shrink" | "flex-basis" | "list-style" | "list-style-type" | "list-style-position" | "list-style-image" | "background-color" | "background-image" | "background-position" | "background-size" | "background-repeat" | "background-origin" | "background-clip" | "background-attachment" | "background-blend-mode" | "mask-image" | "mask-size" | "mask-position" | "mask-repeat" | "mask-composite" | "-webkit-mask-image" | "border-top-style" | "border-top-width" | "border-top-color" | "border-bottom-style" | "border-bottom-width" | "border-bottom-color" | "border-left-style" | "border-left-width" | "border-left-color" | "border-right-style" | "border-right-width" | "border-right-color" | "border-top-left-radius" | "border-top-right-radius" | "border-bottom-left-radius" | "border-bottom-right-radius" | "border-collapse" | "border-spacing" | "table-layout" | "opacity" | "visibility" | "transition" | "transition-property" | "transition-duration" | "transition-timing-function" | "transition-delay" | "transition-behavior" | "animation" | "animation-name" | "animation-duration" | "animation-timing-function" | "animation-delay" | "animation-iteration-count" | "animation-direction" | "animation-fill-mode" | "animation-play-state" | "animation-timeline" | "animation-range" | "box-shadow" | "backdrop-filter" | "mix-blend-mode" | "isolation" | "clip-path" | "transform" | "transform-origin" | "translate" | "rotate" | "scale" | "transform-style" | "perspective" | "perspective-origin" | "backface-visibility" | "will-change" | "outline-width" | "outline-style" | "outline-color" | "outline-offset" | "pointer-events" | "user-select" | "touch-action" | "resize" | "appearance" | "scroll-behavior" | "overscroll-behavior" | "scroll-snap-type" | "scroll-snap-align" | "scroll-snap-stop" | "scroll-padding-top" | "scroll-margin-top" | "accent-color" | "caret-color" | "color-scheme" | "content" | "position" | "float" | "clear" | "z-index" | "top" | "bottom" | "left" | "right" | "box-sizing" | "aspect-ratio" | "width" | "height" | "min-width" | "min-height" | "max-width" | "max-height" | "overflow" | "overflow-x" | "overflow-y" | "scrollbar-width" | "scrollbar-color" | "container-type" | "container-name" | "object-fit" | "object-position" | "column-width" | "column-count" | "margin-top" | "margin-bottom" | "margin-left" | "margin-right" | "padding-top" | "padding-bottom" | "padding-left" | "padding-right" | "font-family" | "font-weight" | "font-size" | "line-height" | "text-align" | "font-style" | "font-variant" | "font-variant-numeric" | "font-feature-settings" | "text-decoration" | "text-decoration-line" | "text-decoration-color" | "text-decoration-style" | "text-decoration-thickness" | "text-underline-offset" | "letter-spacing" | "word-spacing" | "text-indent" | "text-transform" | "direction" | "writing-mode" | "text-orientation" | "white-space" | "text-wrap" | "word-break" | "overflow-wrap" | "hyphens" | "vertical-align" | "text-overflow" | "text-shadow" | "line-clamp" | "-webkit-line-clamp" | "-webkit-box-orient" | "-webkit-text-fill-color" | "-webkit-background-clip" | "box-decoration-break" | "-webkit-box-decoration-break" | "stroke" | "stroke-width";
205
+ label: "color" | "cursor" | "filter" | "fill" | "display" | "flex-wrap" | "flex-direction" | "align-items" | "justify-items" | "justify-content" | "align-content" | "row-gap" | "column-gap" | "grid-row-gap" | "grid-column-gap" | "grid-template-areas" | "grid-template-columns" | "grid-template-rows" | "grid-auto-flow" | "grid-auto-rows" | "grid-auto-columns" | "grid-row-start" | "grid-column-start" | "grid-row-end" | "grid-column-end" | "align-self" | "justify-self" | "order" | "flex-grow" | "flex-shrink" | "flex-basis" | "list-style" | "list-style-type" | "list-style-position" | "list-style-image" | "background-color" | "background-image" | "background-position" | "background-size" | "background-repeat" | "background-origin" | "background-clip" | "background-attachment" | "background-blend-mode" | "mask-image" | "mask-size" | "mask-position" | "mask-repeat" | "mask-composite" | "-webkit-mask-image" | "border-top-style" | "border-top-width" | "border-top-color" | "border-bottom-style" | "border-bottom-width" | "border-bottom-color" | "border-left-style" | "border-left-width" | "border-left-color" | "border-right-style" | "border-right-width" | "border-right-color" | "border-top-left-radius" | "border-top-right-radius" | "border-bottom-left-radius" | "border-bottom-right-radius" | "border-collapse" | "border-spacing" | "table-layout" | "opacity" | "visibility" | "transition" | "transition-property" | "transition-duration" | "transition-timing-function" | "transition-delay" | "transition-behavior" | "animation" | "animation-name" | "animation-duration" | "animation-timing-function" | "animation-delay" | "animation-iteration-count" | "animation-direction" | "animation-fill-mode" | "animation-play-state" | "animation-timeline" | "animation-range" | "box-shadow" | "backdrop-filter" | "mix-blend-mode" | "isolation" | "clip-path" | "transform" | "transform-origin" | "translate" | "rotate" | "scale" | "transform-style" | "perspective" | "perspective-origin" | "backface-visibility" | "will-change" | "outline-width" | "outline-style" | "outline-color" | "outline-offset" | "pointer-events" | "user-select" | "touch-action" | "resize" | "appearance" | "scroll-behavior" | "overscroll-behavior" | "scroll-snap-type" | "scroll-snap-align" | "scroll-snap-stop" | "scroll-padding-top" | "scroll-margin-top" | "accent-color" | "caret-color" | "color-scheme" | "content" | "position" | "float" | "clear" | "z-index" | "top" | "bottom" | "left" | "right" | "box-sizing" | "aspect-ratio" | "width" | "height" | "min-width" | "min-height" | "max-width" | "max-height" | "overflow" | "overflow-x" | "overflow-y" | "scrollbar-width" | "scrollbar-color" | "container-type" | "container-name" | "object-fit" | "object-position" | "column-width" | "column-count" | "margin-top" | "margin-bottom" | "margin-left" | "margin-right" | "padding-top" | "padding-bottom" | "padding-left" | "padding-right" | "font-family" | "font-weight" | "font-size" | "line-height" | "text-align" | "font-style" | "font-variant" | "font-variant-numeric" | "font-feature-settings" | "text-decoration" | "text-decoration-line" | "text-decoration-color" | "text-decoration-style" | "text-decoration-thickness" | "text-underline-offset" | "letter-spacing" | "word-spacing" | "text-indent" | "text-transform" | "direction" | "writing-mode" | "text-orientation" | "white-space" | "text-wrap" | "word-break" | "overflow-wrap" | "hyphens" | "vertical-align" | "text-overflow" | "text-shadow" | "line-clamp" | "-webkit-line-clamp" | "-webkit-box-orient" | "-webkit-text-fill-color" | "-webkit-background-clip" | "box-decoration-break" | "-webkit-box-decoration-break" | "stroke" | "stroke-width";
204
206
  }[];
205
207
  export declare const baseDefaultValue: Record<StyleCategory, StyleValue>;
206
208
  export default styleConstants;
@@ -191,6 +191,8 @@ var e = {
191
191
  TEXT_INDENT: "text-indent",
192
192
  TEXT_TRANSFORM: "text-transform",
193
193
  DIRECTION: "direction",
194
+ WRITING_MODE: "writing-mode",
195
+ TEXT_ORIENTATION: "text-orientation",
194
196
  WHITE_SPACE: "white-space",
195
197
  TEXT_WRAP: "text-wrap",
196
198
  WORD_BREAK: "word-break",
@@ -413,6 +415,8 @@ var e = {
413
415
  [t.TEXT_INDENT]: "0px",
414
416
  [t.TEXT_TRANSFORM]: "none",
415
417
  [t.DIRECTION]: "ltr",
418
+ [t.WRITING_MODE]: "horizontal-tb",
419
+ [t.TEXT_ORIENTATION]: "mixed",
416
420
  [t.WHITE_SPACE]: "normal",
417
421
  [t.TEXT_WRAP]: "wrap",
418
422
  [t.WORD_BREAK]: "normal",
@@ -1,60 +1,69 @@
1
1
  import { useCommonStoreSync as e } from "../store/index.mjs";
2
2
  import { THEME_COOKIE_NAME as t, applyThemeClass as n, readThemeCookie as r, writeThemeCookie as i } from "./themeCookie.mjs";
3
3
  import a, { createThemeStore as o, resolveScheme as s, setMachineScheme as c, setThemeMode as l } from "./themeStore.mjs";
4
- import u from "./ThemeScope.mjs";
5
- import { use as d, useEffect as f, useId as p, useRef as m, useState as h, useSyncExternalStore as g } from "react";
6
- import { StoreContext as _, useIsomorphicLayoutEffect as v } from "@plitzi/nexus/react";
7
- import { Fragment as y, jsx as b, jsxs as x } from "react/jsx-runtime";
4
+ import u, { ThemeStartContext as d, useThemeState as f } from "./ThemeScope.mjs";
5
+ import { use as p, useEffect as m, useId as h, useRef as g, useState as _ } from "react";
6
+ import { StoreContext as v, useIsomorphicLayoutEffect as y } from "@plitzi/nexus/react";
7
+ import { jsx as b, jsxs as x } from "react/jsx-runtime";
8
8
  //#region src/theme/ThemeProvider.tsx
9
- var S = "(prefers-color-scheme: dark)", C = () => window.matchMedia(S).matches ? "dark" : "light", w = ({ state: t }) => (e([
10
- "theme.mode",
11
- "theme.resolved",
12
- "theme.areas"
13
- ], [
14
- t.mode,
15
- s(t.mode, t.scheme),
16
- t.areas
17
- ]), null), T = ({ defaultTheme: e = "system", theme: s, scope: T = "document", cookieName: E = t, children: D }) => {
18
- let O = T === "container", k = p(), [A] = h(() => O ? o(`theme${k}`) : void 0), j = A ?? a, M = m({
9
+ var S = "(prefers-color-scheme: dark)", C = () => window.matchMedia(S).matches ? "dark" : "light", w = ({ store: t }) => {
10
+ let n = f(t);
11
+ return e([
12
+ "theme.mode",
13
+ "theme.resolved",
14
+ "theme.areas"
15
+ ], [
16
+ n.mode,
17
+ s(n.mode, n.scheme),
18
+ n.areas
19
+ ]), null;
20
+ }, T = ({ defaultTheme: e = "system", theme: s, scope: f = "document", cookieName: T = t, children: E }) => {
21
+ let D = f === "container", O = h(), [k] = _(() => D ? o(`theme${O}`) : void 0), A = k ?? a, j = g({
19
22
  mode: e,
20
23
  remembered: !1
21
24
  });
22
- v(() => {
23
- let t = O ? void 0 : r(E), n = s ?? t ?? e;
24
- M.current = {
25
+ y(() => {
26
+ let t = D ? void 0 : r(T), n = s ?? t ?? e;
27
+ j.current = {
25
28
  mode: n,
26
29
  remembered: t !== void 0
27
- }, j.batch(() => {
28
- c(C(), j), l(n, j);
30
+ }, A.batch(() => {
31
+ c(C(), A), l(n, A);
29
32
  });
30
33
  }, [
31
34
  e,
32
35
  s,
33
- E,
34
- O,
35
- j
36
+ T,
37
+ D,
38
+ A
36
39
  ]);
37
- let N = g(j.subscribe, j.getState, j.getState), P = d(_) !== void 0;
38
- f(() => {
39
- let e = window.matchMedia(S), t = () => c(e.matches ? "dark" : "light", j);
40
+ let M = s ?? e, N = p(v) !== void 0;
41
+ m(() => {
42
+ let e = window.matchMedia(S), t = () => c(e.matches ? "dark" : "light", A);
40
43
  return e.addEventListener("change", t), t(), () => e.removeEventListener("change", t);
41
- }, [j]), f(() => {
42
- if (O) return;
44
+ }, [A]), m(() => {
45
+ if (D) return;
43
46
  let e = () => {
44
- let { mode: e } = j.getState();
45
- (M.current.remembered || e !== M.current.mode) && (i(e, E), M.current.remembered = !0), n(e, document.documentElement);
47
+ let { mode: e } = A.getState();
48
+ (j.current.remembered || e !== j.current.mode) && (i(e, T), j.current.remembered = !0), n(e, document.documentElement);
46
49
  };
47
- return e(), j.subscribe(e);
50
+ return e(), A.subscribe(e);
48
51
  }, [
49
- E,
50
- O,
51
- j
52
+ T,
53
+ D,
54
+ A
52
55
  ]);
53
- let F = P ? /* @__PURE__ */ b(w, { state: N }) : null;
54
- return O ? /* @__PURE__ */ x(u, {
55
- value: A,
56
- children: [F, D]
57
- }) : /* @__PURE__ */ x(y, { children: [F, D] });
56
+ let P = N ? /* @__PURE__ */ b(w, { store: A }) : null;
57
+ return D ? /* @__PURE__ */ b(u, {
58
+ value: k,
59
+ children: /* @__PURE__ */ x(d, {
60
+ value: M,
61
+ children: [P, E]
62
+ })
63
+ }) : /* @__PURE__ */ x(d, {
64
+ value: M,
65
+ children: [P, E]
66
+ });
58
67
  };
59
68
  //#endregion
60
69
  export { T as default };
@@ -1,4 +1,5 @@
1
1
  import { ThemeStoreInstance } from './themeStore';
2
+ import { Theme, ThemeState } from '../types';
2
3
  /**
3
4
  * Which theme store the tree under here reads.
4
5
  *
@@ -11,6 +12,25 @@ import { ThemeStoreInstance } from './themeStore';
11
12
  * Deliberately NOT the way ordinary consumers reach the theme: a panel in a shadow root and an editor in a portal
12
13
  * are under no provider at all, and they still have to get an answer. That is what the fall-through is for.
13
14
  */
14
- declare const ThemeScopeContext: import('react').Context<import('@plitzi/nexus').StoreApi<import('..').ThemeState> | undefined>;
15
+ declare const ThemeScopeContext: import('react').Context<import('@plitzi/nexus').StoreApi<ThemeState> | undefined>;
15
16
  export declare const useThemeStore: () => ThemeStoreInstance;
16
17
  export default ThemeScopeContext;
18
+ /**
19
+ * The mode the surface under a `ThemeProvider` starts in: the theme its host supplied — the cookie a server read — or
20
+ * else its default.
21
+ *
22
+ * For the render that runs before any effect can: the server's, and the hydration that has to agree with it. The
23
+ * provider sets the store from a layout effect, which never runs on a server — so the page was rendered from the
24
+ * store's own starting state, `system` resolving to `light`, whatever the cookie said. The class on `<html>` was right
25
+ * and `{{ theme.resolved }}` was not: a picture whose address names the scheme was the light one, swapped for the dark
26
+ * one as the page hydrated.
27
+ */
28
+ export declare const ThemeStartContext: import('react').Context<Theme | undefined>;
29
+ /**
30
+ * The theme store's state, as the server rendered it until the surface is live.
31
+ *
32
+ * The starting state is the server snapshot, so the server renders with it and the hydration reads the same — it is
33
+ * never written into the store there, which on a server is one module-level singleton every request shares. Once
34
+ * hydrated, the store answers, which the provider has set by then.
35
+ */
36
+ export declare const useThemeState: (store: ThemeStoreInstance) => ThemeState;
@@ -1,7 +1,10 @@
1
1
  import { sharedContext as e } from "../helpers/sharedContext.mjs";
2
- import t from "./themeStore.mjs";
3
- import { use as n } from "react";
2
+ import t, { startingThemeState as n } from "./themeStore.mjs";
3
+ import { use as r, useMemo as i, useSyncExternalStore as a } from "react";
4
4
  //#region src/theme/ThemeScope.ts
5
- var r = e("ThemeScopeContext", void 0), i = () => n(r) ?? t;
5
+ var o = e("ThemeScopeContext", void 0), s = () => r(o) ?? t, c = e("ThemeStartContext", void 0), l = (e) => {
6
+ let t = r(c), o = i(() => t === void 0 ? void 0 : n(t), [t]);
7
+ return a(e.subscribe, e.getState, () => o ?? e.getState());
8
+ };
6
9
  //#endregion
7
- export { r as default, i as useThemeStore };
10
+ export { c as ThemeStartContext, o as default, l as useThemeState, s as useThemeStore };
@@ -1,6 +1,6 @@
1
1
  import { THEME_CLASSES as e, THEME_COOKIE_NAME as t, applyThemeClass as n, isTheme as r, readThemeCookie as i, themeFromCookies as a, writeThemeCookie as o } from "./themeCookie.mjs";
2
- import s, { createThemeState as c, createThemeStore as l, resolveScheme as u, setAreaTheme as d, setMachineScheme as f, setThemeMode as p, themeFor as m } from "./themeStore.mjs";
3
- import { useThemeStore as h } from "./ThemeScope.mjs";
4
- import g from "./ThemeProvider.mjs";
5
- import _, { SPACE_THEME_AREA as v } from "./useTheme.mjs";
6
- export { v as SPACE_THEME_AREA, e as THEME_CLASSES, t as THEME_COOKIE_NAME, g as ThemeProvider, n as applyThemeClass, c as createThemeState, l as createThemeStore, r as isTheme, i as readThemeCookie, u as resolveScheme, d as setAreaTheme, f as setMachineScheme, p as setThemeMode, m as themeFor, a as themeFromCookies, s as themeStore, _ as useTheme, h as useThemeStore, o as writeThemeCookie };
2
+ import s, { createThemeState as c, createThemeStore as l, resolveScheme as u, setAreaTheme as d, setMachineScheme as f, setThemeMode as p, startingThemeState as m, themeFor as h } from "./themeStore.mjs";
3
+ import { ThemeStartContext as g, useThemeState as _, useThemeStore as v } from "./ThemeScope.mjs";
4
+ import y from "./ThemeProvider.mjs";
5
+ import b, { SPACE_THEME_AREA as x } from "./useTheme.mjs";
6
+ export { x as SPACE_THEME_AREA, e as THEME_CLASSES, t as THEME_COOKIE_NAME, y as ThemeProvider, g as ThemeStartContext, n as applyThemeClass, c as createThemeState, l as createThemeStore, r as isTheme, i as readThemeCookie, u as resolveScheme, d as setAreaTheme, f as setMachineScheme, p as setThemeMode, m as startingThemeState, h as themeFor, a as themeFromCookies, s as themeStore, b as useTheme, _ as useThemeState, v as useThemeStore, o as writeThemeCookie };
@@ -1,5 +1,11 @@
1
1
  import { ColorScheme, Theme, ThemeState } from '../types';
2
2
  export declare const createThemeState: () => ThemeState;
3
+ /**
4
+ * The state a surface starts in, before anything could ask the machine: the mode it opens with, and `light` for what a
5
+ * `system` mode resolves to until the browser answers — the one guess a server has to make, and the one the
6
+ * stylesheet's media queries correct without a class.
7
+ */
8
+ export declare const startingThemeState: (mode: Theme) => ThemeState;
3
9
  /**
4
10
  * The theme, as a store rather than a context.
5
11
  *
@@ -4,14 +4,17 @@ var t = () => ({
4
4
  mode: "system",
5
5
  scheme: "light",
6
6
  areas: {}
7
- }), n = (n = "theme") => e(t(), { id: n }), r = n(), i = (e, t) => e === "system" ? t : e, a = (e, t) => (t ? e.areas[t] : void 0) ?? e.mode, o = (e, t = r) => {
7
+ }), n = (e) => ({
8
+ ...t(),
9
+ mode: e
10
+ }), r = (n = "theme") => e(t(), { id: n }), i = r(), a = (e, t) => e === "system" ? t : e, o = (e, t) => (t ? e.areas[t] : void 0) ?? e.mode, s = (e, t = i) => {
8
11
  t.batch(() => {
9
12
  t.setState("mode", e), t.setState("areas", {});
10
13
  });
11
- }, s = (e, t, n = r) => {
14
+ }, c = (e, t, n = i) => {
12
15
  n.setState(`areas.${e}`, t);
13
- }, c = (e, t = r) => {
16
+ }, l = (e, t = i) => {
14
17
  t.setState("scheme", e);
15
18
  };
16
19
  //#endregion
17
- export { t as createThemeState, n as createThemeStore, r as default, i as resolveScheme, s as setAreaTheme, c as setMachineScheme, o as setThemeMode, a as themeFor };
20
+ export { t as createThemeState, r as createThemeStore, i as default, a as resolveScheme, c as setAreaTheme, l as setMachineScheme, s as setThemeMode, n as startingThemeState, o as themeFor };
@@ -1,10 +1,10 @@
1
1
  import { resolveScheme as e, setAreaTheme as t, setThemeMode as n, themeFor as r } from "./themeStore.mjs";
2
- import { useThemeStore as i } from "./ThemeScope.mjs";
3
- import { useCallback as a, useMemo as o, useSyncExternalStore as s } from "react";
2
+ import { useThemeState as i, useThemeStore as a } from "./ThemeScope.mjs";
3
+ import { useCallback as o, useMemo as s } from "react";
4
4
  //#region src/theme/useTheme.ts
5
5
  var c = "canvas", l = (c) => {
6
- let l = i(), u = s(l.subscribe, l.getState, l.getState), d = r(u, c), f = e(d, u.scheme), p = a((e) => c ? t(c, e, l) : n(e, l), [c, l]), m = a(() => p(f === "dark" ? "light" : "dark"), [f, p]);
7
- return o(() => ({
6
+ let l = a(), u = i(l), d = r(u, c), f = e(d, u.scheme), p = o((e) => c ? t(c, e, l) : n(e, l), [c, l]), m = o(() => p(f === "dark" ? "light" : "dark"), [f, p]);
7
+ return s(() => ({
8
8
  theme: d,
9
9
  resolvedTheme: f,
10
10
  setTheme: p,
@@ -772,8 +772,9 @@ export type SSRCompressionConfig = {
772
772
  /** Responses smaller than this many bytes go out uncompressed. Default 1024. */
773
773
  threshold?: number;
774
774
  /**
775
- * Brotli quality, 0–11, for a body compressed on every request — a page rendered for this request alone. Default 2:
776
- * measured on a quarter core, going to 4 cost a tenth of the pages a second to save half a kilobyte on each.
775
+ * Brotli quality, 0–11, for a body compressed on every request — a page rendered for this request alone. Default 5:
776
+ * the first quality under gzip's size for the CPU gzip spends — 2 came out larger than gzip on a 220 KB page (36 KB
777
+ * against 31; 5: 29). On half a core it costs ~0.1 ms a page, 5–8% of the pages a second of a 6 KB page.
777
778
  */
778
779
  brotliQuality?: number;
779
780
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plitzi/sdk-shared",
3
- "version": "0.38.8",
3
+ "version": "0.38.10",
4
4
  "license": "AGPL-3.0",
5
5
  "files": [
6
6
  "dist",