@peers-app/peers-sdk 0.16.5 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contracts/__tests__/builder.test.d.ts +1 -0
- package/dist/contracts/__tests__/builder.test.js +426 -0
- package/dist/contracts/__tests__/extract.test.d.ts +1 -0
- package/dist/contracts/__tests__/extract.test.js +145 -0
- package/dist/contracts/__tests__/integration.test.d.ts +1 -0
- package/dist/contracts/__tests__/integration.test.js +348 -0
- package/dist/contracts/__tests__/registry.test.d.ts +1 -0
- package/dist/contracts/__tests__/registry.test.js +324 -0
- package/dist/contracts/__tests__/validate.test.d.ts +1 -0
- package/dist/contracts/__tests__/validate.test.js +699 -0
- package/dist/contracts/builder.d.ts +102 -0
- package/dist/contracts/builder.js +216 -0
- package/dist/contracts/contract-providers.table.d.ts +40 -0
- package/dist/contracts/contract-providers.table.js +41 -0
- package/dist/contracts/contracts.table.d.ts +44 -0
- package/dist/contracts/contracts.table.js +44 -0
- package/dist/contracts/extract.d.ts +46 -0
- package/dist/contracts/extract.js +51 -0
- package/dist/contracts/index.d.ts +9 -0
- package/dist/contracts/index.js +31 -0
- package/dist/contracts/persistent-registry.d.ts +32 -0
- package/dist/contracts/persistent-registry.js +138 -0
- package/dist/contracts/registry.d.ts +58 -0
- package/dist/contracts/registry.js +155 -0
- package/dist/contracts/types.d.ts +108 -0
- package/dist/contracts/types.js +10 -0
- package/dist/contracts/validate.d.ts +24 -0
- package/dist/contracts/validate.js +274 -0
- package/dist/data/assistants.d.ts +5 -0
- package/dist/data/assistants.js +1 -0
- package/dist/data/package-versions.d.ts +2 -2
- package/dist/data/persistent-vars.d.ts +3 -0
- package/dist/data/persistent-vars.js +3 -0
- package/dist/data/tools.d.ts +5 -2
- package/dist/data/tools.js +1 -1
- package/dist/data/workflows.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/package-loader/contract-package-loader.d.ts +23 -0
- package/dist/package-loader/contract-package-loader.js +65 -0
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +1 -0
- package/dist/package-loader/package-loader.d.ts +11 -0
- package/dist/package-loader/package-loader.js +59 -8
- package/dist/rpc-types.d.ts +7 -0
- package/dist/rpc-types.js +4 -0
- package/dist/types/workflow.d.ts +3 -0
- package/dist/types/workflow.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PersistentContractRegistry = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
const contract_providers_table_1 = require("./contract-providers.table");
|
|
6
|
+
const contracts_table_1 = require("./contracts.table");
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
/**
|
|
9
|
+
* Bridges the in-memory `ContractRegistry` to SQLite-backed persistence tables.
|
|
10
|
+
* Handles persisting contract definitions and provider selections, as well as
|
|
11
|
+
* hydrating a fresh registry from stored data on startup.
|
|
12
|
+
*/
|
|
13
|
+
class PersistentContractRegistry {
|
|
14
|
+
registry;
|
|
15
|
+
dataContext;
|
|
16
|
+
constructor(registry, dataContext) {
|
|
17
|
+
this.registry = registry;
|
|
18
|
+
this.dataContext = dataContext;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Persist a contract definition and its provider to the database.
|
|
22
|
+
* If the definition already exists (same contractId), updates it.
|
|
23
|
+
* Creates or updates the provider record with the given active status.
|
|
24
|
+
*/
|
|
25
|
+
async persist(definition, providerPackageId, isActive) {
|
|
26
|
+
const contractsTable = (0, contracts_table_1.Contracts)(this.dataContext);
|
|
27
|
+
const providersTable = (0, contract_providers_table_1.ContractProviders)(this.dataContext);
|
|
28
|
+
const existingContract = await contractsTable.findOne({ contractId: definition.contractId }, { enforceUnique: true });
|
|
29
|
+
const shape = JSON.stringify({
|
|
30
|
+
tables: definition.tables,
|
|
31
|
+
tools: definition.tools,
|
|
32
|
+
observables: definition.observables,
|
|
33
|
+
});
|
|
34
|
+
if (existingContract) {
|
|
35
|
+
await contractsTable.save({
|
|
36
|
+
...existingContract,
|
|
37
|
+
devTag: definition.devTag,
|
|
38
|
+
name: definition.name,
|
|
39
|
+
description: definition.description,
|
|
40
|
+
shape,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const record = {
|
|
45
|
+
contractId: definition.contractId,
|
|
46
|
+
version: definition.version,
|
|
47
|
+
devTag: definition.devTag,
|
|
48
|
+
name: definition.name,
|
|
49
|
+
description: definition.description,
|
|
50
|
+
shape,
|
|
51
|
+
registeredAt: new Date().toISOString(),
|
|
52
|
+
};
|
|
53
|
+
await contractsTable.save(record);
|
|
54
|
+
}
|
|
55
|
+
const existingProvider = await providersTable.findOne({
|
|
56
|
+
contractId: definition.contractId,
|
|
57
|
+
version: definition.version,
|
|
58
|
+
providerPackageId,
|
|
59
|
+
}, { enforceUnique: true });
|
|
60
|
+
if (existingProvider) {
|
|
61
|
+
await providersTable.save({ ...existingProvider, isActive });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const providerRecord = {
|
|
65
|
+
contractProviderId: (0, utils_1.newid)(),
|
|
66
|
+
contractId: definition.contractId,
|
|
67
|
+
version: definition.version,
|
|
68
|
+
providerPackageId,
|
|
69
|
+
isActive,
|
|
70
|
+
registeredAt: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
await providersTable.save(providerRecord);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Hydrate the in-memory registry from persisted definitions and providers.
|
|
77
|
+
* Registers all stored definitions with their respective providers, then
|
|
78
|
+
* sets the active provider for each contract.
|
|
79
|
+
*/
|
|
80
|
+
async hydrate() {
|
|
81
|
+
const contractsTable = (0, contracts_table_1.Contracts)(this.dataContext);
|
|
82
|
+
const providersTable = (0, contract_providers_table_1.ContractProviders)(this.dataContext);
|
|
83
|
+
const allContracts = await contractsTable.list();
|
|
84
|
+
const allProviders = await providersTable.list();
|
|
85
|
+
const providersByKey = new Map();
|
|
86
|
+
for (const p of allProviders) {
|
|
87
|
+
const key = (0, types_1.contractKey)(p.contractId, p.version);
|
|
88
|
+
const list = providersByKey.get(key) ?? [];
|
|
89
|
+
list.push(p);
|
|
90
|
+
providersByKey.set(key, list);
|
|
91
|
+
}
|
|
92
|
+
for (const contractRecord of allContracts) {
|
|
93
|
+
const definition = this.recordToDefinition(contractRecord);
|
|
94
|
+
const key = (0, types_1.contractKey)(contractRecord.contractId, contractRecord.version);
|
|
95
|
+
const providers = providersByKey.get(key) ?? [];
|
|
96
|
+
for (const provider of providers) {
|
|
97
|
+
this.registry.register(provider.providerPackageId, definition);
|
|
98
|
+
}
|
|
99
|
+
const activeProvider = providers.find((p) => p.isActive);
|
|
100
|
+
if (activeProvider) {
|
|
101
|
+
this.registry.setActiveProvider(contractRecord.contractId, contractRecord.version, activeProvider.providerPackageId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Switch the active provider for a contract and persist the change.
|
|
107
|
+
* Returns false if the switch failed in the in-memory registry.
|
|
108
|
+
*/
|
|
109
|
+
async setActiveProvider(contractId, version, providerPackageId) {
|
|
110
|
+
const switched = this.registry.setActiveProvider(contractId, version, providerPackageId);
|
|
111
|
+
if (!switched)
|
|
112
|
+
return false;
|
|
113
|
+
const providersTable = (0, contract_providers_table_1.ContractProviders)(this.dataContext);
|
|
114
|
+
const providers = await providersTable.list({ contractId, version });
|
|
115
|
+
for (const provider of providers) {
|
|
116
|
+
const shouldBeActive = provider.providerPackageId === providerPackageId;
|
|
117
|
+
if (provider.isActive !== shouldBeActive) {
|
|
118
|
+
await providersTable.save({ ...provider, isActive: shouldBeActive });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
/** Convert a persisted contract record back to an `IContractDefinition`. */
|
|
124
|
+
recordToDefinition(record) {
|
|
125
|
+
const { tables, tools, observables } = JSON.parse(record.shape);
|
|
126
|
+
return {
|
|
127
|
+
contractId: record.contractId,
|
|
128
|
+
version: record.version,
|
|
129
|
+
devTag: record.devTag,
|
|
130
|
+
name: record.name,
|
|
131
|
+
description: record.description,
|
|
132
|
+
tables,
|
|
133
|
+
tools,
|
|
134
|
+
observables,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.PersistentContractRegistry = PersistentContractRegistry;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { IAlsoImplementsDeclaration, IConsumedContract, IContractDefinition, IValidationResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Per-group contract registry. Maps contract identities (contractId + version)
|
|
4
|
+
* to their active provider. In V1 this is in-memory only; persistence will
|
|
5
|
+
* be added when the registry is integrated with the runtime install flow.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ContractRegistry {
|
|
8
|
+
/** All known contract definitions, keyed by contractKey. */
|
|
9
|
+
private definitions;
|
|
10
|
+
/** Active provider for each contract, keyed by contractKey. */
|
|
11
|
+
private activeProviders;
|
|
12
|
+
/** All providers for a contract (active + inactive), keyed by contractKey. */
|
|
13
|
+
private allProviders;
|
|
14
|
+
/** Reverse index: packageId -> list of contract keys it provides. */
|
|
15
|
+
private packageContracts;
|
|
16
|
+
/**
|
|
17
|
+
* Register a package as a provider for a contract.
|
|
18
|
+
*
|
|
19
|
+
* Validates:
|
|
20
|
+
* 1. The implementation satisfies its own declared contract shape.
|
|
21
|
+
* 2. Immutability — a frozen contract cannot be redefined with a different shape.
|
|
22
|
+
* 3. `alsoImplements` declarations.
|
|
23
|
+
*
|
|
24
|
+
* If no active provider exists for this contract yet, the new provider
|
|
25
|
+
* becomes the active one automatically.
|
|
26
|
+
*
|
|
27
|
+
* @returns Validation result. If invalid the provider is not registered.
|
|
28
|
+
*/
|
|
29
|
+
register(providerPackageId: string, definition: IContractDefinition, alsoImplementsDecls?: IAlsoImplementsDeclaration[]): IValidationResult;
|
|
30
|
+
/**
|
|
31
|
+
* Switch the active provider for a contract to a different registered package.
|
|
32
|
+
* Returns false if the target package is not a registered provider for that contract.
|
|
33
|
+
*/
|
|
34
|
+
setActiveProvider(contractId: string, version: number, providerPackageId: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the active provider for a contract.
|
|
37
|
+
* Returns the contract definition if a provider is active, undefined otherwise.
|
|
38
|
+
*/
|
|
39
|
+
resolve(contractId: string, version: number): IContractDefinition | undefined;
|
|
40
|
+
/** Get the active provider's package ID for a contract. */
|
|
41
|
+
getProviderPackageId(contractId: string, version: number): string | undefined;
|
|
42
|
+
/** Get the stored contract definition (regardless of active provider). */
|
|
43
|
+
getDefinition(contractId: string, version: number): IContractDefinition | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Remove all contracts provided by a package. If the removed package was
|
|
46
|
+
* the active provider for a contract, the next registered provider (if any)
|
|
47
|
+
* becomes active.
|
|
48
|
+
*/
|
|
49
|
+
unregister(providerPackageId: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Check whether all consumed contracts have an active provider.
|
|
52
|
+
* Returns an object listing satisfied and missing contracts.
|
|
53
|
+
*/
|
|
54
|
+
checkConsumerDependencies(consumed: IConsumedContract[]): {
|
|
55
|
+
satisfied: IConsumedContract[];
|
|
56
|
+
missing: IConsumedContract[];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContractRegistry = void 0;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
const validate_1 = require("./validate");
|
|
6
|
+
/**
|
|
7
|
+
* Per-group contract registry. Maps contract identities (contractId + version)
|
|
8
|
+
* to their active provider. In V1 this is in-memory only; persistence will
|
|
9
|
+
* be added when the registry is integrated with the runtime install flow.
|
|
10
|
+
*/
|
|
11
|
+
class ContractRegistry {
|
|
12
|
+
/** All known contract definitions, keyed by contractKey. */
|
|
13
|
+
definitions = new Map();
|
|
14
|
+
/** Active provider for each contract, keyed by contractKey. */
|
|
15
|
+
activeProviders = new Map();
|
|
16
|
+
/** All providers for a contract (active + inactive), keyed by contractKey. */
|
|
17
|
+
allProviders = new Map();
|
|
18
|
+
/** Reverse index: packageId -> list of contract keys it provides. */
|
|
19
|
+
packageContracts = new Map();
|
|
20
|
+
/**
|
|
21
|
+
* Register a package as a provider for a contract.
|
|
22
|
+
*
|
|
23
|
+
* Validates:
|
|
24
|
+
* 1. The implementation satisfies its own declared contract shape.
|
|
25
|
+
* 2. Immutability — a frozen contract cannot be redefined with a different shape.
|
|
26
|
+
* 3. `alsoImplements` declarations.
|
|
27
|
+
*
|
|
28
|
+
* If no active provider exists for this contract yet, the new provider
|
|
29
|
+
* becomes the active one automatically.
|
|
30
|
+
*
|
|
31
|
+
* @returns Validation result. If invalid the provider is not registered.
|
|
32
|
+
*/
|
|
33
|
+
register(providerPackageId, definition, alsoImplementsDecls = []) {
|
|
34
|
+
const key = (0, types_1.contractKey)(definition.contractId, definition.version);
|
|
35
|
+
// Immutability check against any previously stored definition
|
|
36
|
+
const existingDef = this.definitions.get(key);
|
|
37
|
+
if (existingDef) {
|
|
38
|
+
const immResult = (0, validate_1.validateImmutability)(existingDef, definition);
|
|
39
|
+
if (!immResult.valid)
|
|
40
|
+
return immResult;
|
|
41
|
+
}
|
|
42
|
+
// alsoImplements check
|
|
43
|
+
if (alsoImplementsDecls.length > 0) {
|
|
44
|
+
const aiResult = (0, validate_1.validateAlsoImplements)(definition, alsoImplementsDecls, (cid, ver) => this.definitions.get((0, types_1.contractKey)(cid, ver)));
|
|
45
|
+
if (!aiResult.valid)
|
|
46
|
+
return aiResult;
|
|
47
|
+
}
|
|
48
|
+
// Store the definition (first-come for frozen, latest for dev)
|
|
49
|
+
this.definitions.set(key, definition);
|
|
50
|
+
const provider = { providerPackageId, definition };
|
|
51
|
+
// Add to the all-providers list
|
|
52
|
+
const providers = this.allProviders.get(key) ?? [];
|
|
53
|
+
const existingIdx = providers.findIndex((p) => p.providerPackageId === providerPackageId);
|
|
54
|
+
if (existingIdx >= 0) {
|
|
55
|
+
providers[existingIdx] = provider;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
providers.push(provider);
|
|
59
|
+
}
|
|
60
|
+
this.allProviders.set(key, providers);
|
|
61
|
+
// If no active provider, auto-activate
|
|
62
|
+
if (!this.activeProviders.has(key)) {
|
|
63
|
+
this.activeProviders.set(key, provider);
|
|
64
|
+
}
|
|
65
|
+
// Update reverse index
|
|
66
|
+
const pkgKeys = this.packageContracts.get(providerPackageId) ?? [];
|
|
67
|
+
if (!pkgKeys.includes(key)) {
|
|
68
|
+
pkgKeys.push(key);
|
|
69
|
+
}
|
|
70
|
+
this.packageContracts.set(providerPackageId, pkgKeys);
|
|
71
|
+
return { valid: true, errors: [] };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Switch the active provider for a contract to a different registered package.
|
|
75
|
+
* Returns false if the target package is not a registered provider for that contract.
|
|
76
|
+
*/
|
|
77
|
+
setActiveProvider(contractId, version, providerPackageId) {
|
|
78
|
+
const key = (0, types_1.contractKey)(contractId, version);
|
|
79
|
+
const providers = this.allProviders.get(key);
|
|
80
|
+
if (!providers)
|
|
81
|
+
return false;
|
|
82
|
+
const target = providers.find((p) => p.providerPackageId === providerPackageId);
|
|
83
|
+
if (!target)
|
|
84
|
+
return false;
|
|
85
|
+
this.activeProviders.set(key, target);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the active provider for a contract.
|
|
90
|
+
* Returns the contract definition if a provider is active, undefined otherwise.
|
|
91
|
+
*/
|
|
92
|
+
resolve(contractId, version) {
|
|
93
|
+
const key = (0, types_1.contractKey)(contractId, version);
|
|
94
|
+
return this.activeProviders.get(key)?.definition;
|
|
95
|
+
}
|
|
96
|
+
/** Get the active provider's package ID for a contract. */
|
|
97
|
+
getProviderPackageId(contractId, version) {
|
|
98
|
+
const key = (0, types_1.contractKey)(contractId, version);
|
|
99
|
+
return this.activeProviders.get(key)?.providerPackageId;
|
|
100
|
+
}
|
|
101
|
+
/** Get the stored contract definition (regardless of active provider). */
|
|
102
|
+
getDefinition(contractId, version) {
|
|
103
|
+
return this.definitions.get((0, types_1.contractKey)(contractId, version));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Remove all contracts provided by a package. If the removed package was
|
|
107
|
+
* the active provider for a contract, the next registered provider (if any)
|
|
108
|
+
* becomes active.
|
|
109
|
+
*/
|
|
110
|
+
unregister(providerPackageId) {
|
|
111
|
+
const keys = this.packageContracts.get(providerPackageId) ?? [];
|
|
112
|
+
for (const key of keys) {
|
|
113
|
+
const providers = this.allProviders.get(key);
|
|
114
|
+
if (providers) {
|
|
115
|
+
const filtered = providers.filter((p) => p.providerPackageId !== providerPackageId);
|
|
116
|
+
if (filtered.length > 0) {
|
|
117
|
+
this.allProviders.set(key, filtered);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.allProviders.delete(key);
|
|
121
|
+
}
|
|
122
|
+
// If this was the active provider, fall back or remove
|
|
123
|
+
const active = this.activeProviders.get(key);
|
|
124
|
+
if (active?.providerPackageId === providerPackageId) {
|
|
125
|
+
if (filtered.length > 0) {
|
|
126
|
+
this.activeProviders.set(key, filtered[0]);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.activeProviders.delete(key);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
this.packageContracts.delete(providerPackageId);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check whether all consumed contracts have an active provider.
|
|
138
|
+
* Returns an object listing satisfied and missing contracts.
|
|
139
|
+
*/
|
|
140
|
+
checkConsumerDependencies(consumed) {
|
|
141
|
+
const satisfied = [];
|
|
142
|
+
const missing = [];
|
|
143
|
+
for (const dep of consumed) {
|
|
144
|
+
const key = (0, types_1.contractKey)(dep.contractId, dep.version);
|
|
145
|
+
if (this.activeProviders.has(key)) {
|
|
146
|
+
satisfied.push(dep);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
missing.push(dep);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { satisfied, missing };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.ContractRegistry = ContractRegistry;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { Table } from "../data/orm/table";
|
|
2
|
+
import type { ITableDefinition } from "../data/orm/table-definitions.type";
|
|
3
|
+
import type { IToolInstance } from "../data/tools";
|
|
4
|
+
import type { Observable } from "../observable";
|
|
5
|
+
import type { FieldType, IField } from "../types/field-type";
|
|
6
|
+
/**
|
|
7
|
+
* A versioned interface definition declaring the shape of tables, tools, and
|
|
8
|
+
* observables that a package provides. Pure data — no executable code.
|
|
9
|
+
*/
|
|
10
|
+
export interface IContractDefinition {
|
|
11
|
+
contractId: string;
|
|
12
|
+
version: number;
|
|
13
|
+
/** Absent = frozen (immutable). `'dev'` = in-development, shape may change. */
|
|
14
|
+
devTag?: "dev";
|
|
15
|
+
name: string;
|
|
16
|
+
description: string;
|
|
17
|
+
tables: IContractTable[];
|
|
18
|
+
tools: IContractTool[];
|
|
19
|
+
observables: IContractObservable[];
|
|
20
|
+
}
|
|
21
|
+
/** Table shape within a contract — derived from ITableMetaData + IField[]. */
|
|
22
|
+
export interface IContractTable {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
primaryKeyName: string;
|
|
26
|
+
fields: IField[];
|
|
27
|
+
}
|
|
28
|
+
/** Tool signature within a contract — derived from ITool + IOSchema. */
|
|
29
|
+
export interface IContractTool {
|
|
30
|
+
name: string;
|
|
31
|
+
usageDescription: string;
|
|
32
|
+
inputFields: IField[];
|
|
33
|
+
outputFields: IField[];
|
|
34
|
+
}
|
|
35
|
+
/** Observable value exposed by a contract. */
|
|
36
|
+
export interface IContractObservable {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
valueType: FieldType;
|
|
40
|
+
writable: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A reference to a contract that a package wants to consume.
|
|
44
|
+
* Recorded during `definePackage` and checked at install time.
|
|
45
|
+
*/
|
|
46
|
+
export interface IConsumedContract {
|
|
47
|
+
contractId: string;
|
|
48
|
+
version: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Declares that the owning contract's implementation also satisfies another
|
|
52
|
+
* contract (single version or inclusive range).
|
|
53
|
+
*/
|
|
54
|
+
export interface IAlsoImplementsDeclaration {
|
|
55
|
+
contractId: string;
|
|
56
|
+
version: number | {
|
|
57
|
+
from: number;
|
|
58
|
+
to: number;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** The result of calling `definePackage()`. */
|
|
62
|
+
export interface IPackageDefinitionResult {
|
|
63
|
+
/** The peer ID of this package (25-char alphanumeric). */
|
|
64
|
+
packageId: string;
|
|
65
|
+
/** Semantic version string baked in from package.json at build time. */
|
|
66
|
+
version?: string;
|
|
67
|
+
/** Version channel tag (e.g. "dev", "beta", "stable"). */
|
|
68
|
+
versionTag?: string;
|
|
69
|
+
/** Contracts this package defines and provides. */
|
|
70
|
+
contracts: IContractDefinition[];
|
|
71
|
+
/** Contracts this package depends on. */
|
|
72
|
+
consumes: IConsumedContract[];
|
|
73
|
+
/** `alsoImplements` declarations keyed by the owning contractId+version. */
|
|
74
|
+
alsoImplements: Map<string, IAlsoImplementsDeclaration[]>;
|
|
75
|
+
/** Package-level items not part of any contract. */
|
|
76
|
+
assistants: unknown[];
|
|
77
|
+
appNavs: unknown[];
|
|
78
|
+
/** All executable tool instances across all contracts in this package. */
|
|
79
|
+
toolInstances: IToolInstance[];
|
|
80
|
+
/** All table definitions across all contracts in this package. */
|
|
81
|
+
tableDefinitions: ITableDefinition[];
|
|
82
|
+
}
|
|
83
|
+
/** A resolved contract in the registry, mapping contract shapes to live instances. */
|
|
84
|
+
export interface IResolvedContract {
|
|
85
|
+
contractId: string;
|
|
86
|
+
version: number;
|
|
87
|
+
providerPackageId: string;
|
|
88
|
+
tables: Record<string, Table<any>>;
|
|
89
|
+
tools: Record<string, IToolInstance>;
|
|
90
|
+
observables: Record<string, Observable<any>>;
|
|
91
|
+
}
|
|
92
|
+
/** Outcome of a validation check. */
|
|
93
|
+
export interface IValidationResult {
|
|
94
|
+
valid: boolean;
|
|
95
|
+
errors: IValidationError[];
|
|
96
|
+
}
|
|
97
|
+
export interface IValidationError {
|
|
98
|
+
/** Which element failed: `'table'`, `'tool'`, `'observable'`, `'contract'` */
|
|
99
|
+
kind: "table" | "tool" | "observable" | "contract" | "field";
|
|
100
|
+
/** Name of the element (table name, tool name, etc.) */
|
|
101
|
+
name: string;
|
|
102
|
+
message: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Builds a stable key for a contract identity (contractId + version).
|
|
106
|
+
* Used as map keys in the registry and alsoImplements tracking.
|
|
107
|
+
*/
|
|
108
|
+
export declare function contractKey(contractId: string, version: number): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.contractKey = contractKey;
|
|
4
|
+
/**
|
|
5
|
+
* Builds a stable key for a contract identity (contractId + version).
|
|
6
|
+
* Used as map keys in the registry and alsoImplements tracking.
|
|
7
|
+
*/
|
|
8
|
+
function contractKey(contractId, version) {
|
|
9
|
+
return `${contractId}@${version}`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IAlsoImplementsDeclaration, IContractDefinition, IValidationResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Validate that an implementation contract satisfies a target contract shape.
|
|
4
|
+
* The implementation must be a superset: all contract tables, tools, and
|
|
5
|
+
* observables must be present with compatible shapes.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateProviderSatisfiesContract(impl: IContractDefinition, contract: IContractDefinition): IValidationResult;
|
|
8
|
+
/**
|
|
9
|
+
* Validate that a frozen (stable) contract definition has not been modified.
|
|
10
|
+
* If the existing definition has no `devTag` it is frozen; the incoming
|
|
11
|
+
* definition must be structurally identical and also stable.
|
|
12
|
+
* Dev contracts (`devTag: "dev"`) may change freely but cannot be registered
|
|
13
|
+
* once a stable version exists for that contract+version.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateImmutability(existing: IContractDefinition, incoming: IContractDefinition): IValidationResult;
|
|
16
|
+
/**
|
|
17
|
+
* Validate that an implementation satisfies all contracts referenced by its
|
|
18
|
+
* `alsoImplements` declarations.
|
|
19
|
+
*
|
|
20
|
+
* @param impl The implementation's extracted contract definition.
|
|
21
|
+
* @param declarations The `alsoImplements` declarations for this contract.
|
|
22
|
+
* @param getContract Callback to look up an existing contract definition.
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateAlsoImplements(impl: IContractDefinition, declarations: IAlsoImplementsDeclaration[], getContract: (contractId: string, version: number) => IContractDefinition | undefined): IValidationResult;
|