@easynet/agent-tool-buildin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/CoreAdapter.d.ts +37 -0
- package/dist/CoreAdapter.d.ts.map +1 -0
- package/dist/CoreToolsModule.d.ts +48 -0
- package/dist/CoreToolsModule.d.ts.map +1 -0
- package/dist/chunk-BUSYA2B4.js +9 -0
- package/dist/chunk-BUSYA2B4.js.map +1 -0
- package/dist/context.d.ts +9 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/exec/runCommand.d.ts +9 -0
- package/dist/exec/runCommand.d.ts.map +1 -0
- package/dist/fs/deletePath.d.ts +8 -0
- package/dist/fs/deletePath.d.ts.map +1 -0
- package/dist/fs/listDir.d.ts +8 -0
- package/dist/fs/listDir.d.ts.map +1 -0
- package/dist/fs/readText.d.ts +8 -0
- package/dist/fs/readText.d.ts.map +1 -0
- package/dist/fs/searchText.d.ts +8 -0
- package/dist/fs/searchText.d.ts.map +1 -0
- package/dist/fs/sha256.d.ts +8 -0
- package/dist/fs/sha256.d.ts.map +1 -0
- package/dist/fs/writeText.d.ts +8 -0
- package/dist/fs/writeText.d.ts.map +1 -0
- package/dist/http/downloadFile.d.ts +8 -0
- package/dist/http/downloadFile.d.ts.map +1 -0
- package/dist/http/duckduckgoSearch.d.ts +9 -0
- package/dist/http/duckduckgoSearch.d.ts.map +1 -0
- package/dist/http/fetchJson.d.ts +8 -0
- package/dist/http/fetchJson.d.ts.map +1 -0
- package/dist/http/fetchPageMainContent.d.ts +9 -0
- package/dist/http/fetchPageMainContent.d.ts.map +1 -0
- package/dist/http/fetchText.d.ts +8 -0
- package/dist/http/fetchText.d.ts.map +1 -0
- package/dist/http/head.d.ts +8 -0
- package/dist/http/head.d.ts.map +1 -0
- package/dist/index.cjs +3840 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1791 -0
- package/dist/index.js.map +1 -0
- package/dist/jmespath-6W7SK7AH.js +1514 -0
- package/dist/jmespath-6W7SK7AH.js.map +1 -0
- package/dist/mustache-CS7KHA4H.js +467 -0
- package/dist/mustache-CS7KHA4H.js.map +1 -0
- package/dist/security/sandbox.d.ts +9 -0
- package/dist/security/sandbox.d.ts.map +1 -0
- package/dist/security/ssrf.d.ts +12 -0
- package/dist/security/ssrf.d.ts.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/util/hashText.d.ts +8 -0
- package/dist/util/hashText.d.ts.map +1 -0
- package/dist/util/jsonSelect.d.ts +8 -0
- package/dist/util/jsonSelect.d.ts.map +1 -0
- package/dist/util/now.d.ts +8 -0
- package/dist/util/now.d.ts.map +1 -0
- package/dist/util/templateRender.d.ts +8 -0
- package/dist/util/templateRender.d.ts.map +1 -0
- package/dist/util/truncate.d.ts +8 -0
- package/dist/util/truncate.d.ts.map +1 -0
- package/package.json +48 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3840 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
};
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
27
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
28
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
29
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
30
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
31
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
32
|
+
mod
|
|
33
|
+
));
|
|
34
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
|
+
|
|
36
|
+
// node_modules/jmespath/jmespath.js
|
|
37
|
+
var require_jmespath = __commonJS({
|
|
38
|
+
"node_modules/jmespath/jmespath.js"(exports2) {
|
|
39
|
+
"use strict";
|
|
40
|
+
(function(exports3) {
|
|
41
|
+
"use strict";
|
|
42
|
+
function isArray2(obj) {
|
|
43
|
+
if (obj !== null) {
|
|
44
|
+
return Object.prototype.toString.call(obj) === "[object Array]";
|
|
45
|
+
} else {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function isObject(obj) {
|
|
50
|
+
if (obj !== null) {
|
|
51
|
+
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
52
|
+
} else {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function strictDeepEqual(first, second) {
|
|
57
|
+
if (first === second) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
var firstType = Object.prototype.toString.call(first);
|
|
61
|
+
if (firstType !== Object.prototype.toString.call(second)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
if (isArray2(first) === true) {
|
|
65
|
+
if (first.length !== second.length) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
for (var i = 0; i < first.length; i++) {
|
|
69
|
+
if (strictDeepEqual(first[i], second[i]) === false) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (isObject(first) === true) {
|
|
76
|
+
var keysSeen = {};
|
|
77
|
+
for (var key in first) {
|
|
78
|
+
if (hasOwnProperty.call(first, key)) {
|
|
79
|
+
if (strictDeepEqual(first[key], second[key]) === false) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
keysSeen[key] = true;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (var key2 in second) {
|
|
86
|
+
if (hasOwnProperty.call(second, key2)) {
|
|
87
|
+
if (keysSeen[key2] !== true) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
function isFalse(obj) {
|
|
97
|
+
if (obj === "" || obj === false || obj === null) {
|
|
98
|
+
return true;
|
|
99
|
+
} else if (isArray2(obj) && obj.length === 0) {
|
|
100
|
+
return true;
|
|
101
|
+
} else if (isObject(obj)) {
|
|
102
|
+
for (var key in obj) {
|
|
103
|
+
if (obj.hasOwnProperty(key)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
} else {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function objValues(obj) {
|
|
113
|
+
var keys = Object.keys(obj);
|
|
114
|
+
var values = [];
|
|
115
|
+
for (var i = 0; i < keys.length; i++) {
|
|
116
|
+
values.push(obj[keys[i]]);
|
|
117
|
+
}
|
|
118
|
+
return values;
|
|
119
|
+
}
|
|
120
|
+
function merge(a, b) {
|
|
121
|
+
var merged = {};
|
|
122
|
+
for (var key in a) {
|
|
123
|
+
merged[key] = a[key];
|
|
124
|
+
}
|
|
125
|
+
for (var key2 in b) {
|
|
126
|
+
merged[key2] = b[key2];
|
|
127
|
+
}
|
|
128
|
+
return merged;
|
|
129
|
+
}
|
|
130
|
+
var trimLeft;
|
|
131
|
+
if (typeof String.prototype.trimLeft === "function") {
|
|
132
|
+
trimLeft = function(str) {
|
|
133
|
+
return str.trimLeft();
|
|
134
|
+
};
|
|
135
|
+
} else {
|
|
136
|
+
trimLeft = function(str) {
|
|
137
|
+
return str.match(/^\s*(.*)/)[1];
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
var TYPE_NUMBER = 0;
|
|
141
|
+
var TYPE_ANY = 1;
|
|
142
|
+
var TYPE_STRING = 2;
|
|
143
|
+
var TYPE_ARRAY = 3;
|
|
144
|
+
var TYPE_OBJECT = 4;
|
|
145
|
+
var TYPE_BOOLEAN = 5;
|
|
146
|
+
var TYPE_EXPREF = 6;
|
|
147
|
+
var TYPE_NULL = 7;
|
|
148
|
+
var TYPE_ARRAY_NUMBER = 8;
|
|
149
|
+
var TYPE_ARRAY_STRING = 9;
|
|
150
|
+
var TYPE_NAME_TABLE = {
|
|
151
|
+
0: "number",
|
|
152
|
+
1: "any",
|
|
153
|
+
2: "string",
|
|
154
|
+
3: "array",
|
|
155
|
+
4: "object",
|
|
156
|
+
5: "boolean",
|
|
157
|
+
6: "expression",
|
|
158
|
+
7: "null",
|
|
159
|
+
8: "Array<number>",
|
|
160
|
+
9: "Array<string>"
|
|
161
|
+
};
|
|
162
|
+
var TOK_EOF = "EOF";
|
|
163
|
+
var TOK_UNQUOTEDIDENTIFIER = "UnquotedIdentifier";
|
|
164
|
+
var TOK_QUOTEDIDENTIFIER = "QuotedIdentifier";
|
|
165
|
+
var TOK_RBRACKET = "Rbracket";
|
|
166
|
+
var TOK_RPAREN = "Rparen";
|
|
167
|
+
var TOK_COMMA = "Comma";
|
|
168
|
+
var TOK_COLON = "Colon";
|
|
169
|
+
var TOK_RBRACE = "Rbrace";
|
|
170
|
+
var TOK_NUMBER = "Number";
|
|
171
|
+
var TOK_CURRENT = "Current";
|
|
172
|
+
var TOK_EXPREF = "Expref";
|
|
173
|
+
var TOK_PIPE = "Pipe";
|
|
174
|
+
var TOK_OR = "Or";
|
|
175
|
+
var TOK_AND = "And";
|
|
176
|
+
var TOK_EQ = "EQ";
|
|
177
|
+
var TOK_GT = "GT";
|
|
178
|
+
var TOK_LT = "LT";
|
|
179
|
+
var TOK_GTE = "GTE";
|
|
180
|
+
var TOK_LTE = "LTE";
|
|
181
|
+
var TOK_NE = "NE";
|
|
182
|
+
var TOK_FLATTEN = "Flatten";
|
|
183
|
+
var TOK_STAR = "Star";
|
|
184
|
+
var TOK_FILTER = "Filter";
|
|
185
|
+
var TOK_DOT = "Dot";
|
|
186
|
+
var TOK_NOT = "Not";
|
|
187
|
+
var TOK_LBRACE = "Lbrace";
|
|
188
|
+
var TOK_LBRACKET = "Lbracket";
|
|
189
|
+
var TOK_LPAREN = "Lparen";
|
|
190
|
+
var TOK_LITERAL = "Literal";
|
|
191
|
+
var basicTokens = {
|
|
192
|
+
".": TOK_DOT,
|
|
193
|
+
"*": TOK_STAR,
|
|
194
|
+
",": TOK_COMMA,
|
|
195
|
+
":": TOK_COLON,
|
|
196
|
+
"{": TOK_LBRACE,
|
|
197
|
+
"}": TOK_RBRACE,
|
|
198
|
+
"]": TOK_RBRACKET,
|
|
199
|
+
"(": TOK_LPAREN,
|
|
200
|
+
")": TOK_RPAREN,
|
|
201
|
+
"@": TOK_CURRENT
|
|
202
|
+
};
|
|
203
|
+
var operatorStartToken = {
|
|
204
|
+
"<": true,
|
|
205
|
+
">": true,
|
|
206
|
+
"=": true,
|
|
207
|
+
"!": true
|
|
208
|
+
};
|
|
209
|
+
var skipChars = {
|
|
210
|
+
" ": true,
|
|
211
|
+
" ": true,
|
|
212
|
+
"\n": true
|
|
213
|
+
};
|
|
214
|
+
function isAlpha(ch) {
|
|
215
|
+
return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch === "_";
|
|
216
|
+
}
|
|
217
|
+
function isNum(ch) {
|
|
218
|
+
return ch >= "0" && ch <= "9" || ch === "-";
|
|
219
|
+
}
|
|
220
|
+
function isAlphaNum(ch) {
|
|
221
|
+
return ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch >= "0" && ch <= "9" || ch === "_";
|
|
222
|
+
}
|
|
223
|
+
function Lexer() {
|
|
224
|
+
}
|
|
225
|
+
Lexer.prototype = {
|
|
226
|
+
tokenize: function(stream) {
|
|
227
|
+
var tokens = [];
|
|
228
|
+
this._current = 0;
|
|
229
|
+
var start;
|
|
230
|
+
var identifier;
|
|
231
|
+
var token;
|
|
232
|
+
while (this._current < stream.length) {
|
|
233
|
+
if (isAlpha(stream[this._current])) {
|
|
234
|
+
start = this._current;
|
|
235
|
+
identifier = this._consumeUnquotedIdentifier(stream);
|
|
236
|
+
tokens.push({
|
|
237
|
+
type: TOK_UNQUOTEDIDENTIFIER,
|
|
238
|
+
value: identifier,
|
|
239
|
+
start
|
|
240
|
+
});
|
|
241
|
+
} else if (basicTokens[stream[this._current]] !== void 0) {
|
|
242
|
+
tokens.push({
|
|
243
|
+
type: basicTokens[stream[this._current]],
|
|
244
|
+
value: stream[this._current],
|
|
245
|
+
start: this._current
|
|
246
|
+
});
|
|
247
|
+
this._current++;
|
|
248
|
+
} else if (isNum(stream[this._current])) {
|
|
249
|
+
token = this._consumeNumber(stream);
|
|
250
|
+
tokens.push(token);
|
|
251
|
+
} else if (stream[this._current] === "[") {
|
|
252
|
+
token = this._consumeLBracket(stream);
|
|
253
|
+
tokens.push(token);
|
|
254
|
+
} else if (stream[this._current] === '"') {
|
|
255
|
+
start = this._current;
|
|
256
|
+
identifier = this._consumeQuotedIdentifier(stream);
|
|
257
|
+
tokens.push({
|
|
258
|
+
type: TOK_QUOTEDIDENTIFIER,
|
|
259
|
+
value: identifier,
|
|
260
|
+
start
|
|
261
|
+
});
|
|
262
|
+
} else if (stream[this._current] === "'") {
|
|
263
|
+
start = this._current;
|
|
264
|
+
identifier = this._consumeRawStringLiteral(stream);
|
|
265
|
+
tokens.push({
|
|
266
|
+
type: TOK_LITERAL,
|
|
267
|
+
value: identifier,
|
|
268
|
+
start
|
|
269
|
+
});
|
|
270
|
+
} else if (stream[this._current] === "`") {
|
|
271
|
+
start = this._current;
|
|
272
|
+
var literal = this._consumeLiteral(stream);
|
|
273
|
+
tokens.push({
|
|
274
|
+
type: TOK_LITERAL,
|
|
275
|
+
value: literal,
|
|
276
|
+
start
|
|
277
|
+
});
|
|
278
|
+
} else if (operatorStartToken[stream[this._current]] !== void 0) {
|
|
279
|
+
tokens.push(this._consumeOperator(stream));
|
|
280
|
+
} else if (skipChars[stream[this._current]] !== void 0) {
|
|
281
|
+
this._current++;
|
|
282
|
+
} else if (stream[this._current] === "&") {
|
|
283
|
+
start = this._current;
|
|
284
|
+
this._current++;
|
|
285
|
+
if (stream[this._current] === "&") {
|
|
286
|
+
this._current++;
|
|
287
|
+
tokens.push({ type: TOK_AND, value: "&&", start });
|
|
288
|
+
} else {
|
|
289
|
+
tokens.push({ type: TOK_EXPREF, value: "&", start });
|
|
290
|
+
}
|
|
291
|
+
} else if (stream[this._current] === "|") {
|
|
292
|
+
start = this._current;
|
|
293
|
+
this._current++;
|
|
294
|
+
if (stream[this._current] === "|") {
|
|
295
|
+
this._current++;
|
|
296
|
+
tokens.push({ type: TOK_OR, value: "||", start });
|
|
297
|
+
} else {
|
|
298
|
+
tokens.push({ type: TOK_PIPE, value: "|", start });
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
var error = new Error("Unknown character:" + stream[this._current]);
|
|
302
|
+
error.name = "LexerError";
|
|
303
|
+
throw error;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return tokens;
|
|
307
|
+
},
|
|
308
|
+
_consumeUnquotedIdentifier: function(stream) {
|
|
309
|
+
var start = this._current;
|
|
310
|
+
this._current++;
|
|
311
|
+
while (this._current < stream.length && isAlphaNum(stream[this._current])) {
|
|
312
|
+
this._current++;
|
|
313
|
+
}
|
|
314
|
+
return stream.slice(start, this._current);
|
|
315
|
+
},
|
|
316
|
+
_consumeQuotedIdentifier: function(stream) {
|
|
317
|
+
var start = this._current;
|
|
318
|
+
this._current++;
|
|
319
|
+
var maxLength = stream.length;
|
|
320
|
+
while (stream[this._current] !== '"' && this._current < maxLength) {
|
|
321
|
+
var current = this._current;
|
|
322
|
+
if (stream[current] === "\\" && (stream[current + 1] === "\\" || stream[current + 1] === '"')) {
|
|
323
|
+
current += 2;
|
|
324
|
+
} else {
|
|
325
|
+
current++;
|
|
326
|
+
}
|
|
327
|
+
this._current = current;
|
|
328
|
+
}
|
|
329
|
+
this._current++;
|
|
330
|
+
return JSON.parse(stream.slice(start, this._current));
|
|
331
|
+
},
|
|
332
|
+
_consumeRawStringLiteral: function(stream) {
|
|
333
|
+
var start = this._current;
|
|
334
|
+
this._current++;
|
|
335
|
+
var maxLength = stream.length;
|
|
336
|
+
while (stream[this._current] !== "'" && this._current < maxLength) {
|
|
337
|
+
var current = this._current;
|
|
338
|
+
if (stream[current] === "\\" && (stream[current + 1] === "\\" || stream[current + 1] === "'")) {
|
|
339
|
+
current += 2;
|
|
340
|
+
} else {
|
|
341
|
+
current++;
|
|
342
|
+
}
|
|
343
|
+
this._current = current;
|
|
344
|
+
}
|
|
345
|
+
this._current++;
|
|
346
|
+
var literal = stream.slice(start + 1, this._current - 1);
|
|
347
|
+
return literal.replace("\\'", "'");
|
|
348
|
+
},
|
|
349
|
+
_consumeNumber: function(stream) {
|
|
350
|
+
var start = this._current;
|
|
351
|
+
this._current++;
|
|
352
|
+
var maxLength = stream.length;
|
|
353
|
+
while (isNum(stream[this._current]) && this._current < maxLength) {
|
|
354
|
+
this._current++;
|
|
355
|
+
}
|
|
356
|
+
var value = parseInt(stream.slice(start, this._current));
|
|
357
|
+
return { type: TOK_NUMBER, value, start };
|
|
358
|
+
},
|
|
359
|
+
_consumeLBracket: function(stream) {
|
|
360
|
+
var start = this._current;
|
|
361
|
+
this._current++;
|
|
362
|
+
if (stream[this._current] === "?") {
|
|
363
|
+
this._current++;
|
|
364
|
+
return { type: TOK_FILTER, value: "[?", start };
|
|
365
|
+
} else if (stream[this._current] === "]") {
|
|
366
|
+
this._current++;
|
|
367
|
+
return { type: TOK_FLATTEN, value: "[]", start };
|
|
368
|
+
} else {
|
|
369
|
+
return { type: TOK_LBRACKET, value: "[", start };
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
_consumeOperator: function(stream) {
|
|
373
|
+
var start = this._current;
|
|
374
|
+
var startingChar = stream[start];
|
|
375
|
+
this._current++;
|
|
376
|
+
if (startingChar === "!") {
|
|
377
|
+
if (stream[this._current] === "=") {
|
|
378
|
+
this._current++;
|
|
379
|
+
return { type: TOK_NE, value: "!=", start };
|
|
380
|
+
} else {
|
|
381
|
+
return { type: TOK_NOT, value: "!", start };
|
|
382
|
+
}
|
|
383
|
+
} else if (startingChar === "<") {
|
|
384
|
+
if (stream[this._current] === "=") {
|
|
385
|
+
this._current++;
|
|
386
|
+
return { type: TOK_LTE, value: "<=", start };
|
|
387
|
+
} else {
|
|
388
|
+
return { type: TOK_LT, value: "<", start };
|
|
389
|
+
}
|
|
390
|
+
} else if (startingChar === ">") {
|
|
391
|
+
if (stream[this._current] === "=") {
|
|
392
|
+
this._current++;
|
|
393
|
+
return { type: TOK_GTE, value: ">=", start };
|
|
394
|
+
} else {
|
|
395
|
+
return { type: TOK_GT, value: ">", start };
|
|
396
|
+
}
|
|
397
|
+
} else if (startingChar === "=") {
|
|
398
|
+
if (stream[this._current] === "=") {
|
|
399
|
+
this._current++;
|
|
400
|
+
return { type: TOK_EQ, value: "==", start };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
},
|
|
404
|
+
_consumeLiteral: function(stream) {
|
|
405
|
+
this._current++;
|
|
406
|
+
var start = this._current;
|
|
407
|
+
var maxLength = stream.length;
|
|
408
|
+
var literal;
|
|
409
|
+
while (stream[this._current] !== "`" && this._current < maxLength) {
|
|
410
|
+
var current = this._current;
|
|
411
|
+
if (stream[current] === "\\" && (stream[current + 1] === "\\" || stream[current + 1] === "`")) {
|
|
412
|
+
current += 2;
|
|
413
|
+
} else {
|
|
414
|
+
current++;
|
|
415
|
+
}
|
|
416
|
+
this._current = current;
|
|
417
|
+
}
|
|
418
|
+
var literalString = trimLeft(stream.slice(start, this._current));
|
|
419
|
+
literalString = literalString.replace("\\`", "`");
|
|
420
|
+
if (this._looksLikeJSON(literalString)) {
|
|
421
|
+
literal = JSON.parse(literalString);
|
|
422
|
+
} else {
|
|
423
|
+
literal = JSON.parse('"' + literalString + '"');
|
|
424
|
+
}
|
|
425
|
+
this._current++;
|
|
426
|
+
return literal;
|
|
427
|
+
},
|
|
428
|
+
_looksLikeJSON: function(literalString) {
|
|
429
|
+
var startingChars = '[{"';
|
|
430
|
+
var jsonLiterals = ["true", "false", "null"];
|
|
431
|
+
var numberLooking = "-0123456789";
|
|
432
|
+
if (literalString === "") {
|
|
433
|
+
return false;
|
|
434
|
+
} else if (startingChars.indexOf(literalString[0]) >= 0) {
|
|
435
|
+
return true;
|
|
436
|
+
} else if (jsonLiterals.indexOf(literalString) >= 0) {
|
|
437
|
+
return true;
|
|
438
|
+
} else if (numberLooking.indexOf(literalString[0]) >= 0) {
|
|
439
|
+
try {
|
|
440
|
+
JSON.parse(literalString);
|
|
441
|
+
return true;
|
|
442
|
+
} catch (ex) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
var bindingPower = {};
|
|
451
|
+
bindingPower[TOK_EOF] = 0;
|
|
452
|
+
bindingPower[TOK_UNQUOTEDIDENTIFIER] = 0;
|
|
453
|
+
bindingPower[TOK_QUOTEDIDENTIFIER] = 0;
|
|
454
|
+
bindingPower[TOK_RBRACKET] = 0;
|
|
455
|
+
bindingPower[TOK_RPAREN] = 0;
|
|
456
|
+
bindingPower[TOK_COMMA] = 0;
|
|
457
|
+
bindingPower[TOK_RBRACE] = 0;
|
|
458
|
+
bindingPower[TOK_NUMBER] = 0;
|
|
459
|
+
bindingPower[TOK_CURRENT] = 0;
|
|
460
|
+
bindingPower[TOK_EXPREF] = 0;
|
|
461
|
+
bindingPower[TOK_PIPE] = 1;
|
|
462
|
+
bindingPower[TOK_OR] = 2;
|
|
463
|
+
bindingPower[TOK_AND] = 3;
|
|
464
|
+
bindingPower[TOK_EQ] = 5;
|
|
465
|
+
bindingPower[TOK_GT] = 5;
|
|
466
|
+
bindingPower[TOK_LT] = 5;
|
|
467
|
+
bindingPower[TOK_GTE] = 5;
|
|
468
|
+
bindingPower[TOK_LTE] = 5;
|
|
469
|
+
bindingPower[TOK_NE] = 5;
|
|
470
|
+
bindingPower[TOK_FLATTEN] = 9;
|
|
471
|
+
bindingPower[TOK_STAR] = 20;
|
|
472
|
+
bindingPower[TOK_FILTER] = 21;
|
|
473
|
+
bindingPower[TOK_DOT] = 40;
|
|
474
|
+
bindingPower[TOK_NOT] = 45;
|
|
475
|
+
bindingPower[TOK_LBRACE] = 50;
|
|
476
|
+
bindingPower[TOK_LBRACKET] = 55;
|
|
477
|
+
bindingPower[TOK_LPAREN] = 60;
|
|
478
|
+
function Parser() {
|
|
479
|
+
}
|
|
480
|
+
Parser.prototype = {
|
|
481
|
+
parse: function(expression) {
|
|
482
|
+
this._loadTokens(expression);
|
|
483
|
+
this.index = 0;
|
|
484
|
+
var ast = this.expression(0);
|
|
485
|
+
if (this._lookahead(0) !== TOK_EOF) {
|
|
486
|
+
var t = this._lookaheadToken(0);
|
|
487
|
+
var error = new Error(
|
|
488
|
+
"Unexpected token type: " + t.type + ", value: " + t.value
|
|
489
|
+
);
|
|
490
|
+
error.name = "ParserError";
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
return ast;
|
|
494
|
+
},
|
|
495
|
+
_loadTokens: function(expression) {
|
|
496
|
+
var lexer = new Lexer();
|
|
497
|
+
var tokens = lexer.tokenize(expression);
|
|
498
|
+
tokens.push({ type: TOK_EOF, value: "", start: expression.length });
|
|
499
|
+
this.tokens = tokens;
|
|
500
|
+
},
|
|
501
|
+
expression: function(rbp) {
|
|
502
|
+
var leftToken = this._lookaheadToken(0);
|
|
503
|
+
this._advance();
|
|
504
|
+
var left = this.nud(leftToken);
|
|
505
|
+
var currentToken = this._lookahead(0);
|
|
506
|
+
while (rbp < bindingPower[currentToken]) {
|
|
507
|
+
this._advance();
|
|
508
|
+
left = this.led(currentToken, left);
|
|
509
|
+
currentToken = this._lookahead(0);
|
|
510
|
+
}
|
|
511
|
+
return left;
|
|
512
|
+
},
|
|
513
|
+
_lookahead: function(number) {
|
|
514
|
+
return this.tokens[this.index + number].type;
|
|
515
|
+
},
|
|
516
|
+
_lookaheadToken: function(number) {
|
|
517
|
+
return this.tokens[this.index + number];
|
|
518
|
+
},
|
|
519
|
+
_advance: function() {
|
|
520
|
+
this.index++;
|
|
521
|
+
},
|
|
522
|
+
nud: function(token) {
|
|
523
|
+
var left;
|
|
524
|
+
var right;
|
|
525
|
+
var expression;
|
|
526
|
+
switch (token.type) {
|
|
527
|
+
case TOK_LITERAL:
|
|
528
|
+
return { type: "Literal", value: token.value };
|
|
529
|
+
case TOK_UNQUOTEDIDENTIFIER:
|
|
530
|
+
return { type: "Field", name: token.value };
|
|
531
|
+
case TOK_QUOTEDIDENTIFIER:
|
|
532
|
+
var node = { type: "Field", name: token.value };
|
|
533
|
+
if (this._lookahead(0) === TOK_LPAREN) {
|
|
534
|
+
throw new Error("Quoted identifier not allowed for function names.");
|
|
535
|
+
}
|
|
536
|
+
return node;
|
|
537
|
+
case TOK_NOT:
|
|
538
|
+
right = this.expression(bindingPower.Not);
|
|
539
|
+
return { type: "NotExpression", children: [right] };
|
|
540
|
+
case TOK_STAR:
|
|
541
|
+
left = { type: "Identity" };
|
|
542
|
+
right = null;
|
|
543
|
+
if (this._lookahead(0) === TOK_RBRACKET) {
|
|
544
|
+
right = { type: "Identity" };
|
|
545
|
+
} else {
|
|
546
|
+
right = this._parseProjectionRHS(bindingPower.Star);
|
|
547
|
+
}
|
|
548
|
+
return { type: "ValueProjection", children: [left, right] };
|
|
549
|
+
case TOK_FILTER:
|
|
550
|
+
return this.led(token.type, { type: "Identity" });
|
|
551
|
+
case TOK_LBRACE:
|
|
552
|
+
return this._parseMultiselectHash();
|
|
553
|
+
case TOK_FLATTEN:
|
|
554
|
+
left = { type: TOK_FLATTEN, children: [{ type: "Identity" }] };
|
|
555
|
+
right = this._parseProjectionRHS(bindingPower.Flatten);
|
|
556
|
+
return { type: "Projection", children: [left, right] };
|
|
557
|
+
case TOK_LBRACKET:
|
|
558
|
+
if (this._lookahead(0) === TOK_NUMBER || this._lookahead(0) === TOK_COLON) {
|
|
559
|
+
right = this._parseIndexExpression();
|
|
560
|
+
return this._projectIfSlice({ type: "Identity" }, right);
|
|
561
|
+
} else if (this._lookahead(0) === TOK_STAR && this._lookahead(1) === TOK_RBRACKET) {
|
|
562
|
+
this._advance();
|
|
563
|
+
this._advance();
|
|
564
|
+
right = this._parseProjectionRHS(bindingPower.Star);
|
|
565
|
+
return {
|
|
566
|
+
type: "Projection",
|
|
567
|
+
children: [{ type: "Identity" }, right]
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
return this._parseMultiselectList();
|
|
571
|
+
case TOK_CURRENT:
|
|
572
|
+
return { type: TOK_CURRENT };
|
|
573
|
+
case TOK_EXPREF:
|
|
574
|
+
expression = this.expression(bindingPower.Expref);
|
|
575
|
+
return { type: "ExpressionReference", children: [expression] };
|
|
576
|
+
case TOK_LPAREN:
|
|
577
|
+
var args = [];
|
|
578
|
+
while (this._lookahead(0) !== TOK_RPAREN) {
|
|
579
|
+
if (this._lookahead(0) === TOK_CURRENT) {
|
|
580
|
+
expression = { type: TOK_CURRENT };
|
|
581
|
+
this._advance();
|
|
582
|
+
} else {
|
|
583
|
+
expression = this.expression(0);
|
|
584
|
+
}
|
|
585
|
+
args.push(expression);
|
|
586
|
+
}
|
|
587
|
+
this._match(TOK_RPAREN);
|
|
588
|
+
return args[0];
|
|
589
|
+
default:
|
|
590
|
+
this._errorToken(token);
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
led: function(tokenName, left) {
|
|
594
|
+
var right;
|
|
595
|
+
switch (tokenName) {
|
|
596
|
+
case TOK_DOT:
|
|
597
|
+
var rbp = bindingPower.Dot;
|
|
598
|
+
if (this._lookahead(0) !== TOK_STAR) {
|
|
599
|
+
right = this._parseDotRHS(rbp);
|
|
600
|
+
return { type: "Subexpression", children: [left, right] };
|
|
601
|
+
}
|
|
602
|
+
this._advance();
|
|
603
|
+
right = this._parseProjectionRHS(rbp);
|
|
604
|
+
return { type: "ValueProjection", children: [left, right] };
|
|
605
|
+
case TOK_PIPE:
|
|
606
|
+
right = this.expression(bindingPower.Pipe);
|
|
607
|
+
return { type: TOK_PIPE, children: [left, right] };
|
|
608
|
+
case TOK_OR:
|
|
609
|
+
right = this.expression(bindingPower.Or);
|
|
610
|
+
return { type: "OrExpression", children: [left, right] };
|
|
611
|
+
case TOK_AND:
|
|
612
|
+
right = this.expression(bindingPower.And);
|
|
613
|
+
return { type: "AndExpression", children: [left, right] };
|
|
614
|
+
case TOK_LPAREN:
|
|
615
|
+
var name = left.name;
|
|
616
|
+
var args = [];
|
|
617
|
+
var expression, node;
|
|
618
|
+
while (this._lookahead(0) !== TOK_RPAREN) {
|
|
619
|
+
if (this._lookahead(0) === TOK_CURRENT) {
|
|
620
|
+
expression = { type: TOK_CURRENT };
|
|
621
|
+
this._advance();
|
|
622
|
+
} else {
|
|
623
|
+
expression = this.expression(0);
|
|
624
|
+
}
|
|
625
|
+
if (this._lookahead(0) === TOK_COMMA) {
|
|
626
|
+
this._match(TOK_COMMA);
|
|
627
|
+
}
|
|
628
|
+
args.push(expression);
|
|
629
|
+
}
|
|
630
|
+
this._match(TOK_RPAREN);
|
|
631
|
+
node = { type: "Function", name, children: args };
|
|
632
|
+
return node;
|
|
633
|
+
case TOK_FILTER:
|
|
634
|
+
var condition = this.expression(0);
|
|
635
|
+
this._match(TOK_RBRACKET);
|
|
636
|
+
if (this._lookahead(0) === TOK_FLATTEN) {
|
|
637
|
+
right = { type: "Identity" };
|
|
638
|
+
} else {
|
|
639
|
+
right = this._parseProjectionRHS(bindingPower.Filter);
|
|
640
|
+
}
|
|
641
|
+
return { type: "FilterProjection", children: [left, right, condition] };
|
|
642
|
+
case TOK_FLATTEN:
|
|
643
|
+
var leftNode = { type: TOK_FLATTEN, children: [left] };
|
|
644
|
+
var rightNode = this._parseProjectionRHS(bindingPower.Flatten);
|
|
645
|
+
return { type: "Projection", children: [leftNode, rightNode] };
|
|
646
|
+
case TOK_EQ:
|
|
647
|
+
case TOK_NE:
|
|
648
|
+
case TOK_GT:
|
|
649
|
+
case TOK_GTE:
|
|
650
|
+
case TOK_LT:
|
|
651
|
+
case TOK_LTE:
|
|
652
|
+
return this._parseComparator(left, tokenName);
|
|
653
|
+
case TOK_LBRACKET:
|
|
654
|
+
var token = this._lookaheadToken(0);
|
|
655
|
+
if (token.type === TOK_NUMBER || token.type === TOK_COLON) {
|
|
656
|
+
right = this._parseIndexExpression();
|
|
657
|
+
return this._projectIfSlice(left, right);
|
|
658
|
+
}
|
|
659
|
+
this._match(TOK_STAR);
|
|
660
|
+
this._match(TOK_RBRACKET);
|
|
661
|
+
right = this._parseProjectionRHS(bindingPower.Star);
|
|
662
|
+
return { type: "Projection", children: [left, right] };
|
|
663
|
+
default:
|
|
664
|
+
this._errorToken(this._lookaheadToken(0));
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
_match: function(tokenType) {
|
|
668
|
+
if (this._lookahead(0) === tokenType) {
|
|
669
|
+
this._advance();
|
|
670
|
+
} else {
|
|
671
|
+
var t = this._lookaheadToken(0);
|
|
672
|
+
var error = new Error("Expected " + tokenType + ", got: " + t.type);
|
|
673
|
+
error.name = "ParserError";
|
|
674
|
+
throw error;
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
_errorToken: function(token) {
|
|
678
|
+
var error = new Error("Invalid token (" + token.type + '): "' + token.value + '"');
|
|
679
|
+
error.name = "ParserError";
|
|
680
|
+
throw error;
|
|
681
|
+
},
|
|
682
|
+
_parseIndexExpression: function() {
|
|
683
|
+
if (this._lookahead(0) === TOK_COLON || this._lookahead(1) === TOK_COLON) {
|
|
684
|
+
return this._parseSliceExpression();
|
|
685
|
+
} else {
|
|
686
|
+
var node = {
|
|
687
|
+
type: "Index",
|
|
688
|
+
value: this._lookaheadToken(0).value
|
|
689
|
+
};
|
|
690
|
+
this._advance();
|
|
691
|
+
this._match(TOK_RBRACKET);
|
|
692
|
+
return node;
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
_projectIfSlice: function(left, right) {
|
|
696
|
+
var indexExpr = { type: "IndexExpression", children: [left, right] };
|
|
697
|
+
if (right.type === "Slice") {
|
|
698
|
+
return {
|
|
699
|
+
type: "Projection",
|
|
700
|
+
children: [indexExpr, this._parseProjectionRHS(bindingPower.Star)]
|
|
701
|
+
};
|
|
702
|
+
} else {
|
|
703
|
+
return indexExpr;
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
_parseSliceExpression: function() {
|
|
707
|
+
var parts = [null, null, null];
|
|
708
|
+
var index = 0;
|
|
709
|
+
var currentToken = this._lookahead(0);
|
|
710
|
+
while (currentToken !== TOK_RBRACKET && index < 3) {
|
|
711
|
+
if (currentToken === TOK_COLON) {
|
|
712
|
+
index++;
|
|
713
|
+
this._advance();
|
|
714
|
+
} else if (currentToken === TOK_NUMBER) {
|
|
715
|
+
parts[index] = this._lookaheadToken(0).value;
|
|
716
|
+
this._advance();
|
|
717
|
+
} else {
|
|
718
|
+
var t = this._lookahead(0);
|
|
719
|
+
var error = new Error("Syntax error, unexpected token: " + t.value + "(" + t.type + ")");
|
|
720
|
+
error.name = "Parsererror";
|
|
721
|
+
throw error;
|
|
722
|
+
}
|
|
723
|
+
currentToken = this._lookahead(0);
|
|
724
|
+
}
|
|
725
|
+
this._match(TOK_RBRACKET);
|
|
726
|
+
return {
|
|
727
|
+
type: "Slice",
|
|
728
|
+
children: parts
|
|
729
|
+
};
|
|
730
|
+
},
|
|
731
|
+
_parseComparator: function(left, comparator) {
|
|
732
|
+
var right = this.expression(bindingPower[comparator]);
|
|
733
|
+
return { type: "Comparator", name: comparator, children: [left, right] };
|
|
734
|
+
},
|
|
735
|
+
_parseDotRHS: function(rbp) {
|
|
736
|
+
var lookahead = this._lookahead(0);
|
|
737
|
+
var exprTokens = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER, TOK_STAR];
|
|
738
|
+
if (exprTokens.indexOf(lookahead) >= 0) {
|
|
739
|
+
return this.expression(rbp);
|
|
740
|
+
} else if (lookahead === TOK_LBRACKET) {
|
|
741
|
+
this._match(TOK_LBRACKET);
|
|
742
|
+
return this._parseMultiselectList();
|
|
743
|
+
} else if (lookahead === TOK_LBRACE) {
|
|
744
|
+
this._match(TOK_LBRACE);
|
|
745
|
+
return this._parseMultiselectHash();
|
|
746
|
+
}
|
|
747
|
+
},
|
|
748
|
+
_parseProjectionRHS: function(rbp) {
|
|
749
|
+
var right;
|
|
750
|
+
if (bindingPower[this._lookahead(0)] < 10) {
|
|
751
|
+
right = { type: "Identity" };
|
|
752
|
+
} else if (this._lookahead(0) === TOK_LBRACKET) {
|
|
753
|
+
right = this.expression(rbp);
|
|
754
|
+
} else if (this._lookahead(0) === TOK_FILTER) {
|
|
755
|
+
right = this.expression(rbp);
|
|
756
|
+
} else if (this._lookahead(0) === TOK_DOT) {
|
|
757
|
+
this._match(TOK_DOT);
|
|
758
|
+
right = this._parseDotRHS(rbp);
|
|
759
|
+
} else {
|
|
760
|
+
var t = this._lookaheadToken(0);
|
|
761
|
+
var error = new Error("Sytanx error, unexpected token: " + t.value + "(" + t.type + ")");
|
|
762
|
+
error.name = "ParserError";
|
|
763
|
+
throw error;
|
|
764
|
+
}
|
|
765
|
+
return right;
|
|
766
|
+
},
|
|
767
|
+
_parseMultiselectList: function() {
|
|
768
|
+
var expressions = [];
|
|
769
|
+
while (this._lookahead(0) !== TOK_RBRACKET) {
|
|
770
|
+
var expression = this.expression(0);
|
|
771
|
+
expressions.push(expression);
|
|
772
|
+
if (this._lookahead(0) === TOK_COMMA) {
|
|
773
|
+
this._match(TOK_COMMA);
|
|
774
|
+
if (this._lookahead(0) === TOK_RBRACKET) {
|
|
775
|
+
throw new Error("Unexpected token Rbracket");
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
this._match(TOK_RBRACKET);
|
|
780
|
+
return { type: "MultiSelectList", children: expressions };
|
|
781
|
+
},
|
|
782
|
+
_parseMultiselectHash: function() {
|
|
783
|
+
var pairs = [];
|
|
784
|
+
var identifierTypes = [TOK_UNQUOTEDIDENTIFIER, TOK_QUOTEDIDENTIFIER];
|
|
785
|
+
var keyToken, keyName, value, node;
|
|
786
|
+
for (; ; ) {
|
|
787
|
+
keyToken = this._lookaheadToken(0);
|
|
788
|
+
if (identifierTypes.indexOf(keyToken.type) < 0) {
|
|
789
|
+
throw new Error("Expecting an identifier token, got: " + keyToken.type);
|
|
790
|
+
}
|
|
791
|
+
keyName = keyToken.value;
|
|
792
|
+
this._advance();
|
|
793
|
+
this._match(TOK_COLON);
|
|
794
|
+
value = this.expression(0);
|
|
795
|
+
node = { type: "KeyValuePair", name: keyName, value };
|
|
796
|
+
pairs.push(node);
|
|
797
|
+
if (this._lookahead(0) === TOK_COMMA) {
|
|
798
|
+
this._match(TOK_COMMA);
|
|
799
|
+
} else if (this._lookahead(0) === TOK_RBRACE) {
|
|
800
|
+
this._match(TOK_RBRACE);
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return { type: "MultiSelectHash", children: pairs };
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
function TreeInterpreter(runtime) {
|
|
808
|
+
this.runtime = runtime;
|
|
809
|
+
}
|
|
810
|
+
TreeInterpreter.prototype = {
|
|
811
|
+
search: function(node, value) {
|
|
812
|
+
return this.visit(node, value);
|
|
813
|
+
},
|
|
814
|
+
visit: function(node, value) {
|
|
815
|
+
var matched, current, result, first, second, field, left, right, collected, i;
|
|
816
|
+
switch (node.type) {
|
|
817
|
+
case "Field":
|
|
818
|
+
if (value !== null && isObject(value)) {
|
|
819
|
+
field = value[node.name];
|
|
820
|
+
if (field === void 0) {
|
|
821
|
+
return null;
|
|
822
|
+
} else {
|
|
823
|
+
return field;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return null;
|
|
827
|
+
case "Subexpression":
|
|
828
|
+
result = this.visit(node.children[0], value);
|
|
829
|
+
for (i = 1; i < node.children.length; i++) {
|
|
830
|
+
result = this.visit(node.children[1], result);
|
|
831
|
+
if (result === null) {
|
|
832
|
+
return null;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return result;
|
|
836
|
+
case "IndexExpression":
|
|
837
|
+
left = this.visit(node.children[0], value);
|
|
838
|
+
right = this.visit(node.children[1], left);
|
|
839
|
+
return right;
|
|
840
|
+
case "Index":
|
|
841
|
+
if (!isArray2(value)) {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
var index = node.value;
|
|
845
|
+
if (index < 0) {
|
|
846
|
+
index = value.length + index;
|
|
847
|
+
}
|
|
848
|
+
result = value[index];
|
|
849
|
+
if (result === void 0) {
|
|
850
|
+
result = null;
|
|
851
|
+
}
|
|
852
|
+
return result;
|
|
853
|
+
case "Slice":
|
|
854
|
+
if (!isArray2(value)) {
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
var sliceParams = node.children.slice(0);
|
|
858
|
+
var computed = this.computeSliceParams(value.length, sliceParams);
|
|
859
|
+
var start = computed[0];
|
|
860
|
+
var stop = computed[1];
|
|
861
|
+
var step = computed[2];
|
|
862
|
+
result = [];
|
|
863
|
+
if (step > 0) {
|
|
864
|
+
for (i = start; i < stop; i += step) {
|
|
865
|
+
result.push(value[i]);
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
for (i = start; i > stop; i += step) {
|
|
869
|
+
result.push(value[i]);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
return result;
|
|
873
|
+
case "Projection":
|
|
874
|
+
var base = this.visit(node.children[0], value);
|
|
875
|
+
if (!isArray2(base)) {
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
collected = [];
|
|
879
|
+
for (i = 0; i < base.length; i++) {
|
|
880
|
+
current = this.visit(node.children[1], base[i]);
|
|
881
|
+
if (current !== null) {
|
|
882
|
+
collected.push(current);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return collected;
|
|
886
|
+
case "ValueProjection":
|
|
887
|
+
base = this.visit(node.children[0], value);
|
|
888
|
+
if (!isObject(base)) {
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
collected = [];
|
|
892
|
+
var values = objValues(base);
|
|
893
|
+
for (i = 0; i < values.length; i++) {
|
|
894
|
+
current = this.visit(node.children[1], values[i]);
|
|
895
|
+
if (current !== null) {
|
|
896
|
+
collected.push(current);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
return collected;
|
|
900
|
+
case "FilterProjection":
|
|
901
|
+
base = this.visit(node.children[0], value);
|
|
902
|
+
if (!isArray2(base)) {
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
var filtered = [];
|
|
906
|
+
var finalResults = [];
|
|
907
|
+
for (i = 0; i < base.length; i++) {
|
|
908
|
+
matched = this.visit(node.children[2], base[i]);
|
|
909
|
+
if (!isFalse(matched)) {
|
|
910
|
+
filtered.push(base[i]);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
for (var j = 0; j < filtered.length; j++) {
|
|
914
|
+
current = this.visit(node.children[1], filtered[j]);
|
|
915
|
+
if (current !== null) {
|
|
916
|
+
finalResults.push(current);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
return finalResults;
|
|
920
|
+
case "Comparator":
|
|
921
|
+
first = this.visit(node.children[0], value);
|
|
922
|
+
second = this.visit(node.children[1], value);
|
|
923
|
+
switch (node.name) {
|
|
924
|
+
case TOK_EQ:
|
|
925
|
+
result = strictDeepEqual(first, second);
|
|
926
|
+
break;
|
|
927
|
+
case TOK_NE:
|
|
928
|
+
result = !strictDeepEqual(first, second);
|
|
929
|
+
break;
|
|
930
|
+
case TOK_GT:
|
|
931
|
+
result = first > second;
|
|
932
|
+
break;
|
|
933
|
+
case TOK_GTE:
|
|
934
|
+
result = first >= second;
|
|
935
|
+
break;
|
|
936
|
+
case TOK_LT:
|
|
937
|
+
result = first < second;
|
|
938
|
+
break;
|
|
939
|
+
case TOK_LTE:
|
|
940
|
+
result = first <= second;
|
|
941
|
+
break;
|
|
942
|
+
default:
|
|
943
|
+
throw new Error("Unknown comparator: " + node.name);
|
|
944
|
+
}
|
|
945
|
+
return result;
|
|
946
|
+
case TOK_FLATTEN:
|
|
947
|
+
var original = this.visit(node.children[0], value);
|
|
948
|
+
if (!isArray2(original)) {
|
|
949
|
+
return null;
|
|
950
|
+
}
|
|
951
|
+
var merged = [];
|
|
952
|
+
for (i = 0; i < original.length; i++) {
|
|
953
|
+
current = original[i];
|
|
954
|
+
if (isArray2(current)) {
|
|
955
|
+
merged.push.apply(merged, current);
|
|
956
|
+
} else {
|
|
957
|
+
merged.push(current);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
return merged;
|
|
961
|
+
case "Identity":
|
|
962
|
+
return value;
|
|
963
|
+
case "MultiSelectList":
|
|
964
|
+
if (value === null) {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
collected = [];
|
|
968
|
+
for (i = 0; i < node.children.length; i++) {
|
|
969
|
+
collected.push(this.visit(node.children[i], value));
|
|
970
|
+
}
|
|
971
|
+
return collected;
|
|
972
|
+
case "MultiSelectHash":
|
|
973
|
+
if (value === null) {
|
|
974
|
+
return null;
|
|
975
|
+
}
|
|
976
|
+
collected = {};
|
|
977
|
+
var child;
|
|
978
|
+
for (i = 0; i < node.children.length; i++) {
|
|
979
|
+
child = node.children[i];
|
|
980
|
+
collected[child.name] = this.visit(child.value, value);
|
|
981
|
+
}
|
|
982
|
+
return collected;
|
|
983
|
+
case "OrExpression":
|
|
984
|
+
matched = this.visit(node.children[0], value);
|
|
985
|
+
if (isFalse(matched)) {
|
|
986
|
+
matched = this.visit(node.children[1], value);
|
|
987
|
+
}
|
|
988
|
+
return matched;
|
|
989
|
+
case "AndExpression":
|
|
990
|
+
first = this.visit(node.children[0], value);
|
|
991
|
+
if (isFalse(first) === true) {
|
|
992
|
+
return first;
|
|
993
|
+
}
|
|
994
|
+
return this.visit(node.children[1], value);
|
|
995
|
+
case "NotExpression":
|
|
996
|
+
first = this.visit(node.children[0], value);
|
|
997
|
+
return isFalse(first);
|
|
998
|
+
case "Literal":
|
|
999
|
+
return node.value;
|
|
1000
|
+
case TOK_PIPE:
|
|
1001
|
+
left = this.visit(node.children[0], value);
|
|
1002
|
+
return this.visit(node.children[1], left);
|
|
1003
|
+
case TOK_CURRENT:
|
|
1004
|
+
return value;
|
|
1005
|
+
case "Function":
|
|
1006
|
+
var resolvedArgs = [];
|
|
1007
|
+
for (i = 0; i < node.children.length; i++) {
|
|
1008
|
+
resolvedArgs.push(this.visit(node.children[i], value));
|
|
1009
|
+
}
|
|
1010
|
+
return this.runtime.callFunction(node.name, resolvedArgs);
|
|
1011
|
+
case "ExpressionReference":
|
|
1012
|
+
var refNode = node.children[0];
|
|
1013
|
+
refNode.jmespathType = TOK_EXPREF;
|
|
1014
|
+
return refNode;
|
|
1015
|
+
default:
|
|
1016
|
+
throw new Error("Unknown node type: " + node.type);
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
computeSliceParams: function(arrayLength, sliceParams) {
|
|
1020
|
+
var start = sliceParams[0];
|
|
1021
|
+
var stop = sliceParams[1];
|
|
1022
|
+
var step = sliceParams[2];
|
|
1023
|
+
var computed = [null, null, null];
|
|
1024
|
+
if (step === null) {
|
|
1025
|
+
step = 1;
|
|
1026
|
+
} else if (step === 0) {
|
|
1027
|
+
var error = new Error("Invalid slice, step cannot be 0");
|
|
1028
|
+
error.name = "RuntimeError";
|
|
1029
|
+
throw error;
|
|
1030
|
+
}
|
|
1031
|
+
var stepValueNegative = step < 0 ? true : false;
|
|
1032
|
+
if (start === null) {
|
|
1033
|
+
start = stepValueNegative ? arrayLength - 1 : 0;
|
|
1034
|
+
} else {
|
|
1035
|
+
start = this.capSliceRange(arrayLength, start, step);
|
|
1036
|
+
}
|
|
1037
|
+
if (stop === null) {
|
|
1038
|
+
stop = stepValueNegative ? -1 : arrayLength;
|
|
1039
|
+
} else {
|
|
1040
|
+
stop = this.capSliceRange(arrayLength, stop, step);
|
|
1041
|
+
}
|
|
1042
|
+
computed[0] = start;
|
|
1043
|
+
computed[1] = stop;
|
|
1044
|
+
computed[2] = step;
|
|
1045
|
+
return computed;
|
|
1046
|
+
},
|
|
1047
|
+
capSliceRange: function(arrayLength, actualValue, step) {
|
|
1048
|
+
if (actualValue < 0) {
|
|
1049
|
+
actualValue += arrayLength;
|
|
1050
|
+
if (actualValue < 0) {
|
|
1051
|
+
actualValue = step < 0 ? -1 : 0;
|
|
1052
|
+
}
|
|
1053
|
+
} else if (actualValue >= arrayLength) {
|
|
1054
|
+
actualValue = step < 0 ? arrayLength - 1 : arrayLength;
|
|
1055
|
+
}
|
|
1056
|
+
return actualValue;
|
|
1057
|
+
}
|
|
1058
|
+
};
|
|
1059
|
+
function Runtime(interpreter) {
|
|
1060
|
+
this._interpreter = interpreter;
|
|
1061
|
+
this.functionTable = {
|
|
1062
|
+
// name: [function, <signature>]
|
|
1063
|
+
// The <signature> can be:
|
|
1064
|
+
//
|
|
1065
|
+
// {
|
|
1066
|
+
// args: [[type1, type2], [type1, type2]],
|
|
1067
|
+
// variadic: true|false
|
|
1068
|
+
// }
|
|
1069
|
+
//
|
|
1070
|
+
// Each arg in the arg list is a list of valid types
|
|
1071
|
+
// (if the function is overloaded and supports multiple
|
|
1072
|
+
// types. If the type is "any" then no type checking
|
|
1073
|
+
// occurs on the argument. Variadic is optional
|
|
1074
|
+
// and if not provided is assumed to be false.
|
|
1075
|
+
abs: { _func: this._functionAbs, _signature: [{ types: [TYPE_NUMBER] }] },
|
|
1076
|
+
avg: { _func: this._functionAvg, _signature: [{ types: [TYPE_ARRAY_NUMBER] }] },
|
|
1077
|
+
ceil: { _func: this._functionCeil, _signature: [{ types: [TYPE_NUMBER] }] },
|
|
1078
|
+
contains: {
|
|
1079
|
+
_func: this._functionContains,
|
|
1080
|
+
_signature: [
|
|
1081
|
+
{ types: [TYPE_STRING, TYPE_ARRAY] },
|
|
1082
|
+
{ types: [TYPE_ANY] }
|
|
1083
|
+
]
|
|
1084
|
+
},
|
|
1085
|
+
"ends_with": {
|
|
1086
|
+
_func: this._functionEndsWith,
|
|
1087
|
+
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }]
|
|
1088
|
+
},
|
|
1089
|
+
floor: { _func: this._functionFloor, _signature: [{ types: [TYPE_NUMBER] }] },
|
|
1090
|
+
length: {
|
|
1091
|
+
_func: this._functionLength,
|
|
1092
|
+
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY, TYPE_OBJECT] }]
|
|
1093
|
+
},
|
|
1094
|
+
map: {
|
|
1095
|
+
_func: this._functionMap,
|
|
1096
|
+
_signature: [{ types: [TYPE_EXPREF] }, { types: [TYPE_ARRAY] }]
|
|
1097
|
+
},
|
|
1098
|
+
max: {
|
|
1099
|
+
_func: this._functionMax,
|
|
1100
|
+
_signature: [{ types: [TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING] }]
|
|
1101
|
+
},
|
|
1102
|
+
"merge": {
|
|
1103
|
+
_func: this._functionMerge,
|
|
1104
|
+
_signature: [{ types: [TYPE_OBJECT], variadic: true }]
|
|
1105
|
+
},
|
|
1106
|
+
"max_by": {
|
|
1107
|
+
_func: this._functionMaxBy,
|
|
1108
|
+
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }]
|
|
1109
|
+
},
|
|
1110
|
+
sum: { _func: this._functionSum, _signature: [{ types: [TYPE_ARRAY_NUMBER] }] },
|
|
1111
|
+
"starts_with": {
|
|
1112
|
+
_func: this._functionStartsWith,
|
|
1113
|
+
_signature: [{ types: [TYPE_STRING] }, { types: [TYPE_STRING] }]
|
|
1114
|
+
},
|
|
1115
|
+
min: {
|
|
1116
|
+
_func: this._functionMin,
|
|
1117
|
+
_signature: [{ types: [TYPE_ARRAY_NUMBER, TYPE_ARRAY_STRING] }]
|
|
1118
|
+
},
|
|
1119
|
+
"min_by": {
|
|
1120
|
+
_func: this._functionMinBy,
|
|
1121
|
+
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }]
|
|
1122
|
+
},
|
|
1123
|
+
type: { _func: this._functionType, _signature: [{ types: [TYPE_ANY] }] },
|
|
1124
|
+
keys: { _func: this._functionKeys, _signature: [{ types: [TYPE_OBJECT] }] },
|
|
1125
|
+
values: { _func: this._functionValues, _signature: [{ types: [TYPE_OBJECT] }] },
|
|
1126
|
+
sort: { _func: this._functionSort, _signature: [{ types: [TYPE_ARRAY_STRING, TYPE_ARRAY_NUMBER] }] },
|
|
1127
|
+
"sort_by": {
|
|
1128
|
+
_func: this._functionSortBy,
|
|
1129
|
+
_signature: [{ types: [TYPE_ARRAY] }, { types: [TYPE_EXPREF] }]
|
|
1130
|
+
},
|
|
1131
|
+
join: {
|
|
1132
|
+
_func: this._functionJoin,
|
|
1133
|
+
_signature: [
|
|
1134
|
+
{ types: [TYPE_STRING] },
|
|
1135
|
+
{ types: [TYPE_ARRAY_STRING] }
|
|
1136
|
+
]
|
|
1137
|
+
},
|
|
1138
|
+
reverse: {
|
|
1139
|
+
_func: this._functionReverse,
|
|
1140
|
+
_signature: [{ types: [TYPE_STRING, TYPE_ARRAY] }]
|
|
1141
|
+
},
|
|
1142
|
+
"to_array": { _func: this._functionToArray, _signature: [{ types: [TYPE_ANY] }] },
|
|
1143
|
+
"to_string": { _func: this._functionToString, _signature: [{ types: [TYPE_ANY] }] },
|
|
1144
|
+
"to_number": { _func: this._functionToNumber, _signature: [{ types: [TYPE_ANY] }] },
|
|
1145
|
+
"not_null": {
|
|
1146
|
+
_func: this._functionNotNull,
|
|
1147
|
+
_signature: [{ types: [TYPE_ANY], variadic: true }]
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
Runtime.prototype = {
|
|
1152
|
+
callFunction: function(name, resolvedArgs) {
|
|
1153
|
+
var functionEntry = this.functionTable[name];
|
|
1154
|
+
if (functionEntry === void 0) {
|
|
1155
|
+
throw new Error("Unknown function: " + name + "()");
|
|
1156
|
+
}
|
|
1157
|
+
this._validateArgs(name, resolvedArgs, functionEntry._signature);
|
|
1158
|
+
return functionEntry._func.call(this, resolvedArgs);
|
|
1159
|
+
},
|
|
1160
|
+
_validateArgs: function(name, args, signature) {
|
|
1161
|
+
var pluralized;
|
|
1162
|
+
if (signature[signature.length - 1].variadic) {
|
|
1163
|
+
if (args.length < signature.length) {
|
|
1164
|
+
pluralized = signature.length === 1 ? " argument" : " arguments";
|
|
1165
|
+
throw new Error("ArgumentError: " + name + "() takes at least" + signature.length + pluralized + " but received " + args.length);
|
|
1166
|
+
}
|
|
1167
|
+
} else if (args.length !== signature.length) {
|
|
1168
|
+
pluralized = signature.length === 1 ? " argument" : " arguments";
|
|
1169
|
+
throw new Error("ArgumentError: " + name + "() takes " + signature.length + pluralized + " but received " + args.length);
|
|
1170
|
+
}
|
|
1171
|
+
var currentSpec;
|
|
1172
|
+
var actualType;
|
|
1173
|
+
var typeMatched;
|
|
1174
|
+
for (var i = 0; i < signature.length; i++) {
|
|
1175
|
+
typeMatched = false;
|
|
1176
|
+
currentSpec = signature[i].types;
|
|
1177
|
+
actualType = this._getTypeName(args[i]);
|
|
1178
|
+
for (var j = 0; j < currentSpec.length; j++) {
|
|
1179
|
+
if (this._typeMatches(actualType, currentSpec[j], args[i])) {
|
|
1180
|
+
typeMatched = true;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
if (!typeMatched) {
|
|
1185
|
+
var expected = currentSpec.map(function(typeIdentifier) {
|
|
1186
|
+
return TYPE_NAME_TABLE[typeIdentifier];
|
|
1187
|
+
}).join(",");
|
|
1188
|
+
throw new Error("TypeError: " + name + "() expected argument " + (i + 1) + " to be type " + expected + " but received type " + TYPE_NAME_TABLE[actualType] + " instead.");
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
},
|
|
1192
|
+
_typeMatches: function(actual, expected, argValue) {
|
|
1193
|
+
if (expected === TYPE_ANY) {
|
|
1194
|
+
return true;
|
|
1195
|
+
}
|
|
1196
|
+
if (expected === TYPE_ARRAY_STRING || expected === TYPE_ARRAY_NUMBER || expected === TYPE_ARRAY) {
|
|
1197
|
+
if (expected === TYPE_ARRAY) {
|
|
1198
|
+
return actual === TYPE_ARRAY;
|
|
1199
|
+
} else if (actual === TYPE_ARRAY) {
|
|
1200
|
+
var subtype;
|
|
1201
|
+
if (expected === TYPE_ARRAY_NUMBER) {
|
|
1202
|
+
subtype = TYPE_NUMBER;
|
|
1203
|
+
} else if (expected === TYPE_ARRAY_STRING) {
|
|
1204
|
+
subtype = TYPE_STRING;
|
|
1205
|
+
}
|
|
1206
|
+
for (var i = 0; i < argValue.length; i++) {
|
|
1207
|
+
if (!this._typeMatches(
|
|
1208
|
+
this._getTypeName(argValue[i]),
|
|
1209
|
+
subtype,
|
|
1210
|
+
argValue[i]
|
|
1211
|
+
)) {
|
|
1212
|
+
return false;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return true;
|
|
1216
|
+
}
|
|
1217
|
+
} else {
|
|
1218
|
+
return actual === expected;
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
_getTypeName: function(obj) {
|
|
1222
|
+
switch (Object.prototype.toString.call(obj)) {
|
|
1223
|
+
case "[object String]":
|
|
1224
|
+
return TYPE_STRING;
|
|
1225
|
+
case "[object Number]":
|
|
1226
|
+
return TYPE_NUMBER;
|
|
1227
|
+
case "[object Array]":
|
|
1228
|
+
return TYPE_ARRAY;
|
|
1229
|
+
case "[object Boolean]":
|
|
1230
|
+
return TYPE_BOOLEAN;
|
|
1231
|
+
case "[object Null]":
|
|
1232
|
+
return TYPE_NULL;
|
|
1233
|
+
case "[object Object]":
|
|
1234
|
+
if (obj.jmespathType === TOK_EXPREF) {
|
|
1235
|
+
return TYPE_EXPREF;
|
|
1236
|
+
} else {
|
|
1237
|
+
return TYPE_OBJECT;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
1241
|
+
_functionStartsWith: function(resolvedArgs) {
|
|
1242
|
+
return resolvedArgs[0].lastIndexOf(resolvedArgs[1]) === 0;
|
|
1243
|
+
},
|
|
1244
|
+
_functionEndsWith: function(resolvedArgs) {
|
|
1245
|
+
var searchStr = resolvedArgs[0];
|
|
1246
|
+
var suffix = resolvedArgs[1];
|
|
1247
|
+
return searchStr.indexOf(suffix, searchStr.length - suffix.length) !== -1;
|
|
1248
|
+
},
|
|
1249
|
+
_functionReverse: function(resolvedArgs) {
|
|
1250
|
+
var typeName = this._getTypeName(resolvedArgs[0]);
|
|
1251
|
+
if (typeName === TYPE_STRING) {
|
|
1252
|
+
var originalStr = resolvedArgs[0];
|
|
1253
|
+
var reversedStr = "";
|
|
1254
|
+
for (var i = originalStr.length - 1; i >= 0; i--) {
|
|
1255
|
+
reversedStr += originalStr[i];
|
|
1256
|
+
}
|
|
1257
|
+
return reversedStr;
|
|
1258
|
+
} else {
|
|
1259
|
+
var reversedArray = resolvedArgs[0].slice(0);
|
|
1260
|
+
reversedArray.reverse();
|
|
1261
|
+
return reversedArray;
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
_functionAbs: function(resolvedArgs) {
|
|
1265
|
+
return Math.abs(resolvedArgs[0]);
|
|
1266
|
+
},
|
|
1267
|
+
_functionCeil: function(resolvedArgs) {
|
|
1268
|
+
return Math.ceil(resolvedArgs[0]);
|
|
1269
|
+
},
|
|
1270
|
+
_functionAvg: function(resolvedArgs) {
|
|
1271
|
+
var sum = 0;
|
|
1272
|
+
var inputArray = resolvedArgs[0];
|
|
1273
|
+
for (var i = 0; i < inputArray.length; i++) {
|
|
1274
|
+
sum += inputArray[i];
|
|
1275
|
+
}
|
|
1276
|
+
return sum / inputArray.length;
|
|
1277
|
+
},
|
|
1278
|
+
_functionContains: function(resolvedArgs) {
|
|
1279
|
+
return resolvedArgs[0].indexOf(resolvedArgs[1]) >= 0;
|
|
1280
|
+
},
|
|
1281
|
+
_functionFloor: function(resolvedArgs) {
|
|
1282
|
+
return Math.floor(resolvedArgs[0]);
|
|
1283
|
+
},
|
|
1284
|
+
_functionLength: function(resolvedArgs) {
|
|
1285
|
+
if (!isObject(resolvedArgs[0])) {
|
|
1286
|
+
return resolvedArgs[0].length;
|
|
1287
|
+
} else {
|
|
1288
|
+
return Object.keys(resolvedArgs[0]).length;
|
|
1289
|
+
}
|
|
1290
|
+
},
|
|
1291
|
+
_functionMap: function(resolvedArgs) {
|
|
1292
|
+
var mapped = [];
|
|
1293
|
+
var interpreter = this._interpreter;
|
|
1294
|
+
var exprefNode = resolvedArgs[0];
|
|
1295
|
+
var elements = resolvedArgs[1];
|
|
1296
|
+
for (var i = 0; i < elements.length; i++) {
|
|
1297
|
+
mapped.push(interpreter.visit(exprefNode, elements[i]));
|
|
1298
|
+
}
|
|
1299
|
+
return mapped;
|
|
1300
|
+
},
|
|
1301
|
+
_functionMerge: function(resolvedArgs) {
|
|
1302
|
+
var merged = {};
|
|
1303
|
+
for (var i = 0; i < resolvedArgs.length; i++) {
|
|
1304
|
+
var current = resolvedArgs[i];
|
|
1305
|
+
for (var key in current) {
|
|
1306
|
+
merged[key] = current[key];
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return merged;
|
|
1310
|
+
},
|
|
1311
|
+
_functionMax: function(resolvedArgs) {
|
|
1312
|
+
if (resolvedArgs[0].length > 0) {
|
|
1313
|
+
var typeName = this._getTypeName(resolvedArgs[0][0]);
|
|
1314
|
+
if (typeName === TYPE_NUMBER) {
|
|
1315
|
+
return Math.max.apply(Math, resolvedArgs[0]);
|
|
1316
|
+
} else {
|
|
1317
|
+
var elements = resolvedArgs[0];
|
|
1318
|
+
var maxElement = elements[0];
|
|
1319
|
+
for (var i = 1; i < elements.length; i++) {
|
|
1320
|
+
if (maxElement.localeCompare(elements[i]) < 0) {
|
|
1321
|
+
maxElement = elements[i];
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
return maxElement;
|
|
1325
|
+
}
|
|
1326
|
+
} else {
|
|
1327
|
+
return null;
|
|
1328
|
+
}
|
|
1329
|
+
},
|
|
1330
|
+
_functionMin: function(resolvedArgs) {
|
|
1331
|
+
if (resolvedArgs[0].length > 0) {
|
|
1332
|
+
var typeName = this._getTypeName(resolvedArgs[0][0]);
|
|
1333
|
+
if (typeName === TYPE_NUMBER) {
|
|
1334
|
+
return Math.min.apply(Math, resolvedArgs[0]);
|
|
1335
|
+
} else {
|
|
1336
|
+
var elements = resolvedArgs[0];
|
|
1337
|
+
var minElement = elements[0];
|
|
1338
|
+
for (var i = 1; i < elements.length; i++) {
|
|
1339
|
+
if (elements[i].localeCompare(minElement) < 0) {
|
|
1340
|
+
minElement = elements[i];
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
return minElement;
|
|
1344
|
+
}
|
|
1345
|
+
} else {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
_functionSum: function(resolvedArgs) {
|
|
1350
|
+
var sum = 0;
|
|
1351
|
+
var listToSum = resolvedArgs[0];
|
|
1352
|
+
for (var i = 0; i < listToSum.length; i++) {
|
|
1353
|
+
sum += listToSum[i];
|
|
1354
|
+
}
|
|
1355
|
+
return sum;
|
|
1356
|
+
},
|
|
1357
|
+
_functionType: function(resolvedArgs) {
|
|
1358
|
+
switch (this._getTypeName(resolvedArgs[0])) {
|
|
1359
|
+
case TYPE_NUMBER:
|
|
1360
|
+
return "number";
|
|
1361
|
+
case TYPE_STRING:
|
|
1362
|
+
return "string";
|
|
1363
|
+
case TYPE_ARRAY:
|
|
1364
|
+
return "array";
|
|
1365
|
+
case TYPE_OBJECT:
|
|
1366
|
+
return "object";
|
|
1367
|
+
case TYPE_BOOLEAN:
|
|
1368
|
+
return "boolean";
|
|
1369
|
+
case TYPE_EXPREF:
|
|
1370
|
+
return "expref";
|
|
1371
|
+
case TYPE_NULL:
|
|
1372
|
+
return "null";
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1375
|
+
_functionKeys: function(resolvedArgs) {
|
|
1376
|
+
return Object.keys(resolvedArgs[0]);
|
|
1377
|
+
},
|
|
1378
|
+
_functionValues: function(resolvedArgs) {
|
|
1379
|
+
var obj = resolvedArgs[0];
|
|
1380
|
+
var keys = Object.keys(obj);
|
|
1381
|
+
var values = [];
|
|
1382
|
+
for (var i = 0; i < keys.length; i++) {
|
|
1383
|
+
values.push(obj[keys[i]]);
|
|
1384
|
+
}
|
|
1385
|
+
return values;
|
|
1386
|
+
},
|
|
1387
|
+
_functionJoin: function(resolvedArgs) {
|
|
1388
|
+
var joinChar = resolvedArgs[0];
|
|
1389
|
+
var listJoin = resolvedArgs[1];
|
|
1390
|
+
return listJoin.join(joinChar);
|
|
1391
|
+
},
|
|
1392
|
+
_functionToArray: function(resolvedArgs) {
|
|
1393
|
+
if (this._getTypeName(resolvedArgs[0]) === TYPE_ARRAY) {
|
|
1394
|
+
return resolvedArgs[0];
|
|
1395
|
+
} else {
|
|
1396
|
+
return [resolvedArgs[0]];
|
|
1397
|
+
}
|
|
1398
|
+
},
|
|
1399
|
+
_functionToString: function(resolvedArgs) {
|
|
1400
|
+
if (this._getTypeName(resolvedArgs[0]) === TYPE_STRING) {
|
|
1401
|
+
return resolvedArgs[0];
|
|
1402
|
+
} else {
|
|
1403
|
+
return JSON.stringify(resolvedArgs[0]);
|
|
1404
|
+
}
|
|
1405
|
+
},
|
|
1406
|
+
_functionToNumber: function(resolvedArgs) {
|
|
1407
|
+
var typeName = this._getTypeName(resolvedArgs[0]);
|
|
1408
|
+
var convertedValue;
|
|
1409
|
+
if (typeName === TYPE_NUMBER) {
|
|
1410
|
+
return resolvedArgs[0];
|
|
1411
|
+
} else if (typeName === TYPE_STRING) {
|
|
1412
|
+
convertedValue = +resolvedArgs[0];
|
|
1413
|
+
if (!isNaN(convertedValue)) {
|
|
1414
|
+
return convertedValue;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
return null;
|
|
1418
|
+
},
|
|
1419
|
+
_functionNotNull: function(resolvedArgs) {
|
|
1420
|
+
for (var i = 0; i < resolvedArgs.length; i++) {
|
|
1421
|
+
if (this._getTypeName(resolvedArgs[i]) !== TYPE_NULL) {
|
|
1422
|
+
return resolvedArgs[i];
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
return null;
|
|
1426
|
+
},
|
|
1427
|
+
_functionSort: function(resolvedArgs) {
|
|
1428
|
+
var sortedArray = resolvedArgs[0].slice(0);
|
|
1429
|
+
sortedArray.sort();
|
|
1430
|
+
return sortedArray;
|
|
1431
|
+
},
|
|
1432
|
+
_functionSortBy: function(resolvedArgs) {
|
|
1433
|
+
var sortedArray = resolvedArgs[0].slice(0);
|
|
1434
|
+
if (sortedArray.length === 0) {
|
|
1435
|
+
return sortedArray;
|
|
1436
|
+
}
|
|
1437
|
+
var interpreter = this._interpreter;
|
|
1438
|
+
var exprefNode = resolvedArgs[1];
|
|
1439
|
+
var requiredType = this._getTypeName(
|
|
1440
|
+
interpreter.visit(exprefNode, sortedArray[0])
|
|
1441
|
+
);
|
|
1442
|
+
if ([TYPE_NUMBER, TYPE_STRING].indexOf(requiredType) < 0) {
|
|
1443
|
+
throw new Error("TypeError");
|
|
1444
|
+
}
|
|
1445
|
+
var that = this;
|
|
1446
|
+
var decorated = [];
|
|
1447
|
+
for (var i = 0; i < sortedArray.length; i++) {
|
|
1448
|
+
decorated.push([i, sortedArray[i]]);
|
|
1449
|
+
}
|
|
1450
|
+
decorated.sort(function(a, b) {
|
|
1451
|
+
var exprA = interpreter.visit(exprefNode, a[1]);
|
|
1452
|
+
var exprB = interpreter.visit(exprefNode, b[1]);
|
|
1453
|
+
if (that._getTypeName(exprA) !== requiredType) {
|
|
1454
|
+
throw new Error(
|
|
1455
|
+
"TypeError: expected " + requiredType + ", received " + that._getTypeName(exprA)
|
|
1456
|
+
);
|
|
1457
|
+
} else if (that._getTypeName(exprB) !== requiredType) {
|
|
1458
|
+
throw new Error(
|
|
1459
|
+
"TypeError: expected " + requiredType + ", received " + that._getTypeName(exprB)
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
if (exprA > exprB) {
|
|
1463
|
+
return 1;
|
|
1464
|
+
} else if (exprA < exprB) {
|
|
1465
|
+
return -1;
|
|
1466
|
+
} else {
|
|
1467
|
+
return a[0] - b[0];
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
for (var j = 0; j < decorated.length; j++) {
|
|
1471
|
+
sortedArray[j] = decorated[j][1];
|
|
1472
|
+
}
|
|
1473
|
+
return sortedArray;
|
|
1474
|
+
},
|
|
1475
|
+
_functionMaxBy: function(resolvedArgs) {
|
|
1476
|
+
var exprefNode = resolvedArgs[1];
|
|
1477
|
+
var resolvedArray = resolvedArgs[0];
|
|
1478
|
+
var keyFunction = this.createKeyFunction(exprefNode, [TYPE_NUMBER, TYPE_STRING]);
|
|
1479
|
+
var maxNumber = -Infinity;
|
|
1480
|
+
var maxRecord;
|
|
1481
|
+
var current;
|
|
1482
|
+
for (var i = 0; i < resolvedArray.length; i++) {
|
|
1483
|
+
current = keyFunction(resolvedArray[i]);
|
|
1484
|
+
if (current > maxNumber) {
|
|
1485
|
+
maxNumber = current;
|
|
1486
|
+
maxRecord = resolvedArray[i];
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
return maxRecord;
|
|
1490
|
+
},
|
|
1491
|
+
_functionMinBy: function(resolvedArgs) {
|
|
1492
|
+
var exprefNode = resolvedArgs[1];
|
|
1493
|
+
var resolvedArray = resolvedArgs[0];
|
|
1494
|
+
var keyFunction = this.createKeyFunction(exprefNode, [TYPE_NUMBER, TYPE_STRING]);
|
|
1495
|
+
var minNumber = Infinity;
|
|
1496
|
+
var minRecord;
|
|
1497
|
+
var current;
|
|
1498
|
+
for (var i = 0; i < resolvedArray.length; i++) {
|
|
1499
|
+
current = keyFunction(resolvedArray[i]);
|
|
1500
|
+
if (current < minNumber) {
|
|
1501
|
+
minNumber = current;
|
|
1502
|
+
minRecord = resolvedArray[i];
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return minRecord;
|
|
1506
|
+
},
|
|
1507
|
+
createKeyFunction: function(exprefNode, allowedTypes) {
|
|
1508
|
+
var that = this;
|
|
1509
|
+
var interpreter = this._interpreter;
|
|
1510
|
+
var keyFunc = function(x) {
|
|
1511
|
+
var current = interpreter.visit(exprefNode, x);
|
|
1512
|
+
if (allowedTypes.indexOf(that._getTypeName(current)) < 0) {
|
|
1513
|
+
var msg = "TypeError: expected one of " + allowedTypes + ", received " + that._getTypeName(current);
|
|
1514
|
+
throw new Error(msg);
|
|
1515
|
+
}
|
|
1516
|
+
return current;
|
|
1517
|
+
};
|
|
1518
|
+
return keyFunc;
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
function compile(stream) {
|
|
1522
|
+
var parser = new Parser();
|
|
1523
|
+
var ast = parser.parse(stream);
|
|
1524
|
+
return ast;
|
|
1525
|
+
}
|
|
1526
|
+
function tokenize(stream) {
|
|
1527
|
+
var lexer = new Lexer();
|
|
1528
|
+
return lexer.tokenize(stream);
|
|
1529
|
+
}
|
|
1530
|
+
function search(data, expression) {
|
|
1531
|
+
var parser = new Parser();
|
|
1532
|
+
var runtime = new Runtime();
|
|
1533
|
+
var interpreter = new TreeInterpreter(runtime);
|
|
1534
|
+
runtime._interpreter = interpreter;
|
|
1535
|
+
var node = parser.parse(expression);
|
|
1536
|
+
return interpreter.search(node, data);
|
|
1537
|
+
}
|
|
1538
|
+
exports3.tokenize = tokenize;
|
|
1539
|
+
exports3.compile = compile;
|
|
1540
|
+
exports3.search = search;
|
|
1541
|
+
exports3.strictDeepEqual = strictDeepEqual;
|
|
1542
|
+
})(typeof exports2 === "undefined" ? exports2.jmespath = {} : exports2);
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
|
|
1546
|
+
// node_modules/mustache/mustache.mjs
|
|
1547
|
+
var mustache_exports = {};
|
|
1548
|
+
__export(mustache_exports, {
|
|
1549
|
+
default: () => mustache_default
|
|
1550
|
+
});
|
|
1551
|
+
function isFunction(object) {
|
|
1552
|
+
return typeof object === "function";
|
|
1553
|
+
}
|
|
1554
|
+
function typeStr(obj) {
|
|
1555
|
+
return isArray(obj) ? "array" : typeof obj;
|
|
1556
|
+
}
|
|
1557
|
+
function escapeRegExp2(string) {
|
|
1558
|
+
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
|
|
1559
|
+
}
|
|
1560
|
+
function hasProperty(obj, propName) {
|
|
1561
|
+
return obj != null && typeof obj === "object" && propName in obj;
|
|
1562
|
+
}
|
|
1563
|
+
function primitiveHasOwnProperty(primitive, propName) {
|
|
1564
|
+
return primitive != null && typeof primitive !== "object" && primitive.hasOwnProperty && primitive.hasOwnProperty(propName);
|
|
1565
|
+
}
|
|
1566
|
+
function testRegExp(re, string) {
|
|
1567
|
+
return regExpTest.call(re, string);
|
|
1568
|
+
}
|
|
1569
|
+
function isWhitespace(string) {
|
|
1570
|
+
return !testRegExp(nonSpaceRe, string);
|
|
1571
|
+
}
|
|
1572
|
+
function escapeHtml(string) {
|
|
1573
|
+
return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap(s) {
|
|
1574
|
+
return entityMap[s];
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
function parseTemplate(template, tags) {
|
|
1578
|
+
if (!template)
|
|
1579
|
+
return [];
|
|
1580
|
+
var lineHasNonSpace = false;
|
|
1581
|
+
var sections = [];
|
|
1582
|
+
var tokens = [];
|
|
1583
|
+
var spaces = [];
|
|
1584
|
+
var hasTag = false;
|
|
1585
|
+
var nonSpace = false;
|
|
1586
|
+
var indentation = "";
|
|
1587
|
+
var tagIndex = 0;
|
|
1588
|
+
function stripSpace() {
|
|
1589
|
+
if (hasTag && !nonSpace) {
|
|
1590
|
+
while (spaces.length)
|
|
1591
|
+
delete tokens[spaces.pop()];
|
|
1592
|
+
} else {
|
|
1593
|
+
spaces = [];
|
|
1594
|
+
}
|
|
1595
|
+
hasTag = false;
|
|
1596
|
+
nonSpace = false;
|
|
1597
|
+
}
|
|
1598
|
+
var openingTagRe, closingTagRe, closingCurlyRe;
|
|
1599
|
+
function compileTags(tagsToCompile) {
|
|
1600
|
+
if (typeof tagsToCompile === "string")
|
|
1601
|
+
tagsToCompile = tagsToCompile.split(spaceRe, 2);
|
|
1602
|
+
if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
|
|
1603
|
+
throw new Error("Invalid tags: " + tagsToCompile);
|
|
1604
|
+
openingTagRe = new RegExp(escapeRegExp2(tagsToCompile[0]) + "\\s*");
|
|
1605
|
+
closingTagRe = new RegExp("\\s*" + escapeRegExp2(tagsToCompile[1]));
|
|
1606
|
+
closingCurlyRe = new RegExp("\\s*" + escapeRegExp2("}" + tagsToCompile[1]));
|
|
1607
|
+
}
|
|
1608
|
+
compileTags(tags || mustache.tags);
|
|
1609
|
+
var scanner = new Scanner(template);
|
|
1610
|
+
var start, type, value, chr, token, openSection;
|
|
1611
|
+
while (!scanner.eos()) {
|
|
1612
|
+
start = scanner.pos;
|
|
1613
|
+
value = scanner.scanUntil(openingTagRe);
|
|
1614
|
+
if (value) {
|
|
1615
|
+
for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
|
|
1616
|
+
chr = value.charAt(i);
|
|
1617
|
+
if (isWhitespace(chr)) {
|
|
1618
|
+
spaces.push(tokens.length);
|
|
1619
|
+
indentation += chr;
|
|
1620
|
+
} else {
|
|
1621
|
+
nonSpace = true;
|
|
1622
|
+
lineHasNonSpace = true;
|
|
1623
|
+
indentation += " ";
|
|
1624
|
+
}
|
|
1625
|
+
tokens.push(["text", chr, start, start + 1]);
|
|
1626
|
+
start += 1;
|
|
1627
|
+
if (chr === "\n") {
|
|
1628
|
+
stripSpace();
|
|
1629
|
+
indentation = "";
|
|
1630
|
+
tagIndex = 0;
|
|
1631
|
+
lineHasNonSpace = false;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
if (!scanner.scan(openingTagRe))
|
|
1636
|
+
break;
|
|
1637
|
+
hasTag = true;
|
|
1638
|
+
type = scanner.scan(tagRe) || "name";
|
|
1639
|
+
scanner.scan(whiteRe);
|
|
1640
|
+
if (type === "=") {
|
|
1641
|
+
value = scanner.scanUntil(equalsRe);
|
|
1642
|
+
scanner.scan(equalsRe);
|
|
1643
|
+
scanner.scanUntil(closingTagRe);
|
|
1644
|
+
} else if (type === "{") {
|
|
1645
|
+
value = scanner.scanUntil(closingCurlyRe);
|
|
1646
|
+
scanner.scan(curlyRe);
|
|
1647
|
+
scanner.scanUntil(closingTagRe);
|
|
1648
|
+
type = "&";
|
|
1649
|
+
} else {
|
|
1650
|
+
value = scanner.scanUntil(closingTagRe);
|
|
1651
|
+
}
|
|
1652
|
+
if (!scanner.scan(closingTagRe))
|
|
1653
|
+
throw new Error("Unclosed tag at " + scanner.pos);
|
|
1654
|
+
if (type == ">") {
|
|
1655
|
+
token = [type, value, start, scanner.pos, indentation, tagIndex, lineHasNonSpace];
|
|
1656
|
+
} else {
|
|
1657
|
+
token = [type, value, start, scanner.pos];
|
|
1658
|
+
}
|
|
1659
|
+
tagIndex++;
|
|
1660
|
+
tokens.push(token);
|
|
1661
|
+
if (type === "#" || type === "^") {
|
|
1662
|
+
sections.push(token);
|
|
1663
|
+
} else if (type === "/") {
|
|
1664
|
+
openSection = sections.pop();
|
|
1665
|
+
if (!openSection)
|
|
1666
|
+
throw new Error('Unopened section "' + value + '" at ' + start);
|
|
1667
|
+
if (openSection[1] !== value)
|
|
1668
|
+
throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
|
|
1669
|
+
} else if (type === "name" || type === "{" || type === "&") {
|
|
1670
|
+
nonSpace = true;
|
|
1671
|
+
} else if (type === "=") {
|
|
1672
|
+
compileTags(value);
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
stripSpace();
|
|
1676
|
+
openSection = sections.pop();
|
|
1677
|
+
if (openSection)
|
|
1678
|
+
throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
|
|
1679
|
+
return nestTokens(squashTokens(tokens));
|
|
1680
|
+
}
|
|
1681
|
+
function squashTokens(tokens) {
|
|
1682
|
+
var squashedTokens = [];
|
|
1683
|
+
var token, lastToken;
|
|
1684
|
+
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
|
|
1685
|
+
token = tokens[i];
|
|
1686
|
+
if (token) {
|
|
1687
|
+
if (token[0] === "text" && lastToken && lastToken[0] === "text") {
|
|
1688
|
+
lastToken[1] += token[1];
|
|
1689
|
+
lastToken[3] = token[3];
|
|
1690
|
+
} else {
|
|
1691
|
+
squashedTokens.push(token);
|
|
1692
|
+
lastToken = token;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
return squashedTokens;
|
|
1697
|
+
}
|
|
1698
|
+
function nestTokens(tokens) {
|
|
1699
|
+
var nestedTokens = [];
|
|
1700
|
+
var collector = nestedTokens;
|
|
1701
|
+
var sections = [];
|
|
1702
|
+
var token, section;
|
|
1703
|
+
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
|
|
1704
|
+
token = tokens[i];
|
|
1705
|
+
switch (token[0]) {
|
|
1706
|
+
case "#":
|
|
1707
|
+
case "^":
|
|
1708
|
+
collector.push(token);
|
|
1709
|
+
sections.push(token);
|
|
1710
|
+
collector = token[4] = [];
|
|
1711
|
+
break;
|
|
1712
|
+
case "/":
|
|
1713
|
+
section = sections.pop();
|
|
1714
|
+
section[5] = token[2];
|
|
1715
|
+
collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
|
|
1716
|
+
break;
|
|
1717
|
+
default:
|
|
1718
|
+
collector.push(token);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
return nestedTokens;
|
|
1722
|
+
}
|
|
1723
|
+
function Scanner(string) {
|
|
1724
|
+
this.string = string;
|
|
1725
|
+
this.tail = string;
|
|
1726
|
+
this.pos = 0;
|
|
1727
|
+
}
|
|
1728
|
+
function Context(view, parentContext) {
|
|
1729
|
+
this.view = view;
|
|
1730
|
+
this.cache = { ".": this.view };
|
|
1731
|
+
this.parent = parentContext;
|
|
1732
|
+
}
|
|
1733
|
+
function Writer() {
|
|
1734
|
+
this.templateCache = {
|
|
1735
|
+
_cache: {},
|
|
1736
|
+
set: function set(key, value) {
|
|
1737
|
+
this._cache[key] = value;
|
|
1738
|
+
},
|
|
1739
|
+
get: function get(key) {
|
|
1740
|
+
return this._cache[key];
|
|
1741
|
+
},
|
|
1742
|
+
clear: function clear() {
|
|
1743
|
+
this._cache = {};
|
|
1744
|
+
}
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
var objectToString, isArray, regExpTest, nonSpaceRe, entityMap, whiteRe, spaceRe, equalsRe, curlyRe, tagRe, mustache, defaultWriter, mustache_default;
|
|
1748
|
+
var init_mustache = __esm({
|
|
1749
|
+
"node_modules/mustache/mustache.mjs"() {
|
|
1750
|
+
"use strict";
|
|
1751
|
+
objectToString = Object.prototype.toString;
|
|
1752
|
+
isArray = Array.isArray || function isArrayPolyfill(object) {
|
|
1753
|
+
return objectToString.call(object) === "[object Array]";
|
|
1754
|
+
};
|
|
1755
|
+
regExpTest = RegExp.prototype.test;
|
|
1756
|
+
nonSpaceRe = /\S/;
|
|
1757
|
+
entityMap = {
|
|
1758
|
+
"&": "&",
|
|
1759
|
+
"<": "<",
|
|
1760
|
+
">": ">",
|
|
1761
|
+
'"': """,
|
|
1762
|
+
"'": "'",
|
|
1763
|
+
"/": "/",
|
|
1764
|
+
"`": "`",
|
|
1765
|
+
"=": "="
|
|
1766
|
+
};
|
|
1767
|
+
whiteRe = /\s*/;
|
|
1768
|
+
spaceRe = /\s+/;
|
|
1769
|
+
equalsRe = /\s*=/;
|
|
1770
|
+
curlyRe = /\s*\}/;
|
|
1771
|
+
tagRe = /#|\^|\/|>|\{|&|=|!/;
|
|
1772
|
+
Scanner.prototype.eos = function eos() {
|
|
1773
|
+
return this.tail === "";
|
|
1774
|
+
};
|
|
1775
|
+
Scanner.prototype.scan = function scan(re) {
|
|
1776
|
+
var match = this.tail.match(re);
|
|
1777
|
+
if (!match || match.index !== 0)
|
|
1778
|
+
return "";
|
|
1779
|
+
var string = match[0];
|
|
1780
|
+
this.tail = this.tail.substring(string.length);
|
|
1781
|
+
this.pos += string.length;
|
|
1782
|
+
return string;
|
|
1783
|
+
};
|
|
1784
|
+
Scanner.prototype.scanUntil = function scanUntil(re) {
|
|
1785
|
+
var index = this.tail.search(re), match;
|
|
1786
|
+
switch (index) {
|
|
1787
|
+
case -1:
|
|
1788
|
+
match = this.tail;
|
|
1789
|
+
this.tail = "";
|
|
1790
|
+
break;
|
|
1791
|
+
case 0:
|
|
1792
|
+
match = "";
|
|
1793
|
+
break;
|
|
1794
|
+
default:
|
|
1795
|
+
match = this.tail.substring(0, index);
|
|
1796
|
+
this.tail = this.tail.substring(index);
|
|
1797
|
+
}
|
|
1798
|
+
this.pos += match.length;
|
|
1799
|
+
return match;
|
|
1800
|
+
};
|
|
1801
|
+
Context.prototype.push = function push(view) {
|
|
1802
|
+
return new Context(view, this);
|
|
1803
|
+
};
|
|
1804
|
+
Context.prototype.lookup = function lookup2(name) {
|
|
1805
|
+
var cache = this.cache;
|
|
1806
|
+
var value;
|
|
1807
|
+
if (cache.hasOwnProperty(name)) {
|
|
1808
|
+
value = cache[name];
|
|
1809
|
+
} else {
|
|
1810
|
+
var context = this, intermediateValue, names, index, lookupHit = false;
|
|
1811
|
+
while (context) {
|
|
1812
|
+
if (name.indexOf(".") > 0) {
|
|
1813
|
+
intermediateValue = context.view;
|
|
1814
|
+
names = name.split(".");
|
|
1815
|
+
index = 0;
|
|
1816
|
+
while (intermediateValue != null && index < names.length) {
|
|
1817
|
+
if (index === names.length - 1)
|
|
1818
|
+
lookupHit = hasProperty(intermediateValue, names[index]) || primitiveHasOwnProperty(intermediateValue, names[index]);
|
|
1819
|
+
intermediateValue = intermediateValue[names[index++]];
|
|
1820
|
+
}
|
|
1821
|
+
} else {
|
|
1822
|
+
intermediateValue = context.view[name];
|
|
1823
|
+
lookupHit = hasProperty(context.view, name);
|
|
1824
|
+
}
|
|
1825
|
+
if (lookupHit) {
|
|
1826
|
+
value = intermediateValue;
|
|
1827
|
+
break;
|
|
1828
|
+
}
|
|
1829
|
+
context = context.parent;
|
|
1830
|
+
}
|
|
1831
|
+
cache[name] = value;
|
|
1832
|
+
}
|
|
1833
|
+
if (isFunction(value))
|
|
1834
|
+
value = value.call(this.view);
|
|
1835
|
+
return value;
|
|
1836
|
+
};
|
|
1837
|
+
Writer.prototype.clearCache = function clearCache() {
|
|
1838
|
+
if (typeof this.templateCache !== "undefined") {
|
|
1839
|
+
this.templateCache.clear();
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
Writer.prototype.parse = function parse2(template, tags) {
|
|
1843
|
+
var cache = this.templateCache;
|
|
1844
|
+
var cacheKey = template + ":" + (tags || mustache.tags).join(":");
|
|
1845
|
+
var isCacheEnabled = typeof cache !== "undefined";
|
|
1846
|
+
var tokens = isCacheEnabled ? cache.get(cacheKey) : void 0;
|
|
1847
|
+
if (tokens == void 0) {
|
|
1848
|
+
tokens = parseTemplate(template, tags);
|
|
1849
|
+
isCacheEnabled && cache.set(cacheKey, tokens);
|
|
1850
|
+
}
|
|
1851
|
+
return tokens;
|
|
1852
|
+
};
|
|
1853
|
+
Writer.prototype.render = function render(template, view, partials, config) {
|
|
1854
|
+
var tags = this.getConfigTags(config);
|
|
1855
|
+
var tokens = this.parse(template, tags);
|
|
1856
|
+
var context = view instanceof Context ? view : new Context(view, void 0);
|
|
1857
|
+
return this.renderTokens(tokens, context, partials, template, config);
|
|
1858
|
+
};
|
|
1859
|
+
Writer.prototype.renderTokens = function renderTokens(tokens, context, partials, originalTemplate, config) {
|
|
1860
|
+
var buffer = "";
|
|
1861
|
+
var token, symbol, value;
|
|
1862
|
+
for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
|
|
1863
|
+
value = void 0;
|
|
1864
|
+
token = tokens[i];
|
|
1865
|
+
symbol = token[0];
|
|
1866
|
+
if (symbol === "#") value = this.renderSection(token, context, partials, originalTemplate, config);
|
|
1867
|
+
else if (symbol === "^") value = this.renderInverted(token, context, partials, originalTemplate, config);
|
|
1868
|
+
else if (symbol === ">") value = this.renderPartial(token, context, partials, config);
|
|
1869
|
+
else if (symbol === "&") value = this.unescapedValue(token, context);
|
|
1870
|
+
else if (symbol === "name") value = this.escapedValue(token, context, config);
|
|
1871
|
+
else if (symbol === "text") value = this.rawValue(token);
|
|
1872
|
+
if (value !== void 0)
|
|
1873
|
+
buffer += value;
|
|
1874
|
+
}
|
|
1875
|
+
return buffer;
|
|
1876
|
+
};
|
|
1877
|
+
Writer.prototype.renderSection = function renderSection(token, context, partials, originalTemplate, config) {
|
|
1878
|
+
var self = this;
|
|
1879
|
+
var buffer = "";
|
|
1880
|
+
var value = context.lookup(token[1]);
|
|
1881
|
+
function subRender(template) {
|
|
1882
|
+
return self.render(template, context, partials, config);
|
|
1883
|
+
}
|
|
1884
|
+
if (!value) return;
|
|
1885
|
+
if (isArray(value)) {
|
|
1886
|
+
for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
|
|
1887
|
+
buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate, config);
|
|
1888
|
+
}
|
|
1889
|
+
} else if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
|
|
1890
|
+
buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate, config);
|
|
1891
|
+
} else if (isFunction(value)) {
|
|
1892
|
+
if (typeof originalTemplate !== "string")
|
|
1893
|
+
throw new Error("Cannot use higher-order sections without the original template");
|
|
1894
|
+
value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
|
|
1895
|
+
if (value != null)
|
|
1896
|
+
buffer += value;
|
|
1897
|
+
} else {
|
|
1898
|
+
buffer += this.renderTokens(token[4], context, partials, originalTemplate, config);
|
|
1899
|
+
}
|
|
1900
|
+
return buffer;
|
|
1901
|
+
};
|
|
1902
|
+
Writer.prototype.renderInverted = function renderInverted(token, context, partials, originalTemplate, config) {
|
|
1903
|
+
var value = context.lookup(token[1]);
|
|
1904
|
+
if (!value || isArray(value) && value.length === 0)
|
|
1905
|
+
return this.renderTokens(token[4], context, partials, originalTemplate, config);
|
|
1906
|
+
};
|
|
1907
|
+
Writer.prototype.indentPartial = function indentPartial(partial, indentation, lineHasNonSpace) {
|
|
1908
|
+
var filteredIndentation = indentation.replace(/[^ \t]/g, "");
|
|
1909
|
+
var partialByNl = partial.split("\n");
|
|
1910
|
+
for (var i = 0; i < partialByNl.length; i++) {
|
|
1911
|
+
if (partialByNl[i].length && (i > 0 || !lineHasNonSpace)) {
|
|
1912
|
+
partialByNl[i] = filteredIndentation + partialByNl[i];
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
return partialByNl.join("\n");
|
|
1916
|
+
};
|
|
1917
|
+
Writer.prototype.renderPartial = function renderPartial(token, context, partials, config) {
|
|
1918
|
+
if (!partials) return;
|
|
1919
|
+
var tags = this.getConfigTags(config);
|
|
1920
|
+
var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
|
|
1921
|
+
if (value != null) {
|
|
1922
|
+
var lineHasNonSpace = token[6];
|
|
1923
|
+
var tagIndex = token[5];
|
|
1924
|
+
var indentation = token[4];
|
|
1925
|
+
var indentedValue = value;
|
|
1926
|
+
if (tagIndex == 0 && indentation) {
|
|
1927
|
+
indentedValue = this.indentPartial(value, indentation, lineHasNonSpace);
|
|
1928
|
+
}
|
|
1929
|
+
var tokens = this.parse(indentedValue, tags);
|
|
1930
|
+
return this.renderTokens(tokens, context, partials, indentedValue, config);
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
Writer.prototype.unescapedValue = function unescapedValue(token, context) {
|
|
1934
|
+
var value = context.lookup(token[1]);
|
|
1935
|
+
if (value != null)
|
|
1936
|
+
return value;
|
|
1937
|
+
};
|
|
1938
|
+
Writer.prototype.escapedValue = function escapedValue(token, context, config) {
|
|
1939
|
+
var escape = this.getConfigEscape(config) || mustache.escape;
|
|
1940
|
+
var value = context.lookup(token[1]);
|
|
1941
|
+
if (value != null)
|
|
1942
|
+
return typeof value === "number" && escape === mustache.escape ? String(value) : escape(value);
|
|
1943
|
+
};
|
|
1944
|
+
Writer.prototype.rawValue = function rawValue(token) {
|
|
1945
|
+
return token[1];
|
|
1946
|
+
};
|
|
1947
|
+
Writer.prototype.getConfigTags = function getConfigTags(config) {
|
|
1948
|
+
if (isArray(config)) {
|
|
1949
|
+
return config;
|
|
1950
|
+
} else if (config && typeof config === "object") {
|
|
1951
|
+
return config.tags;
|
|
1952
|
+
} else {
|
|
1953
|
+
return void 0;
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
Writer.prototype.getConfigEscape = function getConfigEscape(config) {
|
|
1957
|
+
if (config && typeof config === "object" && !isArray(config)) {
|
|
1958
|
+
return config.escape;
|
|
1959
|
+
} else {
|
|
1960
|
+
return void 0;
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
mustache = {
|
|
1964
|
+
name: "mustache.js",
|
|
1965
|
+
version: "4.2.0",
|
|
1966
|
+
tags: ["{{", "}}"],
|
|
1967
|
+
clearCache: void 0,
|
|
1968
|
+
escape: void 0,
|
|
1969
|
+
parse: void 0,
|
|
1970
|
+
render: void 0,
|
|
1971
|
+
Scanner: void 0,
|
|
1972
|
+
Context: void 0,
|
|
1973
|
+
Writer: void 0,
|
|
1974
|
+
/**
|
|
1975
|
+
* Allows a user to override the default caching strategy, by providing an
|
|
1976
|
+
* object with set, get and clear methods. This can also be used to disable
|
|
1977
|
+
* the cache by setting it to the literal `undefined`.
|
|
1978
|
+
*/
|
|
1979
|
+
set templateCache(cache) {
|
|
1980
|
+
defaultWriter.templateCache = cache;
|
|
1981
|
+
},
|
|
1982
|
+
/**
|
|
1983
|
+
* Gets the default or overridden caching object from the default writer.
|
|
1984
|
+
*/
|
|
1985
|
+
get templateCache() {
|
|
1986
|
+
return defaultWriter.templateCache;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
defaultWriter = new Writer();
|
|
1990
|
+
mustache.clearCache = function clearCache2() {
|
|
1991
|
+
return defaultWriter.clearCache();
|
|
1992
|
+
};
|
|
1993
|
+
mustache.parse = function parse3(template, tags) {
|
|
1994
|
+
return defaultWriter.parse(template, tags);
|
|
1995
|
+
};
|
|
1996
|
+
mustache.render = function render2(template, view, partials, config) {
|
|
1997
|
+
if (typeof template !== "string") {
|
|
1998
|
+
throw new TypeError('Invalid template! Template should be a "string" but "' + typeStr(template) + '" was given as the first argument for mustache#render(template, view, partials)');
|
|
1999
|
+
}
|
|
2000
|
+
return defaultWriter.render(template, view, partials, config);
|
|
2001
|
+
};
|
|
2002
|
+
mustache.escape = escapeHtml;
|
|
2003
|
+
mustache.Scanner = Scanner;
|
|
2004
|
+
mustache.Context = Context;
|
|
2005
|
+
mustache.Writer = Writer;
|
|
2006
|
+
mustache_default = mustache;
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
|
|
2010
|
+
// index.ts
|
|
2011
|
+
var index_exports = {};
|
|
2012
|
+
__export(index_exports, {
|
|
2013
|
+
CoreAdapter: () => CoreAdapter,
|
|
2014
|
+
DEFAULT_CORE_TOOLS_CONFIG: () => DEFAULT_CORE_TOOLS_CONFIG,
|
|
2015
|
+
deletePathSpec: () => deletePathSpec,
|
|
2016
|
+
downloadFileSpec: () => downloadFileSpec,
|
|
2017
|
+
duckduckgoSearchSpec: () => duckduckgoSearchSpec,
|
|
2018
|
+
fetchJsonSpec: () => fetchJsonSpec,
|
|
2019
|
+
fetchPageMainContentSpec: () => fetchPageMainContentSpec,
|
|
2020
|
+
fetchTextSpec: () => fetchTextSpec,
|
|
2021
|
+
getBuiltinContext: () => getBuiltinContext,
|
|
2022
|
+
hashTextSpec: () => hashTextSpec,
|
|
2023
|
+
headSpec: () => headSpec,
|
|
2024
|
+
isIpInBlockedCidrs: () => isIpInBlockedCidrs,
|
|
2025
|
+
jsonSelectSpec: () => jsonSelectSpec,
|
|
2026
|
+
listDirSpec: () => listDirSpec,
|
|
2027
|
+
nowHandler: () => nowHandler,
|
|
2028
|
+
nowSpec: () => nowSpec,
|
|
2029
|
+
readTextSpec: () => readTextSpec,
|
|
2030
|
+
registerCoreTools: () => registerCoreTools,
|
|
2031
|
+
resolveSandboxedPath: () => resolveSandboxedPath,
|
|
2032
|
+
runCommandSpec: () => runCommandSpec,
|
|
2033
|
+
runWithBuiltinContext: () => runWithBuiltinContext,
|
|
2034
|
+
searchTextSpec: () => searchTextSpec,
|
|
2035
|
+
sha256Spec: () => sha256Spec,
|
|
2036
|
+
templateRenderSpec: () => templateRenderSpec,
|
|
2037
|
+
truncateSpec: () => truncateSpec,
|
|
2038
|
+
validateUrl: () => validateUrl,
|
|
2039
|
+
writeTextSpec: () => writeTextSpec
|
|
2040
|
+
});
|
|
2041
|
+
module.exports = __toCommonJS(index_exports);
|
|
2042
|
+
|
|
2043
|
+
// context.ts
|
|
2044
|
+
var import_node_async_hooks = require("async_hooks");
|
|
2045
|
+
var storage = new import_node_async_hooks.AsyncLocalStorage();
|
|
2046
|
+
function getBuiltinContext() {
|
|
2047
|
+
const ctx = storage.getStore();
|
|
2048
|
+
if (!ctx) throw new Error("Builtin context not set; invoke only through CoreAdapter.");
|
|
2049
|
+
return ctx;
|
|
2050
|
+
}
|
|
2051
|
+
function runWithBuiltinContext(ctx, fn) {
|
|
2052
|
+
return storage.run(ctx, fn);
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
// CoreAdapter.ts
|
|
2056
|
+
var CoreAdapter = class {
|
|
2057
|
+
kind = "core";
|
|
2058
|
+
handlers = /* @__PURE__ */ new Map();
|
|
2059
|
+
config;
|
|
2060
|
+
constructor(config) {
|
|
2061
|
+
this.config = config;
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* Register a handler for a specific core tool name.
|
|
2065
|
+
*/
|
|
2066
|
+
registerHandler(toolName, handler) {
|
|
2067
|
+
this.handlers.set(toolName, handler);
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Unregister a handler.
|
|
2071
|
+
*/
|
|
2072
|
+
unregisterHandler(toolName) {
|
|
2073
|
+
return this.handlers.delete(toolName);
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* List registered core tool names.
|
|
2077
|
+
*/
|
|
2078
|
+
getRegisteredTools() {
|
|
2079
|
+
return Array.from(this.handlers.keys());
|
|
2080
|
+
}
|
|
2081
|
+
/**
|
|
2082
|
+
* Invoke dispatches to the appropriate handler by spec.name.
|
|
2083
|
+
*/
|
|
2084
|
+
async invoke(spec, args, ctx) {
|
|
2085
|
+
const handler = this.handlers.get(spec.name);
|
|
2086
|
+
if (!handler) {
|
|
2087
|
+
throw new Error(
|
|
2088
|
+
`Core tool handler not found: ${spec.name}. Available: [${this.getRegisteredTools().join(", ")}]`
|
|
2089
|
+
);
|
|
2090
|
+
}
|
|
2091
|
+
const coreCtx = {
|
|
2092
|
+
execCtx: ctx,
|
|
2093
|
+
config: this.config
|
|
2094
|
+
};
|
|
2095
|
+
const output = await runWithBuiltinContext(
|
|
2096
|
+
coreCtx,
|
|
2097
|
+
() => handler(args)
|
|
2098
|
+
);
|
|
2099
|
+
return {
|
|
2100
|
+
result: output.result,
|
|
2101
|
+
raw: { evidence: output.evidence }
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
|
|
2106
|
+
// CoreToolsModule.ts
|
|
2107
|
+
var import_core = require("@easynet/agent-tool/core");
|
|
2108
|
+
|
|
2109
|
+
// types.ts
|
|
2110
|
+
var DEFAULT_CORE_TOOLS_CONFIG = {
|
|
2111
|
+
maxReadBytes: 5 * 1024 * 1024,
|
|
2112
|
+
maxHttpBytes: 5 * 1024 * 1024,
|
|
2113
|
+
maxDownloadBytes: 100 * 1024 * 1024,
|
|
2114
|
+
blockedCidrs: [
|
|
2115
|
+
"127.0.0.0/8",
|
|
2116
|
+
"10.0.0.0/8",
|
|
2117
|
+
"172.16.0.0/12",
|
|
2118
|
+
"192.168.0.0/16",
|
|
2119
|
+
"169.254.0.0/16",
|
|
2120
|
+
"::1/128",
|
|
2121
|
+
"fc00::/7",
|
|
2122
|
+
"fe80::/10"
|
|
2123
|
+
],
|
|
2124
|
+
defaultTimeoutMs: 15e3,
|
|
2125
|
+
httpUserAgent: "agent-tool-core/1.0",
|
|
2126
|
+
enableAutoWriteLargeResponses: false,
|
|
2127
|
+
allowedCommands: [
|
|
2128
|
+
"cat",
|
|
2129
|
+
"echo",
|
|
2130
|
+
"env",
|
|
2131
|
+
"find",
|
|
2132
|
+
"grep",
|
|
2133
|
+
"head",
|
|
2134
|
+
"ls",
|
|
2135
|
+
"pwd",
|
|
2136
|
+
"tail",
|
|
2137
|
+
"wc",
|
|
2138
|
+
"whoami"
|
|
2139
|
+
],
|
|
2140
|
+
maxCommandOutputBytes: 1024 * 1024,
|
|
2141
|
+
commandTimeoutMs: 1e4
|
|
2142
|
+
};
|
|
2143
|
+
|
|
2144
|
+
// fs/readText.ts
|
|
2145
|
+
var import_promises2 = require("fs/promises");
|
|
2146
|
+
|
|
2147
|
+
// security/sandbox.ts
|
|
2148
|
+
var import_node_path = require("path");
|
|
2149
|
+
var import_promises = require("fs/promises");
|
|
2150
|
+
var import_agent_tool = require("@easynet/agent-tool");
|
|
2151
|
+
async function resolveSandboxedPath(inputPath, sandboxRoot) {
|
|
2152
|
+
let normalizedRoot;
|
|
2153
|
+
try {
|
|
2154
|
+
normalizedRoot = await (0, import_promises.realpath)((0, import_node_path.resolve)(sandboxRoot));
|
|
2155
|
+
} catch {
|
|
2156
|
+
normalizedRoot = (0, import_node_path.normalize)((0, import_node_path.resolve)(sandboxRoot));
|
|
2157
|
+
}
|
|
2158
|
+
const resolved = (0, import_node_path.resolve)(normalizedRoot, inputPath);
|
|
2159
|
+
let real;
|
|
2160
|
+
try {
|
|
2161
|
+
await (0, import_promises.access)(resolved);
|
|
2162
|
+
real = await (0, import_promises.realpath)(resolved);
|
|
2163
|
+
} catch {
|
|
2164
|
+
const parentDir = (0, import_node_path.dirname)(resolved);
|
|
2165
|
+
let realParent;
|
|
2166
|
+
try {
|
|
2167
|
+
await (0, import_promises.access)(parentDir);
|
|
2168
|
+
realParent = await (0, import_promises.realpath)(parentDir);
|
|
2169
|
+
} catch {
|
|
2170
|
+
realParent = (0, import_node_path.normalize)(parentDir);
|
|
2171
|
+
}
|
|
2172
|
+
real = (0, import_node_path.resolve)(realParent, (0, import_node_path.basename)(resolved));
|
|
2173
|
+
}
|
|
2174
|
+
if (!isWithinRoot(real, normalizedRoot)) {
|
|
2175
|
+
throw (0, import_agent_tool.createTaggedError)(
|
|
2176
|
+
"PATH_OUTSIDE_SANDBOX",
|
|
2177
|
+
`Path "${inputPath}" resolves to "${real}" which is outside sandbox "${normalizedRoot}"`,
|
|
2178
|
+
{ inputPath, resolvedPath: real, sandboxRoot: normalizedRoot }
|
|
2179
|
+
);
|
|
2180
|
+
}
|
|
2181
|
+
return real;
|
|
2182
|
+
}
|
|
2183
|
+
function isWithinRoot(path, root) {
|
|
2184
|
+
const normalizedPath = (0, import_node_path.normalize)(path);
|
|
2185
|
+
const normalizedRoot = (0, import_node_path.normalize)(root);
|
|
2186
|
+
return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + "/");
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// fs/readText.ts
|
|
2190
|
+
var import_agent_tool2 = require("@easynet/agent-tool");
|
|
2191
|
+
var readTextHandler = (async (args) => {
|
|
2192
|
+
const ctx = getBuiltinContext();
|
|
2193
|
+
const inputPath = args.path;
|
|
2194
|
+
const maxBytes = args.maxBytes ?? ctx.config.maxReadBytes;
|
|
2195
|
+
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2196
|
+
const fileStat = await (0, import_promises2.stat)(resolvedPath);
|
|
2197
|
+
if (fileStat.size > maxBytes) {
|
|
2198
|
+
throw (0, import_agent_tool2.createTaggedError)(
|
|
2199
|
+
"FILE_TOO_LARGE",
|
|
2200
|
+
`File size ${fileStat.size} bytes exceeds limit of ${maxBytes} bytes`,
|
|
2201
|
+
{ path: resolvedPath, size: fileStat.size, limit: maxBytes }
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
const text = await (0, import_promises2.readFile)(resolvedPath, "utf-8");
|
|
2205
|
+
return {
|
|
2206
|
+
result: {
|
|
2207
|
+
path: resolvedPath,
|
|
2208
|
+
text,
|
|
2209
|
+
bytes: fileStat.size
|
|
2210
|
+
},
|
|
2211
|
+
evidence: [
|
|
2212
|
+
{
|
|
2213
|
+
type: "file",
|
|
2214
|
+
ref: resolvedPath,
|
|
2215
|
+
summary: `Read ${fileStat.size} bytes from ${resolvedPath}`,
|
|
2216
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2217
|
+
}
|
|
2218
|
+
]
|
|
2219
|
+
};
|
|
2220
|
+
});
|
|
2221
|
+
|
|
2222
|
+
// fs/writeText.ts
|
|
2223
|
+
var import_promises3 = require("fs/promises");
|
|
2224
|
+
var import_node_crypto = require("crypto");
|
|
2225
|
+
var import_node_path2 = require("path");
|
|
2226
|
+
var writeTextHandler = (async (args) => {
|
|
2227
|
+
const ctx = getBuiltinContext();
|
|
2228
|
+
const inputPath = args.path;
|
|
2229
|
+
const text = args.text;
|
|
2230
|
+
const overwrite = args.overwrite ?? false;
|
|
2231
|
+
const mkdirp = args.mkdirp ?? true;
|
|
2232
|
+
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2233
|
+
if (!overwrite) {
|
|
2234
|
+
const { access: access2 } = await import("fs/promises");
|
|
2235
|
+
try {
|
|
2236
|
+
await access2(resolvedPath);
|
|
2237
|
+
throw new Error(
|
|
2238
|
+
`File already exists: ${resolvedPath}. Set overwrite=true to allow overwriting.`
|
|
2239
|
+
);
|
|
2240
|
+
} catch (err) {
|
|
2241
|
+
if (err instanceof Error && !err.message.includes("already exists")) {
|
|
2242
|
+
} else {
|
|
2243
|
+
throw err;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
if (mkdirp) {
|
|
2248
|
+
await (0, import_promises3.mkdir)((0, import_node_path2.dirname)(resolvedPath), { recursive: true });
|
|
2249
|
+
}
|
|
2250
|
+
await (0, import_promises3.writeFile)(resolvedPath, text, "utf-8");
|
|
2251
|
+
const bytes = Buffer.byteLength(text, "utf-8");
|
|
2252
|
+
const sha256 = (0, import_node_crypto.createHash)("sha256").update(text).digest("hex");
|
|
2253
|
+
return {
|
|
2254
|
+
result: {
|
|
2255
|
+
path: resolvedPath,
|
|
2256
|
+
bytes,
|
|
2257
|
+
sha256
|
|
2258
|
+
},
|
|
2259
|
+
evidence: [
|
|
2260
|
+
{
|
|
2261
|
+
type: "file",
|
|
2262
|
+
ref: resolvedPath,
|
|
2263
|
+
summary: `Wrote ${bytes} bytes to ${resolvedPath} (sha256: ${sha256.slice(0, 12)}...)`,
|
|
2264
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2265
|
+
}
|
|
2266
|
+
]
|
|
2267
|
+
};
|
|
2268
|
+
});
|
|
2269
|
+
|
|
2270
|
+
// fs/listDir.ts
|
|
2271
|
+
var import_promises4 = require("fs/promises");
|
|
2272
|
+
var import_node_path3 = require("path");
|
|
2273
|
+
var listDirHandler = (async (args) => {
|
|
2274
|
+
const ctx = getBuiltinContext();
|
|
2275
|
+
const inputPath = args.path;
|
|
2276
|
+
const maxEntries = args.maxEntries ?? 2e3;
|
|
2277
|
+
const includeHidden = args.includeHidden ?? false;
|
|
2278
|
+
const recursive = args.recursive ?? false;
|
|
2279
|
+
const maxDepth = args.maxDepth ?? 5;
|
|
2280
|
+
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2281
|
+
const entries = [];
|
|
2282
|
+
let truncated = false;
|
|
2283
|
+
await walkDir(resolvedPath, "", entries, {
|
|
2284
|
+
maxEntries,
|
|
2285
|
+
includeHidden,
|
|
2286
|
+
recursive,
|
|
2287
|
+
maxDepth,
|
|
2288
|
+
currentDepth: 0,
|
|
2289
|
+
onTruncate: () => {
|
|
2290
|
+
truncated = true;
|
|
2291
|
+
}
|
|
2292
|
+
});
|
|
2293
|
+
return {
|
|
2294
|
+
result: {
|
|
2295
|
+
path: resolvedPath,
|
|
2296
|
+
entries,
|
|
2297
|
+
totalEntries: entries.length,
|
|
2298
|
+
truncated
|
|
2299
|
+
},
|
|
2300
|
+
evidence: [
|
|
2301
|
+
{
|
|
2302
|
+
type: "tool",
|
|
2303
|
+
ref: `core/fs.listDir:${resolvedPath}`,
|
|
2304
|
+
summary: `Listed ${entries.length} entries in ${resolvedPath}${truncated ? " (truncated)" : ""}`,
|
|
2305
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2306
|
+
}
|
|
2307
|
+
]
|
|
2308
|
+
};
|
|
2309
|
+
});
|
|
2310
|
+
async function walkDir(basePath, relativePath, entries, options) {
|
|
2311
|
+
if (entries.length >= options.maxEntries) {
|
|
2312
|
+
options.onTruncate();
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
const fullPath = relativePath ? (0, import_node_path3.resolve)(basePath, relativePath) : basePath;
|
|
2316
|
+
const dirEntries = await (0, import_promises4.readdir)(fullPath, { withFileTypes: true });
|
|
2317
|
+
for (const dirent of dirEntries) {
|
|
2318
|
+
if (entries.length >= options.maxEntries) {
|
|
2319
|
+
options.onTruncate();
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
if (!options.includeHidden && dirent.name.startsWith(".")) {
|
|
2323
|
+
continue;
|
|
2324
|
+
}
|
|
2325
|
+
const entryPath = (0, import_node_path3.join)(fullPath, dirent.name);
|
|
2326
|
+
const entryRelative = relativePath ? (0, import_node_path3.join)(relativePath, dirent.name) : dirent.name;
|
|
2327
|
+
let entryType;
|
|
2328
|
+
if (dirent.isSymbolicLink()) {
|
|
2329
|
+
entryType = "symlink";
|
|
2330
|
+
} else if (dirent.isDirectory()) {
|
|
2331
|
+
entryType = "directory";
|
|
2332
|
+
} else if (dirent.isFile()) {
|
|
2333
|
+
entryType = "file";
|
|
2334
|
+
} else {
|
|
2335
|
+
entryType = "other";
|
|
2336
|
+
}
|
|
2337
|
+
let size = 0;
|
|
2338
|
+
let mtime = "";
|
|
2339
|
+
try {
|
|
2340
|
+
const entryStat = await (0, import_promises4.stat)(entryPath);
|
|
2341
|
+
size = entryStat.size;
|
|
2342
|
+
mtime = entryStat.mtime.toISOString();
|
|
2343
|
+
} catch {
|
|
2344
|
+
}
|
|
2345
|
+
entries.push({
|
|
2346
|
+
name: entryRelative,
|
|
2347
|
+
type: entryType,
|
|
2348
|
+
size,
|
|
2349
|
+
mtime
|
|
2350
|
+
});
|
|
2351
|
+
if (options.recursive && entryType === "directory" && options.currentDepth < options.maxDepth) {
|
|
2352
|
+
await walkDir(basePath, entryRelative, entries, {
|
|
2353
|
+
...options,
|
|
2354
|
+
currentDepth: options.currentDepth + 1
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
// fs/searchText.ts
|
|
2361
|
+
var import_promises5 = require("fs/promises");
|
|
2362
|
+
var import_node_fs = require("fs");
|
|
2363
|
+
var import_node_readline = require("readline");
|
|
2364
|
+
var import_node_path4 = require("path");
|
|
2365
|
+
var searchTextHandler = (async (args) => {
|
|
2366
|
+
const ctx = getBuiltinContext();
|
|
2367
|
+
const rootPath = args.root;
|
|
2368
|
+
const query = args.query;
|
|
2369
|
+
const glob = args.glob ?? "**/*.{md,txt,log,json,ts,js,py,java,scala}";
|
|
2370
|
+
const maxMatches = args.maxMatches ?? 100;
|
|
2371
|
+
const maxFiles = args.maxFiles ?? 500;
|
|
2372
|
+
const resolvedRoot = await resolveSandboxedPath(rootPath, ctx.config.sandboxRoot);
|
|
2373
|
+
let regex;
|
|
2374
|
+
try {
|
|
2375
|
+
regex = new RegExp(query, "i");
|
|
2376
|
+
} catch {
|
|
2377
|
+
regex = new RegExp(escapeRegExp(query), "i");
|
|
2378
|
+
}
|
|
2379
|
+
const extensions = parseGlobExtensions(glob);
|
|
2380
|
+
const files = [];
|
|
2381
|
+
await collectFiles(resolvedRoot, files, { maxFiles, extensions });
|
|
2382
|
+
const matches = [];
|
|
2383
|
+
let filesScanned = 0;
|
|
2384
|
+
let truncated = false;
|
|
2385
|
+
for (const filePath of files) {
|
|
2386
|
+
if (matches.length >= maxMatches) {
|
|
2387
|
+
truncated = true;
|
|
2388
|
+
break;
|
|
2389
|
+
}
|
|
2390
|
+
filesScanned++;
|
|
2391
|
+
await searchFile(filePath, resolvedRoot, regex, matches, maxMatches);
|
|
2392
|
+
}
|
|
2393
|
+
if (matches.length >= maxMatches) {
|
|
2394
|
+
truncated = true;
|
|
2395
|
+
}
|
|
2396
|
+
return {
|
|
2397
|
+
result: {
|
|
2398
|
+
root: resolvedRoot,
|
|
2399
|
+
query,
|
|
2400
|
+
matches,
|
|
2401
|
+
totalMatches: matches.length,
|
|
2402
|
+
filesScanned,
|
|
2403
|
+
truncated
|
|
2404
|
+
},
|
|
2405
|
+
evidence: [
|
|
2406
|
+
{
|
|
2407
|
+
type: "tool",
|
|
2408
|
+
ref: `core/fs.searchText:${resolvedRoot}`,
|
|
2409
|
+
summary: `Found ${matches.length} matches in ${filesScanned} files under ${resolvedRoot}${truncated ? " (truncated)" : ""}`,
|
|
2410
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2411
|
+
}
|
|
2412
|
+
]
|
|
2413
|
+
};
|
|
2414
|
+
});
|
|
2415
|
+
async function collectFiles(dirPath, files, options) {
|
|
2416
|
+
if (files.length >= options.maxFiles) return;
|
|
2417
|
+
let entries;
|
|
2418
|
+
try {
|
|
2419
|
+
entries = await (0, import_promises5.readdir)(dirPath, { withFileTypes: true });
|
|
2420
|
+
} catch {
|
|
2421
|
+
return;
|
|
2422
|
+
}
|
|
2423
|
+
for (const entry of entries) {
|
|
2424
|
+
if (files.length >= options.maxFiles) return;
|
|
2425
|
+
const fullPath = (0, import_node_path4.join)(dirPath, entry.name);
|
|
2426
|
+
if (entry.isDirectory()) {
|
|
2427
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2428
|
+
await collectFiles(fullPath, files, options);
|
|
2429
|
+
} else if (entry.isFile()) {
|
|
2430
|
+
if (options.extensions.size > 0) {
|
|
2431
|
+
const ext = getExtension(entry.name);
|
|
2432
|
+
if (!ext || !options.extensions.has(ext)) continue;
|
|
2433
|
+
}
|
|
2434
|
+
files.push(fullPath);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
async function searchFile(filePath, root, regex, matches, maxMatches) {
|
|
2439
|
+
const fileStat = await (0, import_promises5.stat)(filePath).catch(() => null);
|
|
2440
|
+
if (!fileStat || fileStat.size > 1024 * 1024) return;
|
|
2441
|
+
const stream = (0, import_node_fs.createReadStream)(filePath, { encoding: "utf-8" });
|
|
2442
|
+
const rl = (0, import_node_readline.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
2443
|
+
let lineNo = 0;
|
|
2444
|
+
for await (const line of rl) {
|
|
2445
|
+
lineNo++;
|
|
2446
|
+
if (matches.length >= maxMatches) {
|
|
2447
|
+
stream.destroy();
|
|
2448
|
+
break;
|
|
2449
|
+
}
|
|
2450
|
+
if (regex.test(line)) {
|
|
2451
|
+
matches.push({
|
|
2452
|
+
file: (0, import_node_path4.relative)(root, filePath),
|
|
2453
|
+
lineNo,
|
|
2454
|
+
excerpt: line.slice(0, 200)
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
function parseGlobExtensions(glob) {
|
|
2460
|
+
const extensions = /* @__PURE__ */ new Set();
|
|
2461
|
+
const braceMatch = glob.match(/\*\.\{([^}]+)\}/);
|
|
2462
|
+
if (braceMatch) {
|
|
2463
|
+
for (const ext of braceMatch[1].split(",")) {
|
|
2464
|
+
extensions.add(ext.trim());
|
|
2465
|
+
}
|
|
2466
|
+
} else {
|
|
2467
|
+
const simpleMatch = glob.match(/\*\.(\w+)/);
|
|
2468
|
+
if (simpleMatch) {
|
|
2469
|
+
extensions.add(simpleMatch[1]);
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
return extensions;
|
|
2473
|
+
}
|
|
2474
|
+
function getExtension(filename) {
|
|
2475
|
+
const dotIdx = filename.lastIndexOf(".");
|
|
2476
|
+
if (dotIdx === -1 || dotIdx === 0) return null;
|
|
2477
|
+
return filename.slice(dotIdx + 1);
|
|
2478
|
+
}
|
|
2479
|
+
function escapeRegExp(str) {
|
|
2480
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
// fs/sha256.ts
|
|
2484
|
+
var import_node_fs2 = require("fs");
|
|
2485
|
+
var import_promises6 = require("fs/promises");
|
|
2486
|
+
var import_node_crypto2 = require("crypto");
|
|
2487
|
+
var sha256Handler = (async (args) => {
|
|
2488
|
+
const ctx = getBuiltinContext();
|
|
2489
|
+
const inputPath = args.path;
|
|
2490
|
+
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2491
|
+
const fileStat = await (0, import_promises6.stat)(resolvedPath);
|
|
2492
|
+
const hash = await new Promise((resolve3, reject) => {
|
|
2493
|
+
const hasher = (0, import_node_crypto2.createHash)("sha256");
|
|
2494
|
+
const stream = (0, import_node_fs2.createReadStream)(resolvedPath);
|
|
2495
|
+
stream.on("data", (chunk) => hasher.update(chunk));
|
|
2496
|
+
stream.on("end", () => resolve3(hasher.digest("hex")));
|
|
2497
|
+
stream.on("error", reject);
|
|
2498
|
+
});
|
|
2499
|
+
return {
|
|
2500
|
+
result: {
|
|
2501
|
+
sha256: hash,
|
|
2502
|
+
path: resolvedPath,
|
|
2503
|
+
bytes: fileStat.size
|
|
2504
|
+
},
|
|
2505
|
+
evidence: [
|
|
2506
|
+
{
|
|
2507
|
+
type: "file",
|
|
2508
|
+
ref: resolvedPath,
|
|
2509
|
+
summary: `SHA-256 of ${resolvedPath} (${fileStat.size} bytes): ${hash.slice(0, 16)}...`,
|
|
2510
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2511
|
+
}
|
|
2512
|
+
]
|
|
2513
|
+
};
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
// fs/deletePath.ts
|
|
2517
|
+
var import_promises7 = require("fs/promises");
|
|
2518
|
+
var deletePathHandler = (async (args) => {
|
|
2519
|
+
const ctx = getBuiltinContext();
|
|
2520
|
+
const inputPath = args.path;
|
|
2521
|
+
const recursive = args.recursive ?? false;
|
|
2522
|
+
const confirm = args.confirm;
|
|
2523
|
+
if (!confirm) {
|
|
2524
|
+
throw new Error(
|
|
2525
|
+
"Deletion not confirmed. Set confirm=true to proceed with deletion."
|
|
2526
|
+
);
|
|
2527
|
+
}
|
|
2528
|
+
const resolvedPath = await resolveSandboxedPath(inputPath, ctx.config.sandboxRoot);
|
|
2529
|
+
let realSandboxRoot;
|
|
2530
|
+
try {
|
|
2531
|
+
const { realpath: rp } = await import("fs/promises");
|
|
2532
|
+
realSandboxRoot = await rp(ctx.config.sandboxRoot);
|
|
2533
|
+
} catch {
|
|
2534
|
+
realSandboxRoot = ctx.config.sandboxRoot;
|
|
2535
|
+
}
|
|
2536
|
+
if (resolvedPath === realSandboxRoot) {
|
|
2537
|
+
throw new Error("Cannot delete the sandbox root directory.");
|
|
2538
|
+
}
|
|
2539
|
+
const fileStat = await (0, import_promises7.stat)(resolvedPath);
|
|
2540
|
+
const isDirectory = fileStat.isDirectory();
|
|
2541
|
+
if (isDirectory) {
|
|
2542
|
+
if (recursive) {
|
|
2543
|
+
await (0, import_promises7.rm)(resolvedPath, { recursive: true, force: true });
|
|
2544
|
+
} else {
|
|
2545
|
+
await (0, import_promises7.rmdir)(resolvedPath);
|
|
2546
|
+
}
|
|
2547
|
+
} else {
|
|
2548
|
+
await (0, import_promises7.unlink)(resolvedPath);
|
|
2549
|
+
}
|
|
2550
|
+
return {
|
|
2551
|
+
result: {
|
|
2552
|
+
path: resolvedPath,
|
|
2553
|
+
deleted: true,
|
|
2554
|
+
type: isDirectory ? "directory" : "file"
|
|
2555
|
+
},
|
|
2556
|
+
evidence: [
|
|
2557
|
+
{
|
|
2558
|
+
type: "file",
|
|
2559
|
+
ref: resolvedPath,
|
|
2560
|
+
summary: `Deleted ${isDirectory ? "directory" : "file"}: ${resolvedPath}${recursive ? " (recursive)" : ""}`,
|
|
2561
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2562
|
+
}
|
|
2563
|
+
]
|
|
2564
|
+
};
|
|
2565
|
+
});
|
|
2566
|
+
|
|
2567
|
+
// security/ssrf.ts
|
|
2568
|
+
var import_promises8 = require("dns/promises");
|
|
2569
|
+
var import_agent_tool3 = require("@easynet/agent-tool");
|
|
2570
|
+
async function validateUrl(url, allowedHosts, blockedCidrs) {
|
|
2571
|
+
let parsed;
|
|
2572
|
+
try {
|
|
2573
|
+
parsed = new URL(url);
|
|
2574
|
+
} catch {
|
|
2575
|
+
throw (0, import_agent_tool3.createTaggedError)(
|
|
2576
|
+
"HTTP_DISALLOWED_HOST",
|
|
2577
|
+
`Invalid URL: ${url}`,
|
|
2578
|
+
{ url }
|
|
2579
|
+
);
|
|
2580
|
+
}
|
|
2581
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2582
|
+
throw (0, import_agent_tool3.createTaggedError)(
|
|
2583
|
+
"HTTP_DISALLOWED_HOST",
|
|
2584
|
+
`Protocol not allowed: ${parsed.protocol}. Only http: and https: are supported.`,
|
|
2585
|
+
{ url, protocol: parsed.protocol }
|
|
2586
|
+
);
|
|
2587
|
+
}
|
|
2588
|
+
const hostname = parsed.hostname;
|
|
2589
|
+
if (!isHostAllowed(hostname, allowedHosts)) {
|
|
2590
|
+
throw (0, import_agent_tool3.createTaggedError)(
|
|
2591
|
+
"HTTP_DISALLOWED_HOST",
|
|
2592
|
+
`Host "${hostname}" is not in the allowed hosts list`,
|
|
2593
|
+
{ url, hostname, allowedHosts }
|
|
2594
|
+
);
|
|
2595
|
+
}
|
|
2596
|
+
try {
|
|
2597
|
+
const { address } = await (0, import_promises8.lookup)(hostname);
|
|
2598
|
+
if (isIpInBlockedCidrs(address, blockedCidrs)) {
|
|
2599
|
+
throw (0, import_agent_tool3.createTaggedError)(
|
|
2600
|
+
"HTTP_DISALLOWED_HOST",
|
|
2601
|
+
`Host "${hostname}" resolves to blocked IP: ${address}`,
|
|
2602
|
+
{ url, hostname, resolvedIp: address }
|
|
2603
|
+
);
|
|
2604
|
+
}
|
|
2605
|
+
} catch (err) {
|
|
2606
|
+
if (err instanceof Error && err.kind === "HTTP_DISALLOWED_HOST") {
|
|
2607
|
+
throw err;
|
|
2608
|
+
}
|
|
2609
|
+
throw (0, import_agent_tool3.createTaggedError)(
|
|
2610
|
+
"HTTP_DISALLOWED_HOST",
|
|
2611
|
+
`DNS resolution failed for host "${hostname}": ${err instanceof Error ? err.message : String(err)}`,
|
|
2612
|
+
{ url, hostname }
|
|
2613
|
+
);
|
|
2614
|
+
}
|
|
2615
|
+
return parsed;
|
|
2616
|
+
}
|
|
2617
|
+
function isHostAllowed(hostname, allowedHosts) {
|
|
2618
|
+
for (const pattern of allowedHosts) {
|
|
2619
|
+
if (pattern.startsWith("*.")) {
|
|
2620
|
+
const suffix = pattern.slice(1);
|
|
2621
|
+
if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
|
|
2622
|
+
return true;
|
|
2623
|
+
}
|
|
2624
|
+
} else if (hostname === pattern) {
|
|
2625
|
+
return true;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
return false;
|
|
2629
|
+
}
|
|
2630
|
+
function isIpInBlockedCidrs(ip, cidrs) {
|
|
2631
|
+
const normalizedIp = normalizeIp(ip);
|
|
2632
|
+
if (!normalizedIp) return false;
|
|
2633
|
+
for (const cidr of cidrs) {
|
|
2634
|
+
if (cidr.includes(":")) {
|
|
2635
|
+
if (!ip.includes(":")) continue;
|
|
2636
|
+
if (isIpv6InCidr(ip, cidr)) return true;
|
|
2637
|
+
} else {
|
|
2638
|
+
if (isIpv4InCidr(normalizedIp, cidr)) return true;
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
return false;
|
|
2642
|
+
}
|
|
2643
|
+
function normalizeIp(ip) {
|
|
2644
|
+
if (ip.startsWith("::ffff:")) {
|
|
2645
|
+
return ip.slice(7);
|
|
2646
|
+
}
|
|
2647
|
+
if (/^\d+\.\d+\.\d+\.\d+$/.test(ip)) {
|
|
2648
|
+
return ip;
|
|
2649
|
+
}
|
|
2650
|
+
return null;
|
|
2651
|
+
}
|
|
2652
|
+
function isIpv4InCidr(ip, cidr) {
|
|
2653
|
+
const [cidrIp, prefixStr] = cidr.split("/");
|
|
2654
|
+
if (!cidrIp || !prefixStr) return false;
|
|
2655
|
+
const prefix = parseInt(prefixStr, 10);
|
|
2656
|
+
if (isNaN(prefix) || prefix < 0 || prefix > 32) return false;
|
|
2657
|
+
const ipNum = ipv4ToNum(ip);
|
|
2658
|
+
const cidrNum = ipv4ToNum(cidrIp);
|
|
2659
|
+
if (ipNum === null || cidrNum === null) return false;
|
|
2660
|
+
const mask = prefix === 0 ? 0 : ~0 << 32 - prefix >>> 0;
|
|
2661
|
+
return (ipNum & mask) === (cidrNum & mask);
|
|
2662
|
+
}
|
|
2663
|
+
function ipv4ToNum(ip) {
|
|
2664
|
+
const parts = ip.split(".");
|
|
2665
|
+
if (parts.length !== 4) return null;
|
|
2666
|
+
let num = 0;
|
|
2667
|
+
for (const part of parts) {
|
|
2668
|
+
const n = parseInt(part, 10);
|
|
2669
|
+
if (isNaN(n) || n < 0 || n > 255) return null;
|
|
2670
|
+
num = num << 8 | n;
|
|
2671
|
+
}
|
|
2672
|
+
return num >>> 0;
|
|
2673
|
+
}
|
|
2674
|
+
function isIpv6InCidr(ip, cidr) {
|
|
2675
|
+
const [cidrIp, prefixStr] = cidr.split("/");
|
|
2676
|
+
if (!cidrIp || !prefixStr) return false;
|
|
2677
|
+
const prefix = parseInt(prefixStr, 10);
|
|
2678
|
+
if (isNaN(prefix)) return false;
|
|
2679
|
+
const ipBytes = expandIpv6(ip);
|
|
2680
|
+
const cidrBytes = expandIpv6(cidrIp);
|
|
2681
|
+
if (!ipBytes || !cidrBytes) return false;
|
|
2682
|
+
const fullBytes = Math.floor(prefix / 8);
|
|
2683
|
+
for (let i = 0; i < fullBytes && i < 16; i++) {
|
|
2684
|
+
if (ipBytes[i] !== cidrBytes[i]) return false;
|
|
2685
|
+
}
|
|
2686
|
+
const remainingBits = prefix % 8;
|
|
2687
|
+
if (remainingBits > 0 && fullBytes < 16) {
|
|
2688
|
+
const mask = ~0 << 8 - remainingBits & 255;
|
|
2689
|
+
if ((ipBytes[fullBytes] & mask) !== (cidrBytes[fullBytes] & mask)) return false;
|
|
2690
|
+
}
|
|
2691
|
+
return true;
|
|
2692
|
+
}
|
|
2693
|
+
function expandIpv6(ip) {
|
|
2694
|
+
const zoneIdx = ip.indexOf("%");
|
|
2695
|
+
if (zoneIdx !== -1) ip = ip.slice(0, zoneIdx);
|
|
2696
|
+
const parts = ip.split("::");
|
|
2697
|
+
if (parts.length > 2) return null;
|
|
2698
|
+
const bytes = new Array(16).fill(0);
|
|
2699
|
+
const expandGroup = (group) => {
|
|
2700
|
+
if (!group) return [];
|
|
2701
|
+
return group.split(":").flatMap((hex) => {
|
|
2702
|
+
const val = parseInt(hex || "0", 16);
|
|
2703
|
+
return [val >> 8 & 255, val & 255];
|
|
2704
|
+
});
|
|
2705
|
+
};
|
|
2706
|
+
if (parts.length === 1) {
|
|
2707
|
+
const expanded = expandGroup(parts[0]);
|
|
2708
|
+
if (expanded.length !== 16) return null;
|
|
2709
|
+
return expanded;
|
|
2710
|
+
}
|
|
2711
|
+
const left = expandGroup(parts[0]);
|
|
2712
|
+
const right = expandGroup(parts[1]);
|
|
2713
|
+
if (left.length + right.length > 16) return null;
|
|
2714
|
+
for (let i = 0; i < left.length; i++) bytes[i] = left[i];
|
|
2715
|
+
for (let i = 0; i < right.length; i++) bytes[16 - right.length + i] = right[i];
|
|
2716
|
+
return bytes;
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
// http/fetchText.ts
|
|
2720
|
+
var import_agent_tool4 = require("@easynet/agent-tool");
|
|
2721
|
+
var fetchTextHandler = (async (args) => {
|
|
2722
|
+
const ctx = getBuiltinContext();
|
|
2723
|
+
const url = args.url;
|
|
2724
|
+
const method = args.method ?? "GET";
|
|
2725
|
+
const headers = args.headers ?? {};
|
|
2726
|
+
const body = args.body ?? void 0;
|
|
2727
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2728
|
+
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
2729
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
2730
|
+
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
2731
|
+
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
2732
|
+
}
|
|
2733
|
+
const controller = new AbortController();
|
|
2734
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2735
|
+
let response;
|
|
2736
|
+
try {
|
|
2737
|
+
response = await fetch(url, {
|
|
2738
|
+
method,
|
|
2739
|
+
headers,
|
|
2740
|
+
body: body ?? void 0,
|
|
2741
|
+
signal: controller.signal
|
|
2742
|
+
});
|
|
2743
|
+
} catch (err) {
|
|
2744
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
2745
|
+
throw (0, import_agent_tool4.createTaggedError)(
|
|
2746
|
+
"HTTP_TIMEOUT",
|
|
2747
|
+
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
2748
|
+
{ url, timeoutMs }
|
|
2749
|
+
);
|
|
2750
|
+
}
|
|
2751
|
+
throw (0, import_agent_tool4.createTaggedError)(
|
|
2752
|
+
"UPSTREAM_ERROR",
|
|
2753
|
+
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2754
|
+
{ url }
|
|
2755
|
+
);
|
|
2756
|
+
} finally {
|
|
2757
|
+
clearTimeout(timer);
|
|
2758
|
+
}
|
|
2759
|
+
const contentLength = response.headers.get("content-length");
|
|
2760
|
+
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
2761
|
+
throw (0, import_agent_tool4.createTaggedError)(
|
|
2762
|
+
"HTTP_TOO_LARGE",
|
|
2763
|
+
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
2764
|
+
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
2765
|
+
);
|
|
2766
|
+
}
|
|
2767
|
+
const text = await readResponseWithLimit(response, maxBytes, url);
|
|
2768
|
+
const bytes = Buffer.byteLength(text, "utf-8");
|
|
2769
|
+
const responseHeaders = {};
|
|
2770
|
+
response.headers.forEach((value, key) => {
|
|
2771
|
+
responseHeaders[key] = value;
|
|
2772
|
+
});
|
|
2773
|
+
return {
|
|
2774
|
+
result: {
|
|
2775
|
+
url,
|
|
2776
|
+
status: response.status,
|
|
2777
|
+
headers: responseHeaders,
|
|
2778
|
+
text,
|
|
2779
|
+
bytes
|
|
2780
|
+
},
|
|
2781
|
+
evidence: [
|
|
2782
|
+
{
|
|
2783
|
+
type: "url",
|
|
2784
|
+
ref: url,
|
|
2785
|
+
summary: `${method} ${url} \u2192 ${response.status} (${bytes} bytes)`,
|
|
2786
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2787
|
+
}
|
|
2788
|
+
]
|
|
2789
|
+
};
|
|
2790
|
+
});
|
|
2791
|
+
async function readResponseWithLimit(response, maxBytes, url) {
|
|
2792
|
+
if (!response.body) {
|
|
2793
|
+
return response.text();
|
|
2794
|
+
}
|
|
2795
|
+
const reader = response.body.getReader();
|
|
2796
|
+
const decoder = new TextDecoder();
|
|
2797
|
+
const chunks = [];
|
|
2798
|
+
let totalBytes = 0;
|
|
2799
|
+
try {
|
|
2800
|
+
while (true) {
|
|
2801
|
+
const { done, value } = await reader.read();
|
|
2802
|
+
if (done) break;
|
|
2803
|
+
totalBytes += value.byteLength;
|
|
2804
|
+
if (totalBytes > maxBytes) {
|
|
2805
|
+
reader.cancel();
|
|
2806
|
+
throw (0, import_agent_tool4.createTaggedError)(
|
|
2807
|
+
"HTTP_TOO_LARGE",
|
|
2808
|
+
`Response body exceeded limit of ${maxBytes} bytes while reading from ${url}`,
|
|
2809
|
+
{ url, bytesRead: totalBytes, limit: maxBytes }
|
|
2810
|
+
);
|
|
2811
|
+
}
|
|
2812
|
+
chunks.push(decoder.decode(value, { stream: true }));
|
|
2813
|
+
}
|
|
2814
|
+
chunks.push(decoder.decode());
|
|
2815
|
+
} finally {
|
|
2816
|
+
reader.releaseLock();
|
|
2817
|
+
}
|
|
2818
|
+
return chunks.join("");
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// http/fetchJson.ts
|
|
2822
|
+
var import_agent_tool5 = require("@easynet/agent-tool");
|
|
2823
|
+
var fetchJsonHandler = (async (args) => {
|
|
2824
|
+
const ctx = getBuiltinContext();
|
|
2825
|
+
const url = args.url;
|
|
2826
|
+
const method = args.method ?? "GET";
|
|
2827
|
+
const headers = args.headers ?? {};
|
|
2828
|
+
const body = args.body ?? void 0;
|
|
2829
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2830
|
+
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
2831
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
2832
|
+
if (!headers["Accept"] && !headers["accept"]) {
|
|
2833
|
+
headers["Accept"] = "application/json";
|
|
2834
|
+
}
|
|
2835
|
+
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
2836
|
+
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
2837
|
+
}
|
|
2838
|
+
const controller = new AbortController();
|
|
2839
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2840
|
+
let response;
|
|
2841
|
+
try {
|
|
2842
|
+
response = await fetch(url, {
|
|
2843
|
+
method,
|
|
2844
|
+
headers,
|
|
2845
|
+
body: body ?? void 0,
|
|
2846
|
+
signal: controller.signal
|
|
2847
|
+
});
|
|
2848
|
+
} catch (err) {
|
|
2849
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
2850
|
+
throw (0, import_agent_tool5.createTaggedError)(
|
|
2851
|
+
"HTTP_TIMEOUT",
|
|
2852
|
+
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
2853
|
+
{ url, timeoutMs }
|
|
2854
|
+
);
|
|
2855
|
+
}
|
|
2856
|
+
throw (0, import_agent_tool5.createTaggedError)(
|
|
2857
|
+
"UPSTREAM_ERROR",
|
|
2858
|
+
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2859
|
+
{ url }
|
|
2860
|
+
);
|
|
2861
|
+
} finally {
|
|
2862
|
+
clearTimeout(timer);
|
|
2863
|
+
}
|
|
2864
|
+
const contentLength = response.headers.get("content-length");
|
|
2865
|
+
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
2866
|
+
throw (0, import_agent_tool5.createTaggedError)(
|
|
2867
|
+
"HTTP_TOO_LARGE",
|
|
2868
|
+
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
2869
|
+
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
const text = await response.text();
|
|
2873
|
+
const bytes = Buffer.byteLength(text, "utf-8");
|
|
2874
|
+
if (bytes > maxBytes) {
|
|
2875
|
+
throw (0, import_agent_tool5.createTaggedError)(
|
|
2876
|
+
"HTTP_TOO_LARGE",
|
|
2877
|
+
`Response body ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
2878
|
+
{ url, bytes, limit: maxBytes }
|
|
2879
|
+
);
|
|
2880
|
+
}
|
|
2881
|
+
let json;
|
|
2882
|
+
try {
|
|
2883
|
+
json = JSON.parse(text);
|
|
2884
|
+
} catch {
|
|
2885
|
+
throw (0, import_agent_tool5.createTaggedError)(
|
|
2886
|
+
"UPSTREAM_ERROR",
|
|
2887
|
+
`Failed to parse JSON response from ${url}: ${text.slice(0, 200)}`,
|
|
2888
|
+
{ url, status: response.status, textPreview: text.slice(0, 500) }
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
return {
|
|
2892
|
+
result: {
|
|
2893
|
+
url,
|
|
2894
|
+
status: response.status,
|
|
2895
|
+
json,
|
|
2896
|
+
bytes
|
|
2897
|
+
},
|
|
2898
|
+
evidence: [
|
|
2899
|
+
{
|
|
2900
|
+
type: "url",
|
|
2901
|
+
ref: url,
|
|
2902
|
+
summary: `${method} ${url} \u2192 ${response.status} JSON (${bytes} bytes)`,
|
|
2903
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2904
|
+
}
|
|
2905
|
+
]
|
|
2906
|
+
};
|
|
2907
|
+
});
|
|
2908
|
+
|
|
2909
|
+
// http/downloadFile.ts
|
|
2910
|
+
var import_promises9 = require("fs/promises");
|
|
2911
|
+
var import_node_crypto3 = require("crypto");
|
|
2912
|
+
var import_node_path5 = require("path");
|
|
2913
|
+
var import_agent_tool6 = require("@easynet/agent-tool");
|
|
2914
|
+
var downloadFileHandler = (async (args) => {
|
|
2915
|
+
const ctx = getBuiltinContext();
|
|
2916
|
+
const url = args.url;
|
|
2917
|
+
const destPath = args.destPath;
|
|
2918
|
+
const headers = args.headers ?? {};
|
|
2919
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
2920
|
+
const maxBytes = args.maxBytes ?? ctx.config.maxDownloadBytes;
|
|
2921
|
+
const overwrite = args.overwrite ?? false;
|
|
2922
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
2923
|
+
const resolvedDest = await resolveSandboxedPath(destPath, ctx.config.sandboxRoot);
|
|
2924
|
+
if (!overwrite) {
|
|
2925
|
+
const { access: access2 } = await import("fs/promises");
|
|
2926
|
+
try {
|
|
2927
|
+
await access2(resolvedDest);
|
|
2928
|
+
throw new Error(
|
|
2929
|
+
`File already exists: ${resolvedDest}. Set overwrite=true to allow overwriting.`
|
|
2930
|
+
);
|
|
2931
|
+
} catch (err) {
|
|
2932
|
+
if (err instanceof Error && !err.message.includes("already exists")) {
|
|
2933
|
+
} else {
|
|
2934
|
+
throw err;
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
2939
|
+
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
2940
|
+
}
|
|
2941
|
+
const controller = new AbortController();
|
|
2942
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2943
|
+
let response;
|
|
2944
|
+
try {
|
|
2945
|
+
response = await fetch(url, {
|
|
2946
|
+
method: "GET",
|
|
2947
|
+
headers,
|
|
2948
|
+
signal: controller.signal
|
|
2949
|
+
});
|
|
2950
|
+
} catch (err) {
|
|
2951
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
2952
|
+
throw (0, import_agent_tool6.createTaggedError)(
|
|
2953
|
+
"HTTP_TIMEOUT",
|
|
2954
|
+
`Download from ${url} timed out after ${timeoutMs}ms`,
|
|
2955
|
+
{ url, timeoutMs }
|
|
2956
|
+
);
|
|
2957
|
+
}
|
|
2958
|
+
throw (0, import_agent_tool6.createTaggedError)(
|
|
2959
|
+
"UPSTREAM_ERROR",
|
|
2960
|
+
`Download failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2961
|
+
{ url }
|
|
2962
|
+
);
|
|
2963
|
+
} finally {
|
|
2964
|
+
clearTimeout(timer);
|
|
2965
|
+
}
|
|
2966
|
+
const contentLength = response.headers.get("content-length");
|
|
2967
|
+
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
2968
|
+
throw (0, import_agent_tool6.createTaggedError)(
|
|
2969
|
+
"HTTP_TOO_LARGE",
|
|
2970
|
+
`Download Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
2971
|
+
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
2972
|
+
);
|
|
2973
|
+
}
|
|
2974
|
+
if (!response.body) {
|
|
2975
|
+
throw (0, import_agent_tool6.createTaggedError)("UPSTREAM_ERROR", `No response body from ${url}`, { url });
|
|
2976
|
+
}
|
|
2977
|
+
const reader = response.body.getReader();
|
|
2978
|
+
const chunks = [];
|
|
2979
|
+
let totalBytes = 0;
|
|
2980
|
+
const hasher = (0, import_node_crypto3.createHash)("sha256");
|
|
2981
|
+
try {
|
|
2982
|
+
while (true) {
|
|
2983
|
+
const { done, value } = await reader.read();
|
|
2984
|
+
if (done) break;
|
|
2985
|
+
totalBytes += value.byteLength;
|
|
2986
|
+
if (totalBytes > maxBytes) {
|
|
2987
|
+
reader.cancel();
|
|
2988
|
+
throw (0, import_agent_tool6.createTaggedError)(
|
|
2989
|
+
"HTTP_TOO_LARGE",
|
|
2990
|
+
`Download from ${url} exceeded limit of ${maxBytes} bytes (received ${totalBytes})`,
|
|
2991
|
+
{ url, bytesRead: totalBytes, limit: maxBytes }
|
|
2992
|
+
);
|
|
2993
|
+
}
|
|
2994
|
+
chunks.push(value);
|
|
2995
|
+
hasher.update(value);
|
|
2996
|
+
}
|
|
2997
|
+
} finally {
|
|
2998
|
+
reader.releaseLock();
|
|
2999
|
+
}
|
|
3000
|
+
const sha256 = hasher.digest("hex");
|
|
3001
|
+
await (0, import_promises9.mkdir)((0, import_node_path5.dirname)(resolvedDest), { recursive: true });
|
|
3002
|
+
const buffer = Buffer.concat(chunks);
|
|
3003
|
+
await (0, import_promises9.writeFile)(resolvedDest, buffer);
|
|
3004
|
+
return {
|
|
3005
|
+
result: {
|
|
3006
|
+
destPath: resolvedDest,
|
|
3007
|
+
bytes: totalBytes,
|
|
3008
|
+
sha256,
|
|
3009
|
+
status: response.status,
|
|
3010
|
+
url
|
|
3011
|
+
},
|
|
3012
|
+
evidence: [
|
|
3013
|
+
{
|
|
3014
|
+
type: "url",
|
|
3015
|
+
ref: url,
|
|
3016
|
+
summary: `Downloaded ${totalBytes} bytes from ${url}`,
|
|
3017
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3018
|
+
},
|
|
3019
|
+
{
|
|
3020
|
+
type: "file",
|
|
3021
|
+
ref: resolvedDest,
|
|
3022
|
+
summary: `Saved to ${resolvedDest} (sha256: ${sha256.slice(0, 12)}...)`,
|
|
3023
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3024
|
+
}
|
|
3025
|
+
]
|
|
3026
|
+
};
|
|
3027
|
+
});
|
|
3028
|
+
|
|
3029
|
+
// http/head.ts
|
|
3030
|
+
var import_agent_tool7 = require("@easynet/agent-tool");
|
|
3031
|
+
var headHandler = (async (args) => {
|
|
3032
|
+
const ctx = getBuiltinContext();
|
|
3033
|
+
const url = args.url;
|
|
3034
|
+
const headers = args.headers ?? {};
|
|
3035
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3036
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
3037
|
+
if (!headers["User-Agent"] && !headers["user-agent"]) {
|
|
3038
|
+
headers["User-Agent"] = ctx.config.httpUserAgent;
|
|
3039
|
+
}
|
|
3040
|
+
const controller = new AbortController();
|
|
3041
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3042
|
+
let response;
|
|
3043
|
+
try {
|
|
3044
|
+
response = await fetch(url, {
|
|
3045
|
+
method: "HEAD",
|
|
3046
|
+
headers,
|
|
3047
|
+
signal: controller.signal
|
|
3048
|
+
});
|
|
3049
|
+
} catch (err) {
|
|
3050
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
3051
|
+
throw (0, import_agent_tool7.createTaggedError)(
|
|
3052
|
+
"HTTP_TIMEOUT",
|
|
3053
|
+
`HEAD request to ${url} timed out after ${timeoutMs}ms`,
|
|
3054
|
+
{ url, timeoutMs }
|
|
3055
|
+
);
|
|
3056
|
+
}
|
|
3057
|
+
throw (0, import_agent_tool7.createTaggedError)(
|
|
3058
|
+
"UPSTREAM_ERROR",
|
|
3059
|
+
`HEAD request failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3060
|
+
{ url }
|
|
3061
|
+
);
|
|
3062
|
+
} finally {
|
|
3063
|
+
clearTimeout(timer);
|
|
3064
|
+
}
|
|
3065
|
+
const responseHeaders = {};
|
|
3066
|
+
response.headers.forEach((value, key) => {
|
|
3067
|
+
responseHeaders[key] = value;
|
|
3068
|
+
});
|
|
3069
|
+
return {
|
|
3070
|
+
result: {
|
|
3071
|
+
url,
|
|
3072
|
+
status: response.status,
|
|
3073
|
+
headers: responseHeaders
|
|
3074
|
+
},
|
|
3075
|
+
evidence: [
|
|
3076
|
+
{
|
|
3077
|
+
type: "url",
|
|
3078
|
+
ref: url,
|
|
3079
|
+
summary: `HEAD ${url} \u2192 ${response.status}`,
|
|
3080
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3081
|
+
}
|
|
3082
|
+
]
|
|
3083
|
+
};
|
|
3084
|
+
});
|
|
3085
|
+
|
|
3086
|
+
// http/duckduckgoSearch.ts
|
|
3087
|
+
var import_agent_tool8 = require("@easynet/agent-tool");
|
|
3088
|
+
var DUCKDUCKGO_API = "https://api.duckduckgo.com/";
|
|
3089
|
+
var duckduckgoSearchHandler = (async (args) => {
|
|
3090
|
+
const ctx = getBuiltinContext();
|
|
3091
|
+
const query = args.query?.trim();
|
|
3092
|
+
if (!query) {
|
|
3093
|
+
throw (0, import_agent_tool8.createTaggedError)("DUCKDUCKGO_INVALID", "query is required", {});
|
|
3094
|
+
}
|
|
3095
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3096
|
+
const maxResults = args.maxResults ?? 10;
|
|
3097
|
+
const url = `${DUCKDUCKGO_API}?q=${encodeURIComponent(query)}&format=json`;
|
|
3098
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
3099
|
+
const controller = new AbortController();
|
|
3100
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3101
|
+
let response;
|
|
3102
|
+
try {
|
|
3103
|
+
response = await fetch(url, {
|
|
3104
|
+
method: "GET",
|
|
3105
|
+
headers: { "User-Agent": ctx.config.httpUserAgent },
|
|
3106
|
+
signal: controller.signal
|
|
3107
|
+
});
|
|
3108
|
+
} catch (err) {
|
|
3109
|
+
clearTimeout(timer);
|
|
3110
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
3111
|
+
throw (0, import_agent_tool8.createTaggedError)(
|
|
3112
|
+
"HTTP_TIMEOUT",
|
|
3113
|
+
`DuckDuckGo search timed out after ${timeoutMs}ms`,
|
|
3114
|
+
{ query, timeoutMs }
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
throw (0, import_agent_tool8.createTaggedError)(
|
|
3118
|
+
"UPSTREAM_ERROR",
|
|
3119
|
+
`DuckDuckGo search failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3120
|
+
{ query }
|
|
3121
|
+
);
|
|
3122
|
+
}
|
|
3123
|
+
clearTimeout(timer);
|
|
3124
|
+
const maxBytes = ctx.config.maxHttpBytes;
|
|
3125
|
+
const text = await response.text();
|
|
3126
|
+
const bytes = Buffer.byteLength(text, "utf-8");
|
|
3127
|
+
if (bytes > maxBytes) {
|
|
3128
|
+
throw (0, import_agent_tool8.createTaggedError)(
|
|
3129
|
+
"HTTP_TOO_LARGE",
|
|
3130
|
+
`DuckDuckGo response ${bytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
3131
|
+
{ query, bytes, limit: maxBytes }
|
|
3132
|
+
);
|
|
3133
|
+
}
|
|
3134
|
+
let raw;
|
|
3135
|
+
try {
|
|
3136
|
+
raw = JSON.parse(text);
|
|
3137
|
+
} catch {
|
|
3138
|
+
throw (0, import_agent_tool8.createTaggedError)(
|
|
3139
|
+
"UPSTREAM_ERROR",
|
|
3140
|
+
`DuckDuckGo returned invalid JSON`,
|
|
3141
|
+
{ query, textPreview: text.slice(0, 200) }
|
|
3142
|
+
);
|
|
3143
|
+
}
|
|
3144
|
+
const results = [];
|
|
3145
|
+
if (Array.isArray(raw.Results)) {
|
|
3146
|
+
for (const r of raw.Results.slice(0, maxResults)) {
|
|
3147
|
+
if (r.FirstURL) {
|
|
3148
|
+
results.push({
|
|
3149
|
+
url: r.FirstURL,
|
|
3150
|
+
title: r.Text ?? r.FirstURL,
|
|
3151
|
+
snippet: r.Text
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
const relatedTopics = [];
|
|
3157
|
+
if (Array.isArray(raw.RelatedTopics)) {
|
|
3158
|
+
for (const t of raw.RelatedTopics.slice(0, maxResults)) {
|
|
3159
|
+
const text2 = t.Text ?? t.Result;
|
|
3160
|
+
if (text2) {
|
|
3161
|
+
relatedTopics.push({ text: text2, url: t.FirstURL });
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
const result = {
|
|
3166
|
+
query,
|
|
3167
|
+
abstract: raw.Abstract ?? raw.AbstractText ?? void 0,
|
|
3168
|
+
abstractUrl: raw.AbstractURL ?? void 0,
|
|
3169
|
+
abstractSource: raw.AbstractSource ?? void 0,
|
|
3170
|
+
heading: raw.Heading ?? void 0,
|
|
3171
|
+
results,
|
|
3172
|
+
relatedTopics
|
|
3173
|
+
};
|
|
3174
|
+
return {
|
|
3175
|
+
result,
|
|
3176
|
+
evidence: [
|
|
3177
|
+
{
|
|
3178
|
+
type: "url",
|
|
3179
|
+
ref: url,
|
|
3180
|
+
summary: `DuckDuckGo search: "${query}" \u2192 ${results.length} results`,
|
|
3181
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3182
|
+
}
|
|
3183
|
+
]
|
|
3184
|
+
};
|
|
3185
|
+
});
|
|
3186
|
+
|
|
3187
|
+
// http/fetchPageMainContent.ts
|
|
3188
|
+
var import_node_html_parser = require("node-html-parser");
|
|
3189
|
+
var import_agent_tool9 = require("@easynet/agent-tool");
|
|
3190
|
+
var MAIN_SELECTORS = [
|
|
3191
|
+
"main",
|
|
3192
|
+
"article",
|
|
3193
|
+
"[role='main']",
|
|
3194
|
+
"#content",
|
|
3195
|
+
"#main",
|
|
3196
|
+
".content",
|
|
3197
|
+
".main-content",
|
|
3198
|
+
".article-body",
|
|
3199
|
+
".post-content",
|
|
3200
|
+
".entry-content"
|
|
3201
|
+
];
|
|
3202
|
+
function extractMainContent(html) {
|
|
3203
|
+
const root = (0, import_node_html_parser.parse)(html, { comment: false });
|
|
3204
|
+
let title = "";
|
|
3205
|
+
const titleEl = root.querySelector("title");
|
|
3206
|
+
if (titleEl) {
|
|
3207
|
+
title = (titleEl.textContent ?? "").trim().replace(/\s+/g, " ");
|
|
3208
|
+
}
|
|
3209
|
+
let mainEl = null;
|
|
3210
|
+
for (const sel of MAIN_SELECTORS) {
|
|
3211
|
+
mainEl = root.querySelector(sel);
|
|
3212
|
+
if (mainEl) break;
|
|
3213
|
+
}
|
|
3214
|
+
if (!mainEl) {
|
|
3215
|
+
const body = root.querySelector("body");
|
|
3216
|
+
if (body) {
|
|
3217
|
+
for (const tag of ["script", "style", "nav", "header", "footer", "aside", "noscript", "iframe"]) {
|
|
3218
|
+
body.querySelectorAll(tag).forEach((el) => el.remove());
|
|
3219
|
+
}
|
|
3220
|
+
mainEl = body;
|
|
3221
|
+
} else {
|
|
3222
|
+
mainEl = root;
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
const text = (mainEl.textContent ?? "").trim().replace(/\s+/g, " ");
|
|
3226
|
+
return { title, mainContent: text };
|
|
3227
|
+
}
|
|
3228
|
+
var fetchPageMainContentHandler = (async (args) => {
|
|
3229
|
+
const ctx = getBuiltinContext();
|
|
3230
|
+
const url = args.url;
|
|
3231
|
+
const timeoutMs = args.timeoutMs ?? ctx.config.defaultTimeoutMs;
|
|
3232
|
+
const maxBytes = args.maxBytes ?? ctx.config.maxHttpBytes;
|
|
3233
|
+
await validateUrl(url, ctx.config.allowedHosts, ctx.config.blockedCidrs);
|
|
3234
|
+
const controller = new AbortController();
|
|
3235
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
3236
|
+
let response;
|
|
3237
|
+
try {
|
|
3238
|
+
response = await fetch(url, {
|
|
3239
|
+
method: "GET",
|
|
3240
|
+
headers: { "User-Agent": ctx.config.httpUserAgent },
|
|
3241
|
+
signal: controller.signal
|
|
3242
|
+
});
|
|
3243
|
+
} catch (err) {
|
|
3244
|
+
clearTimeout(timer);
|
|
3245
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
3246
|
+
throw (0, import_agent_tool9.createTaggedError)(
|
|
3247
|
+
"HTTP_TIMEOUT",
|
|
3248
|
+
`Request to ${url} timed out after ${timeoutMs}ms`,
|
|
3249
|
+
{ url, timeoutMs }
|
|
3250
|
+
);
|
|
3251
|
+
}
|
|
3252
|
+
throw (0, import_agent_tool9.createTaggedError)(
|
|
3253
|
+
"UPSTREAM_ERROR",
|
|
3254
|
+
`Fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3255
|
+
{ url }
|
|
3256
|
+
);
|
|
3257
|
+
}
|
|
3258
|
+
clearTimeout(timer);
|
|
3259
|
+
const contentLength = response.headers.get("content-length");
|
|
3260
|
+
if (contentLength && parseInt(contentLength, 10) > maxBytes) {
|
|
3261
|
+
throw (0, import_agent_tool9.createTaggedError)(
|
|
3262
|
+
"HTTP_TOO_LARGE",
|
|
3263
|
+
`Response Content-Length ${contentLength} exceeds limit of ${maxBytes} bytes`,
|
|
3264
|
+
{ url, contentLength: parseInt(contentLength, 10), limit: maxBytes }
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
const rawText = await response.text();
|
|
3268
|
+
const rawBytes = Buffer.byteLength(rawText, "utf-8");
|
|
3269
|
+
if (rawBytes > maxBytes) {
|
|
3270
|
+
throw (0, import_agent_tool9.createTaggedError)(
|
|
3271
|
+
"HTTP_TOO_LARGE",
|
|
3272
|
+
`Response body ${rawBytes} bytes exceeds limit of ${maxBytes} bytes`,
|
|
3273
|
+
{ url, bytes: rawBytes, limit: maxBytes }
|
|
3274
|
+
);
|
|
3275
|
+
}
|
|
3276
|
+
const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
|
|
3277
|
+
const isHtml = contentType.includes("text/html");
|
|
3278
|
+
let title;
|
|
3279
|
+
let mainContent;
|
|
3280
|
+
if (isHtml && rawText.trim().length > 0) {
|
|
3281
|
+
try {
|
|
3282
|
+
const extracted = extractMainContent(rawText);
|
|
3283
|
+
title = extracted.title || void 0;
|
|
3284
|
+
mainContent = extracted.mainContent;
|
|
3285
|
+
} catch {
|
|
3286
|
+
mainContent = rawText;
|
|
3287
|
+
}
|
|
3288
|
+
} else {
|
|
3289
|
+
mainContent = rawText;
|
|
3290
|
+
}
|
|
3291
|
+
const bytes = Buffer.byteLength(mainContent, "utf-8");
|
|
3292
|
+
return {
|
|
3293
|
+
result: {
|
|
3294
|
+
url,
|
|
3295
|
+
status: response.status,
|
|
3296
|
+
title,
|
|
3297
|
+
mainContent,
|
|
3298
|
+
bytes,
|
|
3299
|
+
isHtml
|
|
3300
|
+
},
|
|
3301
|
+
evidence: [
|
|
3302
|
+
{
|
|
3303
|
+
type: "url",
|
|
3304
|
+
ref: url,
|
|
3305
|
+
summary: `${url} \u2192 ${response.status} main content (${bytes} bytes)`,
|
|
3306
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3307
|
+
}
|
|
3308
|
+
]
|
|
3309
|
+
};
|
|
3310
|
+
});
|
|
3311
|
+
|
|
3312
|
+
// util/jsonSelect.ts
|
|
3313
|
+
var jsonSelectHandler = (async (args) => {
|
|
3314
|
+
const json = args.json;
|
|
3315
|
+
const path = args.path;
|
|
3316
|
+
let jmespath;
|
|
3317
|
+
try {
|
|
3318
|
+
jmespath = await Promise.resolve().then(() => __toESM(require_jmespath(), 1));
|
|
3319
|
+
} catch {
|
|
3320
|
+
throw new Error(
|
|
3321
|
+
"jmespath package is required for core/util.json.select. Install it with: npm install jmespath"
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
let value;
|
|
3325
|
+
try {
|
|
3326
|
+
value = jmespath.search(json, path);
|
|
3327
|
+
} catch (err) {
|
|
3328
|
+
throw new Error(
|
|
3329
|
+
`JMESPath expression error: ${err instanceof Error ? err.message : String(err)}`
|
|
3330
|
+
);
|
|
3331
|
+
}
|
|
3332
|
+
return {
|
|
3333
|
+
result: { value },
|
|
3334
|
+
evidence: [
|
|
3335
|
+
{
|
|
3336
|
+
type: "tool",
|
|
3337
|
+
ref: "core/util.json.select",
|
|
3338
|
+
summary: `Selected "${path}" from JSON \u2192 ${typeof value === "object" ? JSON.stringify(value).slice(0, 100) : String(value).slice(0, 100)}`,
|
|
3339
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3340
|
+
}
|
|
3341
|
+
]
|
|
3342
|
+
};
|
|
3343
|
+
});
|
|
3344
|
+
|
|
3345
|
+
// util/truncate.ts
|
|
3346
|
+
var truncateHandler = (async (args) => {
|
|
3347
|
+
const text = args.text;
|
|
3348
|
+
const maxChars = args.maxChars;
|
|
3349
|
+
const suffix = args.suffix ?? "...";
|
|
3350
|
+
const originalLength = text.length;
|
|
3351
|
+
if (text.length <= maxChars) {
|
|
3352
|
+
return {
|
|
3353
|
+
result: { text, truncated: false, originalLength },
|
|
3354
|
+
evidence: [
|
|
3355
|
+
{
|
|
3356
|
+
type: "tool",
|
|
3357
|
+
ref: "core/util.text.truncate",
|
|
3358
|
+
summary: `Text not truncated (${originalLength} chars <= ${maxChars} max)`,
|
|
3359
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3360
|
+
}
|
|
3361
|
+
]
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
const truncatedText = text.slice(0, maxChars - suffix.length) + suffix;
|
|
3365
|
+
return {
|
|
3366
|
+
result: { text: truncatedText, truncated: true, originalLength },
|
|
3367
|
+
evidence: [
|
|
3368
|
+
{
|
|
3369
|
+
type: "tool",
|
|
3370
|
+
ref: "core/util.text.truncate",
|
|
3371
|
+
summary: `Truncated ${originalLength} chars to ${truncatedText.length} chars`,
|
|
3372
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3373
|
+
}
|
|
3374
|
+
]
|
|
3375
|
+
};
|
|
3376
|
+
});
|
|
3377
|
+
|
|
3378
|
+
// util/hashText.ts
|
|
3379
|
+
var import_node_crypto4 = require("crypto");
|
|
3380
|
+
var hashTextHandler = (async (args) => {
|
|
3381
|
+
const text = args.text;
|
|
3382
|
+
const sha256 = (0, import_node_crypto4.createHash)("sha256").update(text, "utf-8").digest("hex");
|
|
3383
|
+
return {
|
|
3384
|
+
result: { sha256 },
|
|
3385
|
+
evidence: [
|
|
3386
|
+
{
|
|
3387
|
+
type: "tool",
|
|
3388
|
+
ref: "core/util.hash.sha256Text",
|
|
3389
|
+
summary: `SHA-256 of ${text.length} chars: ${sha256.slice(0, 16)}...`,
|
|
3390
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3391
|
+
}
|
|
3392
|
+
]
|
|
3393
|
+
};
|
|
3394
|
+
});
|
|
3395
|
+
|
|
3396
|
+
// util/now.ts
|
|
3397
|
+
var nowHandler = (async (args) => {
|
|
3398
|
+
const timezone = args.timezone ?? "UTC";
|
|
3399
|
+
const now = /* @__PURE__ */ new Date();
|
|
3400
|
+
let formatted;
|
|
3401
|
+
try {
|
|
3402
|
+
formatted = new Intl.DateTimeFormat("en-US", {
|
|
3403
|
+
timeZone: timezone,
|
|
3404
|
+
year: "numeric",
|
|
3405
|
+
month: "2-digit",
|
|
3406
|
+
day: "2-digit",
|
|
3407
|
+
hour: "2-digit",
|
|
3408
|
+
minute: "2-digit",
|
|
3409
|
+
second: "2-digit",
|
|
3410
|
+
hour12: false,
|
|
3411
|
+
timeZoneName: "short"
|
|
3412
|
+
}).format(now);
|
|
3413
|
+
} catch {
|
|
3414
|
+
formatted = now.toISOString();
|
|
3415
|
+
}
|
|
3416
|
+
return {
|
|
3417
|
+
result: {
|
|
3418
|
+
iso: now.toISOString(),
|
|
3419
|
+
epochMs: now.getTime(),
|
|
3420
|
+
timezone,
|
|
3421
|
+
formatted
|
|
3422
|
+
},
|
|
3423
|
+
evidence: [
|
|
3424
|
+
{
|
|
3425
|
+
type: "tool",
|
|
3426
|
+
ref: "core/util.time.now",
|
|
3427
|
+
summary: `Current time: ${now.toISOString()} (${timezone})`,
|
|
3428
|
+
createdAt: now.toISOString()
|
|
3429
|
+
}
|
|
3430
|
+
]
|
|
3431
|
+
};
|
|
3432
|
+
});
|
|
3433
|
+
|
|
3434
|
+
// util/templateRender.ts
|
|
3435
|
+
var templateRenderHandler = (async (args) => {
|
|
3436
|
+
const template = args.template;
|
|
3437
|
+
const data = args.data;
|
|
3438
|
+
let renderFn;
|
|
3439
|
+
try {
|
|
3440
|
+
const mod = await Promise.resolve().then(() => (init_mustache(), mustache_exports));
|
|
3441
|
+
const mustache2 = mod.default ?? mod;
|
|
3442
|
+
renderFn = mustache2.render.bind(mustache2);
|
|
3443
|
+
} catch {
|
|
3444
|
+
throw new Error(
|
|
3445
|
+
"mustache package is required for core/util.template.render. Install it with: npm install mustache"
|
|
3446
|
+
);
|
|
3447
|
+
}
|
|
3448
|
+
let text;
|
|
3449
|
+
try {
|
|
3450
|
+
text = renderFn(template, data);
|
|
3451
|
+
} catch (err) {
|
|
3452
|
+
throw new Error(
|
|
3453
|
+
`Template rendering error: ${err instanceof Error ? err.message : String(err)}`
|
|
3454
|
+
);
|
|
3455
|
+
}
|
|
3456
|
+
return {
|
|
3457
|
+
result: { text },
|
|
3458
|
+
evidence: [
|
|
3459
|
+
{
|
|
3460
|
+
type: "tool",
|
|
3461
|
+
ref: "core/util.template.render",
|
|
3462
|
+
summary: `Rendered template (${template.length} chars) \u2192 ${text.length} chars output`,
|
|
3463
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3464
|
+
}
|
|
3465
|
+
]
|
|
3466
|
+
};
|
|
3467
|
+
});
|
|
3468
|
+
|
|
3469
|
+
// exec/runCommand.ts
|
|
3470
|
+
var import_node_child_process = require("child_process");
|
|
3471
|
+
var import_node_path6 = require("path");
|
|
3472
|
+
var import_agent_tool10 = require("@easynet/agent-tool");
|
|
3473
|
+
var runCommandHandler = (async (args) => {
|
|
3474
|
+
const ctx = getBuiltinContext();
|
|
3475
|
+
const { allowedCommands, maxCommandOutputBytes, commandTimeoutMs } = ctx.config;
|
|
3476
|
+
if (!allowedCommands.length) {
|
|
3477
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
3478
|
+
"EXEC_DISABLED",
|
|
3479
|
+
"Exec is disabled: allowedCommands is empty",
|
|
3480
|
+
{}
|
|
3481
|
+
);
|
|
3482
|
+
}
|
|
3483
|
+
const rawCommand = args.command?.trim();
|
|
3484
|
+
if (!rawCommand) {
|
|
3485
|
+
throw (0, import_agent_tool10.createTaggedError)("EXEC_INVALID", "command is required", {});
|
|
3486
|
+
}
|
|
3487
|
+
const baseName = rawCommand.replace(/^.*\//, "").trim();
|
|
3488
|
+
if (baseName !== rawCommand || /[;&|$`\s]/.test(rawCommand)) {
|
|
3489
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
3490
|
+
"EXEC_INVALID",
|
|
3491
|
+
"command must be a single executable name (no path, no shell chars)",
|
|
3492
|
+
{ command: rawCommand }
|
|
3493
|
+
);
|
|
3494
|
+
}
|
|
3495
|
+
if (!allowedCommands.includes(baseName)) {
|
|
3496
|
+
throw (0, import_agent_tool10.createTaggedError)(
|
|
3497
|
+
"EXEC_NOT_ALLOWED",
|
|
3498
|
+
`Command "${baseName}" is not in allowedCommands`,
|
|
3499
|
+
{ command: baseName, allowed: allowedCommands }
|
|
3500
|
+
);
|
|
3501
|
+
}
|
|
3502
|
+
const cmdArgs = Array.isArray(args.args) ? args.args : [];
|
|
3503
|
+
const timeoutMs = args.timeoutMs ?? commandTimeoutMs;
|
|
3504
|
+
let cwd = (0, import_node_path6.resolve)(ctx.config.sandboxRoot);
|
|
3505
|
+
if (args.cwd != null && args.cwd !== "") {
|
|
3506
|
+
cwd = await resolveSandboxedPath(args.cwd, ctx.config.sandboxRoot);
|
|
3507
|
+
}
|
|
3508
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
3509
|
+
const proc = (0, import_node_child_process.spawn)(baseName, cmdArgs, {
|
|
3510
|
+
cwd,
|
|
3511
|
+
shell: false,
|
|
3512
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3513
|
+
env: { ...process.env }
|
|
3514
|
+
});
|
|
3515
|
+
let stdout = "";
|
|
3516
|
+
let stderr = "";
|
|
3517
|
+
let totalBytes = 0;
|
|
3518
|
+
const append = (chunk, dest) => {
|
|
3519
|
+
const len = Buffer.byteLength(chunk, "utf-8");
|
|
3520
|
+
if (totalBytes + len > maxCommandOutputBytes) {
|
|
3521
|
+
proc.kill("SIGKILL");
|
|
3522
|
+
rejectPromise(
|
|
3523
|
+
(0, import_agent_tool10.createTaggedError)(
|
|
3524
|
+
"EXEC_OUTPUT_TOO_LARGE",
|
|
3525
|
+
`Command output exceeded ${maxCommandOutputBytes} bytes`,
|
|
3526
|
+
{ maxBytes: maxCommandOutputBytes }
|
|
3527
|
+
)
|
|
3528
|
+
);
|
|
3529
|
+
return;
|
|
3530
|
+
}
|
|
3531
|
+
totalBytes += len;
|
|
3532
|
+
if (dest === "stdout") stdout += chunk;
|
|
3533
|
+
else stderr += chunk;
|
|
3534
|
+
};
|
|
3535
|
+
proc.stdout?.setEncoding("utf-8");
|
|
3536
|
+
proc.stderr?.setEncoding("utf-8");
|
|
3537
|
+
proc.stdout?.on("data", (chunk) => append(chunk, "stdout"));
|
|
3538
|
+
proc.stderr?.on("data", (chunk) => append(chunk, "stderr"));
|
|
3539
|
+
const timeout = setTimeout(() => {
|
|
3540
|
+
proc.kill("SIGKILL");
|
|
3541
|
+
resolvePromise({
|
|
3542
|
+
result: {
|
|
3543
|
+
stdout,
|
|
3544
|
+
stderr,
|
|
3545
|
+
exitCode: null,
|
|
3546
|
+
timedOut: true,
|
|
3547
|
+
signal: "SIGKILL"
|
|
3548
|
+
},
|
|
3549
|
+
evidence: [
|
|
3550
|
+
{
|
|
3551
|
+
type: "exec",
|
|
3552
|
+
summary: `Command "${baseName}" timed out after ${timeoutMs}ms`,
|
|
3553
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3554
|
+
}
|
|
3555
|
+
]
|
|
3556
|
+
});
|
|
3557
|
+
}, timeoutMs);
|
|
3558
|
+
proc.on("error", (err) => {
|
|
3559
|
+
clearTimeout(timeout);
|
|
3560
|
+
rejectPromise(
|
|
3561
|
+
(0, import_agent_tool10.createTaggedError)("EXEC_SPAWN_ERROR", err.message, { command: baseName })
|
|
3562
|
+
);
|
|
3563
|
+
});
|
|
3564
|
+
proc.on("close", (code, signal) => {
|
|
3565
|
+
clearTimeout(timeout);
|
|
3566
|
+
resolvePromise({
|
|
3567
|
+
result: {
|
|
3568
|
+
stdout,
|
|
3569
|
+
stderr,
|
|
3570
|
+
exitCode: code,
|
|
3571
|
+
timedOut: false,
|
|
3572
|
+
signal: signal ?? void 0
|
|
3573
|
+
},
|
|
3574
|
+
evidence: [
|
|
3575
|
+
{
|
|
3576
|
+
type: "exec",
|
|
3577
|
+
ref: baseName,
|
|
3578
|
+
summary: `Ran ${baseName} (exit ${code ?? signal})`,
|
|
3579
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3580
|
+
}
|
|
3581
|
+
]
|
|
3582
|
+
});
|
|
3583
|
+
});
|
|
3584
|
+
});
|
|
3585
|
+
});
|
|
3586
|
+
|
|
3587
|
+
// CoreToolsModule.ts
|
|
3588
|
+
var CORE_TOOL_MANIFEST = [
|
|
3589
|
+
// Filesystem
|
|
3590
|
+
{
|
|
3591
|
+
name: "core/fs.readText",
|
|
3592
|
+
kind: "core",
|
|
3593
|
+
description: "Read a UTF-8 text file from the sandbox",
|
|
3594
|
+
tags: ["filesystem", "read", "core"],
|
|
3595
|
+
capabilities: ["read:fs"],
|
|
3596
|
+
sideEffect: "none"
|
|
3597
|
+
},
|
|
3598
|
+
{
|
|
3599
|
+
name: "core/fs.writeText",
|
|
3600
|
+
kind: "core",
|
|
3601
|
+
description: "Write UTF-8 text to a file in the sandbox",
|
|
3602
|
+
tags: ["filesystem", "write", "core"],
|
|
3603
|
+
capabilities: ["write:fs"],
|
|
3604
|
+
sideEffect: "local_write"
|
|
3605
|
+
},
|
|
3606
|
+
{
|
|
3607
|
+
name: "core/fs.listDir",
|
|
3608
|
+
kind: "core",
|
|
3609
|
+
description: "List directory contents in the sandbox",
|
|
3610
|
+
tags: ["filesystem", "read", "core"],
|
|
3611
|
+
capabilities: ["read:fs"],
|
|
3612
|
+
sideEffect: "none"
|
|
3613
|
+
},
|
|
3614
|
+
{
|
|
3615
|
+
name: "core/fs.searchText",
|
|
3616
|
+
kind: "core",
|
|
3617
|
+
description: "Search for text patterns in files within the sandbox",
|
|
3618
|
+
tags: ["filesystem", "search", "core"],
|
|
3619
|
+
capabilities: ["read:fs"],
|
|
3620
|
+
sideEffect: "none"
|
|
3621
|
+
},
|
|
3622
|
+
{
|
|
3623
|
+
name: "core/fs.sha256",
|
|
3624
|
+
kind: "core",
|
|
3625
|
+
description: "Compute SHA-256 hash of a file in the sandbox",
|
|
3626
|
+
tags: ["filesystem", "hash", "core"],
|
|
3627
|
+
capabilities: ["read:fs"],
|
|
3628
|
+
sideEffect: "none"
|
|
3629
|
+
},
|
|
3630
|
+
{
|
|
3631
|
+
name: "core/fs.deletePath",
|
|
3632
|
+
kind: "core",
|
|
3633
|
+
description: "Delete a file or directory in the sandbox (dangerous, requires explicit confirmation)",
|
|
3634
|
+
tags: ["filesystem", "delete", "dangerous", "core"],
|
|
3635
|
+
capabilities: ["danger:destructive", "write:fs"],
|
|
3636
|
+
sideEffect: "destructive"
|
|
3637
|
+
},
|
|
3638
|
+
// HTTP
|
|
3639
|
+
{
|
|
3640
|
+
name: "core/http.fetchText",
|
|
3641
|
+
kind: "core",
|
|
3642
|
+
description: "Fetch a URL and return the response as text",
|
|
3643
|
+
tags: ["http", "network", "core"],
|
|
3644
|
+
capabilities: ["network"],
|
|
3645
|
+
sideEffect: "none"
|
|
3646
|
+
},
|
|
3647
|
+
{
|
|
3648
|
+
name: "core/http.fetchJson",
|
|
3649
|
+
kind: "core",
|
|
3650
|
+
description: "Fetch a URL and return the response as parsed JSON",
|
|
3651
|
+
tags: ["http", "network", "json", "core"],
|
|
3652
|
+
capabilities: ["network"],
|
|
3653
|
+
sideEffect: "none"
|
|
3654
|
+
},
|
|
3655
|
+
{
|
|
3656
|
+
name: "core/http.downloadFile",
|
|
3657
|
+
kind: "core",
|
|
3658
|
+
description: "Download a file from a URL to the sandbox",
|
|
3659
|
+
tags: ["http", "network", "download", "core"],
|
|
3660
|
+
capabilities: ["network", "write:fs"],
|
|
3661
|
+
sideEffect: "local_write"
|
|
3662
|
+
},
|
|
3663
|
+
{
|
|
3664
|
+
name: "core/http.head",
|
|
3665
|
+
kind: "core",
|
|
3666
|
+
description: "Send a HEAD request to get response headers without body",
|
|
3667
|
+
tags: ["http", "network", "core"],
|
|
3668
|
+
capabilities: ["network"],
|
|
3669
|
+
sideEffect: "none"
|
|
3670
|
+
},
|
|
3671
|
+
{
|
|
3672
|
+
name: "core/http.duckduckgoSearch",
|
|
3673
|
+
kind: "core",
|
|
3674
|
+
description: "Search DuckDuckGo via Instant Answer API (no API key). Add api.duckduckgo.com to allowedHosts.",
|
|
3675
|
+
tags: ["http", "search", "duckduckgo", "core"],
|
|
3676
|
+
capabilities: ["network"],
|
|
3677
|
+
sideEffect: "none"
|
|
3678
|
+
},
|
|
3679
|
+
{
|
|
3680
|
+
name: "core/http.fetchPageMainContent",
|
|
3681
|
+
kind: "core",
|
|
3682
|
+
description: "Fetch a URL and return only the main content (main/article/body text). Strips nav, header, footer, scripts.",
|
|
3683
|
+
tags: ["http", "network", "html", "main-content", "core"],
|
|
3684
|
+
capabilities: ["network"],
|
|
3685
|
+
sideEffect: "none"
|
|
3686
|
+
},
|
|
3687
|
+
// Utils
|
|
3688
|
+
{
|
|
3689
|
+
name: "core/util.json.select",
|
|
3690
|
+
kind: "core",
|
|
3691
|
+
description: "Select fields from JSON data using JMESPath expressions",
|
|
3692
|
+
tags: ["util", "json", "core"],
|
|
3693
|
+
capabilities: [],
|
|
3694
|
+
sideEffect: "none"
|
|
3695
|
+
},
|
|
3696
|
+
{
|
|
3697
|
+
name: "core/util.text.truncate",
|
|
3698
|
+
kind: "core",
|
|
3699
|
+
description: "Truncate text to a maximum character length with a suffix marker",
|
|
3700
|
+
tags: ["util", "text", "core"],
|
|
3701
|
+
capabilities: [],
|
|
3702
|
+
sideEffect: "none"
|
|
3703
|
+
},
|
|
3704
|
+
{
|
|
3705
|
+
name: "core/util.hash.sha256Text",
|
|
3706
|
+
kind: "core",
|
|
3707
|
+
description: "Compute SHA-256 hash of a text string",
|
|
3708
|
+
tags: ["util", "hash", "core"],
|
|
3709
|
+
capabilities: [],
|
|
3710
|
+
sideEffect: "none"
|
|
3711
|
+
},
|
|
3712
|
+
{
|
|
3713
|
+
name: "core/util.time.now",
|
|
3714
|
+
kind: "core",
|
|
3715
|
+
description: "Get the current time in various formats",
|
|
3716
|
+
tags: ["util", "time", "core"],
|
|
3717
|
+
capabilities: [],
|
|
3718
|
+
sideEffect: "none"
|
|
3719
|
+
},
|
|
3720
|
+
{
|
|
3721
|
+
name: "core/util.template.render",
|
|
3722
|
+
kind: "core",
|
|
3723
|
+
description: "Render a Mustache template with data",
|
|
3724
|
+
tags: ["util", "template", "core"],
|
|
3725
|
+
capabilities: [],
|
|
3726
|
+
sideEffect: "none"
|
|
3727
|
+
},
|
|
3728
|
+
// Exec
|
|
3729
|
+
{
|
|
3730
|
+
name: "core/exec.runCommand",
|
|
3731
|
+
kind: "core",
|
|
3732
|
+
description: "Run a Linux command in the sandbox (allowlist, timeout, no shell). Command name only; args as array.",
|
|
3733
|
+
tags: ["exec", "shell", "linux", "core"],
|
|
3734
|
+
capabilities: ["exec"],
|
|
3735
|
+
sideEffect: "local_write"
|
|
3736
|
+
}
|
|
3737
|
+
];
|
|
3738
|
+
var CORE_TOOL_HANDLERS = [
|
|
3739
|
+
readTextHandler,
|
|
3740
|
+
writeTextHandler,
|
|
3741
|
+
listDirHandler,
|
|
3742
|
+
searchTextHandler,
|
|
3743
|
+
sha256Handler,
|
|
3744
|
+
deletePathHandler,
|
|
3745
|
+
fetchTextHandler,
|
|
3746
|
+
fetchJsonHandler,
|
|
3747
|
+
downloadFileHandler,
|
|
3748
|
+
headHandler,
|
|
3749
|
+
duckduckgoSearchHandler,
|
|
3750
|
+
fetchPageMainContentHandler,
|
|
3751
|
+
jsonSelectHandler,
|
|
3752
|
+
truncateHandler,
|
|
3753
|
+
hashTextHandler,
|
|
3754
|
+
nowHandler,
|
|
3755
|
+
templateRenderHandler,
|
|
3756
|
+
runCommandHandler
|
|
3757
|
+
];
|
|
3758
|
+
var readTextSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[0]);
|
|
3759
|
+
var writeTextSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[1]);
|
|
3760
|
+
var listDirSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[2]);
|
|
3761
|
+
var searchTextSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[3]);
|
|
3762
|
+
var sha256Spec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[4]);
|
|
3763
|
+
var deletePathSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[5]);
|
|
3764
|
+
var fetchTextSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[6]);
|
|
3765
|
+
var fetchJsonSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[7]);
|
|
3766
|
+
var downloadFileSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[8]);
|
|
3767
|
+
var headSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[9]);
|
|
3768
|
+
var jsonSelectSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[10]);
|
|
3769
|
+
var truncateSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[11]);
|
|
3770
|
+
var hashTextSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[12]);
|
|
3771
|
+
var nowSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[13]);
|
|
3772
|
+
var templateRenderSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[14]);
|
|
3773
|
+
var runCommandSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[15]);
|
|
3774
|
+
var duckduckgoSearchSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[16]);
|
|
3775
|
+
var fetchPageMainContentSpec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[17]);
|
|
3776
|
+
var CORE_GROUP_PREFIX = {
|
|
3777
|
+
fs: "core/fs.",
|
|
3778
|
+
http: "core/http.",
|
|
3779
|
+
util: "core/util.",
|
|
3780
|
+
exec: "core/exec."
|
|
3781
|
+
};
|
|
3782
|
+
function registerCoreTools(registry, userConfig, options) {
|
|
3783
|
+
const config = {
|
|
3784
|
+
...DEFAULT_CORE_TOOLS_CONFIG,
|
|
3785
|
+
...userConfig
|
|
3786
|
+
};
|
|
3787
|
+
const adapter = new CoreAdapter(config);
|
|
3788
|
+
const onlySet = options?.only?.length ? new Set(options.only) : null;
|
|
3789
|
+
const allowedPrefixes = !onlySet && options?.groups?.length ? options.groups.map((g) => CORE_GROUP_PREFIX[g]) : null;
|
|
3790
|
+
for (let i = 0; i < CORE_TOOL_MANIFEST.length; i++) {
|
|
3791
|
+
const spec = (0, import_core.createToolSpec)(CORE_TOOL_MANIFEST[i]);
|
|
3792
|
+
if (onlySet && !onlySet.has(spec.name)) continue;
|
|
3793
|
+
if (allowedPrefixes && !allowedPrefixes.some((p) => spec.name.startsWith(p))) {
|
|
3794
|
+
continue;
|
|
3795
|
+
}
|
|
3796
|
+
const handler = CORE_TOOL_HANDLERS[i];
|
|
3797
|
+
registry.register(spec);
|
|
3798
|
+
adapter.registerHandler(spec.name, handler);
|
|
3799
|
+
}
|
|
3800
|
+
return adapter;
|
|
3801
|
+
}
|
|
3802
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3803
|
+
0 && (module.exports = {
|
|
3804
|
+
CoreAdapter,
|
|
3805
|
+
DEFAULT_CORE_TOOLS_CONFIG,
|
|
3806
|
+
deletePathSpec,
|
|
3807
|
+
downloadFileSpec,
|
|
3808
|
+
duckduckgoSearchSpec,
|
|
3809
|
+
fetchJsonSpec,
|
|
3810
|
+
fetchPageMainContentSpec,
|
|
3811
|
+
fetchTextSpec,
|
|
3812
|
+
getBuiltinContext,
|
|
3813
|
+
hashTextSpec,
|
|
3814
|
+
headSpec,
|
|
3815
|
+
isIpInBlockedCidrs,
|
|
3816
|
+
jsonSelectSpec,
|
|
3817
|
+
listDirSpec,
|
|
3818
|
+
nowHandler,
|
|
3819
|
+
nowSpec,
|
|
3820
|
+
readTextSpec,
|
|
3821
|
+
registerCoreTools,
|
|
3822
|
+
resolveSandboxedPath,
|
|
3823
|
+
runCommandSpec,
|
|
3824
|
+
runWithBuiltinContext,
|
|
3825
|
+
searchTextSpec,
|
|
3826
|
+
sha256Spec,
|
|
3827
|
+
templateRenderSpec,
|
|
3828
|
+
truncateSpec,
|
|
3829
|
+
validateUrl,
|
|
3830
|
+
writeTextSpec
|
|
3831
|
+
});
|
|
3832
|
+
/*! Bundled license information:
|
|
3833
|
+
|
|
3834
|
+
mustache/mustache.mjs:
|
|
3835
|
+
(*!
|
|
3836
|
+
* mustache.js - Logic-less {{mustache}} templates with JavaScript
|
|
3837
|
+
* http://github.com/janl/mustache.js
|
|
3838
|
+
*)
|
|
3839
|
+
*/
|
|
3840
|
+
//# sourceMappingURL=index.cjs.map
|