@unrdf/kgc-runtime 26.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IMPLEMENTATION_SUMMARY.json +150 -0
- package/PLUGIN_SYSTEM_SUMMARY.json +149 -0
- package/README.md +98 -0
- package/TRANSACTION_IMPLEMENTATION.json +119 -0
- package/capability-map.md +93 -0
- package/docs/api-stability.md +269 -0
- package/docs/extensions/plugin-development.md +382 -0
- package/package.json +40 -0
- package/plugins/registry.json +35 -0
- package/src/admission-gate.mjs +414 -0
- package/src/api-version.mjs +373 -0
- package/src/atomic-admission.mjs +310 -0
- package/src/bounds.mjs +289 -0
- package/src/bulkhead-manager.mjs +280 -0
- package/src/capsule.mjs +524 -0
- package/src/crdt.mjs +361 -0
- package/src/enhanced-bounds.mjs +614 -0
- package/src/executor.mjs +73 -0
- package/src/freeze-restore.mjs +521 -0
- package/src/index.mjs +62 -0
- package/src/materialized-views.mjs +371 -0
- package/src/merge.mjs +472 -0
- package/src/plugin-isolation.mjs +392 -0
- package/src/plugin-manager.mjs +441 -0
- package/src/projections-api.mjs +336 -0
- package/src/projections-cli.mjs +238 -0
- package/src/projections-docs.mjs +300 -0
- package/src/projections-ide.mjs +278 -0
- package/src/receipt.mjs +340 -0
- package/src/rollback.mjs +258 -0
- package/src/saga-orchestrator.mjs +355 -0
- package/src/schemas.mjs +1330 -0
- package/src/storage-optimization.mjs +359 -0
- package/src/tool-registry.mjs +272 -0
- package/src/transaction.mjs +466 -0
- package/src/validators.mjs +485 -0
- package/src/work-item.mjs +449 -0
- package/templates/plugin-template/README.md +58 -0
- package/templates/plugin-template/index.mjs +162 -0
- package/templates/plugin-template/plugin.json +19 -0
- package/test/admission-gate.test.mjs +583 -0
- package/test/api-version.test.mjs +74 -0
- package/test/atomic-admission.test.mjs +155 -0
- package/test/bounds.test.mjs +341 -0
- package/test/bulkhead-manager.test.mjs +236 -0
- package/test/capsule.test.mjs +625 -0
- package/test/crdt.test.mjs +215 -0
- package/test/enhanced-bounds.test.mjs +487 -0
- package/test/freeze-restore.test.mjs +472 -0
- package/test/materialized-views.test.mjs +243 -0
- package/test/merge.test.mjs +665 -0
- package/test/plugin-isolation.test.mjs +109 -0
- package/test/plugin-manager.test.mjs +208 -0
- package/test/projections-api.test.mjs +293 -0
- package/test/projections-cli.test.mjs +204 -0
- package/test/projections-docs.test.mjs +173 -0
- package/test/projections-ide.test.mjs +230 -0
- package/test/receipt.test.mjs +295 -0
- package/test/rollback.test.mjs +132 -0
- package/test/saga-orchestrator.test.mjs +279 -0
- package/test/schemas.test.mjs +716 -0
- package/test/storage-optimization.test.mjs +503 -0
- package/test/tool-registry.test.mjs +341 -0
- package/test/transaction.test.mjs +189 -0
- package/test/validators.test.mjs +463 -0
- package/test/work-item.test.mjs +548 -0
- package/test/work-item.test.mjs.bak +548 -0
- package/var/kgc/test-atomic-log.json +519 -0
- package/var/kgc/test-cascading-log.json +145 -0
- package/vitest.config.mjs +18 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# KGC Runtime API Stability and Deprecation Policy
|
|
2
|
+
|
|
3
|
+
## Current Version
|
|
4
|
+
|
|
5
|
+
**API Version**: 5.0.1 (Beta)
|
|
6
|
+
|
|
7
|
+
**Status**: Beta - API is stable but may have minor changes before 5.1.0 stable release
|
|
8
|
+
|
|
9
|
+
## Semantic Versioning
|
|
10
|
+
|
|
11
|
+
KGC Runtime follows [Semantic Versioning 2.0.0](https://semver.org/):
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
MAJOR.MINOR.PATCH
|
|
15
|
+
|
|
16
|
+
5.0.1
|
|
17
|
+
│ │ └─ Patch: Backward compatible bug fixes
|
|
18
|
+
│ └─── Minor: Backward compatible new features
|
|
19
|
+
└───── Major: Breaking changes
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Version Guarantees
|
|
23
|
+
|
|
24
|
+
- **Patch (x.x.PATCH)**: Bug fixes, no API changes
|
|
25
|
+
- **Minor (x.MINOR.x)**: New features, fully backward compatible
|
|
26
|
+
- **Major (MAJOR.x.x)**: Breaking changes, may require migration
|
|
27
|
+
|
|
28
|
+
## Deprecation Policy
|
|
29
|
+
|
|
30
|
+
### Overview
|
|
31
|
+
|
|
32
|
+
To ensure smooth transitions and maintain stability, we follow a strict deprecation policy:
|
|
33
|
+
|
|
34
|
+
**Rule**: APIs are deprecated for **minimum 2 releases** before removal
|
|
35
|
+
|
|
36
|
+
**Minimum Deprecation Period**: 90 days
|
|
37
|
+
|
|
38
|
+
### Deprecation Process
|
|
39
|
+
|
|
40
|
+
#### 1. Announcement (Release N)
|
|
41
|
+
|
|
42
|
+
API feature is marked as deprecated:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated Since v5.0.0. Use newFunction() instead.
|
|
47
|
+
* Will be removed in v7.0.0 (March 2025)
|
|
48
|
+
*/
|
|
49
|
+
export function oldFunction() {
|
|
50
|
+
console.warn('[DEPRECATION] oldFunction is deprecated. Use newFunction instead.');
|
|
51
|
+
// ... implementation continues to work
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
#### 2. Warning Period (Releases N+1, N+2)
|
|
56
|
+
|
|
57
|
+
Deprecated APIs continue to function but emit warnings:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
[DEPRECATION WARNING] oldFunction is deprecated since v5.0.0.
|
|
61
|
+
Use newFunction instead. Removal scheduled for v7.0.0 (March 2025).
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### 3. Removal (Release N+3 or later)
|
|
65
|
+
|
|
66
|
+
After minimum 90 days AND 2 releases, API is removed:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// v7.0.0 - Function removed
|
|
70
|
+
// Import will fail
|
|
71
|
+
// Migration guide: docs/migration/v5-to-v7.md
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## API Stability Levels
|
|
75
|
+
|
|
76
|
+
### Stable
|
|
77
|
+
|
|
78
|
+
- **Guarantee**: No breaking changes in minor/patch versions
|
|
79
|
+
- **Deprecation**: Minimum 2 releases + 90 days notice
|
|
80
|
+
- **Examples**: Core schemas, receipt generation, work items
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
// Stable API - Won't change in 5.x.x
|
|
84
|
+
import { ReceiptSchema } from '@unrdf/kgc-runtime/schemas';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Beta
|
|
88
|
+
|
|
89
|
+
- **Guarantee**: API shape is stable but may have additions
|
|
90
|
+
- **Changes**: New fields/methods can be added in minor versions
|
|
91
|
+
- **Deprecation**: Same as stable (2 releases + 90 days)
|
|
92
|
+
- **Examples**: Plugin system (v5.0.1), API versioning
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Beta API - Stable but may expand
|
|
96
|
+
import { PluginManager } from '@unrdf/kgc-runtime/plugin-manager';
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Experimental
|
|
100
|
+
|
|
101
|
+
- **Guarantee**: None - can change or be removed at any time
|
|
102
|
+
- **Usage**: Not recommended for production
|
|
103
|
+
- **Warning**: Clearly marked in documentation
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
// Experimental API - Use at your own risk
|
|
107
|
+
// @experimental
|
|
108
|
+
import { ExperimentalFeature } from '@unrdf/kgc-runtime/experimental';
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Version Compatibility
|
|
112
|
+
|
|
113
|
+
### Plugin API Version Checking
|
|
114
|
+
|
|
115
|
+
Plugins must declare their required API version:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"name": "my-plugin",
|
|
120
|
+
"api_version": "5.0.1"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Runtime validates compatibility:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
import { validatePluginVersion } from '@unrdf/kgc-runtime/api-version';
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
validatePluginVersion('5.0.0'); // OK - compatible
|
|
131
|
+
validatePluginVersion('4.0.0'); // WARNING - deprecated
|
|
132
|
+
validatePluginVersion('3.0.0'); // ERROR - removed
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error('Incompatible plugin version:', error.message);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Compatibility Rules
|
|
139
|
+
|
|
140
|
+
| Plugin API | Runtime 5.0.1 | Status |
|
|
141
|
+
|-----------|---------------|---------|
|
|
142
|
+
| 5.0.1 | ✅ Compatible | Exact match |
|
|
143
|
+
| 5.0.0 | ✅ Compatible | Patch difference OK |
|
|
144
|
+
| 4.9.9 | ⚠️ Deprecated | Works but warns |
|
|
145
|
+
| 3.x.x | ❌ Removed | Error thrown |
|
|
146
|
+
|
|
147
|
+
## Migration Guides
|
|
148
|
+
|
|
149
|
+
When breaking changes occur, we provide comprehensive migration guides:
|
|
150
|
+
|
|
151
|
+
### Example: v4 to v5 Migration
|
|
152
|
+
|
|
153
|
+
**Location**: `docs/migration/v4-to-v5.md`
|
|
154
|
+
|
|
155
|
+
**Contents**:
|
|
156
|
+
1. Breaking changes summary
|
|
157
|
+
2. Step-by-step migration instructions
|
|
158
|
+
3. Code examples (before/after)
|
|
159
|
+
4. Automated migration scripts
|
|
160
|
+
5. Testing recommendations
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
// v4 (deprecated)
|
|
164
|
+
const receipt = generateReceipt(op, data);
|
|
165
|
+
|
|
166
|
+
// v5 (current)
|
|
167
|
+
const receipt = await generateReceipt(op, inputs, outputs, parentHash);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Deprecation Timeline
|
|
171
|
+
|
|
172
|
+
### Current Deprecations (v5.0.1)
|
|
173
|
+
|
|
174
|
+
| Feature | Deprecated | Removal | Alternative |
|
|
175
|
+
|---------|-----------|---------|-------------|
|
|
176
|
+
| `WorkItem.metadata` direct mutation | v5.0.0 | v7.0.0 | Use `updateMetadata()` method |
|
|
177
|
+
| `Receipt.hash` MD5 | v4.0.0 | v6.0.0 | Now using BLAKE3 (automatic) |
|
|
178
|
+
|
|
179
|
+
### Upcoming Changes (Planned)
|
|
180
|
+
|
|
181
|
+
| Feature | Target Version | Type | Description |
|
|
182
|
+
|---------|---------------|------|-------------|
|
|
183
|
+
| Plugin hot-reload | v5.1.0 | Addition | Reload plugins without restart |
|
|
184
|
+
| WASM plugin support | v5.2.0 | Addition | Run plugins in WASM sandbox |
|
|
185
|
+
| GraphQL API | v6.0.0 | Addition | Query runtime via GraphQL |
|
|
186
|
+
|
|
187
|
+
## Stability Guarantees by Module
|
|
188
|
+
|
|
189
|
+
### Core Runtime (Stable)
|
|
190
|
+
|
|
191
|
+
- ✅ `schemas.mjs` - All core schemas
|
|
192
|
+
- ✅ `receipt.mjs` - Receipt generation/validation
|
|
193
|
+
- ✅ `work-item.mjs` - Work item executor
|
|
194
|
+
- ✅ `bounds.mjs` - Bounds checking
|
|
195
|
+
- ✅ `capsule.mjs` - Run capsule management
|
|
196
|
+
|
|
197
|
+
### Plugin System (Beta)
|
|
198
|
+
|
|
199
|
+
- 🔶 `plugin-manager.mjs` - Plugin lifecycle
|
|
200
|
+
- 🔶 `plugin-isolation.mjs` - Capability security
|
|
201
|
+
- 🔶 `api-version.mjs` - Version management
|
|
202
|
+
|
|
203
|
+
### Governance (Beta)
|
|
204
|
+
|
|
205
|
+
- 🔶 `admission-gate.mjs` - Policy enforcement
|
|
206
|
+
- 🔶 `freeze-restore.mjs` - State snapshots
|
|
207
|
+
- 🔶 `merge.mjs` - State merging
|
|
208
|
+
|
|
209
|
+
## Breaking Change Policy
|
|
210
|
+
|
|
211
|
+
### What Constitutes a Breaking Change?
|
|
212
|
+
|
|
213
|
+
**Breaking** (requires major version):
|
|
214
|
+
- Removing exported function/class
|
|
215
|
+
- Changing function signature (params, return type)
|
|
216
|
+
- Changing schema validation rules (stricter)
|
|
217
|
+
- Removing schema fields
|
|
218
|
+
- Changing default behavior
|
|
219
|
+
|
|
220
|
+
**Not Breaking** (minor/patch version):
|
|
221
|
+
- Adding new function/class
|
|
222
|
+
- Adding optional parameters
|
|
223
|
+
- Adding schema fields (optional)
|
|
224
|
+
- Relaxing validation rules
|
|
225
|
+
- Internal implementation changes
|
|
226
|
+
- Performance improvements
|
|
227
|
+
|
|
228
|
+
### Example Scenarios
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// ❌ BREAKING - Requires v6.0.0
|
|
232
|
+
// v5: generateReceipt(op, data)
|
|
233
|
+
// v6: generateReceipt(op, inputs, outputs) // Changed signature
|
|
234
|
+
|
|
235
|
+
// ✅ NOT BREAKING - Can be v5.1.0
|
|
236
|
+
// v5.0: generateReceipt(op, inputs, outputs)
|
|
237
|
+
// v5.1: generateReceipt(op, inputs, outputs, options = {}) // Added optional param
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Staying Updated
|
|
241
|
+
|
|
242
|
+
### Subscribe to Changes
|
|
243
|
+
|
|
244
|
+
1. **GitHub Releases**: Watch the repository
|
|
245
|
+
2. **Changelog**: Check `CHANGELOG.md` for each release
|
|
246
|
+
3. **Migration Alerts**: Run `npm outdated` for deprecation warnings
|
|
247
|
+
|
|
248
|
+
### Automated Checks
|
|
249
|
+
|
|
250
|
+
Add to your CI/CD:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Check for deprecated API usage
|
|
254
|
+
npm run check-deprecations
|
|
255
|
+
|
|
256
|
+
# Validate plugin compatibility
|
|
257
|
+
npm run validate-plugin-version
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Questions?
|
|
261
|
+
|
|
262
|
+
- **Deprecation Questions**: Open an issue with tag `deprecation`
|
|
263
|
+
- **Migration Help**: Check `docs/migration/` or ask in Discussions
|
|
264
|
+
- **Breaking Change Proposals**: RFC process in GitHub Discussions
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
**Last Updated**: 2024-12-27
|
|
269
|
+
**Next Review**: 2025-03-01 (with v5.1.0 release)
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# KGC Plugin Development Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The KGC Runtime plugin system allows you to extend core functionality with custom receipt types, validators, and tools while maintaining security and deterministic execution.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Create Plugin Manifest
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
// plugin.json
|
|
13
|
+
{
|
|
14
|
+
"name": "my-plugin",
|
|
15
|
+
"version": "1.0.0",
|
|
16
|
+
"description": "My custom KGC plugin",
|
|
17
|
+
"entryPoint": "./index.mjs",
|
|
18
|
+
"capabilities": [
|
|
19
|
+
"receipt:generate",
|
|
20
|
+
"receipt:validate"
|
|
21
|
+
],
|
|
22
|
+
"api_version": "5.0.1",
|
|
23
|
+
"author": "Your Name",
|
|
24
|
+
"license": "MIT"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Implement Plugin
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
// index.mjs
|
|
32
|
+
import { PluginReceiptSchema } from '@unrdf/kgc-runtime/schemas';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Plugin entry point
|
|
36
|
+
* @param {Object} runtime - KGC Runtime API (whitelisted methods only)
|
|
37
|
+
*/
|
|
38
|
+
export default function plugin(runtime) {
|
|
39
|
+
return {
|
|
40
|
+
name: 'my-plugin',
|
|
41
|
+
version: '1.0.0',
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initialize plugin
|
|
45
|
+
*/
|
|
46
|
+
async initialize() {
|
|
47
|
+
console.log('Plugin initialized');
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate custom receipt
|
|
52
|
+
*/
|
|
53
|
+
async generateCustomReceipt(operation, inputs, outputs) {
|
|
54
|
+
const receipt = await runtime.generateReceipt(operation, inputs, outputs);
|
|
55
|
+
|
|
56
|
+
// Add custom metadata
|
|
57
|
+
return PluginReceiptSchema.parse({
|
|
58
|
+
...receipt,
|
|
59
|
+
pluginMetadata: {
|
|
60
|
+
pluginName: 'my-plugin',
|
|
61
|
+
pluginVersion: '1.0.0',
|
|
62
|
+
receiptType: 'custom',
|
|
63
|
+
customFields: {
|
|
64
|
+
myData: 'example'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Cleanup on unload
|
|
72
|
+
*/
|
|
73
|
+
async cleanup() {
|
|
74
|
+
console.log('Plugin cleanup');
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 3. Register and Use
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
import { PluginManager } from '@unrdf/kgc-runtime/plugin-manager';
|
|
84
|
+
|
|
85
|
+
const manager = new PluginManager();
|
|
86
|
+
|
|
87
|
+
// Register plugin
|
|
88
|
+
await manager.registerPlugin({
|
|
89
|
+
name: 'my-plugin',
|
|
90
|
+
version: '1.0.0',
|
|
91
|
+
entryPoint: './plugin.mjs',
|
|
92
|
+
capabilities: ['receipt:generate'],
|
|
93
|
+
api_version: '5.0.1'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Load and activate
|
|
97
|
+
await manager.loadPlugin('my-plugin@1.0.0');
|
|
98
|
+
await manager.activatePlugin('my-plugin@1.0.0');
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## API Reference
|
|
102
|
+
|
|
103
|
+
### Available Runtime APIs (Whitelisted)
|
|
104
|
+
|
|
105
|
+
Plugins can only access these whitelisted APIs:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
runtime = {
|
|
109
|
+
// Receipt operations
|
|
110
|
+
generateReceipt(operation, inputs, outputs, parentHash),
|
|
111
|
+
verifyReceiptHash(receipt),
|
|
112
|
+
|
|
113
|
+
// Schema validation
|
|
114
|
+
validateReceipt(receipt),
|
|
115
|
+
validateWorkItem(workItem),
|
|
116
|
+
validateBounds(bounds),
|
|
117
|
+
|
|
118
|
+
// Tool registry (read-only)
|
|
119
|
+
getTool(name),
|
|
120
|
+
getToolsByCapability(capability),
|
|
121
|
+
|
|
122
|
+
// Bounds checking
|
|
123
|
+
checkBounds(current, limits)
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Blocked Capabilities
|
|
128
|
+
|
|
129
|
+
The following are NEVER allowed for security:
|
|
130
|
+
|
|
131
|
+
- `filesystem:write` - Direct file writes
|
|
132
|
+
- `filesystem:delete` - File deletion
|
|
133
|
+
- `network:http` - HTTP requests
|
|
134
|
+
- `network:socket` - Socket connections
|
|
135
|
+
- `process:spawn` - Process spawning
|
|
136
|
+
- `process:exit` - Process termination
|
|
137
|
+
- `eval:code` - Dynamic code evaluation
|
|
138
|
+
|
|
139
|
+
## Plugin Lifecycle
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
REGISTERED → LOADED → EXECUTING → UNLOADED
|
|
143
|
+
↓ ↓
|
|
144
|
+
FAILED ←──────────────────
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### State Transitions
|
|
148
|
+
|
|
149
|
+
1. **REGISTERED**: Plugin manifest validated and registered
|
|
150
|
+
2. **LOADED**: Plugin code loaded into memory, `initialize()` called
|
|
151
|
+
3. **EXECUTING**: Plugin actively processing requests
|
|
152
|
+
4. **UNLOADED**: Plugin stopped, `cleanup()` called
|
|
153
|
+
5. **FAILED**: Error occurred, check audit log
|
|
154
|
+
|
|
155
|
+
## Custom Receipt Types
|
|
156
|
+
|
|
157
|
+
Define custom receipt schemas:
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
import { z } from 'zod';
|
|
161
|
+
import { PluginReceiptSchema } from '@unrdf/kgc-runtime/schemas';
|
|
162
|
+
|
|
163
|
+
// Define custom receipt type
|
|
164
|
+
const MyCustomReceiptSchema = PluginReceiptSchema.extend({
|
|
165
|
+
pluginMetadata: z.object({
|
|
166
|
+
pluginName: z.literal('my-plugin'),
|
|
167
|
+
pluginVersion: z.string(),
|
|
168
|
+
receiptType: z.literal('performance'),
|
|
169
|
+
customFields: z.object({
|
|
170
|
+
executionTime: z.number(),
|
|
171
|
+
memoryUsed: z.number(),
|
|
172
|
+
optimizationApplied: z.boolean()
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Generate typed receipt
|
|
178
|
+
export async function generatePerformanceReceipt(operation, metrics) {
|
|
179
|
+
const receipt = await runtime.generateReceipt(operation, {}, metrics);
|
|
180
|
+
|
|
181
|
+
return MyCustomReceiptSchema.parse({
|
|
182
|
+
...receipt,
|
|
183
|
+
pluginMetadata: {
|
|
184
|
+
pluginName: 'my-plugin',
|
|
185
|
+
pluginVersion: '1.0.0',
|
|
186
|
+
receiptType: 'performance',
|
|
187
|
+
customFields: {
|
|
188
|
+
executionTime: metrics.duration,
|
|
189
|
+
memoryUsed: metrics.memory,
|
|
190
|
+
optimizationApplied: metrics.optimized
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Security Best Practices
|
|
198
|
+
|
|
199
|
+
### 1. Capability Declaration
|
|
200
|
+
|
|
201
|
+
Always declare minimum required capabilities:
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
{
|
|
205
|
+
"capabilities": [
|
|
206
|
+
"receipt:generate", // Only what you need
|
|
207
|
+
"receipt:validate"
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 2. Input Validation
|
|
213
|
+
|
|
214
|
+
Validate all inputs with Zod schemas:
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
import { z } from 'zod';
|
|
218
|
+
|
|
219
|
+
const InputSchema = z.object({
|
|
220
|
+
operation: z.string().min(1).max(100),
|
|
221
|
+
data: z.record(z.any())
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
export async function processInput(input) {
|
|
225
|
+
// Validate first
|
|
226
|
+
const validated = InputSchema.parse(input);
|
|
227
|
+
|
|
228
|
+
// Then process
|
|
229
|
+
return validated;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 3. Error Handling
|
|
234
|
+
|
|
235
|
+
Use proper error receipts:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
try {
|
|
239
|
+
const result = await riskyOperation();
|
|
240
|
+
return await runtime.generateReceipt('success', {}, { result });
|
|
241
|
+
} catch (error) {
|
|
242
|
+
return await runtime.generateReceipt('error', {}, {
|
|
243
|
+
success: false,
|
|
244
|
+
error: error.message,
|
|
245
|
+
stack: error.stack
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Testing Plugins
|
|
251
|
+
|
|
252
|
+
### Unit Tests
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
import { describe, it, expect } from 'vitest';
|
|
256
|
+
import myPlugin from './plugin.mjs';
|
|
257
|
+
|
|
258
|
+
describe('My Plugin', () => {
|
|
259
|
+
it('should initialize correctly', async () => {
|
|
260
|
+
const mockRuntime = {
|
|
261
|
+
generateReceipt: async (op, inp, out) => ({
|
|
262
|
+
id: 'test',
|
|
263
|
+
operation: op
|
|
264
|
+
})
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const plugin = myPlugin(mockRuntime);
|
|
268
|
+
await plugin.initialize();
|
|
269
|
+
|
|
270
|
+
expect(plugin.name).toBe('my-plugin');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should generate custom receipts', async () => {
|
|
274
|
+
const mockRuntime = {
|
|
275
|
+
generateReceipt: async (op, inp, out) => ({
|
|
276
|
+
id: 'test',
|
|
277
|
+
timestamp: Date.now(),
|
|
278
|
+
operation: op,
|
|
279
|
+
inputs: inp,
|
|
280
|
+
outputs: out,
|
|
281
|
+
hash: 'abc123'
|
|
282
|
+
})
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const plugin = myPlugin(mockRuntime);
|
|
286
|
+
const receipt = await plugin.generateCustomReceipt('test', {}, {});
|
|
287
|
+
|
|
288
|
+
expect(receipt.pluginMetadata).toBeDefined();
|
|
289
|
+
expect(receipt.pluginMetadata.pluginName).toBe('my-plugin');
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Integration Tests
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
import { PluginManager } from '@unrdf/kgc-runtime/plugin-manager';
|
|
298
|
+
import { PluginIsolation } from '@unrdf/kgc-runtime/plugin-isolation';
|
|
299
|
+
|
|
300
|
+
describe('Plugin Integration', () => {
|
|
301
|
+
it('should load and execute with isolation', async () => {
|
|
302
|
+
const manager = new PluginManager();
|
|
303
|
+
const isolation = new PluginIsolation({
|
|
304
|
+
whitelist: ['receipt:generate']
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
await manager.registerPlugin({
|
|
308
|
+
name: 'test-plugin',
|
|
309
|
+
version: '1.0.0',
|
|
310
|
+
entryPoint: './test-plugin.mjs',
|
|
311
|
+
capabilities: ['receipt:generate'],
|
|
312
|
+
api_version: '5.0.1'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
await manager.loadPlugin('test-plugin@1.0.0');
|
|
316
|
+
|
|
317
|
+
const state = manager.getPluginState('test-plugin@1.0.0');
|
|
318
|
+
expect(state).toBe('loaded');
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Publishing Plugins
|
|
324
|
+
|
|
325
|
+
### 1. Prepare Package
|
|
326
|
+
|
|
327
|
+
```json
|
|
328
|
+
{
|
|
329
|
+
"name": "@my-scope/kgc-plugin-name",
|
|
330
|
+
"version": "1.0.0",
|
|
331
|
+
"type": "module",
|
|
332
|
+
"main": "./index.mjs",
|
|
333
|
+
"exports": {
|
|
334
|
+
".": "./index.mjs"
|
|
335
|
+
},
|
|
336
|
+
"peerDependencies": {
|
|
337
|
+
"@unrdf/kgc-runtime": "^1.0.0"
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 2. Test Thoroughly
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
# Run all tests
|
|
346
|
+
npm test
|
|
347
|
+
|
|
348
|
+
# Check type safety
|
|
349
|
+
npm run typecheck
|
|
350
|
+
|
|
351
|
+
# Verify capabilities
|
|
352
|
+
npm run verify-plugin
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### 3. Submit to Registry
|
|
356
|
+
|
|
357
|
+
Create a PR to the [KGC Plugin Registry](https://github.com/unrdf/kgc-plugins):
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"name": "my-plugin",
|
|
362
|
+
"version": "1.0.0",
|
|
363
|
+
"description": "My custom plugin",
|
|
364
|
+
"repository": "https://github.com/my-org/my-plugin",
|
|
365
|
+
"verified": false
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Examples
|
|
370
|
+
|
|
371
|
+
See `templates/plugin-template/` for a complete example plugin with:
|
|
372
|
+
- Manifest configuration
|
|
373
|
+
- Receipt generation
|
|
374
|
+
- Input validation
|
|
375
|
+
- Error handling
|
|
376
|
+
- Comprehensive tests
|
|
377
|
+
|
|
378
|
+
## Support
|
|
379
|
+
|
|
380
|
+
- Documentation: https://unrdf.github.io/kgc-runtime
|
|
381
|
+
- Issues: https://github.com/unrdf/kgc-runtime/issues
|
|
382
|
+
- Discussions: https://github.com/unrdf/kgc-runtime/discussions
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unrdf/kgc-runtime",
|
|
3
|
+
"version": "26.4.2",
|
|
4
|
+
"description": "KGC governance runtime with comprehensive Zod schemas and work item system",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.mjs",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.mjs",
|
|
9
|
+
"./schemas": "./src/schemas.mjs",
|
|
10
|
+
"./work-item": "./src/work-item.mjs",
|
|
11
|
+
"./plugin-manager": "./src/plugin-manager.mjs",
|
|
12
|
+
"./plugin-isolation": "./src/plugin-isolation.mjs",
|
|
13
|
+
"./api-version": "./src/api-version.mjs"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"test:coverage": "vitest run --coverage"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"kgc",
|
|
22
|
+
"governance",
|
|
23
|
+
"runtime",
|
|
24
|
+
"schemas",
|
|
25
|
+
"zod",
|
|
26
|
+
"validation",
|
|
27
|
+
"work-item",
|
|
28
|
+
"async"
|
|
29
|
+
],
|
|
30
|
+
"author": "UNRDF Team",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@unrdf/oxigraph": "workspace:*",
|
|
34
|
+
"hash-wasm": "^4.11.0",
|
|
35
|
+
"zod": "^4.1.13"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"vitest": "^4.0.15"
|
|
39
|
+
}
|
|
40
|
+
}
|