dbgate-rest 7.1.3-alpha.2

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,56 @@
1
+ import type { RestApiDefinition } from './restApiDef';
2
+ import type { AxiosInstance } from 'axios';
3
+ export interface GraphQLTypeRef {
4
+ kind: string;
5
+ name?: string;
6
+ ofType?: GraphQLTypeRef | null;
7
+ }
8
+ export interface GraphQLInputValue {
9
+ name: string;
10
+ description?: string;
11
+ type: GraphQLTypeRef;
12
+ defaultValue?: string;
13
+ }
14
+ export interface GraphQLField {
15
+ name: string;
16
+ description?: string;
17
+ type: GraphQLTypeRef;
18
+ args?: GraphQLInputValue[];
19
+ }
20
+ export interface GraphQLType {
21
+ kind: string;
22
+ name: string;
23
+ description?: string;
24
+ fields?: GraphQLField[];
25
+ inputFields?: GraphQLField[];
26
+ possibleTypes?: GraphQLTypeRef[];
27
+ }
28
+ export interface GraphQLIntrospectionResult {
29
+ __schema: {
30
+ types: GraphQLType[];
31
+ queryType?: {
32
+ name: string;
33
+ };
34
+ mutationType?: {
35
+ name: string;
36
+ };
37
+ subscriptionType?: {
38
+ name: string;
39
+ };
40
+ };
41
+ }
42
+ export declare function scoreFieldName(name: string): number;
43
+ export declare function chooseUsefulNodeAttributes(nodeType: GraphQLType | undefined, typeMap: Map<string, GraphQLType>): string[];
44
+ export declare function buildFirstTenArgs(field: GraphQLField, filterParamName?: string | null, filterValue?: string): string;
45
+ export type GraphQLConnectionProjection = {
46
+ kind: 'edges';
47
+ nodeTypeName: string;
48
+ hasPageInfo: boolean;
49
+ } | {
50
+ kind: 'listField';
51
+ listFieldName: string;
52
+ nodeTypeName: string;
53
+ };
54
+ export declare function detectConnectionProjection(field: GraphQLField, typeMap: Map<string, GraphQLType>): GraphQLConnectionProjection | null;
55
+ export declare function extractRestApiDefinitionFromGraphQlIntrospectionResult(introspectionResult: GraphQLIntrospectionResult): RestApiDefinition;
56
+ export declare function fetchGraphQLSchema(url: string, headers: Record<string, string>, axios: AxiosInstance, maxDepth?: number): Promise<GraphQLIntrospectionResult>;
@@ -0,0 +1,409 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchGraphQLSchema = exports.extractRestApiDefinitionFromGraphQlIntrospectionResult = exports.detectConnectionProjection = exports.buildFirstTenArgs = exports.chooseUsefulNodeAttributes = exports.scoreFieldName = void 0;
4
+ const DEFAULT_INTROSPECTION_DEPTH = 6;
5
+ function buildTypeRefSelection(depth) {
6
+ if (depth <= 0) {
7
+ return `
8
+ kind
9
+ name
10
+ `;
11
+ }
12
+ return `
13
+ kind
14
+ name
15
+ ofType {
16
+ ${buildTypeRefSelection(depth - 1)}
17
+ }
18
+ `;
19
+ }
20
+ function buildIntrospectionQuery(maxDepth) {
21
+ const typeRefSelection = buildTypeRefSelection(maxDepth);
22
+ return `
23
+ query IntrospectionQuery {
24
+ __schema {
25
+ types {
26
+ kind
27
+ name
28
+ description
29
+ fields {
30
+ name
31
+ description
32
+ type {
33
+ ${typeRefSelection}
34
+ }
35
+ args {
36
+ name
37
+ description
38
+ type {
39
+ ${typeRefSelection}
40
+ }
41
+ defaultValue
42
+ }
43
+ }
44
+ inputFields {
45
+ name
46
+ description
47
+ type {
48
+ ${typeRefSelection}
49
+ }
50
+ }
51
+ }
52
+ queryType {
53
+ name
54
+ }
55
+ mutationType {
56
+ name
57
+ }
58
+ subscriptionType {
59
+ name
60
+ }
61
+ }
62
+ }
63
+ `;
64
+ }
65
+ function getTypeString(type) {
66
+ if (!type)
67
+ return 'Unknown';
68
+ if (type.kind === 'NON_NULL')
69
+ return getTypeString(type.ofType) + '!';
70
+ if (type.kind === 'LIST')
71
+ return '[' + getTypeString(type.ofType) + ']';
72
+ return type.name || 'Unknown';
73
+ }
74
+ function findType(types, name) {
75
+ return types.find(t => t.name === name);
76
+ }
77
+ function unwrapNamedTypeRef(typeRef) {
78
+ if (!typeRef)
79
+ return null;
80
+ if (typeRef.kind === 'NON_NULL' || typeRef.kind === 'LIST')
81
+ return unwrapNamedTypeRef(typeRef.ofType);
82
+ return typeRef;
83
+ }
84
+ function unwrapListTypeRef(typeRef) {
85
+ if (!typeRef)
86
+ return null;
87
+ if (typeRef.kind === 'NON_NULL')
88
+ return unwrapListTypeRef(typeRef.ofType);
89
+ if (typeRef.kind === 'LIST')
90
+ return unwrapNamedTypeRef(typeRef.ofType);
91
+ return null;
92
+ }
93
+ function buildTypeMap(types) {
94
+ return new Map((types || []).map(type => [type.name, type]));
95
+ }
96
+ function isScalarLikeField(field, typeMap) {
97
+ const namedType = unwrapNamedTypeRef(field.type);
98
+ if (!(namedType === null || namedType === void 0 ? void 0 : namedType.name))
99
+ return false;
100
+ const type = typeMap.get(namedType.name);
101
+ if (!type)
102
+ return namedType.kind === 'SCALAR' || namedType.kind === 'ENUM';
103
+ return type.kind === 'SCALAR' || type.kind === 'ENUM';
104
+ }
105
+ function scoreFieldName(name) {
106
+ const lowerName = (name || '').toLowerCase();
107
+ const exactOrder = [
108
+ 'id',
109
+ 'name',
110
+ 'title',
111
+ 'email',
112
+ 'username',
113
+ 'status',
114
+ 'createdat',
115
+ 'updatedat',
116
+ 'type',
117
+ 'code',
118
+ 'key',
119
+ ];
120
+ const exactIndex = exactOrder.indexOf(lowerName);
121
+ if (exactIndex >= 0) {
122
+ return 500 - exactIndex;
123
+ }
124
+ if (lowerName.endsWith('id'))
125
+ return 300;
126
+ if (lowerName.includes('name'))
127
+ return 280;
128
+ if (lowerName.includes('title'))
129
+ return 260;
130
+ if (lowerName.includes('email'))
131
+ return 240;
132
+ if (lowerName.includes('status'))
133
+ return 220;
134
+ if (lowerName.includes('date') || lowerName.endsWith('at'))
135
+ return 200;
136
+ return 100;
137
+ }
138
+ exports.scoreFieldName = scoreFieldName;
139
+ function chooseUsefulNodeAttributes(nodeType, typeMap) {
140
+ var _a;
141
+ if (!((_a = nodeType === null || nodeType === void 0 ? void 0 : nodeType.fields) === null || _a === void 0 ? void 0 : _a.length))
142
+ return ['__typename'];
143
+ const scalarFields = nodeType.fields.filter(field => isScalarLikeField(field, typeMap));
144
+ if (scalarFields.length === 0)
145
+ return ['__typename'];
146
+ return scalarFields
147
+ .map((field, index) => ({
148
+ field,
149
+ score: scoreFieldName(field.name),
150
+ index,
151
+ }))
152
+ .sort((left, right) => {
153
+ if (right.score !== left.score)
154
+ return right.score - left.score;
155
+ return left.index - right.index;
156
+ })
157
+ .slice(0, 10)
158
+ .map(item => item.field.name);
159
+ }
160
+ exports.chooseUsefulNodeAttributes = chooseUsefulNodeAttributes;
161
+ function stringifyArgumentValue(argumentTypeRef, value) {
162
+ const namedType = unwrapNamedTypeRef(argumentTypeRef);
163
+ if (!(namedType === null || namedType === void 0 ? void 0 : namedType.name)) {
164
+ // Fallback: safely stringify as a JSON string literal
165
+ return JSON.stringify(String(value));
166
+ }
167
+ const typeName = namedType.name.toLowerCase();
168
+ if (typeName === 'int' || typeName === 'float') {
169
+ const numValue = typeof value === 'number' ? value : Number(value);
170
+ if (Number.isFinite(numValue)) {
171
+ return String(numValue);
172
+ }
173
+ // If the value cannot be parsed as a valid number, fall back to a quoted string
174
+ return JSON.stringify(String(value));
175
+ }
176
+ // For non-numeric types, safely serialize as a JSON string literal
177
+ return JSON.stringify(String(value));
178
+ }
179
+ function buildFirstTenArgs(field, filterParamName, filterValue) {
180
+ const args = field.args || [];
181
+ if (args.length === 0)
182
+ return '';
183
+ const argPairs = [];
184
+ // Add pagination argument
185
+ const candidates = ['first', 'limit', 'pagesize', 'perpage', 'take', 'size', 'count', 'maxresults'];
186
+ const paginationArg = args.find(item => candidates.includes((item.name || '').toLowerCase()));
187
+ if (paginationArg) {
188
+ argPairs.push(`${paginationArg.name}: ${stringifyArgumentValue(paginationArg.type, 10)}`);
189
+ }
190
+ // Add filter argument if provided
191
+ if (filterParamName && filterValue) {
192
+ const filterArg = args.find(item => item.name === filterParamName);
193
+ if (filterArg) {
194
+ argPairs.push(`${filterParamName}: ${stringifyArgumentValue(filterArg.type, filterValue)}`);
195
+ }
196
+ }
197
+ if (argPairs.length === 0)
198
+ return '';
199
+ return `(${argPairs.join(', ')})`;
200
+ }
201
+ exports.buildFirstTenArgs = buildFirstTenArgs;
202
+ function detectConnectionProjection(field, typeMap) {
203
+ var _a, _b;
204
+ const fieldTypeRef = unwrapNamedTypeRef(field.type);
205
+ if (!(fieldTypeRef === null || fieldTypeRef === void 0 ? void 0 : fieldTypeRef.name))
206
+ return null;
207
+ const returnType = typeMap.get(fieldTypeRef.name);
208
+ if (!returnType || returnType.kind !== 'OBJECT' || !((_a = returnType.fields) === null || _a === void 0 ? void 0 : _a.length))
209
+ return null;
210
+ const edgesField = returnType.fields.find(item => item.name === 'edges');
211
+ if (edgesField) {
212
+ const edgeTypeRef = unwrapListTypeRef(edgesField.type);
213
+ if (edgeTypeRef === null || edgeTypeRef === void 0 ? void 0 : edgeTypeRef.name) {
214
+ const edgeType = typeMap.get(edgeTypeRef.name);
215
+ const nodeField = (_b = edgeType === null || edgeType === void 0 ? void 0 : edgeType.fields) === null || _b === void 0 ? void 0 : _b.find(item => item.name === 'node');
216
+ const nodeTypeRef = unwrapNamedTypeRef(nodeField === null || nodeField === void 0 ? void 0 : nodeField.type);
217
+ if (nodeTypeRef === null || nodeTypeRef === void 0 ? void 0 : nodeTypeRef.name) {
218
+ const hasPageInfo = !!returnType.fields.find(item => item.name === 'pageInfo');
219
+ return {
220
+ kind: 'edges',
221
+ nodeTypeName: nodeTypeRef.name,
222
+ hasPageInfo,
223
+ };
224
+ }
225
+ }
226
+ }
227
+ const listFieldNames = ['nodes', 'items', 'results', 'data'];
228
+ for (const listFieldName of listFieldNames) {
229
+ const listField = returnType.fields.find(item => item.name === listFieldName);
230
+ if (!listField)
231
+ continue;
232
+ const listItemTypeRef = unwrapListTypeRef(listField.type);
233
+ if (!(listItemTypeRef === null || listItemTypeRef === void 0 ? void 0 : listItemTypeRef.name))
234
+ continue;
235
+ return {
236
+ kind: 'listField',
237
+ listFieldName,
238
+ nodeTypeName: listItemTypeRef.name,
239
+ };
240
+ }
241
+ return null;
242
+ }
243
+ exports.detectConnectionProjection = detectConnectionProjection;
244
+ function buildConnectionQuery(field, typeMap) {
245
+ const projection = detectConnectionProjection(field, typeMap);
246
+ if (!projection)
247
+ return null;
248
+ const nodeType = typeMap.get(projection.nodeTypeName);
249
+ const selectedAttributes = chooseUsefulNodeAttributes(nodeType, typeMap);
250
+ const argsString = buildFirstTenArgs(field);
251
+ const attributeBlock = selectedAttributes.map(attr => ` ${attr}`).join('\n');
252
+ if (projection.kind === 'edges') {
253
+ const pageInfoBlock = projection.hasPageInfo
254
+ ? `
255
+ pageInfo {
256
+ hasNextPage
257
+ endCursor
258
+ }`
259
+ : '';
260
+ return `query {
261
+ ${field.name}${argsString} {
262
+ edges {
263
+ node {
264
+ ${attributeBlock}
265
+ }
266
+ }${pageInfoBlock}
267
+ }
268
+ }`;
269
+ }
270
+ return `query {
271
+ ${field.name}${argsString} {
272
+ ${projection.listFieldName} {
273
+ ${attributeBlock}
274
+ }
275
+ }
276
+ }`;
277
+ }
278
+ function buildConnectionEndpoints(types, rootTypeName) {
279
+ var _a;
280
+ if (!rootTypeName)
281
+ return [];
282
+ const rootType = findType(types, rootTypeName);
283
+ if (!((_a = rootType === null || rootType === void 0 ? void 0 : rootType.fields) === null || _a === void 0 ? void 0 : _a.length))
284
+ return [];
285
+ const typeMap = buildTypeMap(types);
286
+ const connectionEndpoints = [];
287
+ for (const field of rootType.fields) {
288
+ const connectionQuery = buildConnectionQuery(field, typeMap);
289
+ if (!connectionQuery)
290
+ continue;
291
+ connectionEndpoints.push({
292
+ name: field.name,
293
+ description: field.description || '',
294
+ fields: field.description,
295
+ connectionQuery,
296
+ });
297
+ }
298
+ return connectionEndpoints;
299
+ }
300
+ function buildOperationEndpoints(types, operationType, rootTypeName) {
301
+ if (!rootTypeName)
302
+ return [];
303
+ const rootType = findType(types, rootTypeName);
304
+ if (!rootType || !rootType.fields)
305
+ return [];
306
+ return rootType.fields.map(field => ({
307
+ name: field.name,
308
+ description: field.description || '',
309
+ fields: field.description,
310
+ }));
311
+ }
312
+ function extractRestApiDefinitionFromGraphQlIntrospectionResult(introspectionResult) {
313
+ var _a, _b, _c, _d;
314
+ const { __schema } = introspectionResult;
315
+ const categories = [];
316
+ // Connections (query fields returning connection-like payloads)
317
+ if ((_a = __schema.queryType) === null || _a === void 0 ? void 0 : _a.name) {
318
+ const connectionEndpoints = buildConnectionEndpoints(__schema.types, __schema.queryType.name);
319
+ if (connectionEndpoints.length > 0) {
320
+ categories.push({
321
+ name: 'Connections',
322
+ endpoints: connectionEndpoints.map(connection => ({
323
+ method: 'POST',
324
+ path: connection.name,
325
+ summary: connection.description,
326
+ description: connection.fields,
327
+ parameters: [],
328
+ connectionQuery: connection.connectionQuery,
329
+ })),
330
+ });
331
+ }
332
+ }
333
+ // Queries
334
+ if ((_b = __schema.queryType) === null || _b === void 0 ? void 0 : _b.name) {
335
+ const queryEndpoints = buildOperationEndpoints(__schema.types, 'OBJECT', __schema.queryType.name);
336
+ if (queryEndpoints.length > 0) {
337
+ categories.push({
338
+ name: 'Queries',
339
+ endpoints: queryEndpoints.map(q => ({
340
+ method: 'POST',
341
+ path: q.name,
342
+ summary: q.description,
343
+ description: q.fields,
344
+ parameters: [],
345
+ })),
346
+ });
347
+ }
348
+ }
349
+ // Mutations
350
+ if ((_c = __schema.mutationType) === null || _c === void 0 ? void 0 : _c.name) {
351
+ const mutationEndpoints = buildOperationEndpoints(__schema.types, 'OBJECT', __schema.mutationType.name);
352
+ if (mutationEndpoints.length > 0) {
353
+ categories.push({
354
+ name: 'Mutations',
355
+ endpoints: mutationEndpoints.map(m => ({
356
+ method: 'POST',
357
+ path: m.name,
358
+ summary: m.description,
359
+ description: m.fields,
360
+ parameters: [],
361
+ })),
362
+ });
363
+ }
364
+ }
365
+ // Subscriptions
366
+ if ((_d = __schema.subscriptionType) === null || _d === void 0 ? void 0 : _d.name) {
367
+ const subscriptionEndpoints = buildOperationEndpoints(__schema.types, 'OBJECT', __schema.subscriptionType.name);
368
+ if (subscriptionEndpoints.length > 0) {
369
+ categories.push({
370
+ name: 'Subscriptions',
371
+ endpoints: subscriptionEndpoints.map(s => ({
372
+ method: 'POST',
373
+ path: s.name,
374
+ summary: s.description,
375
+ description: s.fields,
376
+ parameters: [],
377
+ })),
378
+ });
379
+ }
380
+ }
381
+ return {
382
+ categories,
383
+ servers: [],
384
+ };
385
+ }
386
+ exports.extractRestApiDefinitionFromGraphQlIntrospectionResult = extractRestApiDefinitionFromGraphQlIntrospectionResult;
387
+ async function fetchGraphQLSchema(url, headers, axios, maxDepth = DEFAULT_INTROSPECTION_DEPTH) {
388
+ try {
389
+ const query = buildIntrospectionQuery(maxDepth);
390
+ const response = await axios.post(url, { query }, {
391
+ timeout: 10000,
392
+ headers: {
393
+ 'Content-Type': 'application/json',
394
+ ...headers,
395
+ },
396
+ });
397
+ if (response.data.errors) {
398
+ throw new Error(`GraphQL introspection error: ${JSON.stringify(response.data.errors)}`);
399
+ }
400
+ if (!response.data.data) {
401
+ throw new Error('Invalid introspection response: no data field');
402
+ }
403
+ return response.data.data;
404
+ }
405
+ catch (err) {
406
+ throw new Error(`DBGM-00312 Could not fetch GraphQL schema: ${err.message}`);
407
+ }
408
+ }
409
+ exports.fetchGraphQLSchema = fetchGraphQLSchema;
package/lib/index.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export * from './openApiDriver';
2
+ export * from './oDataDriver';
3
+ export * from './graphQlDriver';
4
+ export * from './openApiAdapter';
5
+ export * from './oDataAdapter';
6
+ export * from './oDataMetadataParser';
7
+ export * from './restApiExecutor';
8
+ export * from './arrayify';
9
+ export * from './graphqlIntrospection';
10
+ export * from './graphqlExplorer';
11
+ export * from './graphQlQueryParser';
12
+ export * from './graphQlVariables';
13
+ export * from './restAuthTools';
package/lib/index.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./openApiDriver"), exports);
18
+ __exportStar(require("./oDataDriver"), exports);
19
+ __exportStar(require("./graphQlDriver"), exports);
20
+ __exportStar(require("./openApiAdapter"), exports);
21
+ __exportStar(require("./oDataAdapter"), exports);
22
+ __exportStar(require("./oDataMetadataParser"), exports);
23
+ __exportStar(require("./restApiExecutor"), exports);
24
+ __exportStar(require("./arrayify"), exports);
25
+ __exportStar(require("./graphqlIntrospection"), exports);
26
+ __exportStar(require("./graphqlExplorer"), exports);
27
+ __exportStar(require("./graphQlQueryParser"), exports);
28
+ __exportStar(require("./graphQlVariables"), exports);
29
+ __exportStar(require("./restAuthTools"), exports);
@@ -0,0 +1,33 @@
1
+ import { RestApiDefinition } from './restApiDef';
2
+ export type ODataServiceResource = {
3
+ name?: string;
4
+ kind?: string;
5
+ url?: string;
6
+ };
7
+ export type ODataServiceDocument = {
8
+ '@odata.context'?: string;
9
+ value?: ODataServiceResource[];
10
+ };
11
+ export interface ODataMetadataNavigationProperty {
12
+ name: string;
13
+ type?: string;
14
+ containsTarget: boolean;
15
+ nullable: boolean;
16
+ }
17
+ export interface ODataMetadataEntityType {
18
+ typeName: string;
19
+ fullTypeName: string;
20
+ keyProperties: string[];
21
+ stringProperties: string[];
22
+ navigationProperties: ODataMetadataNavigationProperty[];
23
+ }
24
+ export interface ODataMetadataEntitySet {
25
+ name: string;
26
+ entityType: string;
27
+ navigationBindings: Record<string, string>;
28
+ }
29
+ export interface ODataMetadataDocument {
30
+ entityTypes: Record<string, ODataMetadataEntityType>;
31
+ entitySets: Record<string, ODataMetadataEntitySet>;
32
+ }
33
+ export declare function analyseODataDefinition(doc: ODataServiceDocument, endpointUrl: string, metadataDocumentXml?: string | null): RestApiDefinition;