@voiden/runner 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/bundled-runners/package.json +3 -0
- package/bundled-runners/simple-assertions-runner.js +1 -0
- package/bundled-runners/versions.json +9 -0
- package/bundled-runners/voiden-advanced-auth-runner.js +1 -0
- package/bundled-runners/voiden-faker-runner.js +9 -0
- package/bundled-runners/voiden-graphql-runner.js +1 -0
- package/bundled-runners/voiden-rest-api-runner.js +1 -0
- package/bundled-runners/voiden-scripting-runner.js +397 -0
- package/bundled-runners/voiden-sockets-grpcs-runner.js +1 -0
- package/dist/discovery.d.ts +11 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +54 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.js +384 -112
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +19 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +19 -0
- package/dist/lib.js.map +1 -0
- package/dist/mcpInstall.d.ts +48 -0
- package/dist/mcpInstall.d.ts.map +1 -0
- package/dist/mcpInstall.js +194 -0
- package/dist/mcpInstall.js.map +1 -0
- package/dist/plugins/community.d.ts.map +1 -1
- package/dist/plugins/community.js +9 -2
- package/dist/plugins/community.js.map +1 -1
- package/dist/plugins/loader.d.ts +1 -0
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +32 -18
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/registry.d.ts +11 -0
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +63 -10
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/registryCache.d.ts +2 -0
- package/dist/plugins/registryCache.d.ts.map +1 -1
- package/dist/plugins/registryCache.js.map +1 -1
- package/dist/plugins/store.d.ts +28 -1
- package/dist/plugins/store.d.ts.map +1 -1
- package/dist/plugins/store.js +46 -9
- package/dist/plugins/store.js.map +1 -1
- package/dist/plugins/updateCheck.d.ts +9 -4
- package/dist/plugins/updateCheck.d.ts.map +1 -1
- package/dist/plugins/updateCheck.js +29 -15
- package/dist/plugins/updateCheck.js.map +1 -1
- package/dist/plugins/versionInfo.d.ts +15 -0
- package/dist/plugins/versionInfo.d.ts.map +1 -0
- package/dist/plugins/versionInfo.js +18 -0
- package/dist/plugins/versionInfo.js.map +1 -0
- package/dist/resultBlock.d.ts +31 -0
- package/dist/resultBlock.d.ts.map +1 -0
- package/dist/resultBlock.js +121 -0
- package/dist/resultBlock.js.map +1 -0
- package/dist/runner.d.ts +11 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +61 -2
- package/dist/runner.js.map +1 -1
- package/dist/runtimeVars.js +3 -3
- package/dist/runtimeVars.js.map +1 -1
- package/dist/skillContent.d.ts +8 -0
- package/dist/skillContent.d.ts.map +1 -0
- package/dist/skillContent.js +42 -0
- package/dist/skillContent.js.map +1 -0
- package/package.json +13 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var d=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var S=(r,e)=>{for(var n in e)d(r,n,{get:e[n],enumerable:!0})},v=(r,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of k(e))!w.call(r,a)&&a!==n&&d(r,a,{get:()=>e[a],enumerable:!(o=A(e,a))||o.enumerable});return r};var B=r=>v(d({},"__esModule",{value:!0}),r);var N={};S(N,{buildRequest:()=>R,default:()=>x});module.exports=B(N);function R(r){let e=r.find(t=>t.type==="gqlquery");if(!e)return null;let n=e.content?.find(t=>t.type==="gqlbody")||"",o=n.attrs?.body||"";if(!o.trim())return{errorMessage:"GraphQL query is empty"};let a=n.attrs?.operationType||"query",i=n.attrs?.operationName;if(!i){let t=o.match(/^\s*(query|mutation|subscription)\s+([\w]+)?/);t&&(a=t[1],i=t[2])}let p={},f=r.find(t=>t.type==="gqlvariables");if(f?.attrs?.body)try{p=JSON.parse(f.attrs.body)}catch{}let y="",l=e;if(l&&Array.isArray(l.content)){let t=l.content.find(s=>s.type==="gqlurl");t&&typeof t.content=="string"&&(y=t.content.trim())}if(y||(y=e.attrs?.endpoint||e.attrs?.schemaUrl||""),!y)return{errorMessage:"GraphQL url is empty"};let u=[{key:"Content-Type",value:"application/json",enabled:!0}],c=r.find(t=>t.type==="headers-table");if(c&&Array.isArray(c.content)){for(let t of c.content)if(t.type==="table"&&Array.isArray(t.rows)){for(let s of t.rows)if(!s.attrs?.disabled&&Array.isArray(s.row)&&s.row[0]){let m=String(s.row[0]).trim(),q=String(s.row[1]??"").trim(),g=u.findIndex(h=>h.key.toLowerCase()===m.toLowerCase());g>=0?u[g].value=q:u.push({key:m,value:q,enabled:!0})}}}let b={query:o,variables:p};return i&&(b.operationName=i),{method:"POST",url:y,headers:u,queryParams:[],pathParams:[],body:JSON.stringify(b),contentType:"application/json",metadata:{operationType:a,operationName:i}}}var C=r=>({onload(){r.onBuildRequest((e,n)=>R(n)??e)}}),x=C;0&&(module.exports={buildRequest});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var d=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var g=(e,n)=>{for(var r in n)d(e,r,{get:n[r],enumerable:!0})},q=(e,n,r,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of R(n))!b.call(e,a)&&a!==r&&d(e,a,{get:()=>n[a],enumerable:!(o=x(n,a))||o.enumerable});return e};var h=e=>q(d({},"__esModule",{value:!0}),e);var A={};g(A,{buildRequest:()=>m,default:()=>w});module.exports=h(A);function f(e){let n=[];if(!Array.isArray(e.content))return n;for(let r of e.content)if(r.type==="table"&&Array.isArray(r.rows))for(let o of r.rows){let a=o.attrs?.disabled===!0;if(Array.isArray(o.row)&&o.row.length>=2){let i=String(o.row[0]??"").trim(),u=String(o.row[1]??"").trim();i&&n.push({key:i,value:u,enabled:!a})}}return n}function m(e){if(e.some(t=>t.type==="gqlquery")||e.some(t=>t.type==="socket-request"))return null;let n=e.find(t=>t.type==="request");if(!n)return null;let r="GET",o="";if(Array.isArray(n.content))for(let t of n.content)t.type==="method"&&typeof t.content=="string"&&(r=t.content.trim().toUpperCase()||"GET"),t.type==="url"&&typeof t.content=="string"&&(o=t.content.trim());if(!o)return null;let a=f(e.find(t=>t.type==="headers-table")??{}),i=f(e.find(t=>t.type==="query-table")??{}),u=f(e.find(t=>t.type==="path-table")??{}),y,s,c=e.find(t=>t.type==="json_body");if(c?.attrs?.body){y=String(c.attrs.body);let t=c.attrs.contentType;s=t==="html"?"text/html":t==="text"?"text/plain":"application/json"}let l=e.find(t=>t.type==="xml_body");l?.attrs?.body&&(y=String(l.attrs.body),s=["application/xml","text/xml","application/xhtml+xml"].includes(l.attrs.contentType)?l.attrs.contentType:"application/xml");let p=e.find(t=>t.type==="yml_body");return p?.attrs?.body&&(y=String(p.attrs.body),s=["application/x-yaml","application/yaml","text/yaml","text/x-yaml"].includes(p.attrs.contentType)?p.attrs.contentType:"application/x-yaml"),{method:r,url:o,headers:a,queryParams:i,pathParams:u,body:y,contentType:s,metadata:{}}}var T=e=>({onload(){e.onBuildRequest((n,r)=>m(r)??n)}}),w=T;0&&(module.exports={buildRequest});
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";var O=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var se=Object.prototype.hasOwnProperty;var q=(e,r)=>()=>(e&&(r=e(e=0)),r);var P=(e,r)=>{for(var n in r)O(e,n,{get:r[n],enumerable:!0})},ne=(e,r,n,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let t of re(r))!se.call(e,t)&&t!==n&&O(e,t,{get:()=>r[t],enumerable:!(s=te(r,t))||s.enumerable});return e};var ae=e=>ne(O({},"__esModule",{value:!0}),e);function T(e){return"'"+String(e).replace(/'/g,"'\\''")+"'"}function F(e){let{request:r,response:n,envVars:s,variables:t,logFile:i,varFile:o,assertFile:l,cancelFile:d,reqFile:u,respFile:y,userScriptFile:p}=e,m=Object.entries(s).map(([f,c])=>`_VD_ENV_${f.replace(/[^A-Za-z0-9_]/g,"_")}=${T(String(c))}`).join(`
|
|
2
|
+
`)||"# (no env vars)",b=Object.entries(t).map(([f,c])=>`_VD_VAR_${f.replace(/[^A-Za-z0-9_]/g,"_")}=${T(String(c))}`).join(`
|
|
3
|
+
`)||"# (no variables)",g=!!n,a=T;return["#!/bin/bash","set +e",`_VD_LOG_FILE=${a(i)}`,`_VD_VAR_FILE=${a(o)}`,`_VD_ASSERT_FILE=${a(l)}`,`_VD_CANCEL_FILE=${a(d)}`,`_VD_REQUEST_FILE=${a(u)}`,`_VD_RESPONSE_FILE=${a(y)}`,`_VD_USERSCRIPT_FILE=${a(p)}`,'touch "$_VD_LOG_FILE" "$_VD_VAR_FILE" "$_VD_ASSERT_FILE" "$_VD_REQUEST_FILE" "$_VD_RESPONSE_FILE"','_vd_b64() { printf "%s" "$1" | base64 | tr -d "\\n"; }',"voiden_log() {",' local _level="log"',' case "$1" in log|info|debug|warn|warning|error) _level="$1"; shift;; esac',' [ "$_level" = "warning" ] && _level="warn"',' printf "%s\\t%s\\n" "$(_vd_b64 "$_level")" "$(_vd_b64 "$*")" >> "$_VD_LOG_FILE"',"}",'voiden_env_get() { local _k="_VD_ENV_${1//[^A-Za-z0-9_]/_}"; printf "%s" "${!_k}"; }','voiden_variables_get() { local _k="_VD_VAR_${1//[^A-Za-z0-9_]/_}"; printf "%s" "${!_k}"; }',"voiden_variables_set() {",' local _key="$1" _val="$2"',' local _k="_VD_VAR_${_key//[^A-Za-z0-9_]/_}"',' export "${_k}=${_val}"',' printf "%s\\t%s\\n" "$(_vd_b64 "$_key")" "$(_vd_b64 "$_val")" >> "$_VD_VAR_FILE"',"}",'voiden_cancel() { touch "$_VD_CANCEL_FILE"; }',"","# voiden.* dot-notation aliases (same API as JS / Python)",'voiden.log() { voiden_log "$@"; }','voiden.env.get() { voiden_env_get "$@"; }','voiden.variables.get() { voiden_variables_get "$@"; }','voiden.variables.set() { voiden_variables_set "$@"; }','voiden.assert() { voiden_assert "$@"; }',"voiden.cancel() { voiden_cancel; }","# request getters / setters","# Supports both call styles:",'# voiden.request.url "https://new.com" (bash style)','# voiden.request.url = "https://new.com" (JS-like style \u2014 = is treated as separator)','_vd_val() { [ "$1" = "=" ] && printf "%s" "$2" || printf "%s" "$1"; }','voiden.request.url() { [ $# -gt 0 ] && export VOIDEN_REQUEST_URL="$(_vd_val "$@")" || printf "%s" "$VOIDEN_REQUEST_URL"; }','voiden.request.method() { [ $# -gt 0 ] && export VOIDEN_REQUEST_METHOD="$(_vd_val "$@")" || printf "%s" "$VOIDEN_REQUEST_METHOD"; }','voiden.request.body() { [ $# -gt 0 ] && export VOIDEN_REQUEST_BODY="$(_vd_val "$@")" || printf "%s" "$VOIDEN_REQUEST_BODY"; }',"# shared entry builder \u2014 stores result in $_VD_KV_ENTRY","_vd_build_kv_entry() {",` local _Q='"' _k _v`,' _k="${1//$_Q/\\\\$_Q}"',' _v="${2//$_Q/\\\\$_Q}"',` printf -v _VD_KV_ENTRY '{"key":"%s","value":"%s","enabled":true}' "$_k" "$_v"`,"}","# _vd_set_kv: replace the array with a single entry","_vd_set_kv() {",' local _var="$1"',' _vd_build_kv_entry "$2" "$3"',` printf -v "$_var" '[%s]' "$_VD_KV_ENTRY"`,' export "$_var"',"}","# _vd_push_kv: append an entry to the existing array","_vd_push_kv() {",' local _var="$1" _cur',' _vd_build_kv_entry "$2" "$3"',' _cur="${!_var}"',' if [ -z "$_cur" ] || [ "$_cur" = "[]" ]; then',` printf -v "$_var" '[%s]' "$_VD_KV_ENTRY"`," else",` printf -v "$_var" '%s,%s]' "\${_cur%]}" "$_VD_KV_ENTRY"`," fi",' export "$_var"',"}","# collection setters: 2 args = set as single {key,value}; 1 arg = raw JSON; 0 args = getter",'voiden.request.headers() { if [ $# -ge 2 ]; then _vd_set_kv VOIDEN_REQUEST_HEADERS "$1" "$2"; elif [ $# -gt 0 ]; then export VOIDEN_REQUEST_HEADERS="$(_vd_val "$@")"; else printf "%s" "$VOIDEN_REQUEST_HEADERS"; fi; }','voiden.request.queryParams() { if [ $# -ge 2 ]; then _vd_set_kv VOIDEN_REQUEST_QUERY_PARAMS "$1" "$2"; elif [ $# -gt 0 ]; then export VOIDEN_REQUEST_QUERY_PARAMS="$(_vd_val "$@")"; else printf "%s" "$VOIDEN_REQUEST_QUERY_PARAMS"; fi; }','voiden.request.pathParams() { if [ $# -ge 2 ]; then _vd_set_kv VOIDEN_REQUEST_PATH_PARAMS "$1" "$2"; elif [ $# -gt 0 ]; then export VOIDEN_REQUEST_PATH_PARAMS="$(_vd_val "$@")"; else printf "%s" "$VOIDEN_REQUEST_PATH_PARAMS"; fi; }','voiden.request.headers.push() { _vd_push_kv VOIDEN_REQUEST_HEADERS "$1" "$2"; }','voiden.request.queryParams.push() { _vd_push_kv VOIDEN_REQUEST_QUERY_PARAMS "$1" "$2"; }','voiden.request.pathParams.push() { _vd_push_kv VOIDEN_REQUEST_PATH_PARAMS "$1" "$2"; }',"# response getters and writable setters (status, statusText, body)",'voiden.response.status() { [ $# -gt 0 ] && export VOIDEN_RESPONSE_STATUS="$(_vd_val "$@")" || printf "%s" "$VOIDEN_RESPONSE_STATUS"; }','voiden.response.statusText() { [ $# -gt 0 ] && export VOIDEN_RESPONSE_STATUS_TEXT="$(_vd_val "$@")" || printf "%s" "$VOIDEN_RESPONSE_STATUS_TEXT"; }','voiden.response.body() { [ $# -gt 0 ] && export VOIDEN_RESPONSE_BODY="$(_vd_val "$@")" || printf "%s" "$VOIDEN_RESPONSE_BODY"; }',"# response read-only fields",'voiden.response.headers() { printf "%s" "$VOIDEN_RESPONSE_HEADERS"; }','voiden.response.time() { printf "%s" "$VOIDEN_RESPONSE_TIME"; }','voiden.response.size() { printf "%s" "$VOIDEN_RESPONSE_SIZE"; }',"","voiden_assert() {",' local _actual="$1" _op="$2" _expected="$3" _msg="${4:-}" _passed="false"',' case "$_op" in',' "=="|eq|equal) [ "$_actual" = "$_expected" ] && _passed="true" ;;',' "===") [ "$_actual" = "$_expected" ] && _passed="true" ;;',' "!="|neq|notequal) [ "$_actual" != "$_expected" ] && _passed="true" ;;',' "!==") [ "$_actual" != "$_expected" ] && _passed="true" ;;',' contains|includes) case "$_actual" in *"$_expected"*) _passed="true";; esac ;;',' matches|regex) printf "%s" "$_actual" | grep -qE "$_expected" 2>/dev/null && _passed="true"; true ;;',' truthy) [ -n "$_actual" ] && _passed="true" ;;',' falsy) [ -z "$_actual" ] && _passed="true" ;;',' ">"|greater|greaterthan) (( _actual > _expected )) 2>/dev/null && _passed="true"; true ;;',' ">="|gte) (( _actual >= _expected )) 2>/dev/null && _passed="true"; true ;;',' "<"|less|lessthan) (( _actual < _expected )) 2>/dev/null && _passed="true"; true ;;',' "<="|lte) (( _actual <= _expected )) 2>/dev/null && _passed="true"; true ;;'," esac",' printf "%s\\t%s\\t%s\\t%s\\t%s\\n" "$(_vd_b64 "$_passed")" "$(_vd_b64 "$_actual")" "$(_vd_b64 "$_op")" "$(_vd_b64 "$_expected")" "$(_vd_b64 "$_msg")" >> "$_VD_ASSERT_FILE"',"}","","# Pre-loaded env vars",m,"","# Pre-loaded variables",b,"",`export VOIDEN_REQUEST_URL=${a(r?.url??"")}`,`export VOIDEN_REQUEST_METHOD=${a(r?.method??"GET")}`,`export VOIDEN_REQUEST_BODY=${a(r?.body!=null?typeof r.body=="object"?JSON.stringify(r.body):String(r.body):"")}`,`export VOIDEN_REQUEST_HEADERS=${a(JSON.stringify(r?.headers??[]))}`,`export VOIDEN_REQUEST_QUERY_PARAMS=${a(JSON.stringify(r?.queryParams??[]))}`,`export VOIDEN_REQUEST_PATH_PARAMS=${a(JSON.stringify(r?.pathParams??[]))}`,`export VOIDEN_RESPONSE_STATUS=${a(g?String(n?.status??""):"")}`,`export VOIDEN_RESPONSE_STATUS_TEXT=${a(g?String(n?.statusText??""):"")}`,`export VOIDEN_RESPONSE_BODY=${a(g&&n?.body!=null?typeof n.body=="object"?JSON.stringify(n.body):String(n.body):"")}`,`export VOIDEN_RESPONSE_HEADERS=${a(g?JSON.stringify(n?.headers??{}):"{}")}`,`export VOIDEN_RESPONSE_TIME=${a(g?String(n?.time??0):"0")}`,`export VOIDEN_RESPONSE_SIZE=${a(g?String(n?.size??0):"0")}`,"","# --- User Script (sourced from separate file; errors are caught) ---",'. "$_VD_USERSCRIPT_FILE" || true',"# --- End User Script ---","",'printf "%s\\t%s\\n" "$(_vd_b64 "url")" "$(_vd_b64 "$VOIDEN_REQUEST_URL")" >> "$_VD_REQUEST_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "method")" "$(_vd_b64 "$VOIDEN_REQUEST_METHOD")" >> "$_VD_REQUEST_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "body")" "$(_vd_b64 "$VOIDEN_REQUEST_BODY")" >> "$_VD_REQUEST_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "headers")" "$(_vd_b64 "$VOIDEN_REQUEST_HEADERS")" >> "$_VD_REQUEST_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "queryParams")" "$(_vd_b64 "$VOIDEN_REQUEST_QUERY_PARAMS")" >> "$_VD_REQUEST_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "pathParams")" "$(_vd_b64 "$VOIDEN_REQUEST_PATH_PARAMS")" >> "$_VD_REQUEST_FILE"',"# Write modified response fields (only when a response exists)",`[ -n ${a(g?"1":"")} ] && {`,'printf "%s\\t%s\\n" "$(_vd_b64 "status")" "$(_vd_b64 "$VOIDEN_RESPONSE_STATUS")" >> "$_VD_RESPONSE_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "statusText")" "$(_vd_b64 "$VOIDEN_RESPONSE_STATUS_TEXT")" >> "$_VD_RESPONSE_FILE"','printf "%s\\t%s\\n" "$(_vd_b64 "body")" "$(_vd_b64 "$VOIDEN_RESPONSE_BODY")" >> "$_VD_RESPONSE_FILE"',"}","true"].join(`
|
|
4
|
+
`)}var A,I,L,U=q(()=>{"use strict";A=`
|
|
5
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
6
|
+
|
|
7
|
+
let requestState = null;
|
|
8
|
+
let responseState = null;
|
|
9
|
+
let _envData = {};
|
|
10
|
+
let _variablesData = {};
|
|
11
|
+
const _modifiedVariables = {};
|
|
12
|
+
const logs = [];
|
|
13
|
+
const assertions = [];
|
|
14
|
+
let cancelled = false;
|
|
15
|
+
|
|
16
|
+
function _normalizeLevel(value) {
|
|
17
|
+
if (typeof value !== 'string') return null;
|
|
18
|
+
const lowered = value.toLowerCase();
|
|
19
|
+
if (lowered === 'warning') return 'warn';
|
|
20
|
+
if (lowered === 'log' || lowered === 'info' || lowered === 'debug' || lowered === 'warn' || lowered === 'error') return lowered;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function _pushLog(level, args) {
|
|
25
|
+
logs.push({ level, args });
|
|
26
|
+
self.postMessage({ type: 'log', args });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function _serializeAssertionValue(val) {
|
|
30
|
+
try { return JSON.parse(JSON.stringify(val)); } catch { return String(val); }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function _toConditionText(val) {
|
|
34
|
+
if (typeof val === 'string') return JSON.stringify(val);
|
|
35
|
+
try { return JSON.stringify(val); } catch { return String(val); }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _normalizeOperator(op) {
|
|
39
|
+
if (typeof op !== 'string') return null;
|
|
40
|
+
const key = op.trim().toLowerCase().replace(/\\s+/g, '');
|
|
41
|
+
const map = {
|
|
42
|
+
'==':'==','===':'===','eq':'==','equal':'==',
|
|
43
|
+
'!=':'!=','!==':'!==','neq':'!=','notequal':'!=',
|
|
44
|
+
'greater':'>','greaterthan':'>','gte':'>=',
|
|
45
|
+
'less':'<','lessthan':'<','lte':'<=',
|
|
46
|
+
'>':'>','>=':'>=','<':'<','<=':'<=',
|
|
47
|
+
'contains':'contains','includes':'contains',
|
|
48
|
+
'matches':'matches','regex':'matches',
|
|
49
|
+
'truthy':'truthy','falsy':'falsy',
|
|
50
|
+
};
|
|
51
|
+
return map[key] || null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function _evaluateAssertion(actual, operator, expected) {
|
|
55
|
+
switch (operator) {
|
|
56
|
+
case '==': return actual == expected;
|
|
57
|
+
case '===': return actual === expected;
|
|
58
|
+
case '!=': return actual != expected;
|
|
59
|
+
case '!==': return actual !== expected;
|
|
60
|
+
case '>': return actual > expected;
|
|
61
|
+
case '>=': return actual >= expected;
|
|
62
|
+
case '<': return actual < expected;
|
|
63
|
+
case '<=': return actual <= expected;
|
|
64
|
+
case 'contains':
|
|
65
|
+
if (typeof actual === 'string') return actual.includes(String(expected));
|
|
66
|
+
if (Array.isArray(actual)) return actual.includes(expected);
|
|
67
|
+
return false;
|
|
68
|
+
case 'matches':
|
|
69
|
+
try { return new RegExp(String(expected)).test(String(actual)); } catch { return false; }
|
|
70
|
+
case 'truthy': return Boolean(actual);
|
|
71
|
+
case 'falsy': return !actual;
|
|
72
|
+
default: return Boolean(actual);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
self.onmessage = async (event) => {
|
|
77
|
+
const data = event.data;
|
|
78
|
+
if (data && data.type === 'start') {
|
|
79
|
+
requestState = data.request;
|
|
80
|
+
responseState = data.response;
|
|
81
|
+
_envData = data.envData || {};
|
|
82
|
+
_variablesData = Object.assign({}, data.variablesData || {});
|
|
83
|
+
const scriptBody = data.script;
|
|
84
|
+
|
|
85
|
+
const voiden = {
|
|
86
|
+
request: requestState,
|
|
87
|
+
response: responseState,
|
|
88
|
+
env: { get: function(key) { return _envData[key]; } },
|
|
89
|
+
variables: {
|
|
90
|
+
get: function(key) { return _variablesData[key]; },
|
|
91
|
+
set: function(key, value) { _variablesData[key] = value; _modifiedVariables[key] = value; },
|
|
92
|
+
},
|
|
93
|
+
log: function(levelOrMessage) {
|
|
94
|
+
const rest = Array.prototype.slice.call(arguments, 1);
|
|
95
|
+
const normalized = _normalizeLevel(levelOrMessage);
|
|
96
|
+
if (normalized) { _pushLog(normalized, rest); return; }
|
|
97
|
+
_pushLog('log', [levelOrMessage].concat(rest));
|
|
98
|
+
},
|
|
99
|
+
assert: function(actual, operator, expected, message) {
|
|
100
|
+
const rawOperator = String(operator);
|
|
101
|
+
const normalizedOperator = _normalizeOperator(operator);
|
|
102
|
+
if (!normalizedOperator) {
|
|
103
|
+
assertions.push({ passed: false, message: message ? String(message) : '', reason: 'Unsupported operator: ' + rawOperator, condition: _toConditionText(actual) + ' ' + rawOperator + ' ' + _toConditionText(expected), actualValue: _serializeAssertionValue(actual), operator: rawOperator, expectedValue: _serializeAssertionValue(expected) });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const passed = _evaluateAssertion(actual, normalizedOperator, expected);
|
|
107
|
+
assertions.push({ passed, message: message ? String(message) : '', condition: _toConditionText(actual) + ' ' + normalizedOperator + ' ' + _toConditionText(expected), actualValue: _serializeAssertionValue(actual), operator: normalizedOperator, expectedValue: _serializeAssertionValue(expected) });
|
|
108
|
+
},
|
|
109
|
+
cancel: function() { cancelled = true; },
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const _require = typeof require !== 'undefined' ? require : undefined;
|
|
114
|
+
const fn = new AsyncFunction('voiden', 'vd', 'require', scriptBody);
|
|
115
|
+
await fn(voiden, voiden, _require);
|
|
116
|
+
self.postMessage({ type: 'done', success: true, cancelled, logs, assertions, modifiedRequest: voiden.request, modifiedResponse: voiden.response, modifiedVariables: _modifiedVariables });
|
|
117
|
+
} catch (error) {
|
|
118
|
+
self.postMessage({ type: 'done', success: false, cancelled, logs, assertions, modifiedRequest: voiden.request, modifiedResponse: voiden.response, modifiedVariables: _modifiedVariables, error: (error && (error.stack || error.message)) ? String(error.stack || error.message) : String(error) });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
`,I=`
|
|
123
|
+
'use strict';
|
|
124
|
+
var Worker = require('worker_threads').Worker;
|
|
125
|
+
var _chunks = [];
|
|
126
|
+
process.stdin.on('data', function(c) { _chunks.push(c); });
|
|
127
|
+
process.stdin.on('end', function() {
|
|
128
|
+
var _input = JSON.parse(Buffer.concat(_chunks).toString('utf-8'));
|
|
129
|
+
var _workerSource = _input.workerSource;
|
|
130
|
+
var _envData = _input.envVars || {};
|
|
131
|
+
var _variablesData = _input.variables || {};
|
|
132
|
+
|
|
133
|
+
var _shim = [
|
|
134
|
+
"var workerThreads = require('worker_threads');",
|
|
135
|
+
"var self = { postMessage: function(data) { workerThreads.parentPort.postMessage(data); } };",
|
|
136
|
+
"workerThreads.parentPort.on('message', function(data) { if (self.onmessage) self.onmessage({ data: data }); });",
|
|
137
|
+
""
|
|
138
|
+
].join('\\n');
|
|
139
|
+
|
|
140
|
+
var _worker = new Worker(_shim + _workerSource, { eval: true });
|
|
141
|
+
|
|
142
|
+
var _timeout = setTimeout(function() {
|
|
143
|
+
_worker.terminate();
|
|
144
|
+
process.stdout.write(JSON.stringify({ success: false, logs: [], error: 'Script execution timed out after 10000ms', cancelled: false, modifiedVariables: {} }) + '\\n');
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}, 10000);
|
|
147
|
+
|
|
148
|
+
_worker.on('message', function(msg) {
|
|
149
|
+
if (msg.type === 'done') {
|
|
150
|
+
clearTimeout(_timeout);
|
|
151
|
+
process.stdout.write(JSON.stringify({ success: msg.success, logs: msg.logs || [], assertions: msg.assertions || [], cancelled: msg.cancelled || false, error: msg.error, modifiedRequest: msg.modifiedRequest, modifiedResponse: msg.modifiedResponse, modifiedVariables: msg.modifiedVariables || {} }) + '\\n');
|
|
152
|
+
_worker.terminate();
|
|
153
|
+
process.exit(msg.success ? 0 : 1);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
_worker.on('error', function(err) {
|
|
158
|
+
clearTimeout(_timeout);
|
|
159
|
+
process.stdout.write(JSON.stringify({ success: false, logs: [], error: err.stack || err.message || String(err), cancelled: false, modifiedVariables: {} }) + '\\n');
|
|
160
|
+
process.exit(1);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
_worker.postMessage({ type: 'start', script: _input.scriptBody, request: _input.request || {}, response: _input.response || null, envData: _envData, variablesData: _variablesData });
|
|
164
|
+
});
|
|
165
|
+
`,L=`
|
|
166
|
+
import sys, json
|
|
167
|
+
import traceback
|
|
168
|
+
|
|
169
|
+
def main():
|
|
170
|
+
input_data = json.loads(sys.stdin.read())
|
|
171
|
+
|
|
172
|
+
script_body = input_data["scriptBody"]
|
|
173
|
+
|
|
174
|
+
request_data = input_data.get("request", {})
|
|
175
|
+
response_data = input_data.get("response", None)
|
|
176
|
+
env_data = input_data.get("envVars", {})
|
|
177
|
+
variables_data = input_data.get("variables", {})
|
|
178
|
+
|
|
179
|
+
logs = []
|
|
180
|
+
assertions = []
|
|
181
|
+
cancelled = False
|
|
182
|
+
modified_variables = {}
|
|
183
|
+
|
|
184
|
+
class _List:
|
|
185
|
+
def __init__(self, values=None):
|
|
186
|
+
self._items = []
|
|
187
|
+
if values:
|
|
188
|
+
for v in values:
|
|
189
|
+
self._items.append(_wrap(v))
|
|
190
|
+
|
|
191
|
+
def push(self, *values):
|
|
192
|
+
if len(values) == 2 and isinstance(values[0], str) and not isinstance(values[1], (dict, list, tuple)):
|
|
193
|
+
key = values[0].strip()
|
|
194
|
+
if key:
|
|
195
|
+
self._items.append(_wrap({"key": key, "value": str(values[1]), "enabled": True}))
|
|
196
|
+
return len(self._items)
|
|
197
|
+
for v in values:
|
|
198
|
+
if isinstance(v, dict) and "key" in v and "value" in v:
|
|
199
|
+
key = str(v.get("key", "")).strip()
|
|
200
|
+
if not key: continue
|
|
201
|
+
self._items.append(_wrap({"key": key, "value": str(v.get("value", "")), "enabled": v.get("enabled", True) is not False}))
|
|
202
|
+
continue
|
|
203
|
+
if isinstance(v, dict):
|
|
204
|
+
for mk, mv in v.items():
|
|
205
|
+
mkey = str(mk).strip()
|
|
206
|
+
if not mkey: continue
|
|
207
|
+
self._items.append(_wrap({"key": mkey, "value": str(mv), "enabled": True}))
|
|
208
|
+
continue
|
|
209
|
+
self._items.append(_wrap(v))
|
|
210
|
+
return len(self._items)
|
|
211
|
+
|
|
212
|
+
def append(self, value): self._items.append(_wrap(value))
|
|
213
|
+
def extend(self, values):
|
|
214
|
+
for v in values: self._items.append(_wrap(v))
|
|
215
|
+
def __iter__(self): return iter(self._items)
|
|
216
|
+
def __len__(self): return len(self._items)
|
|
217
|
+
def __getitem__(self, index): return self._items[index]
|
|
218
|
+
def __setitem__(self, index, value): self._items[index] = _wrap(value)
|
|
219
|
+
def __repr__(self): return repr(self._items)
|
|
220
|
+
|
|
221
|
+
def _wrap(val):
|
|
222
|
+
if isinstance(val, dict): return _Obj(val)
|
|
223
|
+
if isinstance(val, list): return _List(val)
|
|
224
|
+
if isinstance(val, tuple): return tuple(_wrap(v) for v in val)
|
|
225
|
+
return val
|
|
226
|
+
|
|
227
|
+
_REQUEST_COLLECTION_FIELDS = {"headers", "queryParams", "pathParams"}
|
|
228
|
+
|
|
229
|
+
class _Obj:
|
|
230
|
+
def __init__(self, data, normalize_collections=False):
|
|
231
|
+
object.__setattr__(self, '_normalize_collections', normalize_collections)
|
|
232
|
+
for k, v in data.items(): setattr(self, k, v)
|
|
233
|
+
|
|
234
|
+
def __setattr__(self, key, value):
|
|
235
|
+
if key == '_normalize_collections':
|
|
236
|
+
object.__setattr__(self, key, value)
|
|
237
|
+
return
|
|
238
|
+
if object.__getattribute__(self, '_normalize_collections') and key in _REQUEST_COLLECTION_FIELDS:
|
|
239
|
+
object.__setattr__(self, key, _List(_normalize_kv_collection(value)))
|
|
240
|
+
return
|
|
241
|
+
object.__setattr__(self, key, _wrap(value))
|
|
242
|
+
|
|
243
|
+
def __getitem__(self, key): return getattr(self, key)
|
|
244
|
+
def __setitem__(self, key, value): setattr(self, key, value)
|
|
245
|
+
def get(self, key, default=None): return getattr(self, key, default)
|
|
246
|
+
def items(self): return ((k, v) for k, v in self.__dict__.items() if k != '_normalize_collections')
|
|
247
|
+
|
|
248
|
+
def _normalize_kv_collection(value):
|
|
249
|
+
items = []
|
|
250
|
+
if isinstance(value, list):
|
|
251
|
+
for item in value:
|
|
252
|
+
if isinstance(item, dict) and "key" in item and "value" in item:
|
|
253
|
+
key = str(item.get("key", "")).strip()
|
|
254
|
+
if not key: continue
|
|
255
|
+
items.append({"key": key, "value": str(item.get("value", "")), "enabled": item.get("enabled", True) is not False})
|
|
256
|
+
elif isinstance(item, dict):
|
|
257
|
+
for mk, mv in item.items():
|
|
258
|
+
mkey = str(mk).strip()
|
|
259
|
+
if not mkey: continue
|
|
260
|
+
items.append({"key": mkey, "value": str(mv), "enabled": True})
|
|
261
|
+
return items
|
|
262
|
+
if isinstance(value, dict):
|
|
263
|
+
if "key" in value and "value" in value:
|
|
264
|
+
key = str(value.get("key", "")).strip()
|
|
265
|
+
if not key: return []
|
|
266
|
+
return [{"key": key, "value": str(value.get("value", "")), "enabled": value.get("enabled", True) is not False}]
|
|
267
|
+
for mk, mv in value.items():
|
|
268
|
+
mkey = str(mk).strip()
|
|
269
|
+
if not mkey: continue
|
|
270
|
+
items.append({"key": mkey, "value": str(mv), "enabled": True})
|
|
271
|
+
return items
|
|
272
|
+
return []
|
|
273
|
+
|
|
274
|
+
class _Variables:
|
|
275
|
+
def get(self, key): return variables_data.get(key)
|
|
276
|
+
def set(self, key, value):
|
|
277
|
+
serialized = _serialize(value)
|
|
278
|
+
variables_data[key] = serialized
|
|
279
|
+
modified_variables[key] = serialized
|
|
280
|
+
|
|
281
|
+
class _Env:
|
|
282
|
+
def get(self, key): return env_data.get(key)
|
|
283
|
+
|
|
284
|
+
class _Vd:
|
|
285
|
+
def __init__(self):
|
|
286
|
+
self.request = _Obj(request_data, normalize_collections=True)
|
|
287
|
+
self.response = _Obj(response_data) if response_data else None
|
|
288
|
+
self.env = _Env()
|
|
289
|
+
self.variables = _Variables()
|
|
290
|
+
|
|
291
|
+
def log(self, *args):
|
|
292
|
+
level = "log"
|
|
293
|
+
payload = args
|
|
294
|
+
if len(args) >= 1 and isinstance(args[0], str):
|
|
295
|
+
lowered = args[0].lower()
|
|
296
|
+
if lowered == "warning": lowered = "warn"
|
|
297
|
+
if lowered in ("log", "info", "debug", "warn", "error"):
|
|
298
|
+
level = lowered
|
|
299
|
+
payload = args[1:]
|
|
300
|
+
logs.append({"level": level, "args": [_serialize(a) for a in payload]})
|
|
301
|
+
|
|
302
|
+
def assert_(self, actual, operator, expected, message=""):
|
|
303
|
+
normalized_operator = _normalize_operator(operator)
|
|
304
|
+
if normalized_operator is None:
|
|
305
|
+
raw_operator = str(operator)
|
|
306
|
+
assertions.append({"passed": False, "message": str(message), "reason": "Unsupported operator: " + raw_operator, "condition": _to_condition_text(actual) + " " + raw_operator + " " + _to_condition_text(expected), "actualValue": _serialize(actual), "operator": raw_operator, "expectedValue": _serialize(expected)})
|
|
307
|
+
return
|
|
308
|
+
passed = _evaluate_assertion(actual, normalized_operator, expected)
|
|
309
|
+
assertions.append({"passed": bool(passed), "message": str(message), "condition": _to_condition_text(actual) + " " + str(normalized_operator) + " " + _to_condition_text(expected), "actualValue": _serialize(actual), "operator": str(normalized_operator), "expectedValue": _serialize(expected)})
|
|
310
|
+
|
|
311
|
+
def cancel(self):
|
|
312
|
+
nonlocal cancelled
|
|
313
|
+
cancelled = True
|
|
314
|
+
|
|
315
|
+
def _serialize(val):
|
|
316
|
+
if isinstance(val, _List): return [_serialize(v) for v in val]
|
|
317
|
+
if isinstance(val, _Obj): return {k: _serialize(v) for k, v in val.__dict__.items() if k != '_normalize_collections'}
|
|
318
|
+
if isinstance(val, dict): return {k: _serialize(v) for k, v in val.items()}
|
|
319
|
+
if isinstance(val, (list, tuple)): return [_serialize(v) for v in val]
|
|
320
|
+
try:
|
|
321
|
+
json.dumps(val)
|
|
322
|
+
return val
|
|
323
|
+
except (TypeError, ValueError): return str(val)
|
|
324
|
+
|
|
325
|
+
def _extract(obj, keys):
|
|
326
|
+
result = {}
|
|
327
|
+
for k in keys:
|
|
328
|
+
if hasattr(obj, k): result[k] = _serialize(getattr(obj, k))
|
|
329
|
+
return result
|
|
330
|
+
|
|
331
|
+
def _json_equal(a, b):
|
|
332
|
+
try: return json.dumps(a, sort_keys=True) == json.dumps(b, sort_keys=True)
|
|
333
|
+
except Exception: return False
|
|
334
|
+
|
|
335
|
+
def _normalize_operator(op):
|
|
336
|
+
if not isinstance(op, str): return None
|
|
337
|
+
key = "".join(op.strip().lower().split())
|
|
338
|
+
mapping = {"==":"==","===":"===","eq":"==","equal":"==","!=":"!=","!==":"!==","neq":"!=","notequal":"!=","greater":">","greaterthan":">","gte":">=","less":"<","lessthan":"<","lte":"<=",">":">",">=":">=","<":"<","<=":"<=","contains":"contains","includes":"contains","matches":"matches","regex":"matches","truthy":"truthy","falsy":"falsy"}
|
|
339
|
+
return mapping.get(key)
|
|
340
|
+
|
|
341
|
+
def _to_condition_text(value):
|
|
342
|
+
if isinstance(value, str): return json.dumps(value)
|
|
343
|
+
try: return json.dumps(value)
|
|
344
|
+
except Exception: return str(value)
|
|
345
|
+
|
|
346
|
+
def _evaluate_assertion(actual, operator, expected):
|
|
347
|
+
try:
|
|
348
|
+
if operator == "==": return actual == expected
|
|
349
|
+
if operator == "===": return type(actual) == type(expected) and actual == expected
|
|
350
|
+
if operator == "!=": return actual != expected
|
|
351
|
+
if operator == "!==": return not (type(actual) == type(expected) and actual == expected)
|
|
352
|
+
if operator == ">": return actual > expected
|
|
353
|
+
if operator == ">=": return actual >= expected
|
|
354
|
+
if operator == "<": return actual < expected
|
|
355
|
+
if operator == "<=": return actual <= expected
|
|
356
|
+
if operator == "contains":
|
|
357
|
+
if isinstance(actual, str): return str(expected) in actual
|
|
358
|
+
if isinstance(actual, (list, tuple)): return expected in actual
|
|
359
|
+
return False
|
|
360
|
+
if operator == "matches":
|
|
361
|
+
import re
|
|
362
|
+
return re.search(str(expected), str(actual)) is not None
|
|
363
|
+
if operator == "truthy": return bool(actual)
|
|
364
|
+
if operator == "falsy": return not bool(actual)
|
|
365
|
+
except Exception: return False
|
|
366
|
+
return bool(actual)
|
|
367
|
+
|
|
368
|
+
voiden = _Vd()
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
script_body = script_body.replace('voiden.assert(', 'voiden.assert_(')
|
|
372
|
+
script_body = script_body.replace('vd.assert(', 'vd.assert_(')
|
|
373
|
+
exec(script_body, {"voiden": voiden, "vd": voiden, "__builtins__": __builtins__})
|
|
374
|
+
|
|
375
|
+
mod_request = _extract(voiden.request, ["url", "method", "headers", "body", "queryParams", "pathParams"])
|
|
376
|
+
mod_response = None
|
|
377
|
+
if voiden.response is not None:
|
|
378
|
+
candidate_response = _extract(voiden.response, ["status", "statusText", "headers", "body", "time", "size"])
|
|
379
|
+
original_response = _serialize(response_data) if response_data is not None else None
|
|
380
|
+
if original_response is None or not _json_equal(candidate_response, original_response):
|
|
381
|
+
mod_response = candidate_response
|
|
382
|
+
|
|
383
|
+
result = {"success": True, "logs": logs, "assertions": assertions, "cancelled": cancelled, "modifiedRequest": mod_request, "modifiedResponse": mod_response, "modifiedVariables": modified_variables}
|
|
384
|
+
except Exception as e:
|
|
385
|
+
result = {"success": False, "logs": logs, "assertions": assertions, "cancelled": cancelled, "error": traceback.format_exc(), "modifiedVariables": _serialize(modified_variables)}
|
|
386
|
+
|
|
387
|
+
print(json.dumps(result))
|
|
388
|
+
sys.exit(0 if result.get("success") else 1)
|
|
389
|
+
|
|
390
|
+
main()
|
|
391
|
+
`});var w={};P(w,{executeHeadlessScript:()=>ye,getPythonBin:()=>j,isNodeAvailable:()=>oe,loadHeadlessVariables:()=>ie});function j(){if(h!==void 0)return h;for(let e of["python3","python"])try{return(0,R.execFileSync)(e,["--version"],{stdio:"pipe",timeout:3e3}),h=e,e}catch{}return h=null,null}function oe(){try{return require("worker_threads"),!0}catch{return!1}}function ie(){let e=(0,v.join)((0,k.homedir)(),".voiden",".process.env.json");if(!(0,_.existsSync)(e))return{};try{return JSON.parse((0,_.readFileSync)(e,"utf-8"))}catch{return{}}}function C(e,r,n){return new Promise(s=>{let t=(0,R.spawn)(e,r,{stdio:["pipe","pipe","pipe"]}),i="",o="";t.stdout.on("data",d=>{i+=d.toString()}),t.stderr.on("data",d=>{o+=d.toString()});let l=setTimeout(()=>{t.kill("SIGKILL"),s({stdout:"",stderr:`Timed out after ${V}ms`,code:-1})},V);t.on("close",d=>{clearTimeout(l),s({stdout:i,stderr:o,code:d})}),t.stdin.write(n,"utf-8"),t.stdin.end()})}function z(e,r,n){let s=e.trim().split(`
|
|
392
|
+
`).pop()??"";try{let t=JSON.parse(s);return{success:!!t.success,logs:Array.isArray(t.logs)?t.logs:[],assertions:Array.isArray(t.assertions)?t.assertions:[],cancelled:!!t.cancelled,error:t.error,exitCode:n??0,modifiedRequest:t.modifiedRequest,modifiedResponse:t.modifiedResponse}}catch{let t=r.trim()||`Script output could not be parsed: ${s.slice(0,300)}`;return{success:!1,logs:[],error:t,cancelled:!1,exitCode:n??1}}}async function le(e,r,n,s,t){let i=Object.getPrototypeOf(async function(){}).constructor,o=[],l=[],d=!1,u={...t},y={},p=a=>({"==":"==","===":"===",eq:"==",equal:"==","!=":"!=","!==":"!==",neq:"!=",notequal:"!=",">":">",">=":">=","<":"<","<=":"<=",greater:">",greaterthan:">",gte:">=",less:"<",lessthan:"<",lte:"<=",contains:"contains",includes:"contains",matches:"matches",regex:"matches",truthy:"truthy",falsy:"falsy"})[a.trim().toLowerCase().replace(/\s+/g,"")]??null,m=(a,f,c)=>{try{switch(f){case"==":return a==c;case"===":return a===c;case"!=":return a!=c;case"!==":return a!==c;case">":return a>c;case">=":return a>=c;case"<":return a<c;case"<=":return a<=c;case"contains":return typeof a=="string"?a.includes(String(c)):Array.isArray(a)&&a.includes(c);case"matches":return new RegExp(String(c)).test(String(a));case"truthy":return!!a;case"falsy":return!a;default:return!!a}}catch{return!1}},b=a=>{try{return JSON.stringify(a)}catch{return String(a)}},g={request:r,response:n,env:{get:a=>s[a]},variables:{get:a=>u[a],set:(a,f)=>{u[a]=f,y[a]=f}},log:(a,...f)=>{let S=typeof a=="string"&&["log","info","debug","warn","warning","error"].includes(a.toLowerCase()),E=S?a==="warning"?"warn":a:"log";o.push({level:E,args:S?f:[a,...f]})},assert:(a,f,c,S)=>{let E=p(f);if(!E){l.push({passed:!1,message:S??"",reason:`Unsupported operator: ${f}`,actualValue:a,operator:f,expectedValue:c});return}l.push({passed:m(a,E,c),message:S??"",condition:`${b(a)} ${E} ${b(c)}`,actualValue:a,operator:E,expectedValue:c})},cancel:()=>{d=!0}};try{return await new i("voiden","vd",e)(g,g),{success:!0,logs:o,assertions:l,cancelled:d,exitCode:0,modifiedRequest:g.request,modifiedResponse:g.response,modifiedVariables:y}}catch(a){return{success:!1,logs:o,assertions:l,error:String(a?.stack||a?.message||a),cancelled:d,exitCode:1,modifiedVariables:y}}}async function ce(e,r,n,s,t){let i=JSON.stringify({scriptBody:e,workerSource:A,request:r??{},response:n??null,envVars:s,variables:t}),{stdout:o,stderr:l,code:d}=await C("node",["-e",I],i);return z(o,l,d)}async function ue(e,r,n,s,t){let i=j();if(!i)return{success:!1,logs:[],error:"python3 not found in PATH. Install Python 3 to run Python scripts in voiden-runner.",cancelled:!1,exitCode:-1};let o=JSON.stringify({scriptBody:e,request:r??{},response:n??null,envVars:s,variables:t}),{stdout:l,stderr:d,code:u}=await C(i,["-c",L],o);return z(l,d,u)}async function de(e,r,n,s,t){let i=`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`,o=(0,v.join)((0,k.tmpdir)(),`voiden-runner-${i}`);(0,_.mkdirSync)(o,{recursive:!0});let l=(0,v.join)(o,"log.tsv"),d=(0,v.join)(o,"vars.tsv"),u=(0,v.join)(o,"assertions.tsv"),y=(0,v.join)(o,"cancel"),p=(0,v.join)(o,"request.tsv"),m=(0,v.join)(o,"response.tsv"),b=(0,v.join)(o,"user.sh"),g=(0,v.join)(o,"wrapper.sh");(0,_.writeFileSync)(b,e,"utf-8");for(let c of[l,d,u,p,m])(0,_.writeFileSync)(c,"","utf-8");let a=F({request:r??{},response:n??null,envVars:s,variables:t,logFile:l,varFile:d,assertFile:u,cancelFile:y,reqFile:p,respFile:m,userScriptFile:b});return(0,_.writeFileSync)(g,a,"utf-8"),new Promise(c=>{let S=(0,R.spawn)("bash",[g],{stdio:["ignore","pipe","pipe"]}),E=setTimeout(()=>{S.kill("SIGKILL"),f(),c({success:!1,logs:[],error:`Shell script timed out after ${V}ms`,cancelled:!1,exitCode:-1})},V);S.on("close",N=>{clearTimeout(E);let G=_e(l),K=pe(u),Z=fe(p,r),X=ge(m,n),ee=(0,_.existsSync)(y);f(),c({success:N===0,logs:G,assertions:K,cancelled:ee,exitCode:N??0,modifiedRequest:Z,modifiedResponse:X})})});function f(){try{(0,_.rmSync)(o,{recursive:!0,force:!0})}catch{}}}function $(e){return Buffer.from(e??"","base64").toString("utf-8")}function _e(e){return(0,_.existsSync)(e)?(0,_.readFileSync)(e,"utf-8").split(`
|
|
393
|
+
`).filter(Boolean).map(r=>{let[n,s]=r.split(" ");return{level:$(n)||"log",args:[$(s)]}}):[]}function pe(e){return(0,_.existsSync)(e)?(0,_.readFileSync)(e,"utf-8").split(`
|
|
394
|
+
`).filter(Boolean).map(r=>{let n=r.split(" ").map($),[s,t,i,o,l]=n;return{passed:s==="true",actualValue:t,operator:i,expectedValue:o,message:l??""}}):[]}function fe(e,r){if(!(0,_.existsSync)(e))return r;let n={...r};return(0,_.readFileSync)(e,"utf-8").split(`
|
|
395
|
+
`).filter(Boolean).forEach(s=>{let[t,i]=s.split(" "),o=$(t),l=$(i);if(o)if(["headers","queryParams","pathParams"].includes(o))try{n[o]=JSON.parse(l)}catch{n[o]=l}else n[o]=l}),n}function ge(e,r){if(!(0,_.existsSync)(e)||!r)return r;let n={...r};return(0,_.readFileSync)(e,"utf-8").split(`
|
|
396
|
+
`).filter(Boolean).forEach(s=>{let[t,i]=s.split(" "),o=$(t),l=$(i);if(o)if(o==="status")n[o]=parseInt(l,10)||0;else if(o==="body")try{n[o]=JSON.parse(l)}catch{n[o]=l}else n[o]=l}),n}async function ye(e,r,n,s,t={},i={},o=!1){return r==="python"?ue(e,n,s,t,i):r==="shell"?de(e,n,s,t,i):o?ce(e,n,s,t,i):le(e,n,s,t,i)}var R,_,v,k,V,h,D=q(()=>{"use strict";R=require("child_process"),_=require("fs"),v=require("path"),k=require("os");U();V=1e4});var Re={};P(Re,{default:()=>$e});module.exports=ae(Re);var J=require("@voiden/sdk/shared"),x=require("fs"),Y=require("path"),W=require("os");function Q(e,r){if(!e?.content)return null;let n=null,s=t=>{t.type===r&&t.attrs?.body&&(n={body:t.attrs.body,language:t.attrs.language??"javascript"}),t.content?.forEach?.(i=>s(i))};return s(e),n}function M(e,r){return r==="python"?e.replace(/#.*$/gm,"").trim():e.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"").trim()}function H(){let e=(0,Y.join)((0,W.homedir)(),".voiden",".process.env.json");if(!(0,x.existsSync)(e))return{};try{return JSON.parse((0,x.readFileSync)(e,"utf-8"))}catch{return{}}}function B(e){let r=n=>Array.isArray(n)?n:n&&typeof n=="object"?Object.entries(n).map(([s,t])=>({key:s,value:String(t),enabled:!0})):[];return{url:e.url??"",method:e.method??"GET",headers:r(e.headers),body:e.body,queryParams:r(e.queryParams),pathParams:r(e.pathParams)}}function ve(e){let r=e.headers??[],n={},s=[];r.forEach(i=>{i.key.toLowerCase()==="set-cookie"?s.push(i.value):n[i.key]=i.value}),s.length>0&&(n["set-cookie"]=s.join(`
|
|
397
|
+
`));let t=(0,J.parseCookies)(r);return{status:e.status,statusText:e.statusText,headers:n,cookies:t,body:e.body,time:e.durationMs??0,size:e.size??0}}function me(e,r){r.url=e.url,r.method=e.method;let n=s=>Array.isArray(s)?s:s&&typeof s=="object"?Object.entries(s).map(([t,i])=>({key:t,value:String(i),enabled:!0})):[];if(r.headers=n(e.headers),r.queryParams=n(e.queryParams),r.pathParams=n(e.pathParams),e.body!=null&&typeof e.body=="object")try{r.body=JSON.stringify(e.body)}catch{r.body=String(e.body)}else r.body=e.body}function Se(e,r){e.status!==void 0&&(r.status=e.status),e.statusText!==void 0&&(r.statusText=e.statusText),e.body!==void 0&&(r.body=e.body)}function Ee(e,r,n){Array.isArray(e.reportEntries)||(e.reportEntries=[]);let s=e.reportEntries;for(let t of r.assertions??[])s.push({type:"assertion",message:t.message||t.condition||"Script assertion",passed:t.passed,actual:t.actualValue,expected:t.expectedValue,operator:t.operator});for(let t of n){let i=Array.isArray(t.args)?t.args.map(o=>typeof o=="object"?JSON.stringify(o):String(o)).join(" "):String(t.args??"");i&&s.push({type:"log",message:i,level:t.level??"log"})}r.error&&s.push({type:"log",message:`Script error: ${r.error}`,level:"error"})}var be=e=>({onload(){let r=null,n={};e.pipeline.registerHook("pre-processing",s=>{if(!s.editor)return;s.requestState.metadata||(s.requestState.metadata={});let t=s.editor.getJSON();s.requestState.metadata.editorDocument=t,r=t,n=s.editor.__cliEnv??{},s.requestState.metadata._cliVarsRef=s.editor.__cliVars??{}},5),e.pipeline.registerHook("pre-send",async s=>{if(!r)return;let t=Q(r,"pre_script");if(!t||!M(t.body,t.language))return;let{executeHeadlessScript:i}=await Promise.resolve().then(()=>(D(),w)),o=s.requestState.metadata?._cliVarsRef??{},l={...H(),...o},d=B(s.requestState),u=await i(t.body,t.language,d,null,n,l);if(u.success&&u.modifiedRequest&&me(u.modifiedRequest,s.requestState),u.modifiedVariables&&Object.assign(o,u.modifiedVariables),s.requestState.metadata||(s.requestState.metadata={}),s.requestState.metadata.preScriptLogs=u.logs??[],s.requestState.metadata.preScriptAssertions=u.assertions??[],u.error&&(s.requestState.metadata.preScriptError=u.error),u.cancelled)throw s.requestState.metadata.scriptCancelled=!0,new Error("Request cancelled by pre-request script")},15),e.pipeline.registerHook("post-processing",async s=>{s.responseState.metadata||(s.responseState.metadata={});let t=s.responseState.metadata;if(!r)return;let i=Q(r,"post_script");if(!i||!M(i.body,i.language))return;let{executeHeadlessScript:o}=await Promise.resolve().then(()=>(D(),w)),l=s.requestState?.metadata?._cliVarsRef??{},d={...H(),...l},u=B(s.requestState),y=ve(s.responseState),p=await o(i.body,i.language,u,y,n,d);p.success&&p.modifiedResponse&&Se(p.modifiedResponse,s.responseState),p.modifiedVariables&&Object.assign(l,p.modifiedVariables),t.postScriptLogs=p.logs??[],t.postScriptAssertions=p.assertions??[],p.error&&(t.postScriptError=p.error),r=null},25),e.pipeline.registerHook("post-processing",s=>{let t=s.responseState;if(!t)return;t.metadata||(t.metadata={});let i=s.requestState?.metadata?.preScriptLogs??[],o=s.requestState?.metadata?.preScriptAssertions??[],l=t.metadata.postScriptLogs??[],d=t.metadata.postScriptAssertions??[],u=s.requestState?.metadata?.preScriptError,y=t.metadata.postScriptError,p={assertions:[...o,...d],error:y??u},m=[...i,...l];Ee(t.metadata,p,m)},60)}}),$e=be;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var f=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var a in e)f(o,a,{get:e[a],enumerable:!0})},w=(o,e,a,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of g(e))!h.call(o,s)&&s!==a&&f(o,s,{get:()=>e[s],enumerable:!(r=p(e,s))||r.enumerable});return o};var R=o=>w(f({},"__esModule",{value:!0}),o);var C={};m(C,{buildRequest:()=>y,default:()=>k});module.exports=R(C);function y(o){let e=o.find(t=>t.type==="socket-request");if(!e)return null;let a="";if(Array.isArray(e.content))for(let t of e.content)t.type==="surl"&&typeof t.content=="string"&&(a=t.content.trim());if(!a)return null;let r=a.toLowerCase(),s="ws";r.startsWith("wss://")?s="wss":r.startsWith("ws://")?s="ws":r.startsWith("grpcs://")?s="grpcs":r.startsWith("grpc://")&&(s="grpc");let l=o.find(t=>t.type==="headers-table"),d=[];if(l&&Array.isArray(l.content)){for(let t of l.content)if(t.type==="table"&&Array.isArray(t.rows))for(let c of t.rows)!c.attrs?.disabled&&Array.isArray(c.row)&&c.row[0]&&d.push({key:String(c.row[0]).trim(),value:String(c.row[1]??"").trim(),enabled:!0})}let u=e.content?.find?.(t=>t.type==="proto"),i={};if(u?.attrs){let t=u.attrs;t.protoFilePath&&(i.protoFilePath=t.protoFilePath),t.service&&(i.service=t.service),t.method&&(i.method=t.method),t.package&&(i.package=t.package),t.callType&&(i.callType=t.callType)}return{method:s.toUpperCase(),url:a,headers:d,queryParams:[],pathParams:[],grpc:Object.keys(i).length?i:void 0,metadata:{protocol:s}}}var b=o=>({onload(){o.onBuildRequest((e,a)=>y(a)??e),o.onProcessResponse(async e=>{let a=e?.metadata?.handoff;if(!a)return;let{protocol:r,url:s,headers:l,grpc:d,body:u}=a,i=Object.entries(l).map(([t,c])=>({key:t,value:c,enabled:!0}));if(r==="ws"||r==="wss"){let t=await o.protocols?.executeWebSocket({protocol:r,url:s,headers:i});if(!t)return;let c={connected:t.connected??!1,protocol:r,url:s,durationMs:t.durationMs,...t.error?{error:t.error}:{}},n=e;n.statusCode=t.connected?101:0,n.statusMessage=t.connected?"Switching Protocols":t.error??"Connection Failed",n.status=n.statusCode,n.statusText=n.statusMessage,e.body=JSON.stringify(c,null,2),e.metadata&&delete e.metadata.handoff}else if(r==="grpc"||r==="grpcs"){let t=await o.protocols?.executeGrpc({protocol:r,url:s,metadata:l,body:u,...d??{}});if(!t)return;let c={connected:t.connected??!1,protocol:r,url:s,durationMs:t.durationMs,...d?.service?{service:d.service}:{},...d?.method?{method:d.method}:{},...t.error?{error:t.error}:{}},n=e;n.statusCode=t.connected?200:0,n.statusMessage=t.connected?"Connected":t.error??"Connection Failed",n.status=n.statusCode,n.statusText=n.statusMessage,e.body=JSON.stringify(c,null,2),e.metadata&&delete e.metadata.handoff}})}}),k=b;0&&(module.exports={buildRequest});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File discovery — resolve CLI-style paths/globs and recursively find .void files.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from index.ts so the MCP server (and any other consumer) can list
|
|
5
|
+
* a project's .void files without duplicating this logic.
|
|
6
|
+
*/
|
|
7
|
+
/** Recursively collect all .void files under a directory. */
|
|
8
|
+
export declare function collectVoidFiles(inputPath: string): Promise<string[]>;
|
|
9
|
+
/** Expand a list of paths/globs into resolved .void file paths. */
|
|
10
|
+
export declare function resolveFiles(patterns: string[]): Promise<string[]>;
|
|
11
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,6DAA6D;AAC7D,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAwB3E;AAED,mEAAmE;AACnE,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBxE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File discovery — resolve CLI-style paths/globs and recursively find .void files.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from index.ts so the MCP server (and any other consumer) can list
|
|
5
|
+
* a project's .void files without duplicating this logic.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, statSync } from 'fs';
|
|
8
|
+
import { resolve } from 'path';
|
|
9
|
+
import { readdir } from 'fs/promises';
|
|
10
|
+
/** Recursively collect all .void files under a directory. */
|
|
11
|
+
export async function collectVoidFiles(inputPath) {
|
|
12
|
+
const abs = resolve(inputPath);
|
|
13
|
+
if (!existsSync(abs))
|
|
14
|
+
return [];
|
|
15
|
+
const stat = statSync(abs);
|
|
16
|
+
if (stat.isFile()) {
|
|
17
|
+
return abs.endsWith('.void') ? [abs] : [];
|
|
18
|
+
}
|
|
19
|
+
if (stat.isDirectory()) {
|
|
20
|
+
const entries = await readdir(abs, { withFileTypes: true });
|
|
21
|
+
const results = [];
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const full = resolve(abs, entry.name);
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
results.push(...(await collectVoidFiles(full)));
|
|
26
|
+
}
|
|
27
|
+
else if (entry.isFile() && entry.name.endsWith('.void')) {
|
|
28
|
+
results.push(full);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return results;
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
/** Expand a list of paths/globs into resolved .void file paths. */
|
|
36
|
+
export async function resolveFiles(patterns) {
|
|
37
|
+
const resolved = [];
|
|
38
|
+
for (const pattern of patterns) {
|
|
39
|
+
if (pattern.includes('*')) {
|
|
40
|
+
const dir = resolve(pattern.replace(/\/?\*.*$/, '') || '.');
|
|
41
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry.isFile() && entry.name.endsWith('.void')) {
|
|
44
|
+
resolved.push(resolve(dir, entry.name));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
resolved.push(...(await collectVoidFiles(pattern)));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return resolved;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAErC,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAE/B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAC1B,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC3C,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAa,EAAE,CAAA;QAC5B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACrC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjD,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,OAAO,EAAE,CAAA;AACX,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAkB;IACnD,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,CAAA;YAC3D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;YAC3D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACnD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;gBACzC,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACrD,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|