@disclosureos/schema 2.0.0-beta.2 → 2.0.0-beta.4
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 +101 -0
- package/README.md +95 -10
- package/dist/experimental/v2/index.d.ts +4431 -81
- package/dist/experimental/v2/index.js +8010 -322
- package/dist/experimental/v2/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +34 -6
- package/schema/enriched-observation.schema.json +16 -16
- package/schema/experimental/archival-case-presentation-0.1.0.schema.json +742 -0
- package/schema/experimental/case-presentation-0.1.0.schema.json +431 -0
- package/schema/experimental/context-case-presentation-0.1.0.schema.json +697 -0
- package/schema/experimental/lidar-point-cloud-profile-0.1.0.schema.json +416 -0
- package/schema/experimental/material-case-presentation-0.1.0.schema.json +802 -0
- package/schema/experimental/passive-sonar-profile-0.1.0.schema.json +238 -0
- package/schema/experimental/product-source-selection-0.1.0.schema.json +673 -0
- package/schema/experimental/radar-profile-0.1.0.schema.json +1232 -0
- package/schema/experimental/satellite-raster-profile-0.1.0.schema.json +406 -0
- package/schema/experimental/secondary-radar-profile-0.1.0.schema.json +154 -0
- package/schema/experimental/sonar-profile-0.1.0.schema.json +197 -0
- package/schema/experimental/steered-radar-profile-0.1.0.schema.json +214 -0
- package/schema/experimental/testimony-case-presentation-0.1.0.schema.json +682 -0
- package/schema/experimental/vocabulary-bindings-0.1.0.schema.json +167 -0
- package/schema/experimental/vocabulary-catalog-0.1.0.schema.json +155 -0
- package/schema/experimental/vocabulary-term-reference-0.1.0.schema.json +61 -0
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ declare const defaultRegistry: ExtensionRegistry;
|
|
|
76
76
|
* to the enriched shape — note that bumping a *layer* schema can also change this
|
|
77
77
|
* artifact, so the drift test guards both.
|
|
78
78
|
*/
|
|
79
|
-
declare const ENRICHED_OBSERVATION_SCHEMA_VERSION = "
|
|
79
|
+
declare const ENRICHED_OBSERVATION_SCHEMA_VERSION = "2.0.0";
|
|
80
80
|
declare const ENRICHED_OBSERVATION_SCHEMA_ID: string;
|
|
81
81
|
/**
|
|
82
82
|
* Compose the enriched `Observation` JSON Schema (draft 2020-12) from the records
|
package/dist/index.js
CHANGED
|
@@ -40,7 +40,7 @@ var ExtensionRegistry = class {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
var defaultRegistry = new ExtensionRegistry();
|
|
43
|
-
var ENRICHED_OBSERVATION_SCHEMA_VERSION = "
|
|
43
|
+
var ENRICHED_OBSERVATION_SCHEMA_VERSION = "2.0.0";
|
|
44
44
|
var ENRICHED_OBSERVATION_SCHEMA_ID = schemaId(
|
|
45
45
|
"schema",
|
|
46
46
|
"enriched-observation",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/registry.ts","../src/compose.ts","../src/parse.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `ExtensionRegistry` — the runtime mirror of the TypeScript module augmentation.\n *\n * In TS, importing `@disclosureos/observables` / `@disclosureos/origins` augments\n * `Observation` with the `observableAssessments` / `origin` slots. That augmentation\n * is compile-time only — invisible to JSON Schema, Python, or any non-TS consumer.\n *\n * This registry makes the same fact available at runtime: it maps each satellite\n * slot to its owner package, canonical schema `$id`, version, and a function that\n * emits the slot's standalone JSON Schema. {@link composeObservationSchema} walks\n * the registry to fold every registered slot into one enriched `Observation` schema,\n * so adding a new first-party (or third-party) slot is a single `register()` call —\n * no edit to the composition logic OR the validation logic: {@link composeObservationSchema}\n * walks the registry for JSON Schema and `parseEnrichedObservation` walks it for runtime\n * validation, both driven entirely by what is registered.\n */\nimport type { ValidationIssue } from '@disclosureos/records/shared';\n\n/** One satellite slot on `Observation`, described for runtime composition. */\nexport interface SlotRegistration {\n /** Property name on `Observation` (e.g. `\"observableAssessments\"`, `\"origin\"`). */\n slot: string;\n /** Package that owns the slot (e.g. `\"@disclosureos/observables\"`). */\n owner: string;\n /** Canonical, versioned `$id` of the slot's standalone JSON Schema. */\n schemaId: string;\n /** Schema version of the slot (its `x-schema-version`). */\n version: string;\n /**\n * Emit the slot's standalone JSON Schema (the same enveloped artifact the owner\n * package commits). Called by {@link composeObservationSchema} during merge.\n */\n jsonSchema: () => Record<string, unknown>;\n /**\n * Validate the slot's value with the owner package's canonical, schema-backed\n * validator. Called by `parseEnrichedObservation` for every present slot, so\n * enriched validation stays brand-free (each package validates with its own Zod)\n * and registry-driven (no slot is hard-coded in the parse path).\n */\n validate: (value: unknown) => ValidationIssue[];\n}\n\n/**\n * A mutable map of `slot → registration`. Use the shared {@link defaultRegistry}\n * for the first-party slots; construct your own only for isolated tests or to\n * compose a custom subset of slots.\n */\nexport class ExtensionRegistry {\n private readonly slots = new Map<string, SlotRegistration>();\n\n /**\n * Register a slot. Throws on a duplicate slot name (one owner per slot).\n *\n * @experimental First-party slots (observables, origins) are registered for you\n * on {@link defaultRegistry}. Registering *third-party* slots is supported but the\n * extensibility contract (how external slots compose, version, and resolve) is\n * still settling and may change in a minor release.\n */\n register(registration: SlotRegistration): this {\n if (this.slots.has(registration.slot)) {\n const existing = this.slots.get(registration.slot)!;\n throw new Error(\n `Slot \"${registration.slot}\" is already registered by ${existing.owner}; `\n + `cannot re-register it for ${registration.owner}.`,\n );\n }\n this.slots.set(registration.slot, registration);\n return this;\n }\n\n /** Look up a slot's registration, or `undefined` if not registered. */\n get(slot: string): SlotRegistration | undefined {\n return this.slots.get(slot);\n }\n\n /** Whether a slot is registered. */\n has(slot: string): boolean {\n return this.slots.has(slot);\n }\n\n /** All registrations, in insertion order. */\n list(): SlotRegistration[] {\n return [...this.slots.values()];\n }\n}\n\n/**\n * The shared registry, pre-populated with the first-party satellite slots. Import\n * sites that need the full enriched contract should use this; it is the runtime\n * counterpart to importing both satellite packages for their TS augmentation.\n */\nexport const defaultRegistry = new ExtensionRegistry();\n","/**\n * `composeObservationSchema()` — fold the records core schema and every registered\n * satellite slot schema into one enriched `Observation` JSON Schema.\n *\n * This is the **portable contract**: the single artifact that means the same thing\n * in TypeScript, JSON Schema, Python, and the docs. The records core schema is\n * deliberately OPEN (`additionalProperties: true`) because its satellite slots\n * attach via augmentation; here we fold those slots back in as real properties and\n * TIGHTEN the root to `additionalProperties: false` — unknown top-level keys are\n * rejected, while the `extensions` bag (a named property) still carries arbitrary\n * third-party data.\n *\n * Composition is a brand-free, plain-data merge: each layer's committed JSON Schema\n * (records + the slots from {@link defaultRegistry}) is merged by `$defs` name. The\n * three layers own disjoint `$defs` (records: `Observation`/`Temporal`/…;\n * observables: `ObservableAssessmentMap`/…; origins: `OriginClaim`/…), so the merge\n * needs no `$ref` rewriting; a collision throws loudly rather than silently winning.\n */\nimport { recordsJsonSchema } from '@disclosureos/records';\nimport { schemaId, jsonSchemaEnvelope } from '@disclosureos/records/shared';\nimport {\n observablesJsonSchema,\n validateObservableAssessments,\n OBSERVABLES_SCHEMA_ID,\n OBSERVABLES_SCHEMA_VERSION,\n} from '@disclosureos/observables';\nimport {\n originsJsonSchema,\n validateOriginClassification,\n ORIGINS_SCHEMA_ID,\n ORIGINS_SCHEMA_VERSION,\n} from '@disclosureos/origins';\nimport { defaultRegistry, ExtensionRegistry } from './registry';\n\n/**\n * Version of the emitted composed-schema artifact. Bump on any intentional change\n * to the enriched shape — note that bumping a *layer* schema can also change this\n * artifact, so the drift test guards both.\n */\nexport const ENRICHED_OBSERVATION_SCHEMA_VERSION = '1.1.0';\n\nexport const ENRICHED_OBSERVATION_SCHEMA_ID = schemaId(\n 'schema',\n 'enriched-observation',\n ENRICHED_OBSERVATION_SCHEMA_VERSION,\n);\n\n// Runtime mirror of the TS augmentation: register the first-party slots once, at\n// module load. Importing `@disclosureos/schema` is the runtime counterpart to\n// importing both satellite packages for their compile-time augmentation.\ndefaultRegistry\n .register({\n slot: 'observableAssessments',\n owner: '@disclosureos/observables',\n schemaId: OBSERVABLES_SCHEMA_ID,\n version: OBSERVABLES_SCHEMA_VERSION,\n jsonSchema: observablesJsonSchema,\n validate: validateObservableAssessments,\n })\n .register({\n slot: 'origin',\n owner: '@disclosureos/origins',\n schemaId: ORIGINS_SCHEMA_ID,\n version: ORIGINS_SCHEMA_VERSION,\n jsonSchema: originsJsonSchema,\n validate: validateOriginClassification,\n });\n\n/** Strip the standard envelope (`$schema`/`$id`/`x-schema-version`) and pull `$defs` off a slot schema. */\nfunction splitSlotSchema(schema: Record<string, unknown>): {\n body: Record<string, unknown>;\n defs: Record<string, unknown>;\n} {\n const { $schema, $id, 'x-schema-version': _version, $defs, ...body } = schema as Record<\n string,\n unknown\n > & { $defs?: Record<string, unknown> };\n void $schema;\n void $id;\n void _version;\n return { body, defs: $defs ?? {} };\n}\n\n/**\n * Compose the enriched `Observation` JSON Schema (draft 2020-12) from the records\n * core plus every slot in `registry` (defaults to the first-party\n * {@link defaultRegistry}).\n *\n * The result is the standard enveloped artifact: a `$ref` to `#/$defs/Observation`,\n * where `Observation` carries the records core properties plus one property per\n * registered slot, and `additionalProperties: false` rejects unknown top-level keys.\n */\nexport function composeObservationSchema(\n registry: ExtensionRegistry = defaultRegistry,\n): Record<string, unknown> {\n const records = recordsJsonSchema();\n const defs = structuredClone(records.$defs ?? {}) as Record<string, Record<string, unknown>>;\n\n const observation = defs['Observation'];\n if (!observation) {\n throw new Error('records schema is missing the \"Observation\" $def; cannot compose.');\n }\n\n const slotProperties: Record<string, unknown> = {};\n\n for (const registration of registry.list()) {\n const { body, defs: slotDefs } = splitSlotSchema(registration.jsonSchema());\n\n for (const [name, def] of Object.entries(slotDefs)) {\n if (name in defs) {\n throw new Error(\n `$defs collision composing enriched schema: \"${name}\" is defined by both `\n + `the records core and ${registration.owner}. Slots must own disjoint $defs.`,\n );\n }\n defs[name] = def as Record<string, unknown>;\n }\n\n slotProperties[registration.slot] = body;\n }\n\n // Fold the slots in as real properties and close the root: unknown top-level keys\n // are rejected; the `extensions` bag (a named property) keeps the third-party seam.\n observation['properties'] = {\n ...(observation['properties'] as Record<string, unknown> | undefined),\n ...slotProperties,\n };\n observation['additionalProperties'] = false;\n\n const composed = {\n description:\n 'A complete DisclosureOS observation: the records core enriched with observable '\n + 'assessments and origin classification. The portable contract across TypeScript, '\n + 'JSON Schema, and other languages.',\n $ref: '#/$defs/Observation',\n $defs: defs,\n };\n\n return jsonSchemaEnvelope(composed, {\n id: ENRICHED_OBSERVATION_SCHEMA_ID,\n version: ENRICHED_OBSERVATION_SCHEMA_VERSION,\n });\n}\n","/**\n * `parseEnrichedObservation()` — the non-stripping validation entry point.\n *\n * The records core `ObservationSchema` does not know about the satellite slots, so\n * a raw `ObservationSchema.parse(record)` SILENTLY DROPS `observableAssessments` and\n * `origin` (the A1 \"strip hazard\"). This function closes that hazard at the\n * integration layer: it validates the core and each present slot with the SAME\n * canonical validators each package ships, rejects unknown top-level keys, and\n * returns the caller's object untouched on success — slots intact.\n *\n * It composes by delegation (not by re-parsing through one mega-Zod-object), so it\n * is brand-free: each package validates its own slot with its own Zod instance,\n * exactly as the CLI does.\n */\nimport { validateObservation } from '@disclosureos/records';\nimport type { Observation } from '@disclosureos/records';\nimport type { ValidationIssue } from '@disclosureos/records/shared';\nimport { composeObservationSchema } from './compose';\nimport { defaultRegistry } from './registry';\n\n/**\n * A complete observation: the records core plus the satellite slots. Because both\n * satellite packages augment `Observation`, the slots are already part of the\n * `Observation` type wherever `@disclosureos/schema` (which imports both) is loaded;\n * this alias names that enriched shape explicitly as the public contract type.\n */\nexport type EnrichedObservation = Observation;\n\n/** Outcome of {@link parseEnrichedObservation}: issues are empty iff `success`. */\nexport interface EnrichedParseResult {\n success: boolean;\n /** The validated record (reference-equal to the input) when `success`. */\n data?: EnrichedObservation;\n /** Flat list of validation issues (empty when valid). */\n issues: ValidationIssue[];\n}\n\n/** Prefix slot-local issue paths with the slot name so errors point at the right field. */\nfunction underSlot(slot: string, issues: ValidationIssue[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? `${slot}.${issue.path}` : slot,\n message: issue.message,\n }));\n}\n\n// The composed schema is the single source of truth for which top-level keys are\n// allowed (records core properties + every registered slot). Computed once.\nlet allowedTopLevelKeys: Set<string> | undefined;\nfunction getAllowedTopLevelKeys(): Set<string> {\n if (!allowedTopLevelKeys) {\n const composed = composeObservationSchema();\n const observation = (composed.$defs as Record<string, Record<string, unknown>>)['Observation'];\n const properties = (observation?.['properties'] as Record<string, unknown>) ?? {};\n allowedTopLevelKeys = new Set(Object.keys(properties));\n }\n return allowedTopLevelKeys;\n}\n\n/**\n * Validate an enriched observation (records core + `observableAssessments` + `origin`)\n * in one call, WITHOUT stripping the satellite slots.\n *\n * Returns `{ success: true, data }` (where `data` is the same object you passed in)\n * when valid, or `{ success: false, issues }` with a flat list of path-tagged issues.\n * Unknown top-level keys are rejected; arbitrary data still belongs under `extensions`.\n */\nexport function parseEnrichedObservation(value: unknown): EnrichedParseResult {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return { success: false, issues: [{ path: '', message: 'expected an observation object' }] };\n }\n\n const record = value as Record<string, unknown>;\n const issues: ValidationIssue[] = [];\n\n issues.push(...validateObservation(record));\n\n // Validate every present slot with its owner's validator — driven by the registry,\n // so a newly registered slot is validated here without editing this function.\n for (const registration of defaultRegistry.list()) {\n const slotValue = record[registration.slot];\n if (slotValue !== undefined) {\n issues.push(...underSlot(registration.slot, registration.validate(slotValue)));\n }\n }\n\n const allowed = getAllowedTopLevelKeys();\n for (const key of Object.keys(record)) {\n if (!allowed.has(key)) {\n issues.push({\n path: key,\n message: `unknown top-level key \"${key}\" — third-party data belongs under \"extensions\".`,\n });\n }\n }\n\n if (issues.length > 0) {\n return { success: false, issues };\n }\n return { success: true, data: record as unknown as EnrichedObservation, issues: [] };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/registry.ts","../src/compose.ts","../src/parse.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `ExtensionRegistry` — the runtime mirror of the TypeScript module augmentation.\n *\n * In TS, importing `@disclosureos/observables` / `@disclosureos/origins` augments\n * `Observation` with the `observableAssessments` / `origin` slots. That augmentation\n * is compile-time only — invisible to JSON Schema, Python, or any non-TS consumer.\n *\n * This registry makes the same fact available at runtime: it maps each satellite\n * slot to its owner package, canonical schema `$id`, version, and a function that\n * emits the slot's standalone JSON Schema. {@link composeObservationSchema} walks\n * the registry to fold every registered slot into one enriched `Observation` schema,\n * so adding a new first-party (or third-party) slot is a single `register()` call —\n * no edit to the composition logic OR the validation logic: {@link composeObservationSchema}\n * walks the registry for JSON Schema and `parseEnrichedObservation` walks it for runtime\n * validation, both driven entirely by what is registered.\n */\nimport type { ValidationIssue } from '@disclosureos/records/shared';\n\n/** One satellite slot on `Observation`, described for runtime composition. */\nexport interface SlotRegistration {\n /** Property name on `Observation` (e.g. `\"observableAssessments\"`, `\"origin\"`). */\n slot: string;\n /** Package that owns the slot (e.g. `\"@disclosureos/observables\"`). */\n owner: string;\n /** Canonical, versioned `$id` of the slot's standalone JSON Schema. */\n schemaId: string;\n /** Schema version of the slot (its `x-schema-version`). */\n version: string;\n /**\n * Emit the slot's standalone JSON Schema (the same enveloped artifact the owner\n * package commits). Called by {@link composeObservationSchema} during merge.\n */\n jsonSchema: () => Record<string, unknown>;\n /**\n * Validate the slot's value with the owner package's canonical, schema-backed\n * validator. Called by `parseEnrichedObservation` for every present slot, so\n * enriched validation stays brand-free (each package validates with its own Zod)\n * and registry-driven (no slot is hard-coded in the parse path).\n */\n validate: (value: unknown) => ValidationIssue[];\n}\n\n/**\n * A mutable map of `slot → registration`. Use the shared {@link defaultRegistry}\n * for the first-party slots; construct your own only for isolated tests or to\n * compose a custom subset of slots.\n */\nexport class ExtensionRegistry {\n private readonly slots = new Map<string, SlotRegistration>();\n\n /**\n * Register a slot. Throws on a duplicate slot name (one owner per slot).\n *\n * @experimental First-party slots (observables, origins) are registered for you\n * on {@link defaultRegistry}. Registering *third-party* slots is supported but the\n * extensibility contract (how external slots compose, version, and resolve) is\n * still settling and may change in a minor release.\n */\n register(registration: SlotRegistration): this {\n if (this.slots.has(registration.slot)) {\n const existing = this.slots.get(registration.slot)!;\n throw new Error(\n `Slot \"${registration.slot}\" is already registered by ${existing.owner}; `\n + `cannot re-register it for ${registration.owner}.`,\n );\n }\n this.slots.set(registration.slot, registration);\n return this;\n }\n\n /** Look up a slot's registration, or `undefined` if not registered. */\n get(slot: string): SlotRegistration | undefined {\n return this.slots.get(slot);\n }\n\n /** Whether a slot is registered. */\n has(slot: string): boolean {\n return this.slots.has(slot);\n }\n\n /** All registrations, in insertion order. */\n list(): SlotRegistration[] {\n return [...this.slots.values()];\n }\n}\n\n/**\n * The shared registry, pre-populated with the first-party satellite slots. Import\n * sites that need the full enriched contract should use this; it is the runtime\n * counterpart to importing both satellite packages for their TS augmentation.\n */\nexport const defaultRegistry = new ExtensionRegistry();\n","/**\n * `composeObservationSchema()` — fold the records core schema and every registered\n * satellite slot schema into one enriched `Observation` JSON Schema.\n *\n * This is the **portable contract**: the single artifact that means the same thing\n * in TypeScript, JSON Schema, Python, and the docs. The records core schema is\n * deliberately OPEN (`additionalProperties: true`) because its satellite slots\n * attach via augmentation; here we fold those slots back in as real properties and\n * TIGHTEN the root to `additionalProperties: false` — unknown top-level keys are\n * rejected, while the `extensions` bag (a named property) still carries arbitrary\n * third-party data.\n *\n * Composition is a brand-free, plain-data merge: each layer's committed JSON Schema\n * (records + the slots from {@link defaultRegistry}) is merged by `$defs` name. The\n * three layers own disjoint `$defs` (records: `Observation`/`Temporal`/…;\n * observables: `ObservableAssessmentMap`/…; origins: `OriginClaim`/…), so the merge\n * needs no `$ref` rewriting; a collision throws loudly rather than silently winning.\n */\nimport { recordsJsonSchema } from '@disclosureos/records';\nimport { schemaId, jsonSchemaEnvelope } from '@disclosureos/records/shared';\nimport {\n observablesJsonSchema,\n validateObservableAssessments,\n OBSERVABLES_SCHEMA_ID,\n OBSERVABLES_SCHEMA_VERSION,\n} from '@disclosureos/observables';\nimport {\n originsJsonSchema,\n validateOriginClassification,\n ORIGINS_SCHEMA_ID,\n ORIGINS_SCHEMA_VERSION,\n} from '@disclosureos/origins';\nimport { defaultRegistry, ExtensionRegistry } from './registry';\n\n/**\n * Version of the emitted composed-schema artifact. Bump on any intentional change\n * to the enriched shape — note that bumping a *layer* schema can also change this\n * artifact, so the drift test guards both.\n */\nexport const ENRICHED_OBSERVATION_SCHEMA_VERSION = '2.0.0';\n\nexport const ENRICHED_OBSERVATION_SCHEMA_ID = schemaId(\n 'schema',\n 'enriched-observation',\n ENRICHED_OBSERVATION_SCHEMA_VERSION,\n);\n\n// Runtime mirror of the TS augmentation: register the first-party slots once, at\n// module load. Importing `@disclosureos/schema` is the runtime counterpart to\n// importing both satellite packages for their compile-time augmentation.\ndefaultRegistry\n .register({\n slot: 'observableAssessments',\n owner: '@disclosureos/observables',\n schemaId: OBSERVABLES_SCHEMA_ID,\n version: OBSERVABLES_SCHEMA_VERSION,\n jsonSchema: observablesJsonSchema,\n validate: validateObservableAssessments,\n })\n .register({\n slot: 'origin',\n owner: '@disclosureos/origins',\n schemaId: ORIGINS_SCHEMA_ID,\n version: ORIGINS_SCHEMA_VERSION,\n jsonSchema: originsJsonSchema,\n validate: validateOriginClassification,\n });\n\n/** Strip the standard envelope (`$schema`/`$id`/`x-schema-version`) and pull `$defs` off a slot schema. */\nfunction splitSlotSchema(schema: Record<string, unknown>): {\n body: Record<string, unknown>;\n defs: Record<string, unknown>;\n} {\n const { $schema, $id, 'x-schema-version': _version, $defs, ...body } = schema as Record<\n string,\n unknown\n > & { $defs?: Record<string, unknown> };\n void $schema;\n void $id;\n void _version;\n return { body, defs: $defs ?? {} };\n}\n\n/**\n * Compose the enriched `Observation` JSON Schema (draft 2020-12) from the records\n * core plus every slot in `registry` (defaults to the first-party\n * {@link defaultRegistry}).\n *\n * The result is the standard enveloped artifact: a `$ref` to `#/$defs/Observation`,\n * where `Observation` carries the records core properties plus one property per\n * registered slot, and `additionalProperties: false` rejects unknown top-level keys.\n */\nexport function composeObservationSchema(\n registry: ExtensionRegistry = defaultRegistry,\n): Record<string, unknown> {\n const records = recordsJsonSchema();\n const defs = structuredClone(records.$defs ?? {}) as Record<string, Record<string, unknown>>;\n\n const observation = defs['Observation'];\n if (!observation) {\n throw new Error('records schema is missing the \"Observation\" $def; cannot compose.');\n }\n\n const slotProperties: Record<string, unknown> = {};\n\n for (const registration of registry.list()) {\n const { body, defs: slotDefs } = splitSlotSchema(registration.jsonSchema());\n\n for (const [name, def] of Object.entries(slotDefs)) {\n if (name in defs) {\n throw new Error(\n `$defs collision composing enriched schema: \"${name}\" is defined by both `\n + `the records core and ${registration.owner}. Slots must own disjoint $defs.`,\n );\n }\n defs[name] = def as Record<string, unknown>;\n }\n\n slotProperties[registration.slot] = body;\n }\n\n // Fold the slots in as real properties and close the root: unknown top-level keys\n // are rejected; the `extensions` bag (a named property) keeps the third-party seam.\n observation['properties'] = {\n ...(observation['properties'] as Record<string, unknown> | undefined),\n ...slotProperties,\n };\n observation['additionalProperties'] = false;\n\n const composed = {\n description:\n 'A complete DisclosureOS observation: the records core enriched with observable '\n + 'assessments and origin classification. The portable contract across TypeScript, '\n + 'JSON Schema, and other languages.',\n $ref: '#/$defs/Observation',\n $defs: defs,\n };\n\n return jsonSchemaEnvelope(composed, {\n id: ENRICHED_OBSERVATION_SCHEMA_ID,\n version: ENRICHED_OBSERVATION_SCHEMA_VERSION,\n });\n}\n","/**\n * `parseEnrichedObservation()` — the non-stripping validation entry point.\n *\n * The records core `ObservationSchema` does not know about the satellite slots, so\n * a raw `ObservationSchema.parse(record)` SILENTLY DROPS `observableAssessments` and\n * `origin` (the A1 \"strip hazard\"). This function closes that hazard at the\n * integration layer: it validates the core and each present slot with the SAME\n * canonical validators each package ships, rejects unknown top-level keys, and\n * returns the caller's object untouched on success — slots intact.\n *\n * It composes by delegation (not by re-parsing through one mega-Zod-object), so it\n * is brand-free: each package validates its own slot with its own Zod instance,\n * exactly as the CLI does.\n */\nimport { validateObservation } from '@disclosureos/records';\nimport type { Observation } from '@disclosureos/records';\nimport type { ValidationIssue } from '@disclosureos/records/shared';\nimport { composeObservationSchema } from './compose';\nimport { defaultRegistry } from './registry';\n\n/**\n * A complete observation: the records core plus the satellite slots. Because both\n * satellite packages augment `Observation`, the slots are already part of the\n * `Observation` type wherever `@disclosureos/schema` (which imports both) is loaded;\n * this alias names that enriched shape explicitly as the public contract type.\n */\nexport type EnrichedObservation = Observation;\n\n/** Outcome of {@link parseEnrichedObservation}: issues are empty iff `success`. */\nexport interface EnrichedParseResult {\n success: boolean;\n /** The validated record (reference-equal to the input) when `success`. */\n data?: EnrichedObservation;\n /** Flat list of validation issues (empty when valid). */\n issues: ValidationIssue[];\n}\n\n/** Prefix slot-local issue paths with the slot name so errors point at the right field. */\nfunction underSlot(slot: string, issues: ValidationIssue[]): ValidationIssue[] {\n return issues.map((issue) => ({\n path: issue.path ? `${slot}.${issue.path}` : slot,\n message: issue.message,\n }));\n}\n\n// The composed schema is the single source of truth for which top-level keys are\n// allowed (records core properties + every registered slot). Computed once.\nlet allowedTopLevelKeys: Set<string> | undefined;\nfunction getAllowedTopLevelKeys(): Set<string> {\n if (!allowedTopLevelKeys) {\n const composed = composeObservationSchema();\n const observation = (composed.$defs as Record<string, Record<string, unknown>>)['Observation'];\n const properties = (observation?.['properties'] as Record<string, unknown>) ?? {};\n allowedTopLevelKeys = new Set(Object.keys(properties));\n }\n return allowedTopLevelKeys;\n}\n\n/**\n * Validate an enriched observation (records core + `observableAssessments` + `origin`)\n * in one call, WITHOUT stripping the satellite slots.\n *\n * Returns `{ success: true, data }` (where `data` is the same object you passed in)\n * when valid, or `{ success: false, issues }` with a flat list of path-tagged issues.\n * Unknown top-level keys are rejected; arbitrary data still belongs under `extensions`.\n */\nexport function parseEnrichedObservation(value: unknown): EnrichedParseResult {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return { success: false, issues: [{ path: '', message: 'expected an observation object' }] };\n }\n\n const record = value as Record<string, unknown>;\n const issues: ValidationIssue[] = [];\n\n issues.push(...validateObservation(record));\n\n // Validate every present slot with its owner's validator — driven by the registry,\n // so a newly registered slot is validated here without editing this function.\n for (const registration of defaultRegistry.list()) {\n const slotValue = record[registration.slot];\n if (slotValue !== undefined) {\n issues.push(...underSlot(registration.slot, registration.validate(slotValue)));\n }\n }\n\n const allowed = getAllowedTopLevelKeys();\n for (const key of Object.keys(record)) {\n if (!allowed.has(key)) {\n issues.push({\n path: key,\n message: `unknown top-level key \"${key}\" — third-party data belongs under \"extensions\".`,\n });\n }\n }\n\n if (issues.length > 0) {\n return { success: false, issues };\n }\n return { success: true, data: record as unknown as EnrichedObservation, issues: [] };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@disclosureos/schema",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.4",
|
|
4
4
|
"description": "The DisclosureOS portable contract — composes the records core, observable assessments, and origin classification into one enriched Observation schema (TypeScript + JSON Schema), with a non-stripping parse",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"disclosureos",
|
|
16
16
|
"UAP",
|
|
17
17
|
"schema",
|
|
18
|
+
"docs",
|
|
18
19
|
"json-schema",
|
|
19
20
|
"observation",
|
|
20
21
|
"typescript"
|
|
@@ -66,7 +67,34 @@
|
|
|
66
67
|
"./experimental/v2/migration-legacy-scores/schema": "./schema/experimental/migration-legacy-scores-0.1.0.schema.json",
|
|
67
68
|
"./experimental/v2/migration-legacy-scores/schema/0.1.0": "./schema/experimental/migration-legacy-scores-0.1.0.schema.json",
|
|
68
69
|
"./experimental/v2/migration-compatibility/schema": "./schema/experimental/migration-compatibility-0.1.0.schema.json",
|
|
69
|
-
"./experimental/v2/migration-compatibility/schema/0.1.0": "./schema/experimental/migration-compatibility-0.1.0.schema.json"
|
|
70
|
+
"./experimental/v2/migration-compatibility/schema/0.1.0": "./schema/experimental/migration-compatibility-0.1.0.schema.json",
|
|
71
|
+
"./experimental/v2/presentation/schema/0.1.0": "./schema/experimental/case-presentation-0.1.0.schema.json",
|
|
72
|
+
"./experimental/v2/context-presentation/schema/0.1.0": "./schema/experimental/context-case-presentation-0.1.0.schema.json",
|
|
73
|
+
"./experimental/v2/testimony-presentation/schema/0.1.0": "./schema/experimental/testimony-case-presentation-0.1.0.schema.json",
|
|
74
|
+
"./experimental/v2/archival-presentation/schema/0.1.0": "./schema/experimental/archival-case-presentation-0.1.0.schema.json",
|
|
75
|
+
"./experimental/v2/material-presentation/schema/0.1.0": "./schema/experimental/material-case-presentation-0.1.0.schema.json",
|
|
76
|
+
"./experimental/v2/product-source-selection/schema": "./schema/experimental/product-source-selection-0.1.0.schema.json",
|
|
77
|
+
"./experimental/v2/product-source-selection/schema/0.1.0": "./schema/experimental/product-source-selection-0.1.0.schema.json",
|
|
78
|
+
"./experimental/v2/radar-profile/schema": "./schema/experimental/radar-profile-0.1.0.schema.json",
|
|
79
|
+
"./experimental/v2/radar-profile/schema/0.1.0": "./schema/experimental/radar-profile-0.1.0.schema.json",
|
|
80
|
+
"./experimental/v2/steered-radar-profile/schema": "./schema/experimental/steered-radar-profile-0.1.0.schema.json",
|
|
81
|
+
"./experimental/v2/steered-radar-profile/schema/0.1.0": "./schema/experimental/steered-radar-profile-0.1.0.schema.json",
|
|
82
|
+
"./experimental/v2/secondary-radar-profile/schema": "./schema/experimental/secondary-radar-profile-0.1.0.schema.json",
|
|
83
|
+
"./experimental/v2/secondary-radar-profile/schema/0.1.0": "./schema/experimental/secondary-radar-profile-0.1.0.schema.json",
|
|
84
|
+
"./experimental/v2/sonar-profile/schema": "./schema/experimental/sonar-profile-0.1.0.schema.json",
|
|
85
|
+
"./experimental/v2/sonar-profile/schema/0.1.0": "./schema/experimental/sonar-profile-0.1.0.schema.json",
|
|
86
|
+
"./experimental/v2/passive-sonar-profile/schema": "./schema/experimental/passive-sonar-profile-0.1.0.schema.json",
|
|
87
|
+
"./experimental/v2/passive-sonar-profile/schema/0.1.0": "./schema/experimental/passive-sonar-profile-0.1.0.schema.json",
|
|
88
|
+
"./experimental/v2/lidar-profile/schema": "./schema/experimental/lidar-point-cloud-profile-0.1.0.schema.json",
|
|
89
|
+
"./experimental/v2/lidar-profile/schema/0.1.0": "./schema/experimental/lidar-point-cloud-profile-0.1.0.schema.json",
|
|
90
|
+
"./experimental/v2/satellite-raster-profile/schema": "./schema/experimental/satellite-raster-profile-0.1.0.schema.json",
|
|
91
|
+
"./experimental/v2/satellite-raster-profile/schema/0.1.0": "./schema/experimental/satellite-raster-profile-0.1.0.schema.json",
|
|
92
|
+
"./experimental/v2/vocabulary-catalog/schema": "./schema/experimental/vocabulary-catalog-0.1.0.schema.json",
|
|
93
|
+
"./experimental/v2/vocabulary-catalog/schema/0.1.0": "./schema/experimental/vocabulary-catalog-0.1.0.schema.json",
|
|
94
|
+
"./experimental/v2/vocabulary-term-reference/schema": "./schema/experimental/vocabulary-term-reference-0.1.0.schema.json",
|
|
95
|
+
"./experimental/v2/vocabulary-term-reference/schema/0.1.0": "./schema/experimental/vocabulary-term-reference-0.1.0.schema.json",
|
|
96
|
+
"./experimental/v2/vocabulary-bindings/schema": "./schema/experimental/vocabulary-bindings-0.1.0.schema.json",
|
|
97
|
+
"./experimental/v2/vocabulary-bindings/schema/0.1.0": "./schema/experimental/vocabulary-bindings-0.1.0.schema.json"
|
|
70
98
|
},
|
|
71
99
|
"main": "./dist/index.js",
|
|
72
100
|
"types": "./dist/index.d.ts",
|
|
@@ -79,10 +107,10 @@
|
|
|
79
107
|
],
|
|
80
108
|
"dependencies": {
|
|
81
109
|
"zod": "4.4.3",
|
|
82
|
-
"@disclosureos/observables": "2.0.0-beta.
|
|
83
|
-
"@disclosureos/origins": "2.0.0-beta.
|
|
84
|
-
"@disclosureos/
|
|
85
|
-
"@disclosureos/
|
|
110
|
+
"@disclosureos/observables": "2.0.0-beta.4",
|
|
111
|
+
"@disclosureos/origins": "2.0.0-beta.4",
|
|
112
|
+
"@disclosureos/records": "2.0.0-beta.4",
|
|
113
|
+
"@disclosureos/instruments": "2.0.0-beta.4"
|
|
86
114
|
},
|
|
87
115
|
"devDependencies": {
|
|
88
116
|
"@types/node": "^20",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://os.disclosure.org/schema/schema/
|
|
4
|
-
"x-schema-version": "
|
|
3
|
+
"$id": "https://os.disclosure.org/schema/schema/2.0.0/enriched-observation.json",
|
|
4
|
+
"x-schema-version": "2.0.0",
|
|
5
5
|
"description": "A complete DisclosureOS observation: the records core enriched with observable assessments and origin classification. The portable contract across TypeScript, JSON Schema, and other languages.",
|
|
6
6
|
"$ref": "#/$defs/Observation",
|
|
7
7
|
"$defs": {
|
|
@@ -2609,7 +2609,7 @@
|
|
|
2609
2609
|
"measured",
|
|
2610
2610
|
"confirmed"
|
|
2611
2611
|
],
|
|
2612
|
-
"description": "
|
|
2612
|
+
"description": "Support tier describing the available information about a characteristic. It is separate from a V2 claim outcome and does not establish anomalous behavior."
|
|
2613
2613
|
},
|
|
2614
2614
|
"confidence": {
|
|
2615
2615
|
"description": "Confidence in the assessment, in [0,1]. 0 = none, 1 = absolute.",
|
|
@@ -2631,14 +2631,14 @@
|
|
|
2631
2631
|
"propertyNames": {
|
|
2632
2632
|
"type": "string",
|
|
2633
2633
|
"enum": [
|
|
2634
|
-
"
|
|
2635
|
-
"
|
|
2636
|
-
"
|
|
2637
|
-
"
|
|
2638
|
-
"
|
|
2639
|
-
"
|
|
2634
|
+
"apparent_hover",
|
|
2635
|
+
"abrupt_motion",
|
|
2636
|
+
"hypersonic_signature_discrepancy",
|
|
2637
|
+
"sensor_detection_discrepancy",
|
|
2638
|
+
"apparent_medium_transition",
|
|
2639
|
+
"event_associated_biological_changes"
|
|
2640
2640
|
],
|
|
2641
|
-
"description": "Identifier of a
|
|
2641
|
+
"description": "Identifier of a technology-related characteristic in the DisclosureOS vocabulary. No mechanism or origin is established by the category."
|
|
2642
2642
|
},
|
|
2643
2643
|
"additionalProperties": {
|
|
2644
2644
|
"type": "array",
|
|
@@ -2653,12 +2653,12 @@
|
|
|
2653
2653
|
"propertyNames": {
|
|
2654
2654
|
"type": "string",
|
|
2655
2655
|
"enum": [
|
|
2656
|
-
"
|
|
2657
|
-
"
|
|
2658
|
-
"
|
|
2659
|
-
"
|
|
2660
|
-
"
|
|
2661
|
-
"
|
|
2656
|
+
"molecular_complexity_pattern",
|
|
2657
|
+
"isotope_ratio_departure",
|
|
2658
|
+
"molecular_composition_difference",
|
|
2659
|
+
"unresolved_sequence_relationship",
|
|
2660
|
+
"unresolved_morphological_characteristics",
|
|
2661
|
+
"reported_biological_interaction"
|
|
2662
2662
|
],
|
|
2663
2663
|
"description": "Identifier of a Biologics observable."
|
|
2664
2664
|
},
|