Skip to content

Releases: doeixd/foldkit-plus

v0.25.0

Choose a tag to compare

@github-actions github-actions released this 19 Oct 03:46

Concentric corners: buttons and fields round with the Card, Dialog, Toast or Alert holding them
(Theme.concentric), the Drawer gains a grip to drag it by, and a Calendar, a Slider and
Steps no longer spill a phone's card. foldkit-mixins 0.15.0 and foldkit-mixins-ui 0.14.0
change, and foldkit-plus is 0.7.0. Packages that pin one of them, or a package that does,
republish with a patch so their ranges cover the new versions (foldkit-builder, foldkit-cms,
foldkit-cms-drizzle, foldkit-composition, foldkit-mixins-builder, foldkit-mixins-crud,
foldkit-mixins-data-grid, foldkit-mixins-form, foldkit-mixins-richtext,
foldkit-mixins-surface, foldkit-primitives). Nothing written for 0.24 needs changing; a
control in a card is drawn with a smaller corner (below).

Added

  • foldkit-mixins/theme's Theme.concentric({ min, max }): a control's corner, concentric with
    the nearest container that nests (its corner less its inset), kept between min and max,
    and max outside any. Theme.nests now also publishes --fk-control-corner for it.

  • In foldkit-mixins-ui, buttons, the segmented tray and every field's chrome take
    concentric({ min: sm, max: md }), and the Card, Dialog panel, Toast and Alert nests, so the
    buttons and fields in them round with their corner (sm where the padding is deeper than the
    corner, as in the default theme's cards). control-round still makes a button a pill.

  • foldkit-mixins-ui's Drawer has a grip slot: more of the panel to drag it by, such as its
    row of tabs, where a vertical swipe drags and a sideways one still scrolls. A drag that starts
    there ends with no click to pass over, so the next press on the handle toggles it.

Changed

  • A button or a field inside a Card, Dialog, Toast or Alert is drawn with a corner concentric with
    the container's instead of radius-md: with the shipped scale, radius-sm.
  • The Drawer's handle is a 44px target, drawn tight to its bar by negative margins, and the
    peek stays above a phone's home indicator (safe-bottom).
  • A Slider's mark labels at either end sit flush with the track's ends instead of centered on
    their dots, hanging half past the track.
  • A horizontal Steps row narrower than 17rem draws the current step's title and description on
    a line of their own under the markers, the lines between them even, instead of squeezing them
    beside the current marker.

Fixed

  • A Calendar's month in a container narrower than seven cells shrinks its days, which stay round,
    instead of spilling past the container.

v0.24.0

Choose a tag to compare

@github-actions github-actions released this 19 Oct 00:55

Themes: hard shadows and a relief for buttons and fields (Theme.hardShadows, Theme.relief),
type knobs (text-scale, heading-scale, leading, the heading's weight and tracking), a pill
control corner, and a Drawer docked to the bottom of the screen. foldkit-mixins 0.14.0 and
foldkit-mixins-ui 0.13.0 change, and foldkit-plus is 0.6.0. Packages that pin one of them, or
peer on it, republish with a patch so their ranges cover the new versions (foldkit-cms,
foldkit-cms-drizzle, foldkit-composition, foldkit-mixins-builder, foldkit-mixins-crud,
foldkit-mixins-data-grid, foldkit-mixins-form, foldkit-mixins-richtext,
foldkit-mixins-surface, foldkit-primitives). Nothing written for 0.23 needs changing; a
Typography display is set a hair tighter (below).

Added

  • foldkit-mixins/theme's Theme.hardShadows: the shadow scale drawn as solid offset copies
    with no blur, for retro and brutalist themes. Compose it over Theme.tokens;
    shadow-strength still fades it.
  • A control's relief: Theme.tokens gains shadow-raised, shadow-pressed and
    shadow-field, flat by default, and foldkit-mixins/theme's Theme.relief gives them depth
    (soft, hard, or bevel's lit and shaded edges). In foldkit-mixins-ui, a solid, outline
    or primary Button stands out by raised and is pressed in by pressed while held or on; ghost
    and icon buttons stay flat; and every field's chrome (Input, Textarea, Select, Listbox,
    Combobox, DatePicker, NumberField, TagsInput, OtpField, CascadeSelect, InputCopy, the
    pagination's page size, Checkbox and RadioGroup) sinks by field.
  • Type knobs in Theme.tokens: text-scale scales every size of the type scale,
    heading-scale how far the headings stand above the body, and leading the line heights;
    weight-heading and tracking-heading set what a heading is drawn in. At their shipped values
    every size, line height and weight draws as before. foldkit-mixins-ui's Typography headings and interface roles, the Dialog's title and
    the Empty title now read font-heading, weight-heading and tracking-heading, so a theme's
    heading font reaches them.
  • foldkit-mixins-ui's Drawer and Recipes.Drawer: a panel docked to the bottom of the
    screen that peeks or opens beside the page, not over it, as a tool tray. Its handle drags it
    (a flick or a quarter of the way settles it) and a click or Enter toggles it; the handle's bar
    bends into a chevron pointing up as it goes down, with the finger while dragged. dock: 'always',
    or below-lg / below-xl, above which it is the column it sits in.
  • radius-control and the control-round knob: a Button and a Segmented tray round to a pill at
    1, whatever the radius factor, while fields keep radius-md.

Changed

  • foldkit-mixins-ui: Typography's display takes the heading tracking (-0.01em by default),
    as the other headings already did.

Fixed

  • foldkit-composition and foldkit-mixins-surface declared their foldkit-mixins peer as
    ^0.11.0, which no release since 0.11 satisfies; they now peer on the version they ship with.
  • foldkit-mixins: an element holding several Mounts no longer logs "unhandled failure" for each
    as it is removed; a Mount that ends interrupted is torn down, not failing.

v0.23.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 04:38

Mobile and touch: hover that no longer sticks after a tap, a pressed state for every control,
44px targets on a touch screen, safe areas, the on-screen keyboard, holds and pinches, and
fixes for the Sheet's drag and the editor's caret keys. foldkit-mixins 0.13.0,
foldkit-mixins-ui 0.12.0, foldkit-primitives 0.12.0, foldkit-richtext-dom 0.6.0 and
foldkit-mixins-form 0.7.0 change; foldkit-mixins-data-grid 0.2.4 is fixes. Packages that
pin one of them republish with a patch to re-pin (foldkit-builder, foldkit-cms,
foldkit-cms-drizzle, foldkit-mixins-builder, foldkit-mixins-crud,
foldkit-mixins-richtext), and foldkit-plus is 0.5.0. Changes that can break code written
for 0.22: a Table without fluid is wrapped in its frame; the ImageCropper's zoom Mount is
ImageCropperZoom; the Menu's and the Toast's Models gain fields; and an editor edit that
changes nothing returns a RichText.answer Command, which a Scene test resolves.

Added

  • foldkit-richtext-dom/editor's answerEditor(hostId) and the attachment's answered():
    the editor bundle answers every edit its editor asks for, once drawn or refused, with a
    RichText.answer Command. A Scene test that sends an edit which changes nothing now
    resolves that Command, and an application that replaces the editor's RichText.patch
    with its own runs its patch before the editor's other Commands.
  • foldkit-primitives/dom's KeyboardInset Mount (and keyboardInset, KEYBOARD_INSET): the
    on-screen keyboard's height as --fk-keyboard-inset on its element, from the visual
    viewport. foldkit-mixins-ui's Dialog.keyboard mixin runs it on a dialog's or sheet's
    panel, and the Dialog and Sheet recipes keep the panel above the keys: iOS Safari, and
    Chrome on Android, leave a fixed panel under them when a field in it takes focus.
  • foldkit-mixins-form: FieldAttrs takes autocomplete, inputMode, enterKeyHint,
    autocapitalize and spellcheck, for text, multiline and number fields; an email, tel or
    url type turns capitalizing and spellchecking off by default.
  • foldkit-mixins: a safe token group, Theme.ref.safe.top / right / bottom / left:
    what a notch, rounded corners or the home indicator take from each screen edge
    (env(safe-area-inset-*), 0 unless the page's viewport meta says viewport-fit=cover).

Changed

  • foldkit-mixins: a rule whose selector hovers is written for a pointer that can hover
    (@media (hover: hover)), with a copy for one that cannot that keeps every other branch
    (:is(:hover, :focus-within) still shows on focus there). A touch screen keeps :hover on
    what was tapped last, so a hover fill stayed behind after the finger left. Class names do
    not change.
  • foldkit-mixins: Defaults.reset draws no tap highlight of the browser's own, sets
    touch-action: manipulation on interactive elements (a second quick tap is not a zoom),
    and text-size-adjust: 100% in place of none, which also turned off the reader's own
    text size. Defaults.links and Defaults.controls hover only where the pointer can, and
    show :active.

Fixed

  • foldkit-mixins: a control's words are no text to select: Defaults.reset sets
    user-select: none on buttons, summary, and the button, tab, option, menu item, switch,
    checkbox and radio roles, so a long press on one no longer selects its label and offers to
    copy it on a phone, nor a double tap a word of it. A tree's rows and a grid's cells keep
    theirs.
  • foldkit-mixins-ui: a Toast stack under a finger holds its countdown without spreading out
    (a new touch holder in its Model): a stack spread as a tap landed, or as a swipe began,
    moved what the finger was on, and the focus Android gives a tapped action spread it too. Its
    close and action buttons have a finger's target where the pointer is coarse.
  • foldkit-mixins-ui: an ImageCropper zooms by two fingers, spread or pinched (Pinched): its
    viewport took the page's own pinch away and gave none back. Its zoom Mount is now
    ImageCropperZoom, for the wheel and the fingers both.
  • foldkit-primitives: PointerDrag drags by touch. A finger's press is a drag once held
    still HOLD_TO_DRAG_MS (400ms), and one that moves HOLD_SLOP (8px) first is a scroll, so a
    list of draggable rows still scrolls; once the drag is on, the page is kept still and
    Android's own menu shut. Before, the browser took every finger's drag for a scroll and
    cancelled it, so the Builder's palette, layers and canvas could not be dragged on a phone.
  • foldkit-mixins-ui: a context menu opens on a touch screen. A finger or a pen held on
    Menu.target's area for Menu.HOLD_MS (500ms) opens it under the finger, since iOS fires
    no contextmenu, while a finger that moves 10px is a scroll and opens nothing; Android's
    own contextmenu for the hold opens it once, under the finger, as pointTarget now records a
    finger's press. The Menu's Model gains holding and hold.
  • foldkit-mixins-data-grid: the fill handle takes its drag on a touch screen (touch-action: none), where a finger panned the grid instead, and it and the column resize grip have a
    finger's target there (44px and 24px) around what they draw.
  • foldkit-mixins-ui: a Carousel's autoplay pauses while a finger is on it and goes on when
    it lifts; a tap's emulated mouseenter held it paused until something else was tapped.
  • foldkit-richtext-dom: a press on a block's handle is a drag only once it moves 5px
    (DRAG_THRESHOLD): a tap's wander, or the page scrolling under a still finger, dropped the
    block.
  • foldkit-mixins-ui: a Combobox's and the Command's field ask a phone's keyboard not to
    capitalize or correct what filters, and to show a search key (autocapitalize,
    autocorrect, spellcheck, enterkeyhint).
  • foldkit-mixins-ui: a Table always stands in its frame, which scrolls sideways when the
    table is wider than the screen (the default static header; a sticky one keeps sticking to
    the application's scroller). Breaking for markup: a Table without fluid is now wrapped
    in the frame's div.
  • foldkit-mixins-ui: scrolled to its end, a swipe on a Dialog or Sheet panel, a popup list,
    the Command list or the Sidebar's nav no longer moves the page behind
    (overscroll-behavior: contain); a popup list is at most 40% of the screen a phone's
    keyboard leaves; menu, listbox and HoverCard panels are never wider than the screen.
  • foldkit-mixins: user-select is written with -webkit-user-select beside it, which iOS
    Safari still reads alone, so a long press on a drag surface no longer selects its text there.
    The recipes' drag surfaces (sliders' dials, the colour area, the cropper, the signature pad,
    splitters, the toast's body, the Sheet's handle, the FloatingPanel's grips) also set
    -webkit-touch-callout: none.
  • foldkit-mixins-ui, foldkit-mixins-data-grid: the OTP input, the colour picker's fields
    and the grid's cell editor are 16px or more on a touch screen, where iOS zoomed the page into
    them.
  • foldkit-mixins-ui: on a touch screen the recipes' controls are as large as a finger
    needs, 44px: Defaults.reset sets --fk-touch-floor where the pointer is coarse, and a
    control's height on the size ladder is at least that (buttons, icon buttons square, fields,
    selects, tabs, segmented items, menu and list rows, accordion triggers, calendar days,
    carousel, alert and chat actions). A desktop keeps the ladder's density, and a region that
    must stay dense sets the floor to 0px.
  • foldkit-mixins-ui: Toast stacks and Dialog panels keep clear of the notch and the home
    indicator: each edge a stack sits at is held off by the screen's inset there, and a panel's
    margins and largest size leave every inset out.
  • foldkit-mixins-ui: a tap shows. The recipes' hover is also their pressed state
    (:is(:hover, :active)), as are the hover fills of menu, listbox and tree rows, nav and
    sidebar items, accordion triggers, table sort buttons, steppers, tag removers and pressable
    cards and items: with hover written only where a pointer can, a finger on one of them
    shows it, and lifting takes it away.
  • foldkit-mixins-ui: a Sheet grabbed while its Dialog was still opening (an animation
    ending, a SucceededShowDialog) lost the drag, and its handle took no new press until the
    pointer was let go. A drag now ends only when the Dialog opens or closes. (#186)
  • foldkit-richtext-dom: a caret key pressed before an edit was drawn moved the caret
    through the page as it was: three fast Enters and an ArrowUp went two lines up. Caret keys,
    and edits typed behind them, wait until the edits before them are drawn. (#187)

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 22:35

A component library worth building on, and a richer rich-text editor.
foldkit-mixins-ui 0.11.0 grows from the parity components to the whole UI
plan: the polish pass over every component (state colour, concentric corners,
the top layer, overlay scroll bars, right to left), the merges into one Alert,
Dialog, Sheet, Menu, Slider and date system, and chat (ChatMessage,
MessageScroller, Thinking Indicator, Thinking Steps, Questionnaire) and Zag's
long tail (Angle Slider, Timer, Marquee, Image Cropper, Signature Pad, QR Code,
Chart, Cascade Select, Floating Panel, Tour). foldkit-mixins 0.12.0 for the
state ink, nests/nested(), surface.field, the shadow and chart tokens;
foldkit-primitives 0.11.0 for ScrollBars, Swipe, ScrollSettle,
PointerPosition and TrackBox; foldkit-richtext 0.4.0,
foldkit-richtext-dom 0.5.0, foldkit-mixins-richtext 0.4.0 and
foldkit-richtext-markdown 0.3.0 for the editor's changes below;
foldkit-remote-server 0.15.0 for RemoteServer.memory's entities and
optional principal; foldkit-auth 0.1.1 and foldkit-ssr 0.7.1 for Fetch
Metadata on a request with no Origin; foldkit-mixins-data-grid 0.2.3 for
the motion tiers; and foldkit-plus 0.4.0. Every package that pins one of
them republishes with a patch to re-pin: foldkit-builder 0.3.3,
foldkit-cms 0.7.3, foldkit-cms-drizzle 0.6.6, foldkit-mixins-builder
0.3.3, foldkit-mixins-crud 0.7.3, foldkit-mixins-form 0.6.2,
foldkit-remote-drizzle 0.12.3, foldkit-richtext-code 0.2.1,
foldkit-richtext-code-shiki 0.2.1 and foldkit-site 0.4.1.

Changes that can break code written for 0.21 are marked "Breaking" in the
entries below; most are in foldkit-mixins-ui and the rich-text packages.

Added

  • foldkit-primitives/dom: TrackBox. A Mount that follows the element
    named by its data-target and writes its viewport box (and, asked, its
    corner radius) as --fk-<name>-x, -y, -w, -h and -radius, telling
    TrackedTarget { target, found }; the Tour's cutout now draws with it
    (its Spotlight Mount is gone, its properties are --fk-tour-w and -h,
    and its ring follows the target's corner).
  • foldkit-mixins-ui: Calendar options, presets and a locale. The
    fourth argument of Calendar.toView, inputs and resolve
    (CalendarOptions) takes weekNumbers (ISO weeks), caption: 'label' or
    month and year selects (dropdowns, answered by Calendar.show),
    paging with Calendar.alongside for two months side by side, and a
    range's preview under the pointer. Presets are Calendar.lastDays,
    nextDays, monthOf, day and presetsView; Calendar.localeOf(tag)
    reads upstream's locale from Intl; the recipe takes outside: 'hidden'.
  • foldkit-mixins-ui: Tabs, Segmented, Breadcrumb and a navigation menu
    with panels.
    Tabs take icons and counts (label and icon slots, a
    Badge after the words), overflow: 'scroll' (one line, its edges
    fading), size: 'lg', a vertical tablist's rule at its inline end, and
    closable tabs (TabsContext.close: a close button and Delete; answer with
    Tabs.closing). A Segmented option takes an icon, alone with
    iconOnly; the recipe adds tray: 'underline', width: 'fill' and size: 'lg'. Breadcrumb's collapse: { max, menu } makes the ellipsis open a
    Menu of the hidden steps (Breadcrumb.menuRows, Breadcrumb.chosen).
    Nav.view draws a navigation menu whose triggers open panels of link
    columns in the top layer, with the APG's disclosure-navigation keys, its
    open panel in Nav.init/Nav.update; the recipe adds indicator: 'pill'
    and a column.
  • foldkit-mixins-ui: Steps, Accordion, Table, Progress, Rating and
    Resizable grow.
    Steps take marker: 'dot', connector: 'progress' with
    the view's progress, and size on the Avatar's steps. The Accordion
    takes variant (plain, bordered, separated, filled, ghost),
    separators, indicator: 'plus', indicatorPosition: 'start', active
    and its own icon. Table sorts (sortKey, sort: { by, onSort },
    aria-sort, Table.nextSort), chooses rows with checkboxes
    (selection), opens a row's detail below it (expansion) and stands an
    empty state across itself, all the application's; the recipe adds
    rows, density and header: 'sticky'. Progress takes showValue, a
    value of stacked sections, a buffer and segments, and the recipe
    tone, stripes and size. Rating takes precision: 0.5, a read-only
    fraction, onClear, showValue, and Home and End (Rating.Ends); a
    read-only rating takes no onChange; the recipe adds glyph and an
    error tone. Resizable collapses a panel (collapsible, collapsedTo)
    on Enter or a double-click, nests either way, and handle: 'grip' shows
    a pill of dots.
  • foldkit-primitives/dom: ScrollSettle, a Mount that reports the
    item nearest a scroller's start once a scroll rests (scrollend, or a
    quiet scroll where it is missing), right to left from the right edge.
  • foldkit-mixins-ui: a custom Select, and Combobox chips, clearing and an
    empty panel.
    A select drawn over Listbox: Listbox.parts draws an
    option's icon, label, description and check, and the trigger's value (or
    its placeholder, muted) and chevron; Recipes.Listbox gains check
    (end, start, none), trigger (outline, filled, ghost) and size
    lg. The Combobox takes chips (each chosen value a chip in the field,
    its remove button choosing it again, which a multiple combobox toggles
    off), clearContent and clearLabel (a clear button while the field has
    text) and empty (a polite panel in the list's place with nothing to list,
    a loading line too); Combobox.parts draws an option with the typed text
    marked. ComboboxChipRender and ComboboxExtraInputs are exported.
  • foldkit-mixins-ui: TagsInput's max and refusals, PasswordInput's
    strength and rules, InputCopy's reset.
    TagsInput.init({ max }) holds at
    most max tags; a commit that adds nothing, or not all of the draft, is a
    Refusal (Repeat, Empty, Full), said in a polite message slot
    (refusalText words it) with a one-time shake that travel stills.
    PasswordInput takes strength (a Meter), requirements
    (PasswordRequirements listed under the field, each read as met or not)
    and capsLock: { on, onKey }, a polite hint while Caps Lock is on, read
    from each key by capsLockOf. InputCopy gains a Model (init({ resetAfter }), default 2000ms) and update: Copied shows the value as
    copied and starts Reset, which sets it back to "Copy" unless a later copy
    came first.
  • foldkit-mixins/theme: shadows tinted by shadow-h and shadow-c.
    Theme.oklch({ shadow: { h, c } }) sets two knobs every shadow reads,
    defaulting to the neutrals' hue at twice their chroma, so shadows take the
    page's hue rather than a neutral black.
  • foldkit-mixins-ui: Card, Avatar, Separator, Skeleton, Spinner, Item and
    Empty grow their looks.
    Card takes elevation (0 to 3, a step of
    the surface ladder: lighter in a dark scheme, a contact and an ambient
    shadow in a light one) and lift: 'hover' (a lift under the pointer,
    times travel); Card.overlay is the one stretched press control a
    pressable card or Item draws. Avatar takes src, initials, status
    and statusLabel; Avatar.group({ people, max, label, moreLabel }) draws
    overlapping avatars and counts the rest as one more (AvatarGroupSlots,
    Recipes.AvatarGroup({ overlap: 'tight' | 'loose' | 'none' })), and
    Recipes.Avatar gains sizes xs and xl, shape (circle, rounded,
    square), color: 'name' (a hue from the name) and ring. Separator
    takes label and decorative, and the recipe line (solid, dashed,
    dotted), thickness, spacing and inset. Skeleton gains lines,
    avatarRow, card and tableRow({ columns }), and animation (pulse,
    shimmer, none). Spinner takes showLabel, and the recipe kind
    (ring, dots, bars, pulse, orbit), size and tone (accent,
    neutral, current). Item is the row primitive: press, label,
    selected and disabled, Item.group for a list (ItemGroupSlots,
    Recipes.ItemGroup({ layout: 'divided' | 'separated' })), and the recipe's
    variant (plain, outline, muted) and media (plain, icon,
    image). Empty takes media (icon, illustration), frame (none,
    dashed, filled), tone (neutral, danger) and size.
  • foldkit-mixins-ui: menu check rows, groups and shortcuts; Command pages
    and hints; a Toast component.
    A Menu row may be a CheckRow (check: 'checkbox' | 'radio', checked): choosing it sends Selected and leaves
    the menu open, the application keeping checked. Any row may name a
    group (a heading, and a separator between groups), a shortcut (keys
    drawn as Kbd with kbd, named in aria-keyshortcuts) and tone: 'destructive'. A Menubar's menus take the same rows, and Menubar.init(ids, { isAnimated, isModal }) passes both to every menu. A Command row takes
    icon, description (matched by the query) and opensPage; the view
    takes page: { trail, onBack } (Backspace in an empty field goes back),
    loading, hints for a footer of keys and kbd; Command.hotkey(message)
    is ⌘K or Ctrl+K anywhere, and Recipes.Command({ frame: 'bare' }) sits in
    a dialog. Toast is now a component: init, show, settle, dismiss,
    update and view. Toasts stack after Sonner's, spread out when held,
    pause while the pointer or focus is on the stack or the page is hidden
    (keeping the time left), show three at most, swipe away toward their
    edge, and are spoken in a polite or, for an error, an assertive region.
    settle turns a loading toast into its outcome, a promise toast; an
    action sends Acted with its value. Recipes.Toast({ tone: 'rich' })
    tints each ty...
Read more

v0.21.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 01:11
23c6526

Authentication through Yielded Auth. foldkit-auth 0.1.0 is new;
foldkit-remote 0.18.0, foldkit-remote-server 0.14.0, foldkit-sync
0.12.0, foldkit-guard 0.3.0, foldkit-agent-mcp 0.7.0, foldkit-ssr 0.7.0,
foldkit-site 0.4.0 and foldkit-plus 0.3.0 for the changes below, and
foldkit-primitives 0.10.2 for a corrected doc comment; every package that
pins one of them republishes with a patch to re-pin.

Five changes can break code written for 0.20:

  • serveFetch's and defineDocumentHost's resolvePrincipal returns an
    Effect, refusing with RemoteUnauthenticated; a resolver that throws is a
    500, where it was a 401 carrying its message.
  • foldkit-agent-mcp's authenticate returns an Effect refusing with
    AgentMcp.unauthenticated(), where it returned the principal or undefined.
  • Guards.declare requires unguarded: 'allow' | 'deny'.
  • SSR.entry throws for a plan with a server fallback and no origins.
  • Remote.http reads every 401 as Unauthenticated and every 403 as
    Forbidden, whatever the body says, so a view that compared other tags for
    them sees these instead.

Added

  • foldkit-sync/journal: documentHost, a document's Sync host for any
    runtime.
    It answers an upgrade request before a socket opens: refused
    with the Response to send (401 for a refused principal, 500 for a
    resolver, layer or journal that broke), or accepted with serve for the
    opened socket and abandon for one that never opens, with revalidate,
    opens, admit and settle as defineDocumentHost has them, and
    layer required exactly when the resolver needs a service. defineDocumentHost is now built on it,
    and a runtime without WebSocketPair is a 500 that resolves no one.

  • foldkit-auth: the client repeats whom it was answered as.
    AuthServer.answered(config) (the resolver's config, with its key) is
    serveFetch's headers, naming each answer's principal in
    x-foldkit-subject; believing() from foldkit-auth is a fetch for
    Remote.http/httpWithLive that repeats it, so once another tab switches
    account a read is refused with SUBJECT_CHANGED rather than answered as
    the new account. Any 401 makes it believe no one, and an answer to a
    request sent before it (or before forget(), for this tab's own sign-in
    and sign-out) is not believed. The subject is URI-encoded.

  • foldkit-remote-server: serveFetch takes headers: principal => …,
    added to every answer to that principal, a live stream's included.

  • foldkit-auth (early, 0.1.0): a Yielded Auth session as the principal.
    AuthServer.resolver({ auth, http, principal }) from foldkit-auth/server
    is a resolvePrincipal for serveFetch: it reads the session cookie Yielded
    set (named from the same Http.make options), verifies it with the
    application's Auth service, and builds the principal with the
    application's principal. No cookie is a visitor; a cookie on a request
    without a trusted Origin and Yielded's CSRF header, a cookie that no
    longer verifies, two session cookies, or an x-foldkit-subject header
    naming someone else is a 401 Unauthenticated; http naming something
    that is not an origin throws at once. With requests: 'browser' it serves
    what a browser sends on the page's behalf, defineDocumentHost's upgrade
    or a posted form, where a trusted Origin alone vouches for the cookie,
    since neither carries a CSRF header; SUBJECT_HEADER and subjectSaid,
    from foldkit-auth, are what a client sends. Also re-exported as
    foldkit-plus/auth and foldkit-plus/auth/server, an optional peer.

  • foldkit-sync: defineDocumentHost takes layer: env => Layer for its resolver.
    resolvePrincipal may need a service (a session store), which layer
    provides; it is required exactly when the resolver needs one, built per
    upgrade, kept while the socket is open for revalidate, and closed at once
    for a refused upgrade.

  • foldkit-site: access, who may be shown a page. A node's access: { allow, otherwise } covers it and the nodes below it;
    Site.accessOf(site, route, who) answers Access.Allowed, Pending
    while who is unknown, or Denied({ url }) with otherwise's address for
    what was asked. Presentation for the client and a server's 303; the server
    guards the data regardless. An otherwise whose target the same rule
    covers throws (a sign-in page mounted under it would loop with a growing
    returnTo), and a rule in a node's options names its reader's type.

  • examples/auth: Yielded Auth end to end. Password sign-in and
    sign-out through Yielded's own client and routes, a guarded notes list
    (an admin reads every note, a member their own, a visitor none), Me for
    "signed in as" and an admin line, and a change of principal carried to the
    other tabs; a notes page Site.access sends a visitor away from, server
    rendered as the request's reader; a Sync board whose socket is opened
    with the session cookie, served on Node by documentHost; unit, mutation
    and Chromium e2e tests, the e2e across two tabs and a server restart.

  • foldkit-remote: RemoteData.denied(error), the denial a failure
    was, a Denied (Unauthenticated or Forbidden, with the server's
    reason; not a mutation's refusal), typed,
    or none for any other failure: a RemoteError's _tag is open, so a view
    had to compare strings to tell "sign in again" from "could not load".

  • foldkit-guard: Me, the visitor as an Entity. Guards.me(G, { interactions }) declares one row, me, that everyone reads and no one
    writes: signedIn, key (the principal's declared key) and may for the
    named interactions; GuardServer.me(Me, Policy) serves it, counts for
    validate as applying its rules, and refuses a Policy of another set when
    it is made. Guards.anyone is the rule everyone passes, a visitor
    included, for a public surface under unguarded: 'deny': a surface naming
    it restricts no one, for Sync documents and shared fields too, and
    Guards.all now takes at least one rule. Policy.key is declare's key
    (G.key), for a seam holding the Policy. AuthServer.resolver takes
    key: Policy.key to compare x-foldkit-subject with it.

  • foldkit-ssr: a posted form's own resources. SSR.entry takes
    resources: request => Layer and SSR.handle resources: Layer, built
    once for the post and provided to the Commands its fallback runs beside the
    config's resources; where both provide a service, the post's is used, so
    a Command reads as who posted. SSR.entry's origins names where a form
    may be posted from: any other Origin is a 403 before the body is read or
    flags and resources run (Origin: null counts as the site's own when
    Sec-Fetch-Site says same-origin), and a plan with a server fallback
    made into an entry without origins throws, since a post runs flags and
    every resources as whoever posted.

  • serveFetch and defineDocumentHost take revalidate: { every, key? }. While a live stream or a socket is open, the resolver is asked again,
    of the request it opened with: a refusal ends the stream with
    Unauthenticated (an event: error frame the client reads back as it) or
    closes the socket with 4401, and a principal whose key (as liveHub's,
    Policy.keyOf with guards) changed ends the
    stream as a live error, or closes the socket with 1012, to be opened again
    as the new principal. A revoked session stops being served within one
    interval; the clients do not yet tell these closes apart, so a replica
    reconnects after a 4401 too, and is refused at the upgrade.

  • foldkit-guard: Policy.provide(context), a Policy whose bodies have
    the services they need provided, for the read seams
    (GuardDrizzle.visible, GuardServer.memory, GuardSync), which take a
    Policy needing nothing more. A seam built from it counts as built from the
    Policy it came from, for GuardServer.validate.

  • foldkit-remote: RemoteUnauthenticated (_tag: 'Unauthenticated',
    with an optional reason), the refusal of a caller who could not be told,
    beside RemoteForbidden; RemoteJsonAnswer carries it as
    unauthenticated: { reason? }. foldkit-remote-server's
    RemoteServer.unauthenticated(reason?) makes one.

  • foldkit-remote: every call kind fails with Unauthenticated on a
    401.
    Reads, queries, mutations and live streams declare it in their RPC
    errors and RemoteClient's types; Remote.http and liveFetch read a 401,
    Remote's own (with its reason) or one from middleware in front of it, as
    it, and Data.mutation, ReadFailed and QueryFailed carry
    error._tag: 'Unauthenticated'. Data.satisfy and prefetch can fail with
    it, for a server render to answer as it answers a lost session.
    foldkit-remote-server's answer sends a handler's as a 401, and
    serveFetch ends a live stream with it as an event: error frame the
    client reads back.

Changed

  • foldkit-agent-mcp: authenticate is an Effect. authenticate: request => Effect<Principal, Unauthenticated>, so it may ask a token store;
    where it returned Principal | undefined. Failing with
    AgentMcp.unauthenticated(reason?) (or Remote's RemoteUnauthenticated,
    of the same shape) is a 401 carrying reason; a defect or a throw is a 500
    that says nothing to the caller and is logged. Wrap
    a plain lookup: request => Option.match(lookup(request), { onNone: () => Effect.fail(AgentMcp.unauthenticated()), onSome: Effect.succeed }).

  • foldkit-guard: Guards.declare requires unguarded. What a guarded
    Entity's surface with no rules decides is written down rather than
    defaulted to 'allow'. Pass unguarded: 'allow' to keep what an omitted
    one did; 'deny' refuses such a surface. Anything else, an omission from
    a caller without types included, throws at declare.

  • **`...

Read more

v0.20.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 23:33

foldkit-entity 0.10.0, foldkit-form 0.6.0, foldkit-bundle 0.8.0,
foldkit-surface 0.10.0 and foldkit-remote 0.17.0 for the changes below;
every package that depends on one of them republishes with a patch to re-pin.
foldkit-metadata and the three rich-text model packages are unchanged.

Three changes can break code written for 0.19:

  • A predicate or ordering term over another Entity than the query's no longer
    compiles.
  • An own update in an assembly with Data.wiring no longer receives Remote's
    Messages, so arms that handled them are excess.
  • A test that matched a form's check as an instance by args: { key } matches
    form.Check instead.

Added

  • foldkit-entity: a predicate over another Entity is a compile error.
    Each Expr constructor's result carries the names of the Entities its
    fields belong to (Reads<Names>, type-only), and Query.where refuses a
    query from another: a predicate reads Comment, but the query is from Post.
    Order.asc, desc and chosen do the same for Query.orderBy. The
    run-time check stays for a predicate typed plainly as Predicate. New
    public types: Reads, ReadsOf, and Invalid, which declarations naming
    these steps reach.
  • foldkit-form: form.Check, the Command a key's check runs as. A
    definition (Command.define('<form>.check', …)) rather than an inline
    Command, so a test resolves it with Command.resolve(form.Check, …) instead
    of hand-building { name: '<form>.check', args: { key }, effect }. Its args
    now carry the draft, the values and the subject too, so a test that matched
    the old Command as an instance by args: { key } matches it no longer: match
    form.Check, which compares by name.
  • foldkit-form: Form.input(schema), a plain form's input. A form that
    writes no Entity (a sign-up, a search, a login) took Entity.define and
    Entity.input over the same schema; Form.make('Search', Form.input(Search))
    is that in one call. The ports of Foldkit's form, auth and job-application
    examples use it.

Changed

  • foldkit-bundle: a wiring's own tags leave the parent's own update.
    Wiring takes a Claims parameter typing handles, and
    assembly.update(own) hands own a Message without the tags a wiring claims
    and does not share. Remote's wiring claims every RemoteMessage tag, so an
    own no longer needs if (Remote.reduces(message)) to narrow them away, and
    one that matches exhaustively fails to compile when Data.wiring is removed
    from assemble. An own that handled Remote's tags itself now gets none.
  • foldkit-entity: Expr.eq with a plain value on the left says to put the
    field there.
    The right side is typed from the left, so Expr.eq(3, field)
    was refused with 'number' is not assignable to 'Operand<any>'; it now
    reads Expr.eq takes the field on the left and the value on the right.

Fixed

  • foldkit-form: a filled optional key not checked yet is refused, not left
    out.
    engine.value counted an optional key whose draft was filled by
    fill but not yet validated as valid, and gave the value without it. Such a
    draft must now pass its own check. A submit was never affected: it validates
    every unchecked key first.

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 20:35

Every package with a Foldkit peer now asks for Foldkit 0.168, so each of them
takes a minor version, as do foldkit-entity 0.9.0 (and, or, not and
comparisons), foldkit-remote-drizzle 0.12.0 (compiling them),
foldkit-guard 0.2.0, foldkit-durable 0.9.0 and foldkit-react-codegen
0.3.0 (TypeScript 6 as well as 5). Republished to re-pin: foldkit-cms-drizzle
0.6.3 and foldkit-remote-server 0.13.3; foldkit-richtext-markdown 0.2.1
widens a dependency. foldkit-metadata, foldkit-richtext,
foldkit-richtext-code and foldkit-richtext-code-shiki are unchanged.

Three changes can break code written for 0.18:

  • Foldkit 0.168 itself: an application moves with it, renaming what 0.166 and
    0.167 renamed (read for toChildModel, persistentEntry, the Dom
    stream helpers).
  • GuardServer.validate refuses at startup a query body that filters or orders
    by a member with a Read rule.
  • A Behavior whose Mount fails no longer takes the element's other Behaviors
    with it; it is reported and the rest go on.

Added

  • foldkit-mixins: a reader's light or dark, before the first paint.
    Theme.schemeScript(key?) is a head script that applies the scheme kept in
    localStorage; Theme.chooseScheme(scheme, key?) applies and keeps one
    ('system' removes it); Theme.currentScheme() reads it back. The docs site
    has an Auto/Light/Dark choice built on them.

  • foldkit-sync: the browser asks before leaving while an edit is unsaved.
    Sync.mount shows a durable edit before it is stored; a reload in between
    lost it. From the first such edit until the last is stored, beforeunload
    asks the reader first.

  • Public types a dependent's declarations need. A library built on these
    packages could not emit declarations under TypeScript 7 for a value whose
    inferred type reaches a type it cannot name. The package indexes now export
    them: foldkit-mixins AttributeName, EventName, RequirementName,
    HiddenOf and SlotRecipe; foldkit-bundle PlacedBy, CollectionBy,
    WithoutResources and RuntimeResult; foldkit-agent CapabilitiesByName,
    CapabilitiesByTag, their Any forms, DefinitionOf and AnyCompletion;
    foldkit-data-grid EditableId. An interface that shares its namespace's
    name is exported as a shape: CapabilityShape, SlotViewShape,
    BundleShape, JournalShape.

  • foldkit-guard: GuardServer.validate refuses a query body that filters
    or orders by a member with a Read rule.
    The row comes back without the
    member, but which rows match, and in what order, still tells what it holds;
    with comparisons a client could bisect it (cost < $max).

  • foldkit-entity: Expr.and, Expr.or and Expr.not. The connectives,
    with SQL's three-valued meaning: or takes true over unknown, and false,
    and not of an unknown stays unknown, so a null matches neither a
    comparison nor its not. and and or need an operand and flatten one of
    the same kind. Expr.whenGiven(input, given => predicate) is a filter that
    applies only when a nullable input is given. evaluate runs them, and
    decided(predicate, input) is a predicate's truth from the input alone,
    when it reads no field. The conformance suite covers them.

  • foldkit-entity: comparisons, Expr.lt, lte, gt and gte. Numbers
    compare as numbers; text only under Collation.binary or asciiFold
    (declared on the field or passed) and against a field, refused where it is
    written otherwise, since backends order text by different defaults. A value
    compares in its encoded form, so a date stored as an ISO string is text. The
    evaluator compares as orderBy does, and the conformance suite covers them.

  • foldkit-remote-drizzle: comparisons compiled, the column first however
    the body wrote it, and text under its collation as keyset paging applies one
    (collate "C" on Postgres, collate binary or nocase on SQLite).

  • foldkit-remote-drizzle: and, or and not compiled, and an operand
    that reads no field decided per request, so whenGiven compiles to true
    when its input is null and to the predicate alone when it is given, with no
    parameter for the check.

Changed

  • TypeScript 7. The workspace typechecks and builds with TypeScript 7.0.2,
    the native compiler (a forced typecheck takes under a minute). Its DOM
    library declares the Navigation API, so foldkit-primitives no longer
    declares its own. foldkit-react-codegen peers on typescript@>=5.7.2 <7
    rather than exactly 5.9.3: it reads source through the compiler API, which
    TypeScript 7 does not ship.
  • Foldkit 0.168. Each package with a Foldkit peer asks for foldkit@^0.168.0 (and
    foldkit-mixins-ui on @foldkit/ui@^0.168.0), since they use what 0.166 and
    0.167 renamed: a lifted child is read as an Option (read, not
    toChildModel), the entry factories end in Entry
    (Subscription.persistentEntry, Port.subscriptionEntry), and the DOM
    Stream helpers are Dom's (Dom.streamFromEventFilterMap,
    Dom.streamFromKeyBindings; KeyBinding and KeySequence come from
    foldkit/dom). The examples build with Vite 8 and @foldkit/vite-plugin
    0.27.
  • Effect 4.0.4. The workspace builds and tests against effect@4.0.4 and
    its @effect/* packages at the same version. Published packages still peer on
    effect@^4.0.0, and foldkit-durable now depends on
    @effect/sql-sqlite-node@^4.0.0 rather than exactly 4.0.0, so an
    application chooses its 4.x. examples/livestore moves to
    @livestore/livestore 0.5.0-dev.1, which peers on effect@^4.0.3, so the
    workspace holds one Effect.
  • foldkit-mixins: one Behavior's failing Mount no longer stops the others
    on its element.
    The resolver merges an element's Mounts into one, and from
    Effect 4.0.2 a merge ends when any stream in it fails, so a Measure without
    a ResizeObserver took the canvas's Targets with it. Each fails alone now,
    reported as Foldkit reports a Mount ([OnMount Name] unhandled failure).

Fixed

  • foldkit-remote depends on foldkit-metadata, which its declarations
    name (import("foldkit-metadata").MetadataKey). Without the dependency the
    declaration build copied metadata's types into remote's; TypeScript 7
    refuses that, and the copy was a second set of the same types.
  • foldkit-sync: foldkit-remote is an optional peer again. The manifest
    declared peerDependenciesMeta twice, and the second, naming only
    foldkit-durable, replaced the first.
  • foldkit-durable: a database it cannot open fails as a JournalError.
    From @effect/sql-sqlite-node 4.0.1 opening the file can fail with a
    SqlError, which escaped the journal's declared errors.
  • foldkit-mixins: Theme.oklch's doc said a knob overridden on any
    subtree re-derives the palette.
    A custom property resolves where it is
    declared, so tokens on :root reach a subtree already resolved; the knob
    re-derives them only on the element that declares them (:root, a
    Theme.scoped selector, or a subtree that declares the theme itself).

v0.18.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 23:32

foldkit-site 0.2.0, foldkit-remote 0.15.0, foldkit-primitives 0.9.0,
foldkit-mixins 0.10.0, foldkit-mixins-ui 0.9.0, and foldkit-builder and
foldkit-mixins-builder 0.2.0 for the changes below, and foldkit-plus 0.1.0,
published for the first time. Republished to re-pin: foldkit-cms and
foldkit-cms-drizzle 0.6.2, foldkit-crud 0.7.2, foldkit-data-grid and
foldkit-mixins-data-grid 0.1.4, foldkit-mixins-crud 0.6.6,
foldkit-mixins-form 0.5.2, foldkit-mixins-richtext 0.2.4,
foldkit-remote-drizzle 0.11.2, foldkit-remote-server 0.13.2 and
foldkit-sync 0.10.2, each of which pins a bumped package. Every other
package is unchanged.

Two changes break code written for 0.17 (under Changed): a Site node's
shortcut is now a KeySequence, and a Builder's keys go through
keyPressed.

Added

  • foldkit-remote: Data.preload, prefetch from update. satisfy as a
    Command for a destination the reader has not reached (a hover over a link):
    it reads what the given Surfaces read in the Model you give it and yields one
    new Message, Preloaded, carrying the Messages that wrote it, so they reduce
    into the live Model as it is by then. It never fails, and refuses a Surface
    of another application when the Command is made. Remote.fold lifts it.

  • foldkit-site: head metadata from the tree. A node's meta (a function
    of its route and the Model, returning foldkit-ssr's Meta) and indexed
    flag, on Site.route or the Site.node builder. Site.metaOf(site, route, model) merges the route's chain root first, a deeper node's field replacing
    its ancestor's, the preview title falling back to the node's title, and an
    unindexed route noindex; it is an SSR plan's meta as it stands.
    Site.indexedOf reads the flag, which a node inherits from the nearest
    ancestor that declares it. foldkit-ssr is now a dependency, for the type.

  • foldkit-site: every address, and both directions, from the tree.
    Site.paths(node, list) lists a node's addresses from an Effect (with when
    each last changed), and Site.targets(site, paths) lists the whole site in
    tree order for a build, a sitemap or prefetch, refusing a node with params
    left unsaid. A tree's type now carries its routes: Site.parse(site, NotFound) is the application's URL parser and Site.hrefOf(site, route)
    builds an address back, refusing a route no node holds.
    Site.routeAt(site, url) is the route at an address, or None where no
    node takes it.

  • foldkit-site: Site.shortcuts, key bindings from the tree.
    Site.shortcuts(site, toMessage) is every node's shortcut as a
    Subscription.keyBindings binding sending the Message made of its
    landing target, refusing a shortcut with no landing or keys used twice.

  • foldkit-primitives: pointedLinks() in foldkit-primitives/dom, the
    address of each same-origin link the reader points at or tabs to, once
    while they stay on it: the trigger for reading a page ahead.

  • foldkit-site: Site.routing's arrived. What the application does
    once a new route is set and its routed pages are told, such as moving
    focus to what it drew; an echo of the shown address runs nothing.

  • foldkit-plus: every package in one install, and npx foldkit-plus setup.
    Each package's entry points are re-exported by subpath (foldkit-remote/port
    is foldkit-plus/remote/port), the namespaces most applications use from the
    root, and an adapter that needs a library of its own (React, Drizzle, Shiki,
    @foldkit/ui, Agent Native) is an optional peer, so none of those libraries
    is installed with it. setup prints, for the project it runs in, how to
    install Effect, Foldkit and Foldkit Plus with that project's package manager,
    which effect or foldkit version is wrong or missing, the agent skill, and
    which package does which job, written for a coding agent to follow.

  • foldkit-mixins: code colors in Theme.oklch. A syntax group colors
    each kind foldkit-richtext-code and foldkit-richtext-code-shiki name
    (syntax-keyword reads --fk-syntax-keyword), in hues the palette already
    has, readable in both schemes; syntaxChroma sets how colorful.

  • foldkit-mixins-ui: CodeBlock. Code with a title or language, line
    numbers and a copy button, its tokens (a foldkit-richtext-code tokenizer's
    { from, to, kind }) drawn by kind and colored by Recipes.CodeBlock from
    the theme's syntax group. The block's text is the code exactly.

Changed

  • foldkit-builder: a shortcut is judged in update. The layers and the
    canvas send KeyPressed for every key a command binds
    (PageBuilder.keyPressed), and update runs keyCommand against the Model
    as it is: a key pressed before the frame that drew a new selection deleted
    nothing, or the node selected before it. A bound key with nothing to do
    now has its default held back on those two. A view drawing a Builder by hand
    attaches keyPressed where it attached keyCommand, and a Builder handed
    to foldkit-mixins-builder's views must offer keyPressed too.
  • foldkit-site: Site.routing loads a link its tree does not hold. A
    tree is one application's document, so a click on an address of this
    origin that no node takes is a full load, where it was a Navigate Command
    that could only draw the application's NotFound.
  • foldkit-site: a node's shortcut is a Foldkit KeySequence. Write
    a sequence as an array (['G', 'H'], where it was 'GH') and one press as
    a string ('/', 'Mod+K'), as Subscription.keyBindings names keys.

v0.17.1

Choose a tag to compare

@github-actions github-actions released this 12 Oct 09:04

foldkit-entity 0.8.1, foldkit-remote-drizzle 0.11.1 and
foldkit-mixins-form 0.5.1 for the fixes below. Republished to re-pin:
foldkit-builder and foldkit-mixins-builder 0.1.2, foldkit-cms and
foldkit-cms-drizzle 0.6.1, foldkit-crud 0.7.1, foldkit-data-grid and
foldkit-mixins-data-grid 0.1.3, foldkit-form 0.4.3, foldkit-guard 0.1.1,
foldkit-mixins-crud 0.6.5, foldkit-remote 0.14.1, foldkit-remote-server
0.13.1 and foldkit-sync 0.10.1, each of which pins a bumped package. Every
other package is unchanged.

Fixed

  • foldkit-mixins-form: a locked key is posted with scripts off. It was
    drawn disabled, and a browser leaves a disabled control out of a form post,
    so a locked required key was missing and the save failed to decode; its
    value is also drawn as a hidden input.
  • foldkit-entity, foldkit-remote-drizzle: NUL is refused in eq and
    in, as in contains.
    Given text holding one, the evaluator and SQLite
    answered while Postgres failed the request; every interpreter now refuses it
    as the query's own error.

v0.17.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 07:04

foldkit-agent 0.7.0; foldkit-bundle 0.6.0; foldkit-cms 0.6.0;
foldkit-cms-drizzle 0.6.0; foldkit-composition 0.2.0; foldkit-crud 0.7.0;
foldkit-durable 0.8.0; foldkit-entity 0.8.0; foldkit-mixins 0.9.0;
foldkit-mixins-form 0.5.0; foldkit-mixins-ui 0.8.0; foldkit-primitives
0.8.0; foldkit-remote 0.14.0; foldkit-remote-server 0.13.0;
foldkit-remote-drizzle 0.11.0; foldkit-ssr 0.5.0; foldkit-surface 0.8.0;
foldkit-sync 0.10.0; foldkit-data-grid and foldkit-mixins-data-grid 0.1.2.
New: foldkit-guard and foldkit-site 0.1.0. Republished to re-pin:
foldkit-agent-a2a, foldkit-agent-mcp and foldkit-agent-native 0.5.2,
foldkit-agent-webmcp 0.6.1, foldkit-builder and foldkit-mixins-builder
0.1.1, foldkit-bundle-surface 0.3.2, foldkit-form 0.4.2, foldkit-mirror
0.5.2, foldkit-mixins-crud 0.6.4, foldkit-mixins-richtext 0.2.3,
foldkit-mixins-surface 0.5.3 and foldkit-richtext-dom 0.3.1, each of which
pins a bumped package. Every other package is unchanged.

Who may do what is declared once, and Remote places rows instead of
refetching them.
foldkit-guard declares guards on the shared domain and
enforces them on every seam: reads compiled into SQL, declared writes and
handlers checked before they land and answered as their writer may see the
row, Sync's cell edits, live updates and agents, with a startup check that
refuses a Source left unguarded. A write is declared as data (Write.update,
insert, delete) and served with no handler. A list whose query body
declares its order has a change placed in it with no request, checked against
the server under verifyPlacement. foldkit-site states a routed site's
topology once. And a review of this release's work fixed the ways a write or a
read could get past its rules, lose another author's edit, or send the server's
SQL to a client.

Upgrading from 0.16

  • journalExchange's refuse is admit (foldkit-sync), which answers as
    authorize does and may be an Effect; opens refuses a connection whole.
    defineDocumentHost takes both as functions of the principal, and its
    settle is (env, journal) => Effect.
  • foldkit-sync/entity's overlay helpers are gone (overlay, held,
    newlyHeld, settled, shows): RemoteEdits from foldkit-sync/remote
    shows the edits through Remote.
  • Remote.visibleItems is Data.visibleItems(remote, connection)
    (foldkit-remote), which draws a list as its reads do.
  • An OrderTerm is tagged Term, and a body's orderBy holds Orderings
    (foldkit-entity): an interpreter resolves Query.orderFor(body, input)
    first. foldkit-remote-drizzle refuses an orderBy beside a body that
    declares its order.
  • Cms.slugTaken and the CmsConflict: / CmsSlugTaken: message prefixes
    are gone
    (foldkit-cms): read a refusal with Data.refusal
    (Cms.refusal.field, Cms.refusal.conflict).
  • CmsServer.make takes a guard set (foldkit-cms-drizzle): policy and
    authors for isAuthor, transitions beside allow, and each content
    entry its guarded entity; published(column, isAuthor) is gone, bind with
    GuardDrizzle.visible. Transaction may fail with a RemoteServerError.
  • LiveHub.deleted may fail and needs the Sources' services
    (foldkit-remote-server), as changed does; it re-reads each subscriber's
    selection rather than deleting for all.
  • returning.row fails with a RemoteServerError (foldkit-remote-drizzle)
    when the database refuses it; run a handler's own statements through
    runStatement.

Added

  • foldkit-remote-server: fields every principal reads alike skip the live
    hub's re-read.
    A Source declares shared (RemoteServer.entity,
    RemoteServer.memory per entity, foldkit-remote-drizzle's source);
    hub.changed(ref, fields, values) sends a shared field's given value to
    each subscriber as it is and re-reads the rest, and the handlers give it a
    declared write's answer, the row as stored (a handler's answer is still
    re-read). A shared field the Source does not serve is refused when it is
    made. foldkit-guard: GuardServer.validate refuses a shared field a Read
    rule could tell readers apart by.
  • One editor for create and edit. foldkit-entity: an Option-typed
    input key maps itself to the field its value fits, as a nullable one does,
    so an input's id may be Schema.OptionFromNullOr(PostId). foldkit-crud's
    editor then saves a blank form with Option.none() and an opened one with
    its id. foldkit-guard: GuardServer.mutation's id may answer an
    Option, and none is a create, checked against the row's Create rule.
  • foldkit-agent: authorize may refuse with a reason. It answers
    { allowed: false, reason } (an AuthorizationDecision) beside a boolean,
    and the reason is the AgentAuthorizationError's message.
    foldkit-guard: may carries explained refusals. Its answer gains
    reasons, the sentence an explain gave each row interaction it refused,
    read with May.reason; GuardAgent.authorize refuses with it, so an
    agent learns why as a client's write would.
  • foldkit-entity, foldkit-remote: a list is fetched, not placed, when
    a row changes what the server's read rule filters on.
    ReadFilter.of(members)
    is Entity metadata naming the members a server filters rows by under a rule
    the client does not run; foldkit-guard's attach declares it from the
    row's Read rules. Remote gathers it per Entity name when the domain is
    defined (registry.filtered), so a query declared over the Entity before
    the rule was attached still sees it, and a row a list does not hold that
    changes one invalidates the list. A row it holds is judged by the body as
    before.
  • foldkit-remote-drizzle: a visible rule may answer with an Effect,
    and is given its own binding.
    (principal, self) => SQL | undefined | Effect<SQL | undefined, RemoteServerError>, so a rule that must ask
    something first (a guard's body) can, and one written before bind names
    columns through self.columns. Every path a table is read by applies it as
    before.
  • foldkit-remote-drizzle: source(binding, { filter }), the
    per-record read plan RemoteServer.entity takes, passed through. A source
    and a query carry their binding's visible, for a startup check.
  • foldkit-agent: withPrincipal(key), the principal's type taken from
    the Context key a server reads it from (G.Principal), so the agent's and
    the server's are one type. withPrincipal<P>() stays.
  • foldkit-crud: an editor locks the keys its row's reader may not set.
    Crud.editor(name, { form, mutation, locks }) loads the members locks
    selects beside the form's, and editor.at(...).locked(model) names the
    form's keys whose member (or relation) locks.locked refuses, for
    foldkit-mixins-form's locked. Nothing is locked for a new one, or
    before the row is loaded. foldkit-guard's May.locks is one.
  • foldkit-mixins-form: keys drawn but not editable. The view input
    locked: ['ownerId'] draws those keys disabled, every control kind (a
    many picker's choices included), for a key the person may not set. A key in
    a nested row is not locked by it, and a Bundle-backed key draws as its
    Bundle does.
  • foldkit-remote, foldkit-remote-server: a refusal of who is asking,
    end to end.
    A mutation Source fails with RemoteServer.forbid(reason?);
    the wire carries it as RemoteForbidden (_tag: 'Forbidden', reason
    only when given), RemoteServer.answer sends it as a 403 with
    { error, forbidden: { reason? } }, and Remote.json reads it back. A 403
    whose body is not Remote's answer, from middleware in front of the server,
    fails a mutation as Forbidden and any other call with the status.
    Data.mutation is Failed with the Forbidden error, and RemoteError
    carries reason.
  • foldkit-remote-server: a principal read from Context on each call, and
    a live hub keyed by person.
    RemoteServer.handlers(server, principal)
    takes a Context key for principal as well as a value, read by every read,
    query, mutation and live subscription, so one handler set (one RPC layer)
    answers every request and authentication provides the key per request; the
    key is added to what the handlers require. RemoteServer.liveHub(sources, { key }) shares a re-read between subscribers whose principals have one
    key, read as the first of them; without one, only the same value shares.
  • foldkit-remote-server, foldkit-remote-drizzle: a write answered as its
    writer may now see the row.
    EntityWriter.read, when a writer has one,
    reads a row as a principal may see it; RemoteServer.write answers through
    it, and a row the write hid from its writer answers in deleted. A Drizzle
    writer over a binding with a visible rule reads through it. A writer may
    fail with RemoteForbidden. A declared write's Source carries writes,
    the Entity and the writer, for a startup check.
  • foldkit-remote-server: EntitySource.visible and
    QuerySource.visible
    , the rule that decides which rows a source returns,
    as it was given one. The server never runs it; a startup check such as
    GuardServer.validate reads it. RemoteServer.memory's sources carry its
    readable.
  • foldkit-remote-server: what a principal sees, per record and per row.
    EntitySource.filter(principal, fields) returns a read plan: the fields to
    read (the allowed ones, and any the decision needs) and apply, one record
    as the principal sees it; a member it drops is settled like one the Source
    did not return. It runs for reads by id and live patches. RemoteServer.memory
    takes filter per entity, as it takes authorize, and readable (given a
    lookup of another row by id), which
    hides a row the principal may not read from reads by id, from every query,
    and fr...
Read more