@vertesia/studio-utils 1.3.0 → 1.4.0-dev.20260629.130134Z
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/lib/conditions/index.d.ts +2 -0
- package/lib/conditions/index.d.ts.map +1 -0
- package/lib/conditions/index.js +2 -0
- package/lib/conditions/index.js.map +1 -0
- package/lib/conditions/match.d.ts +54 -0
- package/lib/conditions/match.d.ts.map +1 -0
- package/lib/conditions/match.js +156 -0
- package/lib/conditions/match.js.map +1 -0
- package/lib/logger.d.ts +6 -0
- package/lib/logger.d.ts.map +1 -0
- package/lib/logger.js +15 -0
- package/lib/logger.js.map +1 -0
- package/lib/vertesia-studio-utils.js +1 -1
- package/lib/vertesia-studio-utils.js.map +1 -1
- package/package.json +26 -9
- package/src/conditions/index.ts +1 -0
- package/src/conditions/match.test.ts +75 -0
- package/src/conditions/match.ts +146 -0
- package/src/logger.ts +25 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conditions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/conditions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PropertyConditions } from '@vertesia/common';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a property path against a context object.
|
|
4
|
+
*
|
|
5
|
+
* Supports:
|
|
6
|
+
* - `clearance` → obj.clearance
|
|
7
|
+
* - `email` → obj.email
|
|
8
|
+
* - `properties.department` → obj.properties.department (one nested level under `properties`)
|
|
9
|
+
*
|
|
10
|
+
* Returns `undefined` if any segment is missing or non-traversable.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolvePath(obj: Record<string, unknown>, path: string): unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Match a wildcard pattern against a string value.
|
|
15
|
+
*
|
|
16
|
+
* Supports `*` as wildcard:
|
|
17
|
+
* - `"*@domain.com"` — ends with
|
|
18
|
+
* - `"bogdan.*"` — starts with
|
|
19
|
+
* - `"bogdan+*@vertesia.com"` — contains
|
|
20
|
+
* - `"*"` — match all
|
|
21
|
+
*
|
|
22
|
+
* Case-insensitive. Non-string `value` always returns `false`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function matchLike(value: unknown, pattern: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Evaluate a PropertyConditions object against a set of properties (JS-side, in-memory).
|
|
27
|
+
*
|
|
28
|
+
* Supports the MongoDB query syntax subset shared across token-server (principal property
|
|
29
|
+
* matching at JWT-mint time) and zeno-server (write-path ABAC permission checks against an
|
|
30
|
+
* in-memory document):
|
|
31
|
+
*
|
|
32
|
+
* - Direct value match (`{ field: literal }`)
|
|
33
|
+
* - `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
34
|
+
* - `$in`, `$nin` (against array `expected`)
|
|
35
|
+
* - `$exists` (boolean)
|
|
36
|
+
* - `$empty` (boolean) — true for undefined/null/empty-string/empty-array
|
|
37
|
+
* - `$like` (wildcard string, see {@link matchLike})
|
|
38
|
+
*
|
|
39
|
+
* All field-level conditions are AND'd (every field must match). Within a single field, all
|
|
40
|
+
* operators are AND'd.
|
|
41
|
+
*
|
|
42
|
+
* Mirrors the Mongo-side filter built by `conditionsToMongoFilter` (zeno-server utils.ts) and
|
|
43
|
+
* the ES-side filter built by `conditionsToEsQuery`. Use this when conditions need to be
|
|
44
|
+
* evaluated against a single hydrated document instead of pushed down as a query.
|
|
45
|
+
*
|
|
46
|
+
* Unknown operators emit a warning via the studio-utils logger and return false — surfacing
|
|
47
|
+
* misconfiguration loudly without breaking the surrounding token mint or permission check.
|
|
48
|
+
*
|
|
49
|
+
* `$principal.X` substitutions in conditions are expected to have already been resolved at
|
|
50
|
+
* JWT-mint time by `resolveConditions` in token-server; values reaching this function are
|
|
51
|
+
* concrete.
|
|
52
|
+
*/
|
|
53
|
+
export declare function matchConditions(conditions: PropertyConditions, properties: Record<string, unknown>): boolean;
|
|
54
|
+
//# sourceMappingURL=match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/conditions/match.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG3D;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKlE;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CA2D5G"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { getStudioUtilsLogger } from '../logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a property path against a context object.
|
|
4
|
+
*
|
|
5
|
+
* Supports:
|
|
6
|
+
* - `clearance` → obj.clearance
|
|
7
|
+
* - `email` → obj.email
|
|
8
|
+
* - `properties.department` → obj.properties.department (one nested level under `properties`)
|
|
9
|
+
*
|
|
10
|
+
* Returns `undefined` if any segment is missing or non-traversable.
|
|
11
|
+
*/
|
|
12
|
+
export function resolvePath(obj, path) {
|
|
13
|
+
if (path.startsWith('properties.')) {
|
|
14
|
+
const properties = obj.properties;
|
|
15
|
+
return properties && typeof properties === 'object'
|
|
16
|
+
? properties[path.slice(11)]
|
|
17
|
+
: undefined;
|
|
18
|
+
}
|
|
19
|
+
return obj[path];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Match a wildcard pattern against a string value.
|
|
23
|
+
*
|
|
24
|
+
* Supports `*` as wildcard:
|
|
25
|
+
* - `"*@domain.com"` — ends with
|
|
26
|
+
* - `"bogdan.*"` — starts with
|
|
27
|
+
* - `"bogdan+*@vertesia.com"` — contains
|
|
28
|
+
* - `"*"` — match all
|
|
29
|
+
*
|
|
30
|
+
* Case-insensitive. Non-string `value` always returns `false`.
|
|
31
|
+
*/
|
|
32
|
+
export function matchLike(value, pattern) {
|
|
33
|
+
if (typeof value !== 'string')
|
|
34
|
+
return false;
|
|
35
|
+
// Convert wildcard pattern to regex: escape regex chars except *, then replace * with .*
|
|
36
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
37
|
+
return new RegExp(`^${escaped}$`, 'i').test(value);
|
|
38
|
+
}
|
|
39
|
+
function compareOrdered(value, expected, op) {
|
|
40
|
+
if (typeof value !== 'number' && typeof value !== 'string')
|
|
41
|
+
return false;
|
|
42
|
+
if (typeof value !== typeof expected)
|
|
43
|
+
return false;
|
|
44
|
+
const left = value;
|
|
45
|
+
const right = expected;
|
|
46
|
+
switch (op) {
|
|
47
|
+
case '$gt':
|
|
48
|
+
return left > right;
|
|
49
|
+
case '$gte':
|
|
50
|
+
return left >= right;
|
|
51
|
+
case '$lt':
|
|
52
|
+
return left < right;
|
|
53
|
+
case '$lte':
|
|
54
|
+
return left <= right;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Evaluate a PropertyConditions object against a set of properties (JS-side, in-memory).
|
|
59
|
+
*
|
|
60
|
+
* Supports the MongoDB query syntax subset shared across token-server (principal property
|
|
61
|
+
* matching at JWT-mint time) and zeno-server (write-path ABAC permission checks against an
|
|
62
|
+
* in-memory document):
|
|
63
|
+
*
|
|
64
|
+
* - Direct value match (`{ field: literal }`)
|
|
65
|
+
* - `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
66
|
+
* - `$in`, `$nin` (against array `expected`)
|
|
67
|
+
* - `$exists` (boolean)
|
|
68
|
+
* - `$empty` (boolean) — true for undefined/null/empty-string/empty-array
|
|
69
|
+
* - `$like` (wildcard string, see {@link matchLike})
|
|
70
|
+
*
|
|
71
|
+
* All field-level conditions are AND'd (every field must match). Within a single field, all
|
|
72
|
+
* operators are AND'd.
|
|
73
|
+
*
|
|
74
|
+
* Mirrors the Mongo-side filter built by `conditionsToMongoFilter` (zeno-server utils.ts) and
|
|
75
|
+
* the ES-side filter built by `conditionsToEsQuery`. Use this when conditions need to be
|
|
76
|
+
* evaluated against a single hydrated document instead of pushed down as a query.
|
|
77
|
+
*
|
|
78
|
+
* Unknown operators emit a warning via the studio-utils logger and return false — surfacing
|
|
79
|
+
* misconfiguration loudly without breaking the surrounding token mint or permission check.
|
|
80
|
+
*
|
|
81
|
+
* `$principal.X` substitutions in conditions are expected to have already been resolved at
|
|
82
|
+
* JWT-mint time by `resolveConditions` in token-server; values reaching this function are
|
|
83
|
+
* concrete.
|
|
84
|
+
*/
|
|
85
|
+
export function matchConditions(conditions, properties) {
|
|
86
|
+
for (const [key, condition] of Object.entries(conditions)) {
|
|
87
|
+
const value = resolvePath(properties, key);
|
|
88
|
+
if (condition === null || condition === undefined || typeof condition !== 'object') {
|
|
89
|
+
// Direct value match
|
|
90
|
+
if (value !== condition)
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Operator object
|
|
95
|
+
const ops = condition;
|
|
96
|
+
for (const [op, expected] of Object.entries(ops)) {
|
|
97
|
+
switch (op) {
|
|
98
|
+
case '$eq':
|
|
99
|
+
if (value !== expected)
|
|
100
|
+
return false;
|
|
101
|
+
break;
|
|
102
|
+
case '$ne':
|
|
103
|
+
if (value === expected)
|
|
104
|
+
return false;
|
|
105
|
+
break;
|
|
106
|
+
case '$gt':
|
|
107
|
+
if (!compareOrdered(value, expected, '$gt'))
|
|
108
|
+
return false;
|
|
109
|
+
break;
|
|
110
|
+
case '$gte':
|
|
111
|
+
if (!compareOrdered(value, expected, '$gte'))
|
|
112
|
+
return false;
|
|
113
|
+
break;
|
|
114
|
+
case '$lt':
|
|
115
|
+
if (!compareOrdered(value, expected, '$lt'))
|
|
116
|
+
return false;
|
|
117
|
+
break;
|
|
118
|
+
case '$lte':
|
|
119
|
+
if (!compareOrdered(value, expected, '$lte'))
|
|
120
|
+
return false;
|
|
121
|
+
break;
|
|
122
|
+
case '$in':
|
|
123
|
+
if (!Array.isArray(expected) || !expected.includes(value))
|
|
124
|
+
return false;
|
|
125
|
+
break;
|
|
126
|
+
case '$nin':
|
|
127
|
+
if (Array.isArray(expected) && expected.includes(value))
|
|
128
|
+
return false;
|
|
129
|
+
break;
|
|
130
|
+
case '$exists':
|
|
131
|
+
if (typeof expected !== 'boolean' || (value !== undefined) !== expected)
|
|
132
|
+
return false;
|
|
133
|
+
break;
|
|
134
|
+
case '$empty': {
|
|
135
|
+
const isEmpty = value === undefined ||
|
|
136
|
+
value === null ||
|
|
137
|
+
value === '' ||
|
|
138
|
+
(Array.isArray(value) && value.length === 0);
|
|
139
|
+
if (typeof expected !== 'boolean' || isEmpty !== expected)
|
|
140
|
+
return false;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case '$like':
|
|
144
|
+
if (typeof expected !== 'string' || !matchLike(value, expected))
|
|
145
|
+
return false;
|
|
146
|
+
break;
|
|
147
|
+
default:
|
|
148
|
+
getStudioUtilsLogger().warn({ op, key }, 'Unknown operator in PropertyConditions');
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/conditions/match.ts"],"names":[],"mappings":"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"}
|
package/lib/logger.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface StudioUtilsLogger {
|
|
2
|
+
warn(details: Record<string, unknown>, message: string): void;
|
|
3
|
+
}
|
|
4
|
+
export declare function getStudioUtilsLogger(): StudioUtilsLogger;
|
|
5
|
+
export declare function installStudioUtilsLogger(customLogger: StudioUtilsLogger): StudioUtilsLogger;
|
|
6
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjE;AAcD,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,iBAAiB,GAAG,iBAAiB,CAI3F"}
|
package/lib/logger.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const consoleLogger = {
|
|
2
|
+
warn: (details, message) => {
|
|
3
|
+
console.warn(message, details);
|
|
4
|
+
},
|
|
5
|
+
};
|
|
6
|
+
let logger = consoleLogger;
|
|
7
|
+
export function getStudioUtilsLogger() {
|
|
8
|
+
return logger;
|
|
9
|
+
}
|
|
10
|
+
export function installStudioUtilsLogger(customLogger) {
|
|
11
|
+
const previousLogger = logger;
|
|
12
|
+
logger = customLogger;
|
|
13
|
+
return previousLogger;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAQA,MAAM,aAAa,GAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;CACJ,CAAC;AAEF,IAAI,MAAM,GAAsB,aAAa,CAAC;AAE9C,MAAM,UAAU,oBAAoB;IAChC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,YAA+B;IACpE,MAAM,cAAc,GAAG,MAAM,CAAC;IAC9B,MAAM,GAAG,YAAY,CAAC;IACtB,OAAO,cAAc,CAAC;AAC1B,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"handlebars";import{TemplateType as t,PromptSegmentDefType as r,Permission as n,SystemRoles as s}from"@vertesia/common";import{CompositeError as o,renderHandlebarsTemplate as a,renderJsTemplate as c,getFreeVariables as i}from"@vertesia/jst";function u(t){let r;try{r=e.parse(t)}catch{return new Set}const n=new Set,s=[],o=e=>{if(!e||"object"!=typeof e)return;const t=e;switch(t.type){case"Program":{const e=t.body;if(e)for(const t of e)o(t);break}case"BlockStatement":{const e=t.params;if(e)for(const t of e)o(t);o(t.hash);const r=t.program,n=t.inverse,a=new Set([...r?.blockParams??[],...n?.blockParams??[]]);s.push(a),o(t.program),o(t.inverse),s.pop();break}case"MustacheStatement":{const e=t.params,r=t.hash;if((e?.length??0)>0||(r?.pairs?.length??0)>0||o(t.path),e)for(const t of e)o(t);o(r);break}case"SubExpression":{const e=t.params;if(e)for(const t of e)o(t);o(t.hash);break}case"PathExpression":{if(t.data)break;const e=t.parts;if(!e||0===e.length)break;const o=e[0];if(r=o,s.some((e=>e.has(r))))break;n.add(o);break}case"Hash":{const e=t.pairs;if(e)for(const t of e)o(t.value);break}}var r};return o(r),n}function p(e,t="value"){if("$ref"in e)return`%${t}%`;switch((Array.isArray(e.type)?e.type:[e.type])[0]){case"string":default:return`%${t}%`;case"number":case"integer":return Math.floor(101*Math.random());case"boolean":return!0;case"array":{const r=e.items;if(r){const e=Math.floor(2*Math.random())+1;return Array.from({length:e},((e,n)=>p(r,`${t}_${n}`)))}return[]}case"object":{const t={};if(e.properties)for(const[r,n]of Object.entries(e.properties))t[r]=p(n,r);return t}case"null":return null}}function l(e,r,n,s){if(r===t.handlebars)return a(e,s);if(r===t.text)return e;const o=[...n.properties?Object.keys(n.properties):[],"_model"];return c(e,o,s)}function m(e,r,n){try{return{success:!0,content:l(e,t.jst,r,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function d(e,r,n){try{return{success:!0,content:l(e,t.handlebars,r,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function _(e,t){const r=y(e.configuration),n=t[r];let s;return s=Array.isArray(n)?JSON.stringify(n,void 0,2):`No "${r}" property found on input data`,{title:"Chat history",content:s}}function f(e,t){if(!e.template)return{title:"(unknown segment)",content:"",error:new Error("Prompt segment is missing its template")};const r=e.template.inputSchema||{},n=`@${e.template.role}`;try{return{title:n,content:l(e.template.content,e.template.content_type,r,t),segmentId:e.template.id}}catch(t){return{title:n,content:t instanceof Error?t.message:String(t),segmentId:e.template.id,error:t instanceof Error?t:new Error(String(t))}}}function h(e,t){const n=[];for(const s of e)s.type===r.chat?n.push(_(s,t)):s.type===r.template&&n.push(f(s,t));return n}function w(e,t){try{return h(e,"string"==typeof t?JSON.parse(t.trim()):t||{})}catch(e){return e instanceof o?e.errors.map((e=>({error:e,title:"Rendering Error",content:e.message}))):[{error:e instanceof Error?e:new Error(String(e)),title:"Rendering Error",content:e instanceof Error?e.message:String(e)}]}}function g(e,t){const n=[];for(const o of e)if(o.template){const e=o.template.inputSchema||{},r=l(o.template.content,o.template.content_type,e,t);n.push({role:o.template.role,content:r})}else{if(o.type!==r.chat)throw new Error(`Unknown prompt segment type: ${o.type}`);{const e=t[y(o.configuration)];if(s=e,!Array.isArray(s)||!s.every(b))throw new Error("Chat prompt segment must have a messages array");for(const t of e){if(!t.role)throw new Error("Chat prompt segment must have a role");n.push({role:t.role,content:t.content})}}}var s;return n}function y(e){return"object"==typeof e&&null!==e&&"chatKey"in e&&"string"==typeof e.chatKey?e.chatKey:"chat"}function b(e){return"object"==typeof e&&null!==e&&"role"in e&&"content"in e}const v=["_","Array","Set","_model"];function S(e){let r;r=e.contentType===t.handlebars?function(e,t){const r=[],n=u(e),s=new Set(t?.properties?Object.keys(t.properties):[]);for(const e of n)s.has(e)||r.push({type:"undeclared_template_variable",severity:"error",variable:e,message:`Template references variable '{{${e}}}' but it is not declared in input_schema.properties. Add '${e}' to the schema with an appropriate type.`});for(const e of s)n.has(e)||r.push({type:"unused_schema_variable",severity:"warning",variable:e,message:`Schema declares property '${e}' but the template never references it. Remove it from input_schema or use it via {{${e}}}.`});const o=t??{},a=p(o),c=d(e,o,"object"!=typeof a||null===a||Array.isArray(a)?{}:a);return c.success||r.push({type:"handlebars_render_error",severity:"error",message:`Handlebars rendering failed: ${c.error}`}),r}(e.content,e.inputSchema):e.contentType===t.jst?function(e,t){const r=[],n=new Set(t?.properties?Object.keys(t.properties):[]);let s;try{const t=i(e,{globals:v,acorn:{allowReturnOutsideFunction:!0,locations:!0}});s=t.vars;for(const e of t.errors)r.push({type:"jst_unsafe_construct",severity:"error",message:`JST validation error at ${e.location}: ${e.message}`})}catch(e){return r.push({type:"jst_render_error",severity:"error",message:`JST parse failed: ${e instanceof Error?e.message:String(e)}`}),r}for(const e of s)n.has(e)||r.push({type:"undeclared_template_variable",severity:"error",variable:e,message:`Template references variable '${e}' but it is not declared in input_schema.properties. Add '${e}' to the schema with an appropriate type.`});for(const e of n)s.has(e)||r.push({type:"unused_schema_variable",severity:"warning",variable:e,message:`Schema declares property '${e}' but the template never references it. Remove it from input_schema or use it in the template.`});if(!r.some((e=>"error"===e.severity))){const s=p(t??{}),o="object"!=typeof s||null===s||Array.isArray(s)?{}:s;try{c(e,[...n],o)}catch(e){r.push({type:"jst_render_error",severity:"error",message:`JST rendering failed: ${e instanceof Error?e.message:String(e)}`})}}return r}(e.content,e.inputSchema):[];const{error_count:n,warning_count:s}=function(e){let t=0,r=0;for(const n of e)"error"===n.severity?t++:"warning"===n.severity&&r++;return{error_count:t,warning_count:r}}(r);return{issues:r,error_count:n,warning_count:s}}class x{name;domain;permissions;constructor(e,t,r){this.name=e,this.domain=r,this.permissions=new Set(t)}hasPermission(e){return this.permissions.has(e)}}class k extends x{constructor(e,t){super(e,t,"system")}}class j extends x{applicableScopes;constructor(e,t,r,n){super(e,t,r),this.applicableScopes=n}}const $="content",E=["document","collection"];var A;!function(e){e.content_reader="content_reader",e.content_writer="content_writer",e.content_manager="content_manager"}(A||(A={}));const O={[A.content_reader]:new class extends j{constructor(){super(A.content_reader,["read"],$,E)}},[A.content_writer]:new class extends j{constructor(){super(A.content_writer,["read","write"],$,E)}},[A.content_manager]:new class extends j{constructor(){super(A.content_manager,["read","write","delete"],$,E)}}},P={domain:$,roles:new Map(Object.entries(O))};class R extends k{constructor(e,t){super(e,[n.account_member,...t])}}class M extends R{constructor(){super(s.developer,Object.values(n)),this.permissions.delete(n.account_admin),this.permissions.delete(n.project_admin),this.permissions.delete(n.project_settings_write),this.permissions.delete(n.env_admin),this.permissions.delete(n.manage_billing),this.permissions.delete(n.audit_read),this.permissions.delete(n.agent_run_read),this.permissions.delete(n.content_read_all),this.permissions.delete(n.content_superadmin),this.permissions.delete(n.workflow_superadmin)}}const T=[n.studio_access,n.account_read,n.project_integration_read,n.api_key_read,n.billing_read,n.audit_read,n.int_read,n.run_read,n.content_read,n.content_read_all,n.task_read,n.workflow_read,n.agent_run_read];class J extends R{constructor(e){super(e,T)}}const N={[s.owner]:new class extends R{constructor(){super(s.owner,Object.values(n))}},[s.admin]:new class extends R{constructor(){super(s.admin,Object.values(n))}},[s.manager]:new class extends R{constructor(){super(s.manager,Object.values(n)),this.permissions.delete(n.account_admin),this.permissions.delete(n.manage_billing),this.permissions.delete(n.audit_read),this.permissions.delete(n.agent_run_read),this.permissions.delete(n.content_read_all),this.permissions.delete(n.content_superadmin),this.permissions.delete(n.workflow_superadmin)}},[s.developer]:new M,[s.application]:new class extends R{constructor(){super(s.application,[n.int_read,n.int_execute,n.int_write,n.run_read,n.content_write,n.content_read,n.content_write,n.content_admin,n.project_admin,n.workflow_run,n.project_settings_write,n.account_write])}},[s.automation]:new class extends R{constructor(){super(s.automation,[n.content_read,n.content_write,n.content_admin,n.int_read,n.int_execute,n.run_read,n.workflow_run,n.project_integration_read])}},[s.content_processor]:new class extends R{constructor(){super(s.content_processor,[n.content_read,n.content_write,n.content_admin,n.content_superadmin,n.int_execute,n.workflow_read,n.workflow_run,n.run_read])}},[s.consumer]:new class extends R{constructor(){super(s.consumer,[n.content_admin,n.content_read,n.content_write,n.content_delete,n.int_read,n.int_execute,n.run_read,n.workflow_run])}},[s.executor]:new class extends R{constructor(){super(s.executor,[n.int_execute,n.run_read,n.workflow_run])}},[s.reader]:new class extends R{constructor(){super(s.reader,[n.int_read,n.run_read,n.content_read])}},[s.auditor]:new J(s.auditor),[s.support]:new J(s.support),[s.billing]:new class extends R{constructor(){super(s.billing,[n.manage_billing])}},[s.app_member]:new class extends R{constructor(){super(s.app_member,[n.int_read,n.int_execute,n.int_write,n.run_read,n.content_write,n.content_read,n.content_delete,n.workflow_run])}},[s.member]:new R(s.member,[]),[s.content_superadmin]:new class extends M{constructor(){super(),this.name=s.content_superadmin,this.permissions.add(n.content_superadmin)}}},C=[{domain:"system",roles:new Map(Object.entries(N))},P];function K(e){for(const t of C){const r=t.roles.get(e);if(r)return r}throw new Error(`Role ${e} not found`)}function H(){const e=[];for(const t of C)for(const r of t.roles.values())e.push(r);return e}function I(e){const t=C.find((t=>t.domain===e));return t?Array.from(t.roles.values()):[]}function B(e){return H().filter((t=>t instanceof j&&t.applicableScopes.includes(e)))}function F(){return H().filter((e=>e instanceof k))}function U(){return H().map((e=>e.name))}function q(e){const t=new Set;for(const r of e){const e=K(r);for(const r of e.permissions)t.add(r)}return Array.from(t)}class z{roles;constructor(e){this.roles=e}static fromRoleNames(e){const t=e.map((e=>K(e)));return new z(t)}static fromRoleName(e){const t=[K(e)];return new z(t)}hasPermission(e){return this.roles.some((t=>t.hasPermission(e)))}}export{j as AbacRole,A as ContentRoleNames,x as Role,z as RoleList,k as SystemRole,d as executeHandlebars,m as executeJST,u as extractHandlebarsVariables,p as generateMockData,U as getAllRoleNames,q as getPermissionsForRoles,K as getRoleByName,B as listAbacRolesForScope,H as listRoles,I as listRolesByDomain,F as listSystemRoles,g as renderPrompt,h as renderSegments,w as renderSegmentsOrErrors,l as renderTemplate,S as validatePrompt};
|
|
1
|
+
import e from"handlebars";import{TemplateType as t,PromptSegmentDefType as r,Permission as n,SystemRoles as s}from"@vertesia/common";import{CompositeError as o,renderHandlebarsTemplate as a,renderJsTemplate as c,getFreeVariables as i}from"@vertesia/jst";function u(t){let r;try{r=e.parse(t)}catch{return new Set}const n=new Set,s=[],o=e=>{if(!e||"object"!=typeof e)return;const t=e;switch(t.type){case"Program":{const e=t.body;if(e)for(const t of e)o(t);break}case"BlockStatement":{const e=t.params;if(e)for(const t of e)o(t);o(t.hash);const r=t.program,n=t.inverse,a=new Set([...r?.blockParams??[],...n?.blockParams??[]]);s.push(a),o(t.program),o(t.inverse),s.pop();break}case"MustacheStatement":{const e=t.params,r=t.hash;if((e?.length??0)>0||(r?.pairs?.length??0)>0||o(t.path),e)for(const t of e)o(t);o(r);break}case"SubExpression":{const e=t.params;if(e)for(const t of e)o(t);o(t.hash);break}case"PathExpression":{if(t.data)break;const e=t.parts;if(!e||0===e.length)break;const o=e[0];if(r=o,s.some(e=>e.has(r)))break;n.add(o);break}case"Hash":{const e=t.pairs;if(e)for(const t of e)o(t.value);break}}var r};return o(r),n}function p(e,t="value"){if("$ref"in e)return`%${t}%`;switch((Array.isArray(e.type)?e.type:[e.type])[0]){case"string":default:return`%${t}%`;case"number":case"integer":return Math.floor(101*Math.random());case"boolean":return!0;case"array":{const r=e.items;if(r){const e=Math.floor(2*Math.random())+1;return Array.from({length:e},(e,n)=>p(r,`${t}_${n}`))}return[]}case"object":{const t={};if(e.properties)for(const[r,n]of Object.entries(e.properties))t[r]=p(n,r);return t}case"null":return null}}function l(e,r,n,s){if(r===t.handlebars)return a(e,s);if(r===t.text)return e;const o=[...n.properties?Object.keys(n.properties):[],"_model"];return c(e,o,s)}function m(e,r,n){try{return{success:!0,content:l(e,t.jst,r,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function d(e,r,n){try{return{success:!0,content:l(e,t.handlebars,r,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function f(e,t){const r=y(e.configuration),n=t[r];let s;return s=Array.isArray(n)?JSON.stringify(n,void 0,2):`No "${r}" property found on input data`,{title:"Chat history",content:s}}function _(e,t){if(!e.template)return{title:"(unknown segment)",content:"",error:new Error("Prompt segment is missing its template")};const r=e.template.inputSchema||{},n=`@${e.template.role}`;try{return{title:n,content:l(e.template.content,e.template.content_type,r,t),segmentId:e.template.id}}catch(t){return{title:n,content:t instanceof Error?t.message:String(t),segmentId:e.template.id,error:t instanceof Error?t:new Error(String(t))}}}function h(e,t){const n=[];for(const s of e)s.type===r.chat?n.push(f(s,t)):s.type===r.template&&n.push(_(s,t));return n}function w(e,t){try{return h(e,"string"==typeof t?JSON.parse(t.trim()):t||{})}catch(e){return e instanceof o?e.errors.map(e=>({error:e,title:"Rendering Error",content:e.message})):[{error:e instanceof Error?e:new Error(String(e)),title:"Rendering Error",content:e instanceof Error?e.message:String(e)}]}}function g(e,t){const n=[];for(const s of e)if(s.template){const e=s.template.inputSchema||{},r=l(s.template.content,s.template.content_type,e,t);n.push({role:s.template.role,content:r})}else{if(s.type!==r.chat)throw new Error(`Unknown prompt segment type: ${s.type}`);{const e=t[y(s.configuration)];if(!b(e))throw new Error("Chat prompt segment must have a messages array");for(const t of e){if(!t.role)throw new Error("Chat prompt segment must have a role");n.push({role:t.role,content:t.content})}}}return n}function y(e){return"object"==typeof e&&null!==e&&"chatKey"in e&&"string"==typeof e.chatKey?e.chatKey:"chat"}function b(e){return Array.isArray(e)&&e.every(v)}function v(e){return"object"==typeof e&&null!==e&&"role"in e&&"content"in e}const S=["_","Array","Set","_model"];function x(e){let r;r=e.contentType===t.handlebars?function(e,t){const r=[],n=u(e),s=new Set(t?.properties?Object.keys(t.properties):[]);for(const e of n)s.has(e)||r.push({type:"undeclared_template_variable",severity:"error",variable:e,message:`Template references variable '{{${e}}}' but it is not declared in input_schema.properties. Add '${e}' to the schema with an appropriate type.`});for(const e of s)n.has(e)||r.push({type:"unused_schema_variable",severity:"warning",variable:e,message:`Schema declares property '${e}' but the template never references it. Remove it from input_schema or use it via {{${e}}}.`});const o=t??{},a=p(o),c=d(e,o,"object"!=typeof a||null===a||Array.isArray(a)?{}:a);return c.success||r.push({type:"handlebars_render_error",severity:"error",message:`Handlebars rendering failed: ${c.error}`}),r}(e.content,e.inputSchema):e.contentType===t.jst?function(e,t){const r=[],n=new Set(t?.properties?Object.keys(t.properties):[]);let s;try{const t=i(e,{globals:S,acorn:{allowReturnOutsideFunction:!0,locations:!0}});s=t.vars;for(const e of t.errors)r.push({type:"jst_unsafe_construct",severity:"error",message:`JST validation error at ${e.location}: ${e.message}`})}catch(e){return r.push({type:"jst_render_error",severity:"error",message:`JST parse failed: ${e instanceof Error?e.message:String(e)}`}),r}for(const e of s)n.has(e)||r.push({type:"undeclared_template_variable",severity:"error",variable:e,message:`Template references variable '${e}' but it is not declared in input_schema.properties. Add '${e}' to the schema with an appropriate type.`});for(const e of n)s.has(e)||r.push({type:"unused_schema_variable",severity:"warning",variable:e,message:`Schema declares property '${e}' but the template never references it. Remove it from input_schema or use it in the template.`});if(!r.some(e=>"error"===e.severity)){const s=p(t??{}),o="object"!=typeof s||null===s||Array.isArray(s)?{}:s;try{c(e,[...n],o)}catch(e){r.push({type:"jst_render_error",severity:"error",message:`JST rendering failed: ${e instanceof Error?e.message:String(e)}`})}}return r}(e.content,e.inputSchema):[];const{error_count:n,warning_count:s}=function(e){let t=0,r=0;for(const n of e)"error"===n.severity?t++:"warning"===n.severity&&r++;return{error_count:t,warning_count:r}}(r);return{issues:r,error_count:n,warning_count:s}}class k{name;domain;permissions;constructor(e,t,r){this.name=e,this.domain=r,this.permissions=new Set(t)}hasPermission(e){return this.permissions.has(e)}}class j extends k{constructor(e,t){super(e,t,"system")}}class $ extends k{applicableScopes;constructor(e,t,r,n){super(e,t,r),this.applicableScopes=n}}const E="content",A=["document","collection"];var O;!function(e){e.content_reader="content_reader",e.content_writer="content_writer",e.content_manager="content_manager"}(O||(O={}));const P={[O.content_reader]:new class extends ${constructor(){super(O.content_reader,["read"],E,A)}},[O.content_writer]:new class extends ${constructor(){super(O.content_writer,["read","write"],E,A)}},[O.content_manager]:new class extends ${constructor(){super(O.content_manager,["read","write","delete"],E,A)}}},R={domain:E,roles:new Map(Object.entries(P))};class M extends j{constructor(e,t){super(e,[n.account_member,...t])}}class T extends M{constructor(){super(s.developer,Object.values(n)),this.permissions.delete(n.account_admin),this.permissions.delete(n.project_admin),this.permissions.delete(n.project_settings_write),this.permissions.delete(n.env_admin),this.permissions.delete(n.manage_billing),this.permissions.delete(n.audit_read),this.permissions.delete(n.agent_run_read),this.permissions.delete(n.content_read_all),this.permissions.delete(n.content_superadmin),this.permissions.delete(n.workflow_superadmin)}}const J=[n.studio_access,n.account_read,n.project_integration_read,n.api_key_read,n.billing_read,n.audit_read,n.int_read,n.run_read,n.content_read,n.content_read_all,n.task_read,n.workflow_read,n.agent_run_read];class N extends M{constructor(e){super(e,J)}}const C={[s.owner]:new class extends M{constructor(){super(s.owner,Object.values(n))}},[s.admin]:new class extends M{constructor(){super(s.admin,Object.values(n))}},[s.manager]:new class extends M{constructor(){super(s.manager,Object.values(n)),this.permissions.delete(n.account_admin),this.permissions.delete(n.manage_billing),this.permissions.delete(n.audit_read),this.permissions.delete(n.agent_run_read),this.permissions.delete(n.content_read_all),this.permissions.delete(n.content_superadmin),this.permissions.delete(n.workflow_superadmin)}},[s.developer]:new T,[s.application]:new class extends M{constructor(){super(s.application,[n.int_read,n.int_execute,n.int_write,n.run_read,n.content_write,n.content_read,n.content_write,n.content_admin,n.project_admin,n.workflow_run,n.project_settings_write,n.account_write])}},[s.automation]:new class extends M{constructor(){super(s.automation,[n.content_read,n.content_write,n.content_admin,n.int_read,n.int_execute,n.run_read,n.workflow_run,n.project_integration_read])}},[s.content_processor]:new class extends M{constructor(){super(s.content_processor,[n.content_read,n.content_write,n.content_admin,n.content_superadmin,n.int_execute,n.workflow_read,n.workflow_run,n.run_read])}},[s.consumer]:new class extends M{constructor(){super(s.consumer,[n.content_admin,n.content_read,n.content_write,n.content_delete,n.int_read,n.int_execute,n.run_read,n.workflow_run])}},[s.executor]:new class extends M{constructor(){super(s.executor,[n.int_execute,n.run_read,n.workflow_run])}},[s.reader]:new class extends M{constructor(){super(s.reader,[n.int_read,n.run_read,n.content_read])}},[s.auditor]:new N(s.auditor),[s.support]:new N(s.support),[s.billing]:new class extends M{constructor(){super(s.billing,[n.manage_billing])}},[s.app_member]:new class extends M{constructor(){super(s.app_member,[n.int_read,n.int_execute,n.int_write,n.run_read,n.content_write,n.content_read,n.content_delete,n.workflow_run])}},[s.member]:new M(s.member,[]),[s.content_superadmin]:new class extends T{constructor(){super(),this.name=s.content_superadmin,this.permissions.add(n.content_superadmin)}}},K=[{domain:"system",roles:new Map(Object.entries(C))},R];function H(e){for(const t of K){const r=t.roles.get(e);if(r)return r}throw new Error(`Role ${e} not found`)}function I(){const e=[];for(const t of K)for(const r of t.roles.values())e.push(r);return e}function B(e){const t=K.find(t=>t.domain===e);return t?Array.from(t.roles.values()):[]}function F(e){return I().filter(t=>t instanceof $&&t.applicableScopes.includes(e))}function U(){return I().filter(e=>e instanceof j)}function q(){return I().map(e=>e.name)}function z(e){const t=new Set;for(const r of e){const e=H(r);for(const r of e.permissions)t.add(r)}return Array.from(t)}class D{roles;constructor(e){this.roles=e}static fromRoleNames(e){const t=e.map(e=>H(e));return new D(t)}static fromRoleName(e){const t=[H(e)];return new D(t)}hasPermission(e){return this.roles.some(t=>t.hasPermission(e))}}export{$ as AbacRole,O as ContentRoleNames,k as Role,D as RoleList,j as SystemRole,d as executeHandlebars,m as executeJST,u as extractHandlebarsVariables,p as generateMockData,q as getAllRoleNames,z as getPermissionsForRoles,H as getRoleByName,F as listAbacRolesForScope,I as listRoles,B as listRolesByDomain,U as listSystemRoles,g as renderPrompt,h as renderSegments,w as renderSegmentsOrErrors,l as renderTemplate,x as validatePrompt};
|
|
2
2
|
//# sourceMappingURL=vertesia-studio-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertesia-studio-utils.js","sources":["prompts/extract-vars.js","prompts/mock-data.js","prompts/render.js","prompts/validate.js","roles/classes.js","roles/content.js","roles/system.js","roles/index.js"],"sourcesContent":["import Handlebars from 'handlebars';\n/**\n * Extract the set of root-level variable names referenced by a Handlebars template.\n *\n * - `{{foo}}` → `foo`\n * - `{{obj.bar.baz}}` → `obj` (only the root identifier; nested access doesn't add `bar` or `baz`)\n * - `{{#if cond}}{{name}}{{/if}}` → `cond`, `name`\n * - `{{#each items as |item|}}{{item.name}}{{/each}}` → `items` (NOT `item` — bound by `as |item|`)\n * - `{{lookup obj key}}` → `obj`, `key` (helper name skipped)\n * - `{{@index}}`, `{{this}}` → ignored (built-in data vars / self)\n *\n * Helper names in mustaches and block heads (`{{customHelper x}}`, `{{#if x}}`) are NOT added to\n * the set — only the arguments and inner template references are. This matches the typical use\n * case for prompt validation: detect which schema properties the template actually reads.\n *\n * Returns an empty set on parse failure — callers should also run a syntactic render check\n * (e.g. `executeHandlebars`) to surface parse errors separately.\n */\nexport function extractHandlebarsVariables(template) {\n let ast;\n try {\n ast = Handlebars.parse(template);\n }\n catch {\n return new Set();\n }\n const variables = new Set();\n const localScopes = [];\n const isLocal = (name) => localScopes.some((scope) => scope.has(name));\n const visit = (node) => {\n if (!node || typeof node !== 'object')\n return;\n const n = node;\n switch (n.type) {\n case 'Program': {\n const body = n.body;\n if (body)\n for (const stmt of body)\n visit(stmt);\n break;\n }\n case 'BlockStatement': {\n // n.path is the helper name (`#if`, `#each`, `#customBlock`) — never a variable.\n // Visit params + hash to capture variables passed to the block helper.\n const params = n.params;\n if (params)\n for (const p of params)\n visit(p);\n visit(n.hash);\n // Track `as |x y|` block params — these are local bindings, not variables.\n const program = n.program;\n const inverse = n.inverse;\n const scope = new Set([...(program?.blockParams ?? []), ...(inverse?.blockParams ?? [])]);\n localScopes.push(scope);\n visit(n.program);\n visit(n.inverse);\n localScopes.pop();\n break;\n }\n case 'MustacheStatement': {\n // Bare mustache (no params, no hash) → it's a variable reference.\n // With params/hash, it's a helper call — skip the path (helper name), visit args.\n const params = n.params;\n const hash = n.hash;\n const isHelperCall = (params?.length ?? 0) > 0 || (hash?.pairs?.length ?? 0) > 0;\n if (!isHelperCall) {\n visit(n.path);\n }\n if (params)\n for (const p of params)\n visit(p);\n visit(hash);\n break;\n }\n case 'SubExpression': {\n // (helper arg1 arg2) — helper name in path is skipped, args carry variables.\n const params = n.params;\n if (params)\n for (const p of params)\n visit(p);\n visit(n.hash);\n break;\n }\n case 'PathExpression': {\n if (n.data)\n break; // `@-data` references (@index, @key, etc.)\n const parts = n.parts;\n if (!parts || parts.length === 0)\n break; // `this` / `.`\n const root = parts[0];\n if (isLocal(root))\n break;\n variables.add(root);\n break;\n }\n case 'Hash': {\n const pairs = n.pairs;\n if (pairs)\n for (const pair of pairs)\n visit(pair.value);\n break;\n }\n // ContentStatement, CommentStatement, *Literal, PartialStatement — no variables to extract.\n default:\n break;\n }\n };\n visit(ast);\n return variables;\n}\n//# sourceMappingURL=extract-vars.js.map","/**\n * Generate mock data that satisfies a JSON Schema.\n *\n * - string → `%property_name%` (visible placeholder, useful for previews and validation render tests)\n * - number/integer → random value 0–100\n * - boolean → true\n * - array → 1–2 items recursively generated from the items schema\n * - object → recursively populated from properties\n * - null → null\n * - $ref or unknown → `%property_name%`\n *\n * @param schema JSON schema to generate data for\n * @param propertyName Name used for string placeholders (default `value`)\n */\nexport function generateMockData(schema, propertyName = 'value') {\n if ('$ref' in schema) {\n return `%${propertyName}%`;\n }\n const types = Array.isArray(schema.type) ? schema.type : [schema.type];\n const primaryType = types[0];\n switch (primaryType) {\n case 'string':\n return `%${propertyName}%`;\n case 'number':\n case 'integer':\n return Math.floor(Math.random() * 101);\n case 'boolean':\n return true;\n case 'array': {\n const itemSchema = schema.items;\n if (itemSchema) {\n const itemCount = Math.floor(Math.random() * 2) + 1;\n return Array.from({ length: itemCount }, (_, index) => generateMockData(itemSchema, `${propertyName}_${index}`));\n }\n return [];\n }\n case 'object': {\n const result = {};\n if (schema.properties) {\n for (const [propName, propSchema] of Object.entries(schema.properties)) {\n result[propName] = generateMockData(propSchema, propName);\n }\n }\n return result;\n }\n case 'null':\n return null;\n default:\n return `%${propertyName}%`;\n }\n}\n//# sourceMappingURL=mock-data.js.map","import { PromptSegmentDefType, TemplateType } from '@vertesia/common';\nimport { CompositeError, renderHandlebarsTemplate, renderJsTemplate } from '@vertesia/jst';\n/**\n * Render a prompt template with the given input data.\n *\n * Handlebars templates use {{variable}} interpolation against `data`.\n * JST (JavaScript template) bodies evaluate against `data` with the schema's top-level\n * property names exposed as globals, plus `_model` — the active model id, which the\n * studio-server executor injects into the input as `{ ..._model: run.modelId }` when\n * executing an interaction (see `apps/studio-server/src/executor/ExecutionRequest.ts`\n * and `apps/studio-server/src/executor/rendering/template.ts`). Listing it here keeps\n * the Playground preview and `validatePrompt` in sync with runtime resolution — a JST\n * template referencing `_model` validates fine here and renders fine in production.\n *\n * For `TemplateType.text`, the content is returned verbatim — it is static text, not a\n * template — matching the studio-server executor (see `apps/studio-server/src/executor/\n * rendering/template.ts`). Routing it through the JST evaluator would compile the prose as\n * JavaScript and throw on any plain sentence (e.g. \"You are a helpful assistant.\").\n */\nexport function renderTemplate(code, contentType, schema, data) {\n if (contentType === TemplateType.handlebars) {\n return renderHandlebarsTemplate(code, data);\n }\n if (contentType === TemplateType.text) {\n return code;\n }\n const globals = [...(schema.properties ? Object.keys(schema.properties) : []), '_model'];\n return renderJsTemplate(code, globals, data);\n}\n/**\n * Execute a JST (JavaScript Template) with given data.\n * Returns a discriminated union to surface errors without throwing.\n */\nexport function executeJST(jstContent, schema, data) {\n try {\n const result = renderTemplate(jstContent, TemplateType.jst, schema, data);\n return { success: true, content: result };\n }\n catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n}\n/**\n * Execute a Handlebars template with given data.\n * Returns a discriminated union to surface errors without throwing.\n */\nexport function executeHandlebars(handlebarsContent, schema, data) {\n try {\n const result = renderTemplate(handlebarsContent, TemplateType.handlebars, schema, data);\n return { success: true, content: result };\n }\n catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n}\nfunction renderChatSegment(segment, data) {\n const chatKey = getChatKey(segment.configuration);\n const chat = data[chatKey];\n let content;\n if (Array.isArray(chat)) {\n content = JSON.stringify(chat, undefined, 2);\n }\n else {\n content = `No \"${chatKey}\" property found on input data`;\n }\n return {\n title: 'Chat history',\n content,\n };\n}\nfunction renderTemplateSegment(segment, data) {\n if (!segment.template) {\n return { title: '(unknown segment)', content: '', error: new Error('Prompt segment is missing its template') };\n }\n const schema = segment.template.inputSchema || {};\n const title = `@${segment.template.role}`;\n try {\n const content = renderTemplate(segment.template.content, segment.template.content_type, schema, data);\n return { title, content, segmentId: segment.template.id };\n }\n catch (error) {\n // Isolate the failure to this segment so the remaining segments still render.\n return {\n title,\n content: error instanceof Error ? error.message : String(error),\n segmentId: segment.template.id,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\nexport function renderSegments(segments, data) {\n const out = [];\n for (const segment of segments) {\n if (segment.type === PromptSegmentDefType.chat) {\n out.push(renderChatSegment(segment, data));\n }\n else if (segment.type === PromptSegmentDefType.template) {\n out.push(renderTemplateSegment(segment, data));\n }\n }\n return out;\n}\nexport function renderSegmentsOrErrors(segments, textOrObject) {\n try {\n return renderSegments(segments, typeof textOrObject === 'string' ? JSON.parse(textOrObject.trim()) : textOrObject || {});\n }\n catch (error) {\n if (error instanceof CompositeError) {\n return error.errors.map((err) => ({\n error: err,\n title: 'Rendering Error',\n content: err.message,\n }));\n }\n return [\n {\n error: error instanceof Error ? error : new Error(String(error)),\n title: 'Rendering Error',\n content: error instanceof Error ? error.message : String(error),\n },\n ];\n }\n}\nexport function renderPrompt(segments, payload) {\n const out = [];\n for (const segment of segments) {\n if (segment.template) {\n const schema = segment.template.inputSchema || {};\n const content = renderTemplate(segment.template.content, segment.template.content_type, schema, payload);\n out.push({ role: segment.template.role, content });\n }\n else if (segment.type === PromptSegmentDefType.chat) {\n const chatKey = getChatKey(segment.configuration);\n const messages = payload[chatKey];\n if (!isPromptSegmentArray(messages)) {\n throw new Error('Chat prompt segment must have a messages array');\n }\n for (const msg of messages) {\n if (!msg.role) {\n throw new Error('Chat prompt segment must have a role');\n }\n out.push({ role: msg.role, content: msg.content });\n }\n }\n else {\n throw new Error(`Unknown prompt segment type: ${segment.type}`);\n }\n }\n return out;\n}\nfunction getChatKey(configuration) {\n if (typeof configuration === 'object' &&\n configuration !== null &&\n 'chatKey' in configuration &&\n typeof configuration.chatKey === 'string') {\n return configuration.chatKey;\n }\n return 'chat';\n}\nfunction isPromptSegmentArray(value) {\n return Array.isArray(value) && value.every(isPromptSegment);\n}\nfunction isPromptSegment(value) {\n return typeof value === 'object' && value !== null && 'role' in value && 'content' in value;\n}\n//# sourceMappingURL=render.js.map","import { TemplateType } from '@vertesia/common';\nimport { getFreeVariables, renderJsTemplate } from '@vertesia/jst';\nimport { extractHandlebarsVariables } from './extract-vars.js';\nimport { generateMockData } from './mock-data.js';\nimport { executeHandlebars } from './render.js';\n// JST's renderJsTemplate auto-adds `_` (helpers object) and runtime injects `Set` and `Array`\n// — treat them as globals so they don't appear as free vars in user templates.\n// Globals always available to JST templates regardless of schema:\n// - `_`, `Array`, `Set`: runtime-injected by `renderJsTemplate` (jst library)\n// - `_model`: runtime-injected by the studio-server executor as `{ ..._model: run.modelId }`\n// (see ExecutionRequest.ts:313 and executor/rendering/template.ts:13)\n// Keeping these in sync with `renderTemplate` in ./render.ts so a JST template that runs in\n// production also passes the validator.\nconst JST_AUTO_GLOBALS = ['_', 'Array', 'Set', '_model'];\nfunction countSeverities(issues) {\n let error_count = 0;\n let warning_count = 0;\n for (const issue of issues) {\n if (issue.severity === 'error') {\n error_count++;\n }\n else if (issue.severity === 'warning') {\n warning_count++;\n }\n }\n return { error_count, warning_count };\n}\nfunction validateHandlebarsPrompt(content, inputSchema) {\n const issues = [];\n const usedVars = extractHandlebarsVariables(content);\n const declaredVars = new Set(inputSchema?.properties ? Object.keys(inputSchema.properties) : []);\n for (const used of usedVars) {\n if (!declaredVars.has(used)) {\n issues.push({\n type: 'undeclared_template_variable',\n severity: 'error',\n variable: used,\n message: `Template references variable '{{${used}}}' but it is not declared in input_schema.properties. Add '${used}' to the schema with an appropriate type.`,\n });\n }\n }\n for (const declared of declaredVars) {\n if (!usedVars.has(declared)) {\n issues.push({\n type: 'unused_schema_variable',\n severity: 'warning',\n variable: declared,\n message: `Schema declares property '${declared}' but the template never references it. Remove it from input_schema or use it via {{${declared}}}.`,\n });\n }\n }\n // Render-time smoke test — always runs so syntax errors and failing helper calls are\n // surfaced even when undeclared-variable errors are already in the list. Handlebars renders\n // missing vars as empty strings (non-strict by default), so the render check does NOT echo\n // the var errors — anything it reports is a distinct template problem worth showing.\n const renderSchema = inputSchema ?? {};\n const mockData = generateMockData(renderSchema);\n const mockObject = typeof mockData === 'object' && mockData !== null && !Array.isArray(mockData) ? mockData : {};\n const renderResult = executeHandlebars(content, renderSchema, mockObject);\n if (!renderResult.success) {\n issues.push({\n type: 'handlebars_render_error',\n severity: 'error',\n message: `Handlebars rendering failed: ${renderResult.error}`,\n });\n }\n return issues;\n}\nfunction validateJstPrompt(content, inputSchema) {\n const issues = [];\n const declaredVars = new Set(inputSchema?.properties ? Object.keys(inputSchema.properties) : []);\n let referenced;\n try {\n const result = getFreeVariables(content, {\n globals: JST_AUTO_GLOBALS,\n acorn: { allowReturnOutsideFunction: true, locations: true },\n });\n referenced = result.vars;\n for (const err of result.errors) {\n issues.push({\n type: 'jst_unsafe_construct',\n severity: 'error',\n message: `JST validation error at ${err.location}: ${err.message}`,\n });\n }\n }\n catch (parseError) {\n // Acorn parse failure — surface as render error since the template can't be compiled.\n issues.push({\n type: 'jst_render_error',\n severity: 'error',\n message: `JST parse failed: ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n });\n return issues;\n }\n for (const used of referenced) {\n if (!declaredVars.has(used)) {\n issues.push({\n type: 'undeclared_template_variable',\n severity: 'error',\n variable: used,\n message: `Template references variable '${used}' but it is not declared in input_schema.properties. Add '${used}' to the schema with an appropriate type.`,\n });\n }\n }\n for (const declared of declaredVars) {\n if (!referenced.has(declared)) {\n issues.push({\n type: 'unused_schema_variable',\n severity: 'warning',\n variable: declared,\n message: `Schema declares property '${declared}' but the template never references it. Remove it from input_schema or use it in the template.`,\n });\n }\n }\n // Render-time smoke test — only if there are no blocking errors so far, otherwise\n // the failure mode would just echo what we already reported.\n const blockingSoFar = issues.some((i) => i.severity === 'error');\n if (!blockingSoFar) {\n const renderSchema = inputSchema ?? {};\n const mockData = generateMockData(renderSchema);\n const mockObject = typeof mockData === 'object' && mockData !== null && !Array.isArray(mockData)\n ? mockData\n : {};\n try {\n renderJsTemplate(content, [...declaredVars], mockObject);\n }\n catch (renderError) {\n issues.push({\n type: 'jst_render_error',\n severity: 'error',\n message: `JST rendering failed: ${renderError instanceof Error ? renderError.message : String(renderError)}`,\n });\n }\n }\n return issues;\n}\n/**\n * Validate a single prompt template against its declared input schema.\n *\n * For `handlebars` and `jst` templates, the following checks are performed:\n * 1. Every variable referenced in the template must be declared as a top-level property\n * in `inputSchema.properties` (else → `undeclared_template_variable` error).\n * 2. Every property declared in `inputSchema.properties` should be referenced by the template\n * (else → `unused_schema_variable` warning — non-blocking).\n * 3. The template must render successfully against schema-derived mock data\n * (else → `handlebars_render_error` / `jst_render_error` error).\n * 4. For JST only: unsafe constructs (`with`, `for`, `while`, `import`, class, `this`,\n * dynamic property lookup, blacklisted props) → `jst_unsafe_construct` error.\n *\n * `text` content type passes through with no issues.\n */\nexport function validatePrompt(input) {\n let issues;\n if (input.contentType === TemplateType.handlebars) {\n issues = validateHandlebarsPrompt(input.content, input.inputSchema);\n }\n else if (input.contentType === TemplateType.jst) {\n issues = validateJstPrompt(input.content, input.inputSchema);\n }\n else {\n issues = [];\n }\n const { error_count, warning_count } = countSeverities(issues);\n return { issues, error_count, warning_count };\n}\n//# sourceMappingURL=validate.js.map","/**\n * Class hierarchy and registry-bound interface for the role system. These\n * are LOGIC — they have runtime behavior (constructors, instance methods,\n * subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`\n * (not common) per the package-layering contract: only types stay in common.\n */\n/**\n * A role: a named bundle of permissions that ACEs reference by name.\n *\n * Generic over the permission type so subclasses can tighten it:\n * - **System roles** declare `extends Role<Permission>` — construction time\n * type-checks against the central `Permission` enum.\n * - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions\n * are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific\n * verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in\n * `content_security`.\n *\n * The registry stores `Role` (defaulting to `Role<string>`) — the loose type\n * is the lowest common denominator. Tight typing is only enforced at\n * declaration sites of the role subclasses.\n */\nexport class Role {\n name;\n domain;\n permissions;\n constructor(name, permissions, domain) {\n this.name = name;\n this.domain = domain;\n this.permissions = new Set(permissions);\n }\n hasPermission(permission) {\n return this.permissions.has(permission);\n }\n}\n/**\n * Base class for built-in system roles. Hardcodes `domain: 'system'` and\n * specializes `Role<Permission>` so subclasses get compile-time type-checking\n * against the central `Permission` enum at construction.\n */\nexport class SystemRole extends Role {\n constructor(name, permissions) {\n super(name, permissions, 'system');\n }\n}\n/**\n * A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of\n * objects the role can be applied to at the ABAC scope level. Inherits\n * `Role<string>` because ABAC verbs aren't constrained to the central\n * `Permission` enum.\n *\n * The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.\n */\nexport class AbacRole extends Role {\n applicableScopes;\n constructor(name, permissions, domain, applicableScopes) {\n super(name, permissions, domain);\n this.applicableScopes = applicableScopes;\n }\n}\n//# sourceMappingURL=classes.js.map","import { AbacRole } from './classes.js';\nconst ContentRoleDomain = 'content';\nconst APPLICABLE_SCOPES = ['document', 'collection'];\n/**\n * Names of roles owned by the `content` domain. Apply to ContentSet ACEs\n * scoped to either `document` or `collection` — the semantics of \"read\n * content\" are the same for both kinds.\n */\nexport var ContentRoleNames;\n(function (ContentRoleNames) {\n ContentRoleNames[\"content_reader\"] = \"content_reader\";\n ContentRoleNames[\"content_writer\"] = \"content_writer\";\n ContentRoleNames[\"content_manager\"] = \"content_manager\";\n})(ContentRoleNames || (ContentRoleNames = {}));\nclass ContentReaderRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_reader, ['read'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nclass ContentWriterRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_writer, ['read', 'write'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nclass ContentManagerRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_manager, ['read', 'write', 'delete'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nconst contentRoles = {\n [ContentRoleNames.content_reader]: new ContentReaderRole(),\n [ContentRoleNames.content_writer]: new ContentWriterRole(),\n [ContentRoleNames.content_manager]: new ContentManagerRole(),\n};\nexport const contentPartition = {\n domain: ContentRoleDomain,\n roles: new Map(Object.entries(contentRoles)),\n};\n//# sourceMappingURL=content.js.map","import { Permission, SystemRoles } from '@vertesia/common';\nimport { SystemRole } from './classes.js';\nclass OrgMemberRole extends SystemRole {\n constructor(name, permissions) {\n super(name, [Permission.account_member, ...permissions]);\n }\n}\nclass OwnerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.owner, Object.values(Permission));\n }\n}\nclass AdminRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.admin, Object.values(Permission));\n }\n}\nclass ManagerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.manager, Object.values(Permission));\n this.permissions.delete(Permission.account_admin);\n this.permissions.delete(Permission.manage_billing);\n this.permissions.delete(Permission.audit_read);\n this.permissions.delete(Permission.agent_run_read);\n this.permissions.delete(Permission.content_read_all);\n this.permissions.delete(Permission.content_superadmin);\n this.permissions.delete(Permission.workflow_superadmin);\n }\n}\nclass DeveloperRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.developer, Object.values(Permission));\n this.permissions.delete(Permission.account_admin);\n this.permissions.delete(Permission.project_admin);\n this.permissions.delete(Permission.project_settings_write);\n this.permissions.delete(Permission.env_admin);\n this.permissions.delete(Permission.manage_billing);\n this.permissions.delete(Permission.audit_read);\n this.permissions.delete(Permission.agent_run_read);\n this.permissions.delete(Permission.content_read_all);\n this.permissions.delete(Permission.content_superadmin);\n this.permissions.delete(Permission.workflow_superadmin);\n }\n}\nclass ApplicationRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.application, [\n Permission.int_read,\n Permission.int_execute,\n Permission.int_write,\n Permission.run_read,\n Permission.content_write,\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.project_admin,\n Permission.workflow_run,\n Permission.project_settings_write,\n Permission.account_write,\n ]);\n }\n}\nclass AutomationRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.automation, [\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.int_read,\n Permission.int_execute,\n Permission.run_read,\n Permission.workflow_run,\n Permission.project_integration_read,\n ]);\n }\n}\nclass ContentProcessorRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.content_processor, [\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.content_superadmin,\n Permission.int_execute,\n Permission.workflow_read,\n Permission.workflow_run,\n Permission.run_read,\n ]);\n }\n}\nclass ConsumerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.consumer, [\n Permission.content_admin,\n Permission.content_read,\n Permission.content_write,\n Permission.content_delete,\n Permission.int_read,\n Permission.int_execute,\n Permission.run_read,\n Permission.workflow_run,\n ]);\n }\n}\nclass ExecutorRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.executor, [Permission.int_execute, Permission.run_read, Permission.workflow_run]);\n }\n}\nclass ReaderRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.reader, [Permission.int_read, Permission.run_read, Permission.content_read]);\n }\n}\nconst READ_ONLY_AUDIT_PERMISSIONS = [\n Permission.studio_access,\n Permission.account_read,\n Permission.project_integration_read,\n Permission.api_key_read,\n Permission.billing_read,\n Permission.audit_read,\n Permission.int_read,\n Permission.run_read,\n Permission.content_read,\n Permission.content_read_all,\n Permission.task_read,\n Permission.workflow_read,\n Permission.agent_run_read,\n];\nclass ReadOnlyAuditRole extends OrgMemberRole {\n constructor(name) {\n super(name, READ_ONLY_AUDIT_PERMISSIONS);\n }\n}\nclass BillingRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.billing, [Permission.manage_billing]);\n }\n}\nclass AppMemberRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.app_member, [\n Permission.int_read,\n Permission.int_execute,\n Permission.int_write,\n Permission.run_read,\n Permission.content_write,\n Permission.content_read,\n Permission.content_delete,\n Permission.workflow_run,\n ]);\n }\n}\nclass ContentSuperAdmin extends DeveloperRole {\n constructor() {\n super();\n this.name = SystemRoles.content_superadmin;\n this.permissions.add(Permission.content_superadmin);\n }\n}\n// The enum is still named `SystemRoles` (historical); the partition's domain\n// is `system` — the foundational built-in roles, distinct from feature domains\n// like `content` or `tasks`. Renaming the enum to `SystemRoles` is a separate\n// concern to revisit later.\nconst systemRoles = {\n [SystemRoles.owner]: new OwnerRole(),\n [SystemRoles.admin]: new AdminRole(),\n [SystemRoles.manager]: new ManagerRole(),\n [SystemRoles.developer]: new DeveloperRole(),\n [SystemRoles.application]: new ApplicationRole(),\n [SystemRoles.automation]: new AutomationRole(),\n [SystemRoles.content_processor]: new ContentProcessorRole(),\n [SystemRoles.consumer]: new ConsumerRole(),\n [SystemRoles.executor]: new ExecutorRole(),\n [SystemRoles.reader]: new ReaderRole(),\n [SystemRoles.auditor]: new ReadOnlyAuditRole(SystemRoles.auditor),\n [SystemRoles.support]: new ReadOnlyAuditRole(SystemRoles.support),\n [SystemRoles.billing]: new BillingRole(),\n [SystemRoles.app_member]: new AppMemberRole(),\n [SystemRoles.member]: new OrgMemberRole(SystemRoles.member, []),\n [SystemRoles.content_superadmin]: new ContentSuperAdmin(),\n};\nexport const systemPartition = {\n domain: 'system',\n roles: new Map(Object.entries(systemRoles)),\n};\n//# sourceMappingURL=system.js.map","import { AbacRole, SystemRole } from './classes.js';\nimport { contentPartition } from './content.js';\nimport { systemPartition } from './system.js';\nexport { AbacRole, Role, SystemRole } from './classes.js';\nexport { ContentRoleNames } from './content.js';\n/**\n * The ordered partition registry. Partitions are queried in this order — first\n * match wins. The `system` partition is registered first so domain-specific\n * partitions (added later) cannot shadow built-in system roles.\n */\nconst partitions = [systemPartition, contentPartition];\n/** Look up a role by its name across all registered partitions. */\nexport function getRoleByName(name) {\n for (const partition of partitions) {\n const role = partition.roles.get(name);\n if (role)\n return role;\n }\n throw new Error(`Role ${name} not found`);\n}\n/** List every role across all partitions, in partition registration order. */\nexport function listRoles() {\n const result = [];\n for (const partition of partitions) {\n for (const role of partition.roles.values()) {\n result.push(role);\n }\n }\n return result;\n}\n/** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */\nexport function listRolesByDomain(domain) {\n const partition = partitions.find((p) => p.domain === domain);\n return partition ? Array.from(partition.roles.values()) : [];\n}\n/**\n * ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,\n * `'collection'`). System roles are excluded — they don't carry scope semantics.\n */\nexport function listAbacRolesForScope(scope) {\n return listRoles().filter((r) => r instanceof AbacRole && r.applicableScopes.includes(scope));\n}\n/** Shortcut for the system partition: returns only `SystemRole` instances. */\nexport function listSystemRoles() {\n return listRoles().filter((r) => r instanceof SystemRole);\n}\n/** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */\nexport function getAllRoleNames() {\n return listRoles().map((r) => r.name);\n}\n/**\n * Merge the permissions granted by a set of roles into a single array.\n * Intended for the system-role gating path. For ABAC roles, the bare-verb\n * permissions returned here aren't directly meaningful — use the JWT\n * `content_security` pathway instead.\n */\nexport function getPermissionsForRoles(roleNames) {\n const permissions = new Set();\n for (const roleName of roleNames) {\n const role = getRoleByName(roleName);\n for (const permission of role.permissions) {\n permissions.add(permission);\n }\n }\n return Array.from(permissions);\n}\n/**\n * A list of roles with a unified `hasPermission` check across them.\n */\nexport class RoleList {\n roles;\n constructor(roles) {\n this.roles = roles;\n }\n static fromRoleNames(roleNames) {\n const roles = roleNames.map((r) => getRoleByName(r));\n return new RoleList(roles);\n }\n static fromRoleName(roleName) {\n const roles = [getRoleByName(roleName)];\n return new RoleList(roles);\n }\n hasPermission(perm) {\n return this.roles.some((role) => role.hasPermission(perm));\n }\n}\n//# sourceMappingURL=index.js.map"],"names":["extractHandlebarsVariables","template","ast","Handlebars","parse","Set","variables","localScopes","visit","node","n","type","body","stmt","params","p","hash","program","inverse","scope","blockParams","push","pop","length","pairs","path","data","parts","root","name","some","has","add","pair","value","generateMockData","schema","propertyName","Array","isArray","Math","floor","random","itemSchema","items","itemCount","from","_","index","result","properties","propName","propSchema","Object","entries","renderTemplate","code","contentType","TemplateType","handlebars","renderHandlebarsTemplate","text","globals","keys","renderJsTemplate","executeJST","jstContent","success","content","jst","error","Error","message","String","executeHandlebars","handlebarsContent","renderChatSegment","segment","chatKey","getChatKey","configuration","chat","JSON","stringify","undefined","title","renderTemplateSegment","inputSchema","role","content_type","segmentId","id","renderSegments","segments","out","PromptSegmentDefType","renderSegmentsOrErrors","textOrObject","trim","CompositeError","errors","map","err","renderPrompt","payload","messages","every","isPromptSegment","msg","JST_AUTO_GLOBALS","validatePrompt","input","issues","usedVars","declaredVars","used","severity","variable","declared","renderSchema","mockData","renderResult","validateHandlebarsPrompt","referenced","getFreeVariables","acorn","allowReturnOutsideFunction","locations","vars","location","parseError","i","mockObject","renderError","validateJstPrompt","error_count","warning_count","issue","countSeverities","Role","domain","permissions","constructor","this","hasPermission","permission","SystemRole","super","AbacRole","applicableScopes","ContentRoleDomain","APPLICABLE_SCOPES","ContentRoleNames","contentRoles","content_reader","content_writer","content_manager","contentPartition","roles","Map","OrgMemberRole","Permission","account_member","DeveloperRole","SystemRoles","developer","values","delete","account_admin","project_admin","project_settings_write","env_admin","manage_billing","audit_read","agent_run_read","content_read_all","content_superadmin","workflow_superadmin","READ_ONLY_AUDIT_PERMISSIONS","studio_access","account_read","project_integration_read","api_key_read","billing_read","int_read","run_read","content_read","task_read","workflow_read","ReadOnlyAuditRole","systemRoles","owner","admin","manager","application","int_execute","int_write","content_write","content_admin","workflow_run","account_write","automation","content_processor","consumer","content_delete","executor","reader","auditor","support","billing","app_member","member","partitions","getRoleByName","partition","get","listRoles","listRolesByDomain","find","listAbacRolesForScope","filter","r","includes","listSystemRoles","getAllRoleNames","getPermissionsForRoles","roleNames","roleName","RoleList","fromRoleNames","fromRoleName","perm"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vertesia-studio-utils.js","sources":["prompts/extract-vars.js","prompts/mock-data.js","prompts/render.js","prompts/validate.js","roles/classes.js","roles/content.js","roles/system.js","roles/index.js"],"sourcesContent":["import Handlebars from 'handlebars';\n/**\n * Extract the set of root-level variable names referenced by a Handlebars template.\n *\n * - `{{foo}}` → `foo`\n * - `{{obj.bar.baz}}` → `obj` (only the root identifier; nested access doesn't add `bar` or `baz`)\n * - `{{#if cond}}{{name}}{{/if}}` → `cond`, `name`\n * - `{{#each items as |item|}}{{item.name}}{{/each}}` → `items` (NOT `item` — bound by `as |item|`)\n * - `{{lookup obj key}}` → `obj`, `key` (helper name skipped)\n * - `{{@index}}`, `{{this}}` → ignored (built-in data vars / self)\n *\n * Helper names in mustaches and block heads (`{{customHelper x}}`, `{{#if x}}`) are NOT added to\n * the set — only the arguments and inner template references are. This matches the typical use\n * case for prompt validation: detect which schema properties the template actually reads.\n *\n * Returns an empty set on parse failure — callers should also run a syntactic render check\n * (e.g. `executeHandlebars`) to surface parse errors separately.\n */\nexport function extractHandlebarsVariables(template) {\n let ast;\n try {\n ast = Handlebars.parse(template);\n }\n catch {\n return new Set();\n }\n const variables = new Set();\n const localScopes = [];\n const isLocal = (name) => localScopes.some((scope) => scope.has(name));\n const visit = (node) => {\n if (!node || typeof node !== 'object')\n return;\n const n = node;\n switch (n.type) {\n case 'Program': {\n const body = n.body;\n if (body)\n for (const stmt of body)\n visit(stmt);\n break;\n }\n case 'BlockStatement': {\n // n.path is the helper name (`#if`, `#each`, `#customBlock`) — never a variable.\n // Visit params + hash to capture variables passed to the block helper.\n const params = n.params;\n if (params)\n for (const p of params)\n visit(p);\n visit(n.hash);\n // Track `as |x y|` block params — these are local bindings, not variables.\n const program = n.program;\n const inverse = n.inverse;\n const scope = new Set([...(program?.blockParams ?? []), ...(inverse?.blockParams ?? [])]);\n localScopes.push(scope);\n visit(n.program);\n visit(n.inverse);\n localScopes.pop();\n break;\n }\n case 'MustacheStatement': {\n // Bare mustache (no params, no hash) → it's a variable reference.\n // With params/hash, it's a helper call — skip the path (helper name), visit args.\n const params = n.params;\n const hash = n.hash;\n const isHelperCall = (params?.length ?? 0) > 0 || (hash?.pairs?.length ?? 0) > 0;\n if (!isHelperCall) {\n visit(n.path);\n }\n if (params)\n for (const p of params)\n visit(p);\n visit(hash);\n break;\n }\n case 'SubExpression': {\n // (helper arg1 arg2) — helper name in path is skipped, args carry variables.\n const params = n.params;\n if (params)\n for (const p of params)\n visit(p);\n visit(n.hash);\n break;\n }\n case 'PathExpression': {\n if (n.data)\n break; // `@-data` references (@index, @key, etc.)\n const parts = n.parts;\n if (!parts || parts.length === 0)\n break; // `this` / `.`\n const root = parts[0];\n if (isLocal(root))\n break;\n variables.add(root);\n break;\n }\n case 'Hash': {\n const pairs = n.pairs;\n if (pairs)\n for (const pair of pairs)\n visit(pair.value);\n break;\n }\n // ContentStatement, CommentStatement, *Literal, PartialStatement — no variables to extract.\n default:\n break;\n }\n };\n visit(ast);\n return variables;\n}\n//# sourceMappingURL=extract-vars.js.map","/**\n * Generate mock data that satisfies a JSON Schema.\n *\n * - string → `%property_name%` (visible placeholder, useful for previews and validation render tests)\n * - number/integer → random value 0–100\n * - boolean → true\n * - array → 1–2 items recursively generated from the items schema\n * - object → recursively populated from properties\n * - null → null\n * - $ref or unknown → `%property_name%`\n *\n * @param schema JSON schema to generate data for\n * @param propertyName Name used for string placeholders (default `value`)\n */\nexport function generateMockData(schema, propertyName = 'value') {\n if ('$ref' in schema) {\n return `%${propertyName}%`;\n }\n const types = Array.isArray(schema.type) ? schema.type : [schema.type];\n const primaryType = types[0];\n switch (primaryType) {\n case 'string':\n return `%${propertyName}%`;\n case 'number':\n case 'integer':\n return Math.floor(Math.random() * 101);\n case 'boolean':\n return true;\n case 'array': {\n const itemSchema = schema.items;\n if (itemSchema) {\n const itemCount = Math.floor(Math.random() * 2) + 1;\n return Array.from({ length: itemCount }, (_, index) => generateMockData(itemSchema, `${propertyName}_${index}`));\n }\n return [];\n }\n case 'object': {\n const result = {};\n if (schema.properties) {\n for (const [propName, propSchema] of Object.entries(schema.properties)) {\n result[propName] = generateMockData(propSchema, propName);\n }\n }\n return result;\n }\n case 'null':\n return null;\n default:\n return `%${propertyName}%`;\n }\n}\n//# sourceMappingURL=mock-data.js.map","import { PromptSegmentDefType, TemplateType } from '@vertesia/common';\nimport { CompositeError, renderHandlebarsTemplate, renderJsTemplate } from '@vertesia/jst';\n/**\n * Render a prompt template with the given input data.\n *\n * Handlebars templates use {{variable}} interpolation against `data`.\n * JST (JavaScript template) bodies evaluate against `data` with the schema's top-level\n * property names exposed as globals, plus `_model` — the active model id, which the\n * studio-server executor injects into the input as `{ ..._model: run.modelId }` when\n * executing an interaction (see `apps/studio-server/src/executor/ExecutionRequest.ts`\n * and `apps/studio-server/src/executor/rendering/template.ts`). Listing it here keeps\n * the Playground preview and `validatePrompt` in sync with runtime resolution — a JST\n * template referencing `_model` validates fine here and renders fine in production.\n *\n * For `TemplateType.text`, the content is returned verbatim — it is static text, not a\n * template — matching the studio-server executor (see `apps/studio-server/src/executor/\n * rendering/template.ts`). Routing it through the JST evaluator would compile the prose as\n * JavaScript and throw on any plain sentence (e.g. \"You are a helpful assistant.\").\n */\nexport function renderTemplate(code, contentType, schema, data) {\n if (contentType === TemplateType.handlebars) {\n return renderHandlebarsTemplate(code, data);\n }\n if (contentType === TemplateType.text) {\n return code;\n }\n const globals = [...(schema.properties ? Object.keys(schema.properties) : []), '_model'];\n return renderJsTemplate(code, globals, data);\n}\n/**\n * Execute a JST (JavaScript Template) with given data.\n * Returns a discriminated union to surface errors without throwing.\n */\nexport function executeJST(jstContent, schema, data) {\n try {\n const result = renderTemplate(jstContent, TemplateType.jst, schema, data);\n return { success: true, content: result };\n }\n catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n}\n/**\n * Execute a Handlebars template with given data.\n * Returns a discriminated union to surface errors without throwing.\n */\nexport function executeHandlebars(handlebarsContent, schema, data) {\n try {\n const result = renderTemplate(handlebarsContent, TemplateType.handlebars, schema, data);\n return { success: true, content: result };\n }\n catch (error) {\n return { success: false, error: error instanceof Error ? error.message : String(error) };\n }\n}\nfunction renderChatSegment(segment, data) {\n const chatKey = getChatKey(segment.configuration);\n const chat = data[chatKey];\n let content;\n if (Array.isArray(chat)) {\n content = JSON.stringify(chat, undefined, 2);\n }\n else {\n content = `No \"${chatKey}\" property found on input data`;\n }\n return {\n title: 'Chat history',\n content,\n };\n}\nfunction renderTemplateSegment(segment, data) {\n if (!segment.template) {\n return { title: '(unknown segment)', content: '', error: new Error('Prompt segment is missing its template') };\n }\n const schema = segment.template.inputSchema || {};\n const title = `@${segment.template.role}`;\n try {\n const content = renderTemplate(segment.template.content, segment.template.content_type, schema, data);\n return { title, content, segmentId: segment.template.id };\n }\n catch (error) {\n // Isolate the failure to this segment so the remaining segments still render.\n return {\n title,\n content: error instanceof Error ? error.message : String(error),\n segmentId: segment.template.id,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n}\nexport function renderSegments(segments, data) {\n const out = [];\n for (const segment of segments) {\n if (segment.type === PromptSegmentDefType.chat) {\n out.push(renderChatSegment(segment, data));\n }\n else if (segment.type === PromptSegmentDefType.template) {\n out.push(renderTemplateSegment(segment, data));\n }\n }\n return out;\n}\nexport function renderSegmentsOrErrors(segments, textOrObject) {\n try {\n return renderSegments(segments, typeof textOrObject === 'string' ? JSON.parse(textOrObject.trim()) : textOrObject || {});\n }\n catch (error) {\n if (error instanceof CompositeError) {\n return error.errors.map((err) => ({\n error: err,\n title: 'Rendering Error',\n content: err.message,\n }));\n }\n return [\n {\n error: error instanceof Error ? error : new Error(String(error)),\n title: 'Rendering Error',\n content: error instanceof Error ? error.message : String(error),\n },\n ];\n }\n}\nexport function renderPrompt(segments, payload) {\n const out = [];\n for (const segment of segments) {\n if (segment.template) {\n const schema = segment.template.inputSchema || {};\n const content = renderTemplate(segment.template.content, segment.template.content_type, schema, payload);\n out.push({ role: segment.template.role, content });\n }\n else if (segment.type === PromptSegmentDefType.chat) {\n const chatKey = getChatKey(segment.configuration);\n const messages = payload[chatKey];\n if (!isPromptSegmentArray(messages)) {\n throw new Error('Chat prompt segment must have a messages array');\n }\n for (const msg of messages) {\n if (!msg.role) {\n throw new Error('Chat prompt segment must have a role');\n }\n out.push({ role: msg.role, content: msg.content });\n }\n }\n else {\n throw new Error(`Unknown prompt segment type: ${segment.type}`);\n }\n }\n return out;\n}\nfunction getChatKey(configuration) {\n if (typeof configuration === 'object' &&\n configuration !== null &&\n 'chatKey' in configuration &&\n typeof configuration.chatKey === 'string') {\n return configuration.chatKey;\n }\n return 'chat';\n}\nfunction isPromptSegmentArray(value) {\n return Array.isArray(value) && value.every(isPromptSegment);\n}\nfunction isPromptSegment(value) {\n return typeof value === 'object' && value !== null && 'role' in value && 'content' in value;\n}\n//# sourceMappingURL=render.js.map","import { TemplateType } from '@vertesia/common';\nimport { getFreeVariables, renderJsTemplate } from '@vertesia/jst';\nimport { extractHandlebarsVariables } from './extract-vars.js';\nimport { generateMockData } from './mock-data.js';\nimport { executeHandlebars } from './render.js';\n// JST's renderJsTemplate auto-adds `_` (helpers object) and runtime injects `Set` and `Array`\n// — treat them as globals so they don't appear as free vars in user templates.\n// Globals always available to JST templates regardless of schema:\n// - `_`, `Array`, `Set`: runtime-injected by `renderJsTemplate` (jst library)\n// - `_model`: runtime-injected by the studio-server executor as `{ ..._model: run.modelId }`\n// (see ExecutionRequest.ts:313 and executor/rendering/template.ts:13)\n// Keeping these in sync with `renderTemplate` in ./render.ts so a JST template that runs in\n// production also passes the validator.\nconst JST_AUTO_GLOBALS = ['_', 'Array', 'Set', '_model'];\nfunction countSeverities(issues) {\n let error_count = 0;\n let warning_count = 0;\n for (const issue of issues) {\n if (issue.severity === 'error') {\n error_count++;\n }\n else if (issue.severity === 'warning') {\n warning_count++;\n }\n }\n return { error_count, warning_count };\n}\nfunction validateHandlebarsPrompt(content, inputSchema) {\n const issues = [];\n const usedVars = extractHandlebarsVariables(content);\n const declaredVars = new Set(inputSchema?.properties ? Object.keys(inputSchema.properties) : []);\n for (const used of usedVars) {\n if (!declaredVars.has(used)) {\n issues.push({\n type: 'undeclared_template_variable',\n severity: 'error',\n variable: used,\n message: `Template references variable '{{${used}}}' but it is not declared in input_schema.properties. Add '${used}' to the schema with an appropriate type.`,\n });\n }\n }\n for (const declared of declaredVars) {\n if (!usedVars.has(declared)) {\n issues.push({\n type: 'unused_schema_variable',\n severity: 'warning',\n variable: declared,\n message: `Schema declares property '${declared}' but the template never references it. Remove it from input_schema or use it via {{${declared}}}.`,\n });\n }\n }\n // Render-time smoke test — always runs so syntax errors and failing helper calls are\n // surfaced even when undeclared-variable errors are already in the list. Handlebars renders\n // missing vars as empty strings (non-strict by default), so the render check does NOT echo\n // the var errors — anything it reports is a distinct template problem worth showing.\n const renderSchema = inputSchema ?? {};\n const mockData = generateMockData(renderSchema);\n const mockObject = typeof mockData === 'object' && mockData !== null && !Array.isArray(mockData) ? mockData : {};\n const renderResult = executeHandlebars(content, renderSchema, mockObject);\n if (!renderResult.success) {\n issues.push({\n type: 'handlebars_render_error',\n severity: 'error',\n message: `Handlebars rendering failed: ${renderResult.error}`,\n });\n }\n return issues;\n}\nfunction validateJstPrompt(content, inputSchema) {\n const issues = [];\n const declaredVars = new Set(inputSchema?.properties ? Object.keys(inputSchema.properties) : []);\n let referenced;\n try {\n const result = getFreeVariables(content, {\n globals: JST_AUTO_GLOBALS,\n acorn: { allowReturnOutsideFunction: true, locations: true },\n });\n referenced = result.vars;\n for (const err of result.errors) {\n issues.push({\n type: 'jst_unsafe_construct',\n severity: 'error',\n message: `JST validation error at ${err.location}: ${err.message}`,\n });\n }\n }\n catch (parseError) {\n // Acorn parse failure — surface as render error since the template can't be compiled.\n issues.push({\n type: 'jst_render_error',\n severity: 'error',\n message: `JST parse failed: ${parseError instanceof Error ? parseError.message : String(parseError)}`,\n });\n return issues;\n }\n for (const used of referenced) {\n if (!declaredVars.has(used)) {\n issues.push({\n type: 'undeclared_template_variable',\n severity: 'error',\n variable: used,\n message: `Template references variable '${used}' but it is not declared in input_schema.properties. Add '${used}' to the schema with an appropriate type.`,\n });\n }\n }\n for (const declared of declaredVars) {\n if (!referenced.has(declared)) {\n issues.push({\n type: 'unused_schema_variable',\n severity: 'warning',\n variable: declared,\n message: `Schema declares property '${declared}' but the template never references it. Remove it from input_schema or use it in the template.`,\n });\n }\n }\n // Render-time smoke test — only if there are no blocking errors so far, otherwise\n // the failure mode would just echo what we already reported.\n const blockingSoFar = issues.some((i) => i.severity === 'error');\n if (!blockingSoFar) {\n const renderSchema = inputSchema ?? {};\n const mockData = generateMockData(renderSchema);\n const mockObject = typeof mockData === 'object' && mockData !== null && !Array.isArray(mockData)\n ? mockData\n : {};\n try {\n renderJsTemplate(content, [...declaredVars], mockObject);\n }\n catch (renderError) {\n issues.push({\n type: 'jst_render_error',\n severity: 'error',\n message: `JST rendering failed: ${renderError instanceof Error ? renderError.message : String(renderError)}`,\n });\n }\n }\n return issues;\n}\n/**\n * Validate a single prompt template against its declared input schema.\n *\n * For `handlebars` and `jst` templates, the following checks are performed:\n * 1. Every variable referenced in the template must be declared as a top-level property\n * in `inputSchema.properties` (else → `undeclared_template_variable` error).\n * 2. Every property declared in `inputSchema.properties` should be referenced by the template\n * (else → `unused_schema_variable` warning — non-blocking).\n * 3. The template must render successfully against schema-derived mock data\n * (else → `handlebars_render_error` / `jst_render_error` error).\n * 4. For JST only: unsafe constructs (`with`, `for`, `while`, `import`, class, `this`,\n * dynamic property lookup, blacklisted props) → `jst_unsafe_construct` error.\n *\n * `text` content type passes through with no issues.\n */\nexport function validatePrompt(input) {\n let issues;\n if (input.contentType === TemplateType.handlebars) {\n issues = validateHandlebarsPrompt(input.content, input.inputSchema);\n }\n else if (input.contentType === TemplateType.jst) {\n issues = validateJstPrompt(input.content, input.inputSchema);\n }\n else {\n issues = [];\n }\n const { error_count, warning_count } = countSeverities(issues);\n return { issues, error_count, warning_count };\n}\n//# sourceMappingURL=validate.js.map","/**\n * Class hierarchy and registry-bound interface for the role system. These\n * are LOGIC — they have runtime behavior (constructors, instance methods,\n * subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`\n * (not common) per the package-layering contract: only types stay in common.\n */\n/**\n * A role: a named bundle of permissions that ACEs reference by name.\n *\n * Generic over the permission type so subclasses can tighten it:\n * - **System roles** declare `extends Role<Permission>` — construction time\n * type-checks against the central `Permission` enum.\n * - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions\n * are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific\n * verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in\n * `content_security`.\n *\n * The registry stores `Role` (defaulting to `Role<string>`) — the loose type\n * is the lowest common denominator. Tight typing is only enforced at\n * declaration sites of the role subclasses.\n */\nexport class Role {\n name;\n domain;\n permissions;\n constructor(name, permissions, domain) {\n this.name = name;\n this.domain = domain;\n this.permissions = new Set(permissions);\n }\n hasPermission(permission) {\n return this.permissions.has(permission);\n }\n}\n/**\n * Base class for built-in system roles. Hardcodes `domain: 'system'` and\n * specializes `Role<Permission>` so subclasses get compile-time type-checking\n * against the central `Permission` enum at construction.\n */\nexport class SystemRole extends Role {\n constructor(name, permissions) {\n super(name, permissions, 'system');\n }\n}\n/**\n * A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of\n * objects the role can be applied to at the ABAC scope level. Inherits\n * `Role<string>` because ABAC verbs aren't constrained to the central\n * `Permission` enum.\n *\n * The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.\n */\nexport class AbacRole extends Role {\n applicableScopes;\n constructor(name, permissions, domain, applicableScopes) {\n super(name, permissions, domain);\n this.applicableScopes = applicableScopes;\n }\n}\n//# sourceMappingURL=classes.js.map","import { AbacRole } from './classes.js';\nconst ContentRoleDomain = 'content';\nconst APPLICABLE_SCOPES = ['document', 'collection'];\n/**\n * Names of roles owned by the `content` domain. Apply to ContentSet ACEs\n * scoped to either `document` or `collection` — the semantics of \"read\n * content\" are the same for both kinds.\n */\nexport var ContentRoleNames;\n(function (ContentRoleNames) {\n ContentRoleNames[\"content_reader\"] = \"content_reader\";\n ContentRoleNames[\"content_writer\"] = \"content_writer\";\n ContentRoleNames[\"content_manager\"] = \"content_manager\";\n})(ContentRoleNames || (ContentRoleNames = {}));\nclass ContentReaderRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_reader, ['read'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nclass ContentWriterRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_writer, ['read', 'write'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nclass ContentManagerRole extends AbacRole {\n constructor() {\n super(ContentRoleNames.content_manager, ['read', 'write', 'delete'], ContentRoleDomain, APPLICABLE_SCOPES);\n }\n}\nconst contentRoles = {\n [ContentRoleNames.content_reader]: new ContentReaderRole(),\n [ContentRoleNames.content_writer]: new ContentWriterRole(),\n [ContentRoleNames.content_manager]: new ContentManagerRole(),\n};\nexport const contentPartition = {\n domain: ContentRoleDomain,\n roles: new Map(Object.entries(contentRoles)),\n};\n//# sourceMappingURL=content.js.map","import { Permission, SystemRoles } from '@vertesia/common';\nimport { SystemRole } from './classes.js';\nclass OrgMemberRole extends SystemRole {\n constructor(name, permissions) {\n super(name, [Permission.account_member, ...permissions]);\n }\n}\nclass OwnerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.owner, Object.values(Permission));\n }\n}\nclass AdminRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.admin, Object.values(Permission));\n }\n}\nclass ManagerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.manager, Object.values(Permission));\n this.permissions.delete(Permission.account_admin);\n this.permissions.delete(Permission.manage_billing);\n this.permissions.delete(Permission.audit_read);\n this.permissions.delete(Permission.agent_run_read);\n this.permissions.delete(Permission.content_read_all);\n this.permissions.delete(Permission.content_superadmin);\n this.permissions.delete(Permission.workflow_superadmin);\n }\n}\nclass DeveloperRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.developer, Object.values(Permission));\n this.permissions.delete(Permission.account_admin);\n this.permissions.delete(Permission.project_admin);\n this.permissions.delete(Permission.project_settings_write);\n this.permissions.delete(Permission.env_admin);\n this.permissions.delete(Permission.manage_billing);\n this.permissions.delete(Permission.audit_read);\n this.permissions.delete(Permission.agent_run_read);\n this.permissions.delete(Permission.content_read_all);\n this.permissions.delete(Permission.content_superadmin);\n this.permissions.delete(Permission.workflow_superadmin);\n }\n}\nclass ApplicationRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.application, [\n Permission.int_read,\n Permission.int_execute,\n Permission.int_write,\n Permission.run_read,\n Permission.content_write,\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.project_admin,\n Permission.workflow_run,\n Permission.project_settings_write,\n Permission.account_write,\n ]);\n }\n}\nclass AutomationRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.automation, [\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.int_read,\n Permission.int_execute,\n Permission.run_read,\n Permission.workflow_run,\n Permission.project_integration_read,\n ]);\n }\n}\nclass ContentProcessorRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.content_processor, [\n Permission.content_read,\n Permission.content_write,\n Permission.content_admin,\n Permission.content_superadmin,\n Permission.int_execute,\n Permission.workflow_read,\n Permission.workflow_run,\n Permission.run_read,\n ]);\n }\n}\nclass ConsumerRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.consumer, [\n Permission.content_admin,\n Permission.content_read,\n Permission.content_write,\n Permission.content_delete,\n Permission.int_read,\n Permission.int_execute,\n Permission.run_read,\n Permission.workflow_run,\n ]);\n }\n}\nclass ExecutorRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.executor, [Permission.int_execute, Permission.run_read, Permission.workflow_run]);\n }\n}\nclass ReaderRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.reader, [Permission.int_read, Permission.run_read, Permission.content_read]);\n }\n}\nconst READ_ONLY_AUDIT_PERMISSIONS = [\n Permission.studio_access,\n Permission.account_read,\n Permission.project_integration_read,\n Permission.api_key_read,\n Permission.billing_read,\n Permission.audit_read,\n Permission.int_read,\n Permission.run_read,\n Permission.content_read,\n Permission.content_read_all,\n Permission.task_read,\n Permission.workflow_read,\n Permission.agent_run_read,\n];\nclass ReadOnlyAuditRole extends OrgMemberRole {\n constructor(name) {\n super(name, READ_ONLY_AUDIT_PERMISSIONS);\n }\n}\nclass BillingRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.billing, [Permission.manage_billing]);\n }\n}\nclass AppMemberRole extends OrgMemberRole {\n constructor() {\n super(SystemRoles.app_member, [\n Permission.int_read,\n Permission.int_execute,\n Permission.int_write,\n Permission.run_read,\n Permission.content_write,\n Permission.content_read,\n Permission.content_delete,\n Permission.workflow_run,\n ]);\n }\n}\nclass ContentSuperAdmin extends DeveloperRole {\n constructor() {\n super();\n this.name = SystemRoles.content_superadmin;\n this.permissions.add(Permission.content_superadmin);\n }\n}\n// The enum is still named `SystemRoles` (historical); the partition's domain\n// is `system` — the foundational built-in roles, distinct from feature domains\n// like `content` or `tasks`. Renaming the enum to `SystemRoles` is a separate\n// concern to revisit later.\nconst systemRoles = {\n [SystemRoles.owner]: new OwnerRole(),\n [SystemRoles.admin]: new AdminRole(),\n [SystemRoles.manager]: new ManagerRole(),\n [SystemRoles.developer]: new DeveloperRole(),\n [SystemRoles.application]: new ApplicationRole(),\n [SystemRoles.automation]: new AutomationRole(),\n [SystemRoles.content_processor]: new ContentProcessorRole(),\n [SystemRoles.consumer]: new ConsumerRole(),\n [SystemRoles.executor]: new ExecutorRole(),\n [SystemRoles.reader]: new ReaderRole(),\n [SystemRoles.auditor]: new ReadOnlyAuditRole(SystemRoles.auditor),\n [SystemRoles.support]: new ReadOnlyAuditRole(SystemRoles.support),\n [SystemRoles.billing]: new BillingRole(),\n [SystemRoles.app_member]: new AppMemberRole(),\n [SystemRoles.member]: new OrgMemberRole(SystemRoles.member, []),\n [SystemRoles.content_superadmin]: new ContentSuperAdmin(),\n};\nexport const systemPartition = {\n domain: 'system',\n roles: new Map(Object.entries(systemRoles)),\n};\n//# sourceMappingURL=system.js.map","import { AbacRole, SystemRole } from './classes.js';\nimport { contentPartition } from './content.js';\nimport { systemPartition } from './system.js';\nexport { AbacRole, Role, SystemRole } from './classes.js';\nexport { ContentRoleNames } from './content.js';\n/**\n * The ordered partition registry. Partitions are queried in this order — first\n * match wins. The `system` partition is registered first so domain-specific\n * partitions (added later) cannot shadow built-in system roles.\n */\nconst partitions = [systemPartition, contentPartition];\n/** Look up a role by its name across all registered partitions. */\nexport function getRoleByName(name) {\n for (const partition of partitions) {\n const role = partition.roles.get(name);\n if (role)\n return role;\n }\n throw new Error(`Role ${name} not found`);\n}\n/** List every role across all partitions, in partition registration order. */\nexport function listRoles() {\n const result = [];\n for (const partition of partitions) {\n for (const role of partition.roles.values()) {\n result.push(role);\n }\n }\n return result;\n}\n/** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */\nexport function listRolesByDomain(domain) {\n const partition = partitions.find((p) => p.domain === domain);\n return partition ? Array.from(partition.roles.values()) : [];\n}\n/**\n * ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,\n * `'collection'`). System roles are excluded — they don't carry scope semantics.\n */\nexport function listAbacRolesForScope(scope) {\n return listRoles().filter((r) => r instanceof AbacRole && r.applicableScopes.includes(scope));\n}\n/** Shortcut for the system partition: returns only `SystemRole` instances. */\nexport function listSystemRoles() {\n return listRoles().filter((r) => r instanceof SystemRole);\n}\n/** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */\nexport function getAllRoleNames() {\n return listRoles().map((r) => r.name);\n}\n/**\n * Merge the permissions granted by a set of roles into a single array.\n * Intended for the system-role gating path. For ABAC roles, the bare-verb\n * permissions returned here aren't directly meaningful — use the JWT\n * `content_security` pathway instead.\n */\nexport function getPermissionsForRoles(roleNames) {\n const permissions = new Set();\n for (const roleName of roleNames) {\n const role = getRoleByName(roleName);\n for (const permission of role.permissions) {\n permissions.add(permission);\n }\n }\n return Array.from(permissions);\n}\n/**\n * A list of roles with a unified `hasPermission` check across them.\n */\nexport class RoleList {\n roles;\n constructor(roles) {\n this.roles = roles;\n }\n static fromRoleNames(roleNames) {\n const roles = roleNames.map((r) => getRoleByName(r));\n return new RoleList(roles);\n }\n static fromRoleName(roleName) {\n const roles = [getRoleByName(roleName)];\n return new RoleList(roles);\n }\n hasPermission(perm) {\n return this.roles.some((role) => role.hasPermission(perm));\n }\n}\n//# sourceMappingURL=index.js.map"],"names":["extractHandlebarsVariables","template","ast","Handlebars","parse","Set","variables","localScopes","visit","node","n","type","body","stmt","params","p","hash","program","inverse","scope","blockParams","push","pop","length","pairs","path","data","parts","root","name","some","has","add","pair","value","generateMockData","schema","propertyName","Array","isArray","Math","floor","random","itemSchema","items","itemCount","from","_","index","result","properties","propName","propSchema","Object","entries","renderTemplate","code","contentType","TemplateType","handlebars","renderHandlebarsTemplate","text","globals","keys","renderJsTemplate","executeJST","jstContent","success","content","jst","error","Error","message","String","executeHandlebars","handlebarsContent","renderChatSegment","segment","chatKey","getChatKey","configuration","chat","JSON","stringify","undefined","title","renderTemplateSegment","inputSchema","role","content_type","segmentId","id","renderSegments","segments","out","PromptSegmentDefType","renderSegmentsOrErrors","textOrObject","trim","CompositeError","errors","map","err","renderPrompt","payload","messages","isPromptSegmentArray","msg","every","isPromptSegment","JST_AUTO_GLOBALS","validatePrompt","input","issues","usedVars","declaredVars","used","severity","variable","declared","renderSchema","mockData","renderResult","validateHandlebarsPrompt","referenced","getFreeVariables","acorn","allowReturnOutsideFunction","locations","vars","location","parseError","i","mockObject","renderError","validateJstPrompt","error_count","warning_count","issue","countSeverities","Role","domain","permissions","constructor","this","hasPermission","permission","SystemRole","super","AbacRole","applicableScopes","ContentRoleDomain","APPLICABLE_SCOPES","ContentRoleNames","contentRoles","content_reader","content_writer","content_manager","contentPartition","roles","Map","OrgMemberRole","Permission","account_member","DeveloperRole","SystemRoles","developer","values","delete","account_admin","project_admin","project_settings_write","env_admin","manage_billing","audit_read","agent_run_read","content_read_all","content_superadmin","workflow_superadmin","READ_ONLY_AUDIT_PERMISSIONS","studio_access","account_read","project_integration_read","api_key_read","billing_read","int_read","run_read","content_read","task_read","workflow_read","ReadOnlyAuditRole","systemRoles","owner","admin","manager","application","int_execute","int_write","content_write","content_admin","workflow_run","account_write","automation","content_processor","consumer","content_delete","executor","reader","auditor","support","billing","app_member","member","partitions","getRoleByName","partition","get","listRoles","listRolesByDomain","find","listAbacRolesForScope","filter","r","includes","listSystemRoles","getAllRoleNames","getPermissionsForRoles","roleNames","roleName","RoleList","fromRoleNames","fromRoleName","perm"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/studio-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-dev.20260629.130134Z",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared utilities for Vertesia studio: prompt template rendering, schema-based mock data generation, prompt and interaction validation helpers.",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./conditions": {
|
|
14
|
+
"types": "./lib/conditions/index.d.ts",
|
|
15
|
+
"default": "./lib/conditions/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./logger": {
|
|
18
|
+
"types": "./lib/logger.d.ts",
|
|
19
|
+
"default": "./lib/logger.js"
|
|
20
|
+
},
|
|
21
|
+
"./lib/*": "./lib/*",
|
|
22
|
+
"./src/*": "./src/*"
|
|
23
|
+
},
|
|
8
24
|
"license": "Apache-2.0",
|
|
9
25
|
"homepage": "https://docs.vertesiahq.com",
|
|
10
26
|
"files": [
|
|
@@ -29,22 +45,23 @@
|
|
|
29
45
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
30
46
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
31
47
|
"@rollup/plugin-terser": "^1.0.0",
|
|
32
|
-
"@types/node": "^24.
|
|
33
|
-
"rollup": "^4.61.
|
|
48
|
+
"@types/node": "^24.13.2",
|
|
49
|
+
"rollup": "^4.61.1",
|
|
34
50
|
"typescript": "^6.0.3",
|
|
35
|
-
"vitest": "^4.1.
|
|
51
|
+
"vitest": "^4.1.9",
|
|
36
52
|
"@vertesia/tsconfig": "0.1.0"
|
|
37
53
|
},
|
|
38
54
|
"dependencies": {
|
|
39
55
|
"handlebars": "^4.7.9",
|
|
40
|
-
"@llumiverse/common": "1.
|
|
41
|
-
"@vertesia/common": "1.
|
|
42
|
-
"@vertesia/jst": "1.
|
|
56
|
+
"@llumiverse/common": "1.4.0-dev.20260629.090753Z",
|
|
57
|
+
"@vertesia/common": "1.4.0-dev.20260629.130134Z",
|
|
58
|
+
"@vertesia/jst": "1.4.0-dev.20260629.130134Z"
|
|
43
59
|
},
|
|
44
60
|
"scripts": {
|
|
45
61
|
"lint": "biome lint src",
|
|
46
62
|
"test": "vitest run",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
63
|
+
"clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
|
|
64
|
+
"build": "pnpm run clean:lib && pnpm exec tsc -p tsconfig.json && pnpm exec rollup -c",
|
|
65
|
+
"clean": "rimraf ./node_modules ./lib ./tsconfig.tsbuildinfo"
|
|
49
66
|
}
|
|
50
67
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { matchConditions, matchLike, resolvePath } from './match.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { installStudioUtilsLogger, type StudioUtilsLogger } from '../logger.js';
|
|
3
|
+
import { matchConditions, matchLike, resolvePath } from './index.js';
|
|
4
|
+
|
|
5
|
+
describe('resolvePath', () => {
|
|
6
|
+
it('resolves top-level fields and one-level properties fields', () => {
|
|
7
|
+
const value = {
|
|
8
|
+
clearance: 3,
|
|
9
|
+
properties: {
|
|
10
|
+
department: 'engineering',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
expect(resolvePath(value, 'clearance')).toBe(3);
|
|
15
|
+
expect(resolvePath(value, 'properties.department')).toBe('engineering');
|
|
16
|
+
expect(resolvePath(value, 'properties.missing')).toBeUndefined();
|
|
17
|
+
expect(resolvePath({ clearance: 3 }, 'properties.department')).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('matchLike', () => {
|
|
22
|
+
it('matches wildcard string patterns case-insensitively', () => {
|
|
23
|
+
expect(matchLike('bogdan+test@vertesiahq.com', '*+test*@VERTESIAHQ.COM')).toBe(true);
|
|
24
|
+
expect(matchLike('bogdan@gmail.com', '*@vertesiahq.com')).toBe(false);
|
|
25
|
+
expect(matchLike(42, '*')).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('matchConditions', () => {
|
|
30
|
+
it('matches direct values and operator objects', () => {
|
|
31
|
+
const properties = {
|
|
32
|
+
active: true,
|
|
33
|
+
clearance: 5,
|
|
34
|
+
compartments: ['engineering'],
|
|
35
|
+
email: 'bogdan@vertesiahq.com',
|
|
36
|
+
properties: {
|
|
37
|
+
department: 'engineering',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
expect(
|
|
42
|
+
matchConditions(
|
|
43
|
+
{
|
|
44
|
+
active: true,
|
|
45
|
+
clearance: { $gte: 3, $lte: 5 },
|
|
46
|
+
compartments: { $empty: false },
|
|
47
|
+
email: { $like: '*@vertesiahq.com' },
|
|
48
|
+
'properties.department': { $in: ['engineering', 'product'] },
|
|
49
|
+
},
|
|
50
|
+
properties,
|
|
51
|
+
),
|
|
52
|
+
).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('requires ordered comparisons to use matching primitive types', () => {
|
|
56
|
+
expect(matchConditions({ clearance: { $gt: 3 } }, { clearance: 5 })).toBe(true);
|
|
57
|
+
expect(matchConditions({ clearance: { $gt: 3 } }, { clearance: '5' })).toBe(false);
|
|
58
|
+
expect(matchConditions({ code: { $gt: 'a' } }, { code: 'b' })).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('treats unknown operators as non-matches', () => {
|
|
62
|
+
const logger: StudioUtilsLogger = {
|
|
63
|
+
warn: vi.fn(),
|
|
64
|
+
};
|
|
65
|
+
const previousLogger = installStudioUtilsLogger(logger);
|
|
66
|
+
|
|
67
|
+
expect(matchConditions({ clearance: { $unknown: 3 } }, { clearance: 5 })).toBe(false);
|
|
68
|
+
expect(logger.warn).toHaveBeenCalledWith(
|
|
69
|
+
{ op: '$unknown', key: 'clearance' },
|
|
70
|
+
'Unknown operator in PropertyConditions',
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
installStudioUtilsLogger(previousLogger);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { PropertyConditions } from '@vertesia/common';
|
|
2
|
+
import { getStudioUtilsLogger } from '../logger.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a property path against a context object.
|
|
6
|
+
*
|
|
7
|
+
* Supports:
|
|
8
|
+
* - `clearance` → obj.clearance
|
|
9
|
+
* - `email` → obj.email
|
|
10
|
+
* - `properties.department` → obj.properties.department (one nested level under `properties`)
|
|
11
|
+
*
|
|
12
|
+
* Returns `undefined` if any segment is missing or non-traversable.
|
|
13
|
+
*/
|
|
14
|
+
export function resolvePath(obj: Record<string, unknown>, path: string): unknown {
|
|
15
|
+
if (path.startsWith('properties.')) {
|
|
16
|
+
const properties = obj.properties;
|
|
17
|
+
return properties && typeof properties === 'object'
|
|
18
|
+
? (properties as Record<string, unknown>)[path.slice(11)]
|
|
19
|
+
: undefined;
|
|
20
|
+
}
|
|
21
|
+
return obj[path];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Match a wildcard pattern against a string value.
|
|
26
|
+
*
|
|
27
|
+
* Supports `*` as wildcard:
|
|
28
|
+
* - `"*@domain.com"` — ends with
|
|
29
|
+
* - `"bogdan.*"` — starts with
|
|
30
|
+
* - `"bogdan+*@vertesia.com"` — contains
|
|
31
|
+
* - `"*"` — match all
|
|
32
|
+
*
|
|
33
|
+
* Case-insensitive. Non-string `value` always returns `false`.
|
|
34
|
+
*/
|
|
35
|
+
export function matchLike(value: unknown, pattern: string): boolean {
|
|
36
|
+
if (typeof value !== 'string') return false;
|
|
37
|
+
// Convert wildcard pattern to regex: escape regex chars except *, then replace * with .*
|
|
38
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
39
|
+
return new RegExp(`^${escaped}$`, 'i').test(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function compareOrdered(value: unknown, expected: unknown, op: '$gt' | '$gte' | '$lt' | '$lte'): boolean {
|
|
43
|
+
if (typeof value !== 'number' && typeof value !== 'string') return false;
|
|
44
|
+
if (typeof value !== typeof expected) return false;
|
|
45
|
+
const left = value;
|
|
46
|
+
const right = expected as typeof left;
|
|
47
|
+
switch (op) {
|
|
48
|
+
case '$gt':
|
|
49
|
+
return left > right;
|
|
50
|
+
case '$gte':
|
|
51
|
+
return left >= right;
|
|
52
|
+
case '$lt':
|
|
53
|
+
return left < right;
|
|
54
|
+
case '$lte':
|
|
55
|
+
return left <= right;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Evaluate a PropertyConditions object against a set of properties (JS-side, in-memory).
|
|
61
|
+
*
|
|
62
|
+
* Supports the MongoDB query syntax subset shared across token-server (principal property
|
|
63
|
+
* matching at JWT-mint time) and zeno-server (write-path ABAC permission checks against an
|
|
64
|
+
* in-memory document):
|
|
65
|
+
*
|
|
66
|
+
* - Direct value match (`{ field: literal }`)
|
|
67
|
+
* - `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
68
|
+
* - `$in`, `$nin` (against array `expected`)
|
|
69
|
+
* - `$exists` (boolean)
|
|
70
|
+
* - `$empty` (boolean) — true for undefined/null/empty-string/empty-array
|
|
71
|
+
* - `$like` (wildcard string, see {@link matchLike})
|
|
72
|
+
*
|
|
73
|
+
* All field-level conditions are AND'd (every field must match). Within a single field, all
|
|
74
|
+
* operators are AND'd.
|
|
75
|
+
*
|
|
76
|
+
* Mirrors the Mongo-side filter built by `conditionsToMongoFilter` (zeno-server utils.ts) and
|
|
77
|
+
* the ES-side filter built by `conditionsToEsQuery`. Use this when conditions need to be
|
|
78
|
+
* evaluated against a single hydrated document instead of pushed down as a query.
|
|
79
|
+
*
|
|
80
|
+
* Unknown operators emit a warning via the studio-utils logger and return false — surfacing
|
|
81
|
+
* misconfiguration loudly without breaking the surrounding token mint or permission check.
|
|
82
|
+
*
|
|
83
|
+
* `$principal.X` substitutions in conditions are expected to have already been resolved at
|
|
84
|
+
* JWT-mint time by `resolveConditions` in token-server; values reaching this function are
|
|
85
|
+
* concrete.
|
|
86
|
+
*/
|
|
87
|
+
export function matchConditions(conditions: PropertyConditions, properties: Record<string, unknown>): boolean {
|
|
88
|
+
for (const [key, condition] of Object.entries(conditions)) {
|
|
89
|
+
const value = resolvePath(properties, key);
|
|
90
|
+
|
|
91
|
+
if (condition === null || condition === undefined || typeof condition !== 'object') {
|
|
92
|
+
// Direct value match
|
|
93
|
+
if (value !== condition) return false;
|
|
94
|
+
} else {
|
|
95
|
+
// Operator object
|
|
96
|
+
const ops = condition as Record<string, unknown>;
|
|
97
|
+
for (const [op, expected] of Object.entries(ops)) {
|
|
98
|
+
switch (op) {
|
|
99
|
+
case '$eq':
|
|
100
|
+
if (value !== expected) return false;
|
|
101
|
+
break;
|
|
102
|
+
case '$ne':
|
|
103
|
+
if (value === expected) return false;
|
|
104
|
+
break;
|
|
105
|
+
case '$gt':
|
|
106
|
+
if (!compareOrdered(value, expected, '$gt')) return false;
|
|
107
|
+
break;
|
|
108
|
+
case '$gte':
|
|
109
|
+
if (!compareOrdered(value, expected, '$gte')) return false;
|
|
110
|
+
break;
|
|
111
|
+
case '$lt':
|
|
112
|
+
if (!compareOrdered(value, expected, '$lt')) return false;
|
|
113
|
+
break;
|
|
114
|
+
case '$lte':
|
|
115
|
+
if (!compareOrdered(value, expected, '$lte')) return false;
|
|
116
|
+
break;
|
|
117
|
+
case '$in':
|
|
118
|
+
if (!Array.isArray(expected) || !expected.includes(value)) return false;
|
|
119
|
+
break;
|
|
120
|
+
case '$nin':
|
|
121
|
+
if (Array.isArray(expected) && expected.includes(value)) return false;
|
|
122
|
+
break;
|
|
123
|
+
case '$exists':
|
|
124
|
+
if (typeof expected !== 'boolean' || (value !== undefined) !== expected) return false;
|
|
125
|
+
break;
|
|
126
|
+
case '$empty': {
|
|
127
|
+
const isEmpty =
|
|
128
|
+
value === undefined ||
|
|
129
|
+
value === null ||
|
|
130
|
+
value === '' ||
|
|
131
|
+
(Array.isArray(value) && value.length === 0);
|
|
132
|
+
if (typeof expected !== 'boolean' || isEmpty !== expected) return false;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case '$like':
|
|
136
|
+
if (typeof expected !== 'string' || !matchLike(value, expected)) return false;
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
getStudioUtilsLogger().warn({ op, key }, 'Unknown operator in PropertyConditions');
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface StudioUtilsLogger {
|
|
2
|
+
warn(details: Record<string, unknown>, message: string): void;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
// studio-utils deliberately excludes DOM/Node lib globals so browser and Node
|
|
6
|
+
// consumers stay symmetric. Declare the minimal console surface for the fallback logger.
|
|
7
|
+
declare const console: { warn(...args: unknown[]): void };
|
|
8
|
+
|
|
9
|
+
const consoleLogger: StudioUtilsLogger = {
|
|
10
|
+
warn: (details, message) => {
|
|
11
|
+
console.warn(message, details);
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let logger: StudioUtilsLogger = consoleLogger;
|
|
16
|
+
|
|
17
|
+
export function getStudioUtilsLogger(): StudioUtilsLogger {
|
|
18
|
+
return logger;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function installStudioUtilsLogger(customLogger: StudioUtilsLogger): StudioUtilsLogger {
|
|
22
|
+
const previousLogger = logger;
|
|
23
|
+
logger = customLogger;
|
|
24
|
+
return previousLogger;
|
|
25
|
+
}
|