Repository navigation
v0.4.0
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 |
| 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 |
| 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.paidfor 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/kernelat^0.10.0.A caret on 0.x does not cross a minor, so
^0.9.1stopped reaching the framework the moment 0.10.0
was published —check-ranges.mjsfails 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could not reach it.
chat 0.4.16 → 0.5.1
0.5.0 — release
Minor Changes
- ca447a2: Incoming webhooks are gone: the
chat.webhooks.incomingprocedure, thePOST /api/chat/webhooks/{token}route and themod_chat.webhookstable. Nothing could ever create a
token — the only thing that ever named achat.webhooks.createprocedure 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, and0001_drop_webhooks.sqlis guarded withif existsso 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 atitleon 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.1could 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, andannounce.test.tsasserts the frames. - b4a1a17: The composer's voice and video buttons say why they cannot record. They were disabled whenever the
browser has noMediaRecorder— which is also every instance served over plain HTTP, where
navigator.mediaDevicesis 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could 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
.ctlrule was also reaching the control wrapper insideFieldand 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/kernelat^0.10.0.A caret on 0.x does not cross a minor, so
^0.9.1stopped reaching the framework the moment 0.10.0
was published —check-ranges.mjsfails 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could not reach it.
inventory 0.5.1 → 0.5.3
0.5.2 — release
Patch Changes
-
9f255ab: Peer
@kernhq/kernelat^0.10.0.A caret on 0.x does not cross a minor, so
^0.9.1stopped reaching the framework the moment 0.10.0
was published —check-ranges.mjsfails 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could 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, sopnpm installin every host that reached
^0.5.1failed 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.buildMessagenow wraps text with no HTML beside it intemplates/_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.tscompiles 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.listandsuppressions.removeare 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:okonly when the provider accepted the message,errorin the provider's own words, and
a new optionalstatus(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
insideprocessSend's try, so a wrong host or a missing key leaves the rowfailedwith the reason
rather thanqueuedfor 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/kernelat^0.10.0.A caret on 0.x does not cross a minor, so
^0.9.1stopped reaching the framework the moment 0.10.0
was published —check-ranges.mjsfails 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could 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 whosecore.settings.getIntegrationfails, the endpoint
answered500 {"code":"INTERNAL_SERVER_ERROR","message":"Internal server error"}and the screen
showed that as the toast. It answers200 {"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.sendAndWaitenqueues no job, so thesendjob'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 rowqueuedwith nothing to sweep it; the reason to accept that, and the reason not to add a
sweeper, are in its comment. Andmail.delivery.failednow 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.tscovers 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, soRichTextEditornever installed the mention node and typing@ada
left the characters@adain a sentence — while the server has always readmentionnodes out of
a body and raised aquire.mentionnotification 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could 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 addsarchivedAttoWorkspaceSummary. A caret on 0.x does
not cross a minor, so the previous^0.7.0could 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
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
chat
Fix
- fix(auth): state what an MCP token is being used for
- fix(gateway): re-authorise subscriptions and stop presence killing chat
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
collab
Fix
- fix(auth): refuse an MCP token on the document socket