chore: version packages#3387
Merged
Merged
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 21, 2026 14:15
cd6121b to
71f2c63
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
2 times, most recently
from
July 21, 2026 14:39
b9d79bc to
29551e8
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 21, 2026 15:02
29551e8 to
5d8ea00
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 21, 2026 15:12
5d8ea00 to
122798f
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 21, 2026 15:22
122798f to
eba7196
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
2 times, most recently
from
July 21, 2026 15:39
6e7b185 to
10462e5
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
3 times, most recently
from
July 21, 2026 16:11
a3ac5a8 to
6c4be0f
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 21, 2026 16:21
6c4be0f to
ed5c0a3
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 21, 2026 16:40
ed5c0a3 to
6ec6ac0
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 22, 2026 00:05
6ec6ac0 to
21933cf
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
from
July 22, 2026 00:27
21933cf to
f3ce1f2
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/cli@16.1.0
Minor Changes
9e45b63: feat(cli): preflight that every
requirescapability has an installable providerin the current edition (Preflight that required capabilities have an installable provider in the current edition #3366)
A capability listed in
requires: [...]was only checked atserve/starttime,and a missing provider produced a generic "not installed — add it to your
dependencies" error even when the provider has no installable version in the
current edition.
os validate(token-vocabulary only) andos build(neverresolved providers) both passed, so a
validate && build && testCI script nevercaught it — it surfaced only as an opaque boot crash. Seen upgrading an
open-edition app from
14.7to16after@objectstack/service-aiwentcloud-only (ADR-0025).
@objectstack/spec/kernelnow exportsPLATFORM_CAPABILITY_PROVIDERS(token → provider package + edition) and a pure
classifyRequiredCapability()—one machine-readable source of truth for the provider/edition knowledge the
serve resolver previously encoded informally.
os buildandos validategained a provider preflight. Arequiresentrywhose provider has no installable version in the active edition (e.g.
ai→@objectstack/service-ai, cloud-only) now fails fast with an edition-awaremessage; an absent-but-installable provider is an advisory
pnpm addhint, nota hard error; a satisfied
requireslist passes unchanged.os serveboot error now renders the same classification, so preflight andboot read identically.
db160dd: Flag dead action/route references in dashboard header & widget actions (ADR-0049 for references, Flag dead action/route references in dashboard header actions (ADR-0049 for references) #3367).
os validate/os buildnow run a newvalidateDashboardActionRefsgate over every dashboardheader.actions[]and widgetactionUrl:actionType: 'script' | 'modal'— error unlessactionUrlresolves to a defined action (stack.actionsor an object'sactions).modalalso resolves via the runtime<verb>_<object>convention (create_/new_/add_/edit_/update_+ a real object) and bare object names. A dangling target ships a button that renders and silently does nothing on click — a false affordance, exactly the "declared ≠ enforced" gap ADR-0049 closes, applied to references.actionType: 'url'— warning when a relative in-app path names aobjects/reports/dashboards/pages/viewsroute whose target does not exist in the stack. External URLs, interpolated (${…}) targets, and opaque routes are skipped to keep false positives near zero.Patch Changes
@objectstack/console@16.1.0
Minor Changes
7b07417: Console (objectui) refreshed to
cf2d56e32a11. Frontend changes in this range:objectui range:
9a5f016f7d5c...cf2d56e32a11@objectstack/core@16.1.0
Minor Changes
b20201f: fix(service-automation):
runAs:'user'runs data ops with the triggering user'sreal permission sets + positions, not a bare member fallback (service-automation: runAs:'user' runs data ops with a credential-less user — trigger context never carries the actor's permission sets/positions (follow-up to #1888) #3356, follow-up to
[P0][security] Flow runAs never switches execution identity #1888)
Since [P0][security] Flow runAs never switches execution identity #1888 the automation engine honours
flow.runAs(systemelevates), butthe
runAs:'user'credential propagation was hollow. A record-change-triggeredrunAs:'user'flow ran its data nodes (update_record, …) with a zero-grantprincipal — only the
member/everyonebaseline — even when the triggering userwas fully authorized. Two faces by object config: a
privateobject 403'd thein-flow write (
not permitted for positions [org_member, everyone]— the user'spermission sets were invisible); a
public_read_writeobject let the writethrough but silently stripped readonly/FLS-gated fields. The root cause: the
ObjectQL record-change hook session carries only a
userId— never the writer'spositions/permission sets — and nothing in between resolved them, so the comment
promising "enforces RLS exactly as the user who made the change" never held.
The fix resolves the triggering user's actual authorization at run setup, from
the same tables a direct REST request resolves through:
@objectstack/corefactors the userId-driven core ofresolveAuthzContextinto a new exported
resolveUserAuthzGrants(ql, userId, opts)— the single placethat reads
sys_member/sys_user_position/sys_*_permission_setandderives positions, permission-set names,
platform_admin, and posture. TheHTTP resolver now delegates to it (behaviour byte-identical; the full contract
suite still passes), so a non-HTTP surface that already knows the user id builds
the SAME envelope instead of re-implementing the reads.
@objectstack/service-automationgainsAutomationEngine.setUserGrantsResolver,wired by the plugin to
resolveUserAuthzGrantsover the objectql/data engine.For a
runAs:'user'run whose trigger left the authz envelope unresolved (nopermissions), the engine now resolves the user's positions + permission setsonce at run setup and threads them into every data node's ObjectQL context —
so the run enforces RLS/FLS exactly as that user. Contexts that already carry
permissionsare left untouched (a REST trigger, and notably an ADR-0090 agentceiling acting on-behalf-of a user — always non-empty — so a deliberately
narrowed identity is never re-broadened).
runAs:'system'is unchanged, and aresolver error fails safe (warns, keeps the bare user — never elevates).
@objectstack/trigger-record-changestops forwarding the misleadinghalf-populated
positions(empty in practice, and neverpermissions) from thehook session; it forwards
userId+ tenant only and lets the engine resolve thefull grants authoritatively.
When no ObjectQL engine is present (bare engine / tests) the resolver is unwired
and run identity is unchanged from before.
Patch Changes
@objectstack/lint@16.1.0
Minor Changes
fa006fb: Validate dashboard filter field-existence at build time (extend ADR-0021, Validate dashboard filter field-existence at build time (extend ADR-0021) #3365).
validateWidgetBindingsnow checks that every dashboard-level filter (dateRangeglobalFilters[]) resolves to a real field on each bound widget's datasetobject. Since Dashboard-level filters (date / region) driving multiple charts #2501 wired these filters into every widget's analytics query, a
filter field absent on a widget's object — e.g. a
dateRangebound toclose_dateinherited by an account/contact widget over a different object —emitted invalid SQL (
no such column: close_date) and crashed the widget atrender time. That build-decidable invariant previously escaped
os validate/os buildand failed only when a user opened the dashboard.It now fails the build (new rule
dashboard-filter-field-unknown) with a messagenaming the dashboard, widget, filter, field, and object, unless the widget opts
out via
filterBindings: { <name>: false }or re-targets to an existing field —mirroring the field-existence invariant ADR-0032 enforces for CEL references.
Effective-field resolution matches the runtime (
filterBindingsre-target /opt-out, legacy
targetWidgetsallow-list, filter default). Registry-injectedsystem fields (e.g.
created_at, thedateRangedefault) and objects outsidethe validated stack never false-positive.
db160dd: Flag dead action/route references in dashboard header & widget actions (ADR-0049 for references, Flag dead action/route references in dashboard header actions (ADR-0049 for references) #3367).
os validate/os buildnow run a newvalidateDashboardActionRefsgate over every dashboardheader.actions[]and widgetactionUrl:actionType: 'script' | 'modal'— error unlessactionUrlresolves to a defined action (stack.actionsor an object'sactions).modalalso resolves via the runtime<verb>_<object>convention (create_/new_/add_/edit_/update_+ a real object) and bare object names. A dangling target ships a button that renders and silently does nothing on click — a false affordance, exactly the "declared ≠ enforced" gap ADR-0049 closes, applied to references.actionType: 'url'— warning when a relative in-app path names aobjects/reports/dashboards/pages/viewsroute whose target does not exist in the stack. External URLs, interpolated (${…}) targets, and opaque routes are skipped to keep false positives near zero.Patch Changes
@objectstack/service-automation@16.1.0
Minor Changes
b20201f: fix(service-automation):
runAs:'user'runs data ops with the triggering user'sreal permission sets + positions, not a bare member fallback (service-automation: runAs:'user' runs data ops with a credential-less user — trigger context never carries the actor's permission sets/positions (follow-up to #1888) #3356, follow-up to
[P0][security] Flow runAs never switches execution identity #1888)
Since [P0][security] Flow runAs never switches execution identity #1888 the automation engine honours
flow.runAs(systemelevates), butthe
runAs:'user'credential propagation was hollow. A record-change-triggeredrunAs:'user'flow ran its data nodes (update_record, …) with a zero-grantprincipal — only the
member/everyonebaseline — even when the triggering userwas fully authorized. Two faces by object config: a
privateobject 403'd thein-flow write (
not permitted for positions [org_member, everyone]— the user'spermission sets were invisible); a
public_read_writeobject let the writethrough but silently stripped readonly/FLS-gated fields. The root cause: the
ObjectQL record-change hook session carries only a
userId— never the writer'spositions/permission sets — and nothing in between resolved them, so the comment
promising "enforces RLS exactly as the user who made the change" never held.
The fix resolves the triggering user's actual authorization at run setup, from
the same tables a direct REST request resolves through:
@objectstack/corefactors the userId-driven core ofresolveAuthzContextinto a new exported
resolveUserAuthzGrants(ql, userId, opts)— the single placethat reads
sys_member/sys_user_position/sys_*_permission_setandderives positions, permission-set names,
platform_admin, and posture. TheHTTP resolver now delegates to it (behaviour byte-identical; the full contract
suite still passes), so a non-HTTP surface that already knows the user id builds
the SAME envelope instead of re-implementing the reads.
@objectstack/service-automationgainsAutomationEngine.setUserGrantsResolver,wired by the plugin to
resolveUserAuthzGrantsover the objectql/data engine.For a
runAs:'user'run whose trigger left the authz envelope unresolved (nopermissions), the engine now resolves the user's positions + permission setsonce at run setup and threads them into every data node's ObjectQL context —
so the run enforces RLS/FLS exactly as that user. Contexts that already carry
permissionsare left untouched (a REST trigger, and notably an ADR-0090 agentceiling acting on-behalf-of a user — always non-empty — so a deliberately
narrowed identity is never re-broadened).
runAs:'system'is unchanged, and aresolver error fails safe (warns, keeps the bare user — never elevates).
@objectstack/trigger-record-changestops forwarding the misleadinghalf-populated
positions(empty in practice, and neverpermissions) from thehook session; it forwards
userId+ tenant only and lets the engine resolve thefull grants authoritatively.
When no ObjectQL engine is present (bare engine / tests) the resolver is unwired
and run identity is unchanged from before.
Patch Changes
@objectstack/spec@16.1.0
Minor Changes
9e45b63: feat(cli): preflight that every
requirescapability has an installable providerin the current edition (Preflight that required capabilities have an installable provider in the current edition #3366)
A capability listed in
requires: [...]was only checked atserve/starttime,and a missing provider produced a generic "not installed — add it to your
dependencies" error even when the provider has no installable version in the
current edition.
os validate(token-vocabulary only) andos build(neverresolved providers) both passed, so a
validate && build && testCI script nevercaught it — it surfaced only as an opaque boot crash. Seen upgrading an
open-edition app from
14.7to16after@objectstack/service-aiwentcloud-only (ADR-0025).
@objectstack/spec/kernelnow exportsPLATFORM_CAPABILITY_PROVIDERS(token → provider package + edition) and a pure
classifyRequiredCapability()—one machine-readable source of truth for the provider/edition knowledge the
serve resolver previously encoded informally.
os buildandos validategained a provider preflight. Arequiresentrywhose provider has no installable version in the active edition (e.g.
ai→@objectstack/service-ai, cloud-only) now fails fast with an edition-awaremessage; an absent-but-installable provider is an advisory
pnpm addhint, nota hard error; a satisfied
requireslist passes unchanged.os serveboot error now renders the same classification, so preflight andboot read identically.
@objectstack/hono@16.1.0
Patch Changes
@objectstack/account@16.1.0
Patch Changes
@objectstack/setup@16.1.0
Patch Changes
@objectstack/studio@16.1.0
Patch Changes
@objectstack/client@16.1.0
Patch Changes
@objectstack/client-react@16.1.0
Patch Changes
@objectstack/cloud-connection@16.1.0
Patch Changes
@objectstack/connector-mcp@16.1.0
Patch Changes
@objectstack/connector-openapi@16.1.0
Patch Changes
@objectstack/connector-rest@16.1.0
Patch Changes
@objectstack/connector-slack@16.1.0
Patch Changes
@objectstack/formula@16.1.0
Patch Changes
@objectstack/mcp@16.1.0
Patch Changes
@objectstack/metadata@16.1.0
Patch Changes
@objectstack/metadata-core@16.1.0
Patch Changes
@objectstack/metadata-fs@16.1.0
Patch Changes
@objectstack/metadata-protocol@16.1.0
Patch Changes
@objectstack/objectql@16.1.0
Patch Changes
@objectstack/observability@16.1.0
Patch Changes
818e6a3: fix(server-timing): emit the per-request, admin-gated
Server-Timingheader on the standard server (os serve/dev) (v16.0: per-request admin-gated Server-Timing never emits on the hono server (os serve/dev) #3361)The per-request
Server-Timingpath (feat(observability): per-request performance timing → Server-Timing (perf-tuning mode) #2408) — where an admin sendsX-OS-Debug-Timing: 1(orjson) and gets phase timings while an ordinary usergets nothing — never emitted on the shipped Hono server. The disclosure gate the
Hono middleware opens is only ever flipped by the runtime dispatcher's
timedResolveExecutionContext, but the data (/api/v1/data/*) and metadata(
/api/v1/meta/*) routes onos serve/devare served by@objectstack/rest'sRestServer(which shadows the Hono plugin's own CRUD), and its identityresolver never opened the gate. Only global mode (
OS_SERVER_TIMING=true) — whichdiscloses to every caller, not just admins — worked.
isPerfDisclosurePrincipal(ec)nowlives here (the home of the gate), the single definition of "who may pull
per-request timings" shared by every HTTP entry point.
@objectstack/runtimere-exports it for back-compat.
RestServer.resolveExecCtxopens the gate for an admin/serviceprincipal (via the carried
posturerung), the REST-server analog of thedispatcher — this is the fix that makes
os serve/devemit.resolveCtxopens the gate too (deriving the rung for the gate decision only,never writing it onto the enforcement context). Adds an e2e test that boots the
Hono app and asserts an admin gets
Server-Timingwhile a member/anon does not.Updated dependencies [9e45b63]
@objectstack/platform-objects@16.1.0
Patch Changes
212b66a: fix(platform-objects): allow import/export on sys_business_unit (业务单元需要支持导入:列表页导入按钮 405(apiMethods 白名单缺 import/export) #3025)
The Business Units list (Setup → Business Units) surfaces Import/Export buttons,
but
sys_business_unitdeclared a restrictiveenable.apiMethodswhitelist ofonly the five CRUD verbs. The REST data plane gates import/export on that
whitelist (ADR-0049), so both buttons returned
405 OBJECT_API_METHOD_NOT_ALLOWED.This was an unintentional gap, not a deliberate restriction: the object's fields
(
external_ref,effective_from/to) are designed for HRIS batch sync, and theorg tree is expected to support bulk import. Added
'import'and'export'tothe whitelist. Import reuses the
create/updateaffordances the object alreadygrants, and the managed-object reconciliation backstop leaves import/export
untouched (it only strips write verbs). Regression test added.
d10c4dc: fix(platform-objects): allow import/export on sys_business_unit_member (业务单元需要支持导入:列表页导入按钮 405(apiMethods 白名单缺 import/export) #3025 / 跟踪:UI 操作按钮与 apiMethods 白名单一致性契约落地(#3026 设计定稿) #3391 P0)
Completes the 业务单元需要支持导入:列表页导入按钮 405(apiMethods 白名单缺 import/export) #3025 point-fix. fix(platform-objects): allow import/export on sys_business_unit (#3025) #3392 unblocked
sys_business_unit's Import/Exportbuttons (405
OBJECT_API_METHOD_NOT_ALLOWED) by adding'import'/'export'to itsenable.apiMethodswhitelist, but the HRIS org-tree sync scenario imports twotables together — the units and their memberships — and the sibling
sys_business_unit_memberwas left on the CRUD-only whitelist, so the membershipImport/Export path still 405'd. 跟踪:UI 操作按钮与 apiMethods 白名单一致性契约落地(#3026 设计定稿) #3391's P0 checklist pairs both tables; this is the
half fix(platform-objects): allow import/export on sys_business_unit (#3025) #3392 missed.
packages/platform-objects/src/identity/sys-business-unit-member.object.ts:apiMethodsgains'import','export'. Import reuses the object'salready-granted create/update affordances; export is a bulk read.
managedBy:'platform', butreconcileManagedApiMethodsonly strips generic write verbs(
create/update/upsert/delete/purge—MANAGED_WRITE_VERB_AFFORDANCE). It nevertouches
import/export, so the declared whitelist reaches the REST gate intact(no false-green: the static whitelist the regression test asserts IS what
apiAccessDenialFromEnableenforces at runtime).platform-objects.test.ts) locksimport/exportpresence andCRUD retention. Proven red-before-green: reverting the object edit fails with
expected [...] to include 'import'.Transitional: 跟踪:UI 操作按钮与 apiMethods 白名单一致性契约落地(#3026 设计定稿) #3391 P2 replaces per-object
import/exportdeclarations with asingle derived mapping (import ⊆ create/update, export ⊆ list) and reclaims the
explicit entries on both business-unit objects together.
Refs 业务单元需要支持导入:列表页导入按钮 405(apiMethods 白名单缺 import/export) #3025, 跟踪:UI 操作按钮与 apiMethods 白名单一致性契约落地(#3026 设计定稿) #3391.
Updated dependencies [9e45b63]
@objectstack/driver-memory@16.1.0
Patch Changes
@objectstack/driver-mongodb@16.1.0
Patch Changes
@objectstack/driver-sql@16.1.0
Patch Changes
@objectstack/driver-sqlite-wasm@16.1.0
Patch Changes
@objectstack/embedder-openai@16.1.0
Patch Changes
@objectstack/knowledge-memory@16.1.0
Patch Changes
@objectstack/knowledge-ragflow@16.1.0
Patch Changes
@objectstack/plugin-approvals@16.1.0
Patch Changes
@objectstack/plugin-audit@16.1.0
Patch Changes
@objectstack/plugin-auth@16.1.0
Patch Changes
@objectstack/plugin-dev@16.1.0
Patch Changes
@objectstack/plugin-email@16.1.0
Patch Changes
@objectstack/plugin-hono-server@16.1.0
Patch Changes
818e6a3: fix(server-timing): emit the per-request, admin-gated
Server-Timingheader on the standard server (os serve/dev) (v16.0: per-request admin-gated Server-Timing never emits on the hono server (os serve/dev) #3361)The per-request
Server-Timingpath (feat(observability): per-request performance timing → Server-Timing (perf-tuning mode) #2408) — where an admin sendsX-OS-Debug-Timing: 1(orjson) and gets phase timings while an ordinary usergets nothing — never emitted on the shipped Hono server. The disclosure gate the
Hono middleware opens is only ever flipped by the runtime dispatcher's
timedResolveExecutionContext, but the data (/api/v1/data/*) and metadata(
/api/v1/meta/*) routes onos serve/devare served by@objectstack/rest'sRestServer(which shadows the Hono plugin's own CRUD), and its identityresolver never opened the gate. Only global mode (
OS_SERVER_TIMING=true) — whichdiscloses to every caller, not just admins — worked.
isPerfDisclosurePrincipal(ec)nowlives here (the home of the gate), the single definition of "who may pull
per-request timings" shared by every HTTP entry point.
@objectstack/runtimere-exports it for back-compat.
RestServer.resolveExecCtxopens the gate for an admin/serviceprincipal (via the carried
posturerung), the REST-server analog of thedispatcher — this is the fix that makes
os serve/devemit.resolveCtxopens the gate too (deriving the rung for the gate decision only,never writing it onto the enforcement context). Adds an e2e test that boots the
Hono app and asserts an admin gets
Server-Timingwhile a member/anon does not.Updated dependencies [9e45b63]
Updated dependencies [b20201f]
Updated dependencies [818e6a3]
@objectstack/plugin-pinyin-search@16.1.0
Patch Changes
@objectstack/plugin-reports@16.1.0
Patch Changes
@objectstack/plugin-security@16.1.0
Patch Changes
@objectstack/plugin-sharing@16.1.0
Patch Changes
@objectstack/plugin-webhooks@16.1.0
Patch Changes
@objectstack/rest@16.1.0
Patch Changes
818e6a3: fix(server-timing): emit the per-request, admin-gated
Server-Timingheader on the standard server (os serve/dev) (v16.0: per-request admin-gated Server-Timing never emits on the hono server (os serve/dev) #3361)The per-request
Server-Timingpath (feat(observability): per-request performance timing → Server-Timing (perf-tuning mode) #2408) — where an admin sendsX-OS-Debug-Timing: 1(orjson) and gets phase timings while an ordinary usergets nothing — never emitted on the shipped Hono server. The disclosure gate the
Hono middleware opens is only ever flipped by the runtime dispatcher's
timedResolveExecutionContext, but the data (/api/v1/data/*) and metadata(
/api/v1/meta/*) routes onos serve/devare served by@objectstack/rest'sRestServer(which shadows the Hono plugin's own CRUD), and its identityresolver never opened the gate. Only global mode (
OS_SERVER_TIMING=true) — whichdiscloses to every caller, not just admins — worked.
isPerfDisclosurePrincipal(ec)nowlives here (the home of the gate), the single definition of "who may pull
per-request timings" shared by every HTTP entry point.
@objectstack/runtimere-exports it for back-compat.
RestServer.resolveExecCtxopens the gate for an admin/serviceprincipal (via the carried
posturerung), the REST-server analog of thedispatcher — this is the fix that makes
os serve/devemit.resolveCtxopens the gate too (deriving the rung for the gate decision only,never writing it onto the enforcement context). Adds an e2e test that boots the
Hono app and asserts an admin gets
Server-Timingwhile a member/anon does not.Updated dependencies [212b66a]
Updated dependencies [d10c4dc]
Updated dependencies [9e45b63]
Updated dependencies [b20201f]
Updated dependencies [818e6a3]
@objectstack/runtime@16.1.0
Patch Changes
818e6a3: fix(server-timing): emit the per-request, admin-gated
Server-Timingheader on the standard server (os serve/dev) (v16.0: per-request admin-gated Server-Timing never emits on the hono server (os serve/dev) #3361)The per-request
Server-Timingpath (feat(observability): per-request performance timing → Server-Timing (perf-tuning mode) #2408) — where an admin sendsX-OS-Debug-Timing: 1(orjson) and gets phase timings while an ordinary usergets nothing — never emitted on the shipped Hono server. The disclosure gate the
Hono middleware opens is only ever flipped by the runtime dispatcher's
timedResolveExecutionContext, but the data (/api/v1/data/*) and metadata(
/api/v1/meta/*) routes onos serve/devare served by@objectstack/rest'sRestServer(which shadows the Hono plugin's own CRUD), and its identityresolver never opened the gate. Only global mode (
OS_SERVER_TIMING=true) — whichdiscloses to every caller, not just admins — worked.
isPerfDisclosurePrincipal(ec)nowlives here (the home of the gate), the single definition of "who may pull
per-request timings" shared by every HTTP entry point.
@objectstack/runtimere-exports it for back-compat.
RestServer.resolveExecCtxopens the gate for an admin/serviceprincipal (via the carried
posturerung), the REST-server analog of thedispatcher — this is the fix that makes
os serve/devemit.resolveCtxopens the gate too (deriving the rung for the gate decision only,never writing it onto the enforcement context). Adds an e2e test that boots the
Hono app and asserts an admin gets
Server-Timingwhile a member/anon does not.Updated dependencies [9e45b63]
Updated dependencies [b20201f]
Updated dependencies [818e6a3]
@objectstack/service-analytics@16.1.0
Patch Changes
@objectstack/service-cache@16.1.0
Patch Changes
@objectstack/service-cluster@16.1.0
Patch Changes
@objectstack/service-cluster-redis@16.1.0
Patch Changes
@objectstack/service-datasource@16.1.0
Patch Changes
@objectstack/service-i18n@16.1.0
Patch Changes
@objectstack/service-job@16.1.0
Patch Changes
@objectstack/service-knowledge@16.1.0
Patch Changes
@objectstack/service-messaging@16.1.0
Patch Changes
@objectstack/service-package@16.1.0
Patch Changes
@objectstack/service-queue@16.1.0
Patch Changes
@objectstack/service-realtime@16.1.0
Patch Changes
@objectstack/service-settings@16.1.0
Patch Changes
@objectstack/service-sms@16.1.0
Patch Changes
@objectstack/service-storage@16.1.0
Patch Changes
@objectstack/trigger-api@16.1.0
Patch Changes
@objectstack/trigger-record-change@16.1.0
Patch Changes
b20201f: fix(service-automation):
runAs:'user'runs data ops with the triggering user'sreal permission sets + positions, not a bare member fallback (service-automation: runAs:'user' runs data ops with a credential-less user — trigger context never carries the actor's permission sets/positions (follow-up to #1888) #3356, follow-up to
[P0][security] Flow runAs never switches execution identity #1888)
Since [P0][security] Flow runAs never switches execution identity #1888 the automation engine honours
flow.runAs(systemelevates), butthe
runAs:'user'credential propagation was hollow. A record-change-triggeredrunAs:'user'flow ran its data nodes (update_record, …) with a zero-grantprincipal — only the
member/everyonebaseline — even when the triggering userwas fully authorized. Two faces by object config: a
privateobject 403'd thein-flow write (
not permitted for positions [org_member, everyone]— the user'spermission sets were invisible); a
public_read_writeobject let the writethrough but silently stripped readonly/FLS-gated fields. The root cause: the
ObjectQL record-change hook session carries only a
userId— never the writer'spositions/permission sets — and nothing in between resolved them, so the comment
promising "enforces RLS exactly as the user who made the change" never held.
The fix resolves the triggering user's actual authorization at run setup, from
the same tables a direct REST request resolves through:
@objectstack/corefactors the userId-driven core ofresolveAuthzContextinto a new exported
resolveUserAuthzGrants(ql, userId, opts)— the single placethat reads
sys_member/sys_user_position/sys_*_permission_setandderives positions, permission-set names,
platform_admin, and posture. TheHTTP resolver now delegates to it (behaviour byte-identical; the full contract
suite still passes), so a non-HTTP surface that already knows the user id builds
the SAME envelope instead of re-implementing the reads.
@objectstack/service-automationgainsAutomationEngine.setUserGrantsResolver,wired by the plugin to
resolveUserAuthzGrantsover the objectql/data engine.For a
runAs:'user'run whose trigger left the authz envelope unresolved (nopermissions), the engine now resolves the user's positions + permission setsonce at run setup and threads them into every data node's ObjectQL context —
so the run enforces RLS/FLS exactly as that user. Contexts that already carry
permissionsare left untouched (a REST trigger, and notably an ADR-0090 agentceiling acting on-behalf-of a user — always non-empty — so a deliberately
narrowed identity is never re-broadened).
runAs:'system'is unchanged, and aresolver error fails safe (warns, keeps the bare user — never elevates).
@objectstack/trigger-record-changestops forwarding the misleadinghalf-populated
positions(empty in practice, and neverpermissions) from thehook session; it forwards
userId+ tenant only and lets the engine resolve thefull grants authoritatively.
When no ObjectQL engine is present (bare engine / tests) the resolver is unwired
and run identity is unchanged from before.
Updated dependencies [9e45b63]
Updated dependencies [b20201f]
@objectstack/trigger-schedule@16.1.0
Patch Changes
@objectstack/types@16.1.0
Patch Changes
@objectstack/verify@16.1.0
Patch Changes
create-objectstack@16.1.0
@objectstack/sdui-parser@16.1.0
objectstack-vscode@16.1.0
@objectstack/example-crm@4.0.91
Patch Changes
@objectstack/example-showcase@0.3.13
Patch Changes
@objectstack/example-todo@4.0.91
Patch Changes
@objectstack/example-embed-objectql@0.0.31
Patch Changes
@objectstack/dogfood@0.0.39
Patch Changes
@objectstack/downstream-contract@0.0.37
Patch Changes
@objectstack/http-conformance@0.0.5
Patch Changes