Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
run: npm run validate
- name: Negative fixtures (must all be rejected)
run: npm run validate -- --fixtures negative
- name: lib boundary (pure imports; corpus through the import surface)
run: npm run check:lib
- name: File mode accepts a valid document
run: npm run validate -- --file examples/shadcn-ui.dspack.json
- name: File mode rejects an invalid document
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,34 @@ dspack files can also simply be written by hand — the [shadcn/ui example](exam

ds-mcp is one way to consume a dspack file, not the only way. The format is independent of MCP, independent of any specific AI agent or orchestration framework, and independent of any particular runtime environment. (On why the reference implementation is deliberately not the center of gravity, see [DESIGN.md](./DESIGN.md).)

### Validating dspack files programmatically

The validation harness behind the `dspack-validate` CLI is importable —
pure functions, schemas injected, so the identical checks run under Node or
in a browser bundle. The CLI is a front-end over this one implementation,
never a second validator:

```js
import {
compileSchemaSet,
documentReport,
} from "@aestheticfunction/dspack-spec/lib/validate.mjs";
import v04 from "@aestheticfunction/dspack-spec/schema/dspack.v0.4.schema.json" with { type: "json" };
import surface from "@aestheticfunction/dspack-spec/schema/dspack.surface.v0_1.schema.json" with { type: "json" };
Comment on lines +131 to +132

const { validators } = compileSchemaSet({
"dspack.v0.4.schema.json": v04,
"dspack.surface.v0_1.schema.json": surface,
});
const report = documentReport(doc, validators);
// { valid, version, errors } — schema gate, governance consistency,
// categories, and S1/S2 over the contract's own examples.
```

Types ship alongside (`lib/validate.d.mts`). CI's `check:lib` gate keeps the
lib pure (ajv-only imports) and replays the full example + negative-fixture
corpus through the import surface.

If you want to build a dspack reader for a different use case, the format is available under the Apache-2.0 license. Potential directions include:

- Readers for non-MCP agentic frameworks (LangChain, AutoGen, or similar)
Expand Down
54 changes: 54 additions & 0 deletions lib/validate.d.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Types for the importable validation harness (lib/validate.mjs).
* Import path (no exports map, by design — every published file stays
* reachable): "@aestheticfunction/dspack-spec/lib/validate.mjs".
*/

export declare const DSPACK_SCHEMAS: Record<string, string>;
export declare const GOVERNANCE_VERSIONS: Set<string>;
export declare const SURFACE_SCHEMA: string;

/** ajv validate function shape (kept structural to avoid an ajv type dependency). */
export interface SchemaValidator {
(data: unknown): boolean;
errors?: Array<{ instancePath?: string; message?: string }> | null;
}

export type ValidatorMap = Map<string, SchemaValidator>;

export interface CompiledSchemaSet {
validators: ValidatorMap;
failures: string[];
}

/** Compile an injected schema set: { [schemaFileName]: schemaJson }. */
export declare function compileSchemaSet(schemas: Record<string, unknown>): CompiledSchemaSet;

export interface Vocabulary {
components: Map<string, { props: Map<string, unknown>; slots: Set<string> }>;
subComponents: Map<string, string>;
duplicateSubIds: Set<string>;
}

export declare function buildVocabulary(doc: Record<string, unknown>): Vocabulary;

/** Gate S2: walk a surface tree against a contract vocabulary. Returns error strings. */
export declare function checkVocabulary(surface: Record<string, unknown>, vocab: Vocabulary): string[];

export declare function checkCategories(doc: Record<string, unknown>): string[];

export declare function checkGovernance(doc: Record<string, unknown>, validateSurface: SchemaValidator): string[];

/** The back-compat strip: a governance-version document minus its additive blocks. */
export declare function stripAdditiveBlocks(doc: Record<string, unknown>): Record<string, unknown>;

/** Fully validate one dspack document. Returns error strings (empty = valid). */
export declare function validateDocument(doc: unknown, validators: ValidatorMap): string[];

export interface DocumentReport {
valid: boolean;
version: string | undefined;
errors: string[];
}

export declare function documentReport(doc: unknown, validators: ValidatorMap): DocumentReport;
Loading
Loading