Skip to content

Commit 9f92e4f

Browse files
committed
chore(changeset): retire the i?.content ?? i unwrap family (#8378)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARidKDYSCD56LaygrvDPnk
1 parent 19db289 commit 9f92e4f

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
"@objectstack/plugin-email": patch
3+
"@objectstack/plugin-security": patch
4+
"@objectstack/plugin-sharing": patch
5+
"@objectstack/plugin-webhooks": patch
6+
---
7+
8+
fix(plugins): a declared item reaches its schema intact — retire the `i?.content ?? i` unwrap from plugin read paths (#8378)
9+
10+
Ten production reads over `SchemaRegistry.listItems` unwrapped every declared
11+
item as `i?.content ?? i`, presuming a `{ name, content }` storage envelope.
12+
That envelope has **no producer**. Re-measured at these seams rather than
13+
inherited from #7519's measurement of `MetadataFacade`:
14+
15+
- `registerMetadataCollections` (objectql) registers each stack-collection
16+
element as-is — `registerItem(type, item, 'name')`, no boxing;
17+
- `loadMetaFromDb` registers `convertStoredItem(JSON.parse(record.metadata))`
18+
the parsed body, never the `sys_metadata` row (whose body column is
19+
`metadata`, not `content`);
20+
- the facade's own interim boxing of non-object values, the one writer that ever
21+
produced the shape, was removed by #8349.
22+
23+
**Removal is a fix, not a cleanup.** None of the types read through these seams
24+
`permission`, `position`, `capability`, `object`, `sharingRule`, `webhook`,
25+
`emailTemplate` — declares a stored `content` key; every one of them rejects it
26+
as an unrecognized key. So wherever the key did appear the unwrap replaced a
27+
whole authoring document with one of its values, and `''` — falsy but
28+
non-nullish — passed `??` and then died at the reader's own `filter(Boolean)`,
29+
dropping the item with no warning, no count and no row.
30+
31+
**On email templates the harm was sharpest, and it is the one users will
32+
notice.** `content` really is a spelling an author can write there:
33+
`EmailTemplateDefinitionSchema` lists it in its `strictObject` **aliases** table
34+
(`content: 'bodyHtml'`). That table is a *rejection* facility, not a conversion —
35+
it feeds `strictUnknownKeyError`, which runs only on the `unrecognized_keys`
36+
path and only builds a message; nothing rewrites the key, and the ADR-0087
37+
conversion layer has no `email_template` entry either. The schema was therefore
38+
always ready with the author's fix, and the unwrap was the one thing standing
39+
between the author and it: the HTML string reached
40+
`EmailTemplateDefinitionSchema.parse()`, which answered `Invalid input: expected
41+
object, received string`, and the boot warning's `name` field came back
42+
`undefined` — so an operator could not even tell **which** template had failed.
43+
44+
A template authored with `content` now yields what it was always meant to:
45+
46+
> Unrecognized key(s) on this email template: `content`. Did you mean
47+
> `content``bodyHtml`?
48+
49+
…named against the template it came from, and counted as `skipped` rather than
50+
vanishing.
51+
52+
No behaviour changes for spec-valid metadata: the reads hand back exactly the
53+
documents they always did.

0 commit comments

Comments
 (0)