@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 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") return signature.message.test(error);
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;