@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 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 (typeof specification === "object" &&
34
- specification !== null &&
35
- "executionPermitted" in specification &&
36
- specification
37
- .executionPermitted === false) {
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 (typeof specification === "object" &&
44
- specification !== null &&
45
- "requiredCondition" in specification) {
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
- const context = request.context;
48
- if (typeof context === "object" &&
49
- context !== null &&
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 (typeof specification === "object" &&
61
- specification !== null &&
62
- "internalCapacityRequired" in specification) {
63
- const required = specification.internalCapacityRequired;
64
- const context = request.context;
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 (typeof specification === "object" &&
78
- specification !== null &&
79
- "externalCapacityRequired" in specification) {
80
- const required = specification.externalCapacityRequired;
81
- const context = request.context;
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.0",
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"