18.2.0
Release notes and upgrade checklist for 18.2.0, the first release that ships the Console and the @object-ui packages from this repository. A minor that carries breaking changes: one access rule for file references, app automation refused identity writes under elevation, installs that check declared dependencies, action copy refused at publish, and seven breaking changes that os migrate meta carries.
How this page was compiled. From the 231 changesets the version commit
27f38ada49 (#25640) consumed, each placed by classifyReleaseBullet in
scripts/release-github-releases.mjs, the function that groups the GitHub
Release body. The five sections below use its five headings, in its order, and
its counts: 52 need you to act, 7 are converted for you, 41 add
capabilities, 3 declare a semantic change, and 128 are other fixes.
Every changeset is listed once, under its section. The version commit wrote an
## 18.2.0 section into 111 CHANGELOGs, and the same function places each of
their distinct entries in the section this page lists it under. Each package's
Release also carries an Updated dependencies bullet under 其他修复, which this
page does not repeat. Four changesets merged while the version pull request
was open are not in 18.2.0 and wait in .changeset/ for the next release:
the navigation group default (#26427), missed scheduled runs (#26485), every
cell error of an import row (#26454), and the copy button on keyboard focus
(#26487). The
upgrade checklist is compiled from the changesets and
has not been walked.
Highlights — 18.2.0
- The Console and
@object-ui/*ship from this repository. objectui became theui/workspace of this repository (fd40831, #25825, for #25752), and@objectstack/consoleis built fromui/apps/consoleat the commit it releases (2a61f08, #25745). There is no objectui pin any more:dist/.objectui-shaanddist/.objectstack-injection.jsonleave the Console tarball. The 37 public@object-ui/*packages join the@objectstack/*fixed group, so 18.2.0 is the first release in which both scopes publish at one version. See Console (Studio). - ⚠️ A minor that breaks. 59 of the 231 changesets are declared breaking:
15 graded
minorbecause they narrow the metadata protocol, and 44 gradedpatchunder the level rule (#25105, ruling A). 52 of them need you to act; 7 are converted byos migrate meta. Read the version number. - One access rule for a file reference. A record write claims or copies
only a file its caller may read, and is refused at the field when it names
one it may not (
3761710,7e4af20). An unclaimed file is served only inside its organization (3b8ea15), a released file keeps its record's rule (d9e6ac2), and no anonymous write carries a file (e2b40a2,b4199c9). A seed can now ship a file withseedFile(path)(2163e80). - App automation cannot write identity rows under elevation. A
runAs: 'system'hook, an action body, an inherited system context andctx.api.sudo()are refused writes to position holdings, permission-set grants, invitations and memberships, as a system flow already was (073f08b,6a6ebff), and a hook or action body that writes one in its source is refused at save (07586f5). A permission set that only shares a position's name is no longer granted to its holders (733b3c8): name it in the position'spermissionSets. An environment that runs HotCRM takes HotCRMv6.0.0or later first. - Installs check what a package declares. An install whose
manifest.dependenciesthe environment does not satisfy is refused422 DEPENDENCY_MISSING(3446d43), and a module that declares its app may share the app's namespace (be78977). - Action copy is judged at publish. An action's
confirmText,successMessageanderrorMessagearetemplateslots (384bb7b), and a blank sentence, an unbound root or a${…}token the runner shows raw now failsos validate,os buildand the publish gate (0c81694,d727348). - Pinned means pinned.
@objectstack/cli,@objectstack/honoand@objectstack/plugin-devpublish their@objectstack/*dependencies at exactly their own version (f4860da), so the override the 18.1.0 checklist added is no longer needed. kind: 'react'pages are off unless the deployment turns them on withOS_PAGE_REACT_ENABLED=true(5e7cf63), and the Console document carries a nonce-based content-security-policy (3c30afd).- New to author: a field permission
when(c8cb510),controlledByParent.ownerMayEdit(5e113b3), a flow'srequiredPermissions(f1ddace),demoStaff(f00e8d5), duration measures (d1663ba), the$nowcomparand (be531f6), and translation keys for positions, permission sets, reports and form entries.
Release facts, as measured
Read from the version commit 27f38ada49, its CHANGELOGs, and npm view on
2026-10-27:
| Measured | |
|---|---|
| Version commit | 27f38ada49 (#25640) |
| Published | 2026-10-27 |
| Packages | 110 publish at 18.2.0: 72 @objectstack/*, create-objectstack, and 37 @object-ui/*. The VS Code extension (object-ui) takes the version and is private |
@object-ui/* before this release | every one of the 37 reads latest 18.1.0 on npm, published from the objectui repository |
@object-ui/sdui-parser | not released. It is deleted from the workspace (80f267d, #26343); its 18.1 line on npm is its last. Use @objectstack/sdui-parser |
next | 18.0.0-next.5 on @objectstack/cli and @objectstack/console, older than latest. ⛔ Never install @next for 18 |
rc | 17.0.0-rc.6 |
| CLI dependencies | the 49 @objectstack/* dependencies of @objectstack/cli are declared workspace:* and publish as exact versions. At 18.1.0, eight were workspace:^ and published as caret ranges |
Two notes for reading the 18.2.0 CHANGELOGs:
- Each entry names its own commit. Every 18.2.0 CHANGELOG bullet opens with the commit that added its changeset, as the generator has done since #25804. This page cites the same commits.
- objectui's last 65 changesets are one entry. The changes objectui made
between its 18.1.0 release and the import came across under
ui/.changeset/, whichchangeset versiondoes not read. One changeset carries them into this release (9a0af4e, #26068), and each of the 65 files stays inui/.changeset/as the full record.
The Docker image was not read for this page.
What's new in 18.2.0
The version number is not the signal
Every package still versions in lockstep, and now that includes the
@object-ui/* scope. The level of a release says whether the metadata
protocol moved, and nothing else:
| Kind of change | Level |
|---|---|
| Added to the metadata protocol: a new authorable key, accepted value or metadata type | minor |
| Narrowed or retired: a key removed or tombstoned, a value refused, a requirement tightened | minor |
| Semantic: the meaning or default of an authorable key changes | minor |
Everything else: REST, drivers, services, the CLI, the Console, feat: and fix!: alike | patch |
So 18.2.0 carries 44 changesets graded patch that say BREAKING, beside
15 graded minor. Of all 231, 38 are graded minor and 193 patch; none is
major. Pin exact versions of both scopes, and read the release notes for
every version you cross.
需手动处理 — breaking changes you must act on
The 52 entries that are breaking and carry no ADR-0087 conversion. Each line names what you do; the CHANGELOG entry carries the full before and after.
Security, identity and administration
- A permission set that shares a held position's name is no longer granted
(
733b3c8, #26064). A holder of positionsales_manageris granted only the sets the position's definition lists inpermissionSets; theposition_name_fold_grantwarning now logsgranted: false. Fix: writepermissionSets: ['sales_manager']on the position. An environment that runs HotCRM must be on HotCRMv6.0.0or later before it takes 18.2.0. Code that buildsUserAuthzGrantsorResolvedAuthzContextfrom@objectstack/coreby hand sets the newdirectPermissions([]with no grant rows). - A
runAs: 'system'hook and an action body are refused writes tosys_user_position,sys_user_permission_set,sys_invitationandsys_member(073f08b, #25954), with403 PERMISSION_DENIED, and nothing is written. Fix: set the hook'srunAsto'user'; move an action body's grant into arunAs: 'user'flow; change invitations and memberships through the organization endpoints, such asPOST /api/v1/auth/organization/invite-member,cancel-invitationandremove-member. - The same refusal reaches a hook that inherits a system context, a hook's
ctx.api.sudo(), and an action reached throughexecute()(6a6ebff, #25982). Fix: declarerunAs: 'user'on the hook and leavesudo()out, or use the organization endpoints. A hook a plugin registers in code withengine.registerHookis not affected. - On a runtime with no hierarchy resolver, a permission set that grants
own_and_reports,unitorunit_and_belowis refused on publish (b029c90, #26305):422 INVALID_METADATAunder the rulehierarchy-scope-capability-required, and a warning on a draft save. Fix: set the grant'sreadScope/writeScopetoownororg, or run it where the enterprisehierarchy-securityresolver is mounted. - A delegated admin's write outside their own scope answers
403 DELEGATION_SCOPE_VIOLATION, not403 PERMISSION_DENIED(495fa07, #26320). Fix: a client that matchedPERMISSION_DENIEDfor these refusals matches the new code too; its message is safe to show. - Under a walled posture,
POST /api/v1/auth/admin/create-useradds the new user to the administrator's current organization, and refuses400 NO_ACTIVE_ORGANIZATIONwhen there is none (17f8217, #25626). Fix: switch to the organization the user belongs to, then create them. - Admin create-user refuses a password outside the deployment's length
range with
400 INVALID_REQUEST, and a too-long one no longer answersPASSWORD_TOO_LONG(1d2a246, #25927). Fix: send a password insideminPasswordLength/maxPasswordLength, orgeneratePassword: true; matchINVALID_REQUESTinstead ofPASSWORD_TOO_LONG. IdentityImportDeps.getAuthContext()is required (e3e936e, #26018), so admin import-users sizes a temporary password to the deployment's range. Fix: a host that callsrunAdminImportUsersitself passesgetAuthContext, for exampleAuthManager.getAuthContext(). TheAuthPluginroute is already wired.- The built-in
auth.invitationmail requiresexpiresAt(d284ff3, #26072); a send without it is refusedMISSING_VARIABLES: expiresAt. Fix: code that sendsauth.invitationitself adds the invitation's expiry instant to the send'sdataasexpiresAt.
Files and storage
- An anonymous public-form submission carries no file (
e2b40a2, #25682).POST /api/v1/forms/:slug/submitrefuses a value in afile,image,avatar,videooraudiofield with400 VALIDATION_FAILED. Fix: take the file field off the guest-facing form, or leave it for the visitor to leave empty; a visitor who must provide a file registers and signs in. - A form open to anonymous intake that declares a file field fails the
build and the publish gate (
6ad226a, #25737), under the rulepublic-form-file-field. Fix (one line): take the file field off the public form. A stored view keeps serving until its next save. - Every anonymous write is refused a file value, not only the public form
door (
b4199c9, #26036). Fix: leave file fields empty in an anonymous write; a signed-in caller provides the file through the authenticated upload doors. - A record write claims or copies only a file its caller may read
(
3761710, #25951), under the download door's own rule. Fix: reference a file as a caller who may read it, or upload it again; a server-side copy between records runs as a system write. - An unclaimed file is served only within its organization under the
isolatedandgrouppostures (3b8ea15, #25704); anyone else gets403 FILE_DOWNLOAD_DENIED. Fix: download it while acting in its organization, have a record claim it, or mark itacl: 'public_read'. - A record write naming a file its caller may not read is refused at the
field with
400 VALIDATION_FAILEDandinvalid_value(7e4af20, #26237); so is an id that names no file of the organization. Fix: name a file the caller may read, or leave the field empty. - A file its record lets go keeps that record's read rule until it is
claimed again or collected (
d9e6ac2, #26144).sys_filegainsreleased_ref_objectandreleased_ref_id, which schema sync adds. Fix: read or claim such a file as a reader of that record. - A seed record's file field holding an id that names no stored file is
refused, by row (
2163e80, #26244). Fix: replace the value withseedFile('<path in the package>'), imported from@objectstack/spec/data, or remove it. The same change addsseedFile:os buildwrites the bytes into the artifact and the seed loader stores them. - A flow screen field typed
filecollects an upload, and the resume refuses any value that is not a file id with400 INVALID_SCREEN_INPUT(6d9d3ef, #26134). Fix: a caller that resumes the run itself uploads first and posts thesys_fileid; a field not meant for an upload takes anothertype.
Metadata the build and the save doors now refuse
- An approval node refuses
excludeSubmitter: truebesideonEmptyApprovers: 'auto_approve'(4bcc4df, #25700). Fix: choose'admin_rescue'(the default),'fail', or'fallback'withfallbackApprovers.excludeSubmitteris new in this release, so no released source holds the pair. - An action's
confirmText,successMessageorerrorMessagefinding is an error, not a warning (0c81694, #25702): a blank sentence, a hole over a root the key does not bind, a single-brace{x}token, logic in a hole, or a${…}token the runner shows raw.os validateandos buildfail, and an active save answers422 INVALID_METADATA. Fix: write the hole the finding prescribes (Delete {{ record.name }}?), name a root the key binds, double a single brace, move logic out of the hole, or delete a blank key. - The holeless
${record.*}confirmTextand${result.*}successMessageare refused too (d727348, #25989): the Console's runner shows them as written. Fix:Delete ${record.name}?becomesDelete {{ record.name }}?, andInvitation sent to ${result.email}becomesInvitation sent to {{ result.email }}. - A code package's action is stored as its
ActionSchemaparse (e44a1ff, #25699), so a body the schema refuses fails registration with422 INVALID_METADATA, andrequiresFeaturenow takes effect on bound actions. Fix: correct the action asissues[]describes; one that passesos validateis unaffected. - An object's own actions are parsed the same way (
a4eae06, #25981): a raw manifest's object whose action failsActionSchemais refused, and nothing of it is stored. Fix: correct the action atactions.N.KEYasissues[]describes.
Flows and notifications
- A
notifynode mails the address in an email field of the trigger record, and refuses a computed address no user holds (d1e329e, #25721). In a node whosechannelsincludeemail, a recipient an expression evaluates to an address must belong to a user, or the node fails. One address receives at most 5 email-field sends per hour. Fix: give that address its own node withrecipients: { emailField: 'FIELD' }andchannels: 'email', or give the person a user.@objectstack/service-automationnow depends on@objectstack/plugin-auth. - A
notifynode that does not nameemailfails on an address no user holds, written out or computed, instead of reporting success (b0384f3, #25964). Fix: addemailto the node'schannelsto mail a written-out address, or name a user (a user id, an audience selector such asteam:ID, or the address the user holds). - The flow trigger doors refuse a
paramsthat is not a JSON object with400 VALIDATION_FAILEDnamingparams(e12d3f3, #25974). Fix: sendparamsas an object ({"params":{"ownerId":"u1"}}), or leave the key out. - The action door refuses a body or
paramsthat is not an object, and the trigger door a body that is not one (3821ec8, #26034). Fix: send each as an object, for example{"recordId":"…","params":{"note":"x"}}, or leave it out.
REST, MCP, imports and analytics
- Eight doors answer an unknown resource
404 RESOURCE_NOT_FOUND(0dc4b5d, #25628):POST /api/v1/packages/:id/publish-draftsanddiscard-drafts,GET /api/v1/packages/:id/commits,GET /api/v1/automation/:name/runs,DELETE /api/v1/automation/:name, andPATCH,DELETEandmigrate-credentialon/api/v1/datasources/:name. Fix:packages.publishDrafts,discardDrafts,listCommits,automation.listRunsandautomation.deleteonObjectStackClientnow reject for an unknown id; treat that as "no such resource". - An inline import mapping entry's
transform,defaultValueandrequiredare applied (50af6fa, #25540), onPOST /api/v1/data/:object/import, the async job and the admin user import.transform: 'date_format'is refused400 UNSUPPORTED_TRANSFORM, and a blank required cell400 MISSING_REQUIRED_FIELD. Fix: dropdate_format(a date field still parses the cell), and fill a required column or give it adefaultValue. - An
update/upsertimport refuses its own rows that share a match key, before any write, withDUPLICATE_MATCH_KEY(617f27e, #26250). Fix: keep one row per key and import again. GETandDELETEon/api/v1/mcpanswer405withAllow: POST(bb85f5f, #25774). An MCP client stops re-opening the stream by itself. Fix: a probe or health check that readGET /api/v1/mcpas200sends aPOSTinitializeinstead.- A NOT NULL refusal on a declared field answers
400 VALIDATION_FAILEDat every door, named by the field's label (48e84a9, #26026); the dispatcher/datadoors answered500. Fix: a TypeScript caller moves fromnotNullRefusalSite(answer)tonotNullViolationSite(error)in@objectstack/types, and dropsrelabelNotNullRefusal; a client reads the validator's envelope. - A NOT NULL refusal on a column no field declares answers the same
400body at the dispatcher/dataand actions doors (1af2cea, #26171), where they answered500 INTERNAL_ERRORand400 VALIDATION_ERROR. Fix: readerror.codeanderror.details; the driver's text no longer reaches the wire.@objectstack/typesaddsdriverNotNullRefusalAnswer. - The analytics admission bridge answers
503 SERVICE_UNAVAILABLEwhen thesecurityservice is missing or cannot be used (2e6d446, #25673), not403. Fix: treat503as a server-side fault, and register asecurityservice (for exampleplugin-security) where analytics should answer. - An analytics read gate that could not decide answers
503 SERVICE_UNAVAILABLE(f1d6be0, #25595): a provider that threw, field permissions or the API exposure declaration that could not be resolved. Real denials keep403. Fix: retry once the resolver is healthy, and do not show it as a missing grant. - A filtered measure asked as
CUBE.MEASUREapplies its filter (3117289, #26007), as the bare name did, and the read gate judges the filter's fields. Fix: nothing for a caller that wanted the measure as declared; one that relied on the unfiltered total asks an unfiltered measure. - A
driver-sqlupsertwith nothing left to merge is a plainINSERT(88f22e0, #26015), so a collision raises the unique-violation error instead of merging every column. Fix: catch the unique violation, or useupdate()to change a stored row.
Packages and installs
- An install checks the package's declared
dependenciesfirst (3446d43, #25986), atPOST /api/v1/packages, the in-processinstallPackageandPOST /api/v1/marketplace/install-local; an unmet entry refuses the whole install422 DEPENDENCY_MISSING, naming each one. Fix: install the dependencies, at versions inside the declared ranges, first. - A package that declares an installed app in
manifest.dependenciesmay share its namespace (be78977, #26054), and a boot hydrates installed packages in dependency order. A multi-package artifact's wrapper id no longer counts as delivered, andDeclaredDependencyCheck.deliveredIdsis removed. Fix: a module that uses its app's namespace declares the app inmanifest.dependencies.
Deployment
kind: 'react'pages are off unless the deployment turns them on (5e7cf63, #25789). With the tier off, a react page shows a notice and the Console's policy drops'unsafe-eval'. Fix: setOS_PAGE_REACT_ENABLED=trueon a deployment that serves react pages;OS_PAGE_REACT=onis still read, with a deprecation warning. Stored pages need no change.
Code against the published @objectstack/* packages
| Removed or changed | Use instead |
|---|---|
renderTemplate from @objectstack/plugin-email (92a0073, #26399) | an email_template item, rendered by services.email through renderTemplate({ template, data, locale }) or sendTemplate |
ResolveLocalizationInput.tenantId of resolveLocalizationContext in @objectstack/core (65145d3, #26078) | organizationId, the organization's id; never an environment id. A spread object that still carries tenantId is ignored, so search for it |
@objectstack/sdui-parser's validateTree judges the nodes in a manifest entry's slots (8faba89, #26211) | nothing for the save gate's manifest, which carries no slots. SchemaNode and ValidationResult are deprecated aliases of ParsedSchemaNode and ManifestValidationResult |
a template's formatter locale read from a root named locale (14b5597, #26282) | the evaluate context's locale: templateEngine.evaluate(expr, { extra: roots, locale }), or fillTemplateHoles(source, roots, locale) |
Console and the @object-ui/* packages
- objectui's own breaking changes from its 18.1.0 to the import arrive as
one entry (
9a0af4e, #26068). Five retirements, each with its migration inui/.changeset/: the rawhtmlnode (13449-retire-html-renderer.md), themodulewidget source (13450-retire-widget-module-source.md), nine zero-consumer modules with@object-ui/runnermade private (the four13453-*files on modules, hooks,LiveCursorsand test helpers), the@object-ui/providerstrio (13453-providers-retire-trio.md), and nine duration keys that now end inMsorSeconds(25762-duration-keys-carry-unit.md). Also: thereact/react-dompeer is^19.0.0, so a React 18 host is no longer supported, and thereact-pagescapability defaults off in@object-ui/core. Fix: follow each file's table, and move a host to React 19. - The renderer runs
@objectstack/sdui-parser, and@object-ui/sdui-parseris deleted (80f267d, #26343). An html-tier page whose attribute does not fit its declared type now shows the compile-error block instead of dropping the value. Fix: depend on@objectstack/sdui-parser, and write the value in its declared type (columns={['name','amount']}). useAdapter()andAdapterCtxfrom@object-ui/reactare typed byDataSource(ef025fe, #26292), and the package no longer depends on@object-ui/data-objectstack. Fix: declare your adapter once with adeclare module '@object-ui/react'augmentation ofAdapterContextRegister(adapter: ObjectStackAdapter), or narrow where you read an ObjectStack-only member. A host that imports@object-ui/app-shellkeeps today's type.- 54 root exports of
@object-ui/app-shellare retired (aec5f7b, #26219). Fix: derive a retired type from the name the entry still exports (UseUrlOverlayOptionsbecomesParameters<typeof useUrlOverlay>[1]), as the CHANGELOG's FROM → TO list gives for each; the rest have no replacement. - The node-level
visibleOn,hiddenOnanddisabledOnare retired (e843b5b, #26274), with no alias window. Fix: rename the key and keep the value:visibleWhen,hidden,disabled. A form field'sfields[].visibleOnis a different slot and is unchanged. - The Console stops offering New, Edit and Delete when
/me/permissionsomits the bit (b727956, #26273), because the server refuses them. Fix: nothing, unless a user should have those actions: grant the bit in a permission set. FilterBuilderRow.valueis the spec rule's value: optional, and may benull(0489214, #26338). Fix: code that readsrow.valuehandlesundefinedandnullfirst.- A
FilterBuilderRowlist value holds strings and numbers only (57ab06b, #26380). Fix: write a boolean entry as its string spelling, or keep the boolean as a scalar underequals.
自动迁移 — converted for you by os migrate meta
Seven breaking changes carry an ADR-0087 registration on the protocol-18 step, and
os migrate meta does each one: it converts what has one meaning and lists
the rest for you. A live author of a narrowing is refused at parse, with the
prescription.
os migrate meta --from 17 lists the edits for your sources (--write
applies the ones it can trace to one literal), and os migrate meta --stored
lists and rewrites a deployment's stored rows.
| Change | ADR-0087 id | What os migrate meta does, and what is left to you |
|---|---|---|
A permission set can no longer declare allowDelete: false beside modifyAllRecords: true; an omitted allowDelete beside it now parses to true (f6ba134, #25707) | permission-modify-all-allow-delete-false-to-true, permission-modify-all-allow-delete-false-refused | converts a stored row or built artifact to allowDelete: true, which changes no access decision. A source that declares the pair is refused: delete allowDelete, or, for "edit every record, delete none", drop modifyAllRecords and add a criteria sharing rule with accessLevel: 'edit' (os explain security-modify-all-delete-withheld) |
An SLA escalation's escalateTo naming a team:, department: or org_membership_level: address, or the prefix ADR-0090 D3 retired, is refused (9993165, #26154) | approval-escalation-dead-target-refused | lists each one; no conversion, because only you know who was meant. Write a position name, position:NAME, a user id or an email; the retired prefix becomes position: |
The package upgrade model leaves @objectstack/spec: UpgradePlanSchema and its family, IPackageService.planUpgrade / upgrade / rollback / getSnapshot, and PackageUpgradeResponse.data.plan (557973d, #25757) | kernel-package-upgrade-family-retired | lists it; nothing ever read or produced these shapes. Delete the imports. A new version over an installed package is POST /api/v1/packages with overwrite: true; the package rollback served is POST /api/v1/packages/:id/rollback with a commitId |
PackageDependency.optional and AppManifest.dependencies are tombstones (436d284, #26401) | dependency-unread-spellings-retired | lists it; nothing read either key. Delete the key, and declare each dependency with its range in manifest.dependencies |
A locale must be a BCP-47 tag: zh_CN, a padded value or a language name is refused (39a78b1, #25983) | translation-locale-tag-canonicalized, translation-locale-non-tag-refused | rewrites zh_CN to zh-CN and trims whitespace, in stored rows and with --from 17 --write in sources; any other value is reported as a TODO. Replace a language name with its tag |
A runAs: 'system' hook or a type: 'script' action whose sandboxed JS body writes sys_user_position, sys_user_permission_set, sys_invitation or sys_member is refused at save, not only when it runs (07586f5, #26430) | hook-action-body-system-identity-assignment-write-refused | lists each one; no conversion, because the route is your choice. Set the hook's runAs to 'user', or move an action's grant into a runAs: 'user' flow; use the organization endpoints for invitations and memberships |
PositionGrantVia loses 'name', and Setup → Positions drops its "(by name)" badge (9494dd8, #26398) | position-grant-via-name-retired | lists it; no server serves the value. Delete a branch that compares with 'name', and name the set in the position's permissionSets |
新增能力 — new capabilities
Access and approvals
- A field permission entry can carry a row condition,
when, on its edit vote (c8cb510, #25980), in the CEL ofrowLevelSecurity[].using(status == 'approved'), and the Studio permission-set form offers it as When (edit) (7111e14, #26010). sharing.controlledByParent.ownerMayEdit: truelets the owner of acontrolled_by_parentdetail row update it with read access to the master (5e113b3, #26005).- A flow declares who may start it with
requiredPermissions, checked at the trigger route, atype: 'flow'action and a flow endpoint (f1ddace, #25643). - An approval step's
excludeSubmitterkeeps the submitter off the slate its approvers resolve to (49653f9, #25632); the engine honours it in this release (see other fixes). - A record-anchored approval lock read answers
{ locked }to every caller who can read the record, atGET /api/v1/approvals/records/:object/:recordId/lock(6a2866a, #26361). - An administrator who is not the approver sees one status line and one
override menu on a record under approval (
054652b, #26053). - A delegated admin's out-of-scope save shows the server's reason in the
Console (
0e7be7e, #26363). - A member takes back their own comment reaction through
DELETE /api/v1/comments/reactions/:id, with no object delete grant (1a298dd, #26345). - A free-text
searchresolves only over the fields the caller may query (5874d25, #25705), so a user or owner picker no longer fails403for a non-admin member.
Organizations, sign-in and demo data
- A single-organization deployment can rename its organization
(
a0fac02, #25661), andPUBLIC_AUTH_FEATURESbooks Rename Organization under the organization capability (a0fac02, #25661). - The platform OIDC provider emits the standard
localeclaim at userinfo (431f065, #26012). - An invitee who opens the link signed out is greeted for the invitation
and offered "Create an account and join" first (
326a559, #26158). demoStaffdeclares the demo accounts a development boot creates and the seed deals its rows to (f00e8d5, #25830).
Flows and actions
- A
notifyrecipient can be the address in an email field of the trigger record,{ emailField: 'applicant_email' }(6021b5e, #25645). - An
apiflow's start node may name its inbound hook secret,config.secretRef, instead of carrying it (fa44dd2, #25703). - A
type: 'flow'action may declareonSuccess, and the Console navigates after a run that completes (dc71845, #26011). - A read-only
record_linkscreen field shows a record the run created, as a link to its page (4548ba3, #26355). - A hook body reads
ctx.provenance, so a guard that tells a flow's write from a user's ships as metadata (1ee1d1b, #25952). - An action's
confirmText,successMessageanderrorMessagearetemplateslots over the roots the Console's runner binds (384bb7b, #25637). The refusals that follow from it are under 需手动处理.
Data, imports, seeds and analytics
- An import column can be written only when its row is created
(
applyOn), andmatchFieldstakes ordered key sets (b77bb37, #25664). - A seed dataset column can be written only on create,
columns.FIELD.applyOn: 'create'(493a6c4, #25813). - A package's action can launch a flow, and its widget bind a dataset, that
another package of the same artifact ships, through
defineStack(config, { artifactFlows })(cc10e74, #25617). - A dataset measure can aggregate the time between two datetime fields,
duration: { from, to, unit }(d1663ba, #25903). - A filter can compare a datetime column against now shifted by days held
on the record,
{ $now: true, addDays }(be531f6, #26261). - A list-view grouping level can order its groups by another field,
grouping.fields[].orderBy(b00fc55, #25828). - Object-level
composite/repeaterare documented as untyped JSON, and a typed list points to a child object (4034f47, #25755).
Translations
- A form section entry's
label,placeholderandhelpTextare translatable atobjects.<object>._sections.<section>.fields.<field>(42d9fe8, #25620). - Positions and permission sets, as
positions.<name>andpermissions.<name>(47af3dd, #25701). - Reports, as
reports.<name>(dd5e355, #25826). - The System Overview's tile captions and column headers in every shipped
locale (
db5fca7, #26008). - 92 message keys nothing read are deleted from the ten Console locale
packs (
326a559, #26158).
Boot and serving
- The pinyin search companion pass no longer holds readiness, and an
unchanged restart reads no rows (
f9a1e93, #25690). GET /meta/appjudges its navigation on the protocol's execution face,getMetaItemsForExecution, instead of parsing every object on each read (1ac2bb5, #25941).
Console
- A kanban board dims the lanes a dragged card's
state_machinecloses, and refuses a drop into one (c14e910, #26253). - An edit form's
state_machineselect offers only the moves the server accepts (4f48d2b, #26033). - The record activity timeline folds consecutive updates by one actor into
one row with a count (
0b76a1f, #26055). - A related list's "View all" opens the rows the list showed, its own
filterincluded, or is not offered (4f7e041, #26060). - The
@object-ui/types/zodmirrors keep an unknown key instead of dropping it (1bbb7bf, #26019). - The Console document's
connect-srcnames the store the server presigns browser uploads to, so S3, R2 and MinIO uploads work under the policy (69aa630, #26281).
语义变化 — semantic changes
hideEmpty: falseon an all-emptyrecord:detailssection renders, in read mode, the heading and one fold row instead of a column of empty rows (2af790f, #25612). Edit mode is unchanged, and no authored metadata needs a change.- A
notifynode'srecipients: an address written out is an author constant, sent as written; a computed address on an email-channel node must be a user's;{ emailField }is delivered (52f3f51, #25739). Thedescribe()text says so; the refusal itself is under 需手动处理. actions: []on arecord:related_listalso hides the built-in New (f02e644, #26277). A page that wroteactions: []and still wants New deletes the key.
Three entries the Release body files elsewhere declare Metadata-protocol: semantic too. The flow screen field typed file (#26134) is breaking, so it
is listed under 需手动处理. The action copy template slots (#25637) and
object-level composite / repeater (#25755) declare a Clause-②: yes
widening, so they are new capabilities.
其他修复 — other fixes
The 128 entries that declare no breaking change and no protocol kind. The ones that touch an upgrade come first.
Packaging and module formats
@objectstack/cli,@objectstack/honoand@objectstack/plugin-devdepend on the other@objectstack/*packages at exactly their own version; remove the overrides you added to hold them (f4860da, #25662).- The bundled blank template of
create-objectstackpins every@objectstack/*dependency at the exact release version (dc6c7ee, #25665). - The declared
zodfloor moves to^4.6.6, past GHSA-mrhx-c7xc-m3w5, andpostal-mimeandnodemailermove to their patched releases (7cd2ebf, #25657). - Every entry point of
@objectstack/specshares one module graph, so a schema two entries reach ships once (3a2d38c, #25748). - The 14 published packages that had no LICENSE ship one (
2409c9c, #26260). - Publishing metadata: per-format types in
exports, declaredsideEffects, and a README for the 18 published packages without one (8061f33, #26198). @objectstack/coreserves both module formats from one declaration, so each export condition gets its owntypes(876aa27, #26279).- The ESM-only subpaths of
metadata-core,service-clusterandcreate-objectstackdeclare their types underimport(40f5c6e, #26321). - The
@objectstack/cliREADME says its three code subpaths are ESM (e2129cb, #26352). - TypeScript's legacy
node10module resolution is documented as unsupported for packages with subpath exports (3b480e0, #26378).
CLI and the development boot
os devcompiles the config before it boots, so the served connectorbaseUrlis the one dispatch calls (8b7253c, #26240).- A direct
os serve --devcompiles the config the same way (6294157, #26289). os dev -p Nandos serve --port Nexport the port asOS_PORT/PORTto the config (9888008, #26268), and so doesos devwhen it shifts off a busy port (583b024, #26330).os create plugin NAME --in-reposcaffolds extendtsconfig.base.json(a8e7393, #26331), and pass their owntypecheckandbuild(13e5c0e, #26395).objectstack buildlowers a hook handler that readsctx.provenanceinstead of bundling it (1ee1d1b, #25952).os i18n checkreads a field'sinlineHelpTextas the default-locale text of itshelpkey (1252db9, #25720).- The Console drift warning and refusal name
pnpm console:build, not the retiredpnpm objectui:build(8fcdf52, #26063). - The verify README says how a local stack arms scheduled flows (
9657318, #25659).
The Console package and its policy
@objectstack/consoleis built in this workspace fromui/apps/console,dist/.objectui-shaanddist/.objectstack-injection.jsonleave the tarball, and the@object-ui/*packages join the fixed group (2a61f08, #25745). See Console (Studio).- The last objectui pin refresh, to
b41ed7f68956: among others the first page load no longer downloads the chat UI, andhtmlandrichtextvalues are sanitized withrehype-sanitize(f871670, #25735). - The Console document is served with a nonce-based content-security-policy;
list another map or tile host in
OS_CONSOLE_CSP_CONNECT_SRC(3c30afd, #25569). OS_CONSOLE_MAP_STYLE_URLnames a deployment's default map style, served asmapStyleUrlonGET /api/v1/runtime/configand allowed by the policy (21075ce, #26162).
Approvals
- An approval step's
excludeSubmitter: truekeeps the submitter from approving their own request (888d686, #25722). - An SLA escalation that reassigns to a target resolving to no one keeps the
request on its approvers and notifies them (
2351c8d, #25600). - The approver a pending step waits on can read the record the request is
about (
b7b04e5, #26397). - An approval notification names the record by its title (
c51aed4, #26389). - The note an
admin_rescuerequest writes on its timeline reads in the reader's language (ca80f05, #25627).
Flows and messaging
- A refusal a flow's write node meets is worded in the language of the person
who started the run (
de2b7e0, #25929). - A
notifynode namingemailand another channel mails an address no user holds, and writes no inbox row addressed to it (d12b0c1, #26039). - The automation run doors answer another flow's run as an unknown one
(
9ca36b1, #25944). - A sandboxed hook's or action's business refusal is logged once, at info,
without a stack (
1d3ad39, #26249).
Data, imports and analytics
- A cell an import declares null through
nullValuesstays blank whatever casetransformits entry declares (f123f75, #25646). - An aggregate query that would answer a wrong table is refused
400, and an empty aggregate list is answered (7a04ba2, #25935). - A dataset filter key that names an object field filters that field, even
when a dimension shares its name (
1cce9d8, #26009). - An all-NULL
sumgroup sorts and pages as the0it answers, on SQLite and PostgreSQL alike (d5f4c2a, #25953). GET /i18n/translations/:localecarries anETagand answers a matchingIf-None-Matchwith304(69fa23d, #25956).- Served metadata lists parse each unchanged document once (
1ac2bb5, #25941).
Organizations, security and sharing
- The seed-ownership claims re-own row by row when a stored expression reads
owner_id(43edf90, #25724). - A new organization takes its default currency from its creator's language
or region (
e8de8a7, #25621), and thesingleposture's Default Organization from its first owner's (5cf1b9d, #25706). - A signed-out invitation preview read lets the landing page name the
inviting organization and the inviter (
83a26c3, #26151). - The sharing-rule pass note and the
ISharingService.grantcontract say what a share on a public object does (8654435, #25603). @objectstack/spec/uiexportsanonymousFormObjectName, which the public-form file rule and the doors share (6e47e16, #25979).
Platform objects and labels
- The team-side Add Member action is booked under the
organizationfeature gate (fc4ac58, #25670), and, opened from a team, binds that team (fc4ac58, #25670). - The zh-CN label for an organization's logo reads 「徽标」 (
6444288, #26069). - A business unit membership is titled by the person's and the unit's names
(
1f40201, #26300). - Every built-in permission set says who holds it, in English, Chinese,
Japanese and Spanish (
f6c6193, #26090), and its name is shown in Chinese, Japanese and Spanish (07bdecd, #26145). - The hosted product reads "ObjectOS Cloud" everywhere a user reads it, and the
Community Console carries "Powered by ObjectStack" (
f00cbe3, #26215); the AI 501 remedy and the AI and knowledge settings hints say so too (af13616, #26342).
Audit and activity
- An activity entry for an update that moves no
trackHistoryfield names the fields that changed (ef1fc78, #25958). - An activity summary reads in the reader's language (
c496886, #26258).
Spec and lint internals
- The shipped liveness ledger cites the automation seam modules that hold the
moved engine bodies (
e2a4b6a, #25796). - Three comments in
@objectstack/specdescribe the shared-chunk bundle layout (f0b33ee, #25975). - The liveness author warnings read ledger rows at every depth of
children(13136f7, #26379). - The
onSuccess.navigateandtype: 'url'targetdescribes say an in-app path is an app-qualified console route,/apps/APP/OBJECT/record/ID(ab0bc89, #26435).
Skills
objectstack-automation: a declared webhook or auto-launched flow is refused without itsrequirespair (f3d0eab, #25689), and the inbound-hook table namesconfig.secretRef(d0eac35, #25708).objectstack-platform: the bootstrap example pins every@objectstack/*dependency to one exact version (061cc94, #25667), and the stack-config example declaresengines: { protocol: '^18' }(992a7e1, #25688).- Object-level
composite/repeaterare untyped JSON; a typed list is a child object (8f35ffc, #25741). - Every published package declares exactly one anchor-safe
isDefault: truepermission set (d65cbb6, #25930). - The
objectuiskill joins the published catalog, so@objectstack/skillsships the@object-ui/*authoring skill (a8f2afa, #26097).
Console (Studio): records, lists and forms
- A lookup's option subtitle no longer repeats the record name (
dfaad4d, #26062). - A refused submit moves focus to the first invalid field, and no longer
toasts the field list over the dialog's title (
326a559, #26158). - The record page's inline-edit pencil shows on keyboard focus (
411fc00, #26325). - A grid's
datecolumn reads in one absolute face when its field declares noformat(9c3097e, #26341). - The record page's read mode wraps a text value instead of cutting it
(
d98d3e2, #25998). - An empty list tells "no records you can see" and "nothing of yours yet"
apart from "no records" (
cc378e9, #25987). - A grouped grid orders a level's groups by its
grouping.fields[].orderBy(62ba5ef, #25977). - A
{ group }form section no longer warns aboutcollapsiblethe author never wrote (3993793, #26042). - A
userfield's person object is alwayssys_user(9598405, #26050). - The record create and update toasts name the saved record (
b3ed6c8, #26202). - On a narrow window, a toast beside the record drawer no longer covers its
Edit and ⋯ buttons (
26e7c75, #26426). - A record locked by an approval is shown locked to a reader outside it
(
9a0108c, #26402). - Empty related lists fold into one line after the lists with records, and
record:pathterminal stages share the rail's width (775a000, #26414). - A bulk action's
confirmTextfills its{{ count }}hole with the number of records the run covers (6676991, #26030), each param hole with the param's display value (ef5d0a4, #26217), and formats numbers and dates in the viewer's locale (6390fe5, #26358). - A
compareToKPI tile shows its number under All time (4391c50, #26027). - A map whose style or tiles fail to load shows the record list with a
translated notice (
326a559, #26158), and a map view with no style draws the deployment's default before the public demo style (9f16f16, #26326). - A list view or page whose
labelis an inline locale map is named in the viewer's language (416e96f, #25997).
Console (Studio): Setup and administration
- Setup → Positions shows each position's description (
04148ac, #26100), shows read-only what each named permission set grants (77a52cf, #26360), and lists a position created from New right after Save (d613fdc, #26269). - The permission matrix sets and shows each object's read and write record
scope (
5cb1c1a, #26284). - The Delegated Admin Scope block lists the companion grants a delegate needs,
and grants the missing ones in one click (
e14d9ce, #26340), and the permission editor tells it whether it edits under a package (71c620a, #26372). - The audit log's From and To filters use the platform date picker
(
9753d16, #26061). - The Console draws
DEPENDENCY_MISSINGin the author's terms, one line per unmet dependency (934810c, #26123). - Browse Marketplace says the catalog could not be reached when the runtime
cannot reach it (
b239a01, #26213). - In the field type picker, Enter after a search picks the type it names
(
586a7ed, #26259). - A member takes back their own comment reaction through the unreact door
(
48a9d9d, #26384).
Console (Studio): Studio, flows and AI
- A whole-app build approved from the proposed plan draws its result card,
live and after a reload (
712770b, #26037). - Pending changes folds what the platform wrote into one collapsed line
(
7bbc0b9, #25984). - The Studio no longer warns for every navigation
visiblepredicate of the apps it lists (b981324, #26105). - The Console no longer sends two requests it knows will be refused
(
6d15aca, #26056). - The notify node's recipients editor writes and keeps a
{ emailField }recipient (3518664, #25996). - A failed flow run reads the refusal its write node met the way a record save
reads it (
f20a491, #25985). - The flow inspector's list field shows a stored string as one entry
(
a52cfaf, #26038). - One app opens under one address: a name-alias route moves onto the package
id (
61ba04f, #26262). - The code editor loads Monaco from the Console's own build, never from
cdn.jsdelivr.net (
56a2346, #25993).
Console (Studio): sign-in, navigation and language
- The sign-up form shows a password mismatch under the confirm field, and the
register page links privacy and terms (
ff91895, #26291). - The Chinese account menu's sign-out item reads 「退出登录」 (
c7aa9cd, #26045). - A collapsed sidebar navigation group shows how many entries it holds
(
679fc7c, #26103). - The last English literals on the data table, the chart view, react pages,
the References sheet and Flow Runs read the user's language (
c86c823, #25978). - The "nothing in this app is available to you" screen (
fbb7599, #26166) and the draft preview's failure pane (601c773, #26135) are drawn by the shared empty and error states.
Console (Studio): refactors, tests and build
- The Console
ObjectViewis split into sibling modules and hooks: leaf pieces (e638193, #26310), header toolbar and list URL state (e677770, #26396), module-level helpers (d00215f, #26152), identity import and record navigation (3db7bbf, #26353), realtime refresh and record count (b9cd980, #26336), view options (96635f5, #26233), tab strip and header chrome (08ed7e2, #26412), toolbar affordances (3acbeff, #26374), and page header and record overlay (a7f4b99, #26434). ObjectGrid's module-level helpers (7158025, #26323) and its host-facing props types (222755e, #26354) move into sibling modules, and its authored-input diagnostics into a sibling hook (eeaa827, #26364).- Five Interfaces rail label tests share one Studio harness (
697a307, #26255). - The Console's build-identity define no longer leaks into the other ui test
projects (
f143cd8, #26197). - The build's chunk-membership report attributes only objectui's own packages
(
823d0f6, #26225). - Every ui package whose
testscript callsvitestdeclares it as a devDependency (6ea429d, #26290).
Console (Studio) — objectui joins the repository
18.1.0 bundled objectui at a pinned commit. 18.2.0 is the first release built
the other way: objectui became the ui/ workspace of this repository, a
subtree import at its frozen tip 9e1fe03286 (fd40831, #25825, for #25752),
and @objectstack/console is built from ui/apps/console at the commit being
released (2a61f08, #25745).
- No pin to read.
dist/.objectui-sha, which named the objectui commit a Console was built from, anddist/.objectstack-injection.jsonleave the@objectstack/consoletarball. The Console's version is the framework's version. Installing@objectstack/consoleis unchanged. - One version for both scopes. The 37 public
@object-ui/*packages join the@objectstack/*fixed group and move from18.1.0, the last release the objectui repository published, to18.2.0. Pin them with the@objectstack/*packages, at the same exact version. - One SDUI parser.
@object-ui/sdui-parseris deleted and not released; the renderer and the save gate both run@objectstack/sdui-parser(80f267d, #26343). - React 19. Every
@object-ui/*package'sreact/react-dompeer is^19.0.0(9a0af4e, #26068). - In a framework checkout, run
pnpm console:buildwhere you ranpnpm objectui:build: it buildsui/apps/consoleand copies itsdist/intopackages/console. The CLI's drift warning names it (8fcdf52, #26063). - The
objectuiauthoring skill ships in@objectstack/skills(a8f2afa, #26097).
Every Console change is listed once, in its section above. 89 of the 231
changesets touch an @object-ui/* package: 10 under
需手动处理 (most under "Console and the @object-ui/*
packages"), 1 under 自动迁移 (the "(by name)" badge), 14
under 新增能力, 1 under
语义变化, and 63 under 其他修复, where the
"Console (Studio)" groups hold them. What a Console user notices first:
- Approvals. An administrator who is not the approver sees one status line
and one override menu (
054652b), and a record locked by an approval reads as locked to everyone who can read it (6a2866a,9a0108c). - Records and boards. A kanban board refuses a drop its
state_machinecloses (c14e910), an edit form offers only the moves the server accepts (4f48d2b), the activity timeline folds repeated updates (0b76a1f), and New, Edit and Delete are offered only where the server allows them (b727956). - Invitations. A signed-out invitee is greeted for the invitation and
offered sign-up first (
326a559). - The document policy. The Console is served with a content-security-policy
(
3c30afd), loads Monaco from its own build (56a2346), and allows the presigned upload store (69aa630) and the deployment's map style (21075ce,9f16f16).
Upgrade checklist
⚠️ For an 18.1.0 app. From 18.0.0, walk the 18.1.0 checklist first, and from 17.x the 18.0.0 checklist before it.
18.2.0
How far this list has been walked. Not at all. It is compiled from the changesets, and no app has been moved from 18.1.0 to 18.2.0 for this page. Each step names the entry it comes from; read that entry above for the exact refusal.
1. Move the pins
- Move every
@objectstack/*dependency, and every@object-ui/*one, to18.2.0together, with@objectstack/skillsandcreate-objectstackwhere you use them. Pin the exact version: a caret range takes every later 18.x by itself, and a patch can break a non-protocol surface. - Drop the override the 18.1.0 checklist added for the eight packages
@objectstack/cliranged. From 18.2.0 the CLI,@objectstack/honoand@objectstack/plugin-devpublish their@objectstack/*dependencies exact (f4860da, #25662), so an exact pin holds the tree. If you keep the override, move it with the pins. - Replace
@object-ui/sdui-parserwith@objectstack/sdui-parser, and move a React host to React 19 (80f267d,9a0af4e). - On an environment that runs HotCRM, move HotCRM to
v6.0.0or later first (733b3c8).
2. Before the first boot
- A deployment that serves
kind: 'react'pages setsOS_PAGE_REACT_ENABLED=true(5e7cf63). Without it, each react page shows a notice instead of running. - List every host a map view or its tiles load from in
OS_CONSOLE_CSP_CONNECT_SRC, space-separated, or the Console's policy refuses it (3c30afd). Name the deployment's own map style inOS_CONSOLE_MAP_STYLE_URL(21075ce). A malformed value of either stops the boot, naming it. - In a framework checkout, build the Console with
pnpm console:build(2a61f08).
3. Run the build, and fix what it refuses
os validate
os build
os migrate meta --from 17 # the protocol-18 step, with this release's seven entriesFix each refusal with its line in 需手动处理 or 自动迁移. The ones an app is most likely to meet:
- an action
confirmTextorsuccessMessagethat writes${record.name}or${result.email}: write{{ record.name }}and{{ result.email }}(0c81694,d727348); - a form open to anonymous intake that declares a file field (
6ad226a); excludeSubmitter: truebesideonEmptyApprovers: 'auto_approve'(4bcc4df);- an
escalateTowritten asteam:,department:,org_membership_level:or the prefix ADR-0090 D3 retired (9993165); allowDelete: falsebesidemodifyAllRecords: true(f6ba134);- a locale that is not a BCP-47 tag, such as
zh_CN(39a78b1); visibleOn,hiddenOnordisabledOnon a page node (e843b5b);- a
runAs: 'system'hook orscriptaction whose body writes an identity-assignment object (07586f5); optionalon a marketplace dependency entry, ordependencieson an app install manifest (436d284).
A TypeScript project also meets the retired exports at compile time: the
package upgrade model of @objectstack/spec (557973d), PositionGrantVia's
'name' (9494dd8), renderTemplate of @objectstack/plugin-email
(92a0073), tenantId on resolveLocalizationContext (65145d3),
notNullRefusalSite and relabelNotNullRefusal (48e84a9), the 54
@object-ui/app-shell exports (aec5f7b), useAdapter()'s type (ef025fe),
and FilterBuilderRow.value (0489214, 57ab06b).
4. After the boot
- Run
os migrate meta --storedto list and rewrite the stored rows the conversions touch: permission sets that storeallowDelete: falsebesidemodifyAllRecords: true, andtranslationrows underzh_CN-style locales. - Name each permission set a position should grant in its
permissionSets. Theposition_name_fold_grantwarning, now logged withgranted: false, names each position whose same-named set is no longer granted (733b3c8). - Move identity writes out of elevated automation. A
runAs: 'system'hook, an action body, a hook that inherits a system context or callsctx.api.sudo()is refused writes to positions, permission-set grants, invitations and memberships (073f08b,6a6ebff). - Check each
notifynode that mails a computed address, or names an address no user holds (d1e329e,b0384f3): use{ emailField }, add theemailchannel, or name a user. - On a walled deployment, check who downloads unclaimed files from outside
their organization (
3b8ea15), and that a public form or an anonymous endpoint no longer carries files (e2b40a2,b4199c9). - Publish a hierarchy-scope permission set only where the
hierarchy-securityresolver is mounted (b029c90). - Install a package's declared dependencies before it (
3446d43), and declare the app inmanifest.dependenciesof a module that shares its namespace (be78977). - Update API clients for the changed answers:
404 RESOURCE_NOT_FOUNDfrom eight doors (0dc4b5d);405onGET /api/v1/mcp(bb85f5f);503 SERVICE_UNAVAILABLEfrom analytics (2e6d446,f1d6be0);400 VALIDATION_FAILEDfor a NOT NULL refusal (48e84a9,1af2cea) and for a non-object body orparams(e12d3f3,3821ec8);403 DELEGATION_SCOPE_VIOLATION(495fa07);INVALID_REQUESTfor an admin password out of range (1d2a246); and the import refusalsUNSUPPORTED_TRANSFORM,MISSING_REQUIRED_FIELDandDUPLICATE_MATCH_KEY(50af6fa,617f27e). - Code that sends
auth.invitationitself passesexpiresAt(d284ff3), and a host that callsrunAdminImportUserspassesgetAuthContext(e3e936e).
v18
The v18 line and its GA release, 18.0.0, which closes the `18.0.0-next.N` prerelease train and publishes to npm's `latest` tag. It carries ADR-0131 (organization ownership is total, with no NULL `organization_id`) and landed its breaking changes in stages, each with its own migration.
18.1.0
Release notes and upgrade checklist for 18.1.0, the first minor of the v18 line: a minor that carries breaking changes. ADR-0131 finishes (an organization-less row confers nothing), a production os serve with no organization object is refused, nine metadata narrowings with automatic conversions, one federation rule at every datasource door, and an unreadable SQLite file is refused instead of replaced.