lavs-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +75 -0
  2. package/dist/function-executor.d.ts +26 -0
  3. package/dist/function-executor.d.ts.map +1 -0
  4. package/dist/function-executor.js +116 -0
  5. package/dist/function-executor.js.map +1 -0
  6. package/dist/index.d.ts +25 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +35 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/loader.d.ts +37 -0
  11. package/dist/loader.d.ts.map +1 -0
  12. package/dist/loader.js +187 -0
  13. package/dist/loader.js.map +1 -0
  14. package/dist/permission-checker.d.ts +86 -0
  15. package/dist/permission-checker.d.ts.map +1 -0
  16. package/dist/permission-checker.js +172 -0
  17. package/dist/permission-checker.js.map +1 -0
  18. package/dist/rate-limiter.d.ts +57 -0
  19. package/dist/rate-limiter.d.ts.map +1 -0
  20. package/dist/rate-limiter.js +84 -0
  21. package/dist/rate-limiter.js.map +1 -0
  22. package/dist/script-executor.d.ts +70 -0
  23. package/dist/script-executor.d.ts.map +1 -0
  24. package/dist/script-executor.js +314 -0
  25. package/dist/script-executor.js.map +1 -0
  26. package/dist/subscription-manager.d.ts +106 -0
  27. package/dist/subscription-manager.d.ts.map +1 -0
  28. package/dist/subscription-manager.js +257 -0
  29. package/dist/subscription-manager.js.map +1 -0
  30. package/dist/tool-generator.d.ts +51 -0
  31. package/dist/tool-generator.d.ts.map +1 -0
  32. package/dist/tool-generator.js +147 -0
  33. package/dist/tool-generator.js.map +1 -0
  34. package/dist/types.d.ts +171 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +38 -0
  37. package/dist/types.js.map +1 -0
  38. package/dist/validator.d.ts +94 -0
  39. package/dist/validator.d.ts.map +1 -0
  40. package/dist/validator.js +187 -0
  41. package/dist/validator.js.map +1 -0
  42. package/package.json +51 -0
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ /**
3
+ * LAVS Script Executor
4
+ *
5
+ * Executes script handlers with proper input/output handling and security.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ScriptExecutor = void 0;
9
+ const child_process_1 = require("child_process");
10
+ const types_1 = require("./types");
11
+ class ScriptExecutor {
12
+ /**
13
+ * Execute a script handler
14
+ * @param handler - Script handler configuration
15
+ * @param input - Input data to pass to script
16
+ * @param context - Execution context with permissions
17
+ * @returns Script output (parsed as JSON)
18
+ */
19
+ async execute(handler, input, context) {
20
+ const startTime = Date.now();
21
+ console.log(`[LAVS] Executing script for ${context.endpointId}`, {
22
+ command: handler.command,
23
+ args: handler.args,
24
+ input: handler.input,
25
+ });
26
+ try {
27
+ // 1. Prepare command and arguments
28
+ const { command, args = [] } = handler;
29
+ const resolvedArgs = this.resolveArgs(args, input);
30
+ // 2. Prepare environment variables
31
+ const processEnv = this.buildEnvironment(handler, input, context);
32
+ // 3. Determine timeout
33
+ const timeout = handler.timeout || context.timeout || 30000;
34
+ // 4. Spawn process
35
+ const proc = (0, child_process_1.spawn)(command, resolvedArgs, {
36
+ cwd: handler.cwd || context.workdir,
37
+ env: processEnv,
38
+ timeout,
39
+ stdio: ['pipe', 'pipe', 'pipe'], // stdin, stdout, stderr
40
+ });
41
+ // 5. Send input to stdin if needed
42
+ if (handler.input === 'stdin' && input) {
43
+ try {
44
+ proc.stdin.write(JSON.stringify(input));
45
+ proc.stdin.end();
46
+ }
47
+ catch (e) {
48
+ console.error(`[LAVS] Failed to write to stdin:`, e);
49
+ }
50
+ }
51
+ // 6. Capture output and wait for completion
52
+ const result = await this.captureOutput(proc, timeout, context.endpointId);
53
+ const duration = Date.now() - startTime;
54
+ console.log(`[LAVS] Script completed in ${duration}ms`, {
55
+ endpointId: context.endpointId,
56
+ exitCode: result.exitCode,
57
+ });
58
+ // 7. Handle non-zero exit code
59
+ if (result.exitCode !== 0) {
60
+ throw new types_1.LAVSError(types_1.LAVSErrorCode.HandlerError, `Script exited with code ${result.exitCode}`, {
61
+ exitCode: result.exitCode,
62
+ stderr: result.stderr,
63
+ stdout: result.stdout,
64
+ });
65
+ }
66
+ // 8. Parse output as JSON
67
+ return this.parseOutput(result.stdout, result.stderr);
68
+ }
69
+ catch (error) {
70
+ if (error instanceof types_1.LAVSError) {
71
+ throw error;
72
+ }
73
+ // Handle timeout
74
+ if (error.code === 'ETIMEDOUT' || error.killed) {
75
+ throw new types_1.LAVSError(types_1.LAVSErrorCode.Timeout, `Script execution timeout after ${handler.timeout || context.timeout || 30000}ms`);
76
+ }
77
+ // Handle spawn errors
78
+ throw new types_1.LAVSError(types_1.LAVSErrorCode.HandlerError, `Script execution failed: ${error.message}`, { cause: error });
79
+ }
80
+ }
81
+ /**
82
+ * Resolve argument templates with input values
83
+ * Replaces {{path.to.value}} with actual values from input
84
+ */
85
+ resolveArgs(args, input) {
86
+ if (!input)
87
+ return args;
88
+ return args.map((arg) => {
89
+ return arg.replace(/\{\{([^}]+)\}\}/g, (_, path) => {
90
+ const value = this.getValueByPath(input, path);
91
+ return value != null ? String(value) : '';
92
+ });
93
+ });
94
+ }
95
+ /**
96
+ * Get value from nested object by dot path
97
+ * e.g., "user.name" from { user: { name: "Alice" } } => "Alice"
98
+ * Protects against prototype pollution by blocking __proto__, constructor, prototype keys.
99
+ */
100
+ getValueByPath(obj, path) {
101
+ // Block prototype pollution attacks
102
+ const BLOCKED_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
103
+ const keys = path.split('.');
104
+ let current = obj;
105
+ for (const key of keys) {
106
+ if (current == null)
107
+ return undefined;
108
+ if (BLOCKED_KEYS.has(key))
109
+ return undefined;
110
+ if (typeof current !== 'object')
111
+ return undefined;
112
+ current = current[key];
113
+ }
114
+ return current;
115
+ }
116
+ /**
117
+ * Build environment variables for script execution
118
+ */
119
+ buildEnvironment(handler, input, context) {
120
+ const env = {
121
+ // Inherit base environment (filtered for security)
122
+ ...this.getBaseEnvironment(),
123
+ // LAVS context variables
124
+ LAVS_AGENT_ID: context.agentId,
125
+ LAVS_ENDPOINT_ID: context.endpointId,
126
+ // Handler-specific env vars (declared by manifest author)
127
+ ...(handler.env || {}),
128
+ // Context env vars (e.g. LAVS_PROJECT_PATH)
129
+ ...(context.env || {}),
130
+ };
131
+ // If input mode is 'env', flatten input object to env vars
132
+ if (handler.input === 'env' && input) {
133
+ Object.assign(env, this.inputToEnv(input));
134
+ }
135
+ // Final safety pass: remove any sensitive vars that might have leaked through
136
+ return this.filterSensitiveVars(env);
137
+ }
138
+ /**
139
+ * Sensitive environment variable patterns (case-insensitive match).
140
+ * These keywords in variable names indicate potentially sensitive data.
141
+ */
142
+ static SENSITIVE_PATTERNS = [
143
+ 'SECRET',
144
+ 'TOKEN',
145
+ 'PASSWORD',
146
+ 'PASSWD',
147
+ 'CREDENTIAL',
148
+ 'PRIVATE_KEY',
149
+ 'API_KEY',
150
+ 'APIKEY',
151
+ 'ACCESS_KEY',
152
+ 'AUTH',
153
+ ];
154
+ /**
155
+ * Whitelist of variable names that are safe even if they match sensitive patterns.
156
+ * For example, LAVS variables or NODE_ENV.
157
+ */
158
+ static SAFE_OVERRIDES = new Set([
159
+ 'LAVS_AGENT_ID',
160
+ 'LAVS_ENDPOINT_ID',
161
+ 'LAVS_PROJECT_PATH',
162
+ 'NODE_ENV',
163
+ ]);
164
+ /**
165
+ * Filter out environment variables that match sensitive patterns.
166
+ * Variables explicitly declared in handler.env are preserved (they are
167
+ * intentionally set by the manifest author), but inherited vars from
168
+ * process.env that match sensitive patterns are removed.
169
+ *
170
+ * @param env - Environment variables to filter
171
+ * @returns Filtered environment variables
172
+ */
173
+ filterSensitiveVars(env) {
174
+ const filtered = {};
175
+ for (const [key, value] of Object.entries(env)) {
176
+ // Always allow safe overrides
177
+ if (ScriptExecutor.SAFE_OVERRIDES.has(key)) {
178
+ filtered[key] = value;
179
+ continue;
180
+ }
181
+ // Check if variable name matches any sensitive pattern
182
+ const upperKey = key.toUpperCase();
183
+ const isSensitive = ScriptExecutor.SENSITIVE_PATTERNS.some((pattern) => upperKey.includes(pattern));
184
+ if (!isSensitive) {
185
+ filtered[key] = value;
186
+ }
187
+ }
188
+ return filtered;
189
+ }
190
+ /**
191
+ * Get base environment variables (filtered for security)
192
+ * Only include safe variables, exclude sensitive ones
193
+ */
194
+ getBaseEnvironment() {
195
+ const env = {};
196
+ // Whitelist of safe env vars to inherit
197
+ const safeVars = [
198
+ 'PATH',
199
+ 'HOME',
200
+ 'USER',
201
+ 'LANG',
202
+ 'LC_ALL',
203
+ 'TZ',
204
+ 'NODE_ENV',
205
+ 'SHELL',
206
+ 'TMPDIR',
207
+ 'TERM',
208
+ ];
209
+ for (const key of safeVars) {
210
+ if (process.env[key]) {
211
+ env[key] = process.env[key];
212
+ }
213
+ }
214
+ return env;
215
+ }
216
+ /**
217
+ * Convert input object to environment variables
218
+ * Flattens nested objects with underscore notation
219
+ */
220
+ inputToEnv(input, prefix = '') {
221
+ const env = {};
222
+ for (const [key, value] of Object.entries(input)) {
223
+ const envKey = prefix ? `${prefix}_${key}` : key;
224
+ if (value == null) {
225
+ continue;
226
+ }
227
+ else if (typeof value === 'object' && !Array.isArray(value)) {
228
+ // Recursively flatten nested objects
229
+ Object.assign(env, this.inputToEnv(value, envKey.toUpperCase()));
230
+ }
231
+ else {
232
+ // Convert to string
233
+ env[envKey.toUpperCase()] = String(value);
234
+ }
235
+ }
236
+ return env;
237
+ }
238
+ /**
239
+ * Capture stdout/stderr from process and wait for completion
240
+ */
241
+ async captureOutput(proc, timeout, endpointId) {
242
+ let stdout = '';
243
+ let stderr = '';
244
+ // Collect stdout
245
+ proc.stdout?.on('data', (data) => {
246
+ stdout += data.toString();
247
+ });
248
+ // Collect stderr (and log it)
249
+ proc.stderr?.on('data', (data) => {
250
+ const text = data.toString();
251
+ stderr += text;
252
+ console.log(`[LAVS:${endpointId}] stderr:`, text);
253
+ });
254
+ // Wait for process to exit
255
+ return new Promise((resolve, reject) => {
256
+ let timeoutHandle = null;
257
+ // Set timeout
258
+ timeoutHandle = setTimeout(() => {
259
+ proc.kill('SIGTERM');
260
+ // Give it 5 seconds to terminate gracefully, then force kill
261
+ setTimeout(() => proc.kill('SIGKILL'), 5000);
262
+ reject(new types_1.LAVSError(types_1.LAVSErrorCode.Timeout, `Script execution timeout after ${timeout}ms`));
263
+ }, timeout);
264
+ proc.on('exit', (code) => {
265
+ if (timeoutHandle)
266
+ clearTimeout(timeoutHandle);
267
+ resolve({
268
+ stdout,
269
+ stderr,
270
+ exitCode: code || 0,
271
+ });
272
+ });
273
+ proc.on('error', (error) => {
274
+ if (timeoutHandle)
275
+ clearTimeout(timeoutHandle);
276
+ reject(error);
277
+ });
278
+ });
279
+ }
280
+ /**
281
+ * Parse script output as JSON
282
+ */
283
+ parseOutput(stdout, stderr) {
284
+ const trimmed = stdout.trim();
285
+ // Handle empty output
286
+ if (!trimmed) {
287
+ return null;
288
+ }
289
+ // Try to parse as JSON
290
+ try {
291
+ return JSON.parse(trimmed);
292
+ }
293
+ catch (e) {
294
+ // If not valid JSON, try to extract JSON from output
295
+ // Look for first { or [ and last } or ]
296
+ const jsonMatch = trimmed.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
297
+ if (jsonMatch) {
298
+ try {
299
+ return JSON.parse(jsonMatch[1]);
300
+ }
301
+ catch (e2) {
302
+ // Fall through to error
303
+ }
304
+ }
305
+ throw new types_1.LAVSError(types_1.LAVSErrorCode.HandlerError, 'Script output is not valid JSON', {
306
+ stdout: trimmed,
307
+ stderr,
308
+ parseError: e.message,
309
+ });
310
+ }
311
+ }
312
+ }
313
+ exports.ScriptExecutor = ScriptExecutor;
314
+ //# sourceMappingURL=script-executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-executor.js","sourceRoot":"","sources":["../src/script-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * LAVS Subscription Manager
3
+ *
4
+ * Manages real-time subscriptions for LAVS endpoints.
5
+ * Uses Server-Sent Events (SSE) as the transport layer.
6
+ *
7
+ * Protocol flow:
8
+ * 1. Client opens SSE connection: GET /api/agents/:agentId/lavs/:endpoint/subscribe
9
+ * 2. Server sends events when data changes
10
+ * 3. Client or server can close the connection
11
+ */
12
+ /**
13
+ * Minimal writable response interface for SSE.
14
+ * Compatible with express.Response, http.ServerResponse, etc.
15
+ */
16
+ export interface SSEResponse {
17
+ writeHead(statusCode: number, headers: Record<string, string>): void;
18
+ write(chunk: string): boolean;
19
+ end(): void;
20
+ on(event: string, listener: (...args: any[]) => void): void;
21
+ writableEnded: boolean;
22
+ }
23
+ /**
24
+ * Event data to push to subscribers
25
+ */
26
+ export interface SubscriptionEvent {
27
+ type: string;
28
+ data?: unknown;
29
+ timestamp?: string;
30
+ }
31
+ /**
32
+ * Configuration for the subscription manager
33
+ */
34
+ interface SubscriptionManagerOptions {
35
+ /** Maximum number of concurrent subscriptions (default: 100) */
36
+ maxSubscriptions?: number;
37
+ /** Heartbeat interval in ms to keep connections alive (default: 30000) */
38
+ heartbeatIntervalMs?: number;
39
+ }
40
+ /**
41
+ * LAVS Subscription Manager - manages SSE-based subscriptions
42
+ */
43
+ export declare class SubscriptionManager {
44
+ private subscriptions;
45
+ private readonly maxSubscriptions;
46
+ private heartbeatTimer;
47
+ constructor(options?: SubscriptionManagerOptions);
48
+ /**
49
+ * Send heartbeat to all subscriptions. Removes stale connections.
50
+ */
51
+ private sendHeartbeats;
52
+ /**
53
+ * Stop the heartbeat timer (for graceful shutdown / tests)
54
+ */
55
+ destroy(): void;
56
+ /**
57
+ * Create a new subscription.
58
+ *
59
+ * @param agentId - Agent identifier
60
+ * @param endpointId - Endpoint identifier (must be a subscription endpoint)
61
+ * @param res - Express response object (will be held open for SSE)
62
+ * @returns Subscription ID
63
+ * @throws Error if max subscriptions limit is reached
64
+ */
65
+ subscribe(agentId: string, endpointId: string, res: SSEResponse): string;
66
+ /**
67
+ * Remove a subscription
68
+ */
69
+ unsubscribe(subscriptionId: string): boolean;
70
+ /**
71
+ * Push an event to all subscribers of a specific agent+endpoint.
72
+ *
73
+ * @param agentId - Agent identifier
74
+ * @param endpointId - Endpoint identifier
75
+ * @param event - Event data to push
76
+ * @returns Number of subscribers notified
77
+ */
78
+ publish(agentId: string, endpointId: string, event: SubscriptionEvent): number;
79
+ /**
80
+ * Push an event to all subscribers of a specific agent (any endpoint).
81
+ *
82
+ * @param agentId - Agent identifier
83
+ * @param event - Event data to push
84
+ * @returns Number of subscribers notified
85
+ */
86
+ publishToAgent(agentId: string, event: SubscriptionEvent): number;
87
+ /**
88
+ * Get count of active subscriptions
89
+ */
90
+ getActiveCount(): number;
91
+ /**
92
+ * Get active subscriptions for an agent
93
+ */
94
+ getSubscriptionsForAgent(agentId: string): {
95
+ id: string;
96
+ endpointId: string;
97
+ createdAt: number;
98
+ }[];
99
+ /**
100
+ * Send an SSE event to a response stream
101
+ */
102
+ private sendSSE;
103
+ }
104
+ export declare const subscriptionManager: SubscriptionManager;
105
+ export {};
106
+ //# sourceMappingURL=subscription-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscription-manager.d.ts","sourceRoot":"","sources":["../src/subscription-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,GAAG,IAAI,IAAI,CAAC;IACZ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5D,aAAa,EAAE,OAAO,CAAC;CACxB;AAaD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,0BAA0B;IAClC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,cAAc,CAA+C;gBAEzD,OAAO,GAAE,0BAA+B;IAYpD;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACH,OAAO,IAAI,IAAI;IAWf;;;;;;;;OAQG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,MAAM;IAwDxE;;OAEG;IACH,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO;IAgC5C;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM;IA2B9E;;;;;;OAMG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,MAAM;IA0BjE;;OAEG;IACH,cAAc,IAAI,MAAM;IAIxB;;OAEG;IACH,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE;IAclG;;OAEG;IACH,OAAO,CAAC,OAAO;CAYhB;AAGD,eAAO,MAAM,mBAAmB,qBAA4B,CAAC"}