@sungen/driver-api 3.1.2-beta.122 → 3.1.2-beta.124
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/package.json +2 -2
- package/src/api-catalog.ts +2 -0
- package/src/index.ts +3 -1
- package/src/openapi-import.ts +16 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sungen/driver-api",
|
|
3
|
-
"version": "3.1.2-beta.
|
|
3
|
+
"version": "3.1.2-beta.124",
|
|
4
4
|
"description": "Sungen API capability — the @api annotation, API catalog, OpenAPI import + `sungen api import`, and the specs/api.ts runtime template. Plugs into @sun-asterisk/sungen via the capability SPI.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"author": "eqe team (engineer & quality) — Sun Asterisk",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@sun-asterisk/sungen": "3.1.2-beta.
|
|
16
|
+
"@sun-asterisk/sungen": "3.1.2-beta.124",
|
|
17
17
|
"commander": "^14.0.2",
|
|
18
18
|
"yaml": "^2.8.2"
|
|
19
19
|
},
|
package/src/api-catalog.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface ApiEntry {
|
|
|
27
27
|
method: HttpMethod;
|
|
28
28
|
path: string;
|
|
29
29
|
body?: unknown;
|
|
30
|
+
encoding?: 'json' | 'form' | 'multipart'; // request-body wire format (default json); form = application/x-www-form-urlencoded
|
|
30
31
|
headers?: Record<string, string>; // per-endpoint header templates; `:param` tokens bind at runtime (flow auth, e.g. authorization: "Bearer :token")
|
|
31
32
|
params: string[];
|
|
32
33
|
expect?: { status?: number | string };
|
|
@@ -89,6 +90,7 @@ function parseEntries(file: string, scope: 'screen' | 'shared'): Map<string, Api
|
|
|
89
90
|
method: String(v.method).toUpperCase() as HttpMethod,
|
|
90
91
|
path: v.path,
|
|
91
92
|
body: v.body,
|
|
93
|
+
encoding: v.encoding === 'form' || v.encoding === 'multipart' ? v.encoding : undefined, // default (undefined) = json
|
|
92
94
|
headers: v.headers && typeof v.headers === 'object' ? Object.fromEntries(Object.entries(v.headers).map(([k, hv]) => [k, String(hv)])) : undefined,
|
|
93
95
|
params: Array.isArray(v.params) ? v.params.map((p: any) => String(p)) : [],
|
|
94
96
|
expect: v.expect && typeof v.expect === 'object' ? { status: v.expect.status } : undefined,
|
package/src/index.ts
CHANGED
|
@@ -85,7 +85,9 @@ function apiPreconditionCodegen(input: { tags: string[]; screenName: string; cwd
|
|
|
85
85
|
// their `:param` placeholders bind at runtime from the same params — this is the flow auth/token
|
|
86
86
|
// mechanism (the dynamic value comes via an override like `token={{login.body.token}}`).
|
|
87
87
|
const hdr = entry.headers && Object.keys(entry.headers).length ? `, headers: ${JSON.stringify(entry.headers)}` : '';
|
|
88
|
-
|
|
88
|
+
// request-body wire format (default json); `form` → x-www-form-urlencoded, `multipart` → form-data (#345).
|
|
89
|
+
const enc = entry.encoding ? `, encoding: ${JSON.stringify(entry.encoding)}` : '';
|
|
90
|
+
const req = `{ method: ${JSON.stringify(entry.method)}, path: ${JSON.stringify(entry.path)}${entry.body !== undefined ? `, body: ${JSON.stringify(entry.body)}` : ''}${enc}${hdr}, datasource: ${ds} }`;
|
|
89
91
|
// @concurrent:N → callN (N parallel calls, aggregate result); else a single call. @hybrid adds
|
|
90
92
|
// the storageState opts so the request reuses the UI auth session.
|
|
91
93
|
const callExpr = concurrent
|
package/src/openapi-import.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ImportedApiEntry {
|
|
|
14
14
|
path: string;
|
|
15
15
|
params?: string[];
|
|
16
16
|
body?: Record<string, string>;
|
|
17
|
+
encoding?: 'form' | 'multipart'; // set when the requestBody is form/multipart (json omitted = default)
|
|
17
18
|
expect?: { status: number };
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -52,16 +53,24 @@ function expectedStatus(responses: Record<string, unknown> | undefined): number
|
|
|
52
53
|
return success ?? codes[0];
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
/** Body property names → a `{ prop: ":prop" }` template, + the wire encoding (json | form | multipart),
|
|
57
|
+
* best-effort from the requestBody content-type (#345). JSON is the default (encoding omitted). */
|
|
58
|
+
function bodyTemplate(op: any): { body?: Record<string, string>; props: string[]; encoding?: 'form' | 'multipart' } {
|
|
59
|
+
const content = op?.requestBody?.content ?? {};
|
|
60
|
+
// Prefer JSON; else fall back to form-urlencoded / multipart (those set encoding).
|
|
61
|
+
const pick = content['application/json'] ? { ct: 'application/json' as const, encoding: undefined }
|
|
62
|
+
: content['application/x-www-form-urlencoded'] ? { ct: 'application/x-www-form-urlencoded' as const, encoding: 'form' as const }
|
|
63
|
+
: content['multipart/form-data'] ? { ct: 'multipart/form-data' as const, encoding: 'multipart' as const }
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!pick) return { props: [] };
|
|
66
|
+
const schema = content[pick.ct]?.schema;
|
|
58
67
|
const props = schema && typeof schema === 'object' && schema.properties && typeof schema.properties === 'object'
|
|
59
68
|
? Object.keys(schema.properties)
|
|
60
69
|
: [];
|
|
61
|
-
if (!props.length) return { props: [] };
|
|
70
|
+
if (!props.length) return { props: [], encoding: pick.encoding };
|
|
62
71
|
const body: Record<string, string> = {};
|
|
63
72
|
for (const p of props) body[p] = `:${p}`;
|
|
64
|
-
return { body, props };
|
|
73
|
+
return { body, props, encoding: pick.encoding };
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
export interface ImportResult {
|
|
@@ -89,7 +98,7 @@ export function importOpenApi(doc: any, datasource = 'app_api'): ImportResult {
|
|
|
89
98
|
|
|
90
99
|
const catalogPath = toCatalogPath(rawPath);
|
|
91
100
|
const pathParams = (catalogPath.match(/:([A-Za-z_][A-Za-z0-9_]*)/g) || []).map((s) => s.slice(1));
|
|
92
|
-
const { body, props } = bodyTemplate(op);
|
|
101
|
+
const { body, props, encoding } = bodyTemplate(op);
|
|
93
102
|
const params = [...new Set([...pathParams, ...props])];
|
|
94
103
|
|
|
95
104
|
let name = typeof op.operationId === 'string' && /^[A-Za-z_][A-Za-z0-9_]*$/.test(op.operationId)
|
|
@@ -107,6 +116,7 @@ export function importOpenApi(doc: any, datasource = 'app_api'): ImportResult {
|
|
|
107
116
|
path: catalogPath,
|
|
108
117
|
...(params.length ? { params } : {}),
|
|
109
118
|
...(body ? { body } : {}),
|
|
119
|
+
...(encoding ? { encoding } : {}),
|
|
110
120
|
...(status != null ? { expect: { status } } : {}),
|
|
111
121
|
};
|
|
112
122
|
}
|