diff --git a/content/docs/developers/meta.json b/content/docs/developers/meta.json index f02157e32..4733e095a 100644 --- a/content/docs/developers/meta.json +++ b/content/docs/developers/meta.json @@ -4,6 +4,7 @@ "pages": [ "micro-kernel", "writing-plugins", + "plugin-ecosystem", "custom-widgets", "server-drivers", "cli-tools" diff --git a/content/docs/developers/plugin-ecosystem.mdx b/content/docs/developers/plugin-ecosystem.mdx new file mode 100644 index 000000000..b51ff3616 --- /dev/null +++ b/content/docs/developers/plugin-ecosystem.mdx @@ -0,0 +1,776 @@ +--- +title: Plugin Ecosystem Architecture +description: Building an interoperable plugin ecosystem for ObjectStack with vendor-agnostic protocols +--- + +# Plugin Ecosystem Architecture + +## Overview + +ObjectStack uses a MicroKernel Architecture where all functionality is implemented through plugins. This document defines a comprehensive plugin ecosystem specification that ensures plugins from different vendors can call each other, collaborate, and compose together. + +--- + +## 🎯 Design Goals + +### 1. **Protocol-First** + +Plugins declare capabilities through implementing **Protocols** rather than hard-coded dependencies, similar to: +- Kubernetes CRDs (Custom Resource Definitions) +- OSGi Service Registry +- Eclipse Extension Points + +### 2. **Semantic Versioning** + +All protocols and plugins must use Semantic Versioning (SemVer) for compatibility management: +- Major: Breaking changes +- Minor: Backwards-compatible feature additions +- Patch: Backwards-compatible bug fixes + +### 3. **Reverse Domain Naming** + +All plugins and protocols use reverse domain notation to ensure global uniqueness: +``` +{domain}.{category}.{name} +``` + +**Examples:** +- Plugin: `com.acme.crm.customer-management` +- Protocol: `com.objectstack.protocol.storage.v1` +- Interface: `com.acme.crm.interface.contact_service` + +### 4. **Loose Coupling** + +Plugins communicate through **Interfaces** and **Extension Points**, not direct implementation dependencies. + +--- + +## πŸ—οΈ Core Components + +### 1. Protocol Declaration + +A **Protocol** defines a standardized set of capabilities. Plugins declare which protocols they implement. + +```typescript +import { PluginCapabilityManifest } from '@objectstack/spec/system'; + +const capabilities: PluginCapabilityManifest = { + implements: [ + { + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol v1', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'full', // full | partial | experimental | deprecated + certified: true, + }, + ], +}; +``` + +#### Conformance Levels + +| Level | Description | +|-------|-------------| +| `full` | Complete implementation of all protocol features | +| `partial` | Subset implementation with specific features listed | +| `experimental` | Unstable/preview implementation | +| `deprecated` | Still supported but scheduled for removal | + +### 2. Interface Provision + +An **Interface** defines the service contract a plugin provides. Other plugins can call these interfaces. + +```typescript +const capabilities: PluginCapabilityManifest = { + provides: [ + { + id: 'com.acme.crm.interface.contact_service', + name: 'ContactService', + version: { major: 1, minor: 0, patch: 0 }, + stability: 'stable', // stable | beta | alpha | experimental + + methods: [ + { + name: 'getContact', + description: 'Retrieve a contact by ID', + parameters: [ + { name: 'id', type: 'string', required: true }, + ], + returnType: 'Contact', + async: true, + }, + { + name: 'createContact', + parameters: [ + { name: 'data', type: 'ContactInput', required: true }, + ], + returnType: 'Contact', + async: true, + }, + ], + + events: [ + { + name: 'contactCreated', + description: 'Fired when a new contact is created', + payload: 'Contact', + }, + ], + }, + ], +}; +``` + +### 3. Dependency Declaration + +Plugins declare dependencies on other plugins and specify required capabilities. + +```typescript +const capabilities: PluginCapabilityManifest = { + requires: [ + { + pluginId: 'com.objectstack.driver.postgres', + version: '^1.0.0', + optional: false, + requiredCapabilities: [ + 'com.objectstack.protocol.storage.v1', + 'com.objectstack.protocol.transactions.v1', + ], + }, + { + pluginId: 'com.acme.analytics', + version: '>=2.0.0', + optional: true, + reason: 'Enhanced analytics features', + }, + ], +}; +``` + +### 4. Extension Points + +**Extension Points** allow plugins to declare where other plugins can extend functionality. + +```typescript +const capabilities: PluginCapabilityManifest = { + extensionPoints: [ + { + id: 'com.acme.crm.extension.contact_validator', + name: 'Contact Validator', + type: 'validator', // action | hook | widget | provider | transformer | validator | decorator + cardinality: 'multiple', // single | multiple + contract: { + input: 'Contact', + output: 'ValidationResult', + }, + }, + ], + + extensions: [ + { + targetPluginId: 'com.acme.crm', + extensionPointId: 'com.acme.crm.extension.contact_validator', + implementation: './validators/email-validator.ts', + priority: 50, + }, + ], +}; +``` + +#### Extension Point Types + +| Type | Purpose | +|------|---------| +| `action` | Executable actions | +| `hook` | Lifecycle event hooks | +| `widget` | UI components | +| `provider` | Data/service providers | +| `transformer` | Data transformers | +| `validator` | Data validators | +| `decorator` | Functionality decorators | + +--- + +## πŸ“ Naming Conventions + +### Overview + +ObjectStack uses different naming conventions to distinguish between **package-level identifiers** (for distribution and installation) and **code-level identifiers** (for services and data access). + +### 1. Plugin Identifiers + +**Format:** +``` +{vendor-domain}.{category}.{plugin-name} +``` + +**Rules:** +- Use reverse domain notation +- All lowercase +- Use hyphens for word separation (NPM package naming convention) +- Avoid underscores and camelCase + +**Examples:** +``` +βœ… com.objectstack.driver.postgres +βœ… com.acme.crm.customer-management +βœ… org.apache.kafka.connector +❌ com.acme.CRM (Do not use uppercase) +❌ com.acme.crm_plugin (Do not use underscores) +``` + +### 2. Protocol Identifiers + +**Format:** +``` +{vendor-domain}.protocol.{category}.{name}.v{major} +``` + +**Examples:** +``` +com.objectstack.protocol.storage.v1 +com.objectstack.protocol.auth.oauth2.v2 +com.acme.protocol.payment.stripe.v1 +``` + +### 3. Interface Identifiers + +**Format:** +``` +{plugin-id}.interface.{interface-name} +``` + +**Rules:** +- Use snake_case for interface names (consistent with service names in code) +- Follow ObjectStack data layer naming convention + +**Examples:** +``` +βœ… com.acme.crm.interface.contact_service +βœ… com.acme.analytics.interface.metrics_collector +βœ… com.acme.auth.interface.user_provider +``` + +### 4. Extension Point Identifiers + +**Format:** +``` +{plugin-id}.extension.{extension-name} +``` + +**Rules:** +- Use snake_case for extension names (consistent with method/function naming) + +**Examples:** +``` +βœ… com.acme.crm.extension.contact_validator +βœ… com.acme.app.extension.theme_provider +βœ… com.acme.crm.extension.customer_enrichment +``` + +### Naming Convention Summary + +| Type | Format | Separator | Example | +|------|--------|-----------|---------| +| Plugin ID | `{domain}.{category}.{name}` | kebab-case (hyphens) | `com.acme.crm.customer-management` | +| Protocol ID | `{domain}.protocol.{name}.v{N}` | kebab-case | `com.objectstack.protocol.storage.v1` | +| Interface ID | `{plugin}.interface.{name}` | snake_case | `com.acme.crm.interface.contact_service` | +| Extension ID | `{plugin}.extension.{name}` | snake_case | `com.acme.crm.extension.contact_validator` | + +**Important Notes:** +- **Package-level identifiers** (plugins, protocols) use kebab-case, following NPM package naming convention +- **Code-level identifiers** (interfaces, extensions) use snake_case, consistent with ObjectStack data layer naming + +--- + +## πŸ”„ Plugin Discovery & Registry + +### Plugin Registry + +The ObjectStack Hub provides a centralized plugin registry that supports: +- Plugin publishing and version management +- Dependency resolution +- Capability searching +- Quality scoring +- Security scanning + +```typescript +import { PluginRegistryEntry } from '@objectstack/spec/hub'; + +const registryEntry: PluginRegistryEntry = { + id: 'com.acme.crm.customer-management', + version: '1.2.3', + name: 'Customer Management Plugin', + description: 'Comprehensive customer relationship management', + + category: 'data', + tags: ['crm', 'customer', 'sales'], + + vendor: { + id: 'com.acme', + name: 'ACME Corporation', + verified: true, + trustLevel: 'verified', + }, + + capabilities: { /* ... */ }, + + quality: { + testCoverage: 85, + documentationScore: 90, + securityScan: { + passed: true, + vulnerabilities: { critical: 0, high: 0, medium: 0, low: 0 }, + }, + }, + + statistics: { + downloads: 15000, + ratings: { average: 4.5, count: 120 }, + }, +}; +``` + +### Search & Filtering + +```typescript +import { PluginSearchFilters } from '@objectstack/spec/hub'; + +const filters: PluginSearchFilters = { + query: 'CRM', + category: ['data', 'integration'], + implementsProtocols: ['com.objectstack.protocol.storage.v1'], + trustLevel: ['official', 'verified'], + minRating: 4.0, + sortBy: 'downloads', +}; +``` + +--- + +## πŸ” Plugin Security & Quality + +### 1. Vendor Verification + +The plugin registry supports multiple trust levels: + +| Trust Level | Description | +|-------------|-------------| +| `official` | Official ObjectStack plugins | +| `verified` | Verified vendors | +| `community` | Community contributions | +| `unverified` | Unverified vendors | + +### 2. Quality Metrics + +```typescript +quality: { + testCoverage: 85, + documentationScore: 90, + codeQuality: 88, + + securityScan: { + lastScanDate: '2024-01-15T00:00:00Z', + vulnerabilities: { + critical: 0, + high: 0, + medium: 1, + low: 3, + }, + passed: true, + }, + + conformanceTests: [ + { + protocolId: 'com.objectstack.protocol.storage.v1', + passed: true, + totalTests: 150, + passedTests: 150, + }, + ], +} +``` + +### 3. Permission Declaration + +Plugins must declare required permissions in their manifest: + +```typescript +// objectstack.config.ts +export default { + id: 'com.acme.analytics', + permissions: [ + 'system.user.read', + 'system.data.write', + 'network.http.request', + 'storage.local.write', + ], +}; +``` + +--- + +## 🌐 Inter-Plugin Communication Patterns + +### Pattern 1: Interface Invocation + +Plugin A invokes services provided by Plugin B. + +```typescript +// Plugin B: Provides Interface +export class ContactServicePlugin implements Plugin { + name = 'com.acme.crm'; + + async init(ctx: PluginContext) { + ctx.registerService('contact-service', { + async getContact(id: string): Promise { + // Implementation + }, + }); + } +} + +// Plugin A: Uses Interface +export class ReportingPlugin implements Plugin { + name = 'com.acme.reporting'; + dependencies = ['com.acme.crm']; + + async start(ctx: PluginContext) { + const contactService = ctx.getService('contact-service'); + const contact = await contactService.getContact('123'); + } +} +``` + +### Pattern 2: Event Bus + +Plugins communicate through publish/subscribe pattern. + +```typescript +// Plugin A: Publishes Events +await ctx.trigger('crm:contact:created', { + contactId: '123', + data: contact, +}); + +// Plugin B: Subscribes to Events +ctx.hook('crm:contact:created', async (event) => { + console.log('New contact:', event.data); +}); +``` + +### Pattern 3: Extension Contribution + +Plugin A contributes extensions to Plugin B. + +```typescript +// Plugin B: Defines Extension Point +capabilities: { + extensionPoints: [{ + id: 'com.acme.crm.extension.contact_validator', + type: 'validator', + contract: { + input: 'Contact', + output: 'ValidationResult', + }, + }], +} + +// Plugin A: Contributes Extension +capabilities: { + extensions: [{ + targetPluginId: 'com.acme.crm', + extensionPointId: 'com.acme.crm.extension.contact_validator', + implementation: './validators/email-validator.ts', + }], +} +``` + +--- + +## πŸ“¦ Complete Example + +### Scenario: Building a CRM Ecosystem + +#### 1. Core CRM Plugin + +```typescript +// objectstack.config.ts +import { ObjectStackManifest } from '@objectstack/spec/system'; + +const manifest: ObjectStackManifest = { + id: 'com.acme.crm', + version: '1.0.0', + type: 'plugin', + name: 'ACME CRM Core', + + capabilities: { + implements: [ + { + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'full', + }, + ], + + provides: [ + { + id: 'com.acme.crm.interface.customer_service', + name: 'CustomerService', + version: { major: 1, minor: 0, patch: 0 }, + methods: [ + { + name: 'getCustomer', + parameters: [{ name: 'id', type: 'string' }], + returnType: 'Customer', + async: true, + }, + ], + }, + ], + + extensionPoints: [ + { + id: 'com.acme.crm.extension.customer_enrichment', + name: 'Customer Data Enrichment', + type: 'transformer', + cardinality: 'multiple', + }, + ], + }, + + objects: ['./src/objects/*.object.ts'], +}; + +export default manifest; +``` + +#### 2. Email Integration Plugin + +```typescript +// objectstack.config.ts +const manifest: ObjectStackManifest = { + id: 'com.acme.crm.email-integration', + version: '1.0.0', + type: 'plugin', + name: 'Email Integration for CRM', + + capabilities: { + requires: [ + { + pluginId: 'com.acme.crm', + version: '^1.0.0', + requiredCapabilities: [ + 'com.acme.crm.interface.customer_service', + ], + }, + ], + + implements: [ + { + protocol: { + id: 'com.objectstack.protocol.email.v1', + label: 'Email Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'full', + }, + ], + + extensions: [ + { + targetPluginId: 'com.acme.crm', + extensionPointId: 'com.acme.crm.extension.customer_enrichment', + implementation: './enrichment/email-enricher.ts', + priority: 100, + }, + ], + }, +}; + +export default manifest; +``` + +#### 3. Analytics Plugin + +```typescript +const manifest: ObjectStackManifest = { + id: 'com.acme.crm.analytics', + version: '2.0.0', + type: 'plugin', + name: 'CRM Analytics', + + capabilities: { + requires: [ + { + pluginId: 'com.acme.crm', + version: '^1.0.0', + }, + ], + + provides: [ + { + id: 'com.acme.crm.interface.analytics_service', + name: 'AnalyticsService', + version: { major: 2, minor: 0, patch: 0 }, + methods: [ + { + name: 'getMetrics', + parameters: [ + { name: 'query', type: 'MetricsQuery' }, + ], + returnType: 'MetricsResult', + async: true, + }, + ], + events: [ + { + name: 'metricsUpdated', + payload: 'MetricsSnapshot', + }, + ], + }, + ], + }, +}; + +export default manifest; +``` + +--- + +## πŸš€ Best Practices + +### 1. Protocol Design + +#### βœ… Recommended + +- Use semantic versioning +- Protocols should be stable and backwards compatible +- Provide clear protocol documentation and examples +- Define explicit test specifications + +#### ❌ Avoid + +- Exposing implementation details in protocols +- Frequent breaking changes +- Undocumented protocols + +### 2. Plugin Design + +#### βœ… Recommended +```typescript +// Explicitly declare dependencies +requires: [{ + pluginId: 'com.objectstack.driver.postgres', + version: '^1.0.0', + requiredCapabilities: ['com.objectstack.protocol.storage.v1'], +}] + +// Use extension points instead of hard-coding +extensionPoints: [{ + id: 'com.acme.app.extension.authentication', + type: 'provider', + cardinality: 'single', +}] + +// Provide clear interfaces +provides: [{ + id: 'com.acme.interface.user_service', + methods: [/* well-documented methods */], + stability: 'stable', +}] +``` + +#### ❌ Avoid +```typescript +// ❌ Don't directly import other plugins +import { UserService } from '@acme/other-plugin'; + +// ❌ Don't use global state +global.myPluginData = {}; + +// ❌ Don't hard-code plugin identifiers +const otherId = 'other-plugin'; // Should use id from manifest +``` + +### 3. Version Management + +```typescript +// βœ… Use SemVer ranges +version: '^1.0.0' // >= 1.0.0 < 2.0.0 +version: '~1.2.3' // >= 1.2.3 < 1.3.0 +version: '>=2.0.0 <3.0.0' + +// βœ… Mark deprecations +deprecated: true, +deprecationMessage: 'Use com.acme.crm.v2 instead', +replacedBy: 'com.acme.crm.v2', +``` + +### 4. Testing & Validation + +```typescript +// Protocol Conformance Tests +describe('Storage Protocol Conformance', () => { + it('should implement all required methods', async () => { + const driver = new MyDriver(); + expect(driver.query).toBeDefined(); + expect(driver.insert).toBeDefined(); + // ... + }); +}); + +// Integration Tests +describe('Plugin Integration', () => { + it('should work with CRM plugin', async () => { + const kernel = new ObjectKernel(); + kernel.use(new CRMPlugin()); + kernel.use(new MyPlugin()); + await kernel.bootstrap(); + // Test inter-plugin communication + }); +}); +``` + +--- + +## πŸ“š References + +### Related Documentation +- [MicroKernel Architecture](/docs/developers/micro-kernel) +- [Writing Plugins](/docs/developers/writing-plugins) +- [Manifest Schema](/docs/references/system/manifest) +- [Plugin Capability Protocol](/docs/references/system/plugin-capability) +- [Plugin Registry](/docs/references/hub/plugin-registry) + +### Industry Standard References +- [OSGi Service Platform](https://www.osgi.org/) +- [Eclipse Extension Points](https://wiki.eclipse.org/FAQ_What_are_extensions_and_extension_points) +- [Kubernetes CRDs](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +- [VS Code Extension API](https://code.visualstudio.com/api) + +--- + +## πŸŽ“ Summary + +The ObjectStack plugin ecosystem ensures vendor interoperability through: + +1. **Protocol-First Design** - Plugins communicate through protocols not implementations +2. **Reverse Domain Naming** - Ensures globally unique identifiers +3. **Capability Declaration** - Explicit interface and dependency declarations +4. **Extension Points** - Standardized extension mechanisms +5. **Version Management** - Semantic versioning +6. **Quality Assurance** - Testing, certification, and scoring systems +7. **Centralized Registry** - Plugin discovery and dependency resolution + +By following these specifications, plugins from different vendors can: +- πŸ” Discover and depend on each other +- 🀝 Safely invoke each other's services +- πŸ”Œ Flexibly compose and extend +- πŸ“ˆ Continuously evolve without breaking compatibility diff --git a/content/docs/references/hub/index.mdx b/content/docs/references/hub/index.mdx index a2bcf34f2..9821de8e4 100644 --- a/content/docs/references/hub/index.mdx +++ b/content/docs/references/hub/index.mdx @@ -11,6 +11,7 @@ This section contains all protocol schemas for the hub layer of ObjectStack. + diff --git a/content/docs/references/hub/meta.json b/content/docs/references/hub/meta.json index e3a0b24fb..316797192 100644 --- a/content/docs/references/hub/meta.json +++ b/content/docs/references/hub/meta.json @@ -4,6 +4,7 @@ "composer", "license", "marketplace", + "plugin-registry", "space", "tenant" ] diff --git a/content/docs/references/hub/plugin-registry.mdx b/content/docs/references/hub/plugin-registry.mdx new file mode 100644 index 000000000..23cf14461 --- /dev/null +++ b/content/docs/references/hub/plugin-registry.mdx @@ -0,0 +1,130 @@ +--- +title: Plugin Registry +description: Plugin Registry protocol schemas +--- + +# Plugin Registry + + +**Source:** `packages/spec/src/hub/plugin-registry.zod.ts` + + +## TypeScript Usage + +```typescript +import { PluginInstallConfigSchema, PluginQualityMetricsSchema, PluginRegistryEntrySchema, PluginSearchFiltersSchema, PluginStatisticsSchema, PluginVendorSchema } from '@objectstack/spec/hub'; +import type { PluginInstallConfig, PluginQualityMetrics, PluginRegistryEntry, PluginSearchFilters, PluginStatistics, PluginVendor } from '@objectstack/spec/hub'; + +// Validate data +const result = PluginInstallConfigSchema.parse(data); +``` + +--- + +## PluginInstallConfig + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **pluginId** | `string` | βœ… | | +| **version** | `string` | optional | Defaults to latest | +| **config** | `Record` | optional | | +| **autoUpdate** | `boolean` | optional | | +| **options** | `object` | optional | | + +--- + +## PluginQualityMetrics + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **testCoverage** | `number` | optional | | +| **documentationScore** | `number` | optional | | +| **codeQuality** | `number` | optional | | +| **securityScan** | `object` | optional | | +| **conformanceTests** | `object[]` | optional | | + +--- + +## PluginRegistryEntry + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | βœ… | Plugin identifier (reverse domain notation) | +| **version** | `string` | βœ… | | +| **name** | `string` | βœ… | | +| **description** | `string` | optional | | +| **readme** | `string` | optional | | +| **category** | `Enum<'data' \| 'integration' \| 'ui' \| 'analytics' \| 'security' \| 'automation' \| 'ai' \| 'utility' \| 'driver' \| 'gateway' \| 'adapter'>` | optional | | +| **tags** | `string[]` | optional | | +| **vendor** | `object` | βœ… | | +| **capabilities** | `object` | optional | | +| **compatibility** | `object` | optional | | +| **links** | `object` | optional | | +| **media** | `object` | optional | | +| **quality** | `object` | optional | | +| **statistics** | `object` | optional | | +| **license** | `string` | optional | SPDX license identifier | +| **pricing** | `object` | optional | | +| **publishedAt** | `string` | optional | | +| **updatedAt** | `string` | optional | | +| **deprecated** | `boolean` | optional | | +| **deprecationMessage** | `string` | optional | | +| **replacedBy** | `string` | optional | Plugin ID that replaces this one | +| **flags** | `object` | optional | | + +--- + +## PluginSearchFilters + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **query** | `string` | optional | | +| **category** | `string[]` | optional | | +| **tags** | `string[]` | optional | | +| **trustLevel** | `Enum<'official' \| 'verified' \| 'community' \| 'unverified'>[]` | optional | | +| **implementsProtocols** | `string[]` | optional | | +| **pricingModel** | `Enum<'free' \| 'freemium' \| 'paid' \| 'enterprise'>[]` | optional | | +| **minRating** | `number` | optional | | +| **sortBy** | `Enum<'relevance' \| 'downloads' \| 'rating' \| 'updated' \| 'name'>` | optional | | +| **sortOrder** | `Enum<'asc' \| 'desc'>` | optional | | +| **page** | `integer` | optional | | +| **limit** | `integer` | optional | | + +--- + +## PluginStatistics + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **downloads** | `integer` | optional | | +| **downloadsLastMonth** | `integer` | optional | | +| **activeInstallations** | `integer` | optional | | +| **ratings** | `object` | optional | | +| **stars** | `integer` | optional | | +| **dependents** | `integer` | optional | | + +--- + +## PluginVendor + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | βœ… | Vendor identifier (reverse domain) | +| **name** | `string` | βœ… | | +| **website** | `string` | optional | | +| **email** | `string` | optional | | +| **verified** | `boolean` | optional | Whether vendor is verified by ObjectStack | +| **trustLevel** | `Enum<'official' \| 'verified' \| 'community' \| 'unverified'>` | optional | | + diff --git a/content/docs/references/system/index.mdx b/content/docs/references/system/index.mdx index dd4607dd2..4883942a9 100644 --- a/content/docs/references/system/index.mdx +++ b/content/docs/references/system/index.mdx @@ -19,6 +19,7 @@ This section contains all protocol schemas for the system layer of ObjectStack. + diff --git a/content/docs/references/system/manifest.mdx b/content/docs/references/system/manifest.mdx index a13db0918..cf6fbb749 100644 --- a/content/docs/references/system/manifest.mdx +++ b/content/docs/references/system/manifest.mdx @@ -39,5 +39,6 @@ const result = ManifestSchema.parse(data); | **configuration** | `object` | optional | Plugin configuration settings | | **contributes** | `object` | optional | Platform contributions | | **data** | `object[]` | optional | Initial seed data | +| **capabilities** | `object` | optional | Plugin capability declarations for interoperability | | **extensions** | `Record` | optional | Extension points and contributions | diff --git a/content/docs/references/system/meta.json b/content/docs/references/system/meta.json index 09e989f8b..491685715 100644 --- a/content/docs/references/system/meta.json +++ b/content/docs/references/system/meta.json @@ -12,6 +12,7 @@ "logger", "manifest", "plugin", + "plugin-capability", "scoped-storage", "translation" ] diff --git a/content/docs/references/system/plugin-capability.mdx b/content/docs/references/system/plugin-capability.mdx new file mode 100644 index 000000000..83324fd7a --- /dev/null +++ b/content/docs/references/system/plugin-capability.mdx @@ -0,0 +1,151 @@ +--- +title: Plugin Capability +description: Plugin Capability protocol schemas +--- + +# Plugin Capability + + +**Source:** `packages/spec/src/system/plugin-capability.zod.ts` + + +## TypeScript Usage + +```typescript +import { CapabilityConformanceLevelSchema, ExtensionPointSchema, PluginCapabilitySchema, PluginCapabilityManifestSchema, PluginDependencySchema, PluginInterfaceSchema, ProtocolFeatureSchema, ProtocolReferenceSchema, ProtocolVersionSchema } from '@objectstack/spec/system'; +import type { CapabilityConformanceLevel, ExtensionPoint, PluginCapability, PluginCapabilityManifest, PluginDependency, PluginInterface, ProtocolFeature, ProtocolReference, ProtocolVersion } from '@objectstack/spec/system'; + +// Validate data +const result = CapabilityConformanceLevelSchema.parse(data); +``` + +--- + +## CapabilityConformanceLevel + +Level of protocol conformance + +### Allowed Values + +* `full` +* `partial` +* `experimental` +* `deprecated` + +--- + +## ExtensionPoint + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | βœ… | Unique extension point identifier | +| **name** | `string` | βœ… | | +| **description** | `string` | optional | | +| **type** | `Enum<'action' \| 'hook' \| 'widget' \| 'provider' \| 'transformer' \| 'validator' \| 'decorator'>` | βœ… | | +| **contract** | `object` | optional | | +| **cardinality** | `Enum<'single' \| 'multiple'>` | optional | Whether multiple extensions can register to this point | + +--- + +## PluginCapability + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **protocol** | `object` | βœ… | | +| **conformance** | `Enum<'full' \| 'partial' \| 'experimental' \| 'deprecated'>` | optional | Level of protocol conformance | +| **implementedFeatures** | `string[]` | optional | List of implemented feature names | +| **features** | `object[]` | optional | | +| **metadata** | `Record` | optional | | +| **certified** | `boolean` | optional | Has passed official conformance tests | +| **certificationDate** | `string` | optional | | + +--- + +## PluginCapabilityManifest + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **implements** | `object[]` | optional | List of protocols this plugin conforms to | +| **provides** | `object[]` | optional | Services/APIs this plugin offers to others | +| **requires** | `object[]` | optional | Required plugins and their capabilities | +| **extensionPoints** | `object[]` | optional | Points where other plugins can extend this plugin | +| **extensions** | `object[]` | optional | Extensions contributed to other plugins | + +--- + +## PluginDependency + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **pluginId** | `string` | βœ… | Required plugin identifier | +| **version** | `string` | βœ… | Semantic version constraint | +| **optional** | `boolean` | optional | | +| **reason** | `string` | optional | | +| **requiredCapabilities** | `string[]` | optional | Protocol IDs the dependency must support | + +--- + +## PluginInterface + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | βœ… | Unique interface identifier | +| **name** | `string` | βœ… | | +| **description** | `string` | optional | | +| **version** | `object` | βœ… | Semantic version of the protocol | +| **methods** | `object[]` | βœ… | | +| **events** | `object[]` | optional | | +| **stability** | `Enum<'stable' \| 'beta' \| 'alpha' \| 'experimental'>` | optional | | + +--- + +## ProtocolFeature + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **name** | `string` | βœ… | Feature identifier within the protocol | +| **enabled** | `boolean` | optional | | +| **description** | `string` | optional | | +| **sinceVersion** | `string` | optional | Version when this feature was added | +| **deprecatedSince** | `string` | optional | Version when deprecated | + +--- + +## ProtocolReference + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **id** | `string` | βœ… | Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1) | +| **label** | `string` | βœ… | | +| **version** | `object` | βœ… | Semantic version of the protocol | +| **specification** | `string` | optional | URL or path to protocol specification | +| **description** | `string` | optional | | + +--- + +## ProtocolVersion + +Semantic version of the protocol + +### Properties + +| Property | Type | Required | Description | +| :--- | :--- | :--- | :--- | +| **major** | `integer` | βœ… | | +| **minor** | `integer` | βœ… | | +| **patch** | `integer` | βœ… | | + diff --git a/examples/plugin-advanced-crm/README.md b/examples/plugin-advanced-crm/README.md new file mode 100644 index 000000000..8cb727724 --- /dev/null +++ b/examples/plugin-advanced-crm/README.md @@ -0,0 +1,174 @@ +# Advanced CRM Plugin Example + +This example demonstrates a comprehensive ObjectStack plugin that showcases the full capability manifest system. + +## Key Features Demonstrated + +### 1. Protocol Implementation +- Implements `com.objectstack.protocol.storage.v1` with full conformance +- Partially implements `com.objectstack.protocol.sync.v1` with specific features + +### 2. Service Interfaces +Provides two stable interfaces: +- `CustomerService` - Customer data management (CRUD operations) +- `OpportunityService` - Sales opportunity tracking + +### 3. Plugin Dependencies +Declares dependencies on: +- `com.objectstack.driver.postgres` (required) - Data storage +- `com.objectstack.auth.oauth2` (required) - Authentication +- `com.acme.analytics.basic` (optional) - Enhanced analytics + +### 4. Extension Points +Defines four extension points: +- `customer_enrichment` - Transform customer data +- `customer_validator` - Validate customer data +- `opportunity_scoring` - Calculate win probability +- `dashboard_widget` - Custom UI widgets + +### 5. Extensions Contributed +- Contributes a customer summary widget to the dashboard + +## Naming Conventions + +This example follows ObjectStack naming standards: + +- **Plugin ID**: `com.acme.crm.advanced` (reverse domain notation) +- **Protocol IDs**: `com.objectstack.protocol.{name}.v{major}` +- **Interface IDs**: `com.acme.crm.interface.{name}` +- **Extension Point IDs**: `com.acme.crm.extension.{name}` + +## Interoperability + +This plugin is designed to work with other plugins in the ecosystem: + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ com.acme.crm.advanced β”‚ +β”‚ (This Plugin) β”‚ +β”‚ β”‚ +β”‚ Provides: β”‚ +β”‚ β€’ CustomerService β”‚ +β”‚ β€’ OpportunityService β”‚ +β”‚ β”‚ +β”‚ Extension Points: β”‚ +β”‚ β€’ customer_enrichment β”‚ +β”‚ β€’ customer_validator β”‚ +β”‚ β€’ opportunity_scoring β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”‚ Depends On + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ com.objectstack.driver.postgresβ”‚ +β”‚ Storage Driver β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + + β”‚ Extended By + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ com.acme.crm.email-integration β”‚ +β”‚ Email Plugin β”‚ +β”‚ β”‚ +β”‚ Extends: β”‚ +β”‚ β€’ customer_enrichment β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + + β”‚ Optional + β–Ό +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ com.acme.analytics.basic β”‚ +β”‚ Analytics Plugin β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Usage + +### Installing the Plugin + +```bash +npm install @acme/crm-advanced +``` + +### Configuration + +```typescript +// objectstack.config.ts +export default { + plugins: [ + { + id: 'com.acme.crm.advanced', + config: { + apiEndpoint: 'https://api.acme.com', + syncInterval: 3600, + enableAudit: true, + apiKey: process.env.ACME_API_KEY, + }, + }, + ], +}; +``` + +### Using the Customer Service Interface + +```typescript +// In another plugin +export class MyPlugin implements Plugin { + name = 'com.example.my-plugin'; + dependencies = ['com.acme.crm.advanced']; + + async start(ctx: PluginContext) { + // Get the customer service + const customerService = ctx.getService('customer-service'); + + // Use the interface + const customer = await customerService.getCustomer('123'); + console.log(customer); + + // Listen to events + ctx.hook('crm:customerCreated', async (event) => { + console.log('New customer:', event.data); + }); + } +} +``` + +### Extending the Plugin + +```typescript +// Email enrichment plugin +const manifest: ObjectStackManifest = { + id: 'com.acme.crm.email-enrichment', + + capabilities: { + requires: [ + { + pluginId: 'com.acme.crm.advanced', + version: '^2.0.0', + }, + ], + + extensions: [ + { + targetPluginId: 'com.acme.crm.advanced', + extensionPointId: 'com.acme.crm.extension.customer_enrichment', + implementation: './enrichers/email-enricher.ts', + priority: 100, + }, + ], + }, +}; +``` + +## Documentation + +For more information on the plugin ecosystem: + +- [Plugin Ecosystem Architecture](/docs/developers/plugin-ecosystem) +- [Writing Plugins](/docs/developers/writing-plugins) +- [Plugin Capability Protocol](/docs/references/system/plugin-capability) +- [Plugin Registry](/docs/references/hub/plugin-registry) + +## License + +Apache-2.0 diff --git a/examples/plugin-advanced-crm/objectstack.config.ts b/examples/plugin-advanced-crm/objectstack.config.ts new file mode 100644 index 000000000..0621e3705 --- /dev/null +++ b/examples/plugin-advanced-crm/objectstack.config.ts @@ -0,0 +1,397 @@ +import { ObjectStackManifest } from '@objectstack/spec/system'; + +/** + * Advanced CRM Plugin Example + * + * This example demonstrates a comprehensive plugin manifest that: + * - Implements standard protocols + * - Provides interfaces for other plugins + * - Depends on other plugins + * - Defines extension points + * - Uses proper naming conventions + */ +const CRMPlugin: ObjectStackManifest = { + // Basic Information + id: 'com.acme.crm.advanced', + name: 'ACME Advanced CRM', + version: '2.1.0', + type: 'plugin', + description: 'Comprehensive customer relationship management with advanced features', + + // Dependencies on NPM packages + dependencies: { + '@objectstack/spec': '^0.6.0', + '@objectstack/driver-postgres': '^1.0.0', + }, + + // Required System Permissions + permissions: [ + 'system.user.read', + 'system.data.write', + 'system.data.read', + 'network.http.request', + ], + + // Plugin Configuration Schema + configuration: { + title: 'CRM Configuration', + properties: { + apiEndpoint: { + type: 'string', + default: 'https://api.acme.com', + description: 'External API endpoint for data synchronization', + }, + syncInterval: { + type: 'number', + default: 3600, + description: 'Sync interval in seconds', + }, + enableAudit: { + type: 'boolean', + default: true, + description: 'Enable audit trail for customer data changes', + }, + apiKey: { + type: 'string', + secret: true, + description: 'API key for external service integration', + }, + }, + }, + + // Plugin Capability Declaration + capabilities: { + // Protocols This Plugin Implements + implements: [ + { + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol v1', + version: { major: 1, minor: 0, patch: 0 }, + description: 'Standard data storage and retrieval operations', + }, + conformance: 'full', + certified: true, + certificationDate: '2024-01-15T00:00:00Z', + }, + { + protocol: { + id: 'com.objectstack.protocol.sync.v1', + label: 'Data Sync Protocol v1', + version: { major: 1, minor: 0, patch: 0 }, + description: 'Bidirectional data synchronization', + }, + conformance: 'partial', + implementedFeatures: [ + 'incremental_sync', + 'conflict_resolution', + 'batch_operations', + ], + features: [ + { + name: 'real_time_sync', + enabled: false, + description: 'Real-time synchronization via websockets', + sinceVersion: '2.0.0', + }, + { + name: 'batch_operations', + enabled: true, + description: 'Batch sync operations for performance', + }, + ], + }, + ], + + // Interfaces This Plugin Provides + provides: [ + { + id: 'com.acme.crm.interface.customer_service', + name: 'CustomerService', + description: 'Customer data management service', + version: { major: 2, minor: 1, patch: 0 }, + stability: 'stable', + + methods: [ + { + name: 'getCustomer', + description: 'Retrieve a customer by ID', + parameters: [ + { + name: 'id', + type: 'string', + required: true, + description: 'Customer unique identifier', + }, + ], + returnType: 'Customer', + async: true, + }, + { + name: 'searchCustomers', + description: 'Search customers with filters', + parameters: [ + { + name: 'query', + type: 'CustomerSearchQuery', + required: true, + }, + { + name: 'options', + type: 'SearchOptions', + required: false, + }, + ], + returnType: 'Customer[]', + async: true, + }, + { + name: 'createCustomer', + description: 'Create a new customer', + parameters: [ + { + name: 'data', + type: 'CustomerInput', + required: true, + }, + ], + returnType: 'Customer', + async: true, + }, + { + name: 'updateCustomer', + description: 'Update customer information', + parameters: [ + { + name: 'id', + type: 'string', + required: true, + }, + { + name: 'data', + type: 'Partial', + required: true, + }, + ], + returnType: 'Customer', + async: true, + }, + ], + + events: [ + { + name: 'customerCreated', + description: 'Fired when a new customer is created', + payload: 'Customer', + }, + { + name: 'customerUpdated', + description: 'Fired when customer data is updated', + payload: 'CustomerUpdateEvent', + }, + { + name: 'customerDeleted', + description: 'Fired when a customer is deleted', + payload: 'CustomerDeleteEvent', + }, + ], + }, + + { + id: 'com.acme.crm.interface.opportunity_service', + name: 'OpportunityService', + description: 'Sales opportunity management', + version: { major: 1, minor: 0, patch: 0 }, + stability: 'stable', + + methods: [ + { + name: 'getOpportunity', + parameters: [{ name: 'id', type: 'string', required: true }], + returnType: 'Opportunity', + async: true, + }, + { + name: 'createOpportunity', + parameters: [{ name: 'data', type: 'OpportunityInput', required: true }], + returnType: 'Opportunity', + async: true, + }, + ], + + events: [ + { + name: 'opportunityStageChanged', + description: 'Fired when opportunity stage is updated', + payload: 'OpportunityStageEvent', + }, + ], + }, + ], + + // Dependencies on Other Plugins + requires: [ + { + pluginId: 'com.objectstack.driver.postgres', + version: '^1.0.0', + optional: false, + reason: 'Primary data storage backend', + requiredCapabilities: [ + 'com.objectstack.protocol.storage.v1', + 'com.objectstack.protocol.transactions.v1', + ], + }, + { + pluginId: 'com.objectstack.auth.oauth2', + version: '>=2.0.0 <3.0.0', + optional: false, + reason: 'OAuth2 authentication for external API integration', + }, + { + pluginId: 'com.acme.analytics.basic', + version: '^1.5.0', + optional: true, + reason: 'Enhanced analytics and reporting features', + requiredCapabilities: [ + 'com.acme.protocol.metrics.v1', + ], + }, + ], + + // Extension Points This Plugin Defines + extensionPoints: [ + { + id: 'com.acme.crm.extension.customer_enrichment', + name: 'Customer Data Enrichment', + description: 'Allows other plugins to enrich customer data from external sources', + type: 'transformer', + cardinality: 'multiple', + contract: { + input: 'Customer', + output: 'EnrichedCustomer', + signature: '(customer: Customer) => Promise>', + }, + }, + { + id: 'com.acme.crm.extension.customer_validator', + name: 'Customer Data Validator', + description: 'Custom validation rules for customer data', + type: 'validator', + cardinality: 'multiple', + contract: { + input: 'Customer', + output: 'ValidationResult', + signature: '(customer: Customer) => ValidationResult | Promise', + }, + }, + { + id: 'com.acme.crm.extension.opportunity_scoring', + name: 'Opportunity Scoring Engine', + description: 'Calculate opportunity win probability', + type: 'provider', + cardinality: 'single', + contract: { + input: 'Opportunity', + output: 'OpportunityScore', + }, + }, + { + id: 'com.acme.crm.extension.dashboard_widget', + name: 'Dashboard Widget', + description: 'Custom widgets for CRM dashboard', + type: 'widget', + cardinality: 'multiple', + contract: { + signature: 'React.ComponentType', + }, + }, + ], + + // Extensions This Plugin Contributes to Other Plugins + extensions: [ + { + targetPluginId: 'com.objectstack.ui.dashboard', + extensionPointId: 'com.objectstack.ui.extension.widget', + implementation: './widgets/customer-summary.tsx', + priority: 50, + }, + ], + }, + + // Contribution Points + contributes: { + // Custom Metadata Kinds + kinds: [ + { + id: 'crm.customer', + globs: ['**/*.customer.json', '**/*.customer.ts'], + description: 'Customer data definition files', + }, + ], + + // System Event Subscriptions + events: [ + 'system:plugin:installed', + 'system:plugin:uninstalled', + 'data:record:beforeCreate', + 'data:record:afterCreate', + ], + + // UI Menu Contributions + menus: { + 'sidebar/main': [ + { + id: 'open_crm_dashboard', + label: 'CRM Dashboard', + command: 'crm.openDashboard', + }, + { + id: 'open_customers', + label: 'Customers', + command: 'crm.openCustomers', + }, + ], + }, + + // Custom Actions + actions: [ + { + name: 'sync_customers', + label: 'Sync Customers', + description: 'Manually trigger customer data synchronization', + input: { + fullSync: 'boolean', + }, + output: { + syncedCount: 'number', + errors: 'string[]', + }, + }, + ], + }, + + // Data Model Definitions + objects: ['./src/objects/*.object.ts'], + + // Initial Seed Data + data: [ + { + object: 'crm_customer_status', + records: [ + { name: 'active', label: 'Active', sort_order: 1 }, + { name: 'inactive', label: 'Inactive', sort_order: 2 }, + { name: 'prospect', label: 'Prospect', sort_order: 3 }, + ], + mode: 'upsert', + }, + ], + + // Extension Entry Points + extensions: { + runtime: { + entry: './src/index.ts', + }, + }, +}; + +export default CRMPlugin; diff --git a/packages/spec/json-schema/hub/ComposerResponse.json b/packages/spec/json-schema/hub/ComposerResponse.json index bc7f6a74a..e00931899 100644 --- a/packages/spec/json-schema/hub/ComposerResponse.json +++ b/packages/spec/json-schema/hub/ComposerResponse.json @@ -385,6 +385,411 @@ }, "description": "Initial seed data" }, + "capabilities": { + "type": "object", + "properties": { + "implements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocol": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + }, + "conformance": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance", + "default": "full" + }, + "implementedFeatures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of implemented feature names" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "certified": { + "type": "boolean", + "default": false, + "description": "Has passed official conformance tests" + }, + "certificationDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocol" + ], + "additionalProperties": false + }, + "description": "List of protocols this plugin conforms to" + }, + "provides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+interface\\.[a-z][a-z0-9._]+$", + "description": "Unique interface identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Method name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "description": "Type notation (e.g., string, number, User)" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + }, + "returnType": { + "type": "string", + "description": "Return value type" + }, + "async": { + "type": "boolean", + "default": false, + "description": "Whether method returns a Promise" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Event name" + }, + "description": { + "type": "string" + }, + "payload": { + "type": "string", + "description": "Event payload type" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "stability": { + "type": "string", + "enum": [ + "stable", + "beta", + "alpha", + "experimental" + ], + "default": "stable" + } + }, + "required": [ + "id", + "name", + "version", + "methods" + ], + "additionalProperties": false + }, + "description": "Services/APIs this plugin offers to others" + }, + "requires": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pluginId": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Required plugin identifier" + }, + "version": { + "type": "string", + "description": "Semantic version constraint" + }, + "optional": { + "type": "boolean", + "default": false + }, + "reason": { + "type": "string" + }, + "requiredCapabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol IDs the dependency must support" + } + }, + "required": [ + "pluginId", + "version" + ], + "additionalProperties": false + }, + "description": "Required plugins and their capabilities" + }, + "extensionPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+extension\\.[a-z][a-z0-9._]+$", + "description": "Unique extension point identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "action", + "hook", + "widget", + "provider", + "transformer", + "validator", + "decorator" + ] + }, + "contract": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Input type/schema" + }, + "output": { + "type": "string", + "description": "Output type/schema" + }, + "signature": { + "type": "string", + "description": "Function signature if applicable" + } + }, + "additionalProperties": false + }, + "cardinality": { + "type": "string", + "enum": [ + "single", + "multiple" + ], + "default": "multiple", + "description": "Whether multiple extensions can register to this point" + } + }, + "required": [ + "id", + "name", + "type" + ], + "additionalProperties": false + }, + "description": "Points where other plugins can extend this plugin" + }, + "extensions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "targetPluginId": { + "type": "string", + "description": "Plugin ID being extended" + }, + "extensionPointId": { + "type": "string", + "description": "Extension point identifier" + }, + "implementation": { + "type": "string", + "description": "Path to implementation module" + }, + "priority": { + "type": "integer", + "default": 100, + "description": "Registration priority (lower = higher priority)" + } + }, + "required": [ + "targetPluginId", + "extensionPointId", + "implementation" + ], + "additionalProperties": false + }, + "description": "Extensions contributed to other plugins" + } + }, + "additionalProperties": false, + "description": "Plugin capability declarations for interoperability" + }, "extensions": { "type": "object", "additionalProperties": {}, diff --git a/packages/spec/json-schema/hub/PluginInstallConfig.json b/packages/spec/json-schema/hub/PluginInstallConfig.json new file mode 100644 index 000000000..a86ce6e6a --- /dev/null +++ b/packages/spec/json-schema/hub/PluginInstallConfig.json @@ -0,0 +1,53 @@ +{ + "$ref": "#/definitions/PluginInstallConfig", + "definitions": { + "PluginInstallConfig": { + "type": "object", + "properties": { + "pluginId": { + "type": "string" + }, + "version": { + "type": "string", + "description": "Defaults to latest" + }, + "config": { + "type": "object", + "additionalProperties": {} + }, + "autoUpdate": { + "type": "boolean", + "default": false + }, + "options": { + "type": "object", + "properties": { + "skipDependencies": { + "type": "boolean", + "default": false + }, + "force": { + "type": "boolean", + "default": false + }, + "target": { + "type": "string", + "enum": [ + "system", + "space", + "user" + ], + "default": "space" + } + }, + "additionalProperties": false + } + }, + "required": [ + "pluginId" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/hub/PluginQualityMetrics.json b/packages/spec/json-schema/hub/PluginQualityMetrics.json new file mode 100644 index 000000000..7ba64ecaf --- /dev/null +++ b/packages/spec/json-schema/hub/PluginQualityMetrics.json @@ -0,0 +1,101 @@ +{ + "$ref": "#/definitions/PluginQualityMetrics", + "definitions": { + "PluginQualityMetrics": { + "type": "object", + "properties": { + "testCoverage": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "documentationScore": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "codeQuality": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "securityScan": { + "type": "object", + "properties": { + "lastScanDate": { + "type": "string", + "format": "date-time" + }, + "vulnerabilities": { + "type": "object", + "properties": { + "critical": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "high": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "medium": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "low": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + }, + "passed": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "conformanceTests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocolId": { + "type": "string", + "description": "Protocol being tested" + }, + "passed": { + "type": "boolean" + }, + "totalTests": { + "type": "integer", + "minimum": 0 + }, + "passedTests": { + "type": "integer", + "minimum": 0 + }, + "lastRunDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocolId", + "passed", + "totalTests", + "passedTests" + ], + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/hub/PluginRegistryEntry.json b/packages/spec/json-schema/hub/PluginRegistryEntry.json new file mode 100644 index 000000000..23917ce20 --- /dev/null +++ b/packages/spec/json-schema/hub/PluginRegistryEntry.json @@ -0,0 +1,833 @@ +{ + "$ref": "#/definitions/PluginRegistryEntry", + "definitions": { + "PluginRegistryEntry": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Plugin identifier (reverse domain notation)" + }, + "version": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "readme": { + "type": "string" + }, + "category": { + "type": "string", + "enum": [ + "data", + "integration", + "ui", + "analytics", + "security", + "automation", + "ai", + "utility", + "driver", + "gateway", + "adapter" + ] + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "vendor": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)+$", + "description": "Vendor identifier (reverse domain)" + }, + "name": { + "type": "string" + }, + "website": { + "type": "string", + "format": "uri" + }, + "email": { + "type": "string", + "format": "email" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Whether vendor is verified by ObjectStack" + }, + "trustLevel": { + "type": "string", + "enum": [ + "official", + "verified", + "community", + "unverified" + ], + "default": "unverified" + } + }, + "required": [ + "id", + "name" + ], + "additionalProperties": false + }, + "capabilities": { + "type": "object", + "properties": { + "implements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocol": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + }, + "conformance": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance", + "default": "full" + }, + "implementedFeatures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of implemented feature names" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "certified": { + "type": "boolean", + "default": false, + "description": "Has passed official conformance tests" + }, + "certificationDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocol" + ], + "additionalProperties": false + }, + "description": "List of protocols this plugin conforms to" + }, + "provides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+interface\\.[a-z][a-z0-9._]+$", + "description": "Unique interface identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Method name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "description": "Type notation (e.g., string, number, User)" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + }, + "returnType": { + "type": "string", + "description": "Return value type" + }, + "async": { + "type": "boolean", + "default": false, + "description": "Whether method returns a Promise" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Event name" + }, + "description": { + "type": "string" + }, + "payload": { + "type": "string", + "description": "Event payload type" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "stability": { + "type": "string", + "enum": [ + "stable", + "beta", + "alpha", + "experimental" + ], + "default": "stable" + } + }, + "required": [ + "id", + "name", + "version", + "methods" + ], + "additionalProperties": false + }, + "description": "Services/APIs this plugin offers to others" + }, + "requires": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pluginId": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Required plugin identifier" + }, + "version": { + "type": "string", + "description": "Semantic version constraint" + }, + "optional": { + "type": "boolean", + "default": false + }, + "reason": { + "type": "string" + }, + "requiredCapabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol IDs the dependency must support" + } + }, + "required": [ + "pluginId", + "version" + ], + "additionalProperties": false + }, + "description": "Required plugins and their capabilities" + }, + "extensionPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+extension\\.[a-z][a-z0-9._]+$", + "description": "Unique extension point identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "action", + "hook", + "widget", + "provider", + "transformer", + "validator", + "decorator" + ] + }, + "contract": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Input type/schema" + }, + "output": { + "type": "string", + "description": "Output type/schema" + }, + "signature": { + "type": "string", + "description": "Function signature if applicable" + } + }, + "additionalProperties": false + }, + "cardinality": { + "type": "string", + "enum": [ + "single", + "multiple" + ], + "default": "multiple", + "description": "Whether multiple extensions can register to this point" + } + }, + "required": [ + "id", + "name", + "type" + ], + "additionalProperties": false + }, + "description": "Points where other plugins can extend this plugin" + }, + "extensions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "targetPluginId": { + "type": "string", + "description": "Plugin ID being extended" + }, + "extensionPointId": { + "type": "string", + "description": "Extension point identifier" + }, + "implementation": { + "type": "string", + "description": "Path to implementation module" + }, + "priority": { + "type": "integer", + "default": 100, + "description": "Registration priority (lower = higher priority)" + } + }, + "required": [ + "targetPluginId", + "extensionPointId", + "implementation" + ], + "additionalProperties": false + }, + "description": "Extensions contributed to other plugins" + } + }, + "additionalProperties": false + }, + "compatibility": { + "type": "object", + "properties": { + "minObjectStackVersion": { + "type": "string" + }, + "maxObjectStackVersion": { + "type": "string" + }, + "nodeVersion": { + "type": "string" + }, + "platforms": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "linux", + "darwin", + "win32", + "browser" + ] + } + } + }, + "additionalProperties": false + }, + "links": { + "type": "object", + "properties": { + "homepage": { + "type": "string", + "format": "uri" + }, + "repository": { + "type": "string", + "format": "uri" + }, + "documentation": { + "type": "string", + "format": "uri" + }, + "bugs": { + "type": "string", + "format": "uri" + }, + "changelog": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "media": { + "type": "object", + "properties": { + "icon": { + "type": "string", + "format": "uri" + }, + "logo": { + "type": "string", + "format": "uri" + }, + "screenshots": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + }, + "video": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "quality": { + "type": "object", + "properties": { + "testCoverage": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "documentationScore": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "codeQuality": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "securityScan": { + "type": "object", + "properties": { + "lastScanDate": { + "type": "string", + "format": "date-time" + }, + "vulnerabilities": { + "type": "object", + "properties": { + "critical": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "high": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "medium": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "low": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + }, + "passed": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "conformanceTests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocolId": { + "type": "string", + "description": "Protocol being tested" + }, + "passed": { + "type": "boolean" + }, + "totalTests": { + "type": "integer", + "minimum": 0 + }, + "passedTests": { + "type": "integer", + "minimum": 0 + }, + "lastRunDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocolId", + "passed", + "totalTests", + "passedTests" + ], + "additionalProperties": false + } + } + }, + "additionalProperties": false + }, + "statistics": { + "type": "object", + "properties": { + "downloads": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "downloadsLastMonth": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "activeInstallations": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "ratings": { + "type": "object", + "properties": { + "average": { + "type": "number", + "minimum": 0, + "maximum": 5, + "default": 0 + }, + "count": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "distribution": { + "type": "object", + "properties": { + "1": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "2": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "3": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "4": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "5": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "stars": { + "type": "integer", + "minimum": 0 + }, + "dependents": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + }, + "license": { + "type": "string", + "description": "SPDX license identifier" + }, + "pricing": { + "type": "object", + "properties": { + "model": { + "type": "string", + "enum": [ + "free", + "freemium", + "paid", + "enterprise" + ] + }, + "price": { + "type": "number", + "minimum": 0 + }, + "currency": { + "type": "string", + "default": "USD" + }, + "billingPeriod": { + "type": "string", + "enum": [ + "one-time", + "monthly", + "yearly" + ] + } + }, + "required": [ + "model" + ], + "additionalProperties": false + }, + "publishedAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "deprecationMessage": { + "type": "string" + }, + "replacedBy": { + "type": "string", + "description": "Plugin ID that replaces this one" + }, + "flags": { + "type": "object", + "properties": { + "experimental": { + "type": "boolean", + "default": false + }, + "beta": { + "type": "boolean", + "default": false + }, + "featured": { + "type": "boolean", + "default": false + }, + "verified": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + }, + "required": [ + "id", + "version", + "name", + "vendor" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/hub/PluginSearchFilters.json b/packages/spec/json-schema/hub/PluginSearchFilters.json new file mode 100644 index 000000000..dc3168ee4 --- /dev/null +++ b/packages/spec/json-schema/hub/PluginSearchFilters.json @@ -0,0 +1,91 @@ +{ + "$ref": "#/definitions/PluginSearchFilters", + "definitions": { + "PluginSearchFilters": { + "type": "object", + "properties": { + "query": { + "type": "string" + }, + "category": { + "type": "array", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "trustLevel": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "official", + "verified", + "community", + "unverified" + ] + } + }, + "implementsProtocols": { + "type": "array", + "items": { + "type": "string" + } + }, + "pricingModel": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "free", + "freemium", + "paid", + "enterprise" + ] + } + }, + "minRating": { + "type": "number", + "minimum": 0, + "maximum": 5 + }, + "sortBy": { + "type": "string", + "enum": [ + "relevance", + "downloads", + "rating", + "updated", + "name" + ] + }, + "sortOrder": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc" + }, + "page": { + "type": "integer", + "minimum": 1, + "default": 1 + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20 + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/hub/PluginStatistics.json b/packages/spec/json-schema/hub/PluginStatistics.json new file mode 100644 index 000000000..48676226d --- /dev/null +++ b/packages/spec/json-schema/hub/PluginStatistics.json @@ -0,0 +1,84 @@ +{ + "$ref": "#/definitions/PluginStatistics", + "definitions": { + "PluginStatistics": { + "type": "object", + "properties": { + "downloads": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "downloadsLastMonth": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "activeInstallations": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "ratings": { + "type": "object", + "properties": { + "average": { + "type": "number", + "minimum": 0, + "maximum": 5, + "default": 0 + }, + "count": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "distribution": { + "type": "object", + "properties": { + "1": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "2": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "3": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "4": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "5": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + "stars": { + "type": "integer", + "minimum": 0 + }, + "dependents": { + "type": "integer", + "minimum": 0, + "default": 0 + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/hub/PluginVendor.json b/packages/spec/json-schema/hub/PluginVendor.json new file mode 100644 index 000000000..14fa240a8 --- /dev/null +++ b/packages/spec/json-schema/hub/PluginVendor.json @@ -0,0 +1,47 @@ +{ + "$ref": "#/definitions/PluginVendor", + "definitions": { + "PluginVendor": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9]*(\\.[a-z][a-z0-9]*)+$", + "description": "Vendor identifier (reverse domain)" + }, + "name": { + "type": "string" + }, + "website": { + "type": "string", + "format": "uri" + }, + "email": { + "type": "string", + "format": "email" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Whether vendor is verified by ObjectStack" + }, + "trustLevel": { + "type": "string", + "enum": [ + "official", + "verified", + "community", + "unverified" + ], + "default": "unverified" + } + }, + "required": [ + "id", + "name" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/CapabilityConformanceLevel.json b/packages/spec/json-schema/system/CapabilityConformanceLevel.json new file mode 100644 index 000000000..9a2a7b051 --- /dev/null +++ b/packages/spec/json-schema/system/CapabilityConformanceLevel.json @@ -0,0 +1,16 @@ +{ + "$ref": "#/definitions/CapabilityConformanceLevel", + "definitions": { + "CapabilityConformanceLevel": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance" + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/ExtensionPoint.json b/packages/spec/json-schema/system/ExtensionPoint.json new file mode 100644 index 000000000..8bd10ff88 --- /dev/null +++ b/packages/spec/json-schema/system/ExtensionPoint.json @@ -0,0 +1,67 @@ +{ + "$ref": "#/definitions/ExtensionPoint", + "definitions": { + "ExtensionPoint": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+extension\\.[a-z][a-z0-9._]+$", + "description": "Unique extension point identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "action", + "hook", + "widget", + "provider", + "transformer", + "validator", + "decorator" + ] + }, + "contract": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Input type/schema" + }, + "output": { + "type": "string", + "description": "Output type/schema" + }, + "signature": { + "type": "string", + "description": "Function signature if applicable" + } + }, + "additionalProperties": false + }, + "cardinality": { + "type": "string", + "enum": [ + "single", + "multiple" + ], + "default": "multiple", + "description": "Whether multiple extensions can register to this point" + } + }, + "required": [ + "id", + "name", + "type" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/Manifest.json b/packages/spec/json-schema/system/Manifest.json index 6e0998b92..2b606e230 100644 --- a/packages/spec/json-schema/system/Manifest.json +++ b/packages/spec/json-schema/system/Manifest.json @@ -379,6 +379,411 @@ }, "description": "Initial seed data" }, + "capabilities": { + "type": "object", + "properties": { + "implements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocol": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + }, + "conformance": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance", + "default": "full" + }, + "implementedFeatures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of implemented feature names" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "certified": { + "type": "boolean", + "default": false, + "description": "Has passed official conformance tests" + }, + "certificationDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocol" + ], + "additionalProperties": false + }, + "description": "List of protocols this plugin conforms to" + }, + "provides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+interface\\.[a-z][a-z0-9._]+$", + "description": "Unique interface identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Method name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "description": "Type notation (e.g., string, number, User)" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + }, + "returnType": { + "type": "string", + "description": "Return value type" + }, + "async": { + "type": "boolean", + "default": false, + "description": "Whether method returns a Promise" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Event name" + }, + "description": { + "type": "string" + }, + "payload": { + "type": "string", + "description": "Event payload type" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "stability": { + "type": "string", + "enum": [ + "stable", + "beta", + "alpha", + "experimental" + ], + "default": "stable" + } + }, + "required": [ + "id", + "name", + "version", + "methods" + ], + "additionalProperties": false + }, + "description": "Services/APIs this plugin offers to others" + }, + "requires": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pluginId": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Required plugin identifier" + }, + "version": { + "type": "string", + "description": "Semantic version constraint" + }, + "optional": { + "type": "boolean", + "default": false + }, + "reason": { + "type": "string" + }, + "requiredCapabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol IDs the dependency must support" + } + }, + "required": [ + "pluginId", + "version" + ], + "additionalProperties": false + }, + "description": "Required plugins and their capabilities" + }, + "extensionPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+extension\\.[a-z][a-z0-9._]+$", + "description": "Unique extension point identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "action", + "hook", + "widget", + "provider", + "transformer", + "validator", + "decorator" + ] + }, + "contract": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Input type/schema" + }, + "output": { + "type": "string", + "description": "Output type/schema" + }, + "signature": { + "type": "string", + "description": "Function signature if applicable" + } + }, + "additionalProperties": false + }, + "cardinality": { + "type": "string", + "enum": [ + "single", + "multiple" + ], + "default": "multiple", + "description": "Whether multiple extensions can register to this point" + } + }, + "required": [ + "id", + "name", + "type" + ], + "additionalProperties": false + }, + "description": "Points where other plugins can extend this plugin" + }, + "extensions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "targetPluginId": { + "type": "string", + "description": "Plugin ID being extended" + }, + "extensionPointId": { + "type": "string", + "description": "Extension point identifier" + }, + "implementation": { + "type": "string", + "description": "Path to implementation module" + }, + "priority": { + "type": "integer", + "default": 100, + "description": "Registration priority (lower = higher priority)" + } + }, + "required": [ + "targetPluginId", + "extensionPointId", + "implementation" + ], + "additionalProperties": false + }, + "description": "Extensions contributed to other plugins" + } + }, + "additionalProperties": false, + "description": "Plugin capability declarations for interoperability" + }, "extensions": { "type": "object", "additionalProperties": {}, diff --git a/packages/spec/json-schema/system/PluginCapability.json b/packages/spec/json-schema/system/PluginCapability.json new file mode 100644 index 000000000..6396762bf --- /dev/null +++ b/packages/spec/json-schema/system/PluginCapability.json @@ -0,0 +1,127 @@ +{ + "$ref": "#/definitions/PluginCapability", + "definitions": { + "PluginCapability": { + "type": "object", + "properties": { + "protocol": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + }, + "conformance": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance", + "default": "full" + }, + "implementedFeatures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of implemented feature names" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "certified": { + "type": "boolean", + "default": false, + "description": "Has passed official conformance tests" + }, + "certificationDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocol" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/PluginCapabilityManifest.json b/packages/spec/json-schema/system/PluginCapabilityManifest.json new file mode 100644 index 000000000..fa05a19e7 --- /dev/null +++ b/packages/spec/json-schema/system/PluginCapabilityManifest.json @@ -0,0 +1,410 @@ +{ + "$ref": "#/definitions/PluginCapabilityManifest", + "definitions": { + "PluginCapabilityManifest": { + "type": "object", + "properties": { + "implements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocol": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + }, + "conformance": { + "type": "string", + "enum": [ + "full", + "partial", + "experimental", + "deprecated" + ], + "description": "Level of protocol conformance", + "default": "full" + }, + "implementedFeatures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of implemented feature names" + }, + "features": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "metadata": { + "type": "object", + "additionalProperties": {} + }, + "certified": { + "type": "boolean", + "default": false, + "description": "Has passed official conformance tests" + }, + "certificationDate": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "protocol" + ], + "additionalProperties": false + }, + "description": "List of protocols this plugin conforms to" + }, + "provides": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+interface\\.[a-z][a-z0-9._]+$", + "description": "Unique interface identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Method name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "description": "Type notation (e.g., string, number, User)" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + }, + "returnType": { + "type": "string", + "description": "Return value type" + }, + "async": { + "type": "boolean", + "default": false, + "description": "Whether method returns a Promise" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Event name" + }, + "description": { + "type": "string" + }, + "payload": { + "type": "string", + "description": "Event payload type" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "stability": { + "type": "string", + "enum": [ + "stable", + "beta", + "alpha", + "experimental" + ], + "default": "stable" + } + }, + "required": [ + "id", + "name", + "version", + "methods" + ], + "additionalProperties": false + }, + "description": "Services/APIs this plugin offers to others" + }, + "requires": { + "type": "array", + "items": { + "type": "object", + "properties": { + "pluginId": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Required plugin identifier" + }, + "version": { + "type": "string", + "description": "Semantic version constraint" + }, + "optional": { + "type": "boolean", + "default": false + }, + "reason": { + "type": "string" + }, + "requiredCapabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol IDs the dependency must support" + } + }, + "required": [ + "pluginId", + "version" + ], + "additionalProperties": false + }, + "description": "Required plugins and their capabilities" + }, + "extensionPoints": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+extension\\.[a-z][a-z0-9._]+$", + "description": "Unique extension point identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "action", + "hook", + "widget", + "provider", + "transformer", + "validator", + "decorator" + ] + }, + "contract": { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "Input type/schema" + }, + "output": { + "type": "string", + "description": "Output type/schema" + }, + "signature": { + "type": "string", + "description": "Function signature if applicable" + } + }, + "additionalProperties": false + }, + "cardinality": { + "type": "string", + "enum": [ + "single", + "multiple" + ], + "default": "multiple", + "description": "Whether multiple extensions can register to this point" + } + }, + "required": [ + "id", + "name", + "type" + ], + "additionalProperties": false + }, + "description": "Points where other plugins can extend this plugin" + }, + "extensions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "targetPluginId": { + "type": "string", + "description": "Plugin ID being extended" + }, + "extensionPointId": { + "type": "string", + "description": "Extension point identifier" + }, + "implementation": { + "type": "string", + "description": "Path to implementation module" + }, + "priority": { + "type": "integer", + "default": 100, + "description": "Registration priority (lower = higher priority)" + } + }, + "required": [ + "targetPluginId", + "extensionPointId", + "implementation" + ], + "additionalProperties": false + }, + "description": "Extensions contributed to other plugins" + } + }, + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/PluginDependency.json b/packages/spec/json-schema/system/PluginDependency.json new file mode 100644 index 000000000..0daf3a3f1 --- /dev/null +++ b/packages/spec/json-schema/system/PluginDependency.json @@ -0,0 +1,39 @@ +{ + "$ref": "#/definitions/PluginDependency", + "definitions": { + "PluginDependency": { + "type": "object", + "properties": { + "pluginId": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+[a-z][a-z0-9-]+$", + "description": "Required plugin identifier" + }, + "version": { + "type": "string", + "description": "Semantic version constraint" + }, + "optional": { + "type": "boolean", + "default": false + }, + "reason": { + "type": "string" + }, + "requiredCapabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Protocol IDs the dependency must support" + } + }, + "required": [ + "pluginId", + "version" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/PluginInterface.json b/packages/spec/json-schema/system/PluginInterface.json new file mode 100644 index 000000000..397bcd9ee --- /dev/null +++ b/packages/spec/json-schema/system/PluginInterface.json @@ -0,0 +1,141 @@ +{ + "$ref": "#/definitions/PluginInterface", + "definitions": { + "PluginInterface": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+interface\\.[a-z][a-z0-9._]+$", + "description": "Unique interface identifier" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Method name" + }, + "description": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string", + "description": "Type notation (e.g., string, number, User)" + }, + "required": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "additionalProperties": false + } + }, + "returnType": { + "type": "string", + "description": "Return value type" + }, + "async": { + "type": "boolean", + "default": false, + "description": "Whether method returns a Promise" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Event name" + }, + "description": { + "type": "string" + }, + "payload": { + "type": "string", + "description": "Event payload type" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "stability": { + "type": "string", + "enum": [ + "stable", + "beta", + "alpha", + "experimental" + ], + "default": "stable" + } + }, + "required": [ + "id", + "name", + "version", + "methods" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/ProtocolFeature.json b/packages/spec/json-schema/system/ProtocolFeature.json new file mode 100644 index 000000000..7f38fba4b --- /dev/null +++ b/packages/spec/json-schema/system/ProtocolFeature.json @@ -0,0 +1,34 @@ +{ + "$ref": "#/definitions/ProtocolFeature", + "definitions": { + "ProtocolFeature": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Feature identifier within the protocol" + }, + "enabled": { + "type": "boolean", + "default": true + }, + "description": { + "type": "string" + }, + "sinceVersion": { + "type": "string", + "description": "Version when this feature was added" + }, + "deprecatedSince": { + "type": "string", + "description": "Version when deprecated" + } + }, + "required": [ + "name" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/ProtocolReference.json b/packages/spec/json-schema/system/ProtocolReference.json new file mode 100644 index 000000000..f47c51479 --- /dev/null +++ b/packages/spec/json-schema/system/ProtocolReference.json @@ -0,0 +1,56 @@ +{ + "$ref": "#/definitions/ProtocolReference", + "definitions": { + "ProtocolReference": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^([a-z][a-z0-9]*\\.)+protocol\\.[a-z][a-z0-9._]*\\.v\\d+$", + "description": "Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)" + }, + "label": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + }, + "specification": { + "type": "string", + "description": "URL or path to protocol specification" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "version" + ], + "additionalProperties": false + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/json-schema/system/ProtocolVersion.json b/packages/spec/json-schema/system/ProtocolVersion.json new file mode 100644 index 000000000..811ba3254 --- /dev/null +++ b/packages/spec/json-schema/system/ProtocolVersion.json @@ -0,0 +1,30 @@ +{ + "$ref": "#/definitions/ProtocolVersion", + "definitions": { + "ProtocolVersion": { + "type": "object", + "properties": { + "major": { + "type": "integer", + "minimum": 0 + }, + "minor": { + "type": "integer", + "minimum": 0 + }, + "patch": { + "type": "integer", + "minimum": 0 + } + }, + "required": [ + "major", + "minor", + "patch" + ], + "additionalProperties": false, + "description": "Semantic version of the protocol" + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} \ No newline at end of file diff --git a/packages/spec/src/hub/index.ts b/packages/spec/src/hub/index.ts index 8e09f8dfc..a4265ff8f 100644 --- a/packages/spec/src/hub/index.ts +++ b/packages/spec/src/hub/index.ts @@ -1,6 +1,7 @@ // Export Hub Components export * from './composer.zod'; export * from './marketplace.zod'; +export * from './plugin-registry.zod'; export * from './space.zod'; export * from './tenant.zod'; export * from './license.zod'; diff --git a/packages/spec/src/hub/plugin-registry.zod.ts b/packages/spec/src/hub/plugin-registry.zod.ts new file mode 100644 index 000000000..db72242ec --- /dev/null +++ b/packages/spec/src/hub/plugin-registry.zod.ts @@ -0,0 +1,412 @@ +import { z } from 'zod'; +import { PluginCapabilityManifestSchema } from '../system/plugin-capability.zod'; + +/** + * # Plugin Registry Protocol + * + * Defines the schema for the plugin discovery and registry system. + * This enables plugins from different vendors to be discovered, validated, + * and composed together in the ObjectStack ecosystem. + */ + +/** + * Plugin Vendor Information + */ +export const PluginVendorSchema = z.object({ + /** + * Vendor identifier (reverse domain notation) + * Example: "com.acme", "org.apache", "com.objectstack" + */ + id: z.string() + .regex(/^[a-z][a-z0-9]*(\.[a-z][a-z0-9]*)+$/) + .describe('Vendor identifier (reverse domain)'), + + /** + * Vendor display name + */ + name: z.string(), + + /** + * Vendor website + */ + website: z.string().url().optional(), + + /** + * Contact email + */ + email: z.string().email().optional(), + + /** + * Verification status + */ + verified: z.boolean().default(false).describe('Whether vendor is verified by ObjectStack'), + + /** + * Trust level + */ + trustLevel: z.enum(['official', 'verified', 'community', 'unverified']).default('unverified'), +}); + +/** + * Plugin Quality Metrics + */ +export const PluginQualityMetricsSchema = z.object({ + /** + * Test coverage percentage + */ + testCoverage: z.number().min(0).max(100).optional(), + + /** + * Documentation score (0-100) + */ + documentationScore: z.number().min(0).max(100).optional(), + + /** + * Code quality score (0-100) + */ + codeQuality: z.number().min(0).max(100).optional(), + + /** + * Security scan status + */ + securityScan: z.object({ + lastScanDate: z.string().datetime().optional(), + vulnerabilities: z.object({ + critical: z.number().int().min(0).default(0), + high: z.number().int().min(0).default(0), + medium: z.number().int().min(0).default(0), + low: z.number().int().min(0).default(0), + }).optional(), + passed: z.boolean().default(false), + }).optional(), + + /** + * Conformance test results + */ + conformanceTests: z.array(z.object({ + protocolId: z.string().describe('Protocol being tested'), + passed: z.boolean(), + totalTests: z.number().int().min(0), + passedTests: z.number().int().min(0), + lastRunDate: z.string().datetime().optional(), + })).optional(), +}); + +/** + * Plugin Usage Statistics + */ +export const PluginStatisticsSchema = z.object({ + /** + * Total downloads + */ + downloads: z.number().int().min(0).default(0), + + /** + * Downloads in the last 30 days + */ + downloadsLastMonth: z.number().int().min(0).default(0), + + /** + * Number of active installations + */ + activeInstallations: z.number().int().min(0).default(0), + + /** + * User ratings + */ + ratings: z.object({ + average: z.number().min(0).max(5).default(0), + count: z.number().int().min(0).default(0), + distribution: z.object({ + '5': z.number().int().min(0).default(0), + '4': z.number().int().min(0).default(0), + '3': z.number().int().min(0).default(0), + '2': z.number().int().min(0).default(0), + '1': z.number().int().min(0).default(0), + }).optional(), + }).optional(), + + /** + * GitHub stars (if open source) + */ + stars: z.number().int().min(0).optional(), + + /** + * Number of dependent plugins + */ + dependents: z.number().int().min(0).default(0), +}); + +/** + * Plugin Registry Entry + * Complete metadata for a plugin in the registry. + */ +export const PluginRegistryEntrySchema = z.object({ + /** + * Plugin identifier (must match manifest.id) + */ + id: z.string() + .regex(/^([a-z][a-z0-9]*\.)+[a-z][a-z0-9-]+$/) + .describe('Plugin identifier (reverse domain notation)'), + + /** + * Current version + */ + version: z.string().regex(/^\d+\.\d+\.\d+$/), + + /** + * Plugin display name + */ + name: z.string(), + + /** + * Short description + */ + description: z.string().optional(), + + /** + * Detailed documentation/README + */ + readme: z.string().optional(), + + /** + * Plugin type/category + */ + category: z.enum([ + 'data', // Data management, storage, databases + 'integration', // External service integrations + 'ui', // UI components and themes + 'analytics', // Analytics and reporting + 'security', // Security, auth, compliance + 'automation', // Workflows and automation + 'ai', // AI/ML capabilities + 'utility', // General utilities + 'driver', // Database/storage drivers + 'gateway', // API gateways + 'adapter', // Runtime adapters + ]).optional(), + + /** + * Tags for categorization + */ + tags: z.array(z.string()).optional(), + + /** + * Vendor information + */ + vendor: PluginVendorSchema, + + /** + * Capability manifest (what the plugin implements/provides) + */ + capabilities: PluginCapabilityManifestSchema.optional(), + + /** + * Compatibility information + */ + compatibility: z.object({ + /** + * Minimum ObjectStack version required + */ + minObjectStackVersion: z.string().optional(), + + /** + * Maximum ObjectStack version supported + */ + maxObjectStackVersion: z.string().optional(), + + /** + * Node.js version requirement + */ + nodeVersion: z.string().optional(), + + /** + * Supported platforms + */ + platforms: z.array(z.enum(['linux', 'darwin', 'win32', 'browser'])).optional(), + }).optional(), + + /** + * Links and resources + */ + links: z.object({ + homepage: z.string().url().optional(), + repository: z.string().url().optional(), + documentation: z.string().url().optional(), + bugs: z.string().url().optional(), + changelog: z.string().url().optional(), + }).optional(), + + /** + * Media assets + */ + media: z.object({ + icon: z.string().url().optional(), + logo: z.string().url().optional(), + screenshots: z.array(z.string().url()).optional(), + video: z.string().url().optional(), + }).optional(), + + /** + * Quality metrics + */ + quality: PluginQualityMetricsSchema.optional(), + + /** + * Usage statistics + */ + statistics: PluginStatisticsSchema.optional(), + + /** + * License information + */ + license: z.string().optional().describe('SPDX license identifier'), + + /** + * Pricing (if commercial) + */ + pricing: z.object({ + model: z.enum(['free', 'freemium', 'paid', 'enterprise']), + price: z.number().min(0).optional(), + currency: z.string().default('USD').optional(), + billingPeriod: z.enum(['one-time', 'monthly', 'yearly']).optional(), + }).optional(), + + /** + * Publication dates + */ + publishedAt: z.string().datetime().optional(), + updatedAt: z.string().datetime().optional(), + + /** + * Deprecation status + */ + deprecated: z.boolean().default(false), + deprecationMessage: z.string().optional(), + replacedBy: z.string().optional().describe('Plugin ID that replaces this one'), + + /** + * Feature flags + */ + flags: z.object({ + experimental: z.boolean().default(false), + beta: z.boolean().default(false), + featured: z.boolean().default(false), + verified: z.boolean().default(false), + }).optional(), +}); + +/** + * Plugin Search Filters + */ +export const PluginSearchFiltersSchema = z.object({ + /** + * Search query + */ + query: z.string().optional(), + + /** + * Filter by category + */ + category: z.array(z.string()).optional(), + + /** + * Filter by tags + */ + tags: z.array(z.string()).optional(), + + /** + * Filter by vendor trust level + */ + trustLevel: z.array(z.enum(['official', 'verified', 'community', 'unverified'])).optional(), + + /** + * Filter by protocols implemented + */ + implementsProtocols: z.array(z.string()).optional(), + + /** + * Filter by pricing model + */ + pricingModel: z.array(z.enum(['free', 'freemium', 'paid', 'enterprise'])).optional(), + + /** + * Minimum rating + */ + minRating: z.number().min(0).max(5).optional(), + + /** + * Sort options + */ + sortBy: z.enum([ + 'relevance', + 'downloads', + 'rating', + 'updated', + 'name', + ]).optional(), + + /** + * Sort order + */ + sortOrder: z.enum(['asc', 'desc']).default('desc').optional(), + + /** + * Pagination + */ + page: z.number().int().min(1).default(1).optional(), + limit: z.number().int().min(1).max(100).default(20).optional(), +}); + +/** + * Plugin Installation Configuration + */ +export const PluginInstallConfigSchema = z.object({ + /** + * Plugin identifier to install + */ + pluginId: z.string(), + + /** + * Version to install (supports semver ranges) + */ + version: z.string().optional().describe('Defaults to latest'), + + /** + * Plugin-specific configuration values + */ + config: z.record(z.any()).optional(), + + /** + * Whether to auto-update + */ + autoUpdate: z.boolean().default(false).optional(), + + /** + * Installation options + */ + options: z.object({ + /** + * Skip dependency installation + */ + skipDependencies: z.boolean().default(false).optional(), + + /** + * Force reinstall + */ + force: z.boolean().default(false).optional(), + + /** + * Installation target + */ + target: z.enum(['system', 'space', 'user']).default('space').optional(), + }).optional(), +}); + +// Export types +export type PluginVendor = z.infer; +export type PluginQualityMetrics = z.infer; +export type PluginStatistics = z.infer; +export type PluginRegistryEntry = z.infer; +export type PluginSearchFilters = z.infer; +export type PluginInstallConfig = z.infer; diff --git a/packages/spec/src/system/index.ts b/packages/spec/src/system/index.ts index f441582fb..d3298d978 100644 --- a/packages/spec/src/system/index.ts +++ b/packages/spec/src/system/index.ts @@ -17,6 +17,7 @@ export * from './types'; // Re-export Core System Definitions export * from './manifest.zod'; export * from './plugin.zod'; +export * from './plugin-capability.zod'; export * from './logger.zod'; export * from './context.zod'; export * from './scoped-storage.zod'; diff --git a/packages/spec/src/system/manifest.zod.ts b/packages/spec/src/system/manifest.zod.ts index c8030a61d..5139dc5bc 100644 --- a/packages/spec/src/system/manifest.zod.ts +++ b/packages/spec/src/system/manifest.zod.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { PluginCapabilityManifestSchema } from './plugin-capability.zod'; /** * Schema for the ObjectStack Manifest. @@ -183,6 +184,14 @@ export const ManifestSchema = z.object({ mode: z.enum(['upsert', 'insert', 'ignore']).default('upsert').describe('Seeding mode') })).optional().describe('Initial seed data'), + /** + * Plugin Capability Manifest. + * Declares protocols implemented, interfaces provided, dependencies, and extension points. + * This enables plugin interoperability and automatic discovery. + */ + capabilities: PluginCapabilityManifestSchema.optional() + .describe('Plugin capability declarations for interoperability'), + /** * Extension points contributed by this package. * Allows packages to extend UI components, add functionality, etc. diff --git a/packages/spec/src/system/plugin-capability.test.ts b/packages/spec/src/system/plugin-capability.test.ts new file mode 100644 index 000000000..1c3d279e9 --- /dev/null +++ b/packages/spec/src/system/plugin-capability.test.ts @@ -0,0 +1,330 @@ +import { describe, it, expect } from 'vitest'; +import { + CapabilityConformanceLevelSchema, + ProtocolVersionSchema, + ProtocolReferenceSchema, + PluginCapabilitySchema, + PluginInterfaceSchema, + PluginDependencySchema, + ExtensionPointSchema, + PluginCapabilityManifestSchema, + ProtocolFeatureSchema, +} from './plugin-capability.zod'; + +describe('Plugin Capability Schemas', () => { + describe('CapabilityConformanceLevelSchema', () => { + it('should accept valid conformance levels', () => { + expect(CapabilityConformanceLevelSchema.parse('full')).toBe('full'); + expect(CapabilityConformanceLevelSchema.parse('partial')).toBe('partial'); + expect(CapabilityConformanceLevelSchema.parse('experimental')).toBe('experimental'); + expect(CapabilityConformanceLevelSchema.parse('deprecated')).toBe('deprecated'); + }); + + it('should reject invalid conformance levels', () => { + expect(() => CapabilityConformanceLevelSchema.parse('invalid')).toThrow(); + }); + }); + + describe('ProtocolVersionSchema', () => { + it('should accept valid semantic versions', () => { + const version = ProtocolVersionSchema.parse({ major: 1, minor: 2, patch: 3 }); + expect(version).toEqual({ major: 1, minor: 2, patch: 3 }); + }); + + it('should reject negative version numbers', () => { + expect(() => ProtocolVersionSchema.parse({ major: -1, minor: 0, patch: 0 })).toThrow(); + }); + + it('should reject non-integer versions', () => { + expect(() => ProtocolVersionSchema.parse({ major: 1.5, minor: 0, patch: 0 })).toThrow(); + }); + }); + + describe('ProtocolReferenceSchema', () => { + it('should accept valid protocol identifiers', () => { + const protocol = ProtocolReferenceSchema.parse({ + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }); + expect(protocol.id).toBe('com.objectstack.protocol.storage.v1'); + }); + + it('should accept protocol with subcategories', () => { + const protocol = ProtocolReferenceSchema.parse({ + id: 'com.objectstack.protocol.auth.oauth2.v2', + label: 'OAuth2 Authentication Protocol', + version: { major: 2, minor: 0, patch: 0 }, + }); + expect(protocol.id).toBe('com.objectstack.protocol.auth.oauth2.v2'); + }); + + it('should reject invalid protocol format', () => { + expect(() => ProtocolReferenceSchema.parse({ + id: 'invalid-protocol', + label: 'Invalid', + version: { major: 1, minor: 0, patch: 0 }, + })).toThrow(); + }); + + it('should reject protocol without version suffix', () => { + expect(() => ProtocolReferenceSchema.parse({ + id: 'com.objectstack.protocol.storage', + label: 'Storage', + version: { major: 1, minor: 0, patch: 0 }, + })).toThrow(); + }); + }); + + describe('ProtocolFeatureSchema', () => { + it('should accept minimal feature flag', () => { + const feature = ProtocolFeatureSchema.parse({ + name: 'advanced_caching', + }); + expect(feature.name).toBe('advanced_caching'); + expect(feature.enabled).toBe(true); + }); + + it('should accept feature with deprecation info', () => { + const feature = ProtocolFeatureSchema.parse({ + name: 'legacy_api', + enabled: false, + deprecatedSince: '2.0.0', + }); + expect(feature.deprecatedSince).toBe('2.0.0'); + }); + }); + + describe('PluginCapabilitySchema', () => { + it('should accept full conformance capability', () => { + const capability = PluginCapabilitySchema.parse({ + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'full', + certified: true, + }); + expect(capability.conformance).toBe('full'); + }); + + it('should accept partial conformance with features', () => { + const capability = PluginCapabilitySchema.parse({ + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'partial', + implementedFeatures: ['read', 'write', 'delete'], + }); + expect(capability.implementedFeatures).toHaveLength(3); + }); + + it('should default to full conformance', () => { + const capability = PluginCapabilitySchema.parse({ + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + }); + expect(capability.conformance).toBe('full'); + }); + }); + + describe('PluginInterfaceSchema', () => { + it('should accept valid interface declaration', () => { + const iface = PluginInterfaceSchema.parse({ + id: 'com.acme.crm.interface.contact_service', + name: 'ContactService', + version: { major: 1, minor: 0, patch: 0 }, + methods: [ + { + name: 'getContact', + description: 'Retrieve a contact by ID', + parameters: [ + { name: 'id', type: 'string', required: true }, + ], + returnType: 'Contact', + async: true, + }, + ], + }); + expect(iface.methods).toHaveLength(1); + expect(iface.stability).toBe('stable'); + }); + + it('should accept interface with events', () => { + const iface = PluginInterfaceSchema.parse({ + id: 'com.acme.crm.interface.contact_service', + name: 'ContactService', + version: { major: 1, minor: 0, patch: 0 }, + methods: [], + events: [ + { + name: 'contactCreated', + description: 'Fired when a new contact is created', + payload: 'Contact', + }, + ], + }); + expect(iface.events).toHaveLength(1); + }); + + it('should reject invalid interface id format', () => { + expect(() => PluginInterfaceSchema.parse({ + id: 'invalid_interface', + name: 'Invalid', + version: { major: 1, minor: 0, patch: 0 }, + methods: [], + })).toThrow(); + }); + }); + + describe('PluginDependencySchema', () => { + it('should accept valid plugin dependency', () => { + const dep = PluginDependencySchema.parse({ + pluginId: 'com.objectstack.driver.postgres', + version: '^1.0.0', + }); + expect(dep.optional).toBe(false); + }); + + it('should accept optional dependency', () => { + const dep = PluginDependencySchema.parse({ + pluginId: 'com.acme.analytics', + version: '>=2.0.0', + optional: true, + reason: 'Enhanced analytics features', + }); + expect(dep.optional).toBe(true); + }); + + it('should accept dependency with capability requirements', () => { + const dep = PluginDependencySchema.parse({ + pluginId: 'com.objectstack.driver.postgres', + version: '1.0.0', + requiredCapabilities: [ + 'com.objectstack.protocol.storage.v1', + 'com.objectstack.protocol.transactions.v1', + ], + }); + expect(dep.requiredCapabilities).toHaveLength(2); + }); + + it('should reject invalid plugin id', () => { + expect(() => PluginDependencySchema.parse({ + pluginId: 'Invalid_Plugin', + version: '1.0.0', + })).toThrow(); + }); + }); + + describe('ExtensionPointSchema', () => { + it('should accept valid extension point', () => { + const ext = ExtensionPointSchema.parse({ + id: 'com.acme.crm.extension.contact_validator', + name: 'Contact Validator', + type: 'validator', + contract: { + input: 'Contact', + output: 'ValidationResult', + }, + }); + expect(ext.type).toBe('validator'); + expect(ext.cardinality).toBe('multiple'); + }); + + it('should accept single cardinality extension point', () => { + const ext = ExtensionPointSchema.parse({ + id: 'com.acme.app.extension.theme_provider', + name: 'Theme Provider', + type: 'provider', + cardinality: 'single', + }); + expect(ext.cardinality).toBe('single'); + }); + + it('should accept all extension types', () => { + const types = ['action', 'hook', 'widget', 'provider', 'transformer', 'validator', 'decorator']; + types.forEach(type => { + const ext = ExtensionPointSchema.parse({ + id: `com.test.extension.${type}`, + name: type, + type, + }); + expect(ext.type).toBe(type); + }); + }); + }); + + describe('PluginCapabilityManifestSchema', () => { + it('should accept complete capability manifest', () => { + const manifest = PluginCapabilityManifestSchema.parse({ + implements: [ + { + protocol: { + id: 'com.objectstack.protocol.storage.v1', + label: 'Storage Protocol', + version: { major: 1, minor: 0, patch: 0 }, + }, + conformance: 'full', + }, + ], + provides: [ + { + id: 'com.acme.crm.interface.contact_service', + name: 'ContactService', + version: { major: 1, minor: 0, patch: 0 }, + methods: [ + { + name: 'getContact', + returnType: 'Contact', + async: true, + }, + ], + }, + ], + requires: [ + { + pluginId: 'com.objectstack.driver.postgres', + version: '^1.0.0', + }, + ], + extensionPoints: [ + { + id: 'com.acme.crm.extension.contact_validator', + name: 'Contact Validator', + type: 'validator', + }, + ], + }); + expect(manifest.implements).toHaveLength(1); + expect(manifest.provides).toHaveLength(1); + expect(manifest.requires).toHaveLength(1); + expect(manifest.extensionPoints).toHaveLength(1); + }); + + it('should accept manifest with extensions', () => { + const manifest = PluginCapabilityManifestSchema.parse({ + extensions: [ + { + targetPluginId: 'com.acme.crm', + extensionPointId: 'com.acme.crm.extension.contact_validator', + implementation: './validators/email-validator.ts', + priority: 50, + }, + ], + }); + expect(manifest.extensions).toHaveLength(1); + expect(manifest.extensions![0].priority).toBe(50); + }); + + it('should accept empty manifest', () => { + const manifest = PluginCapabilityManifestSchema.parse({}); + expect(manifest).toBeDefined(); + }); + }); +}); diff --git a/packages/spec/src/system/plugin-capability.zod.ts b/packages/spec/src/system/plugin-capability.zod.ts new file mode 100644 index 000000000..b50f4db70 --- /dev/null +++ b/packages/spec/src/system/plugin-capability.zod.ts @@ -0,0 +1,317 @@ +import { z } from 'zod'; + +/** + * # Plugin Capability Protocol + * + * Defines the standard way plugins declare their capabilities, implementations, + * and conformance levels to ensure interoperability across vendors. + * + * Based on the Protocol-Oriented Architecture pattern similar to: + * - Kubernetes CRDs (Custom Resource Definitions) + * - OSGi Service Registry + * - Eclipse Extension Points + */ + +/** + * Capability Conformance Level + * Indicates how completely a plugin implements a given protocol. + */ +export const CapabilityConformanceLevelSchema = z.enum([ + 'full', // Complete implementation of all protocol features + 'partial', // Subset implementation with specific features listed + 'experimental', // Unstable/preview implementation + 'deprecated', // Still supported but scheduled for removal +]).describe('Level of protocol conformance'); + +/** + * Protocol Version Schema + * Uses semantic versioning to track protocol evolution. + */ +export const ProtocolVersionSchema = z.object({ + major: z.number().int().min(0), + minor: z.number().int().min(0), + patch: z.number().int().min(0), +}).describe('Semantic version of the protocol'); + +/** + * Protocol Reference + * Uniquely identifies a protocol/interface that a plugin can implement. + * + * Examples: + * - com.objectstack.protocol.storage.v1 + * - com.objectstack.protocol.auth.oauth2.v2 + * - com.acme.protocol.payment.stripe.v1 + */ +export const ProtocolReferenceSchema = z.object({ + /** + * Protocol identifier using reverse domain notation. + * Format: {domain}.protocol.{category}.{name}[.{subcategory}].v{major} + */ + id: z.string() + .regex(/^([a-z][a-z0-9]*\.)+protocol\.[a-z][a-z0-9._]*\.v\d+$/) + .describe('Unique protocol identifier (e.g., com.objectstack.protocol.storage.v1)'), + + /** + * Human-readable protocol name + */ + label: z.string(), + + /** + * Protocol version + */ + version: ProtocolVersionSchema, + + /** + * Detailed protocol specification URL or file reference + */ + specification: z.string().optional().describe('URL or path to protocol specification'), + + /** + * Brief description of what this protocol defines + */ + description: z.string().optional(), +}); + +/** + * Protocol Feature + * Represents a specific capability within a protocol. + */ +export const ProtocolFeatureSchema = z.object({ + name: z.string().describe('Feature identifier within the protocol'), + enabled: z.boolean().default(true), + description: z.string().optional(), + sinceVersion: z.string().optional().describe('Version when this feature was added'), + deprecatedSince: z.string().optional().describe('Version when deprecated'), +}); + +/** + * Plugin Capability Declaration + * Documents what protocols a plugin implements and to what extent. + */ +export const PluginCapabilitySchema = z.object({ + /** + * The protocol being implemented + */ + protocol: ProtocolReferenceSchema, + + /** + * Conformance level + */ + conformance: CapabilityConformanceLevelSchema.default('full'), + + /** + * Specific features implemented (required if conformance is 'partial') + */ + implementedFeatures: z.array(z.string()).optional().describe('List of implemented feature names'), + + /** + * Optional feature flags indicating advanced capabilities + */ + features: z.array(ProtocolFeatureSchema).optional(), + + /** + * Custom metadata for vendor-specific information + */ + metadata: z.record(z.any()).optional(), + + /** + * Testing/Certification status + */ + certified: z.boolean().default(false).describe('Has passed official conformance tests'), + certificationDate: z.string().datetime().optional(), +}); + +/** + * Plugin Interface Declaration + * Defines the contract for services this plugin provides to other plugins. + */ +export const PluginInterfaceSchema = z.object({ + /** + * Unique interface identifier + * Format: {plugin-id}.interface.{name} + */ + id: z.string() + .regex(/^([a-z][a-z0-9]*\.)+interface\.[a-z][a-z0-9._]+$/) + .describe('Unique interface identifier'), + + /** + * Interface name + */ + name: z.string(), + + /** + * Description of what this interface provides + */ + description: z.string().optional(), + + /** + * Interface version + */ + version: ProtocolVersionSchema, + + /** + * Methods exposed by this interface + */ + methods: z.array(z.object({ + name: z.string().describe('Method name'), + description: z.string().optional(), + parameters: z.array(z.object({ + name: z.string(), + type: z.string().describe('Type notation (e.g., string, number, User)'), + required: z.boolean().default(true), + description: z.string().optional(), + })).optional(), + returnType: z.string().optional().describe('Return value type'), + async: z.boolean().default(false).describe('Whether method returns a Promise'), + })), + + /** + * Events emitted by this interface + */ + events: z.array(z.object({ + name: z.string().describe('Event name'), + description: z.string().optional(), + payload: z.string().optional().describe('Event payload type'), + })).optional(), + + /** + * Stability level + */ + stability: z.enum(['stable', 'beta', 'alpha', 'experimental']).default('stable'), +}); + +/** + * Plugin Dependency Declaration + * Specifies what other plugins or capabilities this plugin requires. + */ +export const PluginDependencySchema = z.object({ + /** + * Plugin ID using reverse domain notation + */ + pluginId: z.string() + .regex(/^([a-z][a-z0-9]*\.)+[a-z][a-z0-9-]+$/) + .describe('Required plugin identifier'), + + /** + * Version constraint (supports semver ranges) + * Examples: "1.0.0", "^1.2.3", ">=2.0.0 <3.0.0" + */ + version: z.string().describe('Semantic version constraint'), + + /** + * Whether this dependency is optional + */ + optional: z.boolean().default(false), + + /** + * Reason for the dependency + */ + reason: z.string().optional(), + + /** + * Minimum required capabilities from the dependency + */ + requiredCapabilities: z.array(z.string()).optional().describe('Protocol IDs the dependency must support'), +}); + +/** + * Extension Point Declaration + * Defines hooks where other plugins can extend this plugin's functionality. + */ +export const ExtensionPointSchema = z.object({ + /** + * Extension point identifier + */ + id: z.string() + .regex(/^([a-z][a-z0-9]*\.)+extension\.[a-z][a-z0-9._]+$/) + .describe('Unique extension point identifier'), + + /** + * Extension point name + */ + name: z.string(), + + /** + * Description + */ + description: z.string().optional(), + + /** + * Type of extension point + */ + type: z.enum([ + 'action', // Plugins can register executable actions + 'hook', // Plugins can listen to lifecycle events + 'widget', // Plugins can contribute UI widgets + 'provider', // Plugins can provide data/services + 'transformer', // Plugins can transform data + 'validator', // Plugins can validate data + 'decorator', // Plugins can enhance/wrap functionality + ]), + + /** + * Expected interface contract for extensions + */ + contract: z.object({ + input: z.string().optional().describe('Input type/schema'), + output: z.string().optional().describe('Output type/schema'), + signature: z.string().optional().describe('Function signature if applicable'), + }).optional(), + + /** + * Cardinality + */ + cardinality: z.enum(['single', 'multiple']).default('multiple') + .describe('Whether multiple extensions can register to this point'), +}); + +/** + * Complete Plugin Capability Manifest + * This is included in the main plugin manifest to declare all capabilities. + */ +export const PluginCapabilityManifestSchema = z.object({ + /** + * Protocols this plugin implements + */ + implements: z.array(PluginCapabilitySchema).optional() + .describe('List of protocols this plugin conforms to'), + + /** + * Interfaces this plugin exposes to other plugins + */ + provides: z.array(PluginInterfaceSchema).optional() + .describe('Services/APIs this plugin offers to others'), + + /** + * Dependencies on other plugins + */ + requires: z.array(PluginDependencySchema).optional() + .describe('Required plugins and their capabilities'), + + /** + * Extension points this plugin defines + */ + extensionPoints: z.array(ExtensionPointSchema).optional() + .describe('Points where other plugins can extend this plugin'), + + /** + * Extensions this plugin contributes to other plugins + */ + extensions: z.array(z.object({ + targetPluginId: z.string().describe('Plugin ID being extended'), + extensionPointId: z.string().describe('Extension point identifier'), + implementation: z.string().describe('Path to implementation module'), + priority: z.number().int().default(100).describe('Registration priority (lower = higher priority)'), + })).optional().describe('Extensions contributed to other plugins'), +}); + +// Export types +export type CapabilityConformanceLevel = z.infer; +export type ProtocolVersion = z.infer; +export type ProtocolReference = z.infer; +export type ProtocolFeature = z.infer; +export type PluginCapability = z.infer; +export type PluginInterface = z.infer; +export type PluginDependency = z.infer; +export type ExtensionPoint = z.infer; +export type PluginCapabilityManifest = z.infer;