@object-ui/data-objectstack 17.1.0 → 17.3.0

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,233 @@
1
1
  # @object-ui/data-objectstack
2
2
 
3
+ ## 17.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d22ae31: Track `@objectstack/spec` 17.0.0-rc.2 (objectui#3235, #3208, #3287, #3264).
8
+
9
+ The pin moves from `^17.0.0-rc.1` to `^17.0.0-rc.2` across the workspace, and
10
+ the sibling `@objectstack/*` packages (`client` / `core` / `formula` / `lint`)
11
+ move with it — they pin `@objectstack/spec` **exactly**, so leaving them behind
12
+ kept a second copy of the spec in the tree and would have had `@objectstack/lint`
13
+ validating against rc.1 schemas that still accept keys rc.2 retires.
14
+
15
+ Breaking semantics, in FROM → TO form:
16
+
17
+ - **`app.homePageId` is retired — an app's landing page is now its first
18
+ navigation item.** An app that pinned a landing page with `homePageId` will
19
+ open on the first reachable navigation entry (by `order`) instead; the root
20
+ landing still follows `isDefault`. To restore a specific landing page, reorder
21
+ `navigation` so the intended entry comes first. Stored metadata is migrated by
22
+ `os migrate meta --from 16`. The key is a hard error now, not a stripped one:
23
+ the spec ships a tombstone that names the migration.
24
+ Upstream retired it because of its SHAPE, not its usage — it was an ID
25
+ cross-reference with no referential integrity, so a `homePageId` that pointed
26
+ at nothing silently fell back to the first navigation item anyway
27
+ (objectstack#4667, premise corrected in #4709). If the capability returns, it
28
+ returns as a flag on the navigation item itself, which cannot dangle.
29
+ - **`@object-ui/types`' `HttpMethod` now resolves to the spec's
30
+ `HttpMethodType`.** Shape is verbatim identical — the same 5-value UI subset —
31
+ and `@object-ui/types` still exports it as `HttpMethod`, so no consumer
32
+ changes. The spec renamed its `./ui` export because `HttpMethod` named two
33
+ different types depending on the import path (`./shared` / `./api` carry a
34
+ 7-value enum including `HEAD` / `OPTIONS`); objectui deliberately keeps the
35
+ 5-value one (objectstack#4691).
36
+ - **`AppContextSelector.includeAll` / `placement` are gone.** Neither ever did
37
+ anything in this renderer: context selectors are mandatory-scope, so no "All"
38
+ row was ever rendered, and `placement: 'topbar'` put nothing in the topbar.
39
+ Both carried schema defaults, which is why the liveness lint structurally
40
+ could not flag them — removal was the only channel that reaches an author
41
+ (framework#4509).
42
+ - **`NavigationArea.visible` / `order` / `requiredPermissions` are gone.** An
43
+ area is a layout grouping, not an access boundary. Gating moved down to the
44
+ navigation ITEM, where `visible` and `requiredPermissions` are unchanged and
45
+ still enforced. `AppSchemaRenderer`'s area switcher no longer hides an area, so
46
+ an area whose items are all gated away renders as visible-but-empty rather
47
+ than disappearing.
48
+ - **`@object-ui/core` no longer exports `NotificationProtocol`**
49
+ (`resolveNotificationConfig`, `specNotificationToToast`, `mapSeverityToVariant`,
50
+ `mapPosition`, `ToastNotification`). It bridged `@objectstack/spec/ui`'s
51
+ `Notification` / `NotificationConfig`, which objectstack#4610 deleted with no
52
+ successor. Use `resolveNotificationConfig` from `@object-ui/react`
53
+ (`NotificationContext`), which owns the live `NotificationSystemConfig` and is
54
+ what every notification surface already read. Note that the spec's _other_
55
+ `Notification` — `@objectstack/spec/api` — is the REST inbox row, a different
56
+ contract, and is deliberately NOT aliased in as a replacement.
57
+ - **The `email_template` client-side validator now uses
58
+ `EmailTemplateDefinitionSchema`.** It was pointing at the removed
59
+ `EmailTemplateSchema`, so authored templates were being checked against the
60
+ wrong contract: the live one is keyed `name` + `locale` (not `id`) and splits
61
+ the body into `bodyHtml` / `bodyText` (not `body` + `bodyType`)
62
+ (objectstack#4616 / #4807).
63
+
64
+ Fixes that are not breaking, but were only found because rc.2 stopped being
65
+ lenient — each had been passing vacuously:
66
+
67
+ - **`view` drafts are actually validated now.** The client validator named the
68
+ aggregated container schema while this admin authors first-class `ViewItem`s,
69
+ and the container used to strip `viewKind` / `config` in silence — so no view
70
+ draft ever had one of its own keys checked. It now validates each shape
71
+ against its own schema (objectui#3312).
72
+ - **The console's worked examples were wrong**, and being stripped rather than
73
+ refused: `view.list.object` (the container root already declares it),
74
+ `job.concurrency` / `job.timeoutMs` (no such keys; the spelling is `timeout`,
75
+ already in ms), `email_template.from` / `.to` (a template is not a send —
76
+ the sender override is `fromOverride`, an object), and
77
+ `datasource.capabilities` / `.healthCheck` (objectstack#4583 removed the
78
+ former; the latter was never a datasource key). These are the drafts an
79
+ author — or a model generating metadata — copies.
80
+ - Action key inventory re-derived: `ActionSchema` gained the package-lock
81
+ envelope (`_lock*` / `_package*` / `_provenance`), so a packaged action no
82
+ longer reports them as unknown keys.
83
+ - The schema-diff panel labels the new `default_mismatch` finding.
84
+ - Test fixtures pinning the retired `managedBy: 'system'` bucket now use
85
+ `engine-owned`. Protocol 17 split that value (objectstack#3355), so it
86
+ resolved to the default-writable fallback and a batch of "stays locked"
87
+ assertions had quietly stopped asserting anything.
88
+
89
+ ### Patch Changes
90
+
91
+ - Updated dependencies [18cd432]
92
+ - Updated dependencies [d915c47]
93
+ - Updated dependencies [5781fb1]
94
+ - Updated dependencies [9e9e9a9]
95
+ - Updated dependencies [23018cc]
96
+ - Updated dependencies [d915c47]
97
+ - Updated dependencies [f44d872]
98
+ - Updated dependencies [509104a]
99
+ - Updated dependencies [a4cff5b]
100
+ - Updated dependencies [f833d3a]
101
+ - Updated dependencies [2a9513d]
102
+ - Updated dependencies [d22ae31]
103
+ - @object-ui/core@17.3.0
104
+ - @object-ui/types@17.3.0
105
+
106
+ ## 17.2.0
107
+
108
+ ### Minor Changes
109
+
110
+ - c5ccbd5: Stop declaring 12 `@object-ui/data-objectstack` / `@object-ui/plugin-chatbot` /
111
+ `@object-ui/plugin-list` symbols under names `@objectstack/spec` owns
112
+ (objectui#3160, objectstack#4115 batch 6). All three packages leave the ledger.
113
+
114
+ **Breaking for importers of `@object-ui/data-objectstack`** — four exported
115
+ names changed, because the spec exports the same name for a _different_ thing:
116
+
117
+ | was | now | what the spec's same-named export actually is |
118
+ | :-------------------- | :-------------------------- | :--------------------------------------------------------------------------------------- |
119
+ | `CacheStats` | `MetadataCacheStats` | the platform `ICacheService` counters (`keyCount`, `memoryUsage`) |
120
+ | `MetadataSaveOptions` | `MetadataClientSaveOptions` | options for writing a metadata item to a **file** (`format`, `path`, `indent`, `atomic`) |
121
+ | `SecurityPolicy` | `SecurityManagerPolicy` | the package supply-chain policy (`autoScan`, licences, code signing, sandbox) |
122
+ | `ValidationError` | `DataApiValidationError` | a plain `{ field, message, code? }` entry in a validation report |
123
+
124
+ Each pair is disjoint or nearly so — `MetadataSaveOptions` and `SecurityPolicy`
125
+ share not one key with the spec type whose name they wore — so none of them was
126
+ a dialect to reconcile; they were four unrelated concepts squatting on spec
127
+ names. `DataApiValidationError` follows the `<what was validated>Validation<Error|Result>`
128
+ convention registered on objectstack#4115 (`@object-ui/core` took
129
+ `SchemaNodeValidationError` in batch 4). Its **runtime** `name` deliberately
130
+ stays `'ValidationError'`: `normaliseClientError` and `@object-ui/react`'s
131
+ error-message helper both sniff `err.name`, so that string is a wire contract,
132
+ not a symbol.
133
+
134
+ **Breaking for importers of `@object-ui/plugin-chatbot`** — `PendingActionRow`
135
+ and `PendingActionStatus` are now re-exported from `@objectstack/spec/contracts`
136
+ instead of hand-transcribed, which narrows them. The copies had drifted three
137
+ ways, and each drift had **disabled a compile-time check** rather than merely
138
+ differed from one:
139
+
140
+ - `status: PendingActionStatus | string` — a union with `string` absorbs the
141
+ literals, so that annotation carried no information at all;
142
+ - `[key: string]: unknown` — the objectstack#4075 mechanism: an index signature
143
+ makes every structural comparison against the spec answer "identical", however
144
+ far the copy has drifted;
145
+ - `created_at` / `updated_at`, which the service contract does not carry and no
146
+ consumer in this repo reads.
147
+
148
+ **Breaking for importers of `@object-ui/plugin-list`** — `ViewTab` is derived from the spec's `ViewTabSchema`
149
+ — from its **input** side, because `pinned` / `isDefault` / `visible` carry
150
+ `.default()`s and this component is handed authored metadata, not parsed output.
151
+ That removes a renderer-side tolerance the copy carried: `visible` accepted
152
+ `string | boolean` and the tab bar compared it against the literal `'false'`, a
153
+ spelling no producer emits. `label` also stops being required (the spec makes it
154
+ optional; `name` is the identifier) and `filter` stops being `any`.
155
+
156
+ `ListView` and `UserFilters` keep their names as declared dialects: both are the
157
+ React **renderers** of the spec types whose names they share, and each takes that
158
+ spec type as a prop (`ListViewProps.schema`, `UserFiltersProps.config`) rather
159
+ than restating its shape. `Tool` and `MessageContent` in `plugin-chatbot` are
160
+ vendored Vercel AI Elements / Shadcn primitives — upstream's component API, not
161
+ objectui's authored surface — so the guard now skips that directory the same way
162
+ it already skips `components/src/ui/`, with a test that fails if any file there
163
+ stops carrying its vendor banner.
164
+
165
+ Scored `minor`, not `major`, per this repo's fixed-group rule — objectui's major
166
+ tracks `@objectstack`, so breaking changes of our own ship as minor with the
167
+ semantics spelled out above (see AGENTS.md §版本号策略). A `major` here would carry
168
+ all 39 packages of the fixed group to `18.0.0` and off objectstack's 17.x line.
169
+
170
+ - d3584c6: Bring the whole `@objectstack` family to `17.0.0-rc.1`, so the dependency graph resolves a
171
+ single copy of `@objectstack/spec`.
172
+
173
+ #3178 bumped **only** `@objectstack/spec` to `17.0.0-rc.1`. The rest of the family —
174
+ `client`, `core`, `formula`, `lint` (and `sdui-parser`, reached through `lint`) — stayed on
175
+ `17.0.0-rc.0`, and each of them depends on spec at an **exact** version rather than a
176
+ caret:
177
+
178
+ ```
179
+ @objectstack/client@17.0.0-rc.0 -> spec "17.0.0-rc.0"
180
+ @objectstack/core@17.0.0-rc.0 -> spec "17.0.0-rc.0"
181
+ @objectstack/formula@17.0.0-rc.0 -> spec "17.0.0-rc.0"
182
+ @objectstack/lint@17.0.0-rc.0 -> spec "17.0.0-rc.0"
183
+ ```
184
+
185
+ So `main` carried **two** spec copies: objectui's own code read `17.0.0-rc.1` while every
186
+ `@objectstack/*` package read `17.0.0-rc.0` from its own nested `node_modules`. That breaks
187
+ the single-contract invariant this repo's guards are built on, and it breaks them
188
+ _silently_ — the affected checks depend on identity, not on version strings:
189
+
190
+ - `spec-subschema-parity.test.ts` distinguishes a genuine re-export from a fork by
191
+ **reference identity** of the zod schema object. Two spec copies make every schema a
192
+ distinct object, so a real re-export starts reading as a fork (or a fork slips through,
193
+ depending on which copy each side resolved).
194
+ - `scripts/check-spec-symbol-derivation.mjs` and `spec-symbol-parity.test.ts` use
195
+ `createRequire` to resolve spec's `.d.ts` and run it through the TS checker. With two
196
+ copies installed, _which_ declaration file the checker sees is a function of resolution
197
+ order rather than of intent.
198
+
199
+ The declared ranges were already `^17.0.0-rc.0`, which technically admits rc.1 — the pin
200
+ lived in the lockfile. Raising the remaining ranges to `^17.0.0-rc.1` makes the floor
201
+ explicit and forbids a future install from silently sliding back onto a family member that
202
+ drags rc.0 along with it. The rc.1 family members pin spec at `17.0.0-rc.1` exactly, so the
203
+ graph now converges on one copy by construction, not by luck.
204
+
205
+ No product behaviour changes here. `check:spec-symbols` reconciliation was already
206
+ completed by #3178 and stays green under the unified graph; this changeset is `minor`
207
+ per the repo's fixed-group version policy.
208
+
209
+ ### Patch Changes
210
+
211
+ - Updated dependencies [4ae0ac4]
212
+ - Updated dependencies [696e3c1]
213
+ - Updated dependencies [bca45cc]
214
+ - Updated dependencies [4bf612c]
215
+ - Updated dependencies [335041c]
216
+ - Updated dependencies [b414983]
217
+ - Updated dependencies [256f8cc]
218
+ - Updated dependencies [d9668a7]
219
+ - Updated dependencies [cb82705]
220
+ - Updated dependencies [f572849]
221
+ - Updated dependencies [d3584c6]
222
+ - Updated dependencies [a8ad6c0]
223
+ - Updated dependencies [444457c]
224
+ - Updated dependencies [850033c]
225
+ - Updated dependencies [022e4c3]
226
+ - Updated dependencies [009e25d]
227
+ - Updated dependencies [726b89c]
228
+ - @object-ui/types@17.2.0
229
+ - @object-ui/core@17.2.0
230
+
3
231
  ## 17.1.0
4
232
 
5
233
  ### Minor Changes
package/README.md CHANGED
@@ -179,7 +179,12 @@ import {
179
179
  BulkOperationError, // Bulk operation failures with partial results
180
180
  ConnectionError, // Network/connection errors (503/504)
181
181
  AuthenticationError, // Authentication failures (401/403)
182
- ValidationError, // Data validation errors (400)
182
+ DataApiValidationError, // Data validation errors (400). Its runtime `name` is
183
+ // still 'ValidationError' — that string is the wire
184
+ // discriminator shared with @objectstack/client. The
185
+ // SYMBOL is prefixed because @objectstack/spec/kernel
186
+ // owns `ValidationError` for a { field, message, code? }
187
+ // record (objectui#3160).
183
188
  } from '@object-ui/data-objectstack';
184
189
  ```
185
190
 
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  CloudOperations: () => CloudOperations,
30
30
  ConcurrentUpdateError: () => ConcurrentUpdateError,
31
31
  ConnectionError: () => ConnectionError,
32
+ DataApiValidationError: () => DataApiValidationError,
32
33
  FILTER_OPERATOR_ALIASES: () => FILTER_OPERATOR_ALIASES,
33
34
  IntegrationManager: () => IntegrationManager,
34
35
  MalformedFilterError: () => MalformedFilterError,
@@ -37,7 +38,6 @@ __export(index_exports, {
37
38
  ObjectStackAdapter: () => ObjectStackAdapter,
38
39
  ObjectStackError: () => ObjectStackError,
39
40
  SecurityManager: () => SecurityManager,
40
- ValidationError: () => ValidationError,
41
41
  calculateAutoLayout: () => calculateAutoLayout,
42
42
  classifyAnalyticsFailure: () => classifyAnalyticsFailure,
43
43
  clearSharedDiscoveryCache: () => clearSharedDiscoveryCache,
@@ -76,6 +76,7 @@ function errorCodeIsAnyOf(err, codes) {
76
76
  }
77
77
 
78
78
  // ../core/src/utils/filter-converter.ts
79
+ var import_ui = require("@objectstack/spec/ui");
79
80
  var FilterOperatorError = class extends Error {
80
81
  constructor(message) {
81
82
  super(message);
@@ -933,10 +934,10 @@ var AuthenticationError = class extends ObjectStackError {
933
934
  this.name = "AuthenticationError";
934
935
  }
935
936
  };
936
- var ValidationError = class extends ObjectStackError {
937
+ var DataApiValidationError = class extends ObjectStackError {
937
938
  /**
938
- * Create a new ValidationError
939
- *
939
+ * Create a new DataApiValidationError
940
+ *
940
941
  * @param message - Human-readable error message
941
942
  * @param field - The field that failed validation (optional)
942
943
  * @param validationErrors - Array of validation error details
@@ -987,7 +988,7 @@ function createErrorFromResponse(response, context) {
987
988
  }
988
989
  return new ObjectStackError(message, "NOT_FOUND", 404, details);
989
990
  case 400:
990
- return new ValidationError(message, void 0, response?.data?.errors, details);
991
+ return new DataApiValidationError(message, void 0, response?.data?.errors, details);
991
992
  case 503:
992
993
  return new ConnectionError(message, response?.config?.url, details, 503);
993
994
  case 504:
@@ -1504,7 +1505,7 @@ var FILTER_OPERATOR_ALIASES = {
1504
1505
  before: "<",
1505
1506
  after: ">"
1506
1507
  };
1507
- function normalizeFilterOperator(op) {
1508
+ function normalizeFilterOperator2(op) {
1508
1509
  if (typeof op !== "string") return null;
1509
1510
  const lower = op.toLowerCase();
1510
1511
  return FILTER_OPERATOR_ALIASES[lower] ?? FILTER_OPERATOR_ALIASES[op] ?? op;
@@ -1533,7 +1534,7 @@ function objectFilterEntryToAST(entry) {
1533
1534
  if (!entry || typeof entry !== "object") return null;
1534
1535
  const field = entry.field;
1535
1536
  const rawOp = entry.operator ?? entry.op ?? "=";
1536
- const op = normalizeFilterOperator(rawOp);
1537
+ const op = normalizeFilterOperator2(rawOp);
1537
1538
  if (!field || !op) return null;
1538
1539
  return [String(field), op, entry.value];
1539
1540
  }
@@ -1700,7 +1701,7 @@ function normaliseClientError(error) {
1700
1701
  const message = typeof rec.message === "string" && rec.message.trim() ? rec.message : typeof rec.code === "string" ? rec.code : "";
1701
1702
  return { field, message };
1702
1703
  }).filter((x) => x !== null);
1703
- return new ValidationError(
1704
+ return new DataApiValidationError(
1704
1705
  typeof e.message === "string" ? e.message : "Validation failed",
1705
1706
  validationErrors[0]?.field,
1706
1707
  validationErrors,
@@ -1751,6 +1752,31 @@ function stableStringify(value) {
1751
1752
  const keys = Object.keys(obj).sort();
1752
1753
  return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
1753
1754
  }
1755
+ function sameWireValue(a, b) {
1756
+ if (a === b) return true;
1757
+ const aEmpty = a === null || a === void 0;
1758
+ const bEmpty = b === null || b === void 0;
1759
+ if (aEmpty || bEmpty) return aEmpty && bEmpty;
1760
+ return stableStringify(a) === stableStringify(b);
1761
+ }
1762
+ function withoutNoOpDrops(droppedFields, sent, stored) {
1763
+ if (!sent || !stored || typeof sent !== "object" || typeof stored !== "object") {
1764
+ return droppedFields;
1765
+ }
1766
+ const out = [];
1767
+ for (const e of droppedFields) {
1768
+ const kept = e.fields.filter((f) => {
1769
+ if (!Object.prototype.hasOwnProperty.call(sent, f)) return true;
1770
+ if (!Object.prototype.hasOwnProperty.call(stored, f)) return true;
1771
+ return !sameWireValue(
1772
+ sent[f],
1773
+ stored[f]
1774
+ );
1775
+ });
1776
+ if (kept.length > 0) out.push({ ...e, fields: kept });
1777
+ }
1778
+ return out;
1779
+ }
1754
1780
  var ObjectStackAdapter = class {
1755
1781
  constructor(config) {
1756
1782
  __publicField(this, "client");
@@ -2127,12 +2153,14 @@ var ObjectStackAdapter = class {
2127
2153
  * whose response type predates `droppedFields`: the field is read structurally
2128
2154
  * and validated, so an older client (or a backend that never drops) is a no-op.
2129
2155
  */
2130
- notifyDroppedFields(operation, resource, result, id) {
2156
+ notifyDroppedFields(operation, resource, result, id, sent) {
2131
2157
  const dropped = result?.droppedFields;
2132
2158
  if (!Array.isArray(dropped) || dropped.length === 0) return;
2133
- const droppedFields = dropped.filter(
2159
+ const valid = dropped.filter(
2134
2160
  (e) => !!e && typeof e === "object" && Array.isArray(e.fields) && e.fields.length > 0
2135
2161
  );
2162
+ const stored = result?.record;
2163
+ const droppedFields = withoutNoOpDrops(valid, sent, stored);
2136
2164
  if (droppedFields.length === 0) return;
2137
2165
  this.emitWriteWarning({ operation, resource, ...id !== void 0 ? { id } : {}, droppedFields });
2138
2166
  }
@@ -2151,17 +2179,25 @@ var ObjectStackAdapter = class {
2151
2179
  notifyBatchDroppedFields(operations, payload) {
2152
2180
  const dropped = payload?.droppedFields;
2153
2181
  if (!Array.isArray(dropped) || dropped.length === 0) return;
2182
+ const results = payload?.results;
2154
2183
  for (const entry of dropped) {
2155
2184
  if (!entry || typeof entry !== "object") continue;
2156
2185
  const e = entry;
2157
2186
  if (!Array.isArray(e.fields) || e.fields.length === 0) continue;
2158
2187
  const op = typeof e.index === "number" ? operations[e.index] : void 0;
2188
+ const stored = typeof e.index === "number" && Array.isArray(results) ? results[e.index] : void 0;
2189
+ const [live] = withoutNoOpDrops(
2190
+ [{ object: e.object, fields: e.fields, reason: e.reason }],
2191
+ op?.data,
2192
+ stored
2193
+ );
2194
+ if (!live) continue;
2159
2195
  const operation = (op?.action ?? "create") === "create" ? "create" : "update";
2160
2196
  this.emitWriteWarning({
2161
2197
  operation,
2162
2198
  resource: e.object ?? op?.object ?? "",
2163
2199
  ...op?.id !== void 0 && op?.id !== null ? { id: op.id } : {},
2164
- droppedFields: [{ object: e.object, fields: e.fields, reason: e.reason }]
2200
+ droppedFields: [live]
2165
2201
  });
2166
2202
  }
2167
2203
  }
@@ -2181,7 +2217,13 @@ var ObjectStackAdapter = class {
2181
2217
  try {
2182
2218
  const result = await this.client.data.create(resource, data);
2183
2219
  this.emitMutation({ type: "create", resource, record: { ...result.record } });
2184
- this.notifyDroppedFields("create", resource, result, result.record?.id);
2220
+ this.notifyDroppedFields(
2221
+ "create",
2222
+ resource,
2223
+ result,
2224
+ result.record?.id,
2225
+ data
2226
+ );
2185
2227
  return result.record;
2186
2228
  } catch (err) {
2187
2229
  throw normaliseClientError(err);
@@ -2208,7 +2250,7 @@ var ObjectStackAdapter = class {
2208
2250
  opts?.ifMatch ? { ifMatch: opts.ifMatch } : void 0
2209
2251
  );
2210
2252
  this.emitMutation({ type: "update", resource, id, record: { ...result.record } });
2211
- this.notifyDroppedFields("update", resource, result, id);
2253
+ this.notifyDroppedFields("update", resource, result, id, data);
2212
2254
  return result.record;
2213
2255
  } catch (err) {
2214
2256
  throw normaliseClientError(err);
@@ -3736,6 +3778,7 @@ function createObjectStackAdapter(config) {
3736
3778
  CloudOperations,
3737
3779
  ConcurrentUpdateError,
3738
3780
  ConnectionError,
3781
+ DataApiValidationError,
3739
3782
  FILTER_OPERATOR_ALIASES,
3740
3783
  IntegrationManager,
3741
3784
  MalformedFilterError,
@@ -3744,7 +3787,6 @@ function createObjectStackAdapter(config) {
3744
3787
  ObjectStackAdapter,
3745
3788
  ObjectStackError,
3746
3789
  SecurityManager,
3747
- ValidationError,
3748
3790
  calculateAutoLayout,
3749
3791
  classifyAnalyticsFailure,
3750
3792
  clearSharedDiscoveryCache,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { ObjectStackClient } from '@objectstack/client';
2
+ import { DroppedFieldsEvent } from '@objectstack/spec/data';
3
+ export { DroppedFieldsEvent } from '@objectstack/spec/data';
2
4
  import { DataSource, QueryParams, QueryResult, GlobalSearchResult, DataSourceMutationEvent, BatchTransactionOperation, ImportRequestOptions, ImportRecordsResult, CreateImportJobResult, ImportJobProgressInfo, ImportJobResultsInfo, ListImportJobsOptions, ImportJobSummaryInfo, ImportJobUndoResult, ExportDownloadRequest, FileUploadResult } from '@object-ui/types';
3
5
  export { FileUploadResult } from '@object-ui/types';
4
6
 
@@ -95,16 +97,28 @@ declare class AuthenticationError extends ObjectStackError {
95
97
  constructor(message?: string, details?: Record<string, unknown>, statusCode?: number);
96
98
  }
97
99
  /**
98
- * Error thrown when data validation fails
100
+ * Error thrown when the ObjectStack data API rejects a write as invalid.
101
+ *
102
+ * NOT the spec's `ValidationError` (`@objectstack/spec/kernel`), whose name this
103
+ * class wore until objectui#3160 (objectstack#4115 ledger batch 6). That one is
104
+ * a plain DATA SHAPE — `{ field, message, code? }`, one entry in a plugin
105
+ * manifest's validation report — and `@object-ui/types` re-exports it under that
106
+ * name. This is a runtime `Error` subclass carrying an HTTP status plus a list
107
+ * of such entries, so the two are not even the same KIND of thing.
108
+ *
109
+ * The name follows the convention registered on objectstack#4115 for this
110
+ * family — `<what was validated>Validation<Error|Result>`. `@object-ui/core`
111
+ * took `SchemaNodeValidationError` for its SDUI-tree walk; this one belongs to
112
+ * the data API.
99
113
  */
100
- declare class ValidationError extends ObjectStackError {
114
+ declare class DataApiValidationError extends ObjectStackError {
101
115
  field?: string | undefined;
102
116
  validationErrors?: Array<{
103
117
  field: string;
104
118
  message: string;
105
119
  }> | undefined;
106
120
  /**
107
- * Create a new ValidationError
121
+ * Create a new DataApiValidationError
108
122
  *
109
123
  * @param message - Human-readable error message
110
124
  * @param field - The field that failed validation (optional)
@@ -148,9 +162,18 @@ declare function isErrorType<T extends ObjectStackError>(error: unknown, errorCl
148
162
  * LICENSE file in the root directory of this source tree.
149
163
  */
150
164
  /**
151
- * Cache statistics for monitoring
165
+ * Statistics reported by {@link MetadataCache.getStats} for monitoring.
166
+ *
167
+ * NOT the spec's `CacheStats` (`@objectstack/spec/contracts`), whose name this
168
+ * interface wore until objectui#3160 (objectstack#4115 ledger batch 6). That one
169
+ * describes the platform's `ICacheService` — a server-side KV cache measured by
170
+ * `keyCount` and `memoryUsage`. This one describes the browser-side LRU in front
171
+ * of `/api/v1/meta/*`: it is bounded (`size`/`maxSize`), it evicts, it coalesces
172
+ * concurrent fetches onto one in-flight promise, and it reports a `hitRate`.
173
+ * Neither type has a key the other has, so this is a name collision, not a
174
+ * dialect — deriving would have replaced every field.
152
175
  */
153
- interface CacheStats {
176
+ interface MetadataCacheStats {
154
177
  size: number;
155
178
  maxSize: number;
156
179
  hits: number;
@@ -563,7 +586,21 @@ interface MetadataDraftHeader {
563
586
  updatedAt: string | null;
564
587
  updatedBy: string | null;
565
588
  }
566
- interface MetadataSaveOptions {
589
+ /**
590
+ * Options for {@link MetadataClient.save} — a WRITE OVER HTTP to
591
+ * `/api/v1/meta/:type/:name`.
592
+ *
593
+ * NOT the spec's `MetadataSaveOptions` (`@objectstack/spec/system` and
594
+ * `/kernel`), whose name this interface wore until objectui#3160
595
+ * (objectstack#4115 ledger batch 6). Both spec copies describe writing a
596
+ * metadata item to a FILE — `format: json|yaml|ts`, `path`, `indent`,
597
+ * `prettify`, `sortKeys`, `backup`, `atomic`, `loader`. Not one of those keys
598
+ * exists here, and not one of these exists there: this is the REST client's
599
+ * request envelope — optimistic concurrency (`ifMatch` → `If-Match`), actor
600
+ * attribution, the destructive-change override, the ADR-0033 draft/publish
601
+ * mode, and the owning package. Same words, different layer.
602
+ */
603
+ interface MetadataClientSaveOptions {
567
604
  /**
568
605
  * Optimistic concurrency token (the `checksum` returned by the last
569
606
  * read). When present, sent as the `If-Match` header so concurrent
@@ -608,7 +645,7 @@ interface MetadataGetOptions {
608
645
  */
609
646
  packageId?: string;
610
647
  }
611
- interface MetadataDeleteOptions extends MetadataSaveOptions {
648
+ interface MetadataDeleteOptions extends MetadataClientSaveOptions {
612
649
  /**
613
650
  * Target state. `'draft'` discards the pending draft (keeps the
614
651
  * published overlay intact). Omit to reset the active overlay back
@@ -847,7 +884,7 @@ declare class MetadataClient {
847
884
  * envelopes; we send bare for consistency. Pass `mode: 'draft'` to
848
885
  * stage the change without publishing (Studio's "Save" button).
849
886
  */
850
- save<T = unknown>(type: string, name: string, item: unknown, options?: MetadataSaveOptions): Promise<T>;
887
+ save<T = unknown>(type: string, name: string, item: unknown, options?: MetadataClientSaveOptions): Promise<T>;
851
888
  /**
852
889
  * Publish a single pending draft BY REFERENCE — promotes the draft row for
853
890
  * `(type, name)` into the active overlay and drops the draft. Works for ANY
@@ -957,7 +994,20 @@ declare class MetadataClient {
957
994
  * Security module integration for @objectstack/spec v3.0.0
958
995
  * Provides advanced security policies: CSP config, audit logging, data masking.
959
996
  */
960
- interface SecurityPolicy {
997
+ /**
998
+ * Configuration for {@link SecurityManager} — this adapter's browser-side
999
+ * security posture: the CSP header it generates, the in-memory audit log it
1000
+ * keeps, and the field-masking rules it applies before a record is rendered.
1001
+ *
1002
+ * NOT the spec's `SecurityPolicy` (`@objectstack/spec/kernel`), whose name this
1003
+ * interface wore until objectui#3160 (objectstack#4115 ledger batch 6). That one
1004
+ * is the PACKAGE SUPPLY-CHAIN policy — `{ id, name, autoScan, thresholds,
1005
+ * allowedLicenses, prohibitedLicenses, codeSigning, sandbox }` — the rules a
1006
+ * marketplace applies when scanning a plugin before install. It shares no key
1007
+ * with this one, so there was nothing to derive; the collision is the word
1008
+ * "security", not the concept.
1009
+ */
1010
+ interface SecurityManagerPolicy {
961
1011
  /** Content Security Policy configuration */
962
1012
  csp?: CSPConfig;
963
1013
  /** Audit logging configuration */
@@ -1031,7 +1081,7 @@ interface AuditLogEntry {
1031
1081
  declare class SecurityManager {
1032
1082
  private policy;
1033
1083
  private auditLog;
1034
- constructor(policy?: SecurityPolicy);
1084
+ constructor(policy?: SecurityManagerPolicy);
1035
1085
  /**
1036
1086
  * Generate a CSP header string from the configuration.
1037
1087
  */
@@ -1055,11 +1105,11 @@ declare class SecurityManager {
1055
1105
  /**
1056
1106
  * Update the security policy.
1057
1107
  */
1058
- updatePolicy(policy: Partial<SecurityPolicy>): void;
1108
+ updatePolicy(policy: Partial<SecurityManagerPolicy>): void;
1059
1109
  /**
1060
1110
  * Get current security policy.
1061
1111
  */
1062
- getPolicy(): SecurityPolicy;
1112
+ getPolicy(): SecurityManagerPolicy;
1063
1113
  }
1064
1114
 
1065
1115
  /**
@@ -1379,7 +1429,7 @@ declare function isConcurrentUpdateError(error: unknown): error is ConcurrentUpd
1379
1429
  *
1380
1430
  * Two shapes are recognised:
1381
1431
  * - `409` + `CONCURRENT_UPDATE` → {@link ConcurrentUpdateError};
1382
- * - `400` + `VALIDATION_FAILED` → {@link ValidationError}, carrying the
1432
+ * - `400` + `VALIDATION_FAILED` → {@link DataApiValidationError}, carrying the
1383
1433
  * server's per-field entries so a form can mark the offending inputs
1384
1434
  * instead of showing one undirected toast.
1385
1435
  */
@@ -1414,19 +1464,7 @@ type ConnectionStateListener = (event: ConnectionStateEvent) => void;
1414
1464
  * Event listener type for batch operation progress
1415
1465
  */
1416
1466
  type BatchProgressListener = (event: BatchProgressEvent) => void;
1417
- /**
1418
- * One server-reported write-strip: caller-supplied fields the backend LEGALLY
1419
- * removed from a write before persisting (a non-system caller cannot seed a
1420
- * `readonly` field, a `readonlyWhen` predicate locked it, etc.). Mirrors the
1421
- * framework `DroppedFieldsEvent` (spec `DroppedFieldsEventSchema`) structurally
1422
- * so we don't pin a client type version — `reason` is kept as a widened string
1423
- * for forward-compatibility with reasons added server-side.
1424
- */
1425
- interface DroppedFieldsEvent {
1426
- object: string;
1427
- fields: string[];
1428
- reason: string;
1429
- }
1467
+
1430
1468
  /**
1431
1469
  * Emitted after a create/update whose response carried `droppedFields`
1432
1470
  * (framework #3431/#3455). The write SUCCEEDED — this is a warning that some
@@ -2085,7 +2123,7 @@ declare class ObjectStackAdapter<T = unknown> implements DataSource<T> {
2085
2123
  /**
2086
2124
  * Get cache statistics for monitoring performance.
2087
2125
  */
2088
- getCacheStats(): CacheStats;
2126
+ getCacheStats(): MetadataCacheStats;
2089
2127
  /**
2090
2128
  * Invalidate metadata cache entries.
2091
2129
  *
@@ -2173,4 +2211,4 @@ declare function createObjectStackAdapter<T = unknown>(config: {
2173
2211
  reconnectDelay?: number;
2174
2212
  }): DataSource<T>;
2175
2213
 
2176
- export { AnalyticsNotInstalledError, AnalyticsQueryRejectedError, type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CacheStats, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, type DataMaskingConfig, type DataMaskingRule, type DroppedFieldsEvent, type EmailIntegrationConfig, FILTER_OPERATOR_ALIASES, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MalformedFilterError, type MetadataAuditEntry, type MetadataAuditResponse, MetadataClient, type MetadataClientConfig, type MetadataDeleteOptions, type MetadataDiagnostics, type MetadataDiagnosticsEntry, type MetadataDiagnosticsOptions, type MetadataDiagnosticsSummary, type MetadataDraftHeader, type MetadataError, type MetadataGetOptions, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataSaveOptions, type MetadataValidationIssue, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, ValidationError, type WebhookIntegrationConfig, type WriteWarningEvent, type WriteWarningListener, calculateAutoLayout, classifyAnalyticsFailure, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isAnalyticsNotInstalledError, isConcurrentUpdateError, isErrorType, isMalformedFilterError, isObjectStackError, normaliseClientError, readTransactionalBatchCapability, serializeOrderBy, snapToGrid, validatePluginContract };
2214
+ export { AnalyticsNotInstalledError, AnalyticsQueryRejectedError, type AuditEventType, type AuditLogConfig, type AuditLogEntry, AuthenticationError, type BatchProgressEvent, type BatchProgressListener, BulkOperationError, type CSPConfig, type CloudDeploymentConfig, type CloudHostingConfig, type CloudMarketplaceEntry, CloudOperations, ConcurrentUpdateError, ConnectionError, type ConnectionState, type ConnectionStateEvent, type ConnectionStateListener, type ContractValidationError, type ContractValidationResult, DataApiValidationError, type DataMaskingConfig, type DataMaskingRule, type EmailIntegrationConfig, FILTER_OPERATOR_ALIASES, type IntegrationConfig, IntegrationManager, type IntegrationProvider, type IntegrationTrigger, MalformedFilterError, type MetadataAuditEntry, type MetadataAuditResponse, type MetadataCacheStats, MetadataClient, type MetadataClientConfig, type MetadataClientSaveOptions, type MetadataDeleteOptions, type MetadataDiagnostics, type MetadataDiagnosticsEntry, type MetadataDiagnosticsOptions, type MetadataDiagnosticsSummary, type MetadataDraftHeader, type MetadataError, type MetadataGetOptions, type MetadataHistoryOptions, type MetadataLayered, type MetadataListOptions, MetadataNotFoundError, type MetadataReference, type MetadataValidationIssue, ObjectStackAdapter, ObjectStackError, type ObjectStackUserStateAdapterOptions, type PluginAPIContract, type PluginContract, type PluginExport, SecurityManager, type SecurityManagerPolicy, type SlackIntegrationConfig, type StudioCanvasConfig, type StudioColorPalette, type StudioPropertyEditor, type StudioShadowPreset, type StudioThemeBuilderConfig, type StudioTypographyPreset, type UserDataAdapter, type WebhookIntegrationConfig, type WriteWarningEvent, type WriteWarningListener, calculateAutoLayout, classifyAnalyticsFailure, clearSharedDiscoveryCache, createDefaultCanvasConfig, createErrorFromResponse, createObjectStackAdapter, createObjectStackUserStateAdapter, generateContractManifest, getSharedDiscovery, is404Error, isAnalyticsNotInstalledError, isConcurrentUpdateError, isErrorType, isMalformedFilterError, isObjectStackError, normaliseClientError, readTransactionalBatchCapability, serializeOrderBy, snapToGrid, validatePluginContract };