Skip to content

Commit 64d0d4f

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-lewq7j
2 parents b9a89e3 + a3009cb commit 64d0d4f

279 files changed

Lines changed: 9764 additions & 5226 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/core': patch
3+
---
4+
5+
fix(core): an import row with several bad cells reports every one of them in `errors` (#25582)
6+
7+
Clause-②: yes (widening: a failed import row whose cells did not coerce gains the optional `errors` list, `ImportRowResultSchema.errors`; every existing key keeps its value)
8+
Metadata-protocol: none
9+
Ruling-ref: #25582 ruling `6377844879` letter A, proposal 4; the spec seat's fill rule `6434667735`
10+
11+
A row with several bad cells used to report only the first one, so an operator fixed one cell, imported again, and only then saw the next. The row now carries `errors`, one `{ field, code, message }` element per failed cell, in column order. The first-error keys `field`, `code` and `error` are unchanged and name element 0, so a reader of those keys sees the same answer as before.
12+
13+
- It reaches every path that reports rows: the dry run and the commit, on the synchronous `POST /api/v1/data/:object/import` and on the async import job's results.
14+
- It is filled only from the import's cell-coercion errors (`invalid_date`, `invalid_number`, `invalid_option` and the rest). A row that failed for another reason omits it: the dry run's validate verdict, a refused write, a duplicate or ambiguous match key.
15+
- `ImportRowResult` (`@objectstack/core`) gains the optional `errors?: ValidateDataIssue[]`.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
feat(cli): `os validate`, `os build` and `os lint` report `manifest.dependencies` ranges at build time (ADR-0141 D2, author side)
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The pre-install dependency check refuses a package whose `dependencies` range it cannot read, and judges a dependency the same artifact delivers for presence only. Until now the author first heard of either from someone else's environment: a `422 DEPENDENCY_MISSING` on install, or, for an in-artifact mismatch, never. The three authoring commands now judge every `dependencies` entry of the packages one install would deliver (each `packages[]` body of an ADR-0130 artifact, or the top-level manifest of a single package) with the install's own predicate, `checkDeclaredDependencies` from `@objectstack/metadata-core`. Nothing re-parses the range grammar.
11+
12+
- **Error**: a range outside the stated grammar on an entry the artifact does not deliver, and a `dependencies` that is not a `{ PACKAGE_ID: VERSION_RANGE }` record. The install refuses these whatever the target environment holds, so `os build` refusing them refuses nothing the platform would install.
13+
- **Warning**: what the install admits. That is an entry naming a sibling package of the same artifact whose declared `manifest.version` the range does not admit (core bumped to `2.0.0` while a module still declares `^1.0.0`), a co-delivered entry whose range cannot be read, or a sibling whose version is not `MAJOR.MINOR.PATCH`.
14+
15+
Whether an out-of-artifact dependency is installed, and at what version, is still judged only at install. No build can see the target environment.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
'@object-ui/types': patch
3+
'@object-ui/components': patch
4+
---
5+
6+
fix(types,components)!: a renderer's props index signature is `unknown`, not `any`, so a forwarded key must be narrowed before it is used
7+
8+
Clause-②: yes (narrowing)
9+
Metadata-protocol: none
10+
11+
<!-- adr-0087: not-required (type-surface-only ui/packages/types/src/base.ts#ComponentRendererProps) A TypeScript annotation narrowing on a published renderer-props type: no metadata key, accepted value, export or error code is removed or renamed, nothing at runtime changes, and `objectstack migrate meta` has nothing to rewrite. The affected party is a TypeScript consumer, reached by its own compiler. -->
12+
13+
**BREAKING** type-surface narrowing, compile-time only. Nothing a renderer receives or renders at runtime changes.
14+
15+
- **`@object-ui/types`.** `ComponentRendererProps` keeps its index signature, so every key the host forwards is still admitted, but the signature now maps to `unknown` instead of `any`.
16+
- **`@object-ui/components`.** The built-in renderers' own inline props annotations move the same way. The three host keys renderers read by name and pass to their root element (`data-obj-id`, `data-obj-type` and `style`, written or forwarded by `SchemaRenderer`) are declared once in a package-local type instead. The host-supplied callbacks and values a renderer reads by name (`onPageChange` on `pagination`, `onChange` / `value` on `input-otp`, `loading` on `button`, `className` on `text`, react-hook-form's `ref` on the form's built-in controls) are declared on that renderer's props.
17+
18+
**Migration.** A renderer typed with `ComponentRendererProps` that reads a forwarded key:
19+
20+
```ts
21+
// FROM — compiled, because the key was `any`
22+
const Pager = ({ schema, ...props }: ComponentRendererProps<PagerSchema>) =>
23+
<Nav onSelect={(n) => props.onPageChange(n)} />;
24+
25+
// TO — declare the key you read on your own props, or narrow it before use
26+
type PagerProps = ComponentRendererProps<PagerSchema> & { onPageChange?: (page: number) => void };
27+
const Pager = ({ schema, onPageChange }: PagerProps) =>
28+
<Nav onSelect={(n) => onPageChange?.(n)} />;
29+
```
30+
31+
What to do: nothing if your renderers never read a forwarded key off `ComponentRendererProps` without declaring it. Otherwise declare the key on your renderer's props (as above) or narrow the `unknown` value (`typeof x === 'function'`, `typeof x === 'string'`) before using it.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
chore(ui)!: `@object-ui/app-shell` is no longer published to npm (#25922)
6+
7+
Clause-②: `yes (narrowing)`: a published package leaves the registry; ADR-0087 marker per the lane's rules
8+
Metadata-protocol: none
9+
10+
**BREAKING** for anyone who installs `@object-ui/app-shell` from npm. The package exists to serve the ObjectOS Console, and a customisable console for a third-party host has no business demand today, so the package is now `private: true` and leaves the Changesets `fixed` group. `18.2.0` is the last published `@object-ui/app-shell`: the 18.2 Version PR versioned it before this change and the 18.2 publish ships it; no later version reaches npm, and the maintainer deprecates the package on npm after the 18.2 publish. Nothing else moves: the Console (`ui/apps/console`) and the `@object-ui/*` packages that import it are workspace consumers and keep importing it exactly as before, and its exports, views and Studio pages are unchanged.
11+
12+
The host-console posture leaves the repository with it. The two examples that imported the package as a host would, `ui/examples/byo-backend-console` and `ui/examples/console-starter`, are deleted, and so is `ui/docs/app-shell-extraction-guide.md`, the guide to extracting the package into a host. The READMEs, the examples index and the contributor docs that pointed at them no longer do.
13+
14+
Migration: there is no replacement package. `@object-ui/app-shell` FROM npm → TO none. A host that installs it stays on `@object-ui/app-shell@18.2.0`, the last published version, or runs the ObjectOS Console instead of embedding the shell.
15+
16+
<!-- adr-0087: not-required (unpublished) No metadata moves: no spec key, authorable spelling, object definition, stored row or stored shape is added, removed, renamed or re-shaped, so there is nothing for `objectstack migrate meta` to rewrite. What narrows is the npm registry: `@object-ui/app-shell`, the one package this changeset bumps, is `private: true` from this change on and publishes nothing, and its last published version, `18.2.0`, stays on npm until the maintainer deprecates it after the 18.2 publish. -->
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
refactor(app-shell): the Console `ObjectView`'s view management handlers move into a sibling hook
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The view-config panel's save and create handlers, the draft field update, view switching, the mobile view switcher registration and the view-tab CRUD callbacks (rename, delete, pin, set default, reorder, configure, add) move verbatim out of `ObjectViewInner` in `views/ObjectView.tsx` into `useObjectViewViewCrud` in `objectViewViewCrud.tsx`. The panel and dialog state stays in the component, which passes every input in and reads the returned handlers. No logic, name or rendered output changes, and the package entry is unchanged.
11+
12+
What to do: nothing.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/plugin-grid': patch
3+
---
4+
5+
refactor(plugin-grid): `ObjectGrid`'s row load moves into a sibling hook
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The row load of the `ObjectGrid` component moves verbatim out of `ObjectGrid.tsx` into `useObjectGridRowLoad` (`objectGridRowLoad.ts`): the data-invalidation nonce, the one async load effect, the host `findParams` reset of "select all matching" and the page-1 reset on a query change. `toOrderByClause`, whose only caller is the load effect, moves with it. `ObjectGrid` calls the hook where the block stood, so its hook order, its queries and its rendered output do not change. No name is renamed, and the package entry is unchanged.
11+
12+
What to do: nothing.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/plugin-detail': patch
3+
---
4+
5+
fix(plugin-detail): a related list's `date` column reads in one absolute face when its field declares no `format`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
A record page's related list drew its `date` column in mixed faces, for example "Yesterday · 3 days ago · Sep 20, 2025", the way list grids did before their own fix. The related list builds its own table cells and did not tell the date cell that it sits in a column.
11+
12+
- **Default change for an undeclared `format` (visible from metadata).** In a related list's table, a `date` field that declares no `format` now renders the locale's short absolute date (`Oct 25`, with the year when the date is not in the current year), one face for every row, as a list grid already does.
13+
- **The relative phrase moves to the tooltip.** It is shown on hover ("Yesterday", "In 2 days", or "Overdue 3d" on a declared `dueLike` field). A past declared deadline is still red.
14+
- **A declared `format` still wins.** A field that declares `format: 'relative'` keeps the relative face.
15+
- **Other surfaces are unchanged.** The phone-width gallery of a related list, the record detail body and the header highlights strip render `date` values as before. `datetime` cells are not affected.
16+
17+
What to do: nothing. To keep the relative wording in a related list's column, declare `format: 'relative'` on the field.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(app-shell): the full-page record form's save toast names the saved record
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Saving a record on the full-page form route (`/new` and `/record/ID/edit`, used by objects whose form opens as a page) showed "Task updated successfully". The record-form dialog paths already named the record. The page now does the same: `Task "Quarterly review" created` and `Task "Quarterly review" updated`. It uses the same display-name resolver, the same rule for a record with no name, and the same `form.createdNamed` / `form.updatedNamed` strings as the dialog. A record with nothing nameable (the resolver would only answer `Record #ID`) keeps the object-label toast it showed before. No strings are added or changed.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/service-settings': patch
3+
---
4+
5+
fix(service-settings): the settings audit trail records the previous value's digest in `old_hash`, and a non-secret value's digest is the declared SHA-256
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`sys_setting_audit` and `sys_platform_setting_audit` declare `old_hash` as the SHA-256 of the previous value (null when it was unset) and `new_hash` as the SHA-256 of the new value (null on a reset). The write path passed `old_hash: null` on every write and recorded the adapter's FNV-1a 32 (`fnv32:…`) as the new hash, so an operator could not tell from the trail whether a write changed anything.
11+
12+
- **`old_hash`** now holds the digest of the value the row held before the write, read off the row the upsert already looks up: no extra read, and none at all for a first write. It is null for a first write, after a reset, and for a row that held a secret.
13+
- **A non-secret value's digest** is now `sha256:` followed by the hex SHA-256 of its canonical JSON, on both `new_hash` and the `config_change` row's digest in `sys_audit_log`. It no longer goes through `CryptoAdapter.digest`, so an injected adapter cannot change the format. The prefix keeps it distinct from the `fnv32:` rows already stored, which are left as they are: compare hashes only between rows that carry the same prefix.
14+
- **Secret values are unchanged.** They keep the crypto provider's keyed digest (`hmac-sha256:…`) as `new_hash`, or none, and `old_hash` stays null for them.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/plugin-chatbot': patch
4+
'@object-ui/i18n': patch
5+
---
6+
7+
fix(app-shell,plugin-chatbot,i18n): the AI build page's preview header names the app by its label and says what the build card says about publishing; the progress panel shows labels
8+
9+
Clause-②: no
10+
Metadata-protocol: none
11+
12+
- **Preview header.** The Live Canvas header named the app by its machine name and said "unlisted until published" (「未发布 · 仅自己可见」) for any materialized build, even one the build card beside it called live, and never changed. It now reads the build card's own answer: the label the card names the app by (`checklist.app.label`, else the build's label) and whether the card says the app is live. A live build reads "Live app — LABEL" (「运行预览 · LABEL」), and the header follows the card when the build is published. A materialized build the card does not call live keeps the unlisted note.
13+
- **`ChatbotEnhanced`.** New optional prop `onBuildResult({ appName, label, live })`, fired by a build card when it has an app and again when its label or live state changes. Additive; hosts that do not pass it see no change.
14+
- **Listed materialized builds are live.** A build envelope that says `materialized: true` and `appHidden: false` (the app is already listed, ADR-0045 publish = live and visible) now reads "Built and live" on the card. The draft review carries `appHidden` when the envelope says it.
15+
- **Progress items.** `ChatBuildProgress.items` entries gain an optional `label`; the panel shows it in place of the machine name, and falls back to the name when a frame carries none.
16+
- **Footnote.** The finished card's posture line names Publish in the chat instead of Studio, in every shipped locale.
17+
- **i18n.** New key `console.ai.liveCanvasLive` in every locale; `chatbot.build.draftPosture` reworded.

0 commit comments

Comments
 (0)