chore: version packages#2551
Closed
github-actions[bot] wants to merge 1 commit into
Closed
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 03:00
07cb49f to
33acba3
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 03:09
33acba3 to
b4f105d
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 06:58
b4f105d to
ad9201f
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 08:33
ad9201f to
b3fbae9
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 08:44
b3fbae9 to
7d3cb53
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 08:55
7d3cb53 to
a025391
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 09:19
a025391 to
f4374f7
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 10:34
f4374f7 to
08ea4fb
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 10:47
08ea4fb to
52a65fe
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 12:10
52a65fe to
7b7cb53
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 12:19
7b7cb53 to
315093b
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 12:47
315093b to
6521d7b
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 13:00
6521d7b to
93eccd9
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 13:41
93eccd9 to
d4c4ebb
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 14:09
d4c4ebb to
e1dc8a7
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 14:40
e1dc8a7 to
915cc11
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 14:55
915cc11 to
9c4a543
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 4, 2026 15:09
9c4a543 to
bce9a16
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@objectstack/rest@12.0.0
Major Changes
7c09621: feat(security)!:
api.requireAuthnow defaults totrue— anonymous access to the data API is denied by default (ADR-0056 D2 flip)BREAKING. The global
requireAuthdefault flipped FROMfalseTOtrue(
RestApiConfigSchema.requireAuthin@objectstack/spec, mirrored byRestServer.normalizeConfigin@objectstack/rest). Anonymous requests tothe
/data/*CRUD + batch endpoints are now rejected with HTTP 401 unless thedeployment explicitly opts out. (Scope note: this gate covers the REST
/data/*surface — the metadata read/write endpoints and the dispatcherGraphQL route have their own pre-existing anonymous posture, tracked
separately; this flip does not change them.)
Migration (one line): a deployment that intentionally serves data publicly
(demo / playground / kiosk) sets the flag on the stack config — now a declared
ObjectStackDefinitionSchema.apifield, so it survivesdefineStackstrictparsing (previously an undeclared top-level
apikey was silently stripped):The REST plugin logs a boot warning for the explicit opt-out so a fail-open
posture is always visible. A misplaced
api.requireAuthat the plugin level(one nesting short) is now also called out with a boot warning instead of
being silently ignored.
What keeps working with no action:
publicFormGrant(create + read-back on the declared target object only);no
guest_portalprofile needed./auth,/health,/discoveryare exempt.objectstack servewith an auth-less stack — the CLI passes an explicitrequireAuth: falsefor stacks whose tier set has noauth(nothing couldauthenticate against them), with the boot warning.
Patch Changes
@objectstack/spec@12.0.0
Major Changes
7c09621: feat(security)!:
api.requireAuthnow defaults totrue— anonymous access to the data API is denied by default (ADR-0056 D2 flip)BREAKING. The global
requireAuthdefault flipped FROMfalseTOtrue(
RestApiConfigSchema.requireAuthin@objectstack/spec, mirrored byRestServer.normalizeConfigin@objectstack/rest). Anonymous requests tothe
/data/*CRUD + batch endpoints are now rejected with HTTP 401 unless thedeployment explicitly opts out. (Scope note: this gate covers the REST
/data/*surface — the metadata read/write endpoints and the dispatcherGraphQL route have their own pre-existing anonymous posture, tracked
separately; this flip does not change them.)
Migration (one line): a deployment that intentionally serves data publicly
(demo / playground / kiosk) sets the flag on the stack config — now a declared
ObjectStackDefinitionSchema.apifield, so it survivesdefineStackstrictparsing (previously an undeclared top-level
apikey was silently stripped):The REST plugin logs a boot warning for the explicit opt-out so a fail-open
posture is always visible. A misplaced
api.requireAuthat the plugin level(one nesting short) is now also called out with a boot warning instead of
being silently ignored.
What keeps working with no action:
publicFormGrant(create + read-back on the declared target object only);no
guest_portalprofile needed./auth,/health,/discoveryare exempt.objectstack servewith an auth-less stack — the CLI passes an explicitrequireAuth: falsefor stacks whose tier set has noauth(nothing couldauthenticate against them), with the boot warning.
Minor Changes
7709db4: feat(security): permission-set package provenance + declared-permission seeding (ADR-0086 P1)
Packages now ship working default access for their own objects, with a
machine-checkable metadata↔config boundary:
PermissionSetSchema.packageId(owning package fora package-shipped set; absent = env-authored) and per-record provenance
managedBy: 'package' | 'platform' | 'user'on the existingmetadata-persistence axis. Persisted on
sys_permission_setaspackage_id/managed_by(new columns +package_idindex).bootstrapDeclaredPermissions— the siblingof
bootstrapDeclaredRoles— materializesstack.permissionsintosys_permission_setat boot withmanaged_by:'package'+package_id.Idempotent and upgrade-aware: rows the seeder owns are re-seeded to the
shipped declaration on every boot; rows owned by a different package are
refused loudly; env-authored
platform/user/legacy rows are neverclobbered. Closes the ADR-0078 inert-metadata violation for
stack.permissions(declared sets were runtime-enforced but nevermaterialized — invisible to the admin surface, uninstall undefined).
declarative-permission-seeding(ADR-0056 D10) +dogfood proof pin the behavior so it cannot regress to inert.
Patch Changes
7c09621: feat(security): pre-map
transfer/restore/purgeto their RBAC bits ([P0][security] Permission lifecycle ops ungated (allowTransfer/allowRestore/allowPurge) #1883)The permission evaluator now maps the destructive record-lifecycle operations
to their spec permission bits (
transfer→allowTransfer,restore→allowRestore,purge→allowPurge) and extends themodifyAllRecordssuper-user bypass to cover them. The ObjectQL operations themselves are still
roadmap M2 — but the gate now exists ahead of them: the moment such an
operation is dispatched through the security middleware it is denied unless a
resolved permission set grants the matching bit. Unmapped destructive
operations continue to fail closed (ADR-0049). Spec descriptions updated from
[EXPERIMENTAL — not enforced]to[RBAC-gated; operation pending M2].9860de4: Surface view-key collisions during view container expansion instead of renaming silently.
expandViewContainerkeeps its backward-compatible rename behaviour (<object>.<key>→<object>.<key>_2on collision) but now stamps a machine-readable_diagnostics.warningsentry on the renamedExpandedViewItem, explaining thatreferences targeting the requested name (form action targets, navigation
viewNames)will resolve to the other view. Both flattening loaders — the ObjectQL engine and the
MetadataPlugin — log these warnings at boot so the collision is visible instead of
manifesting as a form action opening a list view (expandViewContainer silently renames colliding form view keys (formViews.default → default_2) — form action targets break #2554).
@objectstack/metadata-protocol@12.0.0
Minor Changes
9796e7c: feat(security): two-doors separation for permission sets (ADR-0086 P2)
Splits who may change a permission set into two non-overlapping doors, enforced
at the data layer instead of by convention:
块 1 — the package door (publish-time materialization).
ObjectStackProtocolImplementationgains a generic publish-time materializerregistry (
registerPublishMaterializer(type, fn)). When a draft of a registeredtype is published, its body is projected into a data-plane row and the result is
surfaced on the publish response as
materializeApplied(best-effort, neverthrown — same contract as
seedApplied).promoteDraftnow returns the draft'spackageIdso the materializer can stamp the owning package.plugin-securityregisters a
permissionmaterializer that upserts the published set intosys_permission_setwithmanaged_by:'package'+package_id— so a setauthored through the studio package door (saved as a
permissiondraft, thenpublished) lands in the admin surface with the exact provenance the boot seeder
already stamps, now on the runtime publish path too. The single-set upsert is
shared with
bootstrapDeclaredPermissions(upsertPackagePermissionSet), soboth paths apply the same own-row / foreign-package / env-authored rules.
块 2 — the admin door (data-layer write gate).
The security middleware now refuses any admin-door write
(
update/delete/transfer/restore/purge) to asys_permission_setrowwith
managed_by:'package', and refuses aninsertthat forgesmanaged_by:'package'. The gate fails closed regardless of the caller's grants(a platform admin with
modifyAllRecordsis blocked just the same), so it is areal data-layer boundary rather than a UI hint. System/boot writes carry
isSystemand bypass the whole middleware, so the boot seeder and the publishmaterializer are unaffected. Env-authored sets (
managed_byuser/platformor absent) stay freely editable through the admin door — the two doors never
overwrite each other.
Patch Changes
b5be479: fix(protocol): versionless package installs now persist to sys_packages (DB-created base packages vanish from GET /packages after server restart #2532)
installPackagewrites both package stores, but its durable half was guarded bypkgSvc?.publish && manifest.version— silently skipping every versionlessruntime-created base (
{id, name}from the builder / Setup). Those packageslived only in the in-memory registry and vanished on restart, while their
metadata and tables survived. The version is now defaulted (
0.1.0) instead ofskipping, a failed persist logs loudly instead of silently, and
deletePackagedrops the
sys_packagesrecord so an uninstalled package no longer resurrectsat the next boot (service-package hydrates that table into the registry).
806a40a: Stop runtime view personalization from permanently removing views from the switcher.
A console personalization PUT (grid column sort, inline edit, …) sends only the raw
view config — no top-level
viewKind/object. Persisted verbatim, the overlay rowreplaced the flattened package entry wholesale on read, stripping the identity fields
every switcher-style consumer filters on (
viewKind && object) — one sort click andthe view vanished until the DB row was deleted (Runtime view overlay drops viewKind/object — one grid sort permanently removes the view from the switcher #2555).
Two independent guards:
saveMetaItemnow inherits the missingviewKind/object/labelfrom the registry entry the overlay shadows before persisting, andgetMetaItemsheals identity-less rows already in the DB the same way on read. Theoverlay's own fields always win;
defineViewcontainer bodies are untouched.Updated dependencies [7c09621]
Updated dependencies [7709db4]
Updated dependencies [7c09621]
Updated dependencies [9860de4]
@objectstack/platform-objects@12.0.0
Minor Changes
07f055c: feat(auth): last-login audit fields — sys_user.last_login_at / last_login_ip (ADR-0069 D7)
Completes the ADR-0069 D7 identity-field set:
sys_user.last_login_atandsys_user.last_login_ipare stamped on every successful/sign-in/emailbyAuthManager.stampLastLogin(a best-effort after-hook, independent of thelockout-accounting path so it runs even when lockout is disabled). The IP is
taken from the trusted forwarded headers (
x-forwarded-for→cf-connecting-ip→x-real-ip), the same precedence as the D5 IP allow-listmiddleware, and capped to the 45-char column width. Both fields are
system-managed, read-only, and land in the Admin group of
sys_user.The rest of ADR-0069 P1 (password complexity/history/expiry, HIBP, account
lockout, enforced MFA) was already implemented; this fills the one missing D7
field pair. ADR-0069 status updated Proposed → Accepted (P1/P2 implemented)
with an implementation-status matrix reflecting what is landed vs the remaining
P2 gaps (per-org IP ranges, shared-store rate limiting).
Patch Changes
@objectstack/plugin-auth@12.0.0
Minor Changes
07f055c: feat(auth): last-login audit fields — sys_user.last_login_at / last_login_ip (ADR-0069 D7)
Completes the ADR-0069 D7 identity-field set:
sys_user.last_login_atandsys_user.last_login_ipare stamped on every successful/sign-in/emailbyAuthManager.stampLastLogin(a best-effort after-hook, independent of thelockout-accounting path so it runs even when lockout is disabled). The IP is
taken from the trusted forwarded headers (
x-forwarded-for→cf-connecting-ip→x-real-ip), the same precedence as the D5 IP allow-listmiddleware, and capped to the 45-char column width. Both fields are
system-managed, read-only, and land in the Admin group of
sys_user.The rest of ADR-0069 P1 (password complexity/history/expiry, HIBP, account
lockout, enforced MFA) was already implemented; this fills the one missing D7
field pair. ADR-0069 status updated Proposed → Accepted (P1/P2 implemented)
with an implementation-status matrix reflecting what is landed vs the remaining
P2 gaps (per-org IP ranges, shared-store rate limiting).
1b1b34e: feat(auth): shared cross-node rate-limit + session store via the cache service (ADR-0069 D2)
Multi-node deployments previously rate-limited per process — better-auth's
default
rateLimitstore is in-memory, so each node counted independently andan attacker could rotate nodes to bypass the limit.
AuthPluginnow wires thekernel
cacheservice as better-auth'ssecondaryStorageand flipsrateLimit.storageto'secondary-storage', so rate-limit counters (and thesession cache) are enforced against one shared store across every node —
shared iff the cache service is (Redis adapter in a cluster; memory single-node,
where behavior is unchanged). When no cache service is registered the plugin
logs a warning that a multi-node deployment needs a shared cache (ADR-0069
honesty — no silent per-process limiting presented as global).
New
cacheSecondaryStorage(cache)adapter (ICacheService→ better-authSecondaryStorage). Note: the cache has no atomic increment, so under highconcurrency the get→set counter path can slightly over-count — acceptable for a
rate limiter and strictly better than independent per-node counters; a future
cache adapter exposing atomic INCR can add an
incrementmethod for exactcounting.
Patch Changes
@objectstack/plugin-security@12.0.0
Minor Changes
9796e7c: feat(security): two-doors separation for permission sets (ADR-0086 P2)
Splits who may change a permission set into two non-overlapping doors, enforced
at the data layer instead of by convention:
块 1 — the package door (publish-time materialization).
ObjectStackProtocolImplementationgains a generic publish-time materializerregistry (
registerPublishMaterializer(type, fn)). When a draft of a registeredtype is published, its body is projected into a data-plane row and the result is
surfaced on the publish response as
materializeApplied(best-effort, neverthrown — same contract as
seedApplied).promoteDraftnow returns the draft'spackageIdso the materializer can stamp the owning package.plugin-securityregisters a
permissionmaterializer that upserts the published set intosys_permission_setwithmanaged_by:'package'+package_id— so a setauthored through the studio package door (saved as a
permissiondraft, thenpublished) lands in the admin surface with the exact provenance the boot seeder
already stamps, now on the runtime publish path too. The single-set upsert is
shared with
bootstrapDeclaredPermissions(upsertPackagePermissionSet), soboth paths apply the same own-row / foreign-package / env-authored rules.
块 2 — the admin door (data-layer write gate).
The security middleware now refuses any admin-door write
(
update/delete/transfer/restore/purge) to asys_permission_setrowwith
managed_by:'package', and refuses aninsertthat forgesmanaged_by:'package'. The gate fails closed regardless of the caller's grants(a platform admin with
modifyAllRecordsis blocked just the same), so it is areal data-layer boundary rather than a UI hint. System/boot writes carry
isSystemand bypass the whole middleware, so the boot seeder and the publishmaterializer are unaffected. Env-authored sets (
managed_byuser/platformor absent) stay freely editable through the admin door — the two doors never
overwrite each other.
7c09621: feat(security): pre-map
transfer/restore/purgeto their RBAC bits ([P0][security] Permission lifecycle ops ungated (allowTransfer/allowRestore/allowPurge) #1883)The permission evaluator now maps the destructive record-lifecycle operations
to their spec permission bits (
transfer→allowTransfer,restore→allowRestore,purge→allowPurge) and extends themodifyAllRecordssuper-user bypass to cover them. The ObjectQL operations themselves are still
roadmap M2 — but the gate now exists ahead of them: the moment such an
operation is dispatched through the security middleware it is denied unless a
resolved permission set grants the matching bit. Unmapped destructive
operations continue to fail closed (ADR-0049). Spec descriptions updated from
[EXPERIMENTAL — not enforced]to[RBAC-gated; operation pending M2].7709db4: feat(security): permission-set package provenance + declared-permission seeding (ADR-0086 P1)
Packages now ship working default access for their own objects, with a
machine-checkable metadata↔config boundary:
PermissionSetSchema.packageId(owning package fora package-shipped set; absent = env-authored) and per-record provenance
managedBy: 'package' | 'platform' | 'user'on the existingmetadata-persistence axis. Persisted on
sys_permission_setaspackage_id/managed_by(new columns +package_idindex).bootstrapDeclaredPermissions— the siblingof
bootstrapDeclaredRoles— materializesstack.permissionsintosys_permission_setat boot withmanaged_by:'package'+package_id.Idempotent and upgrade-aware: rows the seeder owns are re-seeded to the
shipped declaration on every boot; rows owned by a different package are
refused loudly; env-authored
platform/user/legacy rows are neverclobbered. Closes the ADR-0078 inert-metadata violation for
stack.permissions(declared sets were runtime-enforced but nevermaterialized — invisible to the admin surface, uninstall undefined).
declarative-permission-seeding(ADR-0056 D10) +dogfood proof pin the behavior so it cannot regress to inert.
Patch Changes
48ad533: fix(security): surface swallowed permission-set resolution failures ([security][observability] resolvePermissionSets swallows dbLoader failures silently — custom permission sets vanish with no log #2565)
PermissionEvaluator.resolvePermissionSetsswallowed metadatalist()andsys_permission_setdbLoader failures silently — fail-closed (unresolvablesets grant nothing), but a transient DB error made custom permission sets
vanish with no trace, leaving the resulting 403s undiagnosable. The evaluator
now accepts an optional
{ logger }and emits onewarnper failed source,naming the unresolved permission sets and the error. SecurityPlugin wires its
plugin logger into both call sites. Resolution behavior is byte-identical.
Updated dependencies [07f055c]
Updated dependencies [7c09621]
Updated dependencies [7709db4]
Updated dependencies [7c09621]
Updated dependencies [9860de4]
@objectstack/service-automation@12.0.0
Minor Changes
ffafb30: feat(automation): durable run history — every terminal run leaves a queryable record with its failure reason
Automation runs were observable only in memory: the engine kept the last N
ExecutionLogEntryrecords in a ring buffer, so "did this flow run, and why didit fail?" could not be answered after a process restart (or once the buffer
evicted the entry), and a failed run surfaced no reason at all. This was the
biggest silent-trust gap for anyone authoring automations — a flow could stop
firing or start failing with nothing durable to inspect.
sys_automation_run— previously the ADR-0019 store for live suspended runsonly — becomes a durable run-history table. On every terminal run the engine
mirrors a row through the
SuspendedRunStore(recordTerminal):status(
completed/failed),finished_at,duration_ms, and, for a failure, theerrormessage a designer needs to fix it.listRuns()merges this durablehistory with the in-memory buffer (in-memory wins on id, newest-first) so the
Studio "Runs" surface shows runs that predate the current process.
The design is safe and additive. Terminal history rows use a
run_-prefixedid, disjoint from live suspended runs (which key on the raw
runIdwithstatus: 'paused'), so the suspend save/load/delete/list path is untouched andresume sweeps (
list()filtersstatus: 'paused') never see history rows.Persisting is best-effort and fire-and-forget — a history-write failure is
logged and swallowed, never breaking the run that produced it. New object fields
(
finished_at,duration_ms,error) are all optional and thestatusenumgains
running/completed/failedalongside the existingpaused.Verified end-to-end on a clean showcase instance: a schedule-triggered flow and
seven task-completion flows each left durable
completedrows; a genuinelyfailing flow (
showcase_resilient_sync) left afailedrow carrying itstry_catchfailure reason; a livepausedsuspended run coexisted withoutcollision; and after a full process restart the
failedrow — reason intact —was still queryable via
/api/v1/data/sys_automation_run. Newrun-history.test.tscovers completed/failed persistence, read-across-restart, and best-effort isolation.
Patch Changes
f84f8d5: fix(automation): bind flow triggers on a cold boot, not just after an HMR reload
Record-triggered (and other trigger-typed) flows silently never fired on a
fresh process start — in dev and in production. The automation service's
boot-time flow pull reads
ql.registry.listItems('flow'), which is empty forflows defined inline in an app manifest —
registry.registerApp()stores theapp under type
'app'and never promotes its inline flows to standaloneregistry
'flow'items. The re-sync that could see them only ran on themetadata:reloadedhook, which never fires on a cold boot (os devrestartsthe process on recompile rather than firing it, and production never reloads).
Net effect: after any real restart, no flow bound its trigger, so
record-change automations did not fire at all.
Fix: bind flows at
kernel:readyfromprotocol.getMetaItems({ type: 'flow' })— the canonical flattened flow view that
GET /meta/flowserves and that doessurface inline app flows — once every plugin has finished
init()/start()(so the app, hence its flows, is registered).
registerFlowis idempotent, sore-binding a flow the boot pull already registered is harmless.
Verified end-to-end on a clean instance: before the fix, updating a record
fired 0 flows (0 bound at boot); after, a cold boot binds all flows and a
single record update fires every matching record-triggered flow. Regression
test boots a kernel with an inline-app record-triggered flow served only via
protocol.getMetaItemsand asserts it is bound afterbootstrap()alone withno
metadata:reloadedfired — it fails on the pre-fix code.9693a36: fix(automation): bind a flow published while the server runs, without a restart
Follow-up to fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560 (cold-boot flow binding). A flow published while the server
is running — the Studio online-authoring journey: author a record-triggered
automation, publish it, immediately update a matching record — did not fire.
Its trigger only bound on the next process restart.
Two gaps, both fixed:
The publish path fired no rebind signal.
POST /packages/:id/publish-drafts→
protocol.publishPackageDraftspromotes the drafts to active but emitted noevent the automation service listens to. The runtime dispatcher now announces
metadata:reloadedafter a successful publish — the same signal a dev artifactreload fires (
MetadataPlugin._reloadAndAnnounce) — so boot-cached consumersre-sync without a restart.
The runtime re-sync read the wrong source. The automation service's
metadata:reloadedre-sync pulledmetadata.list('flow'), which returns 0 in areal running server (it does not surface inline app flows), so even when the
hook fired it bound nothing. It now reads
protocol.getMetaItems({ type: 'flow' })— the same flattened flow view fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560's cold-boot bind and
GET /meta/flowuse —while keeping the teardown of flows removed from the artifact. A failed or
unavailable protocol read is a no-op and never tears down live flows.
Production is largely unaffected (a deploy reboots the process, so fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560's
cold-boot bind covers it); this closes the gap for dev and single-instance
Studio authoring.
Verified end-to-end on a clean instance: authored a record-triggered flow in a
package, published it via
POST /packages/:id/publish-draftswithoutrestarting, then updated a matching record and observed the flow fire (before
the fix it did not). New regression tests boot a kernel whose protocol serves a
flow only after boot and assert
metadata:reloadedbinds it — and that there-sync reads the protocol, not
metadata.list— both failing on the pre-fix code.Updated dependencies [7c09621]
Updated dependencies [7709db4]
Updated dependencies [7c09621]
Updated dependencies [9860de4]
@objectstack/hono@12.0.0
Patch Changes
@objectstack/account@12.0.0
Patch Changes
@objectstack/setup@12.0.0
Patch Changes
@objectstack/studio@12.0.0
Patch Changes
@objectstack/cli@12.0.0
Patch Changes
7c09621: feat(security)!:
api.requireAuthnow defaults totrue— anonymous access to the data API is denied by default (ADR-0056 D2 flip)BREAKING. The global
requireAuthdefault flipped FROMfalseTOtrue(
RestApiConfigSchema.requireAuthin@objectstack/spec, mirrored byRestServer.normalizeConfigin@objectstack/rest). Anonymous requests tothe
/data/*CRUD + batch endpoints are now rejected with HTTP 401 unless thedeployment explicitly opts out. (Scope note: this gate covers the REST
/data/*surface — the metadata read/write endpoints and the dispatcherGraphQL route have their own pre-existing anonymous posture, tracked
separately; this flip does not change them.)
Migration (one line): a deployment that intentionally serves data publicly
(demo / playground / kiosk) sets the flag on the stack config — now a declared
ObjectStackDefinitionSchema.apifield, so it survivesdefineStackstrictparsing (previously an undeclared top-level
apikey was silently stripped):The REST plugin logs a boot warning for the explicit opt-out so a fail-open
posture is always visible. A misplaced
api.requireAuthat the plugin level(one nesting short) is now also called out with a boot warning instead of
being silently ignored.
What keeps working with no action:
publicFormGrant(create + read-back on the declared target object only);no
guest_portalprofile needed./auth,/health,/discoveryare exempt.objectstack servewith an auth-less stack — the CLI passes an explicitrequireAuth: falsefor stacks whose tier set has noauth(nothing couldauthenticate against them), with the boot warning.
Updated dependencies [07f055c]
Updated dependencies [1b1b34e]
Updated dependencies [9796e7c]
Updated dependencies [f84f8d5]
Updated dependencies [9693a36]
Updated dependencies [ffafb30]
Updated dependencies [7c09621]
Updated dependencies [24b62ee]
Updated dependencies [7709db4]
Updated dependencies [48ad533]
Updated dependencies [7c09621]
Updated dependencies [c2fdbf9]
Updated dependencies [9860de4]
@objectstack/client@12.0.0
Patch Changes
@objectstack/client-react@12.0.0
Patch Changes
@objectstack/cloud-connection@12.0.0
Patch Changes
@objectstack/connector-mcp@12.0.0
Patch Changes
@objectstack/connector-openapi@12.0.0
Patch Changes
@objectstack/connector-rest@12.0.0
Patch Changes
@objectstack/connector-slack@12.0.0
Patch Changes
@objectstack/core@12.0.0
Patch Changes
@objectstack/formula@12.0.0
Patch Changes
@objectstack/lint@12.0.0
Patch Changes
@objectstack/mcp@12.0.0
Patch Changes
@objectstack/metadata@12.0.0
Patch Changes
9860de4: Surface view-key collisions during view container expansion instead of renaming silently.
expandViewContainerkeeps its backward-compatible rename behaviour (<object>.<key>→<object>.<key>_2on collision) but now stamps a machine-readable_diagnostics.warningsentry on the renamedExpandedViewItem, explaining thatreferences targeting the requested name (form action targets, navigation
viewNames)will resolve to the other view. Both flattening loaders — the ObjectQL engine and the
MetadataPlugin — log these warnings at boot so the collision is visible instead of
manifesting as a form action opening a list view (expandViewContainer silently renames colliding form view keys (formViews.default → default_2) — form action targets break #2554).
Updated dependencies [07f055c]
Updated dependencies [7c09621]
Updated dependencies [7709db4]
Updated dependencies [7c09621]
Updated dependencies [9860de4]
@objectstack/metadata-core@12.0.0
Patch Changes
@objectstack/metadata-fs@12.0.0
Patch Changes
@objectstack/objectql@12.0.0
Patch Changes
24b62ee: Enforce array shape for multi-value fields in the write pipeline (objectql: write pipeline accepts scalar values for multi-value fields (multiselect/tags/select+multiple/lookup+multiple), corrupting stored shape #2552). Lone scalars sent at a
multiselect/checkboxes/tagsfield — or at aselect/radio/lookup/user/file/imagefield flaggedmultiple: true— are now normalized into single-element arrays before validation instead of being stored verbatim (which silently corrupted the column shape), un-wrappable shapes are rejected with a newinvalid_typevalidation code, and a legal array at aselect+multiplefield is no longer mis-rejected asinvalid_option.c2fdbf9: fix(objectql): surface the human validation message in
ValidationError.message, not afield (code)digestWhen an object-level validation rule (ADR-0020
validations[]) rejected asave, the console toast showed the generic English string
Validation failed for 1 field(s): _record (rule_violation)instead of therule author's own
message(often localized, e.g. 最小水深不能大于最大水深。).The author's message was always transported in
ValidationError.fields[].messagethrough the whole chain (rule-validator → REST envelope
fields[]→ client SDKerror.details), but every generic UI surface displays the top-levelError.message, which only contained thefield (code)pairs.Fix at the single choke point — the
ValidationErrorconstructor now builds itstop-level message from the per-field human messages (joined with
;), fallingback to
field (code)only when a field error has no message. Machine-readablecodeandfields[]are unchanged, so programmatic consumers and the RESTenvelope shape are unaffected; every client (console toast, CLI, SDK callers)
now sees the author-written message with no client-side change needed.
9860de4: Surface view-key collisions during view container expansion instead of renaming silently.
expandViewContainerkeeps its backward-compatible rename behaviour (<object>.<key>→<object>.<key>_2on collision) but now stamps a machine-readable_diagnostics.warningsentry on the renamedExpandedViewItem, explaining thatreferences targeting the requested name (form action targets, navigation
viewNames)will resolve to the other view. Both flattening loaders — the ObjectQL engine and the
MetadataPlugin — log these warnings at boot so the collision is visible instead of
manifesting as a form action opening a list view (expandViewContainer silently renames colliding form view keys (formViews.default → default_2) — form action targets break #2554).
Updated dependencies [9796e7c]
Updated dependencies [7c09621]
Updated dependencies [b5be479]
Updated dependencies [7709db4]
Updated dependencies [7c09621]
Updated dependencies [9860de4]
Updated dependencies [806a40a]
@objectstack/observability@12.0.0
Patch Changes
@objectstack/driver-memory@12.0.0
Patch Changes
@objectstack/driver-mongodb@12.0.0
Patch Changes
@objectstack/driver-sql@12.0.0
Patch Changes
@objectstack/driver-sqlite-wasm@12.0.0
Patch Changes
@objectstack/embedder-openai@12.0.0
Patch Changes
@objectstack/knowledge-memory@12.0.0
Patch Changes
@objectstack/knowledge-ragflow@12.0.0
Patch Changes
@objectstack/plugin-approvals@12.0.0
Patch Changes
@objectstack/plugin-audit@12.0.0
Patch Changes
@objectstack/plugin-dev@12.0.0
Patch Changes
@objectstack/plugin-email@12.0.0
Patch Changes
@objectstack/plugin-hono-server@12.0.0
Patch Changes
@objectstack/plugin-org-scoping@12.0.0
Patch Changes
@objectstack/plugin-reports@12.0.0
Patch Changes
@objectstack/plugin-sharing@12.0.0
Patch Changes
@objectstack/plugin-webhooks@12.0.0
Patch Changes
@objectstack/runtime@12.0.0
Patch Changes
9693a36: fix(automation): bind a flow published while the server runs, without a restart
Follow-up to fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560 (cold-boot flow binding). A flow published while the server
is running — the Studio online-authoring journey: author a record-triggered
automation, publish it, immediately update a matching record — did not fire.
Its trigger only bound on the next process restart.
Two gaps, both fixed:
The publish path fired no rebind signal.
POST /packages/:id/publish-drafts→
protocol.publishPackageDraftspromotes the drafts to active but emitted noevent the automation service listens to. The runtime dispatcher now announces
metadata:reloadedafter a successful publish — the same signal a dev artifactreload fires (
MetadataPlugin._reloadAndAnnounce) — so boot-cached consumersre-sync without a restart.
The runtime re-sync read the wrong source. The automation service's
metadata:reloadedre-sync pulledmetadata.list('flow'), which returns 0 in areal running server (it does not surface inline app flows), so even when the
hook fired it bound nothing. It now reads
protocol.getMetaItems({ type: 'flow' })— the same flattened flow view fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560's cold-boot bind and
GET /meta/flowuse —while keeping the teardown of flows removed from the artifact. A failed or
unavailable protocol read is a no-op and never tears down live flows.
Production is largely unaffected (a deploy reboots the process, so fix(automation): bind flow triggers on cold boot, not just after HMR reload #2560's
cold-boot bind covers it); this closes the gap for dev and single-instance
Studio authoring.
Verified end-to-end on a clean instance: authored a record-triggered flow in a
package, published it via
POST /packages/:id/publish-draftswithoutrestarting, then updated a matching record and observed the flow fire (before
the fix it did not). New regression tests boot a kernel whose protocol serves a
flow only after boot and assert
metadata:reloadedbinds it — and that there-sync reads the protocol, not
metadata.list— both failing on the pre-fix code.Updated dependencies [07f055c]
Updated dependencies [1b1b34e]
Updated dependencies [9796e7c]
Updated dependencies [7c09621]
Updated dependencies [24b62ee]
Updated dependencies [7709db4]
Updated dependencies [48ad533]
Updated dependencies [7c09621]
Updated dependencies [c2fdbf9]
Updated dependencies [9860de4]
@objectstack/service-analytics@12.0.0
Patch Changes
@objectstack/service-cache@12.0.0
Patch Changes
@objectstack/service-cluster@12.0.0
Patch Changes
@objectstack/service-cluster-redis@12.0.0
Patch Changes
@objectstack/service-datasource@12.0.0
Patch Changes
@objectstack/service-i18n@12.0.0
Patch Changes
@objectstack/service-job@12.0.0
Patch Changes
@objectstack/service-knowledge@12.0.0
Patch Changes
@objectstack/service-messaging@12.0.0
Patch Changes
@objectstack/service-package@12.0.0
Patch Changes
@objectstack/service-queue@12.0.0
Patch Changes
@objectstack/service-realtime@12.0.0
Patch Changes
@objectstack/service-settings@12.0.0
Patch Changes
@objectstack/service-storage@12.0.0
Patch Changes
@objectstack/trigger-api@12.0.0
Patch Changes
@objectstack/trigger-record-change@12.0.0
Patch Changes
@objectstack/trigger-schedule@12.0.0
Patch Changes
@objectstack/types@12.0.0
Patch Changes
@objectstack/verify@12.0.0
Patch Changes
7c09621: feat(security)!:
api.requireAuthnow defaults totrue— anonymous access to the data API is denied by default (ADR-0056 D2 flip)BREAKING. The global
requireAuthdefault flipped FROMfalseTOtrue(
RestApiConfigSchema.requireAuthin@objectstack/spec, mirrored byRestServer.normalizeConfigin@objectstack/rest). Anonymous requests tothe
/data/*CRUD + batch endpoints are now rejected with HTTP 401 unless thedeployment explicitly opts out. (Scope note: this gate covers the REST
/data/*surface — the metadata read/write endpoints and the dispatcherGraphQL route have their own pre-existing anonymous posture, tracked
separately; this flip does not change them.)
Migration (one line): a deployment that intentionally serves data publicly
(demo / playground / kiosk) sets the flag on the stack config — now a declared
ObjectStackDefinitionSchema.apifield, so it survivesdefineStackstrictparsing (previously an undeclared top-level
apikey was silently stripped):The REST plugin logs a boot warning for the explicit opt-out so a fail-open
posture is always visible. A misplaced
api.requireAuthat the plugin level(one nesting short) is now also called out with a boot warning instead of
being silently ignored.
What keeps working with no action:
publicFormGrant(create + read-back on the declared target object only);no
guest_portalprofile needed./auth,/health,/discoveryare exempt.objectstack servewith an auth-less stack — the CLI passes an explicitrequireAuth: falsefor stacks whose tier set has noauth(nothing couldauthenticate against them), with the boot warning.
Updated dependencies [07f055c]
Updated dependencies [1b1b34e]
Updated dependencies [9796e7c]
Updated dependencies [f84f8d5]
Updated dependencies [9693a36]
Updated dependencies [ffafb30]
Updated dependencies [7c09621]
Updated dependencies [24b62ee]
Updated dependencies [7709db4]
Updated dependencies [48ad533]
Updated dependencies [7c09621]
Updated dependencies [c2fdbf9]
Updated dependencies [9860de4]
@objectstack/console@12.0.0
create-objectstack@12.0.0
@objectstack/sdui-parser@12.0.0
objectstack-vscode@12.0.0
@objectstack/example-crm@4.0.70
Patch Changes
@objectstack/example-showcase@0.2.16
Patch Changes
@objectstack/example-todo@4.0.70
Patch Changes
@objectstack/example-embed-objectql@0.0.10
Patch Changes
@objectstack/dogfood@0.0.18
Patch Changes
@objectstack/downstream-contract@0.0.16
Patch Changes