@vertesia/studio-utils 1.3.0 → 1.4.0-dev.20260615.051508Z
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/index.d.ts +0 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/vertesia-studio-utils.js +1 -1
- package/lib/vertesia-studio-utils.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +0 -1
- package/lib/roles/classes.d.ts +0 -59
- package/lib/roles/classes.d.ts.map +0 -1
- package/lib/roles/classes.js +0 -60
- package/lib/roles/classes.js.map +0 -1
- package/lib/roles/content.d.ts +0 -13
- package/lib/roles/content.d.ts.map +0 -1
- package/lib/roles/content.js +0 -39
- package/lib/roles/content.js.map +0 -1
- package/lib/roles/index.d.ts +0 -37
- package/lib/roles/index.d.ts.map +0 -1
- package/lib/roles/index.js +0 -87
- package/lib/roles/index.js.map +0 -1
- package/lib/roles/system.d.ts +0 -3
- package/lib/roles/system.d.ts.map +0 -1
- package/lib/roles/system.js +0 -187
- package/lib/roles/system.js.map +0 -1
- package/src/roles/classes.ts +0 -78
- package/src/roles/content.ts +0 -46
- package/src/roles/index.test.ts +0 -206
- package/src/roles/index.ts +0 -96
- package/src/roles/system.ts +0 -204
package/lib/index.d.ts
CHANGED
|
@@ -2,5 +2,4 @@ export { extractHandlebarsVariables } from './prompts/extract-vars.js';
|
|
|
2
2
|
export { generateMockData } from './prompts/mock-data.js';
|
|
3
3
|
export { executeHandlebars, executeJST, renderPrompt, renderSegments, renderSegmentsOrErrors, renderTemplate, type SegmentPreview, } from './prompts/render.js';
|
|
4
4
|
export { type PromptValidationInput, type PromptValidationIssue, type PromptValidationIssueSeverity, type PromptValidationIssueType, type PromptValidationResult, validatePrompt, } from './prompts/validate.js';
|
|
5
|
-
export * from './roles/index.js';
|
|
6
5
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,KAAK,cAAc,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,cAAc,GACjB,MAAM,uBAAuB,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,KAAK,cAAc,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,cAAc,GACjB,MAAM,uBAAuB,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -2,5 +2,4 @@ export { extractHandlebarsVariables } from './prompts/extract-vars.js';
|
|
|
2
2
|
export { generateMockData } from './prompts/mock-data.js';
|
|
3
3
|
export { executeHandlebars, executeJST, renderPrompt, renderSegments, renderSegmentsOrErrors, renderTemplate, } from './prompts/render.js';
|
|
4
4
|
export { validatePrompt, } from './prompts/validate.js';
|
|
5
|
-
export * from './roles/index.js';
|
|
6
5
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAMH,cAAc,GACjB,MAAM,uBAAuB,CAAC
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAMH,cAAc,GACjB,MAAM,uBAAuB,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 r,PromptSegmentDefType as t}from"@vertesia/common";import{CompositeError as n,renderHandlebarsTemplate as o,renderJsTemplate as s,getFreeVariables as a}from"@vertesia/jst";function c(r){let t;try{t=e.parse(r)}catch{return new Set}const n=new Set,o=[],s=e=>{if(!e||"object"!=typeof e)return;const r=e;switch(r.type){case"Program":{const e=r.body;if(e)for(const r of e)s(r);break}case"BlockStatement":{const e=r.params;if(e)for(const r of e)s(r);s(r.hash);const t=r.program,n=r.inverse,a=new Set([...t?.blockParams??[],...n?.blockParams??[]]);o.push(a),s(r.program),s(r.inverse),o.pop();break}case"MustacheStatement":{const e=r.params,t=r.hash;if((e?.length??0)>0||(t?.pairs?.length??0)>0||s(r.path),e)for(const r of e)s(r);s(t);break}case"SubExpression":{const e=r.params;if(e)for(const r of e)s(r);s(r.hash);break}case"PathExpression":{if(r.data)break;const e=r.parts;if(!e||0===e.length)break;const s=e[0];if(t=s,o.some(e=>e.has(t)))break;n.add(s);break}case"Hash":{const e=r.pairs;if(e)for(const r of e)s(r.value);break}}var t};return s(t),n}function i(e,r="value"){if("$ref"in e)return`%${r}%`;switch((Array.isArray(e.type)?e.type:[e.type])[0]){case"string":default:return`%${r}%`;case"number":case"integer":return Math.floor(101*Math.random());case"boolean":return!0;case"array":{const t=e.items;if(t){const e=Math.floor(2*Math.random())+1;return Array.from({length:e},(e,n)=>i(t,`${r}_${n}`))}return[]}case"object":{const r={};if(e.properties)for(const[t,n]of Object.entries(e.properties))r[t]=i(n,t);return r}case"null":return null}}function p(e,t,n,a){if(t===r.handlebars)return o(e,a);if(t===r.text)return e;const c=[...n.properties?Object.keys(n.properties):[],"_model"];return s(e,c,a)}function u(e,t,n){try{return{success:!0,content:p(e,r.jst,t,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function f(e,t,n){try{return{success:!0,content:p(e,r.handlebars,t,n)}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}function l(e,r){const t=d(e.configuration),n=r[t];let o;return o=Array.isArray(n)?JSON.stringify(n,void 0,2):`No "${t}" property found on input data`,{title:"Chat history",content:o}}function m(e,r){if(!e.template)return{title:"(unknown segment)",content:"",error:new Error("Prompt segment is missing its template")};const t=e.template.inputSchema||{},n=`@${e.template.role}`;try{return{title:n,content:p(e.template.content,e.template.content_type,t,r),segmentId:e.template.id}}catch(r){return{title:n,content:r instanceof Error?r.message:String(r),segmentId:e.template.id,error:r instanceof Error?r:new Error(String(r))}}}function h(e,r){const n=[];for(const o of e)o.type===t.chat?n.push(l(o,r)):o.type===t.template&&n.push(m(o,r));return n}function y(e,r){try{return h(e,"string"==typeof r?JSON.parse(r.trim()):r||{})}catch(e){return e instanceof n?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,r){const n=[];for(const o of e)if(o.template){const e=o.template.inputSchema||{},t=p(o.template.content,o.template.content_type,e,r);n.push({role:o.template.role,content:t})}else{if(o.type!==t.chat)throw new Error(`Unknown prompt segment type: ${o.type}`);{const e=r[d(o.configuration)];if(!b(e))throw new Error("Chat prompt segment must have a messages array");for(const r of e){if(!r.role)throw new Error("Chat prompt segment must have a role");n.push({role:r.role,content:r.content})}}}return n}function d(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 _=["_","Array","Set","_model"];function S(e){let t;t=e.contentType===r.handlebars?function(e,r){const t=[],n=c(e),o=new Set(r?.properties?Object.keys(r.properties):[]);for(const e of n)o.has(e)||t.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 o)n.has(e)||t.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 s=r??{},a=i(s),p=f(e,s,"object"!=typeof a||null===a||Array.isArray(a)?{}:a);return p.success||t.push({type:"handlebars_render_error",severity:"error",message:`Handlebars rendering failed: ${p.error}`}),t}(e.content,e.inputSchema):e.contentType===r.jst?function(e,r){const t=[],n=new Set(r?.properties?Object.keys(r.properties):[]);let o;try{const r=a(e,{globals:_,acorn:{allowReturnOutsideFunction:!0,locations:!0}});o=r.vars;for(const e of r.errors)t.push({type:"jst_unsafe_construct",severity:"error",message:`JST validation error at ${e.location}: ${e.message}`})}catch(e){return t.push({type:"jst_render_error",severity:"error",message:`JST parse failed: ${e instanceof Error?e.message:String(e)}`}),t}for(const e of o)n.has(e)||t.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)o.has(e)||t.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(!t.some(e=>"error"===e.severity)){const o=i(r??{}),a="object"!=typeof o||null===o||Array.isArray(o)?{}:o;try{s(e,[...n],a)}catch(e){t.push({type:"jst_render_error",severity:"error",message:`JST rendering failed: ${e instanceof Error?e.message:String(e)}`})}}return t}(e.content,e.inputSchema):[];const{error_count:n,warning_count:o}=function(e){let r=0,t=0;for(const n of e)"error"===n.severity?r++:"warning"===n.severity&&t++;return{error_count:r,warning_count:t}}(t);return{issues:t,error_count:n,warning_count:o}}export{f as executeHandlebars,u as executeJST,c as extractHandlebarsVariables,i as generateMockData,g as renderPrompt,h as renderSegments,y as renderSegmentsOrErrors,p as renderTemplate,S 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"],"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"],"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"],"mappings":"6NAkBO,SAASA,EAA2BC,GACvC,IAAIC,EACJ,IACIA,EAAMC,EAAWC,MAAMH,EAC3B,CACA,MACI,OAAO,IAAII,GACf,CACA,MAAMC,EAAY,IAAID,IAChBE,EAAc,GAEdC,EAASC,IACX,IAAKA,GAAwB,iBAATA,EAChB,OACJ,MAAMC,EAAID,EACV,OAAQC,EAAEC,MACN,IAAK,UAAW,CACZ,MAAMC,EAAOF,EAAEE,KACf,GAAIA,EACA,IAAK,MAAMC,KAAQD,EACfJ,EAAMK,GACd,KACJ,CACA,IAAK,iBAAkB,CAGnB,MAAMC,EAASJ,EAAEI,OACjB,GAAIA,EACA,IAAK,MAAMC,KAAKD,EACZN,EAAMO,GACdP,EAAME,EAAEM,MAER,MAAMC,EAAUP,EAAEO,QACZC,EAAUR,EAAEQ,QACZC,EAAQ,IAAId,IAAI,IAAKY,GAASG,aAAe,MAASF,GAASE,aAAe,KACpFb,EAAYc,KAAKF,GACjBX,EAAME,EAAEO,SACRT,EAAME,EAAEQ,SACRX,EAAYe,MACZ,KACJ,CACA,IAAK,oBAAqB,CAGtB,MAAMR,EAASJ,EAAEI,OACXE,EAAON,EAAEM,KAKf,IAJsBF,GAAQS,QAAU,GAAK,IAAMP,GAAMQ,OAAOD,QAAU,GAAK,GAE3Ef,EAAME,EAAEe,MAERX,EACA,IAAK,MAAMC,KAAKD,EACZN,EAAMO,GACdP,EAAMQ,GACN,KACJ,CACA,IAAK,gBAAiB,CAElB,MAAMF,EAASJ,EAAEI,OACjB,GAAIA,EACA,IAAK,MAAMC,KAAKD,EACZN,EAAMO,GACdP,EAAME,EAAEM,MACR,KACJ,CACA,IAAK,iBAAkB,CACnB,GAAIN,EAAEgB,KACF,MACJ,MAAMC,EAAQjB,EAAEiB,MAChB,IAAKA,GAA0B,IAAjBA,EAAMJ,OAChB,MACJ,MAAMK,EAAOD,EAAM,GACnB,GA9DKE,EA8DOD,EA9DErB,EAAYuB,KAAMX,GAAUA,EAAMY,IAAIF,IA+DhD,MACJvB,EAAU0B,IAAIJ,GACd,KACJ,CACA,IAAK,OAAQ,CACT,MAAMJ,EAAQd,EAAEc,MAChB,GAAIA,EACA,IAAK,MAAMS,KAAQT,EACfhB,EAAMyB,EAAKC,OACnB,KACJ,EAzEQ,IAACL,GAgFjB,OADArB,EAAMN,GACCI,CACX,CC/FO,SAAS6B,EAAiBC,EAAQC,EAAe,SACpD,GAAI,SAAUD,EACV,MAAO,IAAIC,KAIf,QAFcC,MAAMC,QAAQH,EAAOzB,MAAQyB,EAAOzB,KAAO,CAACyB,EAAOzB,OACvC,IAEtB,IAAK,SA0BL,QACI,MAAO,IAAI0B,KAzBf,IAAK,SACL,IAAK,UACD,OAAOG,KAAKC,MAAsB,IAAhBD,KAAKE,UAC3B,IAAK,UACD,OAAO,EACX,IAAK,QAAS,CACV,MAAMC,EAAaP,EAAOQ,MAC1B,GAAID,EAAY,CACZ,MAAME,EAAYL,KAAKC,MAAsB,EAAhBD,KAAKE,UAAgB,EAClD,OAAOJ,MAAMQ,KAAK,CAAEvB,OAAQsB,GAAa,CAACE,EAAGC,IAAUb,EAAiBQ,EAAY,GAAGN,KAAgBW,KAC3G,CACA,MAAO,EACX,CACA,IAAK,SAAU,CACX,MAAMC,EAAS,CAAA,EACf,GAAIb,EAAOc,WACP,IAAK,MAAOC,EAAUC,KAAeC,OAAOC,QAAQlB,EAAOc,YACvDD,EAAOE,GAAYhB,EAAiBiB,EAAYD,GAGxD,OAAOF,CACX,CACA,IAAK,OACD,OAAO,KAInB,CC/BO,SAASM,EAAeC,EAAMC,EAAarB,EAAQV,GACtD,GAAI+B,IAAgBC,EAAaC,WAC7B,OAAOC,EAAyBJ,EAAM9B,GAE1C,GAAI+B,IAAgBC,EAAaG,KAC7B,OAAOL,EAEX,MAAMM,EAAU,IAAK1B,EAAOc,WAAaG,OAAOU,KAAK3B,EAAOc,YAAc,GAAK,UAC/E,OAAOc,EAAiBR,EAAMM,EAASpC,EAC3C,CAKO,SAASuC,EAAWC,EAAY9B,EAAQV,GAC3C,IAEI,MAAO,CAAEyC,SAAS,EAAMC,QADTb,EAAeW,EAAYR,EAAaW,IAAKjC,EAAQV,GAExE,CACA,MAAO4C,GACH,MAAO,CAAEH,SAAS,EAAOG,MAAOA,aAAiBC,MAAQD,EAAME,QAAUC,OAAOH,GACpF,CACJ,CAKO,SAASI,EAAkBC,EAAmBvC,EAAQV,GACzD,IAEI,MAAO,CAAEyC,SAAS,EAAMC,QADTb,EAAeoB,EAAmBjB,EAAaC,WAAYvB,EAAQV,GAEtF,CACA,MAAO4C,GACH,MAAO,CAAEH,SAAS,EAAOG,MAAOA,aAAiBC,MAAQD,EAAME,QAAUC,OAAOH,GACpF,CACJ,CACA,SAASM,EAAkBC,EAASnD,GAChC,MAAMoD,EAAUC,EAAWF,EAAQG,eAC7BC,EAAOvD,EAAKoD,GAClB,IAAIV,EAOJ,OALIA,EADA9B,MAAMC,QAAQ0C,GACJC,KAAKC,UAAUF,OAAMG,EAAW,GAGhC,OAAON,kCAEd,CACHO,MAAO,eACPjB,UAER,CACA,SAASkB,EAAsBT,EAASnD,GACpC,IAAKmD,EAAQ5E,SACT,MAAO,CAAEoF,MAAO,oBAAqBjB,QAAS,GAAIE,MAAO,IAAIC,MAAM,2CAEvE,MAAMnC,EAASyC,EAAQ5E,SAASsF,aAAe,CAAA,EACzCF,EAAQ,IAAIR,EAAQ5E,SAASuF,OACnC,IAEI,MAAO,CAAEH,QAAOjB,QADAb,EAAesB,EAAQ5E,SAASmE,QAASS,EAAQ5E,SAASwF,aAAcrD,EAAQV,GACvEgE,UAAWb,EAAQ5E,SAAS0F,GACzD,CACA,MAAOrB,GAEH,MAAO,CACHe,QACAjB,QAASE,aAAiBC,MAAQD,EAAME,QAAUC,OAAOH,GACzDoB,UAAWb,EAAQ5E,SAAS0F,GAC5BrB,MAAOA,aAAiBC,MAAQD,EAAQ,IAAIC,MAAME,OAAOH,IAEjE,CACJ,CACO,SAASsB,EAAeC,EAAUnE,GACrC,MAAMoE,EAAM,GACZ,IAAK,MAAMjB,KAAWgB,EACdhB,EAAQlE,OAASoF,EAAqBd,KACtCa,EAAIzE,KAAKuD,EAAkBC,EAASnD,IAE/BmD,EAAQlE,OAASoF,EAAqB9F,UAC3C6F,EAAIzE,KAAKiE,EAAsBT,EAASnD,IAGhD,OAAOoE,CACX,CACO,SAASE,EAAuBH,EAAUI,GAC7C,IACI,OAAOL,EAAeC,EAAkC,iBAAjBI,EAA4Bf,KAAK9E,MAAM6F,EAAaC,QAAUD,GAAgB,CAAA,EACzH,CACA,MAAO3B,GACH,OAAIA,aAAiB6B,EACV7B,EAAM8B,OAAOC,IAAKC,IAAG,CACxBhC,MAAOgC,EACPjB,MAAO,kBACPjB,QAASkC,EAAI9B,WAGd,CACH,CACIF,MAAOA,aAAiBC,MAAQD,EAAQ,IAAIC,MAAME,OAAOH,IACzDe,MAAO,kBACPjB,QAASE,aAAiBC,MAAQD,EAAME,QAAUC,OAAOH,IAGrE,CACJ,CACO,SAASiC,EAAaV,EAAUW,GACnC,MAAMV,EAAM,GACZ,IAAK,MAAMjB,KAAWgB,EAClB,GAAIhB,EAAQ5E,SAAU,CAClB,MAAMmC,EAASyC,EAAQ5E,SAASsF,aAAe,CAAA,EACzCnB,EAAUb,EAAesB,EAAQ5E,SAASmE,QAASS,EAAQ5E,SAASwF,aAAcrD,EAAQoE,GAChGV,EAAIzE,KAAK,CAAEmE,KAAMX,EAAQ5E,SAASuF,KAAMpB,WAC5C,KACK,IAAIS,EAAQlE,OAASoF,EAAqBd,KAc3C,MAAM,IAAIV,MAAM,gCAAgCM,EAAQlE,QAdP,CACjD,MACM8F,EAAWD,EADDzB,EAAWF,EAAQG,gBAEnC,IAAK0B,EAAqBD,GACtB,MAAM,IAAIlC,MAAM,kDAEpB,IAAK,MAAMoC,KAAOF,EAAU,CACxB,IAAKE,EAAInB,KACL,MAAM,IAAIjB,MAAM,wCAEpBuB,EAAIzE,KAAK,CAAEmE,KAAMmB,EAAInB,KAAMpB,QAASuC,EAAIvC,SAC5C,CACJ,CAGA,CAEJ,OAAO0B,CACX,CACA,SAASf,EAAWC,GAChB,MAA6B,iBAAlBA,GACW,OAAlBA,GACA,YAAaA,GACoB,iBAA1BA,EAAcF,QACdE,EAAcF,QAElB,MACX,CACA,SAAS4B,EAAqBxE,GAC1B,OAAOI,MAAMC,QAAQL,IAAUA,EAAM0E,MAAMC,EAC/C,CACA,SAASA,EAAgB3E,GACrB,MAAwB,iBAAVA,GAAgC,OAAVA,GAAkB,SAAUA,GAAS,YAAaA,CAC1F,CCvJA,MAAM4E,EAAmB,CAAC,IAAK,QAAS,MAAO,UA2IxC,SAASC,EAAeC,GAC3B,IAAIC,EAEAA,EADAD,EAAMvD,cAAgBC,EAAaC,WA/H3C,SAAkCS,EAASmB,GACvC,MAAM0B,EAAS,GACTC,EAAWlH,EAA2BoE,GACtC+C,EAAe,IAAI9G,IAAIkF,GAAarC,WAAaG,OAAOU,KAAKwB,EAAYrC,YAAc,IAC7F,IAAK,MAAMkE,KAAQF,EACVC,EAAapF,IAAIqF,IAClBH,EAAO5F,KAAK,CACRV,KAAM,+BACN0G,SAAU,QACVC,SAAUF,EACV5C,QAAS,mCAAmC4C,gEAAmEA,+CAI3H,IAAK,MAAMG,KAAYJ,EACdD,EAASnF,IAAIwF,IACdN,EAAO5F,KAAK,CACRV,KAAM,yBACN0G,SAAU,UACVC,SAAUC,EACV/C,QAAS,6BAA6B+C,wFAA+FA,SAQjJ,MAAMC,EAAejC,GAAe,CAAA,EAC9BkC,EAAWtF,EAAiBqF,GAE5BE,EAAehD,EAAkBN,EAASoD,EADT,iBAAbC,GAAsC,OAAbA,GAAsBnF,MAAMC,QAAQkF,GAAuB,CAAA,EAAXA,GASnG,OAPKC,EAAavD,SACd8C,EAAO5F,KAAK,CACRV,KAAM,0BACN0G,SAAU,QACV7C,QAAS,gCAAgCkD,EAAapD,UAGvD2C,CACX,CAwFiBU,CAAyBX,EAAM5C,QAAS4C,EAAMzB,aAElDyB,EAAMvD,cAAgBC,EAAaW,IAzFhD,SAA2BD,EAASmB,GAChC,MAAM0B,EAAS,GACTE,EAAe,IAAI9G,IAAIkF,GAAarC,WAAaG,OAAOU,KAAKwB,EAAYrC,YAAc,IAC7F,IAAI0E,EACJ,IACI,MAAM3E,EAAS4E,EAAiBzD,EAAS,CACrCN,QAASgD,EACTgB,MAAO,CAAEC,4BAA4B,EAAMC,WAAW,KAE1DJ,EAAa3E,EAAOgF,KACpB,IAAK,MAAM3B,KAAOrD,EAAOmD,OACrBa,EAAO5F,KAAK,CACRV,KAAM,uBACN0G,SAAU,QACV7C,QAAS,2BAA2B8B,EAAI4B,aAAa5B,EAAI9B,WAGrE,CACA,MAAO2D,GAOH,OALAlB,EAAO5F,KAAK,CACRV,KAAM,mBACN0G,SAAU,QACV7C,QAAS,qBAAqB2D,aAAsB5D,MAAQ4D,EAAW3D,QAAUC,OAAO0D,OAErFlB,CACX,CACA,IAAK,MAAMG,KAAQQ,EACVT,EAAapF,IAAIqF,IAClBH,EAAO5F,KAAK,CACRV,KAAM,+BACN0G,SAAU,QACVC,SAAUF,EACV5C,QAAS,iCAAiC4C,8DAAiEA,+CAIvH,IAAK,MAAMG,KAAYJ,EACdS,EAAW7F,IAAIwF,IAChBN,EAAO5F,KAAK,CACRV,KAAM,yBACN0G,SAAU,UACVC,SAAUC,EACV/C,QAAS,6BAA6B+C,oGAOlD,IADsBN,EAAOnF,KAAMsG,GAAqB,UAAfA,EAAEf,UACvB,CAChB,MACMI,EAAWtF,EADIoD,GAAe,CAAA,GAE9B8C,EAAiC,iBAAbZ,GAAsC,OAAbA,GAAsBnF,MAAMC,QAAQkF,GAEjF,CAAA,EADAA,EAEN,IACIzD,EAAiBI,EAAS,IAAI+C,GAAekB,EACjD,CACA,MAAOC,GACHrB,EAAO5F,KAAK,CACRV,KAAM,mBACN0G,SAAU,QACV7C,QAAS,yBAAyB8D,aAAuB/D,MAAQ+D,EAAY9D,QAAUC,OAAO6D,MAEtG,CACJ,CACA,OAAOrB,CACX,CAsBiBsB,CAAkBvB,EAAM5C,QAAS4C,EAAMzB,aAGvC,GAEb,MAAMiD,YAAEA,EAAWC,cAAEA,GArJzB,SAAyBxB,GACrB,IAAIuB,EAAc,EACdC,EAAgB,EACpB,IAAK,MAAMC,KAASzB,EACO,UAAnByB,EAAMrB,SACNmB,IAEwB,YAAnBE,EAAMrB,UACXoB,IAGR,MAAO,CAAED,cAAaC,gBAC1B,CAyI2CE,CAAgB1B,GACvD,MAAO,CAAEA,SAAQuB,cAAaC,gBAClC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/studio-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0-dev.20260615.051508Z",
|
|
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",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"handlebars": "^4.7.9",
|
|
40
40
|
"@llumiverse/common": "1.3.0",
|
|
41
|
-
"@vertesia/common": "1.
|
|
41
|
+
"@vertesia/common": "1.4.0-dev.20260615.051508Z",
|
|
42
42
|
"@vertesia/jst": "1.3.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
package/src/index.ts
CHANGED
package/lib/roles/classes.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { AbacScope, Permission, RoleDomain } from '@vertesia/common';
|
|
2
|
-
/**
|
|
3
|
-
* Class hierarchy and registry-bound interface for the role system. These
|
|
4
|
-
* are LOGIC — they have runtime behavior (constructors, instance methods,
|
|
5
|
-
* subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`
|
|
6
|
-
* (not common) per the package-layering contract: only types stay in common.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* A role: a named bundle of permissions that ACEs reference by name.
|
|
10
|
-
*
|
|
11
|
-
* Generic over the permission type so subclasses can tighten it:
|
|
12
|
-
* - **System roles** declare `extends Role<Permission>` — construction time
|
|
13
|
-
* type-checks against the central `Permission` enum.
|
|
14
|
-
* - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions
|
|
15
|
-
* are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific
|
|
16
|
-
* verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in
|
|
17
|
-
* `content_security`.
|
|
18
|
-
*
|
|
19
|
-
* The registry stores `Role` (defaulting to `Role<string>`) — the loose type
|
|
20
|
-
* is the lowest common denominator. Tight typing is only enforced at
|
|
21
|
-
* declaration sites of the role subclasses.
|
|
22
|
-
*/
|
|
23
|
-
export declare class Role<PermissionType extends string = string> {
|
|
24
|
-
name: string;
|
|
25
|
-
domain: RoleDomain;
|
|
26
|
-
permissions: Set<PermissionType>;
|
|
27
|
-
constructor(name: string, permissions: PermissionType[], domain: RoleDomain);
|
|
28
|
-
hasPermission(permission: PermissionType): boolean;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Base class for built-in system roles. Hardcodes `domain: 'system'` and
|
|
32
|
-
* specializes `Role<Permission>` so subclasses get compile-time type-checking
|
|
33
|
-
* against the central `Permission` enum at construction.
|
|
34
|
-
*/
|
|
35
|
-
export declare class SystemRole extends Role<Permission> {
|
|
36
|
-
constructor(name: string, permissions: Permission[]);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of
|
|
40
|
-
* objects the role can be applied to at the ABAC scope level. Inherits
|
|
41
|
-
* `Role<string>` because ABAC verbs aren't constrained to the central
|
|
42
|
-
* `Permission` enum.
|
|
43
|
-
*
|
|
44
|
-
* The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.
|
|
45
|
-
*/
|
|
46
|
-
export declare class AbacRole extends Role<string> {
|
|
47
|
-
applicableScopes: readonly AbacScope[];
|
|
48
|
-
constructor(name: string, permissions: string[], domain: RoleDomain, applicableScopes: readonly AbacScope[]);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* A logical bucket of roles owned by a single domain. The registry iterates
|
|
52
|
-
* partitions in registration order — first match wins. The `system` partition
|
|
53
|
-
* is registered first so domain partitions cannot shadow built-in system roles.
|
|
54
|
-
*/
|
|
55
|
-
export interface RolePartition {
|
|
56
|
-
domain: RoleDomain;
|
|
57
|
-
roles: Map<string, Role>;
|
|
58
|
-
}
|
|
59
|
-
//# sourceMappingURL=classes.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"classes.d.ts","sourceRoot":"","sources":["../../src/roles/classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,qBAAa,IAAI,CAAC,cAAc,SAAS,MAAM,GAAG,MAAM;IAGzC,IAAI,EAAE,MAAM;IAEZ,MAAM,EAAE,UAAU;IAJ7B,WAAW,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;gBAEtB,IAAI,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,EAAE,EACtB,MAAM,EAAE,UAAU;IAK7B,aAAa,CAAC,UAAU,EAAE,cAAc;CAG3C;AAED;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,IAAI,CAAC,UAAU,CAAC;gBAChC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE;CAGtD;AAED;;;;;;;GAOG;AACH,qBAAa,QAAS,SAAQ,IAAI,CAAC,MAAM,CAAC;IAK3B,gBAAgB,EAAE,SAAS,SAAS,EAAE;gBAH7C,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,UAAU,EACX,gBAAgB,EAAE,SAAS,SAAS,EAAE;CAIpD;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC5B"}
|
package/lib/roles/classes.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Class hierarchy and registry-bound interface for the role system. These
|
|
3
|
-
* are LOGIC — they have runtime behavior (constructors, instance methods,
|
|
4
|
-
* subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`
|
|
5
|
-
* (not common) per the package-layering contract: only types stay in common.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* A role: a named bundle of permissions that ACEs reference by name.
|
|
9
|
-
*
|
|
10
|
-
* Generic over the permission type so subclasses can tighten it:
|
|
11
|
-
* - **System roles** declare `extends Role<Permission>` — construction time
|
|
12
|
-
* type-checks against the central `Permission` enum.
|
|
13
|
-
* - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions
|
|
14
|
-
* are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific
|
|
15
|
-
* verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in
|
|
16
|
-
* `content_security`.
|
|
17
|
-
*
|
|
18
|
-
* The registry stores `Role` (defaulting to `Role<string>`) — the loose type
|
|
19
|
-
* is the lowest common denominator. Tight typing is only enforced at
|
|
20
|
-
* declaration sites of the role subclasses.
|
|
21
|
-
*/
|
|
22
|
-
export class Role {
|
|
23
|
-
name;
|
|
24
|
-
domain;
|
|
25
|
-
permissions;
|
|
26
|
-
constructor(name, permissions, domain) {
|
|
27
|
-
this.name = name;
|
|
28
|
-
this.domain = domain;
|
|
29
|
-
this.permissions = new Set(permissions);
|
|
30
|
-
}
|
|
31
|
-
hasPermission(permission) {
|
|
32
|
-
return this.permissions.has(permission);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Base class for built-in system roles. Hardcodes `domain: 'system'` and
|
|
37
|
-
* specializes `Role<Permission>` so subclasses get compile-time type-checking
|
|
38
|
-
* against the central `Permission` enum at construction.
|
|
39
|
-
*/
|
|
40
|
-
export class SystemRole extends Role {
|
|
41
|
-
constructor(name, permissions) {
|
|
42
|
-
super(name, permissions, 'system');
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of
|
|
47
|
-
* objects the role can be applied to at the ABAC scope level. Inherits
|
|
48
|
-
* `Role<string>` because ABAC verbs aren't constrained to the central
|
|
49
|
-
* `Permission` enum.
|
|
50
|
-
*
|
|
51
|
-
* The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.
|
|
52
|
-
*/
|
|
53
|
-
export class AbacRole extends Role {
|
|
54
|
-
applicableScopes;
|
|
55
|
-
constructor(name, permissions, domain, applicableScopes) {
|
|
56
|
-
super(name, permissions, domain);
|
|
57
|
-
this.applicableScopes = applicableScopes;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
//# sourceMappingURL=classes.js.map
|
package/lib/roles/classes.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"classes.js","sourceRoot":"","sources":["../../src/roles/classes.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,IAAI;IAGF;IAEA;IAJX,WAAW,CAAsB;IACjC,YACW,IAAY,EACnB,WAA6B,EACtB,MAAkB;QAFlB,SAAI,GAAJ,IAAI,CAAQ;QAEZ,WAAM,GAAN,MAAM,CAAY;QAEzB,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,UAA0B;QACpC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;CACJ;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,IAAgB;IAC5C,YAAY,IAAY,EAAE,WAAyB;QAC/C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;CACJ;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,QAAS,SAAQ,IAAY;IAK3B;IAJX,YACI,IAAY,EACZ,WAAqB,EACrB,MAAkB,EACX,gBAAsC;QAE7C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QAF1B,qBAAgB,GAAhB,gBAAgB,CAAsB;IAGjD,CAAC;CACJ"}
|
package/lib/roles/content.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type RolePartition } from './classes.js';
|
|
2
|
-
/**
|
|
3
|
-
* Names of roles owned by the `content` domain. Apply to ContentSet ACEs
|
|
4
|
-
* scoped to either `document` or `collection` — the semantics of "read
|
|
5
|
-
* content" are the same for both kinds.
|
|
6
|
-
*/
|
|
7
|
-
export declare enum ContentRoleNames {
|
|
8
|
-
content_reader = "content_reader",
|
|
9
|
-
content_writer = "content_writer",
|
|
10
|
-
content_manager = "content_manager"
|
|
11
|
-
}
|
|
12
|
-
export declare const contentPartition: RolePartition;
|
|
13
|
-
//# sourceMappingURL=content.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/roles/content.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAMvE;;;;GAIG;AACH,oBAAY,gBAAgB;IACxB,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;CACtC;AA0BD,eAAO,MAAM,gBAAgB,EAAE,aAG9B,CAAC"}
|
package/lib/roles/content.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { AbacRole } from './classes.js';
|
|
2
|
-
const ContentRoleDomain = 'content';
|
|
3
|
-
const APPLICABLE_SCOPES = ['document', 'collection'];
|
|
4
|
-
/**
|
|
5
|
-
* Names of roles owned by the `content` domain. Apply to ContentSet ACEs
|
|
6
|
-
* scoped to either `document` or `collection` — the semantics of "read
|
|
7
|
-
* content" are the same for both kinds.
|
|
8
|
-
*/
|
|
9
|
-
export var ContentRoleNames;
|
|
10
|
-
(function (ContentRoleNames) {
|
|
11
|
-
ContentRoleNames["content_reader"] = "content_reader";
|
|
12
|
-
ContentRoleNames["content_writer"] = "content_writer";
|
|
13
|
-
ContentRoleNames["content_manager"] = "content_manager";
|
|
14
|
-
})(ContentRoleNames || (ContentRoleNames = {}));
|
|
15
|
-
class ContentReaderRole extends AbacRole {
|
|
16
|
-
constructor() {
|
|
17
|
-
super(ContentRoleNames.content_reader, ['read'], ContentRoleDomain, APPLICABLE_SCOPES);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
class ContentWriterRole extends AbacRole {
|
|
21
|
-
constructor() {
|
|
22
|
-
super(ContentRoleNames.content_writer, ['read', 'write'], ContentRoleDomain, APPLICABLE_SCOPES);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
class ContentManagerRole extends AbacRole {
|
|
26
|
-
constructor() {
|
|
27
|
-
super(ContentRoleNames.content_manager, ['read', 'write', 'delete'], ContentRoleDomain, APPLICABLE_SCOPES);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
const contentRoles = {
|
|
31
|
-
[ContentRoleNames.content_reader]: new ContentReaderRole(),
|
|
32
|
-
[ContentRoleNames.content_writer]: new ContentWriterRole(),
|
|
33
|
-
[ContentRoleNames.content_manager]: new ContentManagerRole(),
|
|
34
|
-
};
|
|
35
|
-
export const contentPartition = {
|
|
36
|
-
domain: ContentRoleDomain,
|
|
37
|
-
roles: new Map(Object.entries(contentRoles)),
|
|
38
|
-
};
|
|
39
|
-
//# sourceMappingURL=content.js.map
|
package/lib/roles/content.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/roles/content.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiC,MAAM,cAAc,CAAC;AAEvE,MAAM,iBAAiB,GAAe,SAAS,CAAC;AAEhD,MAAM,iBAAiB,GAAyB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,CAAN,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IACxB,qDAAiC,CAAA;IACjC,qDAAiC,CAAA;IACjC,uDAAmC,CAAA;AACvC,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,QAI3B;AAED,MAAM,iBAAkB,SAAQ,QAAQ;IACpC;QACI,KAAK,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IAC3F,CAAC;CACJ;AAED,MAAM,iBAAkB,SAAQ,QAAQ;IACpC;QACI,KAAK,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IACpG,CAAC;CACJ;AAED,MAAM,kBAAmB,SAAQ,QAAQ;IACrC;QACI,KAAK,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IAC/G,CAAC;CACJ;AAED,MAAM,YAAY,GAAmC;IACjD,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,IAAI,iBAAiB,EAAE;IAC1D,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,IAAI,iBAAiB,EAAE;IAC1D,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAAE,IAAI,kBAAkB,EAAE;CAC/D,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAkB;IAC3C,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;CAC/C,CAAC"}
|
package/lib/roles/index.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { AbacScope, RoleDomain } from '@vertesia/common';
|
|
2
|
-
import { AbacRole, type Role, SystemRole } from './classes.js';
|
|
3
|
-
export { AbacRole, Role, type RolePartition, SystemRole } from './classes.js';
|
|
4
|
-
export { ContentRoleNames } from './content.js';
|
|
5
|
-
/** Look up a role by its name across all registered partitions. */
|
|
6
|
-
export declare function getRoleByName(name: string): Role;
|
|
7
|
-
/** List every role across all partitions, in partition registration order. */
|
|
8
|
-
export declare function listRoles(): Role[];
|
|
9
|
-
/** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */
|
|
10
|
-
export declare function listRolesByDomain(domain: RoleDomain): Role[];
|
|
11
|
-
/**
|
|
12
|
-
* ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,
|
|
13
|
-
* `'collection'`). System roles are excluded — they don't carry scope semantics.
|
|
14
|
-
*/
|
|
15
|
-
export declare function listAbacRolesForScope(scope: AbacScope): AbacRole[];
|
|
16
|
-
/** Shortcut for the system partition: returns only `SystemRole` instances. */
|
|
17
|
-
export declare function listSystemRoles(): SystemRole[];
|
|
18
|
-
/** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */
|
|
19
|
-
export declare function getAllRoleNames(): string[];
|
|
20
|
-
/**
|
|
21
|
-
* Merge the permissions granted by a set of roles into a single array.
|
|
22
|
-
* Intended for the system-role gating path. For ABAC roles, the bare-verb
|
|
23
|
-
* permissions returned here aren't directly meaningful — use the JWT
|
|
24
|
-
* `content_security` pathway instead.
|
|
25
|
-
*/
|
|
26
|
-
export declare function getPermissionsForRoles(roleNames: Iterable<string>): string[];
|
|
27
|
-
/**
|
|
28
|
-
* A list of roles with a unified `hasPermission` check across them.
|
|
29
|
-
*/
|
|
30
|
-
export declare class RoleList {
|
|
31
|
-
readonly roles: Role[];
|
|
32
|
-
private constructor();
|
|
33
|
-
static fromRoleNames(roleNames: string[]): RoleList;
|
|
34
|
-
static fromRoleName(roleName: string): RoleList;
|
|
35
|
-
hasPermission(perm: string): boolean;
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=index.d.ts.map
|
package/lib/roles/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/roles/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAsB,UAAU,EAAE,MAAM,cAAc,CAAC;AAInF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAShD,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMhD;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,IAAI,IAAI,EAAE,CAQlC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,CAG5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAElE;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI,UAAU,EAAE,CAE9C;AAED,0GAA0G;AAC1G,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAS5E;AAED;;GAEG;AACH,qBAAa,QAAQ;aACmB,KAAK,EAAE,IAAI,EAAE;IAAjD,OAAO;IAEP,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,QAAQ;IAKnD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAK/C,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAGvC"}
|
package/lib/roles/index.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { AbacRole, SystemRole } from './classes.js';
|
|
2
|
-
import { contentPartition } from './content.js';
|
|
3
|
-
import { systemPartition } from './system.js';
|
|
4
|
-
export { AbacRole, Role, SystemRole } from './classes.js';
|
|
5
|
-
export { ContentRoleNames } from './content.js';
|
|
6
|
-
/**
|
|
7
|
-
* The ordered partition registry. Partitions are queried in this order — first
|
|
8
|
-
* match wins. The `system` partition is registered first so domain-specific
|
|
9
|
-
* partitions (added later) cannot shadow built-in system roles.
|
|
10
|
-
*/
|
|
11
|
-
const partitions = [systemPartition, contentPartition];
|
|
12
|
-
/** Look up a role by its name across all registered partitions. */
|
|
13
|
-
export function getRoleByName(name) {
|
|
14
|
-
for (const partition of partitions) {
|
|
15
|
-
const role = partition.roles.get(name);
|
|
16
|
-
if (role)
|
|
17
|
-
return role;
|
|
18
|
-
}
|
|
19
|
-
throw new Error(`Role ${name} not found`);
|
|
20
|
-
}
|
|
21
|
-
/** List every role across all partitions, in partition registration order. */
|
|
22
|
-
export function listRoles() {
|
|
23
|
-
const result = [];
|
|
24
|
-
for (const partition of partitions) {
|
|
25
|
-
for (const role of partition.roles.values()) {
|
|
26
|
-
result.push(role);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return result;
|
|
30
|
-
}
|
|
31
|
-
/** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */
|
|
32
|
-
export function listRolesByDomain(domain) {
|
|
33
|
-
const partition = partitions.find((p) => p.domain === domain);
|
|
34
|
-
return partition ? Array.from(partition.roles.values()) : [];
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,
|
|
38
|
-
* `'collection'`). System roles are excluded — they don't carry scope semantics.
|
|
39
|
-
*/
|
|
40
|
-
export function listAbacRolesForScope(scope) {
|
|
41
|
-
return listRoles().filter((r) => r instanceof AbacRole && r.applicableScopes.includes(scope));
|
|
42
|
-
}
|
|
43
|
-
/** Shortcut for the system partition: returns only `SystemRole` instances. */
|
|
44
|
-
export function listSystemRoles() {
|
|
45
|
-
return listRoles().filter((r) => r instanceof SystemRole);
|
|
46
|
-
}
|
|
47
|
-
/** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */
|
|
48
|
-
export function getAllRoleNames() {
|
|
49
|
-
return listRoles().map((r) => r.name);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Merge the permissions granted by a set of roles into a single array.
|
|
53
|
-
* Intended for the system-role gating path. For ABAC roles, the bare-verb
|
|
54
|
-
* permissions returned here aren't directly meaningful — use the JWT
|
|
55
|
-
* `content_security` pathway instead.
|
|
56
|
-
*/
|
|
57
|
-
export function getPermissionsForRoles(roleNames) {
|
|
58
|
-
const permissions = new Set();
|
|
59
|
-
for (const roleName of roleNames) {
|
|
60
|
-
const role = getRoleByName(roleName);
|
|
61
|
-
for (const permission of role.permissions) {
|
|
62
|
-
permissions.add(permission);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return Array.from(permissions);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* A list of roles with a unified `hasPermission` check across them.
|
|
69
|
-
*/
|
|
70
|
-
export class RoleList {
|
|
71
|
-
roles;
|
|
72
|
-
constructor(roles) {
|
|
73
|
-
this.roles = roles;
|
|
74
|
-
}
|
|
75
|
-
static fromRoleNames(roleNames) {
|
|
76
|
-
const roles = roleNames.map((r) => getRoleByName(r));
|
|
77
|
-
return new RoleList(roles);
|
|
78
|
-
}
|
|
79
|
-
static fromRoleName(roleName) {
|
|
80
|
-
const roles = [getRoleByName(roleName)];
|
|
81
|
-
return new RoleList(roles);
|
|
82
|
-
}
|
|
83
|
-
hasPermission(perm) {
|
|
84
|
-
return this.roles.some((role) => role.hasPermission(perm));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
//# sourceMappingURL=index.js.map
|