cedar-embeddable-editor 2.0.23 → 2.0.24

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
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.24] - 2026-10-18
9
+
10
+ Aligns with `cedar-model-typescript-library@1.0.20`.
11
+
12
+ - Keeps exact numeric bounds and values through editing and snapshots, checks pattern constraints in bounded workers without discarding answers, holds identifiers and character limits to the shared text policies, separates warnings that do not block saving from errors that do, recovers drafts including unfinished input, and keeps element identities through save acknowledgements.
13
+
8
14
  ## [2.0.23] - 2026-10-08
9
15
 
10
16
  Aligns with `cedar-model-typescript-library@1.0.19`.
package/README.md CHANGED
@@ -119,6 +119,23 @@ Read the record back from `currentMetadata` as CEDAR JSON-LD, or from
119
119
  `currentMetadataYaml` as YAML. The CEE neither submits nor stores it. The host
120
120
  decides when and where a record is saved.
121
121
 
122
+ For recovery across reloads, `captureDraft()` returns a JSON-serializable recovery document
123
+ containing the template, accepted metadata and unfinished field input. This is **not** a
124
+ server-saveable artifact. A host can give it to `restoreDraft(draft)` on a fresh element;
125
+ the method returns `false` without consuming the artifact inputs if the format, version or
126
+ input addresses cannot be restored. Restored input participates in ordinary validation.
127
+ The host owns storage, account and deployment scoping, retention and fresh permission/revision
128
+ checks; restoring a draft grants no write permission. Configure the fresh element normally.
129
+
130
+ For repository saves, call `captureSave()` immediately before submitting its `metadata`.
131
+ If `needsElementIds` is true, read the stored instance after a successful write and verify
132
+ that its ETag equals the write's returned ETag. Pass that document to the snapshot's
133
+ `acknowledge(stored)` function before permitting another save. This adopts assigned element
134
+ IDs without replacing the form, losing newer edits, or confusing reordered occurrences.
135
+ The returned metadata is the submitted form with its assigned IDs, suitable for the host's
136
+ dirty baseline. If readback or acknowledgement fails, retain the draft and block further
137
+ writes until recovery; retrying with unidentified elements can replace their identities.
138
+
122
139
  [Your First Embedded Editor](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/first-editor/)
123
140
  takes the same page apart step by step, and
124
141
  [Embedding in a Framework](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/frameworks/)
@@ -140,16 +157,40 @@ report. Ordinary metadata editing leaves the option off.
140
157
  Read `dataQualityReport` for the whole instance, including nested and off-screen
141
158
  occurrences. Each problem has a code, `severity` (`warning` or `error`), a field
142
159
  `path` and occurrence indices. Pass a field problem to `reveal(problem)` to reach it.
143
-
144
- Missing required answers, insufficient occurrences and unnamed attribute rows are
145
- warnings. Invalid values, malformed incoming data and unfinished edits are errors.
146
- Either makes `isValid` false; the host decides whether saving is allowed. A required
160
+ Use `displayMessage` for the localized user-facing explanation; `message` retains
161
+ the technical diagnostic for logs or a separate details disclosure. Older component
162
+ bundles may omit `displayMessage`.
163
+
164
+ Each problem also carries a shared `category` and `blocksSave` decision. Structural defects
165
+ (including malformed typed values and unnamed attributes) block instance saves. Well-formed
166
+ values outside declared constraints and incomplete answers are quality warnings and remain
167
+ saveable. Use `canSave` for the instance save gate and `isValid` for overall quality;
168
+ `structurallyValid` reports the representation separately. A required
147
169
  field must be answered in every existing containing element. A repeating field
148
170
  needs at least one answer within each such element.
149
171
 
150
172
  The report includes unfinished date/time and attribute-name edits, and `change`
151
173
  fires when metadata **or the report** changes. Invalid imported field IRIs and
152
174
  well-shaped numeric, temporal and IRI defaults remain available for correction.
175
+ Patterns run in a bounded worker, with the same no-flags, whole-value semantics as Java validation.
176
+ While a check is running, `dataQualityReport.pendingValidation` is `true`, `isValid` is `false`,
177
+ and no provisional pattern error is displayed. Listen for the composed `validationChange` event
178
+ (the detail is the updated report) to refresh a host save gate without treating completion as an
179
+ instance edit. CEF's `valueChange` detail carries the same optional `pendingValidation` flag
180
+ and announces completion even when the completed result remains invalid. A timeout, resource limit or unavailable worker is a `regexEvaluation` verification finding;
181
+ `canSave` remains false while checks are pending. Worker execution needs
182
+ `worker-src blob:` in the host CSP. There is no synchronous fallback.
183
+
184
+ Populated controlled terms and external-authority values are checked on load, default seeding
185
+ and edits using the configured services. `semanticChecks` records `passed`, `failed`,
186
+ `notChecked` or `unavailable` for each occurrence. Membership uses the exact IRI and complete
187
+ version-aware constraints. Missing configuration and service failures never count as success;
188
+ those findings affect quality but do not prohibit saving a structurally sound instance.
189
+
190
+ A template pattern change preserves existing preview answers. If a retained answer fails the new
191
+ pattern, the completed report identifies it; a failed or unfinished check never clears the answer
192
+ or removes its containing section. Replacing or destroying the editor cancels obsolete checks.
193
+
153
194
  Terminology membership and server-side validation remain the host's responsibility.
154
195
 
155
196
  ## Embedding a Single Field
@@ -242,7 +283,8 @@ assignment does not change the editor. Getters and events return detached values
242
283
 
243
284
  A numeric value has the shape `{ kind: 'number', value: number | string }`.
244
285
  Ordinary numbers remain numbers. When converting to a JavaScript number would lose
245
- significant digits or exceed its range, CEF returns the exact numeric string instead:
286
+ significant digits, exceed its range, or produce an integer outside its safe range,
287
+ CEF returns the exact numeric string instead:
246
288
  `9007199254740993` and `0.1234567890123456789` retain every digit. Both forms may be
247
289
  assigned back through `value`. Constraint validity remains a separate result.
248
290
 
@@ -4,6 +4,6 @@
4
4
  "main.js",
5
5
  "polyfills.js"
6
6
  ],
7
- "bytes": 2237021,
8
- "sha256": "ee8739e16f93e420373218a88e437afbce27e769156d31b26100c5028e5c96a3"
7
+ "bytes": 2317622,
8
+ "sha256": "e27a9e5713212ddc05530db5553b60c285e6946dd2548c17ecacc201b347124c"
9
9
  }
@@ -4,6 +4,6 @@
4
4
  "main.js",
5
5
  "polyfills.js"
6
6
  ],
7
- "bytes": 2359327,
8
- "sha256": "97bfdc29582a5fab312ed578123ae3a8a10440c7bcb562f0e1ba263da181cfd3"
7
+ "bytes": 2439928,
8
+ "sha256": "e0b5d58c4d00f334af5b1db846133e82f99f9582913a4be118c043e3964b3f0a"
9
9
  }
@@ -128,10 +128,45 @@ export interface CeeConfig {
128
128
  languageMapPathPrefix?: string;
129
129
  }
130
130
  /** A JSON-serialisable value, as it appears in a CEDAR artifact. */
131
- export type CeeJsonValue = string | number | boolean | null | CeeJsonObject | CeeJsonValue[];
131
+ /** Exact numeric atoms returned by the model library's raw-source readers. Use its JSON writer for serialization. */
132
+ export interface CeeExactNumber {
133
+ readonly cedarExactDecimal: true;
134
+ toString(): string;
135
+ toJSON(): unknown;
136
+ }
137
+ export type CeeJsonValue = string | number | CeeExactNumber | boolean | null | CeeJsonObject | CeeJsonValue[];
132
138
  export interface CeeJsonObject {
133
139
  [key: string]: CeeJsonValue;
134
140
  }
141
+ /** Recovery data, not a server-saveable artifact. Hosts own storage and access checks. */
142
+ export interface CeeRecoveryDraft {
143
+ format: 'cedar-cee-draft';
144
+ version: 1;
145
+ template: CeeJsonObject;
146
+ metadata: CeeJsonObject;
147
+ drafts: Array<{
148
+ path: Array<string | number>;
149
+ draft: {
150
+ code: string;
151
+ message: string;
152
+ value: unknown;
153
+ state: unknown;
154
+ };
155
+ }>;
156
+ }
157
+ /** A submitted form and an occurrence-safe acknowledgement of its repository identities. */
158
+ export interface CeeSaveSnapshot {
159
+ readonly metadata: CeeJsonObject;
160
+ readonly needsElementIds: boolean;
161
+ /**
162
+ * Supply the full stored instance from the exact revision acknowledged by the write.
163
+ * Copies only element identifiers into surviving submitted occurrences, preserving later
164
+ * edits and reordering. Returns the submitted metadata with those IDs for a dirty baseline.
165
+ * Throws without changing the form if the snapshot or identities cannot be reconciled.
166
+ * One successful acknowledgement per snapshot; no change event or form remount.
167
+ */
168
+ readonly acknowledge: (stored: CeeJsonObject) => CeeJsonObject;
169
+ }
135
170
  /**
136
171
  * A template and an instance of it, supplied together.
137
172
  *
@@ -157,12 +192,17 @@ export interface CeeTemplateAndInstance {
157
192
  * TypeScript host could not read either without a cast.
158
193
  */
159
194
  export interface CeeValidationProblem {
160
- /** Missing answers are warnings; invalid values and unfinished edits are errors. Both affect isValid. */
195
+ /** Shared rule category and instance save decision. Optional for older producers. */
196
+ category?: 'structural' | 'constraint' | 'completeness' | 'verification';
197
+ blocksSave?: boolean;
198
+ /** Structural defects are errors; value constraints and incomplete verification are warnings. */
161
199
  severity: 'warning' | 'error';
162
200
  /** Machine-readable code, e.g. `numberType` or `temporalGranularity`. */
163
201
  code: string;
164
202
  /** Path to the offending value, outermost first. */
165
203
  path: string[];
204
+ /** Exact RFC 6901 location, including atom properties, when available. */
205
+ location?: string;
166
206
  /**
167
207
  * The entry taken at each repeating field or element along `path`, outermost first.
168
208
  *
@@ -177,8 +217,10 @@ export interface CeeValidationProblem {
177
217
  field: string;
178
218
  /** The field's declared `_ui.inputType`, or null where it declares none. */
179
219
  inputType: string | null;
180
- /** Human-readable explanation. */
220
+ /** Technical diagnostic, retained in English for troubleshooting. */
181
221
  message: string;
222
+ /** Localized user-facing explanation. `message` retains the technical diagnostic. */
223
+ displayMessage?: string;
182
224
  /** The value that failed, when there is one. */
183
225
  value?: unknown;
184
226
  }
@@ -210,11 +252,23 @@ export interface CeeRevealOptions {
210
252
  /**
211
253
  * What CEE thinks of the instance currently in the form.
212
254
  *
213
- * Read through `dataQualityReport`. These four members are the whole object: it
214
- * carried three of CEE's internal working views as well, and the interface was a
215
- * subset of what a host actually received.
255
+ * Read through `dataQualityReport`. The report contains validation facts and
256
+ * counts, without CEE's internal model or working views.
216
257
  */
217
258
  export interface CeeDataQualityReport {
259
+ /** Separate structural/save facts from overall answer quality. */
260
+ structurallyValid?: boolean;
261
+ canSave?: boolean;
262
+ semanticChecks?: Array<{
263
+ path: string[];
264
+ occurrences: number[];
265
+ iri: string;
266
+ status: 'passed' | 'failed' | 'notChecked' | 'unavailable';
267
+ code: string;
268
+ message: string;
269
+ }>;
270
+ /** Worker validation is unresolved; isValid remains false until it settles. */
271
+ pendingValidation?: boolean;
218
272
  /**
219
273
  * How many required fields the template declares.
220
274
  *
@@ -237,7 +291,7 @@ export interface CeeDataQualityReport {
237
291
  * unanswered requirement. The two counters count declarations, not occurrences.
238
292
  */
239
293
  problems: CeeValidationProblem[];
240
- /** True when every required field is filled and no constraint is violated. */
294
+ /** True when required answers, local constraints and applicable semantic checks all pass. */
241
295
  isValid: boolean;
242
296
  }
243
297
  /** The model operation that produced a host-visible instance change. */
@@ -310,6 +364,9 @@ export interface CeeEventHandler {
310
364
  * handler and meaningless for the three read-only getters below.
311
365
  */
312
366
  export interface CedarEmbeddableEditorElement extends HTMLElement {
367
+ /** Validity changed after asynchronous checks; the instance itself did not change. */
368
+ addEventListener(type: 'validationChange', listener: ((this: CedarEmbeddableEditorElement, event: CustomEvent<CeeDataQualityReport>) => unknown) | null, options?: boolean | AddEventListenerOptions): void;
369
+ removeEventListener(type: 'validationChange', listener: ((this: CedarEmbeddableEditorElement, event: CustomEvent<CeeDataQualityReport>) => unknown) | null, options?: boolean | EventListenerOptions): void;
313
370
  /** Typed host mutation event; the inherited overloads still handle every other DOM event. */
314
371
  addEventListener(type: 'change', listener: ((this: CedarEmbeddableEditorElement, event: CustomEvent<CeeChangeDetail>) => unknown) | null, options?: boolean | AddEventListenerOptions): void;
315
372
  addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, event: HTMLElementEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
@@ -328,10 +385,13 @@ export interface CedarEmbeddableEditorElement extends HTMLElement {
328
385
  * and CEE reads a template through class identity.
329
386
  *
330
387
  * Assignable more than once while no instance has been supplied: each one replaces the
331
- * form, building a fresh context, so nothing of the previous template survives. Once an
332
- * instance is loaded the template is fixed, and a further assignment is reported and
333
- * ignored — the answers in front of a person were recorded against the template that
334
- * would be taken away.
388
+ * form, building a fresh context. When the new template keeps the previous one's `@id`,
389
+ * so that it is an edit of it, the new form keeps as much of what the reader entered as
390
+ * it will take without showing an error, and drops the rest silently. Each pager stays
391
+ * on the entry the reader was looking at. A template with another `@id` starts the
392
+ * reader on an empty form. Once an instance is loaded the
393
+ * template is fixed, and a further assignment is reported and ignored — the answers in
394
+ * front of a person were recorded against the template that would be taken away.
335
395
  */
336
396
  templateObject: CeeJsonObject;
337
397
  /**
@@ -371,6 +431,12 @@ export interface CedarEmbeddableEditorElement extends HTMLElement {
371
431
  * goes to the event handler's `error`.
372
432
  */
373
433
  readonly currentMetadata: CeeJsonObject;
434
+ /** Capture immediately before saving. Null while no readable form is loaded. */
435
+ readonly captureSave: () => CeeSaveSnapshot | null;
436
+ /** Captures accepted values and unfinished input, independently of validity. */
437
+ readonly captureDraft: () => CeeRecoveryDraft | null;
438
+ /** Restore into a fresh element; rejects incompatible or malformed data atomically. */
439
+ readonly restoreDraft: (draft: CeeRecoveryDraft) => boolean;
374
440
  /** The instance as CEDAR YAML. Read-only. */
375
441
  readonly currentMetadataYaml: string;
376
442
  /** What CEE thinks of the instance. Read-only. */
@@ -440,6 +506,13 @@ export type CedarEmbeddableFieldValue = {
440
506
  };
441
507
  /** Detail carried by the `cedar-embeddable-field` element's `valueChange` event. */
442
508
  export interface CedarEmbeddableFieldChangeDetail {
509
+ /** Local structure and semantic coverage, separate from default-value validity. */
510
+ structurallyValid?: boolean;
511
+ semanticChecks?: CeeDataQualityReport['semanticChecks'];
512
+ /** Validation facts accompanying a semantic check, for default-value consumers. */
513
+ problems?: CeeValidationProblem[];
514
+ /** Present while bounded pattern checks are unresolved; valid stays false. */
515
+ pendingValidation?: boolean;
443
516
  /** What the field now holds. */
444
517
  value: CedarEmbeddableFieldValue;
445
518
  /** Whether it satisfies the constraints the field declares. */