@effected/schemastore 0.4.0 → 0.6.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/index.d.ts CHANGED
@@ -1,73 +1,4 @@
1
1
  import { Context, Effect, FileSystem, Layer, Option, Order, Path, Result, Schema } from "effect";
2
- //#region src/AnnotationCarriers.d.ts
3
- declare const CarrierDepthExceededError_base: Schema.Class<CarrierDepthExceededError, Schema.TaggedStruct<"CarrierDepthExceededError", {
4
- /** JSON pointer (in the lowered document's coordinates) where the cap was hit. */
5
- readonly path: Schema.String;
6
- /** The nesting cap that was exceeded. */
7
- readonly maxDepth: Schema.Number;
8
- }>, import("effect/Cause").YieldableError>;
9
- /**
10
- * Indicates that the carrier re-graft walk nested past the package's
11
- * hardening cap (256 levels), which also intercepts cyclic inputs before
12
- * they can recurse forever.
13
- *
14
- * Raised by {@link AnnotationCarriers.carry}.
15
- *
16
- * @public
17
- */
18
- declare class CarrierDepthExceededError extends CarrierDepthExceededError_base {
19
- get message(): string;
20
- }
21
- /**
22
- * Re-grafts the declared non-standard keyword families
23
- * ({@link KeywordFamilies}) from a Draft 2020-12 schema node onto its
24
- * lowered Draft-07 counterpart.
25
- *
26
- * Why this exists: annotation keys admitted into the Draft 2020-12 document
27
- * (core's `includeAnnotationKey`) are **dropped by core's Draft-07 lowering**,
28
- * whose keyword walk copies a fixed subset — verified against the installed
29
- * beta. Carrying `x-taplo`, `x-tombi-*`, `x-intellij-*` or the vscode set
30
- * into an emitted SchemaStore document therefore requires this post-lowering
31
- * step; it cannot ride `ToJsonSchemaOptions` alone.
32
- *
33
- * The walk mirrors the lowering's own structural rules, so every carrier
34
- * lands on the node the annotation was attached to — including the one
35
- * coordinate move the lowering makes (2020-12 `prefixItems[i]` → Draft-07
36
- * `items[i]`, trailing `items` → `additionalItems`). Only declared-family
37
- * keys are copied; nothing else about the target changes.
38
- *
39
- * `StoreDocument.fromSchema` applies this automatically to the root schema
40
- * and every `$defs` pool entry — annotate a schema node
41
- * (`Schema.String.annotate({ "x-taplo": { hidden: true } })`) and the key
42
- * appears in the built document. Call this directly only when driving core's
43
- * pipeline yourself.
44
- *
45
- * Know the boundary (core behavior, probed at the installed beta): an
46
- * annotation must sit on the schema **definition** node. Annotating a
47
- * hoisted (identifier-carrying) schema at its *usage* site — e.g.
48
- * `Person.annotate({...})` inside a struct field — reaches neither the
49
- * `$ref` node nor the pool entry, even in the 2020-12 document, so there is
50
- * nothing to carry.
51
- *
52
- * @public
53
- */
54
- declare class AnnotationCarriers {
55
- private constructor();
56
- /**
57
- * Grafts declared-family keys from `source` (a Draft 2020-12 schema
58
- * node) onto `target` (its lowered Draft-07 counterpart), returning a
59
- * new node. Pure and synchronous — the primitive form;
60
- * {@link AnnotationCarriers.carry} is the same walk behind a span.
61
- */
62
- static carryResult(source: unknown, target: unknown): Result.Result<unknown, CarrierDepthExceededError>;
63
- /**
64
- * Effect form of {@link AnnotationCarriers.carryResult}, adding only the
65
- * `AnnotationCarriers.carry` span. Defined in terms of the `Result`
66
- * primitive — synchronous callers can use that variant directly.
67
- */
68
- static readonly carry: (source: unknown, target: unknown) => Effect.Effect<unknown, CarrierDepthExceededError, never>;
69
- }
70
- //#endregion
71
2
  //#region src/CanonicalJson.d.ts
72
3
  declare const NonJsonValueError_base: Schema.Class<NonJsonValueError, Schema.TaggedStruct<"NonJsonValueError", {
73
4
  /** JSON pointer to the offending value (`""` is the document root). */
@@ -87,7 +18,7 @@ declare const NonJsonValueError_base: Schema.Class<NonJsonValueError, Schema.Tag
87
18
  *
88
19
  * @public
89
20
  */
90
- declare class NonJsonValueError extends NonJsonValueError_base {
21
+ export declare class NonJsonValueError extends NonJsonValueError_base {
91
22
  get message(): string;
92
23
  }
93
24
  declare const JsonDepthExceededError_base: Schema.Class<JsonDepthExceededError, Schema.TaggedStruct<"JsonDepthExceededError", {
@@ -105,7 +36,7 @@ declare const JsonDepthExceededError_base: Schema.Class<JsonDepthExceededError,
105
36
  *
106
37
  * @public
107
38
  */
108
- declare class JsonDepthExceededError extends JsonDepthExceededError_base {
39
+ export declare class JsonDepthExceededError extends JsonDepthExceededError_base {
109
40
  get message(): string;
110
41
  }
111
42
  /**
@@ -149,7 +80,7 @@ interface CanonicalJsonOptions {
149
80
  *
150
81
  * @public
151
82
  */
152
- declare class CanonicalJson {
83
+ export declare class CanonicalJson {
153
84
  private constructor();
154
85
  /**
155
86
  * Serializes `value` to canonical JSON text. Pure and synchronous — the
@@ -165,201 +96,6 @@ declare class CanonicalJson {
165
96
  static readonly serialize: (value: unknown, options?: CanonicalJsonOptions | undefined) => Effect.Effect<string, CanonicalJsonError, never>;
166
97
  }
167
98
  //#endregion
168
- //#region src/SchemaVersioning.d.ts
169
- declare const InvalidSchemaVersionError_base: Schema.Class<InvalidSchemaVersionError, Schema.TaggedStruct<"InvalidSchemaVersionError", {
170
- /** The raw input string that failed to parse. */
171
- readonly input: Schema.String;
172
- }>, import("effect/Cause").YieldableError>;
173
- /**
174
- * Indicates that a string is not a valid SchemaStore version label.
175
- *
176
- * Raised by {@link SchemaVersioning.parse}.
177
- *
178
- * @public
179
- */
180
- declare class InvalidSchemaVersionError extends InvalidSchemaVersionError_base {
181
- get message(): string;
182
- }
183
- /**
184
- * A schema version label: a branded string holding a **full three-component
185
- * SemVer** — `major.minor.patch` with an optional prerelease, validated by
186
- * `@effected/semver` itself. Build metadata is rejected (see below).
187
- *
188
- * `1.2` and `1` are NOT accepted, though SchemaStore's own corpus uses such
189
- * labels: requiring all three components makes a label unambiguous to split
190
- * back out of `<name>-<version>.json` or its URL, which is what consumers
191
- * do with it. The file-name convention around the label stays SchemaStore's.
192
- *
193
- * The label round-trips verbatim into file names and catalog `versions`
194
- * keys; ordering parses it directly (see {@link SchemaVersioning.Order}).
195
- *
196
- * @public
197
- */
198
- declare const SchemaVersion: Schema.brand<Schema.String, "SchemaVersion">;
199
- /**
200
- * The type of a validated SchemaStore version label.
201
- *
202
- * @public
203
- */
204
- type SchemaVersion = typeof SchemaVersion.Type;
205
- /**
206
- * The `url`/`versions` half of a catalog entry, as assembled by
207
- * {@link SchemaVersioning.catalogUrls}.
208
- *
209
- * @public
210
- */
211
- interface CatalogUrls {
212
- /** The catalog `url` — the unversioned file, or the latest versioned file. */
213
- readonly url: string;
214
- /**
215
- * The versioned catalog's `versions` map (label → url), inserted — and,
216
- * since a three-component label can never be integer-like, enumerated
217
- * and serialized — in ascending version order.
218
- */
219
- readonly versions?: Readonly<Record<string, string>>;
220
- }
221
- /**
222
- * Both SchemaStore catalog modes as pure derivations: unversioned (a plain
223
- * `name.json` file, `url` only) and versioned (`name-<version>.json` files
224
- * — SchemaStore's own suffix convention — a `versions` map, and `url`
225
- * pointing at the latest version).
226
- *
227
- * Version labels are full three-component SemVer, so ordering is plain
228
- * SemVer precedence: `1.10.0` above `1.9.0`, `2.0.0-beta` below `2.0.0`.
229
- *
230
- * @public
231
- */
232
- declare class SchemaVersioning {
233
- private constructor();
234
- /**
235
- * Parses a version label. Pure and synchronous — the primitive form;
236
- * {@link SchemaVersioning.parse} is the same check behind a span.
237
- */
238
- static parseResult(input: string): Result.Result<SchemaVersion, InvalidSchemaVersionError>;
239
- /**
240
- * Effect form of {@link SchemaVersioning.parseResult}, adding only the
241
- * `SchemaVersioning.parse` span. Defined in terms of the `Result`
242
- * primitive — synchronous callers can use that variant directly.
243
- */
244
- static readonly parse: (input: string) => Effect.Effect<string & import("effect/Brand").Brand<"SchemaVersion">, InvalidSchemaVersionError, never>;
245
- /**
246
- * `Order` instance over version labels: plain SemVer precedence.
247
- * `1.10.0` sorts above `1.9.0` (numeric, not lexical) and `2.0.0-beta`
248
- * below `2.0.0` (prerelease precedence).
249
- */
250
- static readonly Order: Order.Order<SchemaVersion>;
251
- /**
252
- * The highest version label by {@link SchemaVersioning.Order}, or
253
- * `Option.none()` for an empty collection.
254
- */
255
- static latest(versions: ReadonlyArray<SchemaVersion>): Option.Option<SchemaVersion>;
256
- /**
257
- * Derives the schema file name for a catalog name: `name.json`
258
- * unversioned, `name-<version>.json` versioned.
259
- *
260
- * The name must be a simple file base name (no separators, no
261
- * whitespace); anything else is a wiring mistake and throws.
262
- */
263
- static fileName(name: string, version?: SchemaVersion): string;
264
- /**
265
- * The canonical URL a schema file is hosted at: `baseUrl` joined with
266
- * {@link SchemaVersioning.fileName}.
267
- */
268
- static schemaUrl(baseUrl: string, name: string, version?: SchemaVersion): string;
269
- /**
270
- * Assembles the `url`/`versions` half of a catalog entry.
271
- *
272
- * Omitting `versions` selects the unversioned mode (`url` only,
273
- * pointing at the plain `name.json`). Providing them selects the
274
- * versioned mode: the `versions` map carries every label, and `url`
275
- * points at the latest version's file. An **empty** `versions` array is
276
- * a contradiction (versioned mode with no versions) and throws — pass
277
- * `undefined` for the unversioned mode.
278
- *
279
- * Labels are inserted in ascending {@link SchemaVersioning.Order} and
280
- * stay that way on serialization. Requiring three components is what
281
- * buys this: JavaScript enumerates array-index-like keys first, so the
282
- * old grammar's bare-major label (`"2"`) jumped ahead of every dotted
283
- * one regardless of insertion order. No SemVer label is integer-like,
284
- * so that hazard is gone. Deriving ordering from the labels themselves
285
- * (as {@link SchemaVersioning.latest} does) is still the robust read.
286
- */
287
- static catalogUrls(options: {
288
- readonly baseUrl: string;
289
- readonly name: string;
290
- readonly versions?: ReadonlyArray<SchemaVersion>;
291
- }): CatalogUrls;
292
- }
293
- //#endregion
294
- //#region src/CatalogEntry.d.ts
295
- declare const CatalogLintFinding_base: Schema.Class<CatalogLintFinding, Schema.Struct<{
296
- /** Which hygiene check fired. */
297
- readonly check: Schema.Literals<readonly ["GenericFileMatch", "ComplexFileMatch"]>;
298
- /** The `fileMatch` pattern the finding is about. */
299
- readonly pattern: Schema.String;
300
- /** Human-readable explanation with the SchemaStore rationale. */
301
- readonly message: Schema.String;
302
- }>, {}>;
303
- /**
304
- * A fileMatch hygiene finding: a value in a lint report, not an error —
305
- * SchemaStore reviewers reject entries over these, so surfacing them
306
- * locally is the point, but a warned entry is still a valid entry.
307
- *
308
- * @public
309
- */
310
- declare class CatalogLintFinding extends CatalogLintFinding_base {}
311
- declare const CatalogEntry_base: Schema.Class<CatalogEntry, Schema.Struct<{
312
- /** The schema's display name in the catalog. */
313
- readonly name: Schema.String;
314
- /** The catalog description. */
315
- readonly description: Schema.String;
316
- /** Glob patterns editors match files against. */
317
- readonly fileMatch: Schema.$Array<Schema.String>;
318
- /** The schema URL — the unversioned file, or the latest version. */
319
- readonly url: Schema.String;
320
- /**
321
- * Versioned mode only: label → schema URL. Inserted ascending, but key
322
- * order is not a contract — bare-major labels enumerate first (see
323
- * `SchemaVersioning.catalogUrls`); derive ordering from the labels.
324
- */
325
- readonly versions: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
326
- }>, {}>;
327
- /**
328
- * A SchemaStore `catalog.json` entry: the class is the schema, so decoding
329
- * an existing entry and encoding one for submission are the same artifact.
330
- * `versions` is present only for versioned catalogs
331
- * ({@link SchemaVersioning.catalogUrls} assembles both modes).
332
- *
333
- * @public
334
- */
335
- declare class CatalogEntry extends CatalogEntry_base {
336
- /**
337
- * Assembles an entry from a catalog identity plus
338
- * {@link SchemaVersioning.catalogUrls}' inputs: pass `versions` for the
339
- * versioned mode (the `versions` map and latest-pointing `url` are
340
- * derived), omit it for the unversioned mode.
341
- */
342
- static assemble(options: {
343
- readonly name: string;
344
- readonly description: string;
345
- readonly fileMatch: ReadonlyArray<string>;
346
- readonly baseUrl: string;
347
- readonly fileBaseName?: string;
348
- readonly versions?: ReadonlyArray<SchemaVersion>;
349
- }): CatalogEntry;
350
- /**
351
- * The fileMatch hygiene lint over this entry's patterns — pure shape
352
- * analysis (no glob engine): generic patterns SchemaStore rejects and
353
- * complex constructs it asks contributors to expand.
354
- */
355
- lint(): ReadonlyArray<CatalogLintFinding>;
356
- /**
357
- * {@link CatalogEntry.lint} over a bare pattern list, for callers
358
- * checking patterns before an entry exists.
359
- */
360
- static lintFileMatch(patterns: ReadonlyArray<string>): ReadonlyArray<CatalogLintFinding>;
361
- }
362
- //#endregion
363
99
  //#region src/DocumentDiff.d.ts
364
100
  /**
365
101
  * What differs between two schema documents:
@@ -408,7 +144,7 @@ type SchemaChange = "none" | "annotations" | "contract";
408
144
  *
409
145
  * @public
410
146
  */
411
- declare class DocumentDiff {
147
+ export declare class DocumentDiff {
412
148
  private constructor();
413
149
  /**
414
150
  * Classify the difference between two emitted document values (the
@@ -448,7 +184,7 @@ declare class DocumentDiff {
448
184
  *
449
185
  * @public
450
186
  */
451
- declare const DRAFT_07_META_SCHEMA = "http://json-schema.org/draft-07/schema#";
187
+ export declare const DRAFT_07_META_SCHEMA = "http://json-schema.org/draft-07/schema#";
452
188
  declare const SchemaConversionError_base: Schema.Class<SchemaConversionError, Schema.TaggedStruct<"SchemaConversionError", {
453
189
  /** The `$id` of the document that failed to build. */
454
190
  readonly $id: Schema.String;
@@ -465,7 +201,34 @@ declare const SchemaConversionError_base: Schema.Class<SchemaConversionError, Sc
465
201
  *
466
202
  * @public
467
203
  */
468
- declare class SchemaConversionError extends SchemaConversionError_base {
204
+ export declare class SchemaConversionError extends SchemaConversionError_base {
205
+ get message(): string;
206
+ }
207
+ declare const UndeclaredAnnotationKeyError_base: Schema.Class<UndeclaredAnnotationKeyError, Schema.TaggedStruct<"UndeclaredAnnotationKeyError", {
208
+ /** The `$id` of the document that was being built. */
209
+ readonly $id: Schema.String;
210
+ /** The offending keys, deduplicated and sorted. */
211
+ readonly keys: Schema.$Array<Schema.String>;
212
+ }>, import("effect/Cause").YieldableError>;
213
+ /**
214
+ * Indicates that a caller-supplied `includeAnnotationKey` admitted an
215
+ * annotation key outside the declared keyword families
216
+ * ({@link KeywordFamilies}).
217
+ *
218
+ * Raised by {@link StoreDocument.fromSchema}. This package emits
219
+ * SchemaStore-compatible documents only, so the declared families are the
220
+ * whole permitted non-standard surface. A key outside them is refused
221
+ * loudly rather than emitted — which would ship a document SchemaStore's
222
+ * own gate rejects — or silently omitted, which would hide the mistake in
223
+ * the caller's predicate.
224
+ *
225
+ * The predicate itself cannot be introspected, so the offending keys are
226
+ * the ones it actually admitted while the document was being generated: a
227
+ * key the source schema never annotates cannot appear here.
228
+ *
229
+ * @public
230
+ */
231
+ export declare class UndeclaredAnnotationKeyError extends UndeclaredAnnotationKeyError_base {
469
232
  get message(): string;
470
233
  }
471
234
  /**
@@ -482,14 +245,17 @@ interface StoreDocumentOptions {
482
245
  * `includeAnnotationKey`).
483
246
  *
484
247
  * The declared non-standard keyword families ({@link KeywordFamilies})
485
- * are **always admitted** and carried into the built document — annotate
486
- * a schema node (`Schema.String.annotate({ "x-taplo": ... })`) and the
487
- * key survives the Draft-07 lowering via the post-lowering re-graft
488
- * ({@link AnnotationCarriers}). A supplied `includeAnnotationKey` is
489
- * consulted *in addition* for other keys; know the boundary: keys it
490
- * admits outside the declared families reach the Draft 2020-12 document
491
- * but are **dropped by the Draft-07 lowering** (its keyword walk copies
492
- * a fixed subset) verified against the installed beta.
248
+ * are **always admitted**, regardless of what a supplied
249
+ * `includeAnnotationKey` answers annotate a schema node
250
+ * (`Schema.String.annotate({ "x-taplo": ... })`) and the key appears in
251
+ * the built document, in place, on the node it was attached to.
252
+ *
253
+ * A supplied `includeAnnotationKey` is consulted only for other keys,
254
+ * and **admitting one fails the build** with
255
+ * {@link UndeclaredAnnotationKeyError}. The families are the entire
256
+ * non-standard surface this package will emit, so the predicate has no
257
+ * admitting role left; it survives only because the rest of
258
+ * `ToJsonSchemaOptions` passes through, and is best left unset.
493
259
  */
494
260
  readonly jsonSchema?: Schema.ToJsonSchemaOptions;
495
261
  }
@@ -513,13 +279,21 @@ declare const StoreDocument_base: Schema.Class<StoreDocument, Schema.Struct<{
513
279
  * `JsonSchema.toDocumentDraft07` lowering, the `#/definitions` →
514
280
  * `#/$defs` `$ref` rewrite the lowering makes necessary — so every `$ref`
515
281
  * in a built document already resolves against the `$defs` pool — and the
516
- * {@link AnnotationCarriers} re-graft, so annotated non-standard keyword
517
- * families ({@link KeywordFamilies}) survive into the built document. The
518
- * package owns assembly and publication shape, not a JSON Schema engine.
282
+ * gate that holds the document's non-standard surface to the declared
283
+ * keyword families ({@link KeywordFamilies}). The package owns assembly and
284
+ * publication shape, not a JSON Schema engine.
285
+ *
286
+ * Annotated declared-family keys survive into the built document because
287
+ * core's Draft-07 lowering copies unknown and custom keywords through as
288
+ * opaque values, in place, including across the tuple coordinate move
289
+ * (2020-12 `prefixItems[i]` → Draft-07 `items[i]`, trailing `items` →
290
+ * `additionalItems`). This package therefore does no re-grafting of its
291
+ * own; it only declines to rewrite `$ref`-shaped strings *inside* those
292
+ * opaque payloads.
519
293
  *
520
294
  * @public
521
295
  */
522
- declare class StoreDocument extends StoreDocument_base {
296
+ export declare class StoreDocument extends StoreDocument_base {
523
297
  /**
524
298
  * Builds a Draft-07 document from its parts, filling `$schema` with
525
299
  * {@link DRAFT_07_META_SCHEMA}.
@@ -552,26 +326,475 @@ declare class StoreDocument extends StoreDocument_base {
552
326
  * synchronous — the primitive form; {@link StoreDocument.fromSchema} is
553
327
  * the same pipeline behind a span.
554
328
  */
555
- static fromSchemaResult(source: Schema.Constraint, options: StoreDocumentOptions): Result.Result<StoreDocument, SchemaConversionError>;
329
+ static fromSchemaResult(source: Schema.Constraint, options: StoreDocumentOptions): Result.Result<StoreDocument, SchemaConversionError | UndeclaredAnnotationKeyError>;
556
330
  /**
557
331
  * Effect form of {@link StoreDocument.fromSchemaResult}, adding only the
558
332
  * `StoreDocument.fromSchema` span. Defined in terms of the `Result`
559
333
  * primitive — synchronous callers can use that variant directly.
560
334
  */
561
- static readonly fromSchema: (source: Schema.Constraint, options: StoreDocumentOptions) => Effect.Effect<StoreDocument, SchemaConversionError, never>;
335
+ static readonly fromSchema: (source: Schema.Constraint, options: StoreDocumentOptions) => Effect.Effect<StoreDocument, SchemaConversionError | UndeclaredAnnotationKeyError, never>;
562
336
  /**
563
337
  * The flat SchemaStore publication shape: `$schema`, `$id`, the root
564
338
  * schema's keywords spread at the top level, then the `$defs` pool.
565
339
  * `$defs` is omitted when the pool is empty (a deliberate divergence
566
340
  * from the extraction source, which always emitted the key).
567
341
  */
568
- toJson(): Record<string, unknown>;
342
+ toJson(): Record<string, unknown>;
343
+ /**
344
+ * Canonical JSON text of {@link StoreDocument.toJson}, via
345
+ * {@link CanonicalJson.serializeResult} — one serializer, so the
346
+ * document and any consumer-serialized value cannot drift.
347
+ */
348
+ serializeResult(options?: CanonicalJsonOptions): Result.Result<string, CanonicalJsonError>;
349
+ }
350
+ //#endregion
351
+ //#region src/SchemaFile.d.ts
352
+ declare const SchemaFileReadError_base: Schema.Class<SchemaFileReadError, Schema.TaggedStruct<"SchemaFileReadError", {
353
+ /** The path that could not be read. */
354
+ readonly path: Schema.String;
355
+ /** The underlying filesystem failure, preserved structurally. */
356
+ readonly cause: Schema.Defect;
357
+ }>, import("effect/Cause").YieldableError>;
358
+ /**
359
+ * Indicates that a schema file could not be read from the filesystem (a
360
+ * filesystem error other than not-found).
361
+ *
362
+ * @public
363
+ */
364
+ export declare class SchemaFileReadError extends SchemaFileReadError_base {
365
+ get message(): string;
366
+ }
367
+ declare const SchemaFileNotFoundError_base: Schema.Class<SchemaFileNotFoundError, Schema.TaggedStruct<"SchemaFileNotFoundError", {
368
+ /** The path where the schema file was expected. */
369
+ readonly path: Schema.String;
370
+ }>, import("effect/Cause").YieldableError>;
371
+ /**
372
+ * Indicates that no schema file exists at the expected path. Carries its
373
+ * own tag for `catchTag` routing.
374
+ *
375
+ * @public
376
+ */
377
+ export declare class SchemaFileNotFoundError extends SchemaFileNotFoundError_base {
378
+ get message(): string;
379
+ }
380
+ declare const SchemaFileWriteError_base: Schema.Class<SchemaFileWriteError, Schema.TaggedStruct<"SchemaFileWriteError", {
381
+ /** The path that could not be written. */
382
+ readonly path: Schema.String;
383
+ /** The underlying filesystem failure, preserved structurally. */
384
+ readonly cause: Schema.Defect;
385
+ }>, import("effect/Cause").YieldableError>;
386
+ /**
387
+ * Indicates that a schema file could not be written to the filesystem.
388
+ * Narrowed to the filesystem failure only — a serialization failure
389
+ * surfaces as its own `CanonicalJsonError`, never wrapped here.
390
+ *
391
+ * @public
392
+ */
393
+ export declare class SchemaFileWriteError extends SchemaFileWriteError_base {
394
+ get message(): string;
395
+ }
396
+ /**
397
+ * What {@link SchemaFileShape.write} did to the filesystem: `"written"`
398
+ * when it wrote, `"unchanged"` when it left the file alone — reported as a
399
+ * value so the caller decides what to surface, never a log.
400
+ *
401
+ * @public
402
+ */
403
+ type WriteOutcome = "written" | "unchanged";
404
+ /**
405
+ * How the document being written relates to what was already on disk:
406
+ * {@link SchemaChange} plus `"created"` for a file that did not exist, so
407
+ * there was nothing to compare against.
408
+ *
409
+ * @public
410
+ */
411
+ type WriteChange = SchemaChange | "created";
412
+ /**
413
+ * The result of {@link SchemaFileShape.write}: what happened to the file,
414
+ * and what the difference MEANT.
415
+ *
416
+ * The two are independent on purpose. `change` answers the versioning
417
+ * question — `"annotations"` means only prose and editor affordances moved,
418
+ * so the document replaces its predecessor transparently and needs no new
419
+ * {@link SchemaVersioning} version, while `"contract"` means an assertion
420
+ * keyword moved and a consumer's document valid yesterday may be invalid
421
+ * today. `outcome` answers only whether bytes were written, which under
422
+ * `compare: "bytes"` can be `"written"` even when `change` is `"none"`.
423
+ *
424
+ * @public
425
+ */
426
+ interface WriteResult {
427
+ /**
428
+ * Whether the file was written. **This is the authoritative answer to
429
+ * "did the filesystem get touched"** — always, under either `compare`
430
+ * mode. Do not infer it from `change`: under `compare: "bytes"` a
431
+ * `change` of `"none"` still writes.
432
+ */
433
+ readonly outcome: WriteOutcome;
434
+ /** What differs between the previous content and the new document. */
435
+ readonly change: WriteChange;
436
+ }
437
+ /**
438
+ * The result of {@link SchemaFileShape.check}: the same two answers
439
+ * {@link WriteResult} carries, for a call that touched nothing.
440
+ *
441
+ * `wouldWrite` is `outcome`'s counterpart — it honors `compare`, so it
442
+ * answers "would `write` do anything with these same options", which
443
+ * `change` alone cannot under `compare: "bytes"`.
444
+ *
445
+ * @public
446
+ */
447
+ interface CheckResult {
448
+ /** Whether a `write` with the same options would touch the file. */
449
+ readonly wouldWrite: boolean;
450
+ /** What differs between the on-disk content and the new document. */
451
+ readonly change: WriteChange;
452
+ }
453
+ /**
454
+ * Options for {@link SchemaFileShape.write} and
455
+ * {@link SchemaFileShape.check}: the {@link CanonicalJsonOptions} the
456
+ * document serializes under, plus how `write` decides whether to touch the
457
+ * file.
458
+ *
459
+ * @public
460
+ */
461
+ interface SchemaWriteOptions extends CanonicalJsonOptions {
462
+ /**
463
+ * How `write` decides the file needs rewriting:
464
+ *
465
+ * - `"value"` (the default) — compare the parsed content. Immune to any
466
+ * other tool that reformats the file, which is the common case: a repo
467
+ * whose pre-commit hook runs Biome or Prettier over `*.json` would
468
+ * otherwise see every run rewrite the file forever, because the
469
+ * formatter's bytes never match `CanonicalJson`'s.
470
+ * - `"bytes"` — compare the exact text, so the file on disk is only ever
471
+ * `CanonicalJson`'s own output. Choose this when the emitted bytes are
472
+ * themselves the artifact and no other tool is allowed to touch them.
473
+ *
474
+ * `change` in the {@link WriteResult} is classified by content either
475
+ * way; this option decides only whether a byte-level difference is
476
+ * enough to rewrite.
477
+ */
478
+ readonly compare?: "bytes" | "value";
479
+ }
480
+ /**
481
+ * The shape of the {@link SchemaFile} service — the value produced by
482
+ * {@link SchemaFile.make} and carried by its layer.
483
+ *
484
+ * @public
485
+ */
486
+ interface SchemaFileShape {
487
+ /**
488
+ * Read a schema file's exact text (the drift-test read side: compare it
489
+ * against `StoreDocument.serializeResult`). Fails with
490
+ * `SchemaFileNotFoundError` (ENOENT) or `SchemaFileReadError` (other
491
+ * filesystem errors).
492
+ */
493
+ readonly read: (path: string) => Effect.Effect<string, SchemaFileReadError | SchemaFileNotFoundError>;
494
+ /**
495
+ * Serialize a document to canonical JSON and write it **only if the
496
+ * on-disk content differs** (a missing file counts as different),
497
+ * creating parent directories as needed. Answers a {@link WriteResult}
498
+ * as a value: what happened to the file, and what the difference meant.
499
+ * Fails with a `CanonicalJsonError` (the document does not serialize),
500
+ * `SchemaFileReadError` (the existing content could not be read for
501
+ * comparison) or `SchemaFileWriteError` (the filesystem write failed).
502
+ */
503
+ readonly write: (path: string, document: StoreDocument, options?: SchemaWriteOptions) => Effect.Effect<WriteResult, CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError>;
504
+ /**
505
+ * The same comparison {@link SchemaFileShape.write} makes, **without
506
+ * touching the filesystem** — the drift-check half of the pair, for a
507
+ * CI job that must assert a committed schema is current rather than
508
+ * regenerate it.
509
+ *
510
+ * Answers both questions the writer answers: `change` classifies the
511
+ * content (immune to a formatter having reflowed the committed file),
512
+ * and `wouldWrite` honors `compare`, so it agrees with `write` under
513
+ * either mode. Checking drift is `change`; predicting the writer is
514
+ * `wouldWrite`.
515
+ */
516
+ readonly check: (path: string, document: StoreDocument, options?: SchemaWriteOptions) => Effect.Effect<CheckResult, CanonicalJsonError | SchemaFileReadError>;
517
+ }
518
+ declare const SchemaFile_base: Context.ServiceClass<SchemaFile, "@effected/schemastore/SchemaFile", SchemaFileShape>;
519
+ /**
520
+ * Reads and writes emitted schema documents over core `FileSystem` /
521
+ * `Path` — the package's one IO surface. The layer requires those
522
+ * services; provide `@effect/platform-node`'s `NodeFileSystem` / `NodePath`
523
+ * (or a bun equivalent) at the application boundary.
524
+ *
525
+ * `write` is write-if-changed, and by default compares **content**: an
526
+ * unchanged document never touches the file even if another tool has
527
+ * reformatted it, so a generator committed to a repo whose pre-commit hook
528
+ * formats JSON does not churn on every run. It also reports what the
529
+ * difference meant — `"annotations"` (prose only, replaces its predecessor
530
+ * transparently) versus `"contract"` (an assertion moved, so a new
531
+ * `SchemaVersioning` version is warranted). `check` makes the same
532
+ * comparison without writing, which is what a CI drift job wants.
533
+ *
534
+ * @example
535
+ * ```ts
536
+ * import { SchemaFile, StoreDocument } from "@effected/schemastore";
537
+ * import { NodeFileSystem, NodePath } from "@effect/platform-node";
538
+ * import { Effect, Layer, Schema } from "effect";
539
+ *
540
+ * const program = Effect.gen(function* () {
541
+ * const files = yield* SchemaFile;
542
+ * const document = yield* StoreDocument.fromSchema(Schema.Struct({ name: Schema.String }), {
543
+ * $id: "https://example.com/config.schema.json",
544
+ * });
545
+ * return yield* files.write("schemas/config.schema.json", document);
546
+ * }).pipe(
547
+ * Effect.provide(SchemaFile.layer),
548
+ * Effect.provide(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)),
549
+ * );
550
+ * ```
551
+ *
552
+ * @public
553
+ */
554
+ export declare class SchemaFile extends SchemaFile_base {
555
+ /** Build the service implementation from `FileSystem` / `Path` in context; use {@link SchemaFile.layer} to provide it. */
556
+ static readonly make: Effect.Effect<SchemaFileShape, never, FileSystem.FileSystem | Path.Path>;
557
+ /**
558
+ * The live layer. Requires core `FileSystem` / `Path`, provided by the
559
+ * consumer's platform implementation at the edge.
560
+ */
561
+ static readonly layer: Layer.Layer<SchemaFile, never, FileSystem.FileSystem | Path.Path>;
562
+ }
563
+ //#endregion
564
+ //#region src/SchemaVersioning.d.ts
565
+ declare const InvalidSchemaVersionError_base: Schema.Class<InvalidSchemaVersionError, Schema.TaggedStruct<"InvalidSchemaVersionError", {
566
+ /** The raw input string that failed to parse. */
567
+ readonly input: Schema.String;
568
+ }>, import("effect/Cause").YieldableError>;
569
+ /**
570
+ * Indicates that a string is not a valid SchemaStore version label.
571
+ *
572
+ * Raised by {@link SchemaVersioning.parse}.
573
+ *
574
+ * @public
575
+ */
576
+ export declare class InvalidSchemaVersionError extends InvalidSchemaVersionError_base {
577
+ get message(): string;
578
+ }
579
+ /**
580
+ * A schema version label: a branded string holding a **full three-component
581
+ * SemVer** — `major.minor.patch` with an optional prerelease, validated by
582
+ * `@effected/semver` itself. Build metadata is rejected (see below).
583
+ *
584
+ * `1.2` and `1` are NOT accepted, though SchemaStore's own corpus uses such
585
+ * labels: requiring all three components makes a label unambiguous to split
586
+ * back out of `<name>-<version>.json` or its URL, which is what consumers
587
+ * do with it. The file-name convention around the label stays SchemaStore's.
588
+ *
589
+ * The label round-trips verbatim into file names and catalog `versions`
590
+ * keys; ordering parses it directly (see {@link SchemaVersioning.Order}).
591
+ *
592
+ * @public
593
+ */
594
+ export declare const SchemaVersion: Schema.brand<Schema.String, "SchemaVersion">;
595
+ /**
596
+ * The type of a validated SchemaStore version label.
597
+ *
598
+ * @public
599
+ */
600
+ export type SchemaVersion = typeof SchemaVersion.Type;
601
+ /**
602
+ * The `url`/`versions` half of a catalog entry, as assembled by
603
+ * {@link SchemaVersioning.catalogUrls}.
604
+ *
605
+ * @public
606
+ */
607
+ interface CatalogUrls {
608
+ /** The catalog `url` — the unversioned file, or the latest versioned file. */
609
+ readonly url: string;
610
+ /**
611
+ * The versioned catalog's `versions` map (label → url), inserted — and,
612
+ * since a three-component label can never be integer-like, enumerated
613
+ * and serialized — in ascending version order.
614
+ */
615
+ readonly versions?: Readonly<Record<string, string>>;
616
+ }
617
+ /**
618
+ * Both SchemaStore catalog modes as pure derivations: unversioned (a plain
619
+ * `name.json` file, `url` only) and versioned (`name-<version>.json` files
620
+ * — SchemaStore's own suffix convention — a `versions` map, and `url`
621
+ * pointing at the latest version).
622
+ *
623
+ * Version labels are full three-component SemVer, so ordering is plain
624
+ * SemVer precedence: `1.10.0` above `1.9.0`, `2.0.0-beta` below `2.0.0`.
625
+ *
626
+ * @public
627
+ */
628
+ export declare class SchemaVersioning {
629
+ private constructor();
630
+ /**
631
+ * Parses a version label. Pure and synchronous — the primitive form;
632
+ * {@link SchemaVersioning.parse} is the same check behind a span.
633
+ */
634
+ static parseResult(input: string): Result.Result<SchemaVersion, InvalidSchemaVersionError>;
635
+ /**
636
+ * Effect form of {@link SchemaVersioning.parseResult}, adding only the
637
+ * `SchemaVersioning.parse` span. Defined in terms of the `Result`
638
+ * primitive — synchronous callers can use that variant directly.
639
+ */
640
+ static readonly parse: (input: string) => Effect.Effect<string & import("effect/Brand").Brand<"SchemaVersion">, InvalidSchemaVersionError, never>;
641
+ /**
642
+ * `Order` instance over version labels: plain SemVer precedence.
643
+ * `1.10.0` sorts above `1.9.0` (numeric, not lexical) and `2.0.0-beta`
644
+ * below `2.0.0` (prerelease precedence).
645
+ */
646
+ static readonly Order: Order.Order<SchemaVersion>;
647
+ /**
648
+ * The highest version label by {@link SchemaVersioning.Order}, or
649
+ * `Option.none()` for an empty collection.
650
+ */
651
+ static latest(versions: ReadonlyArray<SchemaVersion>): Option.Option<SchemaVersion>;
652
+ /**
653
+ * Whether a label names a pinned, published document — i.e. it is NOT a
654
+ * prerelease. SemVer §9 makes a prerelease's own instability explicit, so
655
+ * a contract change inside one is not a break for anyone.
656
+ *
657
+ * ONE predicate consumed by two policies so they cannot drift:
658
+ * `SchemaPipeline`'s `"block-versioned"` guard (a pinned versioned target
659
+ * refuses an in-place contract change) and {@link SchemaVersioning.next}
660
+ * (a non-pinned label is not bumped). If the two used different tests, a
661
+ * caller could be refused a write AND told to keep the same label — a
662
+ * deadlock.
663
+ */
664
+ static isPinned(version: SchemaVersion): boolean;
665
+ /**
666
+ * The version label a change classification calls for. Pure and
667
+ * synchronous; total over validated labels — a non-label input is a wiring
668
+ * bug and dies as a defect, the same as {@link SchemaVersioning.Order}.
669
+ *
670
+ * - `change !== "contract"` (`"none"`, `"annotations"`, `"created"`) →
671
+ * `current`. A created file has no predecessor to break; an annotation
672
+ * change is transparently replaceable (`DocumentDiff`).
673
+ * - `current` is not pinned (a prerelease) → `current`. A prerelease
674
+ * declares its own instability; the pipeline's `"block-versioned"`
675
+ * policy uses the same {@link SchemaVersioning.isPinned}, so the gate
676
+ * and the bump agree.
677
+ * - `major === 0` → MINOR bump (`0.4.0` → `0.5.0`): on the 0.x line MINOR
678
+ * is the breaking axis.
679
+ * - otherwise → MAJOR bump (`5.0.0` → `6.0.0`).
680
+ *
681
+ * The bump's job is to be strictly greater and conspicuous, NOT to encode
682
+ * SemVer compatibility: `DocumentDiff` cannot tell an added optional
683
+ * property from a removed required one, so every contract change reads as
684
+ * breaking. Each label is its own file and URL, so an over-bump costs a
685
+ * file; an under-bump would overwrite a pinned document. `next` never
686
+ * introduces a prerelease from a stable input.
687
+ *
688
+ * A component that would be bumped past `Number.MAX_SAFE_INTEGER` cannot be
689
+ * represented, and throws this module's explicit invariant `Error` naming
690
+ * the label and the ceiling rather than `SemVer.make`'s bare schema failure.
691
+ */
692
+ static next(current: SchemaVersion, change: WriteChange): SchemaVersion;
693
+ /**
694
+ * Derives the schema file name for a catalog name: `name.json`
695
+ * unversioned, `name-<version>.json` versioned.
696
+ *
697
+ * The name must be a simple file base name (no separators, no
698
+ * whitespace); anything else is a wiring mistake and throws.
699
+ */
700
+ static fileName(name: string, version?: SchemaVersion): string;
701
+ /**
702
+ * The canonical URL a schema file is hosted at: `baseUrl` joined with
703
+ * {@link SchemaVersioning.fileName}.
704
+ */
705
+ static schemaUrl(baseUrl: string, name: string, version?: SchemaVersion): string;
706
+ /**
707
+ * Assembles the `url`/`versions` half of a catalog entry.
708
+ *
709
+ * Omitting `versions` selects the unversioned mode (`url` only,
710
+ * pointing at the plain `name.json`). Providing them selects the
711
+ * versioned mode: the `versions` map carries every label, and `url`
712
+ * points at the latest version's file. An **empty** `versions` array is
713
+ * a contradiction (versioned mode with no versions) and throws — pass
714
+ * `undefined` for the unversioned mode.
715
+ *
716
+ * Labels are inserted in ascending {@link SchemaVersioning.Order} and
717
+ * stay that way on serialization. Requiring three components is what
718
+ * buys this: JavaScript enumerates array-index-like keys first, so the
719
+ * old grammar's bare-major label (`"2"`) jumped ahead of every dotted
720
+ * one regardless of insertion order. No SemVer label is integer-like,
721
+ * so that hazard is gone. Deriving ordering from the labels themselves
722
+ * (as {@link SchemaVersioning.latest} does) is still the robust read.
723
+ */
724
+ static catalogUrls(options: {
725
+ readonly baseUrl: string;
726
+ readonly name: string;
727
+ readonly versions?: ReadonlyArray<SchemaVersion>;
728
+ }): CatalogUrls;
729
+ }
730
+ //#endregion
731
+ //#region src/CatalogEntry.d.ts
732
+ declare const CatalogLintFinding_base: Schema.Class<CatalogLintFinding, Schema.Struct<{
733
+ /** Which hygiene check fired. */
734
+ readonly check: Schema.Literals<readonly ["GenericFileMatch", "ComplexFileMatch"]>;
735
+ /** The `fileMatch` pattern the finding is about. */
736
+ readonly pattern: Schema.String;
737
+ /** Human-readable explanation with the SchemaStore rationale. */
738
+ readonly message: Schema.String;
739
+ }>, {}>;
740
+ /**
741
+ * A fileMatch hygiene finding: a value in a lint report, not an error —
742
+ * SchemaStore reviewers reject entries over these, so surfacing them
743
+ * locally is the point, but a warned entry is still a valid entry.
744
+ *
745
+ * @public
746
+ */
747
+ export declare class CatalogLintFinding extends CatalogLintFinding_base {}
748
+ declare const CatalogEntry_base: Schema.Class<CatalogEntry, Schema.Struct<{
749
+ /** The schema's display name in the catalog. */
750
+ readonly name: Schema.String;
751
+ /** The catalog description. */
752
+ readonly description: Schema.String;
753
+ /** Glob patterns editors match files against. */
754
+ readonly fileMatch: Schema.$Array<Schema.String>;
755
+ /** The schema URL — the unversioned file, or the latest version. */
756
+ readonly url: Schema.String;
757
+ /**
758
+ * Versioned mode only: label → schema URL. Inserted ascending, but key
759
+ * order is not a contract — bare-major labels enumerate first (see
760
+ * `SchemaVersioning.catalogUrls`); derive ordering from the labels.
761
+ */
762
+ readonly versions: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
763
+ }>, {}>;
764
+ /**
765
+ * A SchemaStore `catalog.json` entry: the class is the schema, so decoding
766
+ * an existing entry and encoding one for submission are the same artifact.
767
+ * `versions` is present only for versioned catalogs
768
+ * ({@link SchemaVersioning.catalogUrls} assembles both modes).
769
+ *
770
+ * @public
771
+ */
772
+ export declare class CatalogEntry extends CatalogEntry_base {
773
+ /**
774
+ * Assembles an entry from a catalog identity plus
775
+ * {@link SchemaVersioning.catalogUrls}' inputs: pass `versions` for the
776
+ * versioned mode (the `versions` map and latest-pointing `url` are
777
+ * derived), omit it for the unversioned mode.
778
+ */
779
+ static assemble(options: {
780
+ readonly name: string;
781
+ readonly description: string;
782
+ readonly fileMatch: ReadonlyArray<string>;
783
+ readonly baseUrl: string;
784
+ readonly fileBaseName?: string;
785
+ readonly versions?: ReadonlyArray<SchemaVersion>;
786
+ }): CatalogEntry;
787
+ /**
788
+ * The fileMatch hygiene lint over this entry's patterns — pure shape
789
+ * analysis (no glob engine): generic patterns SchemaStore rejects and
790
+ * complex constructs it asks contributors to expand.
791
+ */
792
+ lint(): ReadonlyArray<CatalogLintFinding>;
569
793
  /**
570
- * Canonical JSON text of {@link StoreDocument.toJson}, via
571
- * {@link CanonicalJson.serializeResult} one serializer, so the
572
- * document and any consumer-serialized value cannot drift.
794
+ * {@link CatalogEntry.lint} over a bare pattern list, for callers
795
+ * checking patterns before an entry exists.
573
796
  */
574
- serializeResult(options?: CanonicalJsonOptions): Result.Result<string, CanonicalJsonError>;
797
+ static lintFileMatch(patterns: ReadonlyArray<string>): ReadonlyArray<CatalogLintFinding>;
575
798
  }
576
799
  //#endregion
577
800
  //#region src/DocumentLint.d.ts
@@ -592,7 +815,7 @@ declare const DocumentLintFinding_base: Schema.Class<DocumentLintFinding, Schema
592
815
  *
593
816
  * @public
594
817
  */
595
- declare class DocumentLintFinding extends DocumentLintFinding_base {}
818
+ export declare class DocumentLintFinding extends DocumentLintFinding_base {}
596
819
  /**
597
820
  * Owned structural checks over an assembled {@link StoreDocument} — the
598
821
  * always-available half of the validation story (a real-engine gate like
@@ -603,7 +826,7 @@ declare class DocumentLintFinding extends DocumentLintFinding_base {}
603
826
  * `#/definitions/...` pointer, is a warning).
604
827
  * - `UnknownKeyword` — no keyword outside Draft-07 plus the declared
605
828
  * non-standard families ({@link KeywordFamilies}: `x-taplo*`, `x-tombi-*`,
606
- * `x-intellij-*` and the vscode set), which ajv strict mode would reject.
829
+ * `x-intellij-*`, `x-ai-*` and the vscode set), which ajv strict mode would reject.
607
830
  * - `DescriptionWithoutUrl` — advisory: SchemaStore's description
608
831
  * convention ends the root description with a docs URL line.
609
832
  *
@@ -612,7 +835,7 @@ declare class DocumentLintFinding extends DocumentLintFinding_base {}
612
835
  *
613
836
  * @public
614
837
  */
615
- declare class DocumentLint {
838
+ export declare class DocumentLint {
616
839
  private constructor();
617
840
  /**
618
841
  * Runs every check; total — hostile nesting degrades to a
@@ -623,10 +846,12 @@ declare class DocumentLint {
623
846
  //#endregion
624
847
  //#region src/KeywordFamilies.d.ts
625
848
  /**
626
- * The one owner of the declared non-standard keyword families the
627
- * language-server keyword sets SchemaStore's CONTRIBUTING enumerates as
628
- * legitimately consumed by editor toolchains, which ajv strict mode would
629
- * otherwise reject:
849
+ * The one owner of the declared non-standard keyword families, in two
850
+ * groups.
851
+ *
852
+ * **Upstream language-server families** — mirrored from SchemaStore's
853
+ * CONTRIBUTING, the keyword sets legitimately consumed by editor
854
+ * toolchains that ajv strict mode would otherwise reject:
630
855
  *
631
856
  * - **vscode-json-languageservice** (exact names): `allowTrailingCommas`,
632
857
  * `defaultSnippets`, `enumDescriptions`, `markdownDescription`,
@@ -639,241 +864,67 @@ declare class DocumentLint {
639
864
  * - **IntelliJ**: the `x-intellij-` prefix (`x-intellij-language-injection`,
640
865
  * `x-intellij-html-description`, `x-intellij-enum-metadata`).
641
866
  *
867
+ * **The house machine-annotation family** — `x-ai-` (WITH the trailing
868
+ * dash; bare `x-ai` and a look-alike prefix like `x-aida-foo` are NOT
869
+ * declared), owned by this package rather than mirrored from anywhere:
870
+ *
871
+ * - It is a NAMESPACE, not a vocabulary — any `x-ai-*` key is declared, and
872
+ * this package does not enumerate specific keys.
873
+ * - The key itself must be one ajv can register: after the prefix, only
874
+ * `[A-Za-z0-9_$:-]` (ajv holds a keyword name to
875
+ * `/^[a-z_$][a-z0-9_$:-]*$/i`). A dot, a space, a slash, an `@`, a `+` or
876
+ * any non-ASCII character makes the engine gate reject the whole document
877
+ * — as a root-pathed `ValidationFinding`, not an error.
878
+ * - A value under a declared `x-ai-*` key must be JSON — `CanonicalJson`
879
+ * fails typed (`NonJsonValueError`) on anything else, the same as
880
+ * every other emitted value.
881
+ * - The one recommended, non-binding key is `x-ai-hint`: a string carrying
882
+ * an instruction to a machine reader about the annotated value.
883
+ * - `x-ai-example` is deliberately NOT recommended. Draft-07's own
884
+ * `examples` keyword already exists, is carried by the assembly, and
885
+ * classifies as a CONTRACT change in `DocumentDiff`; an `x-ai-*`
886
+ * key classifies as ANNOTATIONS. The two would be two example channels
887
+ * with opposite version semantics.
888
+ * - A declared-family value must not contain an `$id` — or a repeated
889
+ * `$anchor` — at ANY depth, not merely as its own top-level key: ajv's
890
+ * reference collection walks unknown keywords looking for them, so a
891
+ * colliding one buried anywhere inside an annotation payload fails the
892
+ * compile, surfacing as a blocking root-pathed `ValidationFinding` rather
893
+ * than a silent no-op. An empty-string `$id` collides too — it resolves
894
+ * to the root id.
895
+ * - No upstream tool sanctions `x-ai-`: a document carrying it that is
896
+ * submitted to schemastore.org needs the corresponding entry added to
897
+ * that repo's own validation config. Until then it is intended for
898
+ * self-hosted publication.
899
+ * - `DocumentDiff` classifies a delta confined to `x-ai-*` keys as
900
+ * `"annotations"`, so adopting the family on an already-published
901
+ * versioned document rewrites that file in place — correct, because
902
+ * annotations are transparently replaceable.
903
+ *
642
904
  * Both consumers of the registry route through {@link KeywordFamilies.isDeclared}:
643
905
  * `DocumentLint`'s `UnknownKeyword` check (a declared key is not flagged) and
644
- * `AnnotationCarriers` (only declared keys are re-grafted after the Draft-07
645
- * lowering). One predicate, so the lint and the carriers cannot drift.
906
+ * `StoreDocument.fromSchema`'s gate (a key outside the families fails the
907
+ * build rather than being emitted). One predicate, so the lint and the gate
908
+ * cannot drift.
646
909
  */
647
910
  /**
648
911
  * The declared non-standard keyword families as one predicate: the
649
912
  * vscode-json-languageservice set by exact name, plus the `x-taplo`,
650
- * `x-tombi-` and `x-intellij-` prefixes.
913
+ * `x-tombi-`, `x-intellij-` and `x-ai-` prefixes.
651
914
  *
652
915
  * @public
653
916
  */
654
- declare class KeywordFamilies {
917
+ export declare class KeywordFamilies {
655
918
  private constructor();
656
919
  /**
657
920
  * Whether `key` belongs to a declared non-standard keyword family.
658
921
  * Draft-07's own keywords are a separate vocabulary — this predicate
659
- * answers only for the language-server extension families.
922
+ * answers only for the language-server extension families and the
923
+ * house `x-ai-` machine-annotation namespace.
660
924
  */
661
925
  static isDeclared(key: string): boolean;
662
926
  }
663
927
  //#endregion
664
- //#region src/SchemaFile.d.ts
665
- declare const SchemaFileReadError_base: Schema.Class<SchemaFileReadError, Schema.TaggedStruct<"SchemaFileReadError", {
666
- /** The path that could not be read. */
667
- readonly path: Schema.String;
668
- /** The underlying filesystem failure, preserved structurally. */
669
- readonly cause: Schema.Defect;
670
- }>, import("effect/Cause").YieldableError>;
671
- /**
672
- * Indicates that a schema file could not be read from the filesystem (a
673
- * filesystem error other than not-found).
674
- *
675
- * @public
676
- */
677
- declare class SchemaFileReadError extends SchemaFileReadError_base {
678
- get message(): string;
679
- }
680
- declare const SchemaFileNotFoundError_base: Schema.Class<SchemaFileNotFoundError, Schema.TaggedStruct<"SchemaFileNotFoundError", {
681
- /** The path where the schema file was expected. */
682
- readonly path: Schema.String;
683
- }>, import("effect/Cause").YieldableError>;
684
- /**
685
- * Indicates that no schema file exists at the expected path. Carries its
686
- * own tag for `catchTag` routing.
687
- *
688
- * @public
689
- */
690
- declare class SchemaFileNotFoundError extends SchemaFileNotFoundError_base {
691
- get message(): string;
692
- }
693
- declare const SchemaFileWriteError_base: Schema.Class<SchemaFileWriteError, Schema.TaggedStruct<"SchemaFileWriteError", {
694
- /** The path that could not be written. */
695
- readonly path: Schema.String;
696
- /** The underlying filesystem failure, preserved structurally. */
697
- readonly cause: Schema.Defect;
698
- }>, import("effect/Cause").YieldableError>;
699
- /**
700
- * Indicates that a schema file could not be written to the filesystem.
701
- * Narrowed to the filesystem failure only — a serialization failure
702
- * surfaces as its own `CanonicalJsonError`, never wrapped here.
703
- *
704
- * @public
705
- */
706
- declare class SchemaFileWriteError extends SchemaFileWriteError_base {
707
- get message(): string;
708
- }
709
- /**
710
- * What {@link SchemaFileShape.write} did to the filesystem: `"written"`
711
- * when it wrote, `"unchanged"` when it left the file alone — reported as a
712
- * value so the caller decides what to surface, never a log.
713
- *
714
- * @public
715
- */
716
- type WriteOutcome = "written" | "unchanged";
717
- /**
718
- * How the document being written relates to what was already on disk:
719
- * {@link SchemaChange} plus `"created"` for a file that did not exist, so
720
- * there was nothing to compare against.
721
- *
722
- * @public
723
- */
724
- type WriteChange = SchemaChange | "created";
725
- /**
726
- * The result of {@link SchemaFileShape.write}: what happened to the file,
727
- * and what the difference MEANT.
728
- *
729
- * The two are independent on purpose. `change` answers the versioning
730
- * question — `"annotations"` means only prose and editor affordances moved,
731
- * so the document replaces its predecessor transparently and needs no new
732
- * {@link SchemaVersioning} version, while `"contract"` means an assertion
733
- * keyword moved and a consumer's document valid yesterday may be invalid
734
- * today. `outcome` answers only whether bytes were written, which under
735
- * `compare: "bytes"` can be `"written"` even when `change` is `"none"`.
736
- *
737
- * @public
738
- */
739
- interface WriteResult {
740
- /**
741
- * Whether the file was written. **This is the authoritative answer to
742
- * "did the filesystem get touched"** — always, under either `compare`
743
- * mode. Do not infer it from `change`: under `compare: "bytes"` a
744
- * `change` of `"none"` still writes.
745
- */
746
- readonly outcome: WriteOutcome;
747
- /** What differs between the previous content and the new document. */
748
- readonly change: WriteChange;
749
- }
750
- /**
751
- * The result of {@link SchemaFileShape.check}: the same two answers
752
- * {@link WriteResult} carries, for a call that touched nothing.
753
- *
754
- * `wouldWrite` is `outcome`'s counterpart — it honors `compare`, so it
755
- * answers "would `write` do anything with these same options", which
756
- * `change` alone cannot under `compare: "bytes"`.
757
- *
758
- * @public
759
- */
760
- interface CheckResult {
761
- /** Whether a `write` with the same options would touch the file. */
762
- readonly wouldWrite: boolean;
763
- /** What differs between the on-disk content and the new document. */
764
- readonly change: WriteChange;
765
- }
766
- /**
767
- * Options for {@link SchemaFileShape.write} and
768
- * {@link SchemaFileShape.check}: the {@link CanonicalJsonOptions} the
769
- * document serializes under, plus how `write` decides whether to touch the
770
- * file.
771
- *
772
- * @public
773
- */
774
- interface SchemaWriteOptions extends CanonicalJsonOptions {
775
- /**
776
- * How `write` decides the file needs rewriting:
777
- *
778
- * - `"value"` (the default) — compare the parsed content. Immune to any
779
- * other tool that reformats the file, which is the common case: a repo
780
- * whose pre-commit hook runs Biome or Prettier over `*.json` would
781
- * otherwise see every run rewrite the file forever, because the
782
- * formatter's bytes never match `CanonicalJson`'s.
783
- * - `"bytes"` — compare the exact text, so the file on disk is only ever
784
- * `CanonicalJson`'s own output. Choose this when the emitted bytes are
785
- * themselves the artifact and no other tool is allowed to touch them.
786
- *
787
- * `change` in the {@link WriteResult} is classified by content either
788
- * way; this option decides only whether a byte-level difference is
789
- * enough to rewrite.
790
- */
791
- readonly compare?: "bytes" | "value";
792
- }
793
- /**
794
- * The shape of the {@link SchemaFile} service — the value produced by
795
- * {@link SchemaFile.make} and carried by its layer.
796
- *
797
- * @public
798
- */
799
- interface SchemaFileShape {
800
- /**
801
- * Read a schema file's exact text (the drift-test read side: compare it
802
- * against `StoreDocument.serializeResult`). Fails with
803
- * `SchemaFileNotFoundError` (ENOENT) or `SchemaFileReadError` (other
804
- * filesystem errors).
805
- */
806
- readonly read: (path: string) => Effect.Effect<string, SchemaFileReadError | SchemaFileNotFoundError>;
807
- /**
808
- * Serialize a document to canonical JSON and write it **only if the
809
- * on-disk content differs** (a missing file counts as different),
810
- * creating parent directories as needed. Answers a {@link WriteResult}
811
- * as a value: what happened to the file, and what the difference meant.
812
- * Fails with a `CanonicalJsonError` (the document does not serialize),
813
- * `SchemaFileReadError` (the existing content could not be read for
814
- * comparison) or `SchemaFileWriteError` (the filesystem write failed).
815
- */
816
- readonly write: (path: string, document: StoreDocument, options?: SchemaWriteOptions) => Effect.Effect<WriteResult, CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError>;
817
- /**
818
- * The same comparison {@link SchemaFileShape.write} makes, **without
819
- * touching the filesystem** — the drift-check half of the pair, for a
820
- * CI job that must assert a committed schema is current rather than
821
- * regenerate it.
822
- *
823
- * Answers both questions the writer answers: `change` classifies the
824
- * content (immune to a formatter having reflowed the committed file),
825
- * and `wouldWrite` honors `compare`, so it agrees with `write` under
826
- * either mode. Checking drift is `change`; predicting the writer is
827
- * `wouldWrite`.
828
- */
829
- readonly check: (path: string, document: StoreDocument, options?: SchemaWriteOptions) => Effect.Effect<CheckResult, CanonicalJsonError | SchemaFileReadError>;
830
- }
831
- declare const SchemaFile_base: Context.ServiceClass<SchemaFile, "@effected/schemastore/SchemaFile", SchemaFileShape>;
832
- /**
833
- * Reads and writes emitted schema documents over core `FileSystem` /
834
- * `Path` — the package's one IO surface. The layer requires those
835
- * services; provide `@effect/platform-node`'s `NodeFileSystem` / `NodePath`
836
- * (or a bun equivalent) at the application boundary.
837
- *
838
- * `write` is write-if-changed, and by default compares **content**: an
839
- * unchanged document never touches the file even if another tool has
840
- * reformatted it, so a generator committed to a repo whose pre-commit hook
841
- * formats JSON does not churn on every run. It also reports what the
842
- * difference meant — `"annotations"` (prose only, replaces its predecessor
843
- * transparently) versus `"contract"` (an assertion moved, so a new
844
- * `SchemaVersioning` version is warranted). `check` makes the same
845
- * comparison without writing, which is what a CI drift job wants.
846
- *
847
- * @example
848
- * ```ts
849
- * import { SchemaFile, StoreDocument } from "@effected/schemastore";
850
- * import { NodeFileSystem, NodePath } from "@effect/platform-node";
851
- * import { Effect, Layer, Schema } from "effect";
852
- *
853
- * const program = Effect.gen(function* () {
854
- * const files = yield* SchemaFile;
855
- * const document = yield* StoreDocument.fromSchema(Schema.Struct({ name: Schema.String }), {
856
- * $id: "https://example.com/config.schema.json",
857
- * });
858
- * return yield* files.write("schemas/config.schema.json", document);
859
- * }).pipe(
860
- * Effect.provide(SchemaFile.layer),
861
- * Effect.provide(Layer.mergeAll(NodeFileSystem.layer, NodePath.layer)),
862
- * );
863
- * ```
864
- *
865
- * @public
866
- */
867
- declare class SchemaFile extends SchemaFile_base {
868
- /** Build the service implementation from `FileSystem` / `Path` in context; use {@link SchemaFile.layer} to provide it. */
869
- static readonly make: Effect.Effect<SchemaFileShape, never, FileSystem.FileSystem | Path.Path>;
870
- /**
871
- * The live layer. Requires core `FileSystem` / `Path`, provided by the
872
- * consumer's platform implementation at the edge.
873
- */
874
- static readonly layer: Layer.Layer<SchemaFile, never, FileSystem.FileSystem | Path.Path>;
875
- }
876
- //#endregion
877
928
  //#region src/SchemaTarget.d.ts
878
929
  /**
879
930
  * A single schema publication target: an Effect Schema source paired with
@@ -886,7 +937,7 @@ declare class SchemaFile extends SchemaFile_base {
886
937
  *
887
938
  * @public
888
939
  */
889
- interface SchemaTarget {
940
+ export interface SchemaTarget {
890
941
  /** The Effect Schema source the document is generated from. */
891
942
  readonly schema: Schema.Constraint;
892
943
  /** The canonical `$id` URL the generated document declares. */
@@ -903,7 +954,20 @@ interface SchemaTarget {
903
954
  readonly name?: string;
904
955
  /** The destination path the document is written to (`SchemaFile`). */
905
956
  readonly path: string;
906
- /** The version label, for versioned catalog mode. Omit for unversioned. */
957
+ /**
958
+ * The version label, for versioned catalog mode. Omit for unversioned.
959
+ *
960
+ * It carries a second meaning the catalog does not: presence of a
961
+ * **pinned** label (one with no prerelease) declares that consumers pin
962
+ * this document's URL, so `SchemaPipeline.run` refuses to rewrite it in
963
+ * place when its validation contract changes — bump `version`, `$id` and
964
+ * `path` together instead, or pass `contractChanges: "allow"`. That is
965
+ * only coherent when the version participates in `path`
966
+ * (`schemas/<version>/<name>-<version>.json`): a versioned target at a
967
+ * fixed path compares the same file forever, and bumping `version` does
968
+ * not move it. A prerelease label declares its own instability and is
969
+ * rewritten in place.
970
+ */
907
971
  readonly version?: SchemaVersion;
908
972
  }
909
973
  /**
@@ -911,7 +975,7 @@ interface SchemaTarget {
911
975
  *
912
976
  * @public
913
977
  */
914
- declare class SchemaTarget {
978
+ export declare class SchemaTarget {
915
979
  private constructor();
916
980
  /**
917
981
  * Builds an unversioned target. `name` is optional — only catalog
@@ -954,7 +1018,7 @@ declare const SchemaValidatorError_base: Schema.Class<SchemaValidatorError, Sche
954
1018
  *
955
1019
  * @public
956
1020
  */
957
- declare class SchemaValidatorError extends SchemaValidatorError_base {
1021
+ export declare class SchemaValidatorError extends SchemaValidatorError_base {
958
1022
  get message(): string;
959
1023
  }
960
1024
  declare const ValidationFinding_base: Schema.Class<ValidationFinding, Schema.Struct<{
@@ -972,7 +1036,7 @@ declare const ValidationFinding_base: Schema.Class<ValidationFinding, Schema.Str
972
1036
  *
973
1037
  * @public
974
1038
  */
975
- declare class ValidationFinding extends ValidationFinding_base {}
1039
+ export declare class ValidationFinding extends ValidationFinding_base {}
976
1040
  /**
977
1041
  * Options for {@link SchemaValidatorShape.validate}.
978
1042
  *
@@ -1038,16 +1102,19 @@ declare const SchemaValidator_base: Context.ServiceClass<SchemaValidator, "@effe
1038
1102
  *
1039
1103
  * @public
1040
1104
  */
1041
- declare class SchemaValidator extends SchemaValidator_base {
1105
+ export declare class SchemaValidator extends SchemaValidator_base {
1042
1106
  /**
1043
1107
  * The shipped ajv implementation — the default a consumer provides.
1044
1108
  *
1045
1109
  * `validate` checks the document against the Draft-07 meta-schema and
1046
1110
  * then compiles it, reporting BOTH as {@link ValidationFinding} values:
1047
1111
  * meta-schema failures keep ajv's structured `instancePath` and
1048
- * `keyword`, while a strict-mode rejection (which ajv raises by throwing
1049
- * at compile time) becomes a root-pathed finding. The error channel
1050
- * stays reserved for the engine failing as a mechanism.
1112
+ * `keyword`, while a rejection ajv raises by *throwing* becomes a
1113
+ * root-pathed finding both a strict-mode compile failure and a
1114
+ * declared keyword whose NAME ajv's own grammar
1115
+ * (`/^[a-z_$][a-z0-9_$:-]*$/i`) refuses, such as an `x-ai-*` key
1116
+ * carrying a dot or a space. The error channel stays reserved for the
1117
+ * engine failing as a mechanism.
1051
1118
  *
1052
1119
  * `strict` defaults to `true` — SchemaStore's gate. Each call builds its
1053
1120
  * own ajv instance, so documents sharing an `$id` never collide.
@@ -1094,7 +1161,7 @@ declare const PipelineFinding_base: Schema.Class<PipelineFinding, Schema.Struct<
1094
1161
  *
1095
1162
  * @public
1096
1163
  */
1097
- declare class PipelineFinding extends PipelineFinding_base {
1164
+ export declare class PipelineFinding extends PipelineFinding_base {
1098
1165
  /**
1099
1166
  * What to call this finding when rendering it: the check name when the
1100
1167
  * gate named one, the gate itself otherwise.
@@ -1118,7 +1185,64 @@ declare const SchemaGateError_base: Schema.Class<SchemaGateError, Schema.TaggedS
1118
1185
  *
1119
1186
  * @public
1120
1187
  */
1121
- declare class SchemaGateError extends SchemaGateError_base {
1188
+ export declare class SchemaGateError extends SchemaGateError_base {
1189
+ get message(): string;
1190
+ }
1191
+ /**
1192
+ * How {@link SchemaPipeline.run} treats a target whose document would change
1193
+ * its validation contract.
1194
+ *
1195
+ * - `"block-versioned"` (the default) — a target carrying a PINNED `version`
1196
+ * ({@link SchemaVersioning.isPinned}) is a published, URL-pinned document:
1197
+ * a `"contract"` change fails with {@link SchemaContractChangeError} BEFORE
1198
+ * any write. A target with no `version`, or with a prerelease label, is a
1199
+ * document that replaces its predecessor in place and is rewritten as
1200
+ * before.
1201
+ * - `"allow"` — classify and report only, never refuse: the pre-guard
1202
+ * behaviour. Also the sanctioned REPAIR path for a published file whose
1203
+ * text no longer parses — `SchemaFile` classifies unparseable text as
1204
+ * `"contract"` so it stays regenerable, and under the default that
1205
+ * classification is refused.
1206
+ *
1207
+ * The policy reads `change`, which is content-classified under either
1208
+ * `write.compare` mode, so `"bytes"` neither strengthens nor weakens it.
1209
+ *
1210
+ * The policy is only coherent when the version participates in `path`
1211
+ * (`schemas/<version>/<name>-<version>.json`): a versioned target at a fixed
1212
+ * path compares the same file forever, and bumping `version` does not move
1213
+ * it.
1214
+ *
1215
+ * @public
1216
+ */
1217
+ type ContractChangePolicy = "block-versioned" | "allow";
1218
+ declare const ContractChangeTarget_base: Schema.Class<ContractChangeTarget, Schema.Struct<{
1219
+ /** The target's `$id`. */
1220
+ readonly $id: Schema.String;
1221
+ /** The path the document would have been written to. */
1222
+ readonly path: Schema.String;
1223
+ /** The target's pinned label. */
1224
+ readonly version: Schema.brand<Schema.String, "SchemaVersion">;
1225
+ /** The label to publish under instead — {@link SchemaVersioning.next} of `version`. */
1226
+ readonly nextVersion: Schema.brand<Schema.String, "SchemaVersion">;
1227
+ }>, {}>;
1228
+ /**
1229
+ * One published document whose validation contract would change.
1230
+ *
1231
+ * @public
1232
+ */
1233
+ export declare class ContractChangeTarget extends ContractChangeTarget_base {}
1234
+ declare const SchemaContractChangeError_base: Schema.Class<SchemaContractChangeError, Schema.TaggedStruct<"SchemaContractChangeError", {
1235
+ /** Every published target whose contract would change, in target order. */
1236
+ readonly targets: Schema.$Array<typeof ContractChangeTarget>;
1237
+ }>, import("effect/Cause").YieldableError>;
1238
+ /**
1239
+ * Indicates that at least one published target's contract changed under the
1240
+ * active {@link ContractChangePolicy}. Raised BEFORE any target is written
1241
+ * and total over the targets, so two broken documents surface in one run.
1242
+ *
1243
+ * @public
1244
+ */
1245
+ export declare class SchemaContractChangeError extends SchemaContractChangeError_base {
1122
1246
  get message(): string;
1123
1247
  }
1124
1248
  /**
@@ -1161,6 +1285,17 @@ interface PipelineCheckResult {
1161
1285
  * never mistaken for clean drift.
1162
1286
  */
1163
1287
  readonly blocked: boolean;
1288
+ /**
1289
+ * Whether the {@link ContractChangePolicy} would refuse this write.
1290
+ *
1291
+ * Read it side by side with {@link PipelineCheckResult.blocked}: `blocked`
1292
+ * answers "would findings block a run under `blocking`", while
1293
+ * `contractBlocked` answers "would the contract policy refuse this write
1294
+ * under `contractChanges`". A drift test that reads `contractBlocked` can
1295
+ * print the right remedy — "regenerate" is wrong advice for a target the
1296
+ * generator will refuse; the fix is a version bump.
1297
+ */
1298
+ readonly contractBlocked: boolean;
1164
1299
  /** What differs between the on-disk content and the new document. */
1165
1300
  readonly change: WriteChange;
1166
1301
  /** Every finding, blocking or not. */
@@ -1185,16 +1320,25 @@ interface SchemaPipelineOptions {
1185
1320
  *
1186
1321
  * **Which findings can actually reach you here.** A `SchemaTarget`
1187
1322
  * carries a `Schema`, so the pipeline's documents come from
1188
- * `StoreDocument.fromSchema` — and the Draft-07 lowering drops every
1189
- * keyword outside its copy-list, so an undeclared keyword never
1190
- * survives to be linted. Through this entry point `UnknownKeyword` is
1191
- * therefore effectively unreachable, and **the engine gate is what
1192
- * blocks in practice**. The lint's warning checks earn their keep on
1323
+ * `StoreDocument.fromSchema` — which never admits an undeclared
1324
+ * keyword: the pipeline supplies no `includeAnnotationKey`, and one
1325
+ * that admitted anything outside the declared families would fail the
1326
+ * build. An undeclared keyword therefore never exists to be linted.
1327
+ * Through this entry point `UnknownKeyword` is effectively unreachable,
1328
+ * and **the engine gate is what blocks in practice**. The lint's warning checks earn their keep on
1193
1329
  * documents this pipeline did not build — a hand-assembled
1194
1330
  * `StoreDocument.draft07`, or one read back off disk — and on depth,
1195
1331
  * which a schema can genuinely exceed.
1196
1332
  */
1197
1333
  readonly blocking?: (finding: PipelineFinding) => boolean;
1334
+ /**
1335
+ * How {@link SchemaPipeline.run} treats a target whose document would
1336
+ * change its validation contract. Defaults to `"block-versioned"`: a
1337
+ * target carrying a pinned `version` is refused rather than rewritten in
1338
+ * place. Pass `"allow"` to classify and report only — including to repair
1339
+ * a published file whose on-disk text no longer parses.
1340
+ */
1341
+ readonly contractChanges?: ContractChangePolicy;
1198
1342
  /** Passed through to `SchemaValidator.validate`. */
1199
1343
  readonly validator?: SchemaValidatorOptions;
1200
1344
  /** Passed through to `SchemaFile.write` / `SchemaFile.check`. */
@@ -1233,17 +1377,49 @@ interface SchemaPipelineOptions {
1233
1377
  *
1234
1378
  * @public
1235
1379
  */
1236
- declare class SchemaPipeline {
1380
+ export declare class SchemaPipeline {
1237
1381
  private constructor();
1238
1382
  /**
1239
1383
  * Run every target: build its document, gather both gates' findings,
1240
- * fail with a {@link SchemaGateError} if any block, and write otherwise.
1384
+ * fail with a {@link SchemaGateError} if any block, refuse a published
1385
+ * target whose contract changed, and write otherwise.
1241
1386
  *
1242
- * Targets are processed in order and the run stops at the first gate
1243
- * failure a document that fails its gate is not written, and neither
1244
- * are the targets after it.
1387
+ * **The run writes nothing unless every target passes both gates.** It
1388
+ * is two-phase: every target is generated, gated and (for a target the
1389
+ * {@link ContractChangePolicy} guards) compared against its predecessor
1390
+ * before any file is touched, and only then are the held documents
1391
+ * written in target order. A gate failure on the third target therefore
1392
+ * leaves the first two unwritten.
1393
+ *
1394
+ * Phase 2 itself is sequential and **not transactional**: a filesystem or
1395
+ * serialization failure part-way through it leaves the targets already
1396
+ * written in place, with no rollback. The guarantee is "no writes unless
1397
+ * every gate passes", not "every write or none".
1398
+ *
1399
+ * The gates run in a fixed precedence: {@link SchemaGateError} is
1400
+ * fail-fast on the first blocked target, because a document the engine
1401
+ * rejects would never be written under any contract policy, so its
1402
+ * classification is noise. {@link SchemaContractChangeError} is total
1403
+ * over the remaining targets, so two published documents whose contracts
1404
+ * moved surface in one run.
1405
+ *
1406
+ * @example
1407
+ * ```ts
1408
+ * import { SchemaContractChangeError, SchemaPipeline } from "@effected/schemastore";
1409
+ * import { Effect } from "effect";
1410
+ *
1411
+ * declare const targets: Parameters<typeof SchemaPipeline.run>[0];
1412
+ *
1413
+ * const program = SchemaPipeline.run(targets).pipe(
1414
+ * Effect.catchTag("SchemaContractChangeError", (error: SchemaContractChangeError) =>
1415
+ * Effect.succeed(
1416
+ * error.targets.map((target) => `${target.$id}: ${target.version} -> ${target.nextVersion}`),
1417
+ * ),
1418
+ * ),
1419
+ * );
1420
+ * ```
1245
1421
  */
1246
- static run(targets: ReadonlyArray<SchemaTarget>, options?: SchemaPipelineOptions): Effect.Effect<ReadonlyArray<PipelineResult>, SchemaGateError | SchemaConversionError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError, SchemaFile | SchemaValidator>;
1422
+ static run(targets: ReadonlyArray<SchemaTarget>, options?: SchemaPipelineOptions): Effect.Effect<ReadonlyArray<PipelineResult>, SchemaGateError | SchemaContractChangeError | SchemaConversionError | UndeclaredAnnotationKeyError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError, SchemaFile | SchemaValidator>;
1247
1423
  /**
1248
1424
  * The same walk with **no writes** — the drift-check counterpart, for a
1249
1425
  * CI job asserting the committed schemas are current.
@@ -1258,19 +1434,19 @@ declare class SchemaPipeline {
1258
1434
  * The error channel is left to the mechanisms that genuinely cannot
1259
1435
  * produce a report (generation, serialization, the engine, the read).
1260
1436
  */
1261
- static check(targets: ReadonlyArray<SchemaTarget>, options?: SchemaPipelineOptions): Effect.Effect<ReadonlyArray<PipelineCheckResult>, SchemaConversionError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError, SchemaFile | SchemaValidator>;
1437
+ static check(targets: ReadonlyArray<SchemaTarget>, options?: SchemaPipelineOptions): Effect.Effect<ReadonlyArray<PipelineCheckResult>, SchemaConversionError | UndeclaredAnnotationKeyError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError, SchemaFile | SchemaValidator>;
1262
1438
  /**
1263
1439
  * {@link SchemaPipeline.run} for a single target, answering its one
1264
1440
  * result directly — so a caller with one target does not index into an
1265
1441
  * array and prove to the type system that element zero exists.
1266
1442
  */
1267
- static runOne(target: SchemaTarget, options?: SchemaPipelineOptions): Effect.Effect<PipelineResult, SchemaGateError | SchemaConversionError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError, SchemaFile | SchemaValidator>;
1443
+ static runOne(target: SchemaTarget, options?: SchemaPipelineOptions): Effect.Effect<PipelineResult, SchemaGateError | SchemaContractChangeError | SchemaConversionError | UndeclaredAnnotationKeyError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError | SchemaFileWriteError, SchemaFile | SchemaValidator>;
1268
1444
  /**
1269
1445
  * {@link SchemaPipeline.check} for a single target, answering its one
1270
1446
  * result directly.
1271
1447
  */
1272
- static checkOne(target: SchemaTarget, options?: SchemaPipelineOptions): Effect.Effect<PipelineCheckResult, SchemaConversionError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError, SchemaFile | SchemaValidator>;
1448
+ static checkOne(target: SchemaTarget, options?: SchemaPipelineOptions): Effect.Effect<PipelineCheckResult, SchemaConversionError | UndeclaredAnnotationKeyError | SchemaValidatorError | CanonicalJsonError | SchemaFileReadError, SchemaFile | SchemaValidator>;
1273
1449
  }
1274
1450
  //#endregion
1275
- export { AnnotationCarriers, CanonicalJson, type CanonicalJsonError, type CanonicalJsonOptions, CarrierDepthExceededError, CatalogEntry, CatalogLintFinding, type CatalogUrls, type CheckResult, DRAFT_07_META_SCHEMA, DocumentDiff, DocumentLint, DocumentLintFinding, InvalidSchemaVersionError, JsonDepthExceededError, KeywordFamilies, NonJsonValueError, type PipelineCheckResult, PipelineFinding, type PipelineResult, type SchemaChange, SchemaConversionError, SchemaFile, SchemaFileNotFoundError, SchemaFileReadError, type SchemaFileShape, SchemaFileWriteError, SchemaGateError, SchemaPipeline, type SchemaPipelineOptions, SchemaTarget, SchemaValidator, SchemaValidatorError, type SchemaValidatorOptions, type SchemaValidatorShape, SchemaVersion, SchemaVersioning, type SchemaWriteOptions, StoreDocument, type StoreDocumentOptions, ValidationFinding, type WriteChange, type WriteOutcome, type WriteResult };
1451
+ export type { CanonicalJsonError, CanonicalJsonOptions, CatalogUrls, CheckResult, ContractChangePolicy, PipelineCheckResult, PipelineResult, SchemaChange, SchemaFileShape, SchemaPipelineOptions, SchemaValidatorOptions, SchemaValidatorShape, SchemaWriteOptions, StoreDocumentOptions, WriteChange, WriteOutcome, WriteResult };
1276
1452
  //# sourceMappingURL=index.d.ts.map