Skip to content

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 06 Sep 07:13
· 28 commits to main since this release

One platform version — every image and every module inside it carries v0.4.0.

repository moved
core 21 commits
shell 24 commits
chat 4 commits
mail 12 commits
collab 3 commits

Modules

module was now
billing 0.5.2 0.5.16
chat 0.4.16 0.5.1
hr 0.23.1 0.23.7
inventory 0.5.1 0.5.3
mail 0.5.0 0.6.3
quire 0.16.3 0.17.1
tracker 0.11.16 0.12.1

billing 0.5.2 → 0.5.16

0.5.3 — release

Patch Changes

  • chore(mock): the demo plan stops promising single sign-on

0.5.4 — release

Patch Changes

  • 754b739: A plan's description and highlights read the right way round on a Persian or Arabic screen. They
    are free text an administrator typed, usually in English, and rendered inside a right-to-left block
    they came out reversed — "2 GB of storage" with the 2 at the far end. Each line now follows its own
    direction.

0.5.5 — release

Patch Changes

  • f022108: Coming back from a Checkout that started a trial, the billing screen says "Card saved — your trial
    has started; nothing is charged until it ends" rather than "Payment received", which was untrue for
    the fourteen days it was on screen.

0.5.6 — release

Patch Changes

  • b9c843b: The plan cards on the billing screen breathe again: the Choose button sat flush against the last
    highlight with the card's padding pooled beneath it, because the grid that was meant to space them
    was declared on the card itself, which is a block. The layout now lives on an element inside it.

0.5.7 — release

Patch Changes

  • 8295305: A plan's description and highlights keep the card's alignment on a Persian or Arabic screen while
    still reading in their own order. The previous fix (dir="auto" on each line) got the order right
    and left the lines as a left-aligned island inside a right-aligned card; the text is now isolated
    with <bdi> instead.

0.5.8 — release

Patch Changes

  • f5bc572: The billing cards carry one consistent 20px of padding instead of the card's own 14px fighting a
    second layer, and the plan price no longer leaves a hole above its digits. Both were invisible
    until the shell started generating the utilities module screens use.

0.5.9 — release

Patch Changes

  • 4d6ecce: Each invoice row links the PDF Stripe issued beside the hosted page, so an accountant gets the file
    without leaving the billing screen.

0.5.10 — release

Patch Changes

  • f99e63a: The first invoice of a new subscription is no longer lost. Stripe sends invoice.paid for it before
    checkout.session.completed, so no subscription row carried the customer yet and the invoice was
    dropped as applied. The invoice is now placed by the subscription metadata Stripe snapshots on it,
    refused for retry when nothing can place it, mirrored again when checkout completes, and backfilled
    nightly for every workspace with a Stripe customer — which restores the ones already missing.

0.5.11 — release

Patch Changes

  • 36afd73: The invoice list says whether each invoice is paid, awaiting payment, unpaid, void or a draft — it
    listed number, date and amount and nothing about whether any of it had been settled. On the admin
    subscriptions table the "Override" badge no longer truncates to "Overrid" when the plan column is
    narrow.

0.5.12 — release

Patch Changes

  • fix(admin): fit the subscriptions table in the admin pane

0.5.13 — release

Patch Changes

  • 6664aa0: A Stripe event for a workspace this instance does not have is logged and skipped instead of being
    written. One Stripe account delivers every event to every endpoint on it, so a checkout run from a
    developer's machine against a shared sandbox reached the cloud, which mirrored an invoice for a
    workspace id it had never seen.

0.5.14 — release

Patch Changes

  • 830a458: A workspace that existed before the instance's default plan was configured is put on it by the
    nightly job, trial and all. A workspace with no subscription row resolves to unlimited, and on an
    instance that takes payments such a workspace had been entitled to everything with no trial and no
    bill, with nothing that would ever change it. Instances with no default plan are unaffected.

0.5.15 — release

Patch Changes

  • 96cfffa: Peer @kernhq/kernel at ^0.10.0.

    A caret on 0.x does not cross a minor, so ^0.9.1 stopped reaching the framework the moment 0.10.0
    was published — check-ranges.mjs fails on it, and CI stops at the lint step before a single test
    runs. The module builds and tests against 0.10.0 unchanged.

0.5.16 — release

Patch Changes

  • ee04437: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

chat 0.4.16 → 0.5.1

0.5.0 — release

Minor Changes

  • ca447a2: Incoming webhooks are gone: the chat.webhooks.incoming procedure, the POST /api/chat/webhooks/{token} route and the mod_chat.webhooks table. Nothing could ever create a
    token — the only thing that ever named a chat.webhooks.create procedure was the comment above the
    table, written in the commit that added it — so there was no procedure, no insert and no screen, and
    the endpoint could only ever answer 404 against a permanently empty table. It was a feature nobody
    could turn on, advertised in the module's OpenAPI document (38 paths before, 37 after). Dropping the
    table loses no data on any instance, and 0001_drop_webhooks.sql is guarded with if exists so the
    folder still survives a replay. Incoming webhooks can come back as a real feature — create, list and
    revoke, with a screen to manage the tokens.

Patch Changes

  • c892f45: The conversation header no longer carries a Huddle button. Calls are not built, so the button was
    permanently disabled on the busiest screen in the product — in every channel and every direct
    message, for everybody — and its only explanation was a title on a natively disabled button,
    which nothing can reach: a disabled button is out of the tab order and receives no pointer events,
    so neither a keyboard nor a screen reader nor a hover ever got the reason. It comes back when calls
    do.
  • 02bae7a: The command palette's "New channel" opens the dialog. It runs /chat?new=1, because a command can
    only navigate — and nothing read that parameter, so the command moved you to the chat page and
    stopped there. The sidebar consumes it now and puts the URL back without it, so running the command
    again after closing the dialog opens it again.
  • 9f8a3d7: Peer and develop against @kernhq/kernel ^0.10.0. A caret on 0.x does not cross a minor, so the
    previous ^0.9.1 could no longer reach the published framework — invisible locally, where the
    workspace copy is linked, and a lint failure in CI, which installs from the registry.
  • 1100063: Archiving a private channel no longer announces it to the whole workspace. realtime.change
    publishes on the workspace channel, which every socket subscribes to for every workspace it belongs
    to the moment it authenticates — so archiving or restoring a private, object or group channel told
    everybody in the workspace that the channel exists and what had just happened to it, whether or not
    they may open it. The change now goes to the channel's own members, the same audience a private
    channel's creation already used, and announce.test.ts asserts the frames.
  • b4a1a17: The composer's voice and video buttons say why they cannot record. They were disabled whenever the
    browser has no MediaRecorder — which is also every instance served over plain HTTP, where
    navigator.mediaDevices is absent — and a disabled button explains nothing to a pointer, a keyboard
    or a screen reader. Pressing one now opens the recorder bar on its "this browser cannot record"
    message, which was written and translated but could never be reached.
  • 800cdb2: A row in the unread-chat widget opens its conversation. It linked to /<ws>/chat?channel=<id>
    while the chat page reads ?c=, so every row on the dashboard landed on chat with nothing selected
    and the "pick a conversation" empty state.

0.5.1 — release

Patch Changes

  • e0593f9: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

hr 0.23.1 → 0.23.7

0.23.2 — release

Patch Changes

  • 7e6ef5d: Rename every client query key onto the entity name the server announces, so the realtime client's [module, entity] prefix invalidation reaches screens it previously never reached. The sensitive-fields panel is deliberately left off that prefix: the server logs every read, and a refetch nobody asked for would record a disclosure nobody performed.

0.23.3 — release

Patch Changes

  • 749c01e: The reports page no longer leaves a blank band between the filters and the report — the page's
    .ctl rule was also reaching the control wrapper inside Field and making every filter 160px
    tall — and its last column is wide enough for its heading. On the rosters settings, a shift that
    crosses midnight reads as two clock times with the "+1" beside them, rather than two full dates
    built from an anchor day nobody chose.

0.23.4 — release

Patch Changes

  • fix(client): fit the attendance report at a laptop width; one clock for shift hours

0.23.5 — release

Patch Changes

  • 25d0ff3: Two checklist strings that rendered as their keys have words now: the due-date field when adding
    an item, and the empty state when a filter matches no checklist.

0.23.6 — release

Patch Changes

  • ce4a9df: Peer @kernhq/kernel at ^0.10.0.

    A caret on 0.x does not cross a minor, so ^0.9.1 stopped reaching the framework the moment 0.10.0
    was published — check-ranges.mjs fails on it, and CI stops at the lint step before a single test
    runs. The module builds and tests against 0.10.0 unchanged.

0.23.7 — release

Patch Changes

  • bbccf84: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

inventory 0.5.1 → 0.5.3

0.5.2 — release

Patch Changes

  • 9f255ab: Peer @kernhq/kernel at ^0.10.0.

    A caret on 0.x does not cross a minor, so ^0.9.1 stopped reaching the framework the moment 0.10.0
    was published — check-ranges.mjs fails on it, and CI stops at the lint step before a single test
    runs. The module builds and tests against 0.10.0 unchanged.

0.5.3 — release

Patch Changes

  • cbe4bec: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

mail 0.5.0 → 0.6.3

0.5.1 — release

Patch Changes

  • chore(deps): take @kernhq/testing ^0.1.12, which has permissionMatrixDiff

0.5.2 — release

Patch Changes

  • ac8a952: Published again with no code change. npm's CDN kept serving the abbreviated package document from
    before 0.5.1 existed for more than twelve hours, so pnpm install in every host that reached
    ^0.5.1 failed with "no matching version" and the nightly release could not advance the services.
    A new publish is what refreshes that document.

0.6.0 — release

Minor Changes

  • f3ec9bc: Send a message that carries only plain text in the shared paper layout.

    Five branded MJML templates shipped in this package and nothing rendered them: every email the
    platform sends is built by its caller, and a caller that names no template got whatever HTML it
    brought — or, for core's notification digest, no HTML at all. The digest is the email most people
    here actually open and it arrived as bare text.

    buildMessage now wraps text with no HTML beside it in templates/_layout.mjml, escaping and
    linking each paragraph, so it looks like the rest of the platform without the caller knowing a
    template name. A caller's own HTML is left exactly as it arrived, and the text part is untouched.

    src/server/templates.test.ts compiles every shipped template against one sample and asserts the
    branding, which nothing did before.

  • 94c38d1: See the blocked addresses, and take one off the list.

    An address that bounced once was blocked from every Kern email for ever. A full mailbox, a
    corporate relay answering 550 during a misconfiguration, or one press of "report spam" on a digest
    stopped that person receiving password resets, sign-in links and invitations — and nothing in the
    product could read the list or change it. The administrator saw "failed — all recipients
    suppressed" and had no way to act; only SQL released the address.

    suppressions.list and suppressions.remove are new on the mail contract, behind
    mail.settings.manage, and Settings → Email now has a Blocked addresses section with a search
    box and a Remove action per row. A workspace sees its own rows and the instance-wide ones — the
    instance-wide rows are the account mail, so leaving them out would have left the worst case
    unreachable — and a row that belongs to the whole instance is marked as such on screen and in the
    confirmation. Every removal is written to the log and to the workspace's activity feed.

  • d3411cd: Send the test message inside the handler and answer what actually happened.

    "Send test" on Settings → Email enqueued a job and reported success, so an administrator saw a
    green toast for credentials that could not connect, for a recipient on the blocked list, and for an
    instance with no provider configured at all. The one control whose job is to prove that mail works
    proved nothing.

    The provider is now built and used before the handler answers, and the answer is the delivery's own
    outcome: ok only when the provider accepted the message, error in the provider's own words, and
    a new optional status (refused, suppressed, timeout) so the screen can say something a
    person can act on. The screen also refreshes the delivery log after every test, whatever the answer.

    Two things the delivery log was getting wrong are fixed with it: building the provider now happens
    inside processSend's try, so a wrong host or a missing key leaves the row failed with the reason
    rather than queued for ever; and the test message renders with the provider's name in it, which
    was blank.

0.6.1 — release

Patch Changes

  • fdaa1ae: Peer @kernhq/kernel at ^0.10.0.

    A caret on 0.x does not cross a minor, so ^0.9.1 stopped reaching the framework the moment 0.10.0
    was published — check-ranges.mjs fails on it, and CI stops at the lint step before a single test
    runs. The module builds and tests against 0.10.0 unchanged.

0.6.2 — release

Patch Changes

  • 7863592: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

0.6.3 — release

Patch Changes

  • 20ebb12: Answer "Send test" with the failure when core cannot be reached, rather than a 500.

    Reading the workspace's provider config is a call to core, and it sat outside the handler's try.
    Core is a different service, so a restart, a rolling deploy or a dropped connection made the whole
    procedure throw. Measured against a stub whose core.settings.getIntegration fails, the endpoint
    answered 500 {"code":"INTERNAL_SERVER_ERROR","message":"Internal server error"} and the screen
    showed that as the toast. It answers 200 {"ok":false,"error":"…","status":"refused"} now — the
    same shape as every other way this control can fail, which matters more here than usual, because the
    control's entire job is to tell an administrator the truth about whether mail works.

    Two things that changed quietly when the test send became synchronous are written down rather than
    reverted. sendAndWait enqueues no job, so the send job's retries and backoff do not apply to a
    test send and a restart between the delivery row being written and the provider answering leaves
    that row queued with nothing to sweep it; the reason to accept that, and the reason not to add a
    sweeper, are in its comment. And mail.delivery.failed now says on the event definition that it
    fires per attempt, not per message — an instance with no provider configured emits one for each of
    the job's six tries, so a subscriber counting them is counting attempts.

    test-send.test.ts covers both new cases: core unreachable, and an instance with no provider
    configured at all.

quire 0.16.3 → 0.17.1

0.16.4 — release

Patch Changes

  • c115b69: The page picker behind the "embed a page" block has its words: its title, search box, space
    selector and empty state were rendering their message keys, in every language.

0.17.0 — release

Minor Changes

  • 6ab429b: @ in a comment names somebody, and they are told. The comment composer and its reply box were
    given no mention source, so RichTextEditor never installed the mention node and typing @ada
    left the characters @ada in a sentence — while the server has always read mention nodes out of
    a body and raised a quire.mention notification for everybody named. A comment that is only a
    mention can now be posted, and the name stays in the line the margin and the notification show.
  • b393959: @ and + in a page find something. The wiki editor installed both suggestion menus and supplied
    neither source, so mentioning a person and linking a page each opened a popup reading "Nothing
    matches that" — as did the / menu's Mention someone, which types an @. @ now offers the
    workspace's members, and + the pages of the space, each with the section it lives in so two
    "Overview" pages can be told apart.

Patch Changes

  • 5d5de7b: Peer on @kernhq/kernel ^0.10.0. A caret on 0.x does not cross a minor, so the previous range
    stopped reaching the framework the day 0.10.0 was published — a host installing this module from
    the registry could not resolve a kernel it declares.

0.17.1 — release

Patch Changes

  • 78fa2b3: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

tracker 0.11.16 → 0.12.1

0.11.17 — release

Patch Changes

  • 07d4d4e: The import page's file picker is a proper button with the chosen file's name beside it, instead of
    the browser's own unstyled "Choose File — No file chosen" control.

0.12.0 — release

Minor Changes

  • 247551b: The workflow "Call webhook" post-function can no longer be pointed at the network the service runs
    on. It sent a request to whatever URL a workspace admin typed, so on a hosted instance — where
    signing up makes you the owner of a workspace — it could be aimed at the other services on the
    internal network or at the cloud provider's metadata endpoint, with a method, headers and a body of
    the caller's choosing.

    A webhook now has to be http or https, its hostname is resolved before anything connects and refused
    if it lands on a loopback, private, link-local, unique-local, multicast or reserved address, and the
    socket goes to the address that was checked rather than to a second lookup that could answer
    differently. Redirects are no longer followed, because the address a redirect names is one nothing
    has checked. Responses are capped and the call times out.

    Anyone whose workflow calls a webhook on their own internal network will see it refused, with the
    address and the reason in the service log.

Patch Changes

  • 94f4b45: The Reports page says when something failed to load instead of reporting nothing. A failed project
    list used to read "There are no projects to report on yet", and a failed report drew its heading and
    then an empty panel; both now show the failure with a Retry.
  • 1f93ac3: The last two places in the tracker that answered a failed request with "there is nothing here" now
    say that something went wrong and offer a Retry: the issue picker used to report "No issue matches"
    when the search had not run, and the timer widget used to report no timer running to someone whose
    clock was going.
  • 26a2b61: Every list in the tracker that could only say "there is nothing here" now says when it failed
    instead, with a Retry. A project's pages no longer report "No project called KERN" when the project
    list did not arrive, the sidebar no longer tells a workspace full of projects to make its first one,
    the planning, projects, import, repeating and workflow settings say what failed, and a dashboard
    count tile no longer renders a confident "0" for a query that never came back.

0.12.1 — release

Patch Changes

  • 6ec2fb2: Peer @kernhq/contracts@^0.8.0, which adds archivedAt to WorkspaceSummary. A caret on 0.x does
    not cross a minor, so the previous ^0.7.0 could not reach it.

Services

core

Feat

  • feat(mail): send every email in the recipient's language

Fix

  • fix(account): make the promised 30-day undo reachable
  • fix(auth): hold an MCP token to its scopes in every service
  • fix(auth): hold an MCP token to the scopes it was granted
  • fix(auth): let only a real session reopen a closed account
  • fix(auth): resolve the client IP behind a proxy and set our own limits
  • fix(auth): stop an API key acting as a session on /api/auth
  • fix(env): treat a blank environment variable as unset
  • fix(files): stop an uploaded file executing on the app's origin
  • fix(mail): stop reporting success when nothing can send
  • fix(mcp): send the workspace where every module expects it
  • fix(notifications): keep one refused address from ending the digest
  • fix(permissions): stop a guest reading every project in the workspace
  • fix(workspaces): make the 30-day deletion undo reachable
  • fix(workspaces): reserve every slug the proxy and the app own

Docs

  • docs(auth): keep the session-origin comment true after the plugin change
  • docs(mail): say why core does not use the module's MJML templates

Test

  • test(auth): show the suite's sign-ins never reach the limiter

compare v0.3.0...v0.4.0

shell

Feat

  • feat(admin): give the instance console its settings and users screens
  • feat(api): reach core's export and erasure routes
  • feat(invite): build the /invite/:token screen every email points at
  • feat(modules): mount module overlays once per workspace
  • feat(privacy): build export, workspace deletion and account closure
  • feat(security): build two-factor enrolment and reach the challenge

Fix

  • fix(account): say why a closure was refused, and sweep the admin screens
  • fix(css): scan the module clients, so a module screen gets every utility it uses
  • fix(deps): pin one @kernhq/sdk copy for a standalone install
  • fix(onboarding): say why a workspace was refused, in real words
  • fix(privacy): keep a workspace reachable while its erasure is scheduled
  • fix(settings): link email delivery once the mail module is on; space icon buttons
  • fix(settings): remove the auto-join field nothing acts on

Docs

  • docs: correct what sign-out does to an overlay
  • docs: record that a layout is reused across a param change
  • docs: record what running the data-rights screens against core taught

Test

  • test(mail): match the test-send wording the module now ships
  • test(modules): cover the overlay selection
  • test(ux): sweep the second-factor challenge

Other

  • i18n: give the admin console's settings and accounts screens their words
  • i18n: undo the duplicate keys my last commit added

compare v0.3.0...v0.4.0

chat

Fix

  • fix(auth): state what an MCP token is being used for
  • fix(gateway): re-authorise subscriptions and stop presence killing chat

compare v0.3.0...v0.4.0

mail

Feat

  • feat(health): report an unset MAIL_WEBHOOK_TOKEN in /api/health

Fix

  • fix(auth): state what an MCP token is being used for
  • fix(webhooks): fail closed and call back only Amazon SNS endpoints
  • fix(webhooks): parse the text/plain body Amazon SNS posts

Docs

  • docs: correct the README on row-level security and inbound mail
  • docs: correct the oRPC auth-ordering claim and pin it in a test
  • docs: correct three claims that do not survive being run
  • docs: the mail tables are row-level secured now

Test

  • test: make the oRPC body guard fail when the body is lost

compare v0.3.0...v0.4.0

collab

Fix

  • fix(auth): refuse an MCP token on the document socket

compare v0.3.0...v0.4.0