@rcrsr/rill 0.7.2 → 0.8.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 +29 -1
- package/dist/ast-nodes.d.ts +635 -0
- package/dist/ast-nodes.d.ts.map +1 -0
- package/dist/ast-nodes.js +2 -0
- package/dist/ast-nodes.js.map +1 -0
- package/dist/ast-unions.d.ts +6 -0
- package/dist/ast-unions.d.ts.map +1 -0
- package/dist/ast-unions.js +6 -0
- package/dist/ast-unions.js.map +1 -0
- package/dist/error-classes.d.ts +90 -0
- package/dist/error-classes.d.ts.map +1 -0
- package/dist/error-classes.js +185 -0
- package/dist/error-classes.js.map +1 -0
- package/dist/error-registry.d.ts +93 -0
- package/dist/error-registry.d.ts.map +1 -0
- package/dist/error-registry.js +876 -0
- package/dist/error-registry.js.map +1 -0
- package/dist/ext/crypto/index.d.ts +32 -0
- package/dist/ext/crypto/index.d.ts.map +1 -0
- package/dist/ext/crypto/index.js +143 -0
- package/dist/ext/crypto/index.js.map +1 -0
- package/dist/ext/exec/index.d.ts +45 -0
- package/dist/ext/exec/index.d.ts.map +1 -0
- package/dist/ext/exec/index.js +168 -0
- package/dist/ext/exec/index.js.map +1 -0
- package/dist/ext/exec/runner.d.ts +62 -0
- package/dist/ext/exec/runner.d.ts.map +1 -0
- package/dist/ext/exec/runner.js +168 -0
- package/dist/ext/exec/runner.js.map +1 -0
- package/dist/ext/fetch/index.d.ts +68 -0
- package/dist/ext/fetch/index.d.ts.map +1 -0
- package/dist/ext/fetch/index.js +259 -0
- package/dist/ext/fetch/index.js.map +1 -0
- package/dist/ext/fetch/request.d.ts +90 -0
- package/dist/ext/fetch/request.d.ts.map +1 -0
- package/dist/ext/fetch/request.js +413 -0
- package/dist/ext/fetch/request.js.map +1 -0
- package/dist/ext/fs/index.d.ts +39 -0
- package/dist/ext/fs/index.d.ts.map +1 -0
- package/dist/ext/fs/index.js +560 -0
- package/dist/ext/fs/index.js.map +1 -0
- package/dist/ext/fs/sandbox.d.ts +78 -0
- package/dist/ext/fs/sandbox.d.ts.map +1 -0
- package/dist/ext/fs/sandbox.js +208 -0
- package/dist/ext/fs/sandbox.js.map +1 -0
- package/dist/ext/kv/index.d.ts +46 -0
- package/dist/ext/kv/index.d.ts.map +1 -0
- package/dist/ext/kv/index.js +215 -0
- package/dist/ext/kv/index.js.map +1 -0
- package/dist/ext/kv/store.d.ts +46 -0
- package/dist/ext/kv/store.d.ts.map +1 -0
- package/dist/ext/kv/store.js +256 -0
- package/dist/ext/kv/store.js.map +1 -0
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.d.ts.map +1 -1
- package/dist/generated/introspection-data.js +509 -481
- package/dist/generated/introspection-data.js.map +1 -1
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/core/callable.d.ts +5 -5
- package/dist/runtime/core/callable.d.ts.map +1 -1
- package/dist/runtime/core/callable.js +2 -1
- package/dist/runtime/core/callable.js.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/collections.js +5 -1
- package/dist/runtime/core/eval/mixins/collections.js.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.d.ts.map +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +5 -1
- package/dist/runtime/core/eval/mixins/literals.js.map +1 -1
- package/dist/runtime/core/eval/mixins/variables.js +12 -12
- package/dist/runtime/core/eval/mixins/variables.js.map +1 -1
- package/dist/runtime/core/values.d.ts +31 -3
- package/dist/runtime/core/values.d.ts.map +1 -1
- package/dist/runtime/core/values.js +47 -1
- package/dist/runtime/core/values.js.map +1 -1
- package/dist/runtime/ext/builtins.d.ts.map +1 -1
- package/dist/runtime/ext/builtins.js +202 -1
- package/dist/runtime/ext/builtins.js.map +1 -1
- package/dist/runtime/ext/extensions.d.ts +39 -3
- package/dist/runtime/ext/extensions.d.ts.map +1 -1
- package/dist/runtime/ext/extensions.js +77 -12
- package/dist/runtime/ext/extensions.js.map +1 -1
- package/dist/runtime/index.d.ts +5 -5
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/source-location.d.ts +10 -0
- package/dist/source-location.d.ts.map +1 -0
- package/dist/source-location.js +5 -0
- package/dist/source-location.js.map +1 -0
- package/dist/token-types.d.ts +68 -0
- package/dist/token-types.d.ts.map +1 -0
- package/dist/token-types.js +79 -0
- package/dist/token-types.js.map +1 -0
- package/dist/types.d.ts +9 -882
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -958
- package/dist/types.js.map +1 -1
- package/dist/value-types.d.ts +3 -0
- package/dist/value-types.d.ts.map +1 -0
- package/dist/value-types.js +2 -0
- package/dist/value-types.js.map +1 -0
- package/package.json +50 -11
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* exec Extension Runner
|
|
3
|
+
*
|
|
4
|
+
* Handles process spawning with argument validation and security controls.
|
|
5
|
+
* Uses child_process.execFile() for shell injection prevention.
|
|
6
|
+
*/
|
|
7
|
+
import { execFile } from 'node:child_process';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
import { RuntimeError } from '../../error-classes.js';
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
// ============================================================
|
|
12
|
+
// VALIDATION
|
|
13
|
+
// ============================================================
|
|
14
|
+
/**
|
|
15
|
+
* Validate arguments against allowlist/blocklist rules.
|
|
16
|
+
*
|
|
17
|
+
* @param args - Command arguments to validate
|
|
18
|
+
* @param config - Command configuration with security rules
|
|
19
|
+
* @param commandName - Command name for error messages
|
|
20
|
+
* @throws RuntimeError RILL-R004 if validation fails
|
|
21
|
+
*/
|
|
22
|
+
function validateArgs(args, config, commandName) {
|
|
23
|
+
const { allowedArgs, blockedArgs } = config;
|
|
24
|
+
// Allowlist mode: every arg must be in allowedArgs
|
|
25
|
+
if (allowedArgs !== undefined) {
|
|
26
|
+
for (const arg of args) {
|
|
27
|
+
if (!allowedArgs.includes(arg)) {
|
|
28
|
+
// EC-14: Arg not in allowlist
|
|
29
|
+
throw new RuntimeError('RILL-R004', `arg "${arg}" not permitted for command "${commandName}"`, undefined, { commandName, arg, allowedArgs });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Blocklist mode: no arg can be in blockedArgs
|
|
34
|
+
if (blockedArgs !== undefined) {
|
|
35
|
+
for (const arg of args) {
|
|
36
|
+
if (blockedArgs.includes(arg)) {
|
|
37
|
+
// EC-15: Arg in blocklist
|
|
38
|
+
throw new RuntimeError('RILL-R004', `arg "${arg}" is blocked for command "${commandName}"`, undefined, { commandName, arg, blockedArgs });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Check if stdin is supported by the command.
|
|
45
|
+
*
|
|
46
|
+
* @param config - Command configuration
|
|
47
|
+
* @param commandName - Command name for error messages
|
|
48
|
+
* @param hasStdin - Whether stdin was provided
|
|
49
|
+
* @throws RuntimeError RILL-R004 if stdin not supported but provided
|
|
50
|
+
*/
|
|
51
|
+
function validateStdin(config, commandName, hasStdin) {
|
|
52
|
+
if (hasStdin && !config.stdin) {
|
|
53
|
+
// EC-19: stdin not supported
|
|
54
|
+
throw new RuntimeError('RILL-R004', `command "${commandName}" does not support stdin`, undefined, { commandName });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// ============================================================
|
|
58
|
+
// EXECUTION
|
|
59
|
+
// ============================================================
|
|
60
|
+
/**
|
|
61
|
+
* Execute command with process spawning and security controls.
|
|
62
|
+
*
|
|
63
|
+
* Uses execFile() to prevent shell injection attacks.
|
|
64
|
+
* Validates arguments against allowlist/blocklist rules.
|
|
65
|
+
* Returns stdout, stderr, and exit code (non-zero exit is not an error).
|
|
66
|
+
*
|
|
67
|
+
* @param commandName - Command name for error messages
|
|
68
|
+
* @param config - Command configuration with security rules
|
|
69
|
+
* @param args - Command arguments
|
|
70
|
+
* @param stdinData - Optional stdin data
|
|
71
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
72
|
+
* @returns Command result with stdout, stderr, and exitCode
|
|
73
|
+
* @throws RuntimeError RILL-R004 for validation failures
|
|
74
|
+
* @throws RuntimeError RILL-R012 for timeout
|
|
75
|
+
* @throws RuntimeError RILL-R004 for output size limit exceeded
|
|
76
|
+
* @throws RuntimeError RILL-R004 for binary not found
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const result = await runCommand('git', {
|
|
81
|
+
* binary: 'git',
|
|
82
|
+
* allowedArgs: ['status', '--short']
|
|
83
|
+
* }, ['status', '--short']);
|
|
84
|
+
* // Returns: { stdout: "...", stderr: "", exitCode: 0 }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export async function runCommand(commandName, config, args, stdinData, signal) {
|
|
88
|
+
// Validate arguments against security rules
|
|
89
|
+
validateArgs(args, config, commandName);
|
|
90
|
+
// Validate stdin support
|
|
91
|
+
validateStdin(config, commandName, stdinData !== undefined);
|
|
92
|
+
// Prepare execFile options
|
|
93
|
+
const options = {
|
|
94
|
+
encoding: 'utf8',
|
|
95
|
+
};
|
|
96
|
+
if (config.timeout !== undefined) {
|
|
97
|
+
options.timeout = config.timeout;
|
|
98
|
+
}
|
|
99
|
+
if (config.maxBuffer !== undefined) {
|
|
100
|
+
options.maxBuffer = config.maxBuffer;
|
|
101
|
+
}
|
|
102
|
+
// Add cwd if provided
|
|
103
|
+
if (config.cwd !== undefined) {
|
|
104
|
+
options.cwd = config.cwd;
|
|
105
|
+
}
|
|
106
|
+
// Add env if provided
|
|
107
|
+
if (config.env !== undefined) {
|
|
108
|
+
options.env = config.env;
|
|
109
|
+
}
|
|
110
|
+
// Add stdin data if provided
|
|
111
|
+
if (stdinData !== undefined) {
|
|
112
|
+
options.input = stdinData;
|
|
113
|
+
}
|
|
114
|
+
// Add abort signal if provided
|
|
115
|
+
if (signal !== undefined) {
|
|
116
|
+
options.signal = signal;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
// Execute command using execFile (no shell interpolation)
|
|
120
|
+
const { stdout, stderr } = await execFileAsync(config.binary, args, options);
|
|
121
|
+
return {
|
|
122
|
+
stdout: String(stdout || ''),
|
|
123
|
+
stderr: String(stderr || ''),
|
|
124
|
+
exitCode: 0,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
// Handle execution errors
|
|
129
|
+
if (err && typeof err === 'object') {
|
|
130
|
+
const execError = err;
|
|
131
|
+
// EC-16: Binary not found
|
|
132
|
+
if (execError.code === 'ENOENT') {
|
|
133
|
+
throw new RuntimeError('RILL-R004', `binary not found: ${config.binary}`, undefined, { commandName, binary: config.binary });
|
|
134
|
+
}
|
|
135
|
+
// EC-18: Output exceeds limit (check multiple conditions)
|
|
136
|
+
const isMaxBufferError = execError.code === 'ERR_CHILD_PROCESS_STDOUT_MAXBUFFER' ||
|
|
137
|
+
execError.code === 'ERR_CHILD_PROCESS_STDERR_MAXBUFFER' ||
|
|
138
|
+
(execError.message &&
|
|
139
|
+
execError.message.toLowerCase().includes('maxbuffer')) ||
|
|
140
|
+
(execError.killed === true &&
|
|
141
|
+
execError.signal === 'SIGTERM' &&
|
|
142
|
+
config.maxBuffer !== undefined);
|
|
143
|
+
if (isMaxBufferError) {
|
|
144
|
+
throw new RuntimeError('RILL-R004', `command output exceeds size limit`, undefined, { commandName, maxBuffer: config.maxBuffer });
|
|
145
|
+
}
|
|
146
|
+
// EC-17: Timeout (must check after maxBuffer to avoid confusion)
|
|
147
|
+
if (execError.killed === true && execError.signal === 'SIGTERM') {
|
|
148
|
+
const timeoutMs = config.timeout || 0;
|
|
149
|
+
throw new RuntimeError('RILL-R012', `command "${commandName}" timed out (${timeoutMs}ms)`, undefined, { commandName, timeoutMs });
|
|
150
|
+
}
|
|
151
|
+
// Non-zero exit code: return as CommandResult (not an error)
|
|
152
|
+
if ('stdout' in execError && 'stderr' in execError) {
|
|
153
|
+
// Extract exit code from error
|
|
154
|
+
const exitCode = 'code' in err && typeof err.code === 'number'
|
|
155
|
+
? err.code
|
|
156
|
+
: 1;
|
|
157
|
+
return {
|
|
158
|
+
stdout: String(execError.stdout || ''),
|
|
159
|
+
stderr: String(execError.stderr || ''),
|
|
160
|
+
exitCode,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Unknown error: re-throw
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/ext/exec/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch Extension Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates host functions for HTTP requests based on endpoint configuration.
|
|
5
|
+
* Scripts call endpoints with positional args or single dict argument.
|
|
6
|
+
* All URLs are constructed from config - scripts cannot specify arbitrary URLs.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExtensionResult } from '../../runtime/ext/extensions.js';
|
|
9
|
+
/** Parameter definition for endpoint */
|
|
10
|
+
export interface EndpointParam {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly type: 'string' | 'number' | 'bool' | 'dict';
|
|
13
|
+
readonly required?: boolean | undefined;
|
|
14
|
+
readonly location: 'path' | 'query' | 'body' | 'header';
|
|
15
|
+
readonly defaultValue?: string | number | boolean | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Endpoint configuration with parameter declarations */
|
|
18
|
+
export interface EndpointConfig {
|
|
19
|
+
readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
20
|
+
readonly path: string;
|
|
21
|
+
readonly params?: EndpointParam[] | undefined;
|
|
22
|
+
readonly headers?: Record<string, string> | undefined;
|
|
23
|
+
readonly body?: 'json' | 'form' | 'text' | undefined;
|
|
24
|
+
readonly responseFormat?: 'json' | 'text' | undefined;
|
|
25
|
+
readonly responseShape?: 'body' | 'full' | undefined;
|
|
26
|
+
readonly description?: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
/** Fetch extension configuration */
|
|
29
|
+
export interface FetchConfig {
|
|
30
|
+
readonly baseUrl: string;
|
|
31
|
+
readonly headers?: Record<string, string> | (() => Record<string, string>) | undefined;
|
|
32
|
+
readonly timeout?: number | undefined;
|
|
33
|
+
readonly retries?: number | undefined;
|
|
34
|
+
readonly retryDelay?: number | undefined;
|
|
35
|
+
readonly maxConcurrent?: number | undefined;
|
|
36
|
+
readonly responseFormat?: 'json' | 'text' | undefined;
|
|
37
|
+
readonly responseShape?: 'body' | 'full' | undefined;
|
|
38
|
+
readonly endpoints: Record<string, EndpointConfig>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create fetch extension with generated endpoint functions.
|
|
42
|
+
*
|
|
43
|
+
* Each endpoint in config becomes a host function.
|
|
44
|
+
* Scripts call endpoints with positional args or single dict.
|
|
45
|
+
* All URLs constructed from config - scripts cannot create arbitrary URLs.
|
|
46
|
+
*
|
|
47
|
+
* @param config - Fetch configuration with endpoints
|
|
48
|
+
* @returns ExtensionResult with endpoint functions and introspection
|
|
49
|
+
* @throws Error on invalid configuration
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const api = createFetchExtension({
|
|
54
|
+
* baseUrl: 'https://api.example.com',
|
|
55
|
+
* endpoints: {
|
|
56
|
+
* getUser: {
|
|
57
|
+
* method: 'GET',
|
|
58
|
+
* path: '/users/:id',
|
|
59
|
+
* params: [
|
|
60
|
+
* { name: 'id', type: 'string', location: 'path' }
|
|
61
|
+
* ]
|
|
62
|
+
* }
|
|
63
|
+
* }
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function createFetchExtension(config: FetchConfig): ExtensionResult;
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ext/fetch/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAmBvE,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACrD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACxD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC/D;AAED,yDAAyD;AACzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAC9B,SAAS,CAAC;IACd,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACpD;AAgID;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAoKzE"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch Extension Factory
|
|
3
|
+
*
|
|
4
|
+
* Creates host functions for HTTP requests based on endpoint configuration.
|
|
5
|
+
* Scripts call endpoints with positional args or single dict argument.
|
|
6
|
+
* All URLs are constructed from config - scripts cannot specify arbitrary URLs.
|
|
7
|
+
*/
|
|
8
|
+
import { RuntimeError } from '../../error-classes.js';
|
|
9
|
+
import { isDict, } from '../../runtime/core/callable.js';
|
|
10
|
+
import { buildRequest, executeRequest, createSemaphore, } from './request.js';
|
|
11
|
+
// ============================================================
|
|
12
|
+
// PARAMETER MAPPING
|
|
13
|
+
// ============================================================
|
|
14
|
+
/**
|
|
15
|
+
* Convert EndpointParam to EndpointArg for request module.
|
|
16
|
+
* Maps type-aware parameters to location-based arguments.
|
|
17
|
+
*
|
|
18
|
+
* @param param - Parameter definition with type information
|
|
19
|
+
* @returns Argument definition for request builder
|
|
20
|
+
*/
|
|
21
|
+
function mapParamToArg(param) {
|
|
22
|
+
return {
|
|
23
|
+
name: param.name,
|
|
24
|
+
location: param.location,
|
|
25
|
+
required: param.required ?? true, // Default to required per spec
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Convert EndpointConfig to InternalEndpointConfig for request module.
|
|
30
|
+
* Maps high-level endpoint config to request-compatible format.
|
|
31
|
+
*
|
|
32
|
+
* @param config - Public endpoint configuration
|
|
33
|
+
* @returns Request-compatible endpoint configuration
|
|
34
|
+
*/
|
|
35
|
+
function mapEndpointConfig(config) {
|
|
36
|
+
return {
|
|
37
|
+
method: config.method,
|
|
38
|
+
path: config.path,
|
|
39
|
+
args: config.params?.map(mapParamToArg),
|
|
40
|
+
headers: config.headers,
|
|
41
|
+
responseShape: config.responseShape ?? 'body',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// ============================================================
|
|
45
|
+
// ARGUMENT PROCESSING
|
|
46
|
+
// ============================================================
|
|
47
|
+
/**
|
|
48
|
+
* Process arguments from positional or dict form.
|
|
49
|
+
* Supports two calling conventions:
|
|
50
|
+
* 1. Positional: endpoint(arg1, arg2, arg3)
|
|
51
|
+
* 2. Dict: endpoint({name: value, ...})
|
|
52
|
+
*
|
|
53
|
+
* @param args - Raw arguments from call site
|
|
54
|
+
* @param params - Parameter definitions
|
|
55
|
+
* @param functionName - Function name for error messages
|
|
56
|
+
* @returns Dict of argument name to value
|
|
57
|
+
* @throws RuntimeError on missing required parameter (EC-8)
|
|
58
|
+
*/
|
|
59
|
+
function processArguments(args, params, functionName) {
|
|
60
|
+
const result = {};
|
|
61
|
+
// Case 1: Single dict argument - extract named parameters
|
|
62
|
+
const firstArg = args[0];
|
|
63
|
+
if (args.length === 1 && firstArg !== undefined && isDict(firstArg)) {
|
|
64
|
+
const argsDict = firstArg;
|
|
65
|
+
for (const param of params) {
|
|
66
|
+
const value = argsDict[param.name];
|
|
67
|
+
if (value === undefined) {
|
|
68
|
+
// Check if parameter has default value
|
|
69
|
+
if (param.defaultValue !== undefined) {
|
|
70
|
+
result[param.name] = param.defaultValue;
|
|
71
|
+
}
|
|
72
|
+
else if (param.required !== false) {
|
|
73
|
+
// EC-8: Missing required parameter
|
|
74
|
+
throw new RuntimeError('RILL-R001', `parameter "${param.name}" is required`, undefined, {
|
|
75
|
+
functionName,
|
|
76
|
+
paramName: param.name,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
result[param.name] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
// Case 2: Positional arguments - map by position
|
|
87
|
+
for (let i = 0; i < params.length; i++) {
|
|
88
|
+
const param = params[i];
|
|
89
|
+
if (param === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
const value = args[i];
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
// Check if parameter has default value
|
|
94
|
+
if (param.defaultValue !== undefined) {
|
|
95
|
+
result[param.name] = param.defaultValue;
|
|
96
|
+
}
|
|
97
|
+
else if (param.required !== false) {
|
|
98
|
+
// EC-8: Missing required parameter
|
|
99
|
+
throw new RuntimeError('RILL-R001', `parameter "${param.name}" is required`, undefined, {
|
|
100
|
+
functionName,
|
|
101
|
+
paramName: param.name,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
result[param.name] = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
// ============================================================
|
|
112
|
+
// FACTORY
|
|
113
|
+
// ============================================================
|
|
114
|
+
/**
|
|
115
|
+
* Create fetch extension with generated endpoint functions.
|
|
116
|
+
*
|
|
117
|
+
* Each endpoint in config becomes a host function.
|
|
118
|
+
* Scripts call endpoints with positional args or single dict.
|
|
119
|
+
* All URLs constructed from config - scripts cannot create arbitrary URLs.
|
|
120
|
+
*
|
|
121
|
+
* @param config - Fetch configuration with endpoints
|
|
122
|
+
* @returns ExtensionResult with endpoint functions and introspection
|
|
123
|
+
* @throws Error on invalid configuration
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const api = createFetchExtension({
|
|
128
|
+
* baseUrl: 'https://api.example.com',
|
|
129
|
+
* endpoints: {
|
|
130
|
+
* getUser: {
|
|
131
|
+
* method: 'GET',
|
|
132
|
+
* path: '/users/:id',
|
|
133
|
+
* params: [
|
|
134
|
+
* { name: 'id', type: 'string', location: 'path' }
|
|
135
|
+
* ]
|
|
136
|
+
* }
|
|
137
|
+
* }
|
|
138
|
+
* });
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function createFetchExtension(config) {
|
|
142
|
+
// Apply defaults
|
|
143
|
+
const timeout = config.timeout ?? 30000;
|
|
144
|
+
const retries = config.retries ?? 0;
|
|
145
|
+
const retryDelay = config.retryDelay ?? 1000;
|
|
146
|
+
const defaultResponseShape = config.responseShape ?? 'body';
|
|
147
|
+
// Create semaphore for concurrency control
|
|
148
|
+
const semaphore = createSemaphore(config.maxConcurrent);
|
|
149
|
+
// Track active requests for dispose()
|
|
150
|
+
const activeControllers = new Set();
|
|
151
|
+
// Convert config to request-compatible format
|
|
152
|
+
const requestConfig = {
|
|
153
|
+
baseUrl: config.baseUrl,
|
|
154
|
+
headers: config.headers,
|
|
155
|
+
timeout,
|
|
156
|
+
retryLimit: retries,
|
|
157
|
+
retryDelay,
|
|
158
|
+
maxConcurrent: config.maxConcurrent,
|
|
159
|
+
endpoints: Object.fromEntries(Object.entries(config.endpoints).map(([name, endpointConfig]) => [
|
|
160
|
+
name,
|
|
161
|
+
mapEndpointConfig(endpointConfig),
|
|
162
|
+
])),
|
|
163
|
+
};
|
|
164
|
+
// ============================================================
|
|
165
|
+
// ENDPOINT FUNCTIONS
|
|
166
|
+
// ============================================================
|
|
167
|
+
const functions = {};
|
|
168
|
+
for (const [endpointName, endpointConfig] of Object.entries(config.endpoints)) {
|
|
169
|
+
const params = endpointConfig.params ?? [];
|
|
170
|
+
// Generate function for this endpoint
|
|
171
|
+
const endpointFn = async (args) => {
|
|
172
|
+
// Process arguments (positional or dict)
|
|
173
|
+
const processedArgs = processArguments(args, params, endpointName);
|
|
174
|
+
// Build request
|
|
175
|
+
const { url, options, responseShape } = buildRequest(requestConfig, endpointName, processedArgs);
|
|
176
|
+
// Create abort controller for this request
|
|
177
|
+
const controller = new AbortController();
|
|
178
|
+
activeControllers.add(controller);
|
|
179
|
+
try {
|
|
180
|
+
// Execute request
|
|
181
|
+
const result = await executeRequest(url, { ...options, signal: controller.signal }, requestConfig, endpointName, responseShape, semaphore);
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
activeControllers.delete(controller);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
// Build parameter definitions for HostFunctionDefinition
|
|
189
|
+
const hostParams = params.map((param) => {
|
|
190
|
+
// Map EndpointParam type to HostFunctionParam type
|
|
191
|
+
const type = param.type === 'bool' ? 'bool' : param.type;
|
|
192
|
+
const hostParam = {
|
|
193
|
+
name: param.name,
|
|
194
|
+
type,
|
|
195
|
+
};
|
|
196
|
+
if (param.defaultValue !== undefined) {
|
|
197
|
+
hostParam.defaultValue = param.defaultValue;
|
|
198
|
+
}
|
|
199
|
+
return hostParam;
|
|
200
|
+
});
|
|
201
|
+
const returnType = (endpointConfig.responseShape ?? defaultResponseShape) === 'full'
|
|
202
|
+
? 'dict'
|
|
203
|
+
: 'any';
|
|
204
|
+
const hostFunctionDef = {
|
|
205
|
+
params: hostParams,
|
|
206
|
+
fn: endpointFn,
|
|
207
|
+
...(endpointConfig.description !== undefined
|
|
208
|
+
? { description: endpointConfig.description }
|
|
209
|
+
: {}),
|
|
210
|
+
returnType,
|
|
211
|
+
};
|
|
212
|
+
functions[endpointName] = hostFunctionDef;
|
|
213
|
+
}
|
|
214
|
+
// ============================================================
|
|
215
|
+
// INTROSPECTION FUNCTION
|
|
216
|
+
// ============================================================
|
|
217
|
+
/**
|
|
218
|
+
* List all configured endpoints.
|
|
219
|
+
* IR-13: Returns list with name, method, path, description.
|
|
220
|
+
*/
|
|
221
|
+
const endpoints = async () => {
|
|
222
|
+
const result = [];
|
|
223
|
+
for (const [name, endpointConfig] of Object.entries(config.endpoints)) {
|
|
224
|
+
result.push({
|
|
225
|
+
name,
|
|
226
|
+
method: endpointConfig.method,
|
|
227
|
+
path: endpointConfig.path,
|
|
228
|
+
description: endpointConfig.description ?? '',
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return result;
|
|
232
|
+
};
|
|
233
|
+
functions['endpoints'] = {
|
|
234
|
+
params: [],
|
|
235
|
+
fn: endpoints,
|
|
236
|
+
description: 'List configured endpoints',
|
|
237
|
+
returnType: 'list',
|
|
238
|
+
};
|
|
239
|
+
// ============================================================
|
|
240
|
+
// DISPOSAL
|
|
241
|
+
// ============================================================
|
|
242
|
+
/**
|
|
243
|
+
* Abort all in-flight requests.
|
|
244
|
+
* AC-8: dispose() aborts in-flight requests.
|
|
245
|
+
*/
|
|
246
|
+
const dispose = () => {
|
|
247
|
+
for (const controller of activeControllers) {
|
|
248
|
+
controller.abort();
|
|
249
|
+
}
|
|
250
|
+
activeControllers.clear();
|
|
251
|
+
};
|
|
252
|
+
// ============================================================
|
|
253
|
+
// EXTENSION RESULT
|
|
254
|
+
// ============================================================
|
|
255
|
+
const result = functions;
|
|
256
|
+
result.dispose = dispose;
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ext/fetch/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch Request Module
|
|
3
|
+
* Handles URL building, retry logic, response parsing, and error handling
|
|
4
|
+
*/
|
|
5
|
+
/** Response shape configuration */
|
|
6
|
+
export type ResponseShape = 'body' | 'full';
|
|
7
|
+
/** Location of argument in request */
|
|
8
|
+
export type ArgLocation = 'path' | 'query' | 'header' | 'body';
|
|
9
|
+
/** Argument definition for endpoint */
|
|
10
|
+
export interface EndpointArg {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly location: ArgLocation;
|
|
13
|
+
readonly required?: boolean | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Internal endpoint configuration for request building */
|
|
16
|
+
export interface InternalEndpointConfig {
|
|
17
|
+
readonly path: string;
|
|
18
|
+
readonly method: string;
|
|
19
|
+
readonly args?: EndpointArg[] | undefined;
|
|
20
|
+
readonly headers?: Record<string, string> | undefined;
|
|
21
|
+
readonly responseShape?: ResponseShape | undefined;
|
|
22
|
+
}
|
|
23
|
+
/** Extension configuration */
|
|
24
|
+
export interface FetchExtensionConfig {
|
|
25
|
+
readonly baseUrl: string;
|
|
26
|
+
readonly endpoints: Record<string, InternalEndpointConfig>;
|
|
27
|
+
readonly headers?: Record<string, string> | (() => Record<string, string>) | undefined;
|
|
28
|
+
readonly timeout?: number | undefined;
|
|
29
|
+
readonly retryLimit?: number | undefined;
|
|
30
|
+
readonly retryDelay?: number | undefined;
|
|
31
|
+
readonly maxConcurrent?: number | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** Full response shape */
|
|
34
|
+
export interface FullResponse {
|
|
35
|
+
readonly status: number;
|
|
36
|
+
readonly headers: Record<string, string>;
|
|
37
|
+
readonly body: unknown;
|
|
38
|
+
}
|
|
39
|
+
/** Fetch request options (compatible with fetch API) */
|
|
40
|
+
export interface FetchOptions {
|
|
41
|
+
readonly method: string;
|
|
42
|
+
readonly headers: Record<string, string>;
|
|
43
|
+
body?: string | undefined;
|
|
44
|
+
signal?: AbortSignal | undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Simple semaphore for limiting concurrent requests.
|
|
48
|
+
* Queues requests when limit is reached.
|
|
49
|
+
*/
|
|
50
|
+
declare class Semaphore {
|
|
51
|
+
private permits;
|
|
52
|
+
private readonly queue;
|
|
53
|
+
constructor(permits: number);
|
|
54
|
+
acquire(): Promise<void>;
|
|
55
|
+
release(): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Execute HTTP request with retry logic.
|
|
59
|
+
* Handles timeouts, network errors, and retries.
|
|
60
|
+
*
|
|
61
|
+
* @param url - Request URL
|
|
62
|
+
* @param options - Fetch options
|
|
63
|
+
* @param config - Extension configuration
|
|
64
|
+
* @param namespace - Extension namespace for error messages
|
|
65
|
+
* @param semaphore - Concurrency semaphore (optional)
|
|
66
|
+
* @returns Response body or full response
|
|
67
|
+
*/
|
|
68
|
+
export declare function executeRequest(url: string, options: FetchOptions, config: FetchExtensionConfig, namespace: string, responseShape: ResponseShape, semaphore?: Semaphore | undefined): Promise<unknown>;
|
|
69
|
+
/**
|
|
70
|
+
* Create semaphore for concurrency control.
|
|
71
|
+
*
|
|
72
|
+
* @param maxConcurrent - Maximum concurrent requests
|
|
73
|
+
* @returns Semaphore instance or undefined if no limit
|
|
74
|
+
*/
|
|
75
|
+
export declare function createSemaphore(maxConcurrent: number | undefined): Semaphore | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Build request from endpoint config and arguments.
|
|
78
|
+
*
|
|
79
|
+
* @param config - Extension configuration
|
|
80
|
+
* @param endpointName - Endpoint name
|
|
81
|
+
* @param args - Request arguments
|
|
82
|
+
* @returns Request URL and options
|
|
83
|
+
*/
|
|
84
|
+
export declare function buildRequest(config: FetchExtensionConfig, endpointName: string, args: Record<string, unknown>): {
|
|
85
|
+
url: string;
|
|
86
|
+
options: FetchOptions;
|
|
87
|
+
responseShape: ResponseShape;
|
|
88
|
+
};
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/ext/fetch/request.ts"],"names":[],"mappings":"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"}
|