@demoscript/cli 1.0.2 → 1.0.3
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/dist/bundle.cjs +10952 -10633
- package/dist/commands/login.d.ts +4 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +109 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/push.d.ts +9 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +146 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/serve.d.ts +9 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +197 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +12 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +39 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/executor.d.ts +20 -0
- package/dist/lib/executor.d.ts.map +1 -0
- package/dist/lib/executor.js +185 -0
- package/dist/lib/executor.js.map +1 -0
- package/dist/lib/executor.test.d.ts +2 -0
- package/dist/lib/executor.test.d.ts.map +1 -0
- package/dist/lib/executor.test.js +62 -0
- package/dist/lib/executor.test.js.map +1 -0
- package/dist/lib/loader.d.ts +10 -0
- package/dist/lib/loader.d.ts.map +1 -0
- package/dist/lib/loader.js +156 -0
- package/dist/lib/loader.js.map +1 -0
- package/dist/lib/openapi.d.ts +108 -0
- package/dist/lib/openapi.d.ts.map +1 -0
- package/dist/lib/openapi.js +375 -0
- package/dist/lib/openapi.js.map +1 -0
- package/dist/lib/openapi.test.d.ts +2 -0
- package/dist/lib/openapi.test.d.ts.map +1 -0
- package/dist/lib/openapi.test.js +318 -0
- package/dist/lib/openapi.test.js.map +1 -0
- package/dist/lib/validator.d.ts +12 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +58 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/server/rest-proxy.d.ts +3 -0
- package/dist/server/rest-proxy.d.ts.map +1 -0
- package/dist/server/rest-proxy.js +34 -0
- package/dist/server/rest-proxy.js.map +1 -0
- package/dist/server/shell-executor.d.ts +3 -0
- package/dist/server/shell-executor.d.ts.map +1 -0
- package/dist/server/shell-executor.js +56 -0
- package/dist/server/shell-executor.js.map +1 -0
- package/dist/types.d.ts +312 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +33 -0
- package/dist/types.js.map +1 -0
- package/dist/ui-dist/assets/index-CtREFkwP.js +175 -0
- package/dist/ui-dist/assets/index-DTJEjfHv.css +1 -0
- package/dist/ui-dist/dist/assets/index-DZpZVgB7.js +177 -0
- package/dist/ui-dist/dist/assets/index-DZpZVgB7.js.map +1 -0
- package/dist/ui-dist/dist/assets/index-OFqwkvWn.css +1 -0
- package/dist/ui-dist/{assets/index-cngvCrhl.js → dist/assets/index-Uvktqp4J.js} +31 -31
- package/dist/ui-dist/dist/assets/index-Uvktqp4J.js.map +1 -0
- package/dist/ui-dist/dist/assets/index-pTz7wI27.css +1 -0
- package/dist/ui-dist/{assets/index-DFwzKJ81.css → dist/assets/index.css} +1 -1
- package/dist/ui-dist/dist/assets/index.js +177 -0
- package/dist/ui-dist/dist/assets/index.js.map +1 -0
- package/dist/ui-dist/dist/demo.yaml +120 -0
- package/dist/ui-dist/dist/index.html +14 -0
- package/dist/ui-dist/index.html +2 -2
- package/package.json +1 -1
- /package/dist/ui-dist/{favicon.svg → dist/favicon.svg} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export async function executeRestStep(step, config, variables) {
|
|
2
|
+
// Parse method and endpoint
|
|
3
|
+
const [method, ...endpointParts] = step.rest.split(' ');
|
|
4
|
+
const endpoint = endpointParts.join(' ');
|
|
5
|
+
// Substitute variables in endpoint
|
|
6
|
+
const resolvedEndpoint = substituteVariables(endpoint, variables);
|
|
7
|
+
// Build full URL
|
|
8
|
+
const baseUrl = step.base_url || config.settings?.base_url || '';
|
|
9
|
+
const fullUrl = `${baseUrl}${resolvedEndpoint}`;
|
|
10
|
+
// Build headers
|
|
11
|
+
const headers = {
|
|
12
|
+
'Content-Type': 'application/json',
|
|
13
|
+
...substituteInObject(step.headers || {}, variables),
|
|
14
|
+
};
|
|
15
|
+
// Build body from form defaults or body
|
|
16
|
+
let body = undefined;
|
|
17
|
+
if (method !== 'GET') {
|
|
18
|
+
if (step.form) {
|
|
19
|
+
body = Object.fromEntries(step.form.map((field) => {
|
|
20
|
+
const value = field.default ?? '';
|
|
21
|
+
const resolved = typeof value === 'string' ? substituteVariables(value, variables) : value;
|
|
22
|
+
return [field.name, resolved];
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
else if (step.body) {
|
|
26
|
+
body = substituteInObject(step.body, variables);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Execute request
|
|
30
|
+
const response = await fetch(fullUrl, {
|
|
31
|
+
method,
|
|
32
|
+
headers,
|
|
33
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
34
|
+
});
|
|
35
|
+
const responseBody = await response.json().catch(() => null);
|
|
36
|
+
const result = {
|
|
37
|
+
request: {
|
|
38
|
+
method,
|
|
39
|
+
url: fullUrl,
|
|
40
|
+
headers,
|
|
41
|
+
body,
|
|
42
|
+
},
|
|
43
|
+
status: response.status,
|
|
44
|
+
body: responseBody,
|
|
45
|
+
};
|
|
46
|
+
// Save variables from initial response BEFORE polling
|
|
47
|
+
// This allows poll endpoint to reference saved variables like $jobId
|
|
48
|
+
// Supported special keywords: _status (HTTP status code)
|
|
49
|
+
if (step.save) {
|
|
50
|
+
for (const [varName, path] of Object.entries(step.save)) {
|
|
51
|
+
if (path === '_status') {
|
|
52
|
+
// Special keyword: capture HTTP status code (200, 404, etc.)
|
|
53
|
+
variables[varName] = response.status;
|
|
54
|
+
}
|
|
55
|
+
else if (responseBody) {
|
|
56
|
+
// JSON path extraction from response body
|
|
57
|
+
const value = getNestedValue(responseBody, path);
|
|
58
|
+
if (value !== undefined) {
|
|
59
|
+
variables[varName] = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Handle polling if configured
|
|
65
|
+
if (step.poll) {
|
|
66
|
+
const pollingResult = await executePoll(step.poll, baseUrl, headers, variables, config.settings?.polling);
|
|
67
|
+
result.pollingResult = pollingResult;
|
|
68
|
+
result.body = pollingResult.finalResponse;
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
async function executePoll(pollConfig, baseUrl, headers, variables, defaults) {
|
|
73
|
+
const interval = pollConfig.interval ?? defaults?.interval ?? 2000;
|
|
74
|
+
const maxAttempts = pollConfig.max_attempts ?? defaults?.max_attempts ?? 30;
|
|
75
|
+
const endpoint = substituteVariables(pollConfig.endpoint, variables);
|
|
76
|
+
// If endpoint is already an absolute URL, don't prepend baseUrl
|
|
77
|
+
const pollUrl = endpoint.startsWith('http://') || endpoint.startsWith('https://')
|
|
78
|
+
? endpoint
|
|
79
|
+
: `${baseUrl}${endpoint}`;
|
|
80
|
+
let attempts = 0;
|
|
81
|
+
let lastResponse = null;
|
|
82
|
+
while (attempts < maxAttempts) {
|
|
83
|
+
attempts++;
|
|
84
|
+
const response = await fetch(pollUrl, {
|
|
85
|
+
method: 'GET',
|
|
86
|
+
headers,
|
|
87
|
+
});
|
|
88
|
+
lastResponse = await response.json().catch(() => null);
|
|
89
|
+
// Check success condition
|
|
90
|
+
if (evaluateCondition(pollConfig.success_when, lastResponse)) {
|
|
91
|
+
return { attempts, finalResponse: lastResponse };
|
|
92
|
+
}
|
|
93
|
+
// Check failure condition if specified
|
|
94
|
+
if (pollConfig.failure_when && evaluateCondition(pollConfig.failure_when, lastResponse)) {
|
|
95
|
+
throw new Error(`Polling failed: ${pollConfig.failure_when} matched after ${attempts} attempts`);
|
|
96
|
+
}
|
|
97
|
+
// Wait before next attempt
|
|
98
|
+
await sleep(interval);
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Polling timed out after ${maxAttempts} attempts`);
|
|
101
|
+
}
|
|
102
|
+
export function evaluateCondition(condition, response) {
|
|
103
|
+
// Parse conditions like "response.status == 'complete'" or "status == 'confirmed'"
|
|
104
|
+
// Support both with and without "response." prefix
|
|
105
|
+
let match = condition.match(/^response\.(.+?)\s*(==|!=)\s*(.+)$/);
|
|
106
|
+
if (!match) {
|
|
107
|
+
// Try without response. prefix
|
|
108
|
+
match = condition.match(/^(.+?)\s*(==|!=)\s*(.+)$/);
|
|
109
|
+
}
|
|
110
|
+
if (!match) {
|
|
111
|
+
console.warn(`Unable to parse condition: ${condition}`);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const [, path, operator, expectedRaw] = match;
|
|
115
|
+
const actualValue = getNestedValue(response, path);
|
|
116
|
+
// Parse expected value
|
|
117
|
+
let expectedValue;
|
|
118
|
+
if (expectedRaw === 'true') {
|
|
119
|
+
expectedValue = true;
|
|
120
|
+
}
|
|
121
|
+
else if (expectedRaw === 'false') {
|
|
122
|
+
expectedValue = false;
|
|
123
|
+
}
|
|
124
|
+
else if (expectedRaw === 'null') {
|
|
125
|
+
expectedValue = null;
|
|
126
|
+
}
|
|
127
|
+
else if (/^['"](.*)['"]$/.test(expectedRaw)) {
|
|
128
|
+
expectedValue = expectedRaw.slice(1, -1);
|
|
129
|
+
}
|
|
130
|
+
else if (!isNaN(Number(expectedRaw))) {
|
|
131
|
+
expectedValue = Number(expectedRaw);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
expectedValue = expectedRaw;
|
|
135
|
+
}
|
|
136
|
+
if (operator === '==') {
|
|
137
|
+
return actualValue === expectedValue;
|
|
138
|
+
}
|
|
139
|
+
else if (operator === '!=') {
|
|
140
|
+
return actualValue !== expectedValue;
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
export function getNestedValue(obj, path) {
|
|
145
|
+
const parts = path.split('.');
|
|
146
|
+
let current = obj;
|
|
147
|
+
for (const part of parts) {
|
|
148
|
+
if (current === null || current === undefined) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
if (typeof current === 'object') {
|
|
152
|
+
current = current[part];
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return current;
|
|
159
|
+
}
|
|
160
|
+
function sleep(ms) {
|
|
161
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
162
|
+
}
|
|
163
|
+
function substituteVariables(str, variables) {
|
|
164
|
+
return str.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, name) => {
|
|
165
|
+
const value = variables[name];
|
|
166
|
+
return value !== undefined ? String(value) : `$${name}`;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function substituteInObject(obj, variables) {
|
|
170
|
+
if (typeof obj === 'string') {
|
|
171
|
+
return substituteVariables(obj, variables);
|
|
172
|
+
}
|
|
173
|
+
if (Array.isArray(obj)) {
|
|
174
|
+
return obj.map((item) => substituteInObject(item, variables));
|
|
175
|
+
}
|
|
176
|
+
if (obj && typeof obj === 'object') {
|
|
177
|
+
const result = {};
|
|
178
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
179
|
+
result[key] = substituteInObject(value, variables);
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
return obj;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/lib/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.test.d.ts","sourceRoot":"","sources":["../../src/lib/executor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { evaluateCondition, getNestedValue } from './executor.js';
|
|
3
|
+
describe('evaluateCondition', () => {
|
|
4
|
+
it('evaluates string equality', () => {
|
|
5
|
+
const response = { status: 'complete' };
|
|
6
|
+
expect(evaluateCondition("response.status == 'complete'", response)).toBe(true);
|
|
7
|
+
expect(evaluateCondition("response.status == 'pending'", response)).toBe(false);
|
|
8
|
+
});
|
|
9
|
+
it('evaluates string inequality', () => {
|
|
10
|
+
const response = { status: 'pending' };
|
|
11
|
+
expect(evaluateCondition("response.status != 'complete'", response)).toBe(true);
|
|
12
|
+
expect(evaluateCondition("response.status != 'pending'", response)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it('evaluates boolean values', () => {
|
|
15
|
+
const response = { ready: true, done: false };
|
|
16
|
+
expect(evaluateCondition('response.ready == true', response)).toBe(true);
|
|
17
|
+
expect(evaluateCondition('response.done == false', response)).toBe(true);
|
|
18
|
+
expect(evaluateCondition('response.ready == false', response)).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
it('evaluates numeric values', () => {
|
|
21
|
+
const response = { count: 42, value: 0 };
|
|
22
|
+
expect(evaluateCondition('response.count == 42', response)).toBe(true);
|
|
23
|
+
expect(evaluateCondition('response.value == 0', response)).toBe(true);
|
|
24
|
+
expect(evaluateCondition('response.count == 43', response)).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
it('evaluates nested paths', () => {
|
|
27
|
+
const response = { data: { job: { status: 'done' } } };
|
|
28
|
+
expect(evaluateCondition("response.data.job.status == 'done'", response)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
it('evaluates null values', () => {
|
|
31
|
+
const response = { error: null };
|
|
32
|
+
expect(evaluateCondition('response.error == null', response)).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('returns false for invalid conditions', () => {
|
|
35
|
+
expect(evaluateCondition('invalid condition', {})).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('getNestedValue', () => {
|
|
39
|
+
it('extracts simple property', () => {
|
|
40
|
+
expect(getNestedValue({ name: 'test' }, 'name')).toBe('test');
|
|
41
|
+
});
|
|
42
|
+
it('extracts deeply nested property', () => {
|
|
43
|
+
const obj = { a: { b: { c: { d: 'value' } } } };
|
|
44
|
+
expect(getNestedValue(obj, 'a.b.c.d')).toBe('value');
|
|
45
|
+
});
|
|
46
|
+
it('returns undefined for missing path', () => {
|
|
47
|
+
expect(getNestedValue({ name: 'test' }, 'missing')).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
it('handles null in path', () => {
|
|
50
|
+
const obj = { data: null };
|
|
51
|
+
expect(getNestedValue(obj, 'data.name')).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
it('handles undefined in path', () => {
|
|
54
|
+
const obj = { data: undefined };
|
|
55
|
+
expect(getNestedValue(obj, 'data.name')).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
it('extracts array element by index', () => {
|
|
58
|
+
const obj = { items: ['a', 'b', 'c'] };
|
|
59
|
+
expect(getNestedValue(obj, 'items.1')).toBe('b');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=executor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.test.js","sourceRoot":"","sources":["../../src/lib/executor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DemoConfig, DemoRecordings } from '../types.js';
|
|
2
|
+
import { type OpenApiSpec } from './openapi.js';
|
|
3
|
+
interface LoadedDemo {
|
|
4
|
+
config: DemoConfig;
|
|
5
|
+
recordings: DemoRecordings | null;
|
|
6
|
+
openapiSpec: OpenApiSpec | null;
|
|
7
|
+
}
|
|
8
|
+
export declare function loadDemo(demoFile: string, skipValidation?: boolean): Promise<LoadedDemo>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/lib/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAA8D,MAAM,aAAa,CAAC;AAG1H,OAAO,EAAyD,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAsCvG,UAAU,UAAU;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,UAAU,EAAE,cAAc,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CACjC;AAED,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,UAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CA+C5F"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
import { isRestStep, isStepGroup } from '../types.js';
|
|
5
|
+
import { validateDemoConfig, formatValidationErrors } from './validator.js';
|
|
6
|
+
import { fetchOpenApiSpec, generateFormFields, mergeFormFields } from './openapi.js';
|
|
7
|
+
/**
|
|
8
|
+
* Convert camelCase variable name to human-readable label
|
|
9
|
+
* e.g. "accessToken" -> "Access Token", "adminUserId" -> "Admin User Id"
|
|
10
|
+
*/
|
|
11
|
+
function formatSaveLabel(varName) {
|
|
12
|
+
return varName
|
|
13
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
14
|
+
.replace(/^./, str => str.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Infer result display type from variable name and json path
|
|
18
|
+
*/
|
|
19
|
+
function inferResultType(varName, jsonPath) {
|
|
20
|
+
const nameLower = varName.toLowerCase();
|
|
21
|
+
const pathLower = jsonPath.toLowerCase();
|
|
22
|
+
// Token/ID fields -> mono (monospace)
|
|
23
|
+
if (nameLower.includes('token') || nameLower.includes('id') ||
|
|
24
|
+
pathLower.includes('token') || pathLower.includes('id')) {
|
|
25
|
+
return 'mono';
|
|
26
|
+
}
|
|
27
|
+
// Address/wallet fields
|
|
28
|
+
if (nameLower.includes('address') || nameLower.includes('wallet')) {
|
|
29
|
+
return 'address';
|
|
30
|
+
}
|
|
31
|
+
// URL fields
|
|
32
|
+
if (nameLower.includes('url') || nameLower.includes('link')) {
|
|
33
|
+
return 'link';
|
|
34
|
+
}
|
|
35
|
+
return 'text';
|
|
36
|
+
}
|
|
37
|
+
export async function loadDemo(demoFile, skipValidation = false) {
|
|
38
|
+
if (!existsSync(demoFile)) {
|
|
39
|
+
throw new Error(`Demo file not found: ${demoFile}`);
|
|
40
|
+
}
|
|
41
|
+
const content = readFileSync(demoFile, 'utf-8');
|
|
42
|
+
const config = yaml.load(content);
|
|
43
|
+
// Validate against JSON Schema
|
|
44
|
+
if (!skipValidation) {
|
|
45
|
+
const result = validateDemoConfig(config);
|
|
46
|
+
if (!result.valid) {
|
|
47
|
+
throw new Error(formatValidationErrors(result.errors));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Basic required fields check (fallback)
|
|
51
|
+
if (!config.title) {
|
|
52
|
+
throw new Error('Demo config missing required field: title');
|
|
53
|
+
}
|
|
54
|
+
if (!config.steps || !Array.isArray(config.steps)) {
|
|
55
|
+
throw new Error('Demo config missing required field: steps');
|
|
56
|
+
}
|
|
57
|
+
// Try to load recordings
|
|
58
|
+
const demoDir = dirname(demoFile);
|
|
59
|
+
const recordingsPath = join(demoDir, 'recordings.json');
|
|
60
|
+
let recordings = null;
|
|
61
|
+
if (existsSync(recordingsPath)) {
|
|
62
|
+
const recordingsContent = readFileSync(recordingsPath, 'utf-8');
|
|
63
|
+
recordings = JSON.parse(recordingsContent);
|
|
64
|
+
}
|
|
65
|
+
// Fetch OpenAPI spec if configured
|
|
66
|
+
const openapiUrl = config.settings?.openapi;
|
|
67
|
+
let openapiSpec = null;
|
|
68
|
+
if (openapiUrl) {
|
|
69
|
+
openapiSpec = await fetchOpenApiSpec(openapiUrl);
|
|
70
|
+
if (openapiSpec) {
|
|
71
|
+
// Process steps to generate forms from OpenAPI
|
|
72
|
+
config.steps = processStepsWithOpenApi(config.steps, openapiSpec, config.settings?.base_url);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { config, recordings, openapiSpec };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Process steps to generate form fields from OpenAPI spec
|
|
79
|
+
*/
|
|
80
|
+
function processStepsWithOpenApi(steps, spec, baseUrl) {
|
|
81
|
+
return steps.map(item => {
|
|
82
|
+
if (isStepGroup(item)) {
|
|
83
|
+
return {
|
|
84
|
+
...item,
|
|
85
|
+
steps: processStepsArray(item.steps, spec, baseUrl)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (isRestStep(item)) {
|
|
89
|
+
return processRestStepWithOpenApi(item, spec, baseUrl);
|
|
90
|
+
}
|
|
91
|
+
return item;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Process a flat array of steps (inside a group)
|
|
96
|
+
*/
|
|
97
|
+
function processStepsArray(steps, spec, baseUrl) {
|
|
98
|
+
return steps.map(step => {
|
|
99
|
+
if (isRestStep(step)) {
|
|
100
|
+
return processRestStepWithOpenApi(step, spec, baseUrl);
|
|
101
|
+
}
|
|
102
|
+
return step;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Process a single REST step to generate form fields and result fields from OpenAPI
|
|
107
|
+
*/
|
|
108
|
+
function processRestStepWithOpenApi(step, spec, baseUrl) {
|
|
109
|
+
// Get method and path from step
|
|
110
|
+
let method;
|
|
111
|
+
let path;
|
|
112
|
+
if ('rest' in step) {
|
|
113
|
+
const parts = step.rest.trim().split(/\s+/);
|
|
114
|
+
if (parts.length === 1) {
|
|
115
|
+
method = 'GET';
|
|
116
|
+
path = parts[0];
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
method = parts[0].toUpperCase();
|
|
120
|
+
path = parts.slice(1).join(' ');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
method = step.method;
|
|
125
|
+
path = step.path;
|
|
126
|
+
}
|
|
127
|
+
// Generate form fields from OpenAPI request body schema
|
|
128
|
+
const openapiFields = generateFormFields(spec, method, path);
|
|
129
|
+
// Generate result fields from save mappings (only if results not specified)
|
|
130
|
+
// This shows what variables were captured from the response
|
|
131
|
+
let results = step.results;
|
|
132
|
+
if (!results || results.length === 0) {
|
|
133
|
+
if (step.save && Object.keys(step.save).length > 0) {
|
|
134
|
+
// Generate results from save mappings
|
|
135
|
+
results = Object.entries(step.save).map(([varName, jsonPath]) => ({
|
|
136
|
+
key: jsonPath,
|
|
137
|
+
label: formatSaveLabel(varName),
|
|
138
|
+
type: inferResultType(varName, jsonPath)
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// If no OpenAPI data found, return step unchanged
|
|
143
|
+
if (openapiFields.length === 0 && !results) {
|
|
144
|
+
return step;
|
|
145
|
+
}
|
|
146
|
+
// Merge form fields with defaults and manual overrides
|
|
147
|
+
const mergedFields = openapiFields.length > 0
|
|
148
|
+
? mergeFormFields(openapiFields, step.defaults, step.form)
|
|
149
|
+
: step.form;
|
|
150
|
+
return {
|
|
151
|
+
...step,
|
|
152
|
+
form: mergedFields || step.form,
|
|
153
|
+
results: results || step.results
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/lib/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { FormField, ResultField } from '../types.js';
|
|
2
|
+
export interface OpenApiSpec {
|
|
3
|
+
openapi: string;
|
|
4
|
+
info: {
|
|
5
|
+
title: string;
|
|
6
|
+
version: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
};
|
|
9
|
+
paths: Record<string, OpenApiPath>;
|
|
10
|
+
components?: {
|
|
11
|
+
schemas?: Record<string, JsonSchema>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface OpenApiPath {
|
|
15
|
+
get?: OpenApiOperation;
|
|
16
|
+
post?: OpenApiOperation;
|
|
17
|
+
put?: OpenApiOperation;
|
|
18
|
+
delete?: OpenApiOperation;
|
|
19
|
+
patch?: OpenApiOperation;
|
|
20
|
+
}
|
|
21
|
+
export interface OpenApiOperation {
|
|
22
|
+
summary?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
operationId?: string;
|
|
25
|
+
tags?: string[];
|
|
26
|
+
parameters?: OpenApiParameter[];
|
|
27
|
+
requestBody?: {
|
|
28
|
+
required?: boolean;
|
|
29
|
+
content: Record<string, {
|
|
30
|
+
schema: JsonSchema;
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
responses: Record<string, {
|
|
34
|
+
description: string;
|
|
35
|
+
content?: Record<string, {
|
|
36
|
+
schema: JsonSchema;
|
|
37
|
+
}>;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
export interface OpenApiParameter {
|
|
41
|
+
name: string;
|
|
42
|
+
in: 'path' | 'query' | 'header';
|
|
43
|
+
required?: boolean;
|
|
44
|
+
schema?: JsonSchema;
|
|
45
|
+
description?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface JsonSchema {
|
|
48
|
+
type?: string;
|
|
49
|
+
properties?: Record<string, JsonSchema>;
|
|
50
|
+
required?: string[];
|
|
51
|
+
default?: unknown;
|
|
52
|
+
description?: string;
|
|
53
|
+
enum?: unknown[];
|
|
54
|
+
items?: JsonSchema;
|
|
55
|
+
$ref?: string;
|
|
56
|
+
allOf?: JsonSchema[];
|
|
57
|
+
oneOf?: JsonSchema[];
|
|
58
|
+
anyOf?: JsonSchema[];
|
|
59
|
+
format?: string;
|
|
60
|
+
minimum?: number;
|
|
61
|
+
maximum?: number;
|
|
62
|
+
minLength?: number;
|
|
63
|
+
maxLength?: number;
|
|
64
|
+
pattern?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Fetch and cache an OpenAPI spec
|
|
68
|
+
*/
|
|
69
|
+
export declare function fetchOpenApiSpec(url: string): Promise<OpenApiSpec | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Clear the OpenAPI spec cache
|
|
72
|
+
*/
|
|
73
|
+
export declare function clearOpenApiCache(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Generate FormField[] from an OpenAPI operation's request body
|
|
76
|
+
*/
|
|
77
|
+
export declare function generateFormFields(spec: OpenApiSpec, method: string, path: string): FormField[];
|
|
78
|
+
/**
|
|
79
|
+
* Merge OpenAPI-generated fields with manual defaults and overrides
|
|
80
|
+
*
|
|
81
|
+
* Priority (smart merge - each layer inherits from previous):
|
|
82
|
+
* 1. OpenAPI schema (base: type, required, options, description)
|
|
83
|
+
* 2. defaults: values (override default values only)
|
|
84
|
+
* 3. form: fields (partial override - only specified properties are changed)
|
|
85
|
+
*
|
|
86
|
+
* This allows YAML like:
|
|
87
|
+
* defaults:
|
|
88
|
+
* wallet: "0x..."
|
|
89
|
+
* form:
|
|
90
|
+
* - name: wallet
|
|
91
|
+
* label: "From Wallet" # Only override the label, inherit default from above
|
|
92
|
+
*/
|
|
93
|
+
export declare function mergeFormFields(openapiFields: FormField[], defaults?: Record<string, unknown>, manualFields?: FormField[]): FormField[];
|
|
94
|
+
/**
|
|
95
|
+
* Get endpoint info from OpenAPI for display
|
|
96
|
+
*/
|
|
97
|
+
export declare function getEndpointInfo(spec: OpenApiSpec, method: string, path: string): {
|
|
98
|
+
summary?: string;
|
|
99
|
+
description?: string;
|
|
100
|
+
} | null;
|
|
101
|
+
/**
|
|
102
|
+
* Generate ResultField[] from an OpenAPI operation's response schema
|
|
103
|
+
*
|
|
104
|
+
* When a REST step doesn't specify `results:`, this function can auto-generate
|
|
105
|
+
* result fields from the OpenAPI response schema.
|
|
106
|
+
*/
|
|
107
|
+
export declare function generateResultFields(spec: OpenApiSpec, method: string, path: string): ResultField[];
|
|
108
|
+
//# sourceMappingURL=openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../src/lib/openapi.ts"],"names":[],"mappings":"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"}
|