@openapi-flow/core 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.
@@ -0,0 +1,81 @@
1
+ import { checkPrimitive, isObject, looksLikeCredential, } from '../utils/validation.js';
2
+ export function isSafeMethod(method) {
3
+ return ['GET', 'HEAD', 'OPTIONS', 'TRACE', 'QUERY'].includes(method);
4
+ }
5
+ export function makeUrl(operation, origin, inputs, missing) {
6
+ let path = operation.path;
7
+ for (const parameter of operation.parameters) {
8
+ const key = parameter.in + '.' + parameter.name;
9
+ const value = inputs[key];
10
+ if (value === undefined) {
11
+ if (parameter.required)
12
+ missing.push(key);
13
+ continue;
14
+ }
15
+ checkPrimitive(value, parameter.schema, 'plan.inputs.' + key);
16
+ if (parameter.in === 'path')
17
+ path = path.replace('{' + parameter.name + '}', encodeURIComponent(String(value)));
18
+ }
19
+ const url = new URL(path, origin);
20
+ for (const parameter of operation.parameters) {
21
+ if (parameter.in !== 'query')
22
+ continue;
23
+ const key = 'query.' + parameter.name;
24
+ if (inputs[key] !== undefined)
25
+ url.searchParams.set(parameter.name, String(inputs[key]));
26
+ }
27
+ return url.href;
28
+ }
29
+ export function makeBody(operation, inputs, missing) {
30
+ if (!operation.body)
31
+ return undefined;
32
+ const value = inputs.body;
33
+ if (value === undefined) {
34
+ if (operation.body.required)
35
+ missing.push('body');
36
+ return undefined;
37
+ }
38
+ if (!isObject(value))
39
+ throw new Error('plan.inputs.body must be an object');
40
+ for (const [name, field] of Object.entries(value)) {
41
+ const schema = operation.body.properties[name];
42
+ if (!schema)
43
+ throw new Error('plan.inputs.body.' + name + ' is not declared in the OAS schema');
44
+ if (looksLikeCredential(name)) {
45
+ throw new Error('plan.inputs.body.' +
46
+ name +
47
+ ' looks like a credential; v1 has no credential binding');
48
+ }
49
+ checkPrimitive(field, schema, 'plan.inputs.body.' + name);
50
+ }
51
+ for (const name of operation.body.requiredProperties) {
52
+ if (!Object.hasOwn(value, name))
53
+ missing.push('body.' + name);
54
+ }
55
+ return JSON.stringify(value);
56
+ }
57
+ export function assertionCode(status, expectedBody, requiredFields = {}) {
58
+ const expected = JSON.stringify(expectedBody);
59
+ const required = JSON.stringify(requiredFields);
60
+ return [
61
+ 'const items = $input.all();',
62
+ "if (items.length !== 1) throw new Error('Expected one response item');",
63
+ 'const response = items[0].json;',
64
+ 'if (response.statusCode !== ' +
65
+ status +
66
+ ') throw new Error("Expected HTTP ' +
67
+ status +
68
+ ', got " + response.statusCode);',
69
+ 'const expected = ' + expected + ';',
70
+ 'const required = ' + required + ';',
71
+ 'for (const [key, type] of Object.entries(required)) {',
72
+ ' const value = response.body?.[key];',
73
+ ' const valid = type === "integer" ? Number.isSafeInteger(value) : type === "number" ? typeof value === "number" && Number.isFinite(value) : typeof value === type;',
74
+ ' if (!valid) throw new Error("Missing or invalid response body field: " + key);',
75
+ '}',
76
+ 'for (const [key, value] of Object.entries(expected)) {',
77
+ ' if (response.body?.[key] !== value) throw new Error("Unexpected response body field: " + key);',
78
+ '}',
79
+ 'return items;',
80
+ ].join('\n');
81
+ }
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@openapi-flow/core",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "description": "Build reviewable n8n workflows from OpenAPI documents and natural-language scenarios",
6
+ "keywords": [
7
+ "openapi",
8
+ "n8n",
9
+ "workflow",
10
+ "langchain"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/carefreelife98/openapi-flow.git",
15
+ "directory": "packages/core"
16
+ },
17
+ "homepage": "https://github.com/carefreelife98/openapi-flow#readme",
18
+ "bugs": "https://github.com/carefreelife98/openapi-flow/issues",
19
+ "author": "carefreelife98",
20
+ "type": "module",
21
+ "engines": {
22
+ "node": ">=24"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/public-api.d.ts",
27
+ "default": "./dist/public-api.js"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE",
34
+ "THIRD_PARTY_NOTICES.md"
35
+ ],
36
+ "publishConfig": {
37
+ "registry": "https://registry.npmjs.org/",
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.json",
42
+ "prepack": "npm run build",
43
+ "prepublishOnly": "npm run typecheck && npm run lint && npm run format:check && npm test",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "lint": "eslint src test integration",
46
+ "format:check": "prettier --check src test integration package.json tsconfig.json eslint.config.mjs",
47
+ "format": "prettier --write src test integration package.json tsconfig.json eslint.config.mjs",
48
+ "test": "npm run build && node --test",
49
+ "test:real-oas": "npm run build && node --test integration/real-oas.mjs"
50
+ },
51
+ "dependencies": {
52
+ "@n8n/workflow-sdk": "0.33.1",
53
+ "@scalar/openapi-parser": "0.29.7",
54
+ "@scalar/openapi-validator": "0.1.6"
55
+ },
56
+ "peerDependencies": {
57
+ "@langchain/core": "^1.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "10.0.1",
61
+ "@langchain/core": "1.2.12",
62
+ "@types/node": "^24.0.0",
63
+ "eslint": "10.11.0",
64
+ "prettier": "3.9.9",
65
+ "typescript": "5.9.3",
66
+ "typescript-eslint": "8.70.1"
67
+ }
68
+ }