@contractspec/lib.contracts 1.49.0 → 1.51.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/app-config/contracts.d.ts +51 -51
- package/dist/app-config/events.d.ts +27 -27
- package/dist/app-config/lifecycle-contracts.d.ts +55 -55
- package/dist/app-config/runtime.d.ts +1 -1
- package/dist/app-config/spec.d.ts +1 -1
- package/dist/capabilities/capabilities.d.ts +64 -5
- package/dist/capabilities/capabilities.js +125 -0
- package/dist/capabilities/context.d.ts +88 -0
- package/dist/capabilities/context.js +87 -0
- package/dist/capabilities/docs/capabilities.docblock.js +191 -2
- package/dist/capabilities/guards.d.ts +110 -0
- package/dist/capabilities/guards.js +146 -0
- package/dist/capabilities/index.d.ts +4 -1
- package/dist/capabilities/index.js +4 -1
- package/dist/capabilities/validation.d.ts +76 -0
- package/dist/capabilities/validation.js +141 -0
- package/dist/client/react/feature-render.d.ts +2 -2
- package/dist/data-views/runtime.d.ts +1 -1
- package/dist/events.d.ts +79 -13
- package/dist/events.js +33 -3
- package/dist/examples/schema.d.ts +10 -10
- package/dist/experiments/spec.d.ts +7 -4
- package/dist/features/install.d.ts +4 -4
- package/dist/features/types.d.ts +28 -32
- package/dist/index.d.ts +21 -12
- package/dist/index.js +12 -3
- package/dist/install.d.ts +1 -1
- package/dist/integrations/openbanking/contracts/accounts.d.ts +67 -67
- package/dist/integrations/openbanking/contracts/balances.d.ts +35 -35
- package/dist/integrations/openbanking/contracts/transactions.d.ts +49 -49
- package/dist/integrations/openbanking/models.d.ts +55 -55
- package/dist/integrations/operations.d.ts +103 -103
- package/dist/integrations/spec.d.ts +1 -1
- package/dist/knowledge/operations.d.ts +67 -67
- package/dist/llm/exporters.d.ts +2 -2
- package/dist/markdown.d.ts +1 -1
- package/dist/onboarding-base.d.ts +29 -29
- package/dist/operations/operation.d.ts +6 -0
- package/dist/ownership.d.ts +133 -8
- package/dist/ownership.js +25 -0
- package/dist/policy/context.d.ts +237 -0
- package/dist/policy/context.js +227 -0
- package/dist/policy/guards.d.ts +145 -0
- package/dist/policy/guards.js +254 -0
- package/dist/policy/index.d.ts +12 -1
- package/dist/policy/index.js +11 -1
- package/dist/policy/spec.d.ts +7 -4
- package/dist/policy/validation.d.ts +67 -0
- package/dist/policy/validation.js +307 -0
- package/dist/presentations/presentations.d.ts +6 -0
- package/dist/tests/spec.d.ts +17 -12
- package/dist/themes.d.ts +7 -4
- package/dist/translations/index.d.ts +6 -0
- package/dist/translations/index.js +5 -0
- package/dist/translations/registry.d.ts +144 -0
- package/dist/translations/registry.js +223 -0
- package/dist/translations/spec.d.ts +126 -0
- package/dist/translations/spec.js +31 -0
- package/dist/translations/validation.d.ts +85 -0
- package/dist/translations/validation.js +328 -0
- package/dist/types.d.ts +140 -14
- package/dist/versioning/index.d.ts +2 -1
- package/dist/versioning/index.js +2 -1
- package/dist/versioning/refs.d.ts +179 -0
- package/dist/versioning/refs.js +161 -0
- package/dist/workflow/context.d.ts +191 -0
- package/dist/workflow/context.js +227 -0
- package/dist/workflow/index.d.ts +4 -2
- package/dist/workflow/index.js +4 -2
- package/dist/workflow/spec.d.ts +1 -1
- package/dist/workflow/validation.d.ts +64 -2
- package/dist/workflow/validation.js +194 -1
- package/package.json +19 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { PolicySpec } from "./spec.js";
|
|
2
|
+
import { OperationSpecRegistry } from "../operations/registry.js";
|
|
3
|
+
import { PolicyRegistry } from "./registry.js";
|
|
4
|
+
|
|
5
|
+
//#region src/policy/validation.d.ts
|
|
6
|
+
|
|
7
|
+
type PolicyValidationLevel = 'error' | 'warning' | 'info';
|
|
8
|
+
interface PolicyValidationIssue {
|
|
9
|
+
level: PolicyValidationLevel;
|
|
10
|
+
message: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
context?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface PolicyValidationResult {
|
|
15
|
+
valid: boolean;
|
|
16
|
+
issues: PolicyValidationIssue[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validate a policy spec for internal consistency.
|
|
20
|
+
*
|
|
21
|
+
* @param spec - Policy spec to validate
|
|
22
|
+
* @returns Validation result with any issues found
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const result = validatePolicySpec(myPolicy);
|
|
27
|
+
* if (!result.valid) {
|
|
28
|
+
* console.log('Issues:', result.issues);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function validatePolicySpec(spec: PolicySpec): PolicyValidationResult;
|
|
33
|
+
interface PolicyConsistencyDeps {
|
|
34
|
+
policies: PolicyRegistry;
|
|
35
|
+
operations?: OperationSpecRegistry;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate policy consistency across registries.
|
|
39
|
+
*
|
|
40
|
+
* Checks that:
|
|
41
|
+
* - Operations reference valid policies
|
|
42
|
+
* - Policy actions align with operation kinds
|
|
43
|
+
*
|
|
44
|
+
* @param deps - Registry dependencies
|
|
45
|
+
* @returns Validation result
|
|
46
|
+
*/
|
|
47
|
+
declare function validatePolicyConsistency(deps: PolicyConsistencyDeps): PolicyValidationResult;
|
|
48
|
+
declare class PolicyValidationError extends Error {
|
|
49
|
+
readonly issues: PolicyValidationIssue[];
|
|
50
|
+
constructor(message: string, issues: PolicyValidationIssue[]);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Assert that a policy spec is valid, throwing if not.
|
|
54
|
+
*
|
|
55
|
+
* @param spec - Policy spec to validate
|
|
56
|
+
* @throws {PolicyValidationError} If validation fails
|
|
57
|
+
*/
|
|
58
|
+
declare function assertPolicySpecValid(spec: PolicySpec): void;
|
|
59
|
+
/**
|
|
60
|
+
* Assert policy consistency across registries.
|
|
61
|
+
*
|
|
62
|
+
* @param deps - Registry dependencies
|
|
63
|
+
* @throws {PolicyValidationError} If validation fails
|
|
64
|
+
*/
|
|
65
|
+
declare function assertPolicyConsistency(deps: PolicyConsistencyDeps): void;
|
|
66
|
+
//#endregion
|
|
67
|
+
export { PolicyConsistencyDeps, PolicyValidationError, PolicyValidationIssue, PolicyValidationLevel, PolicyValidationResult, assertPolicyConsistency, assertPolicySpecValid, validatePolicyConsistency, validatePolicySpec };
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
//#region src/policy/validation.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validate a policy spec for internal consistency.
|
|
4
|
+
*
|
|
5
|
+
* @param spec - Policy spec to validate
|
|
6
|
+
* @returns Validation result with any issues found
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const result = validatePolicySpec(myPolicy);
|
|
11
|
+
* if (!result.valid) {
|
|
12
|
+
* console.log('Issues:', result.issues);
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
function validatePolicySpec(spec) {
|
|
17
|
+
const issues = [];
|
|
18
|
+
validateMeta(spec, issues);
|
|
19
|
+
validateRules(spec, issues);
|
|
20
|
+
validateFieldPolicies(spec, issues);
|
|
21
|
+
validateRateLimits(spec, issues);
|
|
22
|
+
validateConsents(spec, issues);
|
|
23
|
+
validateRelationships(spec, issues);
|
|
24
|
+
return {
|
|
25
|
+
valid: issues.filter((i) => i.level === "error").length === 0,
|
|
26
|
+
issues
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function validateMeta(spec, issues) {
|
|
30
|
+
const { meta } = spec;
|
|
31
|
+
if (!meta.key?.trim()) issues.push({
|
|
32
|
+
level: "error",
|
|
33
|
+
message: "Policy must have a non-empty key",
|
|
34
|
+
path: "meta.key"
|
|
35
|
+
});
|
|
36
|
+
if (!meta.version?.trim()) issues.push({
|
|
37
|
+
level: "error",
|
|
38
|
+
message: "Policy must have a non-empty version",
|
|
39
|
+
path: "meta.version"
|
|
40
|
+
});
|
|
41
|
+
if (!meta.owners?.length) issues.push({
|
|
42
|
+
level: "warning",
|
|
43
|
+
message: "Policy should specify owners",
|
|
44
|
+
path: "meta.owners"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function validateRules(spec, issues) {
|
|
48
|
+
if (!spec.rules?.length) {
|
|
49
|
+
issues.push({
|
|
50
|
+
level: "warning",
|
|
51
|
+
message: "Policy has no rules defined",
|
|
52
|
+
path: "rules"
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const seenRateRefs = /* @__PURE__ */ new Set();
|
|
57
|
+
spec.rules.forEach((rule, index) => {
|
|
58
|
+
const path = `rules[${index}]`;
|
|
59
|
+
if (!rule.actions?.length) issues.push({
|
|
60
|
+
level: "error",
|
|
61
|
+
message: "Rule must specify at least one action",
|
|
62
|
+
path: `${path}.actions`
|
|
63
|
+
});
|
|
64
|
+
if (!["allow", "deny"].includes(rule.effect)) issues.push({
|
|
65
|
+
level: "error",
|
|
66
|
+
message: `Invalid rule effect: ${rule.effect}`,
|
|
67
|
+
path: `${path}.effect`
|
|
68
|
+
});
|
|
69
|
+
if (typeof rule.rateLimit === "string") {
|
|
70
|
+
seenRateRefs.add(rule.rateLimit);
|
|
71
|
+
if (!spec.rateLimits?.some((rl) => rl.id === rule.rateLimit)) issues.push({
|
|
72
|
+
level: "error",
|
|
73
|
+
message: `Rate limit "${rule.rateLimit}" referenced but not defined`,
|
|
74
|
+
path: `${path}.rateLimit`
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (rule.requiresConsent?.length) {
|
|
78
|
+
for (const consentId of rule.requiresConsent) if (!spec.consents?.some((c) => c.id === consentId)) issues.push({
|
|
79
|
+
level: "error",
|
|
80
|
+
message: `Consent "${consentId}" referenced but not defined`,
|
|
81
|
+
path: `${path}.requiresConsent`
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
validateConditions(rule.conditions, `${path}.conditions`, issues);
|
|
85
|
+
});
|
|
86
|
+
if (spec.rateLimits?.length) {
|
|
87
|
+
for (const rl of spec.rateLimits) if (!seenRateRefs.has(rl.id)) {
|
|
88
|
+
if (!spec.rules.some((r) => typeof r.rateLimit === "object" && r.rateLimit.id === rl.id)) issues.push({
|
|
89
|
+
level: "info",
|
|
90
|
+
message: `Rate limit "${rl.id}" is defined but not referenced`,
|
|
91
|
+
path: `rateLimits`
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function validateFieldPolicies(spec, issues) {
|
|
97
|
+
if (!spec.fieldPolicies?.length) return;
|
|
98
|
+
const seenFields = /* @__PURE__ */ new Map();
|
|
99
|
+
spec.fieldPolicies.forEach((rule, index) => {
|
|
100
|
+
const path = `fieldPolicies[${index}]`;
|
|
101
|
+
if (!rule.field?.trim()) issues.push({
|
|
102
|
+
level: "error",
|
|
103
|
+
message: "Field policy must specify a field",
|
|
104
|
+
path: `${path}.field`
|
|
105
|
+
});
|
|
106
|
+
if (!rule.actions?.length) issues.push({
|
|
107
|
+
level: "error",
|
|
108
|
+
message: "Field policy must specify at least one action",
|
|
109
|
+
path: `${path}.actions`
|
|
110
|
+
});
|
|
111
|
+
for (const action of rule.actions) if (!["read", "write"].includes(action)) issues.push({
|
|
112
|
+
level: "error",
|
|
113
|
+
message: `Invalid field action: ${action}`,
|
|
114
|
+
path: `${path}.actions`
|
|
115
|
+
});
|
|
116
|
+
const existing = seenFields.get(rule.field) ?? [];
|
|
117
|
+
existing.push(rule);
|
|
118
|
+
seenFields.set(rule.field, existing);
|
|
119
|
+
validateConditions(rule.conditions, `${path}.conditions`, issues);
|
|
120
|
+
});
|
|
121
|
+
for (const [field, rules] of seenFields.entries()) if (rules.length > 1) {
|
|
122
|
+
if (rules.some((r) => r.effect === "allow") && rules.some((r) => r.effect === "deny")) issues.push({
|
|
123
|
+
level: "warning",
|
|
124
|
+
message: `Field "${field}" has potentially conflicting allow/deny policies`,
|
|
125
|
+
path: "fieldPolicies",
|
|
126
|
+
context: {
|
|
127
|
+
field,
|
|
128
|
+
ruleCount: rules.length
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function validateRateLimits(spec, issues) {
|
|
134
|
+
if (!spec.rateLimits?.length) return;
|
|
135
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
136
|
+
spec.rateLimits.forEach((rl, index) => {
|
|
137
|
+
const path = `rateLimits[${index}]`;
|
|
138
|
+
if (!rl.id?.trim()) issues.push({
|
|
139
|
+
level: "error",
|
|
140
|
+
message: "Rate limit must have an id",
|
|
141
|
+
path: `${path}.id`
|
|
142
|
+
});
|
|
143
|
+
else if (seenIds.has(rl.id)) issues.push({
|
|
144
|
+
level: "error",
|
|
145
|
+
message: `Duplicate rate limit id: ${rl.id}`,
|
|
146
|
+
path: `${path}.id`
|
|
147
|
+
});
|
|
148
|
+
else seenIds.add(rl.id);
|
|
149
|
+
if (typeof rl.rpm !== "number" || rl.rpm <= 0) issues.push({
|
|
150
|
+
level: "error",
|
|
151
|
+
message: "Rate limit rpm must be a positive number",
|
|
152
|
+
path: `${path}.rpm`
|
|
153
|
+
});
|
|
154
|
+
if (rl.windowSeconds !== void 0 && rl.windowSeconds <= 0) issues.push({
|
|
155
|
+
level: "error",
|
|
156
|
+
message: "Rate limit windowSeconds must be positive if specified",
|
|
157
|
+
path: `${path}.windowSeconds`
|
|
158
|
+
});
|
|
159
|
+
if (rl.burst !== void 0 && rl.burst < 0) issues.push({
|
|
160
|
+
level: "error",
|
|
161
|
+
message: "Rate limit burst must be non-negative if specified",
|
|
162
|
+
path: `${path}.burst`
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function validateConsents(spec, issues) {
|
|
167
|
+
if (!spec.consents?.length) return;
|
|
168
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
169
|
+
spec.consents.forEach((consent, index) => {
|
|
170
|
+
const path = `consents[${index}]`;
|
|
171
|
+
if (!consent.id?.trim()) issues.push({
|
|
172
|
+
level: "error",
|
|
173
|
+
message: "Consent must have an id",
|
|
174
|
+
path: `${path}.id`
|
|
175
|
+
});
|
|
176
|
+
else if (seenIds.has(consent.id)) issues.push({
|
|
177
|
+
level: "error",
|
|
178
|
+
message: `Duplicate consent id: ${consent.id}`,
|
|
179
|
+
path: `${path}.id`
|
|
180
|
+
});
|
|
181
|
+
else seenIds.add(consent.id);
|
|
182
|
+
if (!consent.scope?.trim()) issues.push({
|
|
183
|
+
level: "error",
|
|
184
|
+
message: "Consent must specify a scope",
|
|
185
|
+
path: `${path}.scope`
|
|
186
|
+
});
|
|
187
|
+
if (!consent.purpose?.trim()) issues.push({
|
|
188
|
+
level: "error",
|
|
189
|
+
message: "Consent must specify a purpose",
|
|
190
|
+
path: `${path}.purpose`
|
|
191
|
+
});
|
|
192
|
+
if (consent.expiresInDays !== void 0 && consent.expiresInDays <= 0) issues.push({
|
|
193
|
+
level: "error",
|
|
194
|
+
message: "Consent expiresInDays must be positive if specified",
|
|
195
|
+
path: `${path}.expiresInDays`
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function validateRelationships(spec, issues) {
|
|
200
|
+
if (!spec.relationships?.length) return;
|
|
201
|
+
const seenRelations = /* @__PURE__ */ new Set();
|
|
202
|
+
spec.relationships.forEach((rel, index) => {
|
|
203
|
+
const path = `relationships[${index}]`;
|
|
204
|
+
const key = `${rel.subjectType}:${rel.relation}:${rel.objectType}`;
|
|
205
|
+
if (!rel.subjectType?.trim()) issues.push({
|
|
206
|
+
level: "error",
|
|
207
|
+
message: "Relationship must specify subjectType",
|
|
208
|
+
path: `${path}.subjectType`
|
|
209
|
+
});
|
|
210
|
+
if (!rel.relation?.trim()) issues.push({
|
|
211
|
+
level: "error",
|
|
212
|
+
message: "Relationship must specify relation",
|
|
213
|
+
path: `${path}.relation`
|
|
214
|
+
});
|
|
215
|
+
if (!rel.objectType?.trim()) issues.push({
|
|
216
|
+
level: "error",
|
|
217
|
+
message: "Relationship must specify objectType",
|
|
218
|
+
path: `${path}.objectType`
|
|
219
|
+
});
|
|
220
|
+
if (seenRelations.has(key)) issues.push({
|
|
221
|
+
level: "warning",
|
|
222
|
+
message: `Duplicate relationship definition: ${key}`,
|
|
223
|
+
path
|
|
224
|
+
});
|
|
225
|
+
else seenRelations.add(key);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function validateConditions(conditions, path, issues) {
|
|
229
|
+
if (!conditions?.length) return;
|
|
230
|
+
conditions.forEach((cond, index) => {
|
|
231
|
+
if (!cond.expression?.trim()) issues.push({
|
|
232
|
+
level: "error",
|
|
233
|
+
message: "Condition must have a non-empty expression",
|
|
234
|
+
path: `${path}[${index}].expression`
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Validate policy consistency across registries.
|
|
240
|
+
*
|
|
241
|
+
* Checks that:
|
|
242
|
+
* - Operations reference valid policies
|
|
243
|
+
* - Policy actions align with operation kinds
|
|
244
|
+
*
|
|
245
|
+
* @param deps - Registry dependencies
|
|
246
|
+
* @returns Validation result
|
|
247
|
+
*/
|
|
248
|
+
function validatePolicyConsistency(deps) {
|
|
249
|
+
const issues = [];
|
|
250
|
+
for (const policy of deps.policies.list()) {
|
|
251
|
+
const specResult = validatePolicySpec(policy);
|
|
252
|
+
issues.push(...specResult.issues.map((i) => ({
|
|
253
|
+
...i,
|
|
254
|
+
path: `${policy.meta.key}.v${policy.meta.version}${i.path ? `.${i.path}` : ""}`
|
|
255
|
+
})));
|
|
256
|
+
}
|
|
257
|
+
if (deps.operations) for (const operation of deps.operations.list()) {
|
|
258
|
+
const policyRefs = operation.policy.policies ?? [];
|
|
259
|
+
for (const ref of policyRefs) if (!deps.policies.get(ref.key, ref.version)) issues.push({
|
|
260
|
+
level: "error",
|
|
261
|
+
message: `Operation "${operation.meta.key}.v${operation.meta.version}" references unknown policy "${ref.key}.v${ref.version}"`,
|
|
262
|
+
path: `operations.${operation.meta.key}.policy.policies`
|
|
263
|
+
});
|
|
264
|
+
const fieldPolicies = operation.policy.fieldPolicies ?? [];
|
|
265
|
+
for (const fp of fieldPolicies) if (fp.policy) {
|
|
266
|
+
if (!deps.policies.get(fp.policy.key, fp.policy.version)) issues.push({
|
|
267
|
+
level: "error",
|
|
268
|
+
message: `Operation "${operation.meta.key}.v${operation.meta.version}" references unknown field policy "${fp.policy.key}.v${fp.policy.version}"`,
|
|
269
|
+
path: `operations.${operation.meta.key}.policy.fieldPolicies`
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
valid: issues.filter((i) => i.level === "error").length === 0,
|
|
275
|
+
issues
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
var PolicyValidationError = class extends Error {
|
|
279
|
+
constructor(message, issues) {
|
|
280
|
+
super(message);
|
|
281
|
+
this.issues = issues;
|
|
282
|
+
this.name = "PolicyValidationError";
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Assert that a policy spec is valid, throwing if not.
|
|
287
|
+
*
|
|
288
|
+
* @param spec - Policy spec to validate
|
|
289
|
+
* @throws {PolicyValidationError} If validation fails
|
|
290
|
+
*/
|
|
291
|
+
function assertPolicySpecValid(spec) {
|
|
292
|
+
const result = validatePolicySpec(spec);
|
|
293
|
+
if (!result.valid) throw new PolicyValidationError(`Policy ${spec.meta.key}.v${spec.meta.version} is invalid`, result.issues);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Assert policy consistency across registries.
|
|
297
|
+
*
|
|
298
|
+
* @param deps - Registry dependencies
|
|
299
|
+
* @throws {PolicyValidationError} If validation fails
|
|
300
|
+
*/
|
|
301
|
+
function assertPolicyConsistency(deps) {
|
|
302
|
+
const result = validatePolicyConsistency(deps);
|
|
303
|
+
if (!result.valid) throw new PolicyValidationError("Policy consistency check failed", result.issues);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
//#endregion
|
|
307
|
+
export { PolicyValidationError, assertPolicyConsistency, assertPolicySpecValid, validatePolicyConsistency, validatePolicySpec };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CapabilityRef } from "../capabilities/capabilities.js";
|
|
1
2
|
import { OwnerShipMeta } from "../ownership.js";
|
|
2
3
|
import { AnySchemaModel } from "@contractspec/lib.schema";
|
|
3
4
|
import { BlockConfig } from "@blocknote/core";
|
|
@@ -38,6 +39,11 @@ type PresentationSource = PresentationSourceComponentReact | PresentationSourceB
|
|
|
38
39
|
*/
|
|
39
40
|
interface PresentationSpec {
|
|
40
41
|
meta: PresentationSpecMeta;
|
|
42
|
+
/**
|
|
43
|
+
* Optional reference to the capability that provides this presentation.
|
|
44
|
+
* Used for bidirectional linking between capabilities and presentations.
|
|
45
|
+
*/
|
|
46
|
+
capability?: CapabilityRef;
|
|
41
47
|
policy?: {
|
|
42
48
|
flags?: string[];
|
|
43
49
|
pii?: string[];
|
package/dist/tests/spec.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { OptionalVersionedSpecRef } from "../versioning/refs.js";
|
|
1
2
|
import { OwnerShipMeta } from "../ownership.js";
|
|
2
3
|
|
|
3
4
|
//#region src/tests/spec.d.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Reference to an operation to be tested.
|
|
8
|
+
* Version is optional; when omitted, refers to the latest version.
|
|
9
|
+
*/
|
|
10
|
+
type OperationTargetRef = OptionalVersionedSpecRef;
|
|
11
|
+
/**
|
|
12
|
+
* Reference to a workflow to be tested.
|
|
13
|
+
* Version is optional; when omitted, refers to the latest version.
|
|
14
|
+
*/
|
|
15
|
+
type WorkflowTargetRef = OptionalVersionedSpecRef;
|
|
12
16
|
type TestTarget = {
|
|
13
17
|
type: 'operation';
|
|
14
18
|
operation: OperationTargetRef;
|
|
@@ -66,10 +70,11 @@ interface TestSpec {
|
|
|
66
70
|
scenarios: TestScenario[];
|
|
67
71
|
coverage?: CoverageRequirement;
|
|
68
72
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Reference to a test spec.
|
|
75
|
+
* Version is optional; when omitted, refers to the latest version.
|
|
76
|
+
*/
|
|
77
|
+
type TestSpecRef = OptionalVersionedSpecRef;
|
|
73
78
|
declare class TestRegistry {
|
|
74
79
|
private readonly items;
|
|
75
80
|
register(spec: TestSpec): this;
|
package/dist/themes.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { VersionedSpecRef } from "./versioning/refs.js";
|
|
1
2
|
import { OwnerShipMeta } from "./ownership.js";
|
|
2
3
|
import { SpecContractRegistry } from "./registry.js";
|
|
3
4
|
|
|
4
5
|
//#region src/themes.d.ts
|
|
6
|
+
/** Scope at which a theme can be applied. */
|
|
5
7
|
type ThemeScope = 'global' | 'tenant' | 'user';
|
|
6
8
|
interface ThemeToken<T> {
|
|
7
9
|
value: T;
|
|
@@ -39,10 +41,11 @@ interface ThemeSpec {
|
|
|
39
41
|
components?: ComponentVariantSpec[];
|
|
40
42
|
overrides?: ThemeOverride[];
|
|
41
43
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Reference to a theme spec.
|
|
46
|
+
* Uses key and version to identify a specific theme.
|
|
47
|
+
*/
|
|
48
|
+
type ThemeRef = VersionedSpecRef;
|
|
46
49
|
declare class ThemeRegistry extends SpecContractRegistry<'theme', ThemeSpec> {
|
|
47
50
|
constructor(items?: ThemeSpec[]);
|
|
48
51
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BlueprintTranslationCatalog, PlatformTranslationCatalog, TranslationCatalogMeta, TranslationEntry } from "./catalog.js";
|
|
2
|
+
import { TenantTranslationOverride } from "./tenant.js";
|
|
3
|
+
import { Locale, MessageKey, MessageVariant, PlaceholderDef, PlaceholderType, PluralCategory, PluralRule, PluralRuleSet, TranslationMessage, TranslationMessages, TranslationMeta, TranslationRef, TranslationSpec, VariantType, defineTranslation } from "./spec.js";
|
|
4
|
+
import { TranslationLookupResult, TranslationRegistry, TranslationRegistryStats } from "./registry.js";
|
|
5
|
+
import { ICUValidationResult, MissingTranslation, TranslationValidationError, TranslationValidationIssue, TranslationValidationLevel, TranslationValidationResult, assertTranslationSpecValid, findAllMissingTranslations, findMissingTranslations, validateICUFormat, validateTranslationRegistry, validateTranslationSpec } from "./validation.js";
|
|
6
|
+
export { type BlueprintTranslationCatalog, ICUValidationResult, Locale, MessageKey, MessageVariant, MissingTranslation, PlaceholderDef, PlaceholderType, type PlatformTranslationCatalog, PluralCategory, PluralRule, PluralRuleSet, TenantTranslationOverride, type TranslationCatalogMeta, type TranslationEntry, TranslationLookupResult, TranslationMessage, TranslationMessages, TranslationMeta, TranslationRef, TranslationRegistry, TranslationRegistryStats, TranslationSpec, TranslationValidationError, TranslationValidationIssue, TranslationValidationLevel, TranslationValidationResult, VariantType, assertTranslationSpecValid, defineTranslation, findAllMissingTranslations, findMissingTranslations, validateICUFormat, validateTranslationRegistry, validateTranslationSpec };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { defineTranslation } from "./spec.js";
|
|
2
|
+
import { TranslationRegistry } from "./registry.js";
|
|
3
|
+
import { TranslationValidationError, assertTranslationSpecValid, findAllMissingTranslations, findMissingTranslations, validateICUFormat, validateTranslationRegistry, validateTranslationSpec } from "./validation.js";
|
|
4
|
+
|
|
5
|
+
export { TranslationRegistry, TranslationValidationError, assertTranslationSpecValid, defineTranslation, findAllMissingTranslations, findMissingTranslations, validateICUFormat, validateTranslationRegistry, validateTranslationSpec };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Locale, MessageKey, TranslationMessage, TranslationSpec } from "./spec.js";
|
|
2
|
+
|
|
3
|
+
//#region src/translations/registry.d.ts
|
|
4
|
+
|
|
5
|
+
interface TranslationLookupResult {
|
|
6
|
+
spec: TranslationSpec;
|
|
7
|
+
message: TranslationMessage;
|
|
8
|
+
locale: Locale;
|
|
9
|
+
fromFallback: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface TranslationRegistryStats {
|
|
12
|
+
totalSpecs: number;
|
|
13
|
+
locales: Locale[];
|
|
14
|
+
domains: string[];
|
|
15
|
+
totalMessages: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Registry for translation specs with locale-aware lookup.
|
|
19
|
+
*/
|
|
20
|
+
declare class TranslationRegistry {
|
|
21
|
+
private readonly specs;
|
|
22
|
+
private readonly latestByLocale;
|
|
23
|
+
private readonly locales;
|
|
24
|
+
private readonly domains;
|
|
25
|
+
constructor(items?: TranslationSpec[]);
|
|
26
|
+
/**
|
|
27
|
+
* Register a translation spec.
|
|
28
|
+
*
|
|
29
|
+
* @param spec - Translation spec to register
|
|
30
|
+
*/
|
|
31
|
+
register(spec: TranslationSpec): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get a translation spec by key, version, and locale.
|
|
34
|
+
*
|
|
35
|
+
* @param key - Translation spec key
|
|
36
|
+
* @param version - Version string
|
|
37
|
+
* @param locale - Locale code
|
|
38
|
+
* @returns Translation spec or undefined
|
|
39
|
+
*/
|
|
40
|
+
get(key: string, version: string, locale: Locale): TranslationSpec | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Get the latest version of a translation spec for a locale.
|
|
43
|
+
*
|
|
44
|
+
* @param key - Translation spec key
|
|
45
|
+
* @param locale - Locale code
|
|
46
|
+
* @returns Translation spec or undefined
|
|
47
|
+
*/
|
|
48
|
+
getLatest(key: string, locale: Locale): TranslationSpec | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Get a specific message from a translation spec.
|
|
51
|
+
*
|
|
52
|
+
* @param specKey - Translation spec key
|
|
53
|
+
* @param messageKey - Message key within the spec
|
|
54
|
+
* @param locale - Locale code
|
|
55
|
+
* @param version - Optional version (uses latest if not specified)
|
|
56
|
+
* @returns Translation message or undefined
|
|
57
|
+
*/
|
|
58
|
+
getMessage(specKey: string, messageKey: MessageKey, locale: Locale, version?: string): TranslationMessage | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Get a message value with fallback chain support.
|
|
61
|
+
*
|
|
62
|
+
* @param specKey - Translation spec key
|
|
63
|
+
* @param messageKey - Message key within the spec
|
|
64
|
+
* @param locale - Primary locale
|
|
65
|
+
* @param fallbackLocale - Fallback locale (optional, uses spec's fallback if not provided)
|
|
66
|
+
* @param version - Optional version (uses latest if not specified)
|
|
67
|
+
* @returns Translation lookup result or undefined
|
|
68
|
+
*/
|
|
69
|
+
getWithFallback(specKey: string, messageKey: MessageKey, locale: Locale, fallbackLocale?: Locale, version?: string): TranslationLookupResult | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Get a message value string with fallback.
|
|
72
|
+
*
|
|
73
|
+
* Convenience method that returns just the string value or a fallback.
|
|
74
|
+
*
|
|
75
|
+
* @param specKey - Translation spec key
|
|
76
|
+
* @param messageKey - Message key
|
|
77
|
+
* @param locale - Primary locale
|
|
78
|
+
* @param fallback - String to return if message not found (default: messageKey)
|
|
79
|
+
* @returns Message value or fallback
|
|
80
|
+
*/
|
|
81
|
+
getValue(specKey: string, messageKey: MessageKey, locale: Locale, fallback?: string): string;
|
|
82
|
+
/**
|
|
83
|
+
* List all locales available for a spec key.
|
|
84
|
+
*
|
|
85
|
+
* @param specKey - Translation spec key
|
|
86
|
+
* @returns Array of available locales
|
|
87
|
+
*/
|
|
88
|
+
listLocales(specKey: string): Locale[];
|
|
89
|
+
/**
|
|
90
|
+
* List all translation specs.
|
|
91
|
+
*
|
|
92
|
+
* @returns Array of all registered translation specs
|
|
93
|
+
*/
|
|
94
|
+
list(): TranslationSpec[];
|
|
95
|
+
/**
|
|
96
|
+
* List translation specs by locale.
|
|
97
|
+
*
|
|
98
|
+
* @param locale - Locale to filter by
|
|
99
|
+
* @returns Array of translation specs for the locale
|
|
100
|
+
*/
|
|
101
|
+
listByLocale(locale: Locale): TranslationSpec[];
|
|
102
|
+
/**
|
|
103
|
+
* List translation specs by domain.
|
|
104
|
+
*
|
|
105
|
+
* @param domain - Domain to filter by
|
|
106
|
+
* @returns Array of translation specs for the domain
|
|
107
|
+
*/
|
|
108
|
+
listByDomain(domain: string): TranslationSpec[];
|
|
109
|
+
/**
|
|
110
|
+
* Check if a translation spec exists.
|
|
111
|
+
*
|
|
112
|
+
* @param key - Translation spec key
|
|
113
|
+
* @param locale - Locale code
|
|
114
|
+
* @param version - Optional version
|
|
115
|
+
* @returns True if spec exists
|
|
116
|
+
*/
|
|
117
|
+
has(key: string, locale: Locale, version?: string): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Get all registered locales.
|
|
120
|
+
*
|
|
121
|
+
* @returns Set of all registered locales
|
|
122
|
+
*/
|
|
123
|
+
getLocales(): ReadonlySet<Locale>;
|
|
124
|
+
/**
|
|
125
|
+
* Get all registered domains.
|
|
126
|
+
*
|
|
127
|
+
* @returns Set of all registered domains
|
|
128
|
+
*/
|
|
129
|
+
getDomains(): ReadonlySet<string>;
|
|
130
|
+
/**
|
|
131
|
+
* Get registry statistics.
|
|
132
|
+
*
|
|
133
|
+
* @returns Registry statistics
|
|
134
|
+
*/
|
|
135
|
+
getStats(): TranslationRegistryStats;
|
|
136
|
+
/**
|
|
137
|
+
* Clear all registered specs.
|
|
138
|
+
*/
|
|
139
|
+
clear(): void;
|
|
140
|
+
private makeKey;
|
|
141
|
+
private isNewerVersion;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { TranslationLookupResult, TranslationRegistry, TranslationRegistryStats };
|