Releases: objectstack-ai/objectstack
Release list
@objectstack/platform-objects@16.1.0
Patch Changes
-
212b66a: fix(platform-objects): allow import/export on sys_business_unit (#3025)
The Business Units list (Setup → Business Units) surfaces Import/Export buttons,
butsys_business_unitdeclared a restrictiveenable.apiMethodswhitelist of
only the five CRUD verbs. The REST data plane gates import/export on that
whitelist (ADR-0049), so both buttons returned405 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 the
org tree is expected to support bulk import. Added'import'and'export'to
the whitelist. Import reuses thecreate/updateaffordances the object already
grants, 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 (#3025 / #3391 P0)
Completes the #3025 point-fix. #3392 unblocked
sys_business_unit's Import/Export
buttons (405OBJECT_API_METHOD_NOT_ALLOWED) by adding'import'/'export'to its
enable.apiMethodswhitelist, but the HRIS org-tree sync scenario imports two
tables together — the units and their memberships — and the sibling
sys_business_unit_memberwas left on the CRUD-only whitelist, so the membership
Import/Export path still 405'd. #3391's P0 checklist pairs both tables; this is the
half #3392 missed.packages/platform-objects/src/identity/sys-business-unit-member.object.ts:
apiMethodsgains'import','export'. Import reuses the object's
already-granted create/update affordances; export is a bulk read.- Reconcile-safe: the object is
managedBy:'platform', but
reconcileManagedApiMethodsonly strips generic write verbs
(create/update/upsert/delete/purge—MANAGED_WRITE_VERB_AFFORDANCE). It never
touchesimport/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). - Regression test (
platform-objects.test.ts) locksimport/exportpresence and
CRUD retention. Proven red-before-green: reverting the object edit fails with
expected [...] to include 'import'.
Transitional: #3391 P2 replaces per-object
import/exportdeclarations with a
single derived mapping (import ⊆ create/update, export ⊆ list) and reclaims the
explicit entries on both business-unit objects together. -
Updated dependencies [9e45b63]
- @objectstack/spec@16.1.0
- @objectstack/metadata-core@16.1.0
@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) (#3361)The per-request
Server-Timingpath (#2408) — where an admin sends
X-OS-Debug-Timing: 1(orjson) and gets phase timings while an ordinary user
gets 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's
RestServer(which shadows the Hono plugin's own CRUD), and its identity
resolver never opened the gate. Only global mode (OS_SERVER_TIMING=true) — which
discloses to every caller, not just admins — worked.- observability: the disclosure predicate
isPerfDisclosurePrincipal(ec)now
lives here (the home of the gate), the single definition of "who may pull
per-request timings" shared by every HTTP entry point.@objectstack/runtime
re-exports it for back-compat. - rest:
RestServer.resolveExecCtxopens the gate for an admin/service
principal (via the carriedposturerung), the REST-server analog of the
dispatcher — this is the fix that makesos serve/devemit. - plugin-hono-server: the standalone CRUD surface's self-contained
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 getsServer-Timingwhile a member/anon does not.
- observability: the disclosure predicate
-
Updated dependencies [9e45b63]
- @objectstack/spec@16.1.0
@objectstack/objectql@16.1.0
@objectstack/metadata@16.1.0
Patch Changes
- Updated dependencies [212b66a]
- Updated dependencies [d10c4dc]
- Updated dependencies [9e45b63]
- Updated dependencies [b20201f]
- @objectstack/platform-objects@16.1.0
- @objectstack/spec@16.1.0
- @objectstack/core@16.1.0
- @objectstack/metadata-core@16.1.0
- @objectstack/types@16.1.0
- @objectstack/metadata-fs@16.1.0
@objectstack/metadata-protocol@16.1.0
@objectstack/metadata-fs@16.1.0
Patch Changes
- @objectstack/metadata-core@16.1.0
@objectstack/metadata-core@16.1.0
Patch Changes
- Updated dependencies [9e45b63]
- @objectstack/spec@16.1.0
@objectstack/mcp@16.1.0
@objectstack/lint@16.1.0
Minor Changes
-
fa006fb: Validate dashboard filter field-existence at build time (extend ADR-0021, #3365).
validateWidgetBindingsnow checks that every dashboard-level filter (dateRange- each
globalFilters[]) resolves to a real field on each bound widget's dataset
object. Since #2501 wired these filters into every widget's analytics query, a
filter field absent on a widget's object — e.g. adateRangebound to
close_dateinherited by an account/contact widget over a different object —
emitted invalid SQL (no such column: close_date) and crashed the widget at
render time. That build-decidable invariant previously escapedos validate/
os buildand failed only when a user opened the dashboard.
It now fails the build (new rule
dashboard-filter-field-unknown) with a message
naming the dashboard, widget, filter, field, and object, unless the widget opts
out viafilterBindings: { <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, legacytargetWidgetsallow-list, filter default). Registry-injected
system fields (e.g.created_at, thedateRangedefault) and objects outside
the validated stack never false-positive. - each
-
db160dd: Flag dead action/route references in dashboard header & widget 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
- Updated dependencies [9e45b63]
- @objectstack/spec@16.1.0
- @objectstack/formula@16.1.0
- @objectstack/sdui-parser@16.1.0