@unispechq/unispec-core 0.1.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.
@@ -0,0 +1,74 @@
1
+ name: CI & Publish UniSpec Core
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - "unispec-core-v*"
9
+ pull_request:
10
+ branches:
11
+ - main
12
+
13
+ jobs:
14
+ ci:
15
+ name: CI (install & pack)
16
+ runs-on: ubuntu-latest
17
+
18
+ steps:
19
+ - name: Checkout repo
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Use Node.js
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: 20
26
+
27
+ - name: Install dependencies
28
+ run: |
29
+ if [ -f package-lock.json ]; then
30
+ npm ci
31
+ else
32
+ npm install
33
+ fi
34
+
35
+ - name: Run tests (if defined)
36
+ run: |
37
+ if npm run | grep -q " test"; then
38
+ npm test
39
+ else
40
+ echo "No test script defined, skipping tests"
41
+ fi
42
+
43
+ - name: Verify package can be packed
44
+ run: npm pack --dry-run
45
+
46
+ publish:
47
+ name: Publish to npm
48
+ needs: ci
49
+ runs-on: ubuntu-latest
50
+ if: startsWith(github.ref, 'refs/tags/unispec-core-v')
51
+
52
+ steps:
53
+ - name: Checkout repo
54
+ uses: actions/checkout@v4
55
+
56
+ - name: Use Node.js with npm registry
57
+ uses: actions/setup-node@v4
58
+ with:
59
+ node-version: 20
60
+ registry-url: https://registry.npmjs.org
61
+ scope: "@unispechq"
62
+
63
+ - name: Install dependencies
64
+ run: |
65
+ if [ -f package-lock.json ]; then
66
+ npm ci
67
+ else
68
+ npm install
69
+ fi
70
+
71
+ - name: Publish @unispechq/unispec-core to npm
72
+ env:
73
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
74
+ run: npm publish --access public
package/.windsurfrules ADDED
@@ -0,0 +1,138 @@
1
+ # WindSurf Rules for `unispec-core`
2
+ # ---------------------------------
3
+ # This ruleset defines how AI assistants, contributors, and reviewers must
4
+ # interact with the UniSpec Core Engine repository.
5
+ # The Core Engine provides validation, parsing, normalization, diffing,
6
+ # and conversion logic for UniSpec specifications.
7
+
8
+ repository:
9
+ name: "unispec-core"
10
+ description: "Runtime implementation of the UniSpec Core Engine (loader, validator, normalizer, diff engine, converters, shared types). This repository contains only the Core Engine used by other UniSpec platform components (CLI, Registry, Portal, adapters, SDKs)."
11
+ visibility: public
12
+ criticality: core
13
+
14
+ goals:
15
+ - Implement the runtime mechanics of the UniSpec format defined in `unispec-spec`.
16
+ - Provide parsing, validation, normalization, and diffing for UniSpec documents.
17
+ - Provide reusable shared types and utilities for CLI, adapters, registry, and portal.
18
+ - Ensure strict alignment with the specification and JSON Schemas.
19
+ - Consume organization-wide context through MCP GitHub server without violating boundaries.
20
+ - Remain lightweight, stable, deterministic, and fully spec-compliant.
21
+
22
+ assistant_instructions:
23
+ allowed_actions:
24
+ - Read and reference content from other UniSpec repositories via MCP GitHub.
25
+ - Generate and update logic within this repository related to:
26
+ - parsing UniSpec documents,
27
+ - JSON Schema validation,
28
+ - normalization,
29
+ - diffing,
30
+ - conversions (OpenAPI, GraphQL SDL, WebSocket models),
31
+ - shared types and interfaces.
32
+ - Suggest architectural improvements to core modules.
33
+ - Assist in writing documentation, API descriptions, comments, and design notes.
34
+ - Validate behavior using actual spec files from `unispec-spec`.
35
+
36
+ forbidden_actions:
37
+ - Modify any files in external repositories.
38
+ - Introduce changes to the UniSpec language itself (belongs to `unispec-spec`).
39
+ - Implement features that are not grounded in the official spec.
40
+ - Add framework-specific or platform-specific logic (belongs to adapters).
41
+ - Add server code, API endpoints, frontend components, or CLI commands.
42
+ - Introduce non-deterministic behavior or global mutable state.
43
+ - Modify specification version numbers (belongs to `unispec-spec`).
44
+
45
+ escalation_policy:
46
+ - Any behavior that deviates from the official UniSpec spec must require maintainer confirmation.
47
+ - If MCP data reveals discrepancies between spec and code, assistant must warn and suggest alignment.
48
+ - For potentially breaking API changes, assistant must halt and request maintainer approval.
49
+
50
+ context_model:
51
+ mcp_github_usage:
52
+ allowed:
53
+ - Access organization repositories for context (read-only).
54
+ - Inspect:
55
+ - UniSpec format (`unispec-spec`)
56
+ - CLI behavior (`unispec-platform`)
57
+ - Adapters (`unispec-js-adapters`, `unispec-python-adapters`)
58
+ - Registry and Portal APIs
59
+ - Use cross-repo information to ensure Core Engine behavior matches platform expectations.
60
+ forbidden:
61
+ - Editing or mutating files in other repositories.
62
+ - Making assumptions not supported by spec.
63
+ - Introducing coupling that makes core depend on implementation details.
64
+ behaviors:
65
+ - Treat external repos purely as reference sources.
66
+ - Maintain strict alignment with the spec repo.
67
+ - Do not derive new behaviors not defined by the spec.
68
+
69
+ file_structure:
70
+ required_directories:
71
+ src: "Source code for the Core Engine logic"
72
+ src/loader: "Spec loader and YAML/JSON reading utilities"
73
+ src/validator: "Schema validation logic using official UniSpec JSON Schemas"
74
+ src/normalizer: "Canonical normalization of UniSpec documents"
75
+ src/diff: "Diff engine and breaking change detection"
76
+ src/converters: "Converters for OpenAPI, GraphQL, WebSocket, etc."
77
+ src/types: "Shared public-facing TypeScript types/interfaces"
78
+ docs: "Developer documentation and design notes"
79
+
80
+ required_files:
81
+ - "README.md"
82
+ - "package.json"
83
+ - "src/index.ts"
84
+ - "src/types/index.ts"
85
+
86
+ content_guidelines:
87
+ code_requirements:
88
+ - Must be deterministic, pure, and side-effect-free where possible.
89
+ - Must strictly follow the UniSpec JSON Schema definitions.
90
+ - Must use official schemas from `unispec-spec` (via MCP reference or local import).
91
+ - Should be modular, composable, and testable.
92
+ - Must not depend on frameworks (Express, Nest, FastAPI, etc).
93
+ - Must not include platform logic (Registry/Portal).
94
+
95
+ documentation:
96
+ - All modules must have clear API descriptions and rationale.
97
+ - Example inputs and outputs should reference real UniSpec examples.
98
+ - Must reflect the latest UniSpec specification.
99
+
100
+ testing:
101
+ - Core behavior must be validated using examples from `unispec-spec/examples`.
102
+ - All changes must include tests for validation, normalization, diffing, and conversions.
103
+ - Tests must cover edge cases and backward compatibility.
104
+
105
+ versioning_policy:
106
+ rules:
107
+ - Core versioning follows the platform, not the spec.
108
+ - Breaking API changes require:
109
+ - Maintainer approval
110
+ - Minor versions may add new converters or metadata fields if spec permits.
111
+ - Patch versions fix issues, improve accuracy, or correct types.
112
+
113
+ pull_request_rules:
114
+ - PRs must describe:
115
+ - intent,
116
+ - expected behavior,
117
+ - impact on users,
118
+ - compatibility implications.
119
+ - PRs affecting validation, types, or normalization must include:
120
+ - tests,
121
+ - updated docs,
122
+ - verification against real examples.
123
+ - Schema-dependent logic must be checked against `unispec-spec` via MCP.
124
+
125
+ tone_and_style:
126
+ - Code and docs must be clean, consistent, and professional.
127
+ - Naming conventions must follow spec terminology.
128
+ - No noisy logs, no temporary/debug code.
129
+
130
+ license:
131
+ - Must remain open-source.
132
+ - Core engine logic must be available for public use.
133
+
134
+ notes:
135
+ - This repository implements the *mechanics* of UniSpec, not the language definition.
136
+ - The UniSpec format itself lives in `unispec-spec`.
137
+ - Adapters, CLI, Registry, and Portal depend on core — keep APIs stable and predictable.
138
+ - MCP GitHub context may be used for reasoning but not for cross-repo modifications.
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # UniSpec Core Platform
2
+ **The official UniSpec Core Engine package — parser, validator, normalizer, diff engine, and converters for the UniSpec format**
3
+
4
+ ---
5
+
6
+ ## 🚀 Overview
7
+
8
+ **UniSpec Core Engine** is the central runtime package of the UniSpec ecosystem.
9
+ It implements the mechanics of the **UniSpec Format**: loading, JSON Schema validation, normalization, diffing, and conversion to other formats.
10
+
11
+ This repository contains **only the Core Engine**, which is consumed by other UniSpec platform components (CLI, Registry, Portal, adapters, SDKs) that live in separate repositories.
12
+
13
+ Core Engine capabilities:
14
+
15
+ - 🧠 **Core Engine** — parser, validator, normalizer, diff engine, converters
16
+ - 🔄 **Format conversion** — UniSpec → OpenAPI, UniSpec → GraphQL SDL, UniSpec → WebSocket channel models
17
+ - 🧩 **Shared types and utilities** — types and helper functions used by the CLI, adapters, Registry, and Portal
18
+
19
+ UniSpec is designed to unify documentation for:
20
+
21
+ - REST
22
+ - GraphQL
23
+ - WebSocket
24
+ - Event-driven APIs (future)
25
+ - Multi-service architectures
26
+
27
+ ---
28
+
29
+ ## 📦 Repository Structure
30
+
31
+ ```pgsql
32
+ unispec-core/
33
+ ├─ src/
34
+ │ ├─ loader/ # File loading (YAML/JSON → JS object)
35
+ │ ├─ validator/ # JSON Schema validation
36
+ │ ├─ normalizer/ # UniSpec structure normalization
37
+ │ ├─ diff/ # Comparison of two UniSpec documents
38
+ │ ├─ converters/ # OpenAPI, GraphQL SDL, WS, etc.
39
+ │ ├─ types/ # UniSpec types/interfaces
40
+ │ ├─ utils/ # Small helpers
41
+ │ └─ index.ts # Public API
42
+ ├─ tests/ # Unit tests
43
+ ├─ package.json
44
+ └─ README.md
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 🧠 Core Concepts
50
+
51
+ ### 📐 1. UniSpec Format
52
+ Defined in a separate repository: **`unispec-spec`**.
53
+ UniSpec Core Engine *implements* this format but does **not** define it.
54
+
55
+ ### 🧱 2. Core Engine
56
+ Located in this repository, under the `src/` directory.
57
+
58
+ Core Engine provides:
59
+
60
+ - YAML/JSON loader
61
+ - JSON Schema validator
62
+ – Normalizer → canonical UniSpec output (REST paths/methods, GraphQL operations, WebSocket channels/messages)
63
+ – Diff engine (with basic breaking / non-breaking classification for REST, GraphQL and WebSocket)
64
+ – Converters:
65
+ - UniSpec → OpenAPI (REST-centric)
66
+ - UniSpec → GraphQL SDL
67
+ - UniSpec → WebSocket channel models for dashboards
68
+
69
+ This is the foundation used by:
70
+
71
+ - the CLI (in a separate repository/package)
72
+ - framework adapters
73
+ - Registry and Portal (as separate UniSpec platform services)
74
+
75
+ ### 🌉 3. Protocol Coverage in Core
76
+
77
+ At the level of the Core Engine, protocol support is intentionally minimal but deterministic:
78
+
79
+ - **REST**
80
+ - Treated as a general OpenAPI-like structure defined by UniSpec JSON Schemas.
81
+ - Normalizer orders `paths` and HTTP methods for stable diffs.
82
+ - Diff engine annotates path/operation additions and removals with breaking/non-breaking severity.
83
+ - Converter exposes REST as an OpenAPI 3.1 document while preserving the original UniSpec under `x-unispec`.
84
+
85
+ - **GraphQL**
86
+ - Typed protocol with `schema` (SDL) and `operations` (queries/mutations/subscriptions).
87
+ - Normalizer orders operation names within each bucket.
88
+ - Diff engine annotates operation additions/removals as non-breaking/breaking.
89
+ - Converter either passes through user-provided SDL or generates a minimal, deterministic SDL shell.
90
+
91
+ - **WebSocket**
92
+ - Typed protocol with channels and messages, plus extensions.
93
+ - Normalizer orders channels by name and messages by `name` within each channel.
94
+ - Diff engine annotates channel/message additions/removals as non-breaking/breaking changes.
95
+ - Converter produces a dashboard-friendly model with service metadata, a normalized channel list and the raw protocol.
96
+
97
+ ### 💻 4. CLI (separate platform component)
98
+ The CLI uses UniSpec Core Engine for validation, conversion, and working with UniSpec specifications.
99
+
100
+ Example UniSpec CLI commands:
101
+
102
+ ```pgsql
103
+ unispec validate
104
+ unispec push
105
+ unispec dev
106
+ unispec open
107
+ unispec diff
108
+ unispec convert
109
+ ```
110
+
111
+
112
+ ### 🗂 5. Registry API (separate service)
113
+ Stores UniSpec specs from multiple services and uses Core Engine for validation, normalization, and change analysis.
114
+ Effectively acts as the "system of record" for all APIs in the company.
115
+
116
+ ### 🌐 6. Portal Web + API (separate service)
117
+ API documentation portal built on top of UniSpec and Core Engine:
118
+
119
+ - service catalog
120
+ - API endpoints
121
+ - schemas
122
+ - interactive playgrounds
123
+ - version comparison
124
+
125
+ ---
126
+
127
+ ## 🛒 Use Cases
128
+
129
+ ### 🟦 Monolith mode (Swagger-like)
130
+ A backend service includes an adapter →
131
+ `/unispec.json` + `/docs` are served automatically.
132
+
133
+ ### 🟧 Microservice mode
134
+ Each service pushes its UniSpec into Registry →
135
+ Portal Web assembles your entire company's API landscape.
136
+
137
+ ### 🟩 Enterprise mode
138
+ Includes:
139
+
140
+ - SSO / permissions
141
+ - RBAC
142
+ - auditing
143
+ - topology map
144
+ - advanced analytics
145
+
146
+ (Handled via private repos.)
147
+
148
+ ---
149
+
150
+ ## 🏁 Getting Started
151
+
152
+ ### 1. Clone the repo
153
+
154
+ ```pgsql
155
+ git clone https://github.com/unispec/unispec-core.git
156
+ cd unispec-core
157
+ ```
158
+
159
+ ### 2. Install dependencies
160
+
161
+ ```pgsql
162
+ pnpm install
163
+ ```
164
+
165
+ ### 3. Build all packages
166
+
167
+ ```pgsql
168
+ pnpm build
169
+ ```
170
+
171
+ ### 4. Run locally (dev mode)
172
+
173
+ ---
174
+
175
+ ## 🤝 Contributing
176
+
177
+ Contributions are welcome!
178
+ Before contributing, please review:
179
+
180
+ - `docs/development.md`
181
+ - `.windsurfrules`
182
+
183
+ All core changes must comply with:
184
+
185
+ - the UniSpec format from `unispec-spec`
186
+ - compatibility rules
187
+ - test coverage
188
+ - platform architecture
189
+
190
+ ---
191
+
192
+ ## Related Repositories
193
+
194
+ | Repository | Purpose |
195
+ |------------------------|---------|
196
+ | `unispec-spec` | UniSpec format definition (schemas, examples) |
197
+ | `unispec-core` | **This repo** — UniSpec Core Engine implementation |
198
+ | `unispec-docs` | Documentation site |
199
+ | `unispec-js-adapters` | Framework integrations (Express/Nest/Fastify) built on top of Core Engine |
200
+ | `unispec-infra` | Helm charts, Docker, Terraform for deploying the UniSpec platform |
201
+
202
+ ---
203
+
204
+ ## License
205
+
206
+ UniSpec Core Engine is open-source and free to use under the MIT License.
207
+
208
+ ---
209
+
210
+ ## 🔥 Summary
211
+
212
+ `unispec-core` is the **heart of the UniSpec ecosystem** at the code level.
213
+ It provides the Core Engine used to:
214
+
215
+ - validate
216
+ - normalize
217
+ - diff
218
+ - convert
219
+ - and integrate
220
+
221
+ API specifications in the UniSpec format.
222
+
223
+ If you're building tools, adapters, or platform services that rely on UniSpec → **this is where the engine lives.**
@@ -0,0 +1,13 @@
1
+ import { UniSpecDocument } from "../types";
2
+ export interface OpenAPIDocument {
3
+ [key: string]: unknown;
4
+ }
5
+ export interface GraphQLSDLOutput {
6
+ sdl: string;
7
+ }
8
+ export interface WebSocketModel {
9
+ [key: string]: unknown;
10
+ }
11
+ export declare function toOpenAPI(doc: UniSpecDocument): OpenAPIDocument;
12
+ export declare function toGraphQLSDL(doc: UniSpecDocument): GraphQLSDLOutput;
13
+ export declare function toWebSocketModel(doc: UniSpecDocument): WebSocketModel;
@@ -0,0 +1,89 @@
1
+ export function toOpenAPI(doc) {
2
+ const service = doc.service;
3
+ const rest = service.protocols?.rest;
4
+ const info = {
5
+ title: service.title ?? service.name,
6
+ description: service.description,
7
+ };
8
+ const servers = rest?.servers ?? [];
9
+ const paths = rest?.paths ?? {};
10
+ // Transparently forward additional REST protocol fields into the OpenAPI document.
11
+ // This allows users to describe components, security, tags and other structures
12
+ // without forcing a specific REST model at the core layer.
13
+ const { servers: _omitServers, paths: _omitPaths, ...restExtras } = rest ?? {};
14
+ return {
15
+ openapi: "3.1.0",
16
+ info,
17
+ servers,
18
+ paths,
19
+ ...restExtras,
20
+ "x-unispec": doc,
21
+ };
22
+ }
23
+ export function toGraphQLSDL(doc) {
24
+ // Minimal implementation: generate a basic SDL that exposes service metadata
25
+ // via a Query field. This does not attempt to interpret the full GraphQL
26
+ // protocol structure yet, but provides a stable, deterministic SDL shape
27
+ // based on top-level UniSpec document fields.
28
+ const graphql = doc.service.protocols?.graphql;
29
+ const customSDL = graphql?.schema?.sdl;
30
+ if (typeof customSDL === "string" && customSDL.trim()) {
31
+ return { sdl: customSDL };
32
+ }
33
+ const service = doc.service;
34
+ const title = service.title ?? service.name;
35
+ const description = service.description ?? "";
36
+ const lines = [];
37
+ if (title || description) {
38
+ lines.push("\"\"");
39
+ if (title) {
40
+ lines.push(title);
41
+ }
42
+ if (description) {
43
+ lines.push("");
44
+ lines.push(description);
45
+ }
46
+ lines.push("\"\"");
47
+ }
48
+ lines.push("schema {");
49
+ lines.push(" query: Query");
50
+ lines.push("}");
51
+ lines.push("");
52
+ lines.push("type Query {");
53
+ lines.push(" _serviceInfo: String!\n");
54
+ lines.push("}");
55
+ const sdl = lines.join("\n");
56
+ return { sdl };
57
+ }
58
+ export function toWebSocketModel(doc) {
59
+ // Base WebSocket model intended for a modern, dashboard-oriented UI.
60
+ // It exposes service metadata, a normalized list of channels and the raw
61
+ // websocket protocol object, while also embedding the original UniSpec
62
+ // document under a technical key for debugging and introspection.
63
+ const service = doc.service;
64
+ const websocket = (service.protocols?.websocket ?? {});
65
+ const channelsRecord = (websocket && typeof websocket === "object" && websocket.channels && typeof websocket.channels === "object")
66
+ ? websocket.channels
67
+ : {};
68
+ const channels = Object.keys(channelsRecord).sort().map((name) => {
69
+ const channel = channelsRecord[name] ?? {};
70
+ return {
71
+ name,
72
+ summary: channel.summary ?? channel.title,
73
+ description: channel.description,
74
+ direction: channel.direction,
75
+ messages: channel.messages,
76
+ raw: channel,
77
+ };
78
+ });
79
+ return {
80
+ service: {
81
+ name: service.name,
82
+ title: service.title,
83
+ description: service.description,
84
+ },
85
+ channels,
86
+ rawProtocol: websocket,
87
+ "x-unispec-ws": doc,
88
+ };
89
+ }
@@ -0,0 +1,21 @@
1
+ import { UniSpecDocument } from "../types";
2
+ export type ChangeSeverity = "breaking" | "non-breaking" | "unknown";
3
+ export interface UniSpecChange {
4
+ path: string;
5
+ description: string;
6
+ severity: ChangeSeverity;
7
+ protocol?: "rest" | "graphql" | "websocket";
8
+ kind?: string;
9
+ }
10
+ export interface DiffResult {
11
+ changes: UniSpecChange[];
12
+ }
13
+ /**
14
+ * Compute a structural diff between two UniSpec documents.
15
+ *
16
+ * Current behavior:
17
+ * - Tracks added, removed, and changed fields and array items.
18
+ * - Uses JSON Pointer-like paths rooted at "" (e.g., "/info/title").
19
+ * - Marks all changes with severity "unknown" for now.
20
+ */
21
+ export declare function diffUniSpec(oldDoc: UniSpecDocument, newDoc: UniSpecDocument): DiffResult;