Skip to content

Commit 42b6af0

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-04ka71
2 parents 8346407 + 5b5cff1 commit 42b6af0

368 files changed

Lines changed: 24505 additions & 9151 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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/fields': patch
3+
'@object-ui/app-shell': patch
4+
'@object-ui/plugin-detail': patch
5+
'@object-ui/plugin-list': patch
6+
'@object-ui/i18n': patch
7+
---
8+
9+
feat(console): ownership queues in the Console — a queue picker reading both sources, a Claim button the server decides, and an "In a queue" list filter
10+
11+
Clause-②: no
12+
Metadata-protocol: none
13+
14+
The server half of ownership queues shipped without a Console face. Now:
15+
16+
- **Queue pickers list both sources.** The flow designer's approver Value for a `queue` approver, and a sharing rule's `queue` recipient, list the queues an installed app declares (`GET /api/v1/meta/queue`) together with the organization's own `sys_queue` records, one list by machine name, and store the name. The approver picker follows the binding the server publishes (`registry-and-data`); with no data adapter, or a server that publishes another binding, it keeps the text box.
17+
- **Claim.** A record sitting in a queue (no owner, a `queue` named) shows **Claim** in its header only when the explain engine's answer for a transfer of that record carries an admitting `queue_claim` rule; no answer means no button. Claim sends `{ owner_id: <self> }` through the normal update, and a lost race (`409 CONCURRENT_UPDATE`) is reported as "Someone else claimed this record first."
18+
- **In a queue.** A list of an object served with the injected `queue` column gains an **In a queue** toggle that narrows the fetch (and an export) to `owner_id` empty and `queue` set. Which of those rows come back is still the server's read filter.
19+
- **Docs.** A new authoring guide, *Queues and assignment rules*, covers declaring a queue and an assignment rule, the `load` requirement, what a parked record is and who sees it, how a claim is spelled, and that a queue is not a messaging audience; the approvals, sharing-rule and RLS pages link to it.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
"@object-ui/types": minor
3+
"@object-ui/i18n": minor
4+
"@object-ui/cli": minor
5+
---
6+
7+
refactor(ui)!: retire `@object-ui/plugin-ai` and its three node types
8+
9+
Clause-②: no (narrowing)
10+
Metadata-protocol: narrowed
11+
12+
<!-- adr-0087: not-required (runtime-export-retired @object-ui/plugin-ai#*) the retired operands are React components of a published ui package that nothing in the workspace loaded; no packages/spec schema, no ADR-0087 conversion surface and no stored shape names them, so there is nothing for `objectstack migrate meta` to rewrite, and the three node literals are refused by name on the zod face -->
13+
14+
**BREAKING.** `@object-ui/plugin-ai` is retired: `18.2.0` is its last published version, and it gets no further release. The console registered it neither eagerly nor lazily and no workspace package imported it, so the `ai-form-assist`, `ai-recommendations` and `nl-query` node types it registered rendered nowhere in the product.
15+
16+
What leaves, and what to do:
17+
18+
- FROM `@object-ui/plugin-ai` TO nothing: drop the `@object-ui/plugin-ai` import and dependency. A host that still wants the component keeps its own copy and registers it under its own type key.
19+
- Page nodes of type `ai-form-assist`, `ai-recommendations` or `nl-query`: remove them from the page. `safeValidateSchema` and `objectui validate` now refuse each of the three literals by name at `type`, with that remedy; before, the page rendered the "Unknown component type" panel in their place whenever the package was not loaded.
20+
- `@object-ui/types`: `AIFormAssistSchema`, `AIRecommendationsSchema`, `NLQuerySchema`, `AIConfig`, `AIFieldSuggestion`, `AIRecommendationItem`, `NLQueryResult`, `AIProvider` and `AIModelType` are `@deprecated` and now `never`, and `AnySchema` has no member for the three literals. The zod names (`AIFormAssistSchema` and the rest under `@object-ui/types/zod`, `AIComponentSchema` included) are `@deprecated` `z.never()` schemas that accept nothing. Remove every reference. The names stay importable until the tombstone sunset rule decides when they leave the published face.
21+
- `@object-ui/i18n`: the `ai.*` message block (`ai.nlQuery.*`, `ai.formAssist.*`, `ai.recommendations.*`) is gone from all ten packs. A host that registered overrides for those keys can delete them.
22+
- `@object-ui/cli`: `objectui check` no longer lists the three literals as known component types.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/i18n': patch
3+
---
4+
5+
docs(i18n): the `studio` namespace is the designer strings' only home
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Last slice of the move ruled on objectstack#25922** (6431032267, Q2 = A; kept by 6431234244). `@object-ui/app-shell`'s private designer table, empty since the previous slice, is deleted, and its `t()` / `tOptional()` read `@object-ui/i18n/namespaces/studio` alone. Every string reads the same as before in every language. The README and the namespace's doc comments now say so, and point at `src/__tests__/studio-namespace.test.ts` as the namespace's one parity check, since the paired-table gate `check:i18n-designer-parity` is retired with the table. No export or string changes.

‎.changeset/26080-readme-contributing-links.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
'@object-ui/layout': patch
1212
'@object-ui/mobile': patch
1313
'@object-ui/permissions': patch
14-
'@object-ui/plugin-ai': patch
1514
'@object-ui/plugin-calendar': patch
1615
'@object-ui/plugin-charts': patch
1716
'@object-ui/plugin-chatbot': patch
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
'@objectstack/spec': minor
3+
---
4+
5+
fix(spec)!: an action's `newTabUrl` is a path on this backend and must start with `/`; an absolute URL is refused at parse
6+
7+
`newTabUrl` is the zero-roundtrip target of the pre-opened-tab flow (`opensInNewTab: true`): on click the console drives the pre-opened tab to the backend origin + `newTabUrl`, with `{recordId}` substituted, and posts nothing. Its JSDoc called it a path template, while its `.describe()` and the action form's help text called it a URL template, and nothing refused an absolute value. So `newTabUrl: 'https://example.com/export/{recordId}'` parsed clean and opened a tab at `https://BACKEND/https://example.com/export/…`. `ActionSchema.newTabUrl` now refuses any value that does not start with `/`, and the JSDoc, `.describe()` and the form help (all four form-translation locales) say the same thing: a path on this backend.
8+
9+
Clause-②: no (narrowing) — `ActionSchema.newTabUrl` (every action door: `defineAction`, the `action` metadata type, an object's `actions[]`) refuses a value that does not start with `/`. Nothing is widened.
10+
11+
Metadata-protocol: narrowed (an action's `newTabUrl` may no longer be an absolute URL or a relative path without a leading `/`)
12+
13+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed or renamed: newTabUrl keeps its name, shape and meaning, and now refuses the values that never opened the page they named. No backend path can be derived from an external URL, so there is no mechanical rewrite; a stored action row holding one loads unchanged, is counted invalid with a [metadata_spec_invalid] boot line and still registered, is served with _diagnostics locating newTabUrl, and its next save is refused until the author rewrites it. -->
14+
15+
**BREAKING** accept-set narrowing on `ActionSchema.newTabUrl` (`@objectstack/spec`).
16+
17+
- **Before.** `newTabUrl: 'https://example.com/export/{recordId}'` (or `sso-open/{recordId}`) parsed, and the console opened the backend origin + that text: a broken tab.
18+
- **Now.** The parse refuses it at `newTabUrl` with: `` `newTabUrl` is a path on this backend and must start with `/` `` and names the external-page remedy.
19+
- **Unchanged.** A path template such as `/sso-open/{recordId}` or `/api/v1/invoice/{recordId}/pdf` parses byte-identically. No renderer changes: the console already prefixes the backend origin, so the declared meaning and the behaviour now agree.
20+
- **A row stored before this release.** Nothing converts it. It loads unchanged and is still registered, counted `invalid` with a `[metadata_spec_invalid]` boot line; the metadata read serves it with `_diagnostics` locating `newTabUrl`; it keeps opening the same broken tab; and its next save is refused until the value is a path.
21+
- **Who sees it.** An author who wrote an absolute URL in `newTabUrl`. No example, template, fixture or platform object in this repository does.
22+
23+
**The remedy.** For an endpoint on this backend, write its path: `newTabUrl: '/sso-open/{recordId}'`. For an external page, drop `opensInNewTab` and `newTabUrl` and declare a `type: 'url'` action instead: `target: 'https://example.com/export/${ctx.recordId}'`, `openIn: 'new-tab'`.
24+
25+
Also in `@objectstack/spec`, prose only, no accept-set change:
26+
27+
- The `DashboardWidget` docblock and `requiresObject`'s `.describe()` say that, outside design mode, a dataset-bound widget whose query the server refuses as a read refusal (403 `PERMISSION_DENIED`) is left out of the dashboard for that viewer, and that `requiresObject` stays an install gate, never a viewer gate.
28+
- Three shipped citations of `content/docs/concepts/north-star.mdx` "§8" / "§6.3" (sections that page never had; the page is now `concepts/architecture-overview`) are corrected: `expression.zod.ts` cites ADR-0032 ("one CEL language"), `environment-artifact.zod.ts` cites the architecture overview's "Environment Artifact" section, and `hook-body.zod.ts` drops a pointer to a heading that does not exist. The generated references follow.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
---
4+
5+
fix(platform-objects): the action form's `newTabUrl` help text says it is a path on this backend starting with `/`, in all four locales (en, zh-CN, ja-JP, es-ES), and names the `type: 'url'` action for an external page — matching the spec, which now refuses an absolute `newTabUrl`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/formula': minor
3+
---
4+
5+
feat(formula)!: the mail hole grammar refuses a hole whose formatter the whitelist does not name, by name, listing the known formatters
6+
7+
Clause-②: no (narrowing) — `judgeHoleFormatter` gains a third rule, `known-formatter`: a hole that names a formatter `TEMPLATE_FORMATTERS` does not hold (`{{ amount | curency:EUR }}`, `{{ due | dat:long }}`) is refused, so `parseMailHole` carries the refusal and `judgeMailHoleGrammar` reports the hole, where both accepted it before. The in-app dialect, which already refused an unknown formatter in its own parse, now also refuses an inherited object key it used to call as a formatter (`{{ x | toString }}`, which printed `[object Object]`). No accept set is widened and no export is added or removed; `TemplateHoleGrammarRule` gains the member `'known-formatter'`.
8+
Metadata-protocol: narrowed
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped and no export is removed: a hole whose formatter never formatted anything is now refused where the template is judged. A conversion cannot know which formatter the author meant, and the refusal names the hole and lists the known formatters, so there is nothing for a migration to rewrite. -->
11+
12+
**BREAKING** accept-set narrowing in the shared hole grammar.
13+
14+
- **Before.** `parseMailHole(' amount | curency:EUR ')` answered a hole with no refusal, and the mail renderer printed the raw value for it (`1234.5`, an ISO timestamp), because `formatValue` knows no such formatter.
15+
- **Now.** The hole carries a `known-formatter` refusal whose sentence names the hole and lists `TEMPLATE_FORMATTERS`. Text after the `|` that is not a single word (`{{ x | two words }}`) still names no formatter and is left as written. A chained hole is still refused by the one-formatter rule first.
16+
- **In-app.** `templateEngine.compile` keeps its own sentence for an unknown formatter. It now also refuses `toString`, `constructor` and the other inherited object keys, which it used to accept and run as formatters.
17+
- **Who sees it.** A template whose hole misspells a formatter or names one that does not exist. No template shipped in this repository does.
18+
19+
**The remedy.** Correct the formatter's name to one the refusal lists, or format the value in the caller that supplies the data and pass the finished text as its own variable.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/lint': minor
3+
---
4+
5+
feat(lint)!: `email-template-hole-grammar` refuses an email template hole whose formatter the whitelist does not name, naming the hole and listing the known formatters
6+
7+
Clause-②: no (narrowing) — `os validate`, `os build`, `os lint` and the metadata publish door (`422 INVALID_METADATA`) refuse an `email_template` whose `subject`, `bodyText` or `bodyHtml` writes a hole naming a formatter `TEMPLATE_FORMATTERS` does not hold (`{{ amount | curency:EUR }}`, `{{ due | dat:long }}`), which they accepted before. No accept set is widened, and no export or rule id is added or removed.
8+
Metadata-protocol: narrowed
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped: a hole whose formatter never formatted anything (the renderer printed the raw value) is now refused where it is authored. A conversion cannot know which formatter was meant, and the refusal names the hole and lists the known formatters, so there is no key for a migration to rewrite and no tombstone. -->
11+
12+
**BREAKING** accept-set narrowing at every authoring door for `email_template`.
13+
14+
- **Before.** `{{ amount | curency:EUR }}` passed every gate, and the email went out with `1234.5` where money was meant. The in-app template dialect already refused such a hole; mail did not.
15+
- **Now.** The rule refuses it at `error`, naming the hole, the face and the template, and listing the known formatters. The judgement is `@objectstack/formula`'s `judgeMailHoleGrammar`, the grammar the mail renderer parses with.
16+
- **Who sees it.** A template whose hole misspells a formatter or names one that does not exist. No template shipped in this repository does.
17+
18+
**The remedy.** Correct the formatter's name to one the finding lists, or format the value in the caller that supplies the data and pass the finished text as its own variable.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/plugin-email': minor
3+
---
4+
5+
feat(plugin-email)!: a mail template hole whose formatter the whitelist does not name fails the render with `TEMPLATE_INVALID` instead of printing the raw value
6+
7+
Clause-②: no (narrowing) — `sendTemplate` and `renderTemplate` refuse a stored template whose `subject`, `body_text` or `body_html` writes a hole naming a formatter `TEMPLATE_FORMATTERS` does not hold (`{{ amount | curency:EUR }}`), which rendered the raw value before. No accept set is widened, and the package adds no export.
8+
Metadata-protocol: narrowed
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped and no export changes: the renderer refuses a hole the authoring rule refuses, for a template that reached it without being judged. A conversion cannot know which formatter was meant, so there is nothing for a migration to rewrite. -->
11+
12+
**BREAKING** a render that printed a raw value where a formatted one was meant now fails.
13+
14+
- **Before.** `{{ amount | curency:EUR }}` with `amount = 1234.5` rendered `1234.5` in every face, and `{{ due | dat:long }}` rendered the stored timestamp as written: the renderer's fallback for a formatter it did not know was the raw value.
15+
- **Now.** The render throws `TEMPLATE_INVALID: email template NAME (locale=LOCALE): the hole … names the formatter 'curency', which is not a template formatter …`, listing the known formatters; `sendTemplate` sends nothing, and the messaging channels grade the failure permanent as they grade every `TEMPLATE_INVALID`. The authoring doors refuse the same hole first (`email-template-hole-grammar`), so this is reached only by a template stored before that rule, until its next publish.
16+
- **The raw fallback is gone.** `renderTemplate` and `renderPlainTextTemplate` throw `TEMPLATE_INVALID` for such a hole too, when handed a body directly.
17+
18+
**The remedy.** Republish the template with the formatter's name corrected to one the refusal lists.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
docs(spec): the `email_template` face descriptions and the `IEmailService` `TEMPLATE_INVALID` TSDoc name a formatter the template engine does not know among the refused holes
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **The face descriptions.** `subject`, `bodyHtml` and `bodyText` now say that a hole's formatter is one the template engine knows, and that an unknown name (a misspelled `curency`) is refused, naming the known formatters. The `currency` sentence is unchanged. The refusal itself ships in `@objectstack/formula`, `@objectstack/lint` and `@objectstack/plugin-email`; the spec only states the grammar, so no accept set of any schema moves.
11+
- **The TSDoc.** The `TEMPLATE_INVALID` error of `sendTemplate` and `renderTemplate` now names all three holes `email-template-hole-grammar` refuses: a second formatter, a formatter the whitelist does not name, and a `currency` argument that is neither a literal ISO 4217 code nor a marked `@path`.
12+
13+
No type, schema shape or export changes.

0 commit comments

Comments
 (0)