@open-matrix/system-capabilities (1.1.32)
Installation
@open-matrix:registry=npm install @open-matrix/system-capabilities@1.1.32"@open-matrix/system-capabilities": "1.1.32"About this package
System capabilities
The system.capabilities actor owns capability grants, their mutation ledger and browser ACL projection. Boot with createStandaloneSystemCapabilities; configure backend: postgres and databaseUrl for durable operation. $introspect describes every operation. Grants and revocations require verified namespace administration and a stable operationId plus expectedRevision; repeated mutations replay the original result. Each committed grant or revoke writes one durable management audit intent in the same transaction.
Explaining and requesting access
The hosted home facade exposes these operations. Every call carries a real busToken; authorityRoot selects a home that system.auth verifies the caller owns or belongs to. Payload principal identifiers cannot substitute for authentication.
capability.explain {subject, operation, busToken, authorityRoot?}returnsallowedandreason. An active grant includesgrant.capabilityandgrant.grantorPrincipalId; a refused public operation returns the exact required grant and its publishing owner. A visible operation also includes the caller's ownrequest: {id, decision}when one exists within retention. A missing/private operation never discloses request state. Subjects are fully qualified logical subjects, for example<home>.system.canvas. The Registry resolves the service and its live$introspectdeclaration suppliesrequiredScope.capability.access.list {busToken, authorityRoot?}is owner-only and returns{ok: true, publications: [{subject, operation, authorityRoot, ownerPrincipalId, capability}]}for that verified home, ordered by subject and operation and bounded by the existing 1,000-publication limit. Membership alone cannot list disclosures. Withdrawn operations disappear from the list; an empty home returns an empty array.capability.access.publish {subject, operation, public, busToken, authorityRoot?}lets the verified home owner make that operation requestable, or withdraw its disclosure. There are at most 1,000 published operations per home. Visibility is opt-in. An undisclosed service returns the identicalSERVICE_NOT_FOUNDreply as a missing service to strangers; existing grantees may still explain their access.capability.access.request {subject, operation, busToken, authorityRoot?}persists one request per subject, operation and requester, then posts one owner notification with Approve/Deny actions. Duplicate requests return the same id and decision.capability.access.respond {id, decision: approve|deny, busToken, authorityRoot?}requires the original publishing owner to still own the home. Approval rechecks the live required scope and uses the existing GrantMutation path, including session ACL invalidation, with a stable operation id. Denial grants nothing. Both outcomes acknowledge the owner's request notification and notify the requester once. A committed decision cannot be reversed by replay.
Requests have a 30-day horizon and a 1,000-record limit per requesting home; outstanding grant projections are preserved until completed. Expired records are reclaimed on the next request from that home. Notification facts are never served beyond 30 days, matching the notification service's durable deduplication horizon. Undelivered notifications remain persisted, with up to 100 requests replayed each existing 60-second management maintenance cycle and on request/response. No requester-supplied notification content or recipient is trusted. capability.notification.get serves canonical facts only on the central service and is excluded from hosted facades. Account deletion removes disclosures and requests for the deleted principal and homes.
An operation with requiredScopeAuthority selects its target authority from extra call arguments. Since subject and operation alone cannot identify that target, publication is refused with CAPABILITY_ACCESS_DYNAMIC_AUTHORITY_UNSUPPORTED. Owner explanations return the same typed reason; private services still look missing to strangers. Static requiredScope operations support the complete request and approval flow.
An operation without an explicit requiredScope may enforce authorization inside its handler, such as the platform operator check on announcements. Publication is refused with CAPABILITY_ACCESS_AUTHORIZATION_UNDESCRIBED; owner explanations and existing public disclosures return allowed: false with that reason. An undisclosed operation still looks missing to strangers. Absence of scope metadata never implies permission, including for a namespace owner.
pnpm test runs store and actor regressions, including real PostgreSQL, real auth sessions, Registry resolution, notification delivery, refusal privacy, and request → approval → successful protected call. Local backend remains available for existing grant tests; access requests require PostgreSQL.
Auth stays behind the platform account boundary
The platform and services accounts run separate copies of this actor. Both copies read a person's home access through system.auth.introspect: auth.capability.authority derives the caller, home and role from a bus token, and returns that caller's display name and email only when identity: true is requested. Its optional owner-only homePeople: {limit, cursor?} input carries the exact authority-resolved space internally and returns one bounded homePeople page (principal ID, display name and role; never member email) from the existing space-membership read. The platform copy still calls full system.auth for named-principal ownership checks, browser-session invalidation, and deleted-account confirmation locally. The services copy uses introspection for capability checks and grant-session invalidation. A caller-supplied principal or space is never forwarded. capability.account.purge and the internal mutation-receipt lookup refuse outside the platform account. The account bridge exports only system.auth.introspect, never full system.auth or the browser-only system.profile facade.
The home-access read deliberately does not enumerate system.profile operations. The console identifies installed applications but does not claim that installation proves any platform-door allowance; each application operation applies its own access check when it is used.
Browser sessions expire, and are removed
A browser session's access snapshot lives until expires_at (an hour unless the issuer says
otherwise). Nothing reads an expired one: refreshing a person's sessions after a grant change and the
capability.status count both skip them. Each time a session is issued, up to 500 expired sessions
are deleted first (migration 007_browser_session_expiry.sql indexes expires_at for that), as
Postgres-backed session stores prune expired rows; before this they accumulated for ever.
Dependencies
Dependencies
| ID | Version |
|---|---|
| @open-matrix/contracts | 1.1.32 |
| @open-matrix/core | 1.1.32 |
| @open-matrix/credential-plane | 1.1.32 |
| @open-matrix/system-audit | 1.1.32 |
| @open-matrix/system-postgres | 1.1.32 |
Development Dependencies
| ID | Version |
|---|---|
| @matrix/test-utils | 1.1.32 |
| @open-matrix/system-auth | 1.1.32 |
| @open-matrix/system-notifications | 1.1.32 |
| @open-matrix/system-platform | 1.1.32 |
| @types/node | ^20.0.0 |
| esbuild | ^0.25.0 |
| nats | ^2.29.3 |
| tsx | ^4.0.0 |
| typescript | ^5.3.0 |