@zensorum/sdk 0.1.0 → 0.1.1
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/index.d.ts +13 -0
- package/dist/index.js +97 -37
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,19 @@ export interface AIInput<TRecommendation = unknown> {
|
|
|
31
31
|
readonly source: string;
|
|
32
32
|
readonly recommendation: TRecommendation;
|
|
33
33
|
}
|
|
34
|
+
export type PolicyConditionOperator = "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
|
|
35
|
+
export interface PolicyCondition {
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly operator: PolicyConditionOperator;
|
|
38
|
+
readonly value: string | number | boolean | null;
|
|
39
|
+
}
|
|
40
|
+
export interface PolicySpecification {
|
|
41
|
+
readonly all?: readonly PolicyCondition[];
|
|
42
|
+
readonly executionPermitted?: boolean;
|
|
43
|
+
readonly requiredCondition?: string;
|
|
44
|
+
readonly internalCapacityRequired?: boolean;
|
|
45
|
+
readonly externalCapacityRequired?: boolean;
|
|
46
|
+
}
|
|
34
47
|
export interface Policy {
|
|
35
48
|
readonly id: string;
|
|
36
49
|
readonly name: string;
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,71 @@ function createExecutionId() {
|
|
|
15
15
|
.toString(36)
|
|
16
16
|
.slice(2, 10)}`;
|
|
17
17
|
}
|
|
18
|
+
function isRecord(value) {
|
|
19
|
+
return typeof value === "object" && value !== null;
|
|
20
|
+
}
|
|
21
|
+
function readContextValue(context, path) {
|
|
22
|
+
if (!path) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const segments = path.split(".");
|
|
26
|
+
let current = context;
|
|
27
|
+
for (const segment of segments) {
|
|
28
|
+
if (!isRecord(current) || !Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
current = current[segment];
|
|
32
|
+
}
|
|
33
|
+
return current;
|
|
34
|
+
}
|
|
35
|
+
function evaluateCondition(context, condition) {
|
|
36
|
+
const actual = readContextValue(context, condition.path);
|
|
37
|
+
if (actual === undefined) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
switch (condition.operator) {
|
|
41
|
+
case "eq":
|
|
42
|
+
return actual === condition.value;
|
|
43
|
+
case "neq":
|
|
44
|
+
return actual !== condition.value;
|
|
45
|
+
case "lt":
|
|
46
|
+
return (typeof actual === "number" &&
|
|
47
|
+
typeof condition.value === "number" &&
|
|
48
|
+
actual < condition.value);
|
|
49
|
+
case "lte":
|
|
50
|
+
return (typeof actual === "number" &&
|
|
51
|
+
typeof condition.value === "number" &&
|
|
52
|
+
actual <= condition.value);
|
|
53
|
+
case "gt":
|
|
54
|
+
return (typeof actual === "number" &&
|
|
55
|
+
typeof condition.value === "number" &&
|
|
56
|
+
actual > condition.value);
|
|
57
|
+
case "gte":
|
|
58
|
+
return (typeof actual === "number" &&
|
|
59
|
+
typeof condition.value === "number" &&
|
|
60
|
+
actual >= condition.value);
|
|
61
|
+
default:
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function evaluateContextualConditions(context, policyId, conditions) {
|
|
66
|
+
for (const condition of conditions) {
|
|
67
|
+
if (!condition.path ||
|
|
68
|
+
!["eq", "neq", "lt", "lte", "gt", "gte"].includes(condition.operator)) {
|
|
69
|
+
return {
|
|
70
|
+
status: "blocked",
|
|
71
|
+
reason: `Invalid contextual governance condition in institutional policy '${policyId}'.`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (!evaluateCondition(context, condition)) {
|
|
75
|
+
return {
|
|
76
|
+
status: "blocked",
|
|
77
|
+
reason: `Institutional context does not satisfy policy '${policyId}' at '${condition.path}'.`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
18
83
|
function evaluateGovernance(request) {
|
|
19
84
|
if (request.governance.policies.length === 0) {
|
|
20
85
|
return {
|
|
@@ -30,61 +95,56 @@ function evaluateGovernance(request) {
|
|
|
30
95
|
}
|
|
31
96
|
for (const policy of request.governance.policies) {
|
|
32
97
|
const specification = policy.specification;
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
98
|
+
if (!isRecord(specification)) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if ("executionPermitted" in specification &&
|
|
102
|
+
specification.executionPermitted === false) {
|
|
38
103
|
return {
|
|
39
104
|
status: "blocked",
|
|
40
105
|
reason: `Execution is prohibited by institutional policy '${policy.id}'.`,
|
|
41
106
|
};
|
|
42
107
|
}
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
108
|
+
if ("all" in specification) {
|
|
109
|
+
const conditions = specification.all;
|
|
110
|
+
if (!Array.isArray(conditions)) {
|
|
111
|
+
return {
|
|
112
|
+
status: "blocked",
|
|
113
|
+
reason: `Invalid contextual governance specification in institutional policy '${policy.id}'.`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const contextualDecision = evaluateContextualConditions(request.context, policy.id, conditions);
|
|
117
|
+
if (contextualDecision) {
|
|
118
|
+
return contextualDecision;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if ("requiredCondition" in specification) {
|
|
46
122
|
const requiredCondition = specification.requiredCondition;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"operationalCondition" in context &&
|
|
51
|
-
requiredCondition !==
|
|
52
|
-
context
|
|
53
|
-
.operationalCondition) {
|
|
123
|
+
if (isRecord(request.context) &&
|
|
124
|
+
Object.prototype.hasOwnProperty.call(request.context, "operationalCondition") &&
|
|
125
|
+
requiredCondition !== request.context.operationalCondition) {
|
|
54
126
|
return {
|
|
55
127
|
status: "blocked",
|
|
56
128
|
reason: `Institutional context does not satisfy policy '${policy.id}'.`,
|
|
57
129
|
};
|
|
58
130
|
}
|
|
59
131
|
}
|
|
60
|
-
if (
|
|
61
|
-
specification
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (required === true &&
|
|
66
|
-
typeof context === "object" &&
|
|
67
|
-
context !== null &&
|
|
68
|
-
"internalResponseCapacity" in context &&
|
|
69
|
-
context
|
|
70
|
-
.internalResponseCapacity !== "available") {
|
|
132
|
+
if ("internalCapacityRequired" in specification) {
|
|
133
|
+
if (specification.internalCapacityRequired === true &&
|
|
134
|
+
isRecord(request.context) &&
|
|
135
|
+
Object.prototype.hasOwnProperty.call(request.context, "internalResponseCapacity") &&
|
|
136
|
+
request.context.internalResponseCapacity !== "available") {
|
|
71
137
|
return {
|
|
72
138
|
status: "blocked",
|
|
73
139
|
reason: "Institutional context does not provide the required internal response capacity.",
|
|
74
140
|
};
|
|
75
141
|
}
|
|
76
142
|
}
|
|
77
|
-
if (
|
|
78
|
-
specification
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (required === true &&
|
|
83
|
-
typeof context === "object" &&
|
|
84
|
-
context !== null &&
|
|
85
|
-
"externalResponseCapacity" in context &&
|
|
86
|
-
context
|
|
87
|
-
.externalResponseCapacity !== "available") {
|
|
143
|
+
if ("externalCapacityRequired" in specification) {
|
|
144
|
+
if (specification.externalCapacityRequired === true &&
|
|
145
|
+
isRecord(request.context) &&
|
|
146
|
+
Object.prototype.hasOwnProperty.call(request.context, "externalResponseCapacity") &&
|
|
147
|
+
request.context.externalResponseCapacity !== "available") {
|
|
88
148
|
return {
|
|
89
149
|
status: "blocked",
|
|
90
150
|
reason: "Institutional context does not provide the required external response capacity.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zensorum/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Developer SDK for building governed institutional applications with Zensorum.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsc",
|
|
27
|
-
"typecheck": "tsc --noEmit"
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"test": "pnpm build && node --test tests/index.test.js"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"typescript": "^5.0.0"
|