@objectstack/metadata 17.0.0-rc.4 → 17.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +528 -0
- package/dist/errors.cjs +56 -2
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +4 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +56 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.cjs +184 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -17
- package/dist/index.d.ts +37 -17
- package/dist/index.js +184 -73
- package/dist/index.js.map +1 -1
- package/dist/migrations/index.cjs +0 -44
- package/dist/migrations/index.cjs.map +1 -1
- package/dist/migrations/index.d.cts +1 -38
- package/dist/migrations/index.d.ts +1 -38
- package/dist/migrations/index.js +0 -43
- package/dist/migrations/index.js.map +1 -1
- package/dist/node.cjs +184 -73
- package/dist/node.cjs.map +1 -1
- package/dist/node.js +184 -73
- package/dist/node.js.map +1 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,533 @@
|
|
|
1
1
|
# @objectstack/metadata
|
|
2
2
|
|
|
3
|
+
## 17.0.0-rc.6
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 9960cd2: fix(metadata): remove the second, stale-keyed producer of `idx_sys_metadata_overlay_active` (#6771)
|
|
8
|
+
|
|
9
|
+
**Breaking:** `addSysMetadataOverlayIndex` and its `AddSysMetadataOverlayIndexResult`
|
|
10
|
+
type are removed from `@objectstack/metadata/migrations`. Nothing needs to replace
|
|
11
|
+
them — see below.
|
|
12
|
+
|
|
13
|
+
One index name, `idx_sys_metadata_overlay_active`, had **two** producers with
|
|
14
|
+
**different** keys:
|
|
15
|
+
|
|
16
|
+
| producer | key |
|
|
17
|
+
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
|
|
18
|
+
| `metadata-protocol`'s `ensureMetadataOverlayIndexes` (runtime, ADR-0048) | `(type, name, organization_id, COALESCE(package_id, ''))` `WHERE state = 'active'` |
|
|
19
|
+
| this package's `addSysMetadataOverlayIndex` | `(type, name, organization_id, environment_id, scope)` |
|
|
20
|
+
|
|
21
|
+
The second key is the pre-ADR-0048 one. `environment_id` has been retired since
|
|
22
|
+
ADR-0005 (2026-05 revision) — `saveMetaItem` no longer writes it and overlay reads
|
|
23
|
+
never consult it, so it is NULL on every new row, and SQL UNIQUE treats NULLs as
|
|
24
|
+
DISTINCT. `scope` is not part of the current discriminator at all. Both producers
|
|
25
|
+
used `IF NOT EXISTS`, so whichever ran first claimed the name and the other
|
|
26
|
+
silently became a no-op — decided by boot order, not by any declaration.
|
|
27
|
+
|
|
28
|
+
Measured against real SQLite before removal:
|
|
29
|
+
|
|
30
|
+
- On a normal `DatabaseLoader` boot the stored DDL is
|
|
31
|
+
`` CREATE UNIQUE INDEX `idx_sys_metadata_overlay_active` on `sys_metadata` (`type`, `name`, `organization_id`, `package_id`) `` —
|
|
32
|
+
the **declared** index from `metadata-core`'s `sys-metadata.object.ts`, materialized
|
|
33
|
+
by `SqlDriver.syncDeclaredIndexes`, already holds the name with the current key.
|
|
34
|
+
`addSysMetadataOverlayIndex` therefore changed nothing, while still returning
|
|
35
|
+
`status: 'created'`.
|
|
36
|
+
- In the one window where it was _not_ a no-op — the table present but its declared
|
|
37
|
+
indexes not yet materialized, which the engine path hits by construction because
|
|
38
|
+
ObjectQL's startup owns the sync — it installed the **retired** key. Since
|
|
39
|
+
`syncDeclaredIndexes` skips by name, nothing ever repaired it afterwards, and
|
|
40
|
+
overlay uniqueness was left unenforced on every new row.
|
|
41
|
+
|
|
42
|
+
So the function could only ever do nothing or do harm. Overlay uniqueness keeps the
|
|
43
|
+
two producers that are correctly keyed and deliberate: the runtime partial,
|
|
44
|
+
NULL-safe index from `metadata-protocol`, and — for stacks assembled without it —
|
|
45
|
+
the coarser unrestricted UNIQUE that the declaration in `metadata-core` materializes,
|
|
46
|
+
exactly as that file documents.
|
|
47
|
+
|
|
48
|
+
Both call sites in `DatabaseLoader.ensureSchema()` are gone with it, and the empty
|
|
49
|
+
`catch` that surrounded the engine-path one now reports per the ADR-0120 D4 shape
|
|
50
|
+
(name what did not happen, point at the fix, never block the boot) instead of
|
|
51
|
+
swallowing driver-resolution failures.
|
|
52
|
+
|
|
53
|
+
**Migration:** if you called `addSysMetadataOverlayIndex(driver)` directly, delete
|
|
54
|
+
the call. Assemble `metadata-protocol` for the partial, active-scoped index, or rely
|
|
55
|
+
on the declared index that `syncSchema` already builds.
|
|
56
|
+
|
|
57
|
+
<!-- adr-0087: not-required (no-migration-prescription) what is removed is a TypeScript function export, not an authored metadata surface: no metadata key, no key spelling and no stored value moves, so `objectstack migrate meta` has nothing to rewrite and the ledger has no upgrader to reach. The index itself is unchanged in the only spelling that ever reached a database from a correct producer. Measured: the export had zero call sites outside its own package across objectstack, cloud and objectui. -->
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- 55da611: fix(metadata,objectql): stop restating the object name inside driver queries — and stop casting away the query's type to do it (#6231)
|
|
62
|
+
|
|
63
|
+
`DriverQuery` (`Omit<QueryAST, 'object'>`) landed in #6076 and five drivers
|
|
64
|
+
followed in #6075, but five **call sites** stayed as they were, because they
|
|
65
|
+
were hidden behind a cast where the compiler could not see them. This removes
|
|
66
|
+
the redundant key at all five and, with it, the casts that existed only to
|
|
67
|
+
carry it.
|
|
68
|
+
|
|
69
|
+
The redundant key was never the expensive half. `git grep 'query\.object' --
|
|
70
|
+
'packages/drivers/*/src'` is zero: no driver reads it, so the key itself was
|
|
71
|
+
inert. **The cast was the cost.** `as any` on a query argument does not
|
|
72
|
+
suppress one key — it switches off checking for `where`, `orderBy` and
|
|
73
|
+
`fields` as well, which is precisely the account #5181's changeset opened
|
|
74
|
+
(cloud#1053 measured 20 such sites; cloud#1030's `$like` — an operator the
|
|
75
|
+
filter dialect does not have — survived compilation and reached the runtime
|
|
76
|
+
through exactly this hole). `packages/metadata`'s `DatabaseLoader` is the
|
|
77
|
+
main metadata read path, so it was the worst place to be running unchecked.
|
|
78
|
+
|
|
79
|
+
The five sites:
|
|
80
|
+
|
|
81
|
+
- `metadata` `DatabaseLoader._find` / `._findOne` / `._count` — each was
|
|
82
|
+
`driver.find(table, { object: table, ...query } as any)`. The helpers now
|
|
83
|
+
declare `query: DriverQuery` and hand it to the driver unchanged and uncast,
|
|
84
|
+
so all nine of their call sites' `where` / `orderBy` / `fields` are checked
|
|
85
|
+
again.
|
|
86
|
+
- `objectql` `ObjectQL.resolveSecret` — the `sys_secret` read was
|
|
87
|
+
`{ object: 'sys_secret', where: { id } } as QueryAST`, where the cast existed
|
|
88
|
+
only to satisfy the AST's then-required `object`. Both are gone.
|
|
89
|
+
- `objectql` `LifecycleService` governance counter — `count(obj.name,
|
|
90
|
+
{ object: obj.name })` carried no cast; it was admitted by a hand-written
|
|
91
|
+
driver shape whose `query` was `Record<string, unknown>`, which would equally
|
|
92
|
+
have admitted a `where` the dialect does not have. That shape is now the named
|
|
93
|
+
`CountCapableDriver` typed with `DriverQuery`, and the call passes argument
|
|
94
|
+
one only.
|
|
95
|
+
|
|
96
|
+
No behaviour changes: the key was inert on every path, and the object name has
|
|
97
|
+
always travelled as the driver methods' first argument. What changes is that
|
|
98
|
+
these call sites are type-checked again, and that re-adding the key is now a
|
|
99
|
+
compile error (`TS2353`) rather than something a cast quietly absorbs.
|
|
100
|
+
|
|
101
|
+
- 8b06bba: fix(spec): `EngineQueryOptionsSchema.search` accepts the bare query string ADR-0061 D1 calls canonical (#7178)
|
|
102
|
+
|
|
103
|
+
Two sibling schemas in `packages/spec` described the same key and disagreed.
|
|
104
|
+
`BaseQuerySchema.search` (`query.zod.ts`, hence `QueryAST`, hence `DriverQuery`)
|
|
105
|
+
has been `z.union([z.string(), FullTextSearchSchema])` since its own drift
|
|
106
|
+
repair, with a doc comment saying why: the bare string **is** the canonical
|
|
107
|
+
Tier-1 contract (ADR-0061 D1 — "the client sends only the query text; the server
|
|
108
|
+
resolves which fields to search from object metadata"), it is what every surface
|
|
109
|
+
sends, and it is what the dogfood HTTP proof pins.
|
|
110
|
+
`EngineQueryOptionsSchema.search` — the options type of `IDataEngine.find` /
|
|
111
|
+
`findOne` — declared the structured `FullTextSearchSchema` **only**.
|
|
112
|
+
|
|
113
|
+
The runtime never agreed with that narrowing. `expandSearchOnAst`
|
|
114
|
+
(`objectql/src/engine.ts`) reads `search` through `normalizeSearch`, whose first
|
|
115
|
+
line is `if (typeof raw === 'string') return { query: raw }`, and
|
|
116
|
+
`protocol-data.test.ts` asserts the protocol layer hands the engine a bare
|
|
117
|
+
string. So the type forbade what the engine serves, and callers paid the
|
|
118
|
+
standard price: `as any` on the query argument — which does not suppress
|
|
119
|
+
`search` alone, it switches off checking for `where` / `orderBy` / `fields` in
|
|
120
|
+
the same literal. Since this schema is not `.strict()`, an unknown key there is
|
|
121
|
+
**silently dropped**, so the cast this divergence forced was precisely the cast
|
|
122
|
+
`check:query-options-erasure` exists to stop.
|
|
123
|
+
|
|
124
|
+
This is the same-family drift REPAIR, not a new dialect — the identical fix
|
|
125
|
+
`BaseQuerySchema.search` already carries, for the identical reason. On the query
|
|
126
|
+
side the divergence surfaced as a validation failure the moment #3899 started
|
|
127
|
+
validating request bodies; here it surfaced as a type error, when #6231 retyped
|
|
128
|
+
`DatabaseLoader`'s read helpers to `DriverQuery` and the **engine** branch alone
|
|
129
|
+
refused to compile (TS2345 — `DriverQuery` not assignable to
|
|
130
|
+
`EngineQueryOptionsParsed`, purely because of `search`; nothing else differs).
|
|
131
|
+
|
|
132
|
+
Consumer census before landing, per the card's own guard: every site that reads
|
|
133
|
+
object-form members off an engine-options `search` already narrows with `typeof`
|
|
134
|
+
— `engine.ts` (`typeof raw === 'object' ? raw?.fields : undefined`),
|
|
135
|
+
`search-filter.ts` `normalizeSearch`, and `metadata-protocol/protocol.ts`'s
|
|
136
|
+
`searchFields` ingress gate. No consumer needed a guard added, and none changes
|
|
137
|
+
behavior: they were all written for the union already. `count` is untouched —
|
|
138
|
+
`EngineCountOptionsSchema` declares no `search` key at all.
|
|
139
|
+
|
|
140
|
+
With the schemas agreed, the casts the divergence forced are deleted:
|
|
141
|
+
`DatabaseLoader`'s three engine-branch `as any` (`_find` / `_findOne` /
|
|
142
|
+
`_count`), which restores real `where` / `orderBy` / `fields` checking on the
|
|
143
|
+
metadata main read path, and the seven `as any` in
|
|
144
|
+
`engine-findone-contract.test.ts` that were passing the canonical spelling.
|
|
145
|
+
`scripts/query-options-erasure-baseline.json` is ratcheted down accordingly.
|
|
146
|
+
|
|
147
|
+
- 7c6261a: refactor(metadata): peel the stored envelope before an `api` row is parsed as an endpoint (#5309)
|
|
148
|
+
|
|
149
|
+
Internal refactor — no authored format changes, no observable acceptance change
|
|
150
|
+
for the shapes the platform stores today.
|
|
151
|
+
|
|
152
|
+
A metadata _type name_ is worn by two different documents: the **authored
|
|
153
|
+
declaration** (exactly its spec vocabulary) and the **stored row** (that
|
|
154
|
+
declaration plus the metadata layer's own bookkeeping — `packageId`, `state`,
|
|
155
|
+
`version`, `publishedDefinition`, `publishedAt`, `publishedBy`, written by
|
|
156
|
+
`MetadataManager.register` / `publishPackage` and read back by `publishPackage`'s
|
|
157
|
+
package filter). Both `ApiEndpointSchema` parse sites — `buildEndpointIndex` (the
|
|
158
|
+
load-time backstop) and `gateApiItemsForPublish` (the publish gate) — used to hand
|
|
159
|
+
the whole stored row to the schema, and only its unknown-key _stripping_ kept the
|
|
160
|
+
bookkeeping from being judged as endpoint vocabulary.
|
|
161
|
+
|
|
162
|
+
`peelStoredEnvelope` (`packages/metadata/src/stored-envelope.ts`) now takes the
|
|
163
|
+
envelope off first, so the schema sees the authored body and nothing else:
|
|
164
|
+
|
|
165
|
+
- a row carrying a `metadata` value IS an envelope around it — the body is that
|
|
166
|
+
value, everything beside it is bookkeeping. This is the `data.metadata ?? data`
|
|
167
|
+
rule the publish gate, `publishedDefinition` and `getPublished` already shared;
|
|
168
|
+
- otherwise the body is the row minus the declared bookkeeping keys.
|
|
169
|
+
|
|
170
|
+
The peel returns views and never mutates the row, so every existing envelope
|
|
171
|
+
reader (`publishPackage`'s `packageId` filter, `query`'s `state` / `packageId`
|
|
172
|
+
filters, `revertPackage`) is untouched, and `publishedDefinition` still snapshots
|
|
173
|
+
`data.metadata ?? data` verbatim.
|
|
174
|
+
|
|
175
|
+
One consequence worth naming: `buildEndpointIndex` was the last reader that did
|
|
176
|
+
NOT follow the layer's body-selection rule, so a publish envelope
|
|
177
|
+
(`{ name, packageId, state, metadata: {…} }`) used to pass the publish gate and
|
|
178
|
+
then be excluded from the endpoint index — its route answered 404. The two doors
|
|
179
|
+
now read the same document.
|
|
180
|
+
|
|
181
|
+
This is the prerequisite for tightening `ApiEndpointSchema` (#5384): with the
|
|
182
|
+
schema flipped to `strictObject` locally, `packages/metadata` went from 11 failing
|
|
183
|
+
tests to 1, and the one left is an authored non-vocabulary key being refused by
|
|
184
|
+
name — which is what that tightening is for.
|
|
185
|
+
|
|
186
|
+
- 1da39f5: fix(metadata): `isMissingTableError` no longer reads Postgres' write-path missing-COLUMN message as a missing TABLE (#6347)
|
|
187
|
+
|
|
188
|
+
`isMissingTableError` is the single predicate that licenses a caller to treat a
|
|
189
|
+
failed read as "the table is not provisioned yet, so there are genuinely no
|
|
190
|
+
rows". Its own docblock names `column "x" does not exist` (SQLSTATE 42703) as a
|
|
191
|
+
real failure that must stay loud — "a case where 'start numbering at 1' would be
|
|
192
|
+
the wrong answer against a table that may be full of rows" — and the code did
|
|
193
|
+
not honour that, in one direction only.
|
|
194
|
+
|
|
195
|
+
Postgres has **two** missing-column phrasings:
|
|
196
|
+
|
|
197
|
+
| path | message | judged |
|
|
198
|
+
| :-------------------------------- | :----------------------------------------------------- | :---------------------------- |
|
|
199
|
+
| read (`SELECT`) | `column "bogus" does not exist` | correctly NOT a missing table |
|
|
200
|
+
| write (`INSERT`/`UPDATE`/`ALTER`) | `column "label" of relation "sys_team" does not exist` | **wrongly** a missing table |
|
|
201
|
+
|
|
202
|
+
The write-path phrase contains a complete, legal missing-table phrase —
|
|
203
|
+
`relation "sys_team" does not exist` — as a substring, so the table-scoped
|
|
204
|
+
message test matched it. The code channel did not rescue it either: the matcher
|
|
205
|
+
is a sequential OR, so an error carrying `code: '42703'` falls past both code
|
|
206
|
+
lines and is decided by its message. The same superstring covers every other
|
|
207
|
+
sub-object of a relation Postgres phrases this way, e.g.
|
|
208
|
+
`constraint "uq_x" of relation "sys_team" does not exist` (42704).
|
|
209
|
+
|
|
210
|
+
A message regex can never exclude a superstring, so the repair is a
|
|
211
|
+
**front-exclusion** evaluated before any positive test: the column-level
|
|
212
|
+
SQLSTATEs the docblock already names (`42703`, `42704`, `3D000`) and the
|
|
213
|
+
`"x" of relation "y"` sub-object phrasing. Recognising one ends the question
|
|
214
|
+
with `false` — it does not descend into `cause`, because an error that
|
|
215
|
+
identifies as "a column of an existing relation" is that error whatever it
|
|
216
|
+
wraps.
|
|
217
|
+
|
|
218
|
+
What changes for you: a driver error of that shape now propagates instead of
|
|
219
|
+
being silenced. Every consumer of the predicate is affected the same way, and
|
|
220
|
+
all of them get louder rather than quieter — `DatabaseLoader.nextEventSeq` and
|
|
221
|
+
`SysMetadataRepository`'s history counters no longer restart `event_seq` at 1,
|
|
222
|
+
`ObjectQLEngine`'s autonumber seed no longer reseeds from 0, and the metadata
|
|
223
|
+
loaders no longer answer "nothing declared". The set of errors judged benign
|
|
224
|
+
shrinks; nothing that was loud becomes quiet. Genuine missing-table detection is
|
|
225
|
+
unchanged for PostgreSQL, MySQL/MariaDB and the SQLite family.
|
|
226
|
+
|
|
227
|
+
- 91cefb8: refactor(types,rest,metadata,analytics): Postgres 的 `"x" of relation "y"` 短语收归一处,三个包不再各修一遍同一个超串洞(#6615)
|
|
228
|
+
|
|
229
|
+
Postgres 把「关系内部某个子对象」的失败写成 `column "label" of relation "sys_team" does not exist`——里面**逐字包含**一句合法的「表不存在」短语 `relation "sys_team" does not exist`,含义却相反:关系正因为存在才被点名。任何对「这句话是不是在说表没了」的正则收紧都消不掉这个匹配,短语确实在里面;唯一的修法是**先问更具体的问题**。所以修的是**顺序**,不是模式。
|
|
230
|
+
|
|
231
|
+
正因为如此,这个短语被分三次教给了这个仓库,分属三个包、三个 PR,其中两次是在别处已经踩过同一个洞之后:`@objectstack/rest` 的 `mapDataError`(#5352)、`@objectstack/service-analytics` 的缺列扣除(#6035 / PR #6346)、`@objectstack/metadata` 的 `MISSING_TABLE.excludes`(#6347 / PR #6613)。本次把它收进 `@objectstack/types`,与 `isUniqueViolationError`(#6250)和 `isModuleNotFoundError`(framework#3265)同一个理由与同一个位置。
|
|
232
|
+
|
|
233
|
+
**两种宽度,故意保留成两个导出。** 三个消费者要的并不是同一条正则,差别也不是随手写的,而是**每个站点哪个方向的误差是安全的**:
|
|
234
|
+
|
|
235
|
+
- `matchMissingColumnOfRelation(message)` —— 严格提取器,锚定 Postgres 的 errmsg 模板 `column "%s" of relation "%s" does not exist`,返回列名。`rest` 用它把 42703 答成 `400 INVALID_FIELD` 而不是 `404`;`service-analytics` 用它在分类前扣除缺列。这两处**过宽**会把真正缺失的表变成硬失败、回退 #5033 刻意保留的宽容,**漏匹配**只是让消息含糊一点——所以必须严格。
|
|
236
|
+
- `isRelationSubObjectPhrase(message)` —— 宽检测器,丢掉 `column` / `[a-z0-9_]+` / `does not exist` 三个锚点:任意子对象、任意带引号标识符、任意判词。`metadata` 用它做排除。这一处**过宽**只会把良性判定变成响亮判定,**漏匹配**却会让 `event_seq` 从 1 重新开始、撞进一张已有行的历史表——方向正好相反。
|
|
237
|
+
|
|
238
|
+
把两者合并成一条正则,无论哪种宽度胜出都会对其中一个调用方是错的;这是卡片记录在案的风险,两个导出即为此而设,理由是承重的而非风格的。仓库里第四份拷贝(`service-analytics` 测试内用于守护 fixture 的那条正则)同时收编:它本是为「两张面孔别对不上」而写,却把断言打在其中一面的私有复述上,因而正是它要防的漂移。
|
|
239
|
+
|
|
240
|
+
行为逐字保持不变:搬进来的两条模式与原站点逐字节相同。`@objectstack/service-analytics` 因此新增一条对 `@objectstack/types` 的依赖边——这是本次唯一的依赖变化,构造上无环(`@objectstack/types` 只依赖 `@objectstack/spec`,后者无仓内依赖),且仓库 73 个包中已有 25 个、16 个 service 中已有 5 个携带同一条边。
|
|
241
|
+
|
|
242
|
+
- 3de535b: fix(metadata,repo): every enumeration of the stack-collection set is now answerable to `stack.zod.ts`, and the artifact map stops aiming `data:` at the analytics kind (#6242)
|
|
243
|
+
|
|
244
|
+
`ObjectStackDefinitionSchema` decides which collections a stack may declare — 32
|
|
245
|
+
of them today. **Seven** other places re-enumerate that same set by hand (eight
|
|
246
|
+
enumerations in all, because ObjectQL declares its list twice), and nothing
|
|
247
|
+
compared any of them to the schema or to each other:
|
|
248
|
+
|
|
249
|
+
| Enumeration | Site |
|
|
250
|
+
| --------------------------------------------- | ----------------------------------------------------- |
|
|
251
|
+
| `MAP_SUPPORTED_FIELDS` / `PLURAL_TO_SINGULAR` | `packages/spec/src/shared/metadata-collection.zod.ts` |
|
|
252
|
+
| `MetadataCategoryEnum` | `packages/spec/src/kernel/package-artifact.zod.ts` |
|
|
253
|
+
| `metadataArrayKeys` ×2 | `packages/objectql/src/engine.ts` |
|
|
254
|
+
| `ARTIFACT_FIELD_TO_TYPE` | `packages/metadata/src/plugin.ts` |
|
|
255
|
+
| `APP_CATEGORY_KEYS` | `packages/runtime/src/app-plugin.ts` |
|
|
256
|
+
| `STACK_COLLECTION_COVERAGE` | `examples/app-showcase/src/coverage.ts` |
|
|
257
|
+
|
|
258
|
+
They had drifted independently: `ragPipelines` mapped in three of them though no
|
|
259
|
+
schema declares it; `workflows` / `approvals` / `roles` / `profiles` / `policies`
|
|
260
|
+
still iterated by both ObjectQL loops after ADR-0019 / ADR-0020 / ADR-0088 /
|
|
261
|
+
ADR-0090 retired them; `triggers` + `workflows` still legal artifact categories;
|
|
262
|
+
19 of 32 collections absent from that enum.
|
|
263
|
+
|
|
264
|
+
Every row looks like a one-line typo in isolation, and each **has** been fixed
|
|
265
|
+
one line at a time before — `docs` in `ARTIFACT_FIELD_TO_TYPE`, `roles` →
|
|
266
|
+
`positions` in the same map, `capabilities` in `metadataArrayKeys` — each still
|
|
267
|
+
carrying its "this key was missing and it silently dropped X" comment. The cause
|
|
268
|
+
is structural: `KIND_COVERAGE` is answerable to the metadata-type registry and
|
|
269
|
+
fails CI when a kind is added without an entry, and the liveness ledger is
|
|
270
|
+
answerable to the same registry. The collection maps were answerable to nothing.
|
|
271
|
+
|
|
272
|
+
**The gate.** `pnpm check:stack-collection-maps` (root
|
|
273
|
+
`scripts/check-stack-collection-maps.mjs`, wired into the lint job) derives the
|
|
274
|
+
collection set from `ObjectStackDefinitionSchema` — top-level keys whose value is
|
|
275
|
+
`z.array(<X>Schema)`, a mechanical rule rather than a second hand-kept list — and
|
|
276
|
+
reconciles all eight enumerations against it in **both** directions. Deriving them
|
|
277
|
+
is not possible today (they disagree on purpose as often as by accident: `views`
|
|
278
|
+
has no `name`, `data` seeds key by `object`, `translations` is a record), so each
|
|
279
|
+
deviation must instead be a waiver row **carrying its reason**, and the list is a
|
|
280
|
+
ratchet: a waiver that no longer applies fails, like a stale ledger row. An
|
|
281
|
+
enumeration whose symbol cannot be extracted fails too — an empty list would
|
|
282
|
+
reconcile against everything.
|
|
283
|
+
|
|
284
|
+
Writing it immediately found a **seventh** site the hand-audit had missed
|
|
285
|
+
(`APP_CATEGORY_KEYS`) and one divergence _between_ the two ObjectQL copies that
|
|
286
|
+
neither list shows alone: `jobs`, `emailTemplates`, `tools` and `skills` are
|
|
287
|
+
registered from a manifest and **not** from a nested plugin, so a package
|
|
288
|
+
shipping them from a nested plugin registers nothing and stamps no ADR-0010
|
|
289
|
+
provenance. `capabilities` was added to that copy for exactly this reason
|
|
290
|
+
(#5870); nobody then asked what else the two lists disagreed about. Recorded as
|
|
291
|
+
a waiver with the measurement, not fixed here — closing it changes what a nested
|
|
292
|
+
plugin registers at boot.
|
|
293
|
+
|
|
294
|
+
**The one code change**: `ARTIFACT_FIELD_TO_TYPE` no longer maps `data:` (the
|
|
295
|
+
SEED collection) to `'dataset'` (the ADR-0021 analytics kind) — the exact name
|
|
296
|
+
collision `metadata-plugin.zod.ts` warns about in prose. The entry was provably
|
|
297
|
+
inert (`SeedSchema` declares no `name`, and the ingest loop skips nameless
|
|
298
|
+
items), so nothing changes at runtime; what changes is that a dead pointer aimed
|
|
299
|
+
at the wrong kind is gone, instead of waiting for either side to move. Not
|
|
300
|
+
repointed at `'seed'`: seeds are applied by `SeedLoaderService` off the bundle,
|
|
301
|
+
never registered as metadata items, so that would be new behaviour rather than a
|
|
302
|
+
corrected name. The absence is now pinned by the gate.
|
|
303
|
+
|
|
304
|
+
Everything else the gate reports is recorded as a waiver with its reason and left
|
|
305
|
+
alone, deliberately — three of the drift rows sit on **acceptance faces**
|
|
306
|
+
(`MetadataCategoryEnum` decides what a published artifact may declare) and the
|
|
307
|
+
rest are `engine-core` behaviour changes owing their own verification. The value
|
|
308
|
+
landing today is that all eight enumerations now have a checked relationship to
|
|
309
|
+
the schema rather than an assumed one.
|
|
310
|
+
|
|
311
|
+
- Updated dependencies [3d5c090]
|
|
312
|
+
- Updated dependencies [e5bd768]
|
|
313
|
+
- Updated dependencies [e027b3e]
|
|
314
|
+
- Updated dependencies [c2429b0]
|
|
315
|
+
- Updated dependencies [445a0c2]
|
|
316
|
+
- Updated dependencies [f6609e6]
|
|
317
|
+
- Updated dependencies [a70358a]
|
|
318
|
+
- Updated dependencies [97e7e3c]
|
|
319
|
+
- Updated dependencies [8828b9e]
|
|
320
|
+
- Updated dependencies [53068c1]
|
|
321
|
+
- Updated dependencies [ee58392]
|
|
322
|
+
- Updated dependencies [f16e54e]
|
|
323
|
+
- Updated dependencies [06be54e]
|
|
324
|
+
- Updated dependencies [259459d]
|
|
325
|
+
- Updated dependencies [3f7f14e]
|
|
326
|
+
- Updated dependencies [6968885]
|
|
327
|
+
- Updated dependencies [eaed61f]
|
|
328
|
+
- Updated dependencies [debe2f6]
|
|
329
|
+
- Updated dependencies [97b0798]
|
|
330
|
+
- Updated dependencies [5fa04fb]
|
|
331
|
+
- Updated dependencies [43a7a8d]
|
|
332
|
+
- Updated dependencies [73f69dc]
|
|
333
|
+
- Updated dependencies [04c56aa]
|
|
334
|
+
- Updated dependencies [b3efeb7]
|
|
335
|
+
- Updated dependencies [ddd075a]
|
|
336
|
+
- Updated dependencies [88154be]
|
|
337
|
+
- Updated dependencies [e8dc61e]
|
|
338
|
+
- Updated dependencies [2f3e793]
|
|
339
|
+
- Updated dependencies [d8e8d9c]
|
|
340
|
+
- Updated dependencies [94e749b]
|
|
341
|
+
- Updated dependencies [ea1d916]
|
|
342
|
+
- Updated dependencies [ae31a19]
|
|
343
|
+
- Updated dependencies [e0f300b]
|
|
344
|
+
- Updated dependencies [62b6a2f]
|
|
345
|
+
- Updated dependencies [5b4780b]
|
|
346
|
+
- Updated dependencies [a933452]
|
|
347
|
+
- Updated dependencies [8140915]
|
|
348
|
+
- Updated dependencies [7b48cf9]
|
|
349
|
+
- Updated dependencies [b5404f4]
|
|
350
|
+
- Updated dependencies [f764691]
|
|
351
|
+
- Updated dependencies [e120a5a]
|
|
352
|
+
- Updated dependencies [e650d67]
|
|
353
|
+
- Updated dependencies [121852d]
|
|
354
|
+
- Updated dependencies [04476e7]
|
|
355
|
+
- Updated dependencies [79228cd]
|
|
356
|
+
- Updated dependencies [b3363e9]
|
|
357
|
+
- Updated dependencies [2ef1807]
|
|
358
|
+
- Updated dependencies [d03fe25]
|
|
359
|
+
- Updated dependencies [2672f85]
|
|
360
|
+
- Updated dependencies [11066f6]
|
|
361
|
+
- Updated dependencies [916af17]
|
|
362
|
+
- Updated dependencies [84c86fb]
|
|
363
|
+
- Updated dependencies [2a2a9fb]
|
|
364
|
+
- Updated dependencies [a2e157c]
|
|
365
|
+
- Updated dependencies [95c4227]
|
|
366
|
+
- Updated dependencies [2a61116]
|
|
367
|
+
- Updated dependencies [d4df105]
|
|
368
|
+
- Updated dependencies [e2798fa]
|
|
369
|
+
- Updated dependencies [0fd8556]
|
|
370
|
+
- Updated dependencies [74155c7]
|
|
371
|
+
- Updated dependencies [6908830]
|
|
372
|
+
- Updated dependencies [8b06bba]
|
|
373
|
+
- Updated dependencies [4c54037]
|
|
374
|
+
- Updated dependencies [0f7157b]
|
|
375
|
+
- Updated dependencies [d9bef45]
|
|
376
|
+
- Updated dependencies [f549a0d]
|
|
377
|
+
- Updated dependencies [82da264]
|
|
378
|
+
- Updated dependencies [f586f1a]
|
|
379
|
+
- Updated dependencies [9b9b70f]
|
|
380
|
+
- Updated dependencies [f5a9bc2]
|
|
381
|
+
- Updated dependencies [881a3cc]
|
|
382
|
+
- Updated dependencies [ad6317b]
|
|
383
|
+
- Updated dependencies [8a88885]
|
|
384
|
+
- Updated dependencies [5f7669e]
|
|
385
|
+
- Updated dependencies [becbe53]
|
|
386
|
+
- Updated dependencies [b127c8b]
|
|
387
|
+
- Updated dependencies [a80302a]
|
|
388
|
+
- Updated dependencies [474f131]
|
|
389
|
+
- Updated dependencies [050cd82]
|
|
390
|
+
- Updated dependencies [4d552af]
|
|
391
|
+
- Updated dependencies [44d677c]
|
|
392
|
+
- Updated dependencies [c32944d]
|
|
393
|
+
- Updated dependencies [1dd780f]
|
|
394
|
+
- Updated dependencies [c8d6f6e]
|
|
395
|
+
- Updated dependencies [a1b66ef]
|
|
396
|
+
- Updated dependencies [92a67f2]
|
|
397
|
+
- Updated dependencies [9136327]
|
|
398
|
+
- Updated dependencies [bf0ae99]
|
|
399
|
+
- Updated dependencies [cb3b6cd]
|
|
400
|
+
- Updated dependencies [73b7234]
|
|
401
|
+
- Updated dependencies [d2b97c3]
|
|
402
|
+
- Updated dependencies [59b794f]
|
|
403
|
+
- Updated dependencies [fc3a36a]
|
|
404
|
+
- Updated dependencies [69787f0]
|
|
405
|
+
- Updated dependencies [5d022a1]
|
|
406
|
+
- Updated dependencies [042b9ee]
|
|
407
|
+
- Updated dependencies [f549a0d]
|
|
408
|
+
- Updated dependencies [a36db28]
|
|
409
|
+
- Updated dependencies [3f8817a]
|
|
410
|
+
- Updated dependencies [a2443e3]
|
|
411
|
+
- Updated dependencies [e1554b1]
|
|
412
|
+
- Updated dependencies [4856789]
|
|
413
|
+
- Updated dependencies [c3f4916]
|
|
414
|
+
- Updated dependencies [33e0385]
|
|
415
|
+
- Updated dependencies [2205363]
|
|
416
|
+
- Updated dependencies [09fe58d]
|
|
417
|
+
- Updated dependencies [d0a5ceb]
|
|
418
|
+
- Updated dependencies [e18a162]
|
|
419
|
+
- Updated dependencies [d6d1a50]
|
|
420
|
+
- Updated dependencies [d127ff0]
|
|
421
|
+
- Updated dependencies [9b86cf6]
|
|
422
|
+
- Updated dependencies [8825a06]
|
|
423
|
+
- Updated dependencies [5087ac6]
|
|
424
|
+
- Updated dependencies [2d1ddf0]
|
|
425
|
+
- Updated dependencies [354b00f]
|
|
426
|
+
- Updated dependencies [3de535b]
|
|
427
|
+
- Updated dependencies [fe2e15a]
|
|
428
|
+
- Updated dependencies [c6b6bb4]
|
|
429
|
+
- Updated dependencies [59c544d]
|
|
430
|
+
- Updated dependencies [2f59da0]
|
|
431
|
+
- Updated dependencies [5e247fd]
|
|
432
|
+
- Updated dependencies [1a53a02]
|
|
433
|
+
- Updated dependencies [ab07b53]
|
|
434
|
+
- Updated dependencies [a954634]
|
|
435
|
+
- Updated dependencies [8ad609c]
|
|
436
|
+
- Updated dependencies [bbee302]
|
|
437
|
+
- Updated dependencies [08863dd]
|
|
438
|
+
- Updated dependencies [56664f5]
|
|
439
|
+
- Updated dependencies [31cbe90]
|
|
440
|
+
- Updated dependencies [90bbf25]
|
|
441
|
+
- Updated dependencies [eb91eba]
|
|
442
|
+
- Updated dependencies [42da73d]
|
|
443
|
+
- Updated dependencies [643b7c7]
|
|
444
|
+
- Updated dependencies [d0d5205]
|
|
445
|
+
- Updated dependencies [1a15893]
|
|
446
|
+
- Updated dependencies [b70e534]
|
|
447
|
+
- Updated dependencies [2233a85]
|
|
448
|
+
- Updated dependencies [62dd69a]
|
|
449
|
+
- Updated dependencies [e15e679]
|
|
450
|
+
- Updated dependencies [2ab1257]
|
|
451
|
+
- Updated dependencies [4cc4fb7]
|
|
452
|
+
- Updated dependencies [28d1eb7]
|
|
453
|
+
- Updated dependencies [2c26040]
|
|
454
|
+
- Updated dependencies [f758cec]
|
|
455
|
+
- Updated dependencies [684ab22]
|
|
456
|
+
- Updated dependencies [78f0be8]
|
|
457
|
+
- Updated dependencies [35f7fb4]
|
|
458
|
+
- Updated dependencies [a5302c7]
|
|
459
|
+
- Updated dependencies [7084313]
|
|
460
|
+
- Updated dependencies [91cefb8]
|
|
461
|
+
- Updated dependencies [0e043d8]
|
|
462
|
+
- Updated dependencies [dadd1ad]
|
|
463
|
+
- Updated dependencies [2f2e63c]
|
|
464
|
+
- Updated dependencies [486d526]
|
|
465
|
+
- Updated dependencies [89d7b35]
|
|
466
|
+
- Updated dependencies [85ec26d]
|
|
467
|
+
- Updated dependencies [f6476fc]
|
|
468
|
+
- Updated dependencies [4ac12ef]
|
|
469
|
+
- Updated dependencies [b88f5e8]
|
|
470
|
+
- Updated dependencies [42cc219]
|
|
471
|
+
- Updated dependencies [d42a92f]
|
|
472
|
+
- Updated dependencies [51d74ad]
|
|
473
|
+
- Updated dependencies [d7e0b42]
|
|
474
|
+
- Updated dependencies [3510e4a]
|
|
475
|
+
- Updated dependencies [aa4b90d]
|
|
476
|
+
- Updated dependencies [54299ca]
|
|
477
|
+
- Updated dependencies [dc61def]
|
|
478
|
+
- Updated dependencies [251e888]
|
|
479
|
+
- Updated dependencies [183b4c4]
|
|
480
|
+
- Updated dependencies [2fdb36e]
|
|
481
|
+
- Updated dependencies [e787608]
|
|
482
|
+
- Updated dependencies [20526f5]
|
|
483
|
+
- Updated dependencies [c5eef1d]
|
|
484
|
+
- Updated dependencies [e0f300b]
|
|
485
|
+
- Updated dependencies [761a0ba]
|
|
486
|
+
- Updated dependencies [61282f9]
|
|
487
|
+
- Updated dependencies [be87153]
|
|
488
|
+
- Updated dependencies [60f0dd8]
|
|
489
|
+
- Updated dependencies [a87c5cd]
|
|
490
|
+
- Updated dependencies [a47f338]
|
|
491
|
+
- Updated dependencies [2598216]
|
|
492
|
+
- Updated dependencies [2c7e62d]
|
|
493
|
+
- Updated dependencies [eb7613c]
|
|
494
|
+
- Updated dependencies [ecc9110]
|
|
495
|
+
- Updated dependencies [f7bd4e2]
|
|
496
|
+
- Updated dependencies [361bd5b]
|
|
497
|
+
- Updated dependencies [129b378]
|
|
498
|
+
- Updated dependencies [88f9d94]
|
|
499
|
+
- Updated dependencies [1818998]
|
|
500
|
+
- Updated dependencies [3d4c545]
|
|
501
|
+
- Updated dependencies [bb7cb41]
|
|
502
|
+
- Updated dependencies [09ee21c]
|
|
503
|
+
- Updated dependencies [f549a0d]
|
|
504
|
+
- Updated dependencies [3fc2e48]
|
|
505
|
+
- Updated dependencies [e8f435c]
|
|
506
|
+
- Updated dependencies [41610f6]
|
|
507
|
+
- @objectstack/spec@17.0.0-rc.6
|
|
508
|
+
- @objectstack/platform-objects@17.0.0-rc.6
|
|
509
|
+
- @objectstack/metadata-core@17.0.0-rc.6
|
|
510
|
+
- @objectstack/core@17.0.0-rc.6
|
|
511
|
+
- @objectstack/metadata-fs@17.0.0-rc.6
|
|
512
|
+
- @objectstack/types@17.0.0-rc.6
|
|
513
|
+
|
|
514
|
+
## 17.0.0-rc.5
|
|
515
|
+
|
|
516
|
+
### Patch Changes
|
|
517
|
+
|
|
518
|
+
- Updated dependencies [e8f8f6c]
|
|
519
|
+
- Updated dependencies [7f713b6]
|
|
520
|
+
- Updated dependencies [c960170]
|
|
521
|
+
- Updated dependencies [def5919]
|
|
522
|
+
- Updated dependencies [ce0cfe9]
|
|
523
|
+
- Updated dependencies [1363084]
|
|
524
|
+
- @objectstack/spec@17.0.0-rc.5
|
|
525
|
+
- @objectstack/core@17.0.0-rc.5
|
|
526
|
+
- @objectstack/metadata-core@17.0.0-rc.5
|
|
527
|
+
- @objectstack/platform-objects@17.0.0-rc.5
|
|
528
|
+
- @objectstack/types@17.0.0-rc.5
|
|
529
|
+
- @objectstack/metadata-fs@17.0.0-rc.5
|
|
530
|
+
|
|
3
531
|
## 17.0.0-rc.4
|
|
4
532
|
|
|
5
533
|
### Minor Changes
|
package/dist/errors.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(errors_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(errors_exports);
|
|
26
26
|
|
|
27
27
|
// src/utils/schema-sync-errors.ts
|
|
28
|
+
var import_types = require("@objectstack/types");
|
|
28
29
|
var MISSING_TABLE = {
|
|
29
30
|
codes: /* @__PURE__ */ new Set([
|
|
30
31
|
"42P01",
|
|
@@ -38,14 +39,67 @@ var MISSING_TABLE = {
|
|
|
38
39
|
* - PostgreSQL: `relation "sys_metadata_history" does not exist`
|
|
39
40
|
* - MySQL/MariaDB: `Table 'app.sys_metadata_history' doesn't exist`
|
|
40
41
|
*/
|
|
41
|
-
message: /no such table|relation ["'`][^"'`]+["'`] does not exist|table ["'`][^"'`]+["'`] doesn'?t exist|unknown table/i
|
|
42
|
+
message: /no such table|relation ["'`][^"'`]+["'`] does not exist|table ["'`][^"'`]+["'`] doesn'?t exist|unknown table/i,
|
|
43
|
+
excludes: {
|
|
44
|
+
/**
|
|
45
|
+
* Exactly the three SQLSTATEs the docblock above already names as
|
|
46
|
+
* must-stay-loud neighbours of `does not exist`. They are listed here
|
|
47
|
+
* rather than merely trusted to miss the message test, because two of
|
|
48
|
+
* them (42703 columns, 42704 constraints/triggers) have a phrasing that
|
|
49
|
+
* *does* hit it, and because a code is a fact where prose is a guess.
|
|
50
|
+
*
|
|
51
|
+
* Postgres-shaped on purpose: measured, neither MySQL
|
|
52
|
+
* (`Unknown column 'label' in 'field list'`) nor SQLite
|
|
53
|
+
* (`no such column: bogus`, `table t has no column named label`)
|
|
54
|
+
* phrases a sub-object failure so that a missing-table phrase falls out
|
|
55
|
+
* of it, so there is nothing there to exclude. Adding their codes would
|
|
56
|
+
* be surface with no defect behind it.
|
|
57
|
+
*/
|
|
58
|
+
codes: /* @__PURE__ */ new Set([
|
|
59
|
+
"42703",
|
|
60
|
+
// undefined_column
|
|
61
|
+
"42704",
|
|
62
|
+
// undefined_object — constraint, trigger, role, type, …
|
|
63
|
+
"3D000"
|
|
64
|
+
// invalid_catalog_name — `database "x" does not exist`
|
|
65
|
+
]),
|
|
66
|
+
/**
|
|
67
|
+
* `«sub-object» "x" of relation "y" …` — Postgres' phrasing for a
|
|
68
|
+
* failure about something *inside* a relation, which therefore says the
|
|
69
|
+
* relation itself is present. The two in-repo siblings that carry this
|
|
70
|
+
* phrase are `mapDataError` (`packages/rest`, #5352) and
|
|
71
|
+
* `service-analytics`'s missing-column subtraction (#6035/PR #6346).
|
|
72
|
+
*
|
|
73
|
+
* [#6615] All three now read one home — `@objectstack/types` — instead
|
|
74
|
+
* of three hand-kept copies, so the phrase can no longer be taught to
|
|
75
|
+
* the repo a fourth time or drift in one package only. The **width**
|
|
76
|
+
* difference that used to justify the copy is preserved and is the
|
|
77
|
+
* reason the home exports two functions rather than one: those two
|
|
78
|
+
* *extract* the column name to phrase a better error, so a miss costs a
|
|
79
|
+
* vaguer message; this one *excludes*, so a miss restores the
|
|
80
|
+
* corruption. {@link isRelationSubObjectPhrase} is therefore the wider
|
|
81
|
+
* question — it drops their `column`/`[a-z0-9_]+`/`does not exist`
|
|
82
|
+
* anchors: any sub-object, any quoted identifier, any verdict.
|
|
83
|
+
* Over-matching here only ever converts a benign verdict into a loud
|
|
84
|
+
* one, which is the direction this whole module already errs in.
|
|
85
|
+
*/
|
|
86
|
+
matchesMessage: import_types.isRelationSubObjectPhrase
|
|
87
|
+
}
|
|
42
88
|
};
|
|
43
89
|
var MAX_CAUSE_DEPTH = 4;
|
|
44
90
|
function matchesDriverError(error, signature, depth) {
|
|
45
91
|
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return false;
|
|
46
|
-
if (typeof error === "string")
|
|
92
|
+
if (typeof error === "string") {
|
|
93
|
+
if (signature.excludes?.matchesMessage(error)) return false;
|
|
94
|
+
return signature.message.test(error);
|
|
95
|
+
}
|
|
47
96
|
if (typeof error !== "object") return false;
|
|
48
97
|
const err = error;
|
|
98
|
+
const excludes = signature.excludes;
|
|
99
|
+
if (excludes) {
|
|
100
|
+
if (typeof err.code === "string" && excludes.codes.has(err.code)) return false;
|
|
101
|
+
if (typeof err.message === "string" && excludes.matchesMessage(err.message)) return false;
|
|
102
|
+
}
|
|
49
103
|
if (typeof err.code === "string" && signature.codes.has(err.code)) return true;
|
|
50
104
|
if (typeof err.errno === "number" && signature.errnos.has(err.errno)) return true;
|
|
51
105
|
if (typeof err.message === "string" && signature.message.test(err.message)) return true;
|