@ankhorage/data-sources 1.0.0 → 2.0.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.
- package/CHANGELOG.md +12 -0
- package/README.md +6 -41
- package/dist/ankh.provider.js +1 -1
- package/dist/ankh.provider.js.map +1 -1
- package/dist/discovery/http.d.ts +10 -0
- package/dist/discovery/http.d.ts.map +1 -0
- package/dist/discovery/http.js +35 -0
- package/dist/discovery/http.js.map +1 -0
- package/dist/discovery/index.d.ts +9 -9
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +27 -55
- package/dist/discovery/index.js.map +1 -1
- package/dist/graphql/index.d.ts +8 -76
- package/dist/graphql/index.d.ts.map +1 -1
- package/dist/graphql/index.js +17 -197
- package/dist/graphql/index.js.map +1 -1
- package/dist/graphql/introspection.d.ts +5 -0
- package/dist/graphql/introspection.d.ts.map +1 -0
- package/dist/graphql/introspection.js +136 -0
- package/dist/graphql/introspection.js.map +1 -0
- package/dist/graphql/operation.d.ts +5 -0
- package/dist/graphql/operation.d.ts.map +1 -0
- package/dist/graphql/operation.js +39 -0
- package/dist/graphql/operation.js.map +1 -0
- package/dist/graphql/types.d.ts +71 -0
- package/dist/graphql/types.d.ts.map +1 -0
- package/dist/graphql/types.js +2 -0
- package/dist/graphql/types.js.map +1 -0
- package/dist/index.d.ts +1 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -34
- package/dist/index.js.map +1 -1
- package/dist/openapi/endpoints.d.ts +5 -0
- package/dist/openapi/endpoints.d.ts.map +1 -0
- package/dist/openapi/endpoints.js +77 -0
- package/dist/openapi/endpoints.js.map +1 -0
- package/dist/openapi/index.d.ts +7 -87
- package/dist/openapi/index.d.ts.map +1 -1
- package/dist/openapi/index.js +8 -267
- package/dist/openapi/index.js.map +1 -1
- package/dist/openapi/operation.d.ts +5 -0
- package/dist/openapi/operation.d.ts.map +1 -0
- package/dist/openapi/operation.js +141 -0
- package/dist/openapi/operation.js.map +1 -0
- package/dist/openapi/schema.d.ts +5 -0
- package/dist/openapi/schema.d.ts.map +1 -0
- package/dist/openapi/schema.js +84 -0
- package/dist/openapi/schema.js.map +1 -0
- package/dist/openapi/types.d.ts +82 -0
- package/dist/openapi/types.d.ts.map +1 -0
- package/dist/openapi/types.js +2 -0
- package/dist/openapi/types.js.map +1 -0
- package/dist/packageInfo.d.ts +18 -0
- package/dist/packageInfo.d.ts.map +1 -0
- package/dist/packageInfo.js +30 -0
- package/dist/packageInfo.js.map +1 -0
- package/dist/rest/index.d.ts +5 -5
- package/dist/rest/index.d.ts.map +1 -1
- package/dist/rest/index.js +49 -48
- package/dist/rest/index.js.map +1 -1
- package/dist/test-runner/index.d.ts +2 -57
- package/dist/test-runner/index.d.ts.map +1 -1
- package/dist/test-runner/index.js +58 -160
- package/dist/test-runner/index.js.map +1 -1
- package/dist/test-runner/response.d.ts +3 -0
- package/dist/test-runner/response.d.ts.map +1 -0
- package/dist/test-runner/response.js +29 -0
- package/dist/test-runner/response.js.map +1 -0
- package/dist/test-runner/result.d.ts +6 -0
- package/dist/test-runner/result.d.ts.map +1 -0
- package/dist/test-runner/result.js +17 -0
- package/dist/test-runner/result.js.map +1 -0
- package/dist/test-runner/serialization.d.ts +12 -0
- package/dist/test-runner/serialization.d.ts.map +1 -0
- package/dist/test-runner/serialization.js +99 -0
- package/dist/test-runner/serialization.js.map +1 -0
- package/dist/test-runner/types.d.ts +58 -0
- package/dist/test-runner/types.d.ts.map +1 -0
- package/dist/test-runner/types.js +2 -0
- package/dist/test-runner/types.js.map +1 -0
- package/package.json +5 -5
- package/src/ankh.provider.ts +1 -1
- package/src/api-phase1.contract.test.ts +24 -0
- package/src/discovery/http.ts +38 -0
- package/src/discovery/index.test.ts +76 -75
- package/src/discovery/index.ts +49 -72
- package/src/graphql/index.test.ts +10 -11
- package/src/graphql/index.ts +35 -315
- package/src/graphql/introspection.ts +163 -0
- package/src/graphql/operation.ts +60 -0
- package/src/graphql/types.ts +79 -0
- package/src/index.test.ts +21 -13
- package/src/index.ts +1 -54
- package/src/openapi/endpoints.ts +124 -0
- package/src/openapi/index.test.ts +47 -47
- package/src/openapi/index.ts +12 -467
- package/src/openapi/operation.ts +231 -0
- package/src/openapi/schema.ts +127 -0
- package/src/openapi/types.ts +93 -0
- package/src/packageInfo.ts +50 -0
- package/src/rest/index.test.ts +17 -14
- package/src/rest/index.ts +67 -61
- package/src/test-runner/index.test.ts +153 -120
- package/src/test-runner/index.ts +97 -299
- package/src/test-runner/response.ts +32 -0
- package/src/test-runner/result.ts +35 -0
- package/src/test-runner/serialization.ts +151 -0
- package/src/test-runner/types.ts +81 -0
- package/dist/generated-api/index.d.ts +0 -10
- package/dist/generated-api/index.d.ts.map +0 -1
- package/dist/generated-api/index.js +0 -272
- package/dist/generated-api/index.js.map +0 -1
- package/src/generated-api/index.test.ts +0 -173
- package/src/generated-api/index.ts +0 -410
package/dist/rest/index.js
CHANGED
|
@@ -21,13 +21,13 @@ export function extractRestPathParams(path) {
|
|
|
21
21
|
}
|
|
22
22
|
return [...params];
|
|
23
23
|
}
|
|
24
|
-
export function
|
|
24
|
+
export function validateManualRestApi(definition) {
|
|
25
25
|
const diagnostics = [];
|
|
26
26
|
if (definition.baseUrl.trim().length === 0) {
|
|
27
27
|
diagnostics.push({
|
|
28
28
|
code: 'invalid-config',
|
|
29
|
-
|
|
30
|
-
message: 'Manual REST
|
|
29
|
+
apiId: definition.id,
|
|
30
|
+
message: 'Manual REST API requires a non-empty baseUrl.',
|
|
31
31
|
path: 'baseUrl',
|
|
32
32
|
severity: 'error',
|
|
33
33
|
});
|
|
@@ -36,7 +36,7 @@ export function validateManualRestDataSource(definition) {
|
|
|
36
36
|
if (!endpoint.path.startsWith('/')) {
|
|
37
37
|
diagnostics.push({
|
|
38
38
|
code: 'invalid-config',
|
|
39
|
-
|
|
39
|
+
apiId: definition.id,
|
|
40
40
|
endpointId: endpoint.id,
|
|
41
41
|
message: 'Manual REST endpoint paths must start with `/`.',
|
|
42
42
|
path: `endpoints.${endpoint.id}.path`,
|
|
@@ -49,57 +49,21 @@ export function validateManualRestDataSource(definition) {
|
|
|
49
49
|
}
|
|
50
50
|
return diagnostics;
|
|
51
51
|
}
|
|
52
|
-
export function
|
|
53
|
-
const diagnostics =
|
|
52
|
+
export function createManualRestApi(definition) {
|
|
53
|
+
const diagnostics = validateManualRestApi(definition);
|
|
54
54
|
if (diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {
|
|
55
55
|
return { ok: false, diagnostics };
|
|
56
56
|
}
|
|
57
57
|
return {
|
|
58
58
|
ok: true,
|
|
59
|
-
data:
|
|
59
|
+
data: normalizeManualRestApi(definition),
|
|
60
60
|
diagnostics,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
export function
|
|
64
|
-
const endpoints =
|
|
65
|
-
for (const endpoint of definition.endpoints) {
|
|
66
|
-
const operations = {};
|
|
67
|
-
for (const operation of endpoint.operations) {
|
|
68
|
-
const { parameters } = operation;
|
|
69
|
-
const request = operation.request === undefined && parameters === undefined
|
|
70
|
-
? undefined
|
|
71
|
-
: { ...operation.request, parameters };
|
|
72
|
-
operations[operation.id] = {
|
|
73
|
-
id: operation.id,
|
|
74
|
-
endpointId: endpoint.id,
|
|
75
|
-
name: operation.name,
|
|
76
|
-
description: operation.description,
|
|
77
|
-
protocol: 'http',
|
|
78
|
-
intent: operation.intent,
|
|
79
|
-
method: normalizeManualRestMethod(operation.method),
|
|
80
|
-
path: operation.path ?? endpoint.path,
|
|
81
|
-
request,
|
|
82
|
-
response: operation.response,
|
|
83
|
-
pagination: operation.pagination,
|
|
84
|
-
credential: operation.credential,
|
|
85
|
-
metadata: operation.metadata,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
endpoints[endpoint.id] = {
|
|
89
|
-
id: endpoint.id,
|
|
90
|
-
kind: 'http',
|
|
91
|
-
name: endpoint.name,
|
|
92
|
-
description: endpoint.description,
|
|
93
|
-
baseUrl: definition.baseUrl,
|
|
94
|
-
path: endpoint.path,
|
|
95
|
-
credential: endpoint.credential,
|
|
96
|
-
operations,
|
|
97
|
-
metadata: endpoint.metadata,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
63
|
+
export function normalizeManualRestApi(definition) {
|
|
64
|
+
const endpoints = Object.fromEntries(definition.endpoints.map((endpoint) => [endpoint.id, normalizeManualRestEndpoint(endpoint)]));
|
|
100
65
|
return {
|
|
101
66
|
id: definition.id,
|
|
102
|
-
kind: 'api',
|
|
103
67
|
origin: 'external',
|
|
104
68
|
protocol: 'rest',
|
|
105
69
|
name: definition.name,
|
|
@@ -111,6 +75,43 @@ export function normalizeManualRestDataSource(definition) {
|
|
|
111
75
|
metadata: definition.metadata,
|
|
112
76
|
};
|
|
113
77
|
}
|
|
78
|
+
function normalizeManualRestEndpoint(endpoint) {
|
|
79
|
+
const operations = Object.fromEntries(endpoint.operations.map((operation) => [
|
|
80
|
+
operation.id,
|
|
81
|
+
normalizeManualRestOperation(endpoint, operation),
|
|
82
|
+
]));
|
|
83
|
+
return {
|
|
84
|
+
id: endpoint.id,
|
|
85
|
+
kind: 'http',
|
|
86
|
+
name: endpoint.name,
|
|
87
|
+
description: endpoint.description,
|
|
88
|
+
path: endpoint.path,
|
|
89
|
+
credential: endpoint.credential,
|
|
90
|
+
operations,
|
|
91
|
+
metadata: endpoint.metadata,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function normalizeManualRestOperation(endpoint, operation) {
|
|
95
|
+
const { parameters } = operation;
|
|
96
|
+
const request = operation.request === undefined && parameters === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: { ...operation.request, parameters };
|
|
99
|
+
return {
|
|
100
|
+
id: operation.id,
|
|
101
|
+
endpointId: endpoint.id,
|
|
102
|
+
name: operation.name,
|
|
103
|
+
description: operation.description,
|
|
104
|
+
protocol: 'http',
|
|
105
|
+
intent: operation.intent,
|
|
106
|
+
method: normalizeManualRestMethod(operation.method),
|
|
107
|
+
path: operation.path ?? endpoint.path,
|
|
108
|
+
request,
|
|
109
|
+
response: operation.response,
|
|
110
|
+
pagination: operation.pagination,
|
|
111
|
+
credential: operation.credential,
|
|
112
|
+
metadata: operation.metadata,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
114
115
|
function validateManualRestOperation(definition, endpoint, operation, diagnostics) {
|
|
115
116
|
const method = normalizeManualRestMethod(operation.method);
|
|
116
117
|
const path = operation.path ?? endpoint.path;
|
|
@@ -120,7 +121,7 @@ function validateManualRestOperation(definition, endpoint, operation, diagnostic
|
|
|
120
121
|
if (!isManualRestMethod(method)) {
|
|
121
122
|
diagnostics.push({
|
|
122
123
|
code: 'invalid-config',
|
|
123
|
-
|
|
124
|
+
apiId: definition.id,
|
|
124
125
|
endpointId: endpoint.id,
|
|
125
126
|
operationId: operation.id,
|
|
126
127
|
message: `Manual REST operation method must be one of ${REST_METHODS.join(', ')}.`,
|
|
@@ -133,7 +134,7 @@ function validateManualRestOperation(definition, endpoint, operation, diagnostic
|
|
|
133
134
|
continue;
|
|
134
135
|
diagnostics.push({
|
|
135
136
|
code: 'invalid-config',
|
|
136
|
-
|
|
137
|
+
apiId: definition.id,
|
|
137
138
|
endpointId: endpoint.id,
|
|
138
139
|
operationId: operation.id,
|
|
139
140
|
message: `Path template parameter '${templateParam}' must have a matching path parameter definition.`,
|
|
@@ -146,7 +147,7 @@ function validateManualRestOperation(definition, endpoint, operation, diagnostic
|
|
|
146
147
|
continue;
|
|
147
148
|
diagnostics.push({
|
|
148
149
|
code: 'invalid-config',
|
|
149
|
-
|
|
150
|
+
apiId: definition.id,
|
|
150
151
|
endpointId: endpoint.id,
|
|
151
152
|
operationId: operation.id,
|
|
152
153
|
message: `Path parameter '${pathParameter.name}' is not referenced by the operation path template.`,
|
package/dist/rest/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rest/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CredentialRef,\n DataContractValue,\n DataEndpointConfig,\n DataOperationConfig,\n DataOperationIntent,\n DataOperationMethod,\n DataOperationPagination,\n DataOperationParameter,\n DataOperationRequest,\n DataOperationResponse,\n DataSchemaRegistry,\n DataSourceDiagnostic,\n DataSourceDiagnosticResult,\n EndpointId,\n ExternalRestApiDataSourceConfig,\n OperationId,\n} from '@ankhorage/contracts/data';\n\nconst REST_METHODS = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'] as const;\n\nexport type ManualRestMethod = (typeof REST_METHODS)[number];\n\nexport interface ManualRestOperationDefinition {\n readonly id: OperationId;\n readonly intent: DataOperationIntent;\n readonly method: string;\n readonly name?: string;\n readonly description?: string;\n readonly path?: string;\n readonly credential?: CredentialRef;\n readonly parameters?: readonly DataOperationParameter[];\n readonly request?: DataOperationRequest;\n readonly response?: DataOperationResponse;\n readonly pagination?: DataOperationPagination;\n readonly metadata?: DataContractValue;\n}\n\nexport interface ManualRestEndpointDefinition {\n readonly id: EndpointId;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly credential?: CredentialRef;\n readonly operations: readonly ManualRestOperationDefinition[];\n readonly metadata?: DataContractValue;\n}\n\nexport interface ManualRestDataSourceDefinition {\n readonly id: string;\n readonly baseUrl: string;\n readonly name?: string;\n readonly description?: string;\n readonly credential?: CredentialRef;\n readonly endpoints: readonly ManualRestEndpointDefinition[];\n readonly schemas?: DataSchemaRegistry;\n readonly metadata?: DataContractValue;\n}\n\nexport function isManualRestMethod(method: string): method is ManualRestMethod {\n return REST_METHODS.some((restMethod) => restMethod === method);\n}\n\nexport function normalizeManualRestMethod(method: string): DataOperationMethod {\n return method.toUpperCase();\n}\n\nexport function extractRestPathParams(path: string): readonly string[] {\n const params = new Set<string>();\n const bracedParamPattern = /\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\n const colonParamPattern = /(^|\\/):([A-Za-z_][A-Za-z0-9_]*)/g;\n\n for (const match of path.matchAll(bracedParamPattern)) {\n const [, param] = match;\n if (param !== undefined) params.add(param);\n }\n\n for (const match of path.matchAll(colonParamPattern)) {\n const [, , param] = match;\n if (param !== undefined) params.add(param);\n }\n\n return [...params];\n}\n\nexport function validateManualRestDataSource(\n definition: ManualRestDataSourceDefinition,\n): readonly DataSourceDiagnostic[] {\n const diagnostics: DataSourceDiagnostic[] = [];\n\n if (definition.baseUrl.trim().length === 0) {\n diagnostics.push({\n code: 'invalid-config',\n dataSourceId: definition.id,\n message: 'Manual REST data source requires a non-empty baseUrl.',\n path: 'baseUrl',\n severity: 'error',\n });\n }\n\n for (const endpoint of definition.endpoints) {\n if (!endpoint.path.startsWith('/')) {\n diagnostics.push({\n code: 'invalid-config',\n dataSourceId: definition.id,\n endpointId: endpoint.id,\n message: 'Manual REST endpoint paths must start with `/`.',\n path: `endpoints.${endpoint.id}.path`,\n severity: 'error',\n });\n }\n\n for (const operation of endpoint.operations) {\n validateManualRestOperation(definition, endpoint, operation, diagnostics);\n }\n }\n\n return diagnostics;\n}\n\nexport function createManualRestDataSource(\n definition: ManualRestDataSourceDefinition,\n): DataSourceDiagnosticResult<ExternalRestApiDataSourceConfig> {\n const diagnostics = validateManualRestDataSource(definition);\n if (diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return { ok: false, diagnostics };\n }\n\n return {\n ok: true,\n data: normalizeManualRestDataSource(definition),\n diagnostics,\n };\n}\n\nexport function normalizeManualRestDataSource(\n definition: ManualRestDataSourceDefinition,\n): ExternalRestApiDataSourceConfig {\n const endpoints: Record<EndpointId, DataEndpointConfig> = {};\n\n for (const endpoint of definition.endpoints) {\n const operations: Record<OperationId, DataOperationConfig> = {};\n\n for (const operation of endpoint.operations) {\n const { parameters } = operation;\n const request: DataOperationRequest | undefined =\n operation.request === undefined && parameters === undefined\n ? undefined\n : { ...operation.request, parameters };\n\n operations[operation.id] = {\n id: operation.id,\n endpointId: endpoint.id,\n name: operation.name,\n description: operation.description,\n protocol: 'http',\n intent: operation.intent,\n method: normalizeManualRestMethod(operation.method),\n path: operation.path ?? endpoint.path,\n request,\n response: operation.response,\n pagination: operation.pagination,\n credential: operation.credential,\n metadata: operation.metadata,\n };\n }\n\n endpoints[endpoint.id] = {\n id: endpoint.id,\n kind: 'http',\n name: endpoint.name,\n description: endpoint.description,\n baseUrl: definition.baseUrl,\n path: endpoint.path,\n credential: endpoint.credential,\n operations,\n metadata: endpoint.metadata,\n };\n }\n\n return {\n id: definition.id,\n kind: 'api',\n origin: 'external',\n protocol: 'rest',\n name: definition.name,\n description: definition.description,\n baseUrl: definition.baseUrl,\n credential: definition.credential,\n endpoints,\n schemas: definition.schemas,\n metadata: definition.metadata,\n };\n}\n\nfunction validateManualRestOperation(\n definition: ManualRestDataSourceDefinition,\n endpoint: ManualRestEndpointDefinition,\n operation: ManualRestOperationDefinition,\n diagnostics: DataSourceDiagnostic[],\n): void {\n const method = normalizeManualRestMethod(operation.method);\n const path = operation.path ?? endpoint.path;\n const templateParams = extractRestPathParams(path);\n const pathParameters =\n operation.parameters?.filter((parameter) => parameter.location === 'path') ?? [];\n const pathParameterNames = new Set(pathParameters.map((parameter) => parameter.name));\n\n if (!isManualRestMethod(method)) {\n diagnostics.push({\n code: 'invalid-config',\n dataSourceId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Manual REST operation method must be one of ${REST_METHODS.join(', ')}.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.method`,\n severity: 'error',\n });\n }\n\n for (const templateParam of templateParams) {\n if (pathParameterNames.has(templateParam)) continue;\n diagnostics.push({\n code: 'invalid-config',\n dataSourceId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Path template parameter '${templateParam}' must have a matching path parameter definition.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.parameters`,\n severity: 'error',\n });\n }\n\n for (const pathParameter of pathParameters) {\n if (templateParams.includes(pathParameter.name)) continue;\n diagnostics.push({\n code: 'invalid-config',\n dataSourceId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Path parameter '${pathParameter.name}' is not referenced by the operation path template.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.parameters.${pathParameter.name}`,\n severity: 'error',\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rest/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CredentialRef,\n DataContractValue,\n DataEndpointConfig,\n DataOperationConfig,\n DataOperationIntent,\n DataOperationMethod,\n DataOperationPagination,\n DataOperationParameter,\n DataOperationRequest,\n DataOperationResponse,\n DataSchemaRegistry,\n DataSourceDiagnostic,\n DataSourceDiagnosticResult,\n EndpointId,\n ExternalRestApiDefinition,\n OperationId,\n} from '@ankhorage/contracts/data';\n\nconst REST_METHODS = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'] as const;\n\nexport type ManualRestMethod = (typeof REST_METHODS)[number];\n\nexport interface ManualRestOperationDefinition {\n readonly id: OperationId;\n readonly intent: DataOperationIntent;\n readonly method: string;\n readonly name?: string;\n readonly description?: string;\n readonly path?: string;\n readonly credential?: CredentialRef;\n readonly parameters?: readonly DataOperationParameter[];\n readonly request?: DataOperationRequest;\n readonly response?: DataOperationResponse;\n readonly pagination?: DataOperationPagination;\n readonly metadata?: DataContractValue;\n}\n\nexport interface ManualRestEndpointDefinition {\n readonly id: EndpointId;\n readonly path: string;\n readonly name?: string;\n readonly description?: string;\n readonly credential?: CredentialRef;\n readonly operations: readonly ManualRestOperationDefinition[];\n readonly metadata?: DataContractValue;\n}\n\nexport interface ManualRestApiDefinition {\n readonly id: string;\n readonly baseUrl: string;\n readonly name?: string;\n readonly description?: string;\n readonly credential?: CredentialRef;\n readonly endpoints: readonly ManualRestEndpointDefinition[];\n readonly schemas?: DataSchemaRegistry;\n readonly metadata?: DataContractValue;\n}\n\nexport function isManualRestMethod(method: string): method is ManualRestMethod {\n return REST_METHODS.some((restMethod) => restMethod === method);\n}\n\nexport function normalizeManualRestMethod(method: string): DataOperationMethod {\n return method.toUpperCase();\n}\n\nexport function extractRestPathParams(path: string): readonly string[] {\n const params = new Set<string>();\n const bracedParamPattern = /\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g;\n const colonParamPattern = /(^|\\/):([A-Za-z_][A-Za-z0-9_]*)/g;\n\n for (const match of path.matchAll(bracedParamPattern)) {\n const [, param] = match;\n if (param !== undefined) params.add(param);\n }\n\n for (const match of path.matchAll(colonParamPattern)) {\n const [, , param] = match;\n if (param !== undefined) params.add(param);\n }\n\n return [...params];\n}\n\nexport function validateManualRestApi(\n definition: ManualRestApiDefinition,\n): readonly DataSourceDiagnostic[] {\n const diagnostics: DataSourceDiagnostic[] = [];\n\n if (definition.baseUrl.trim().length === 0) {\n diagnostics.push({\n code: 'invalid-config',\n apiId: definition.id,\n message: 'Manual REST API requires a non-empty baseUrl.',\n path: 'baseUrl',\n severity: 'error',\n });\n }\n\n for (const endpoint of definition.endpoints) {\n if (!endpoint.path.startsWith('/')) {\n diagnostics.push({\n code: 'invalid-config',\n apiId: definition.id,\n endpointId: endpoint.id,\n message: 'Manual REST endpoint paths must start with `/`.',\n path: `endpoints.${endpoint.id}.path`,\n severity: 'error',\n });\n }\n\n for (const operation of endpoint.operations) {\n validateManualRestOperation(definition, endpoint, operation, diagnostics);\n }\n }\n\n return diagnostics;\n}\n\nexport function createManualRestApi(\n definition: ManualRestApiDefinition,\n): DataSourceDiagnosticResult<ExternalRestApiDefinition> {\n const diagnostics = validateManualRestApi(definition);\n if (diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return { ok: false, diagnostics };\n }\n\n return {\n ok: true,\n data: normalizeManualRestApi(definition),\n diagnostics,\n };\n}\n\nexport function normalizeManualRestApi(\n definition: ManualRestApiDefinition,\n): ExternalRestApiDefinition {\n const endpoints = Object.fromEntries(\n definition.endpoints.map((endpoint) => [endpoint.id, normalizeManualRestEndpoint(endpoint)]),\n );\n\n return {\n id: definition.id,\n origin: 'external',\n protocol: 'rest',\n name: definition.name,\n description: definition.description,\n baseUrl: definition.baseUrl,\n credential: definition.credential,\n endpoints,\n schemas: definition.schemas,\n metadata: definition.metadata,\n };\n}\n\nfunction normalizeManualRestEndpoint(endpoint: ManualRestEndpointDefinition): DataEndpointConfig {\n const operations = Object.fromEntries(\n endpoint.operations.map((operation) => [\n operation.id,\n normalizeManualRestOperation(endpoint, operation),\n ]),\n );\n return {\n id: endpoint.id,\n kind: 'http',\n name: endpoint.name,\n description: endpoint.description,\n path: endpoint.path,\n credential: endpoint.credential,\n operations,\n metadata: endpoint.metadata,\n };\n}\n\nfunction normalizeManualRestOperation(\n endpoint: ManualRestEndpointDefinition,\n operation: ManualRestOperationDefinition,\n): DataOperationConfig {\n const { parameters } = operation;\n const request: DataOperationRequest | undefined =\n operation.request === undefined && parameters === undefined\n ? undefined\n : { ...operation.request, parameters };\n return {\n id: operation.id,\n endpointId: endpoint.id,\n name: operation.name,\n description: operation.description,\n protocol: 'http',\n intent: operation.intent,\n method: normalizeManualRestMethod(operation.method),\n path: operation.path ?? endpoint.path,\n request,\n response: operation.response,\n pagination: operation.pagination,\n credential: operation.credential,\n metadata: operation.metadata,\n };\n}\n\nfunction validateManualRestOperation(\n definition: ManualRestApiDefinition,\n endpoint: ManualRestEndpointDefinition,\n operation: ManualRestOperationDefinition,\n diagnostics: DataSourceDiagnostic[],\n): void {\n const method = normalizeManualRestMethod(operation.method);\n const path = operation.path ?? endpoint.path;\n const templateParams = extractRestPathParams(path);\n const pathParameters =\n operation.parameters?.filter((parameter) => parameter.location === 'path') ?? [];\n const pathParameterNames = new Set(pathParameters.map((parameter) => parameter.name));\n\n if (!isManualRestMethod(method)) {\n diagnostics.push({\n code: 'invalid-config',\n apiId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Manual REST operation method must be one of ${REST_METHODS.join(', ')}.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.method`,\n severity: 'error',\n });\n }\n\n for (const templateParam of templateParams) {\n if (pathParameterNames.has(templateParam)) continue;\n diagnostics.push({\n code: 'invalid-config',\n apiId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Path template parameter '${templateParam}' must have a matching path parameter definition.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.parameters`,\n severity: 'error',\n });\n }\n\n for (const pathParameter of pathParameters) {\n if (templateParams.includes(pathParameter.name)) continue;\n diagnostics.push({\n code: 'invalid-config',\n apiId: definition.id,\n endpointId: endpoint.id,\n operationId: operation.id,\n message: `Path parameter '${pathParameter.name}' is not referenced by the operation path template.`,\n path: `endpoints.${endpoint.id}.operations.${operation.id}.parameters.${pathParameter.name}`,\n severity: 'error',\n });\n }\n}\n"]}
|
|
@@ -1,60 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type
|
|
3
|
-
export type EndpointTestHeaders = Readonly<Record<string, string>>;
|
|
4
|
-
export interface EndpointTestCredential {
|
|
5
|
-
readonly headers?: EndpointTestHeaders;
|
|
6
|
-
readonly query?: EndpointTestInputValues;
|
|
7
|
-
}
|
|
8
|
-
export type EndpointTestCredentialResolver = (credential: CredentialRef) => EndpointTestCredential | Promise<EndpointTestCredential | undefined> | undefined;
|
|
9
|
-
export interface EndpointTestFetchInit {
|
|
10
|
-
readonly method: string;
|
|
11
|
-
readonly headers: EndpointTestHeaders;
|
|
12
|
-
readonly body?: string;
|
|
13
|
-
}
|
|
14
|
-
export interface EndpointTestFetchResponse {
|
|
15
|
-
readonly status: number;
|
|
16
|
-
readonly headers?: EndpointTestHeaders;
|
|
17
|
-
text(): Promise<string>;
|
|
18
|
-
}
|
|
19
|
-
export type EndpointTestFetch = (url: string, init: EndpointTestFetchInit) => Promise<EndpointTestFetchResponse>;
|
|
20
|
-
export interface EndpointTestInput {
|
|
21
|
-
readonly dataSource: DataSourceConfig;
|
|
22
|
-
readonly endpointId: EndpointId;
|
|
23
|
-
readonly operationId: OperationId;
|
|
24
|
-
readonly values?: EndpointTestInputValues;
|
|
25
|
-
readonly dryRun?: boolean;
|
|
26
|
-
readonly fetch?: EndpointTestFetch;
|
|
27
|
-
readonly credentialResolver?: EndpointTestCredentialResolver;
|
|
28
|
-
}
|
|
29
|
-
export interface EndpointTestRequestDiagnostic {
|
|
30
|
-
readonly dataSourceId: string;
|
|
31
|
-
readonly endpointId: EndpointId;
|
|
32
|
-
readonly operationId: OperationId;
|
|
33
|
-
readonly url: string;
|
|
34
|
-
readonly method: string;
|
|
35
|
-
readonly headers: EndpointTestHeaders;
|
|
36
|
-
readonly body?: string;
|
|
37
|
-
readonly dryRun: boolean;
|
|
38
|
-
}
|
|
39
|
-
export interface EndpointTestResponseDiagnostic {
|
|
40
|
-
readonly status: number;
|
|
41
|
-
readonly ok: boolean;
|
|
42
|
-
readonly headers?: EndpointTestHeaders;
|
|
43
|
-
readonly bodyText?: string;
|
|
44
|
-
readonly parsedBody?: DataContractValue;
|
|
45
|
-
}
|
|
46
|
-
export type EndpointTestResult = {
|
|
47
|
-
readonly ok: true;
|
|
48
|
-
readonly request: EndpointTestRequestDiagnostic;
|
|
49
|
-
readonly response?: EndpointTestResponseDiagnostic;
|
|
50
|
-
readonly data?: DataContractValue;
|
|
51
|
-
readonly diagnostics: readonly DataSourceDiagnostic[];
|
|
52
|
-
} | {
|
|
53
|
-
readonly ok: false;
|
|
54
|
-
readonly request?: EndpointTestRequestDiagnostic;
|
|
55
|
-
readonly response?: EndpointTestResponseDiagnostic;
|
|
56
|
-
readonly diagnostics: readonly DataSourceDiagnostic[];
|
|
57
|
-
};
|
|
1
|
+
import type { EndpointTestInput, EndpointTestResult } from './types';
|
|
2
|
+
export type * from './types';
|
|
58
3
|
export declare function testEndpoint(input: EndpointTestInput): Promise<EndpointTestResult>;
|
|
59
4
|
export declare function buildEndpointTestRequest(input: EndpointTestInput): Promise<EndpointTestResult>;
|
|
60
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/test-runner/index.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,mBAAmB,SAAS,CAAC;AAO7B,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4BxF;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,kBAAkB,CAAC,CA8B7B"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { createResponseDiagnostic } from './response';
|
|
2
|
+
import { createDiagnostic, createNetworkErrorMessage, failure } from './result';
|
|
3
|
+
import { appendQuery, collectHeaders, collectQuery, createHttpBody, getRecordValue, getStringMetadataValue, getStringValue, interpolatePath, joinUrl, } from './serialization';
|
|
1
4
|
export async function testEndpoint(input) {
|
|
2
5
|
const built = await buildEndpointTestRequest(input);
|
|
3
6
|
if (!built.ok || input.dryRun === true)
|
|
@@ -14,20 +17,7 @@ export async function testEndpoint(input) {
|
|
|
14
17
|
headers: built.request.headers,
|
|
15
18
|
body: built.request.body,
|
|
16
19
|
});
|
|
17
|
-
|
|
18
|
-
const diagnostics = [...built.diagnostics];
|
|
19
|
-
if (!responseDiagnostic.ok) {
|
|
20
|
-
diagnostics.push(createDiagnostic(input, 'http-error', `Endpoint test request returned HTTP status ${responseDiagnostic.status}.`));
|
|
21
|
-
}
|
|
22
|
-
return responseDiagnostic.ok
|
|
23
|
-
? {
|
|
24
|
-
ok: true,
|
|
25
|
-
request: built.request,
|
|
26
|
-
response: responseDiagnostic,
|
|
27
|
-
data: responseDiagnostic.parsedBody,
|
|
28
|
-
diagnostics,
|
|
29
|
-
}
|
|
30
|
-
: failure(built.request, diagnostics, responseDiagnostic);
|
|
20
|
+
return createEndpointTestResult(input, built, await createResponseDiagnostic(response));
|
|
31
21
|
}
|
|
32
22
|
catch (error) {
|
|
33
23
|
return failure(built.request, [
|
|
@@ -37,34 +27,51 @@ export async function testEndpoint(input) {
|
|
|
37
27
|
}
|
|
38
28
|
}
|
|
39
29
|
export async function buildEndpointTestRequest(input) {
|
|
30
|
+
if (input.api.origin === 'internal') {
|
|
31
|
+
return failure(undefined, [
|
|
32
|
+
createDiagnostic(input, 'invalid-config', 'Internal APIs are not executable in API phase 1.'),
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
40
35
|
const selection = selectEndpointOperation(input);
|
|
41
36
|
if (selection === undefined) {
|
|
42
37
|
return failure(undefined, [
|
|
43
38
|
createDiagnostic(input, 'missing-operation', 'Endpoint or operation could not be found.'),
|
|
44
39
|
]);
|
|
45
40
|
}
|
|
46
|
-
if (selection.operation.protocol
|
|
41
|
+
if (selection.operation.protocol !== 'http' && selection.operation.protocol !== 'graphql') {
|
|
47
42
|
return failure(undefined, [
|
|
48
|
-
createDiagnostic(input, 'invalid-config',
|
|
43
|
+
createDiagnostic(input, 'invalid-config', `API operation protocol '${selection.operation.protocol}' is not supported.`),
|
|
49
44
|
]);
|
|
50
45
|
}
|
|
51
46
|
const diagnostics = [];
|
|
52
47
|
const credential = await resolveEndpointCredential(input, selection, diagnostics);
|
|
53
|
-
const request = selection
|
|
54
|
-
? buildGraphQlRequest(input, selection, credential, diagnostics)
|
|
55
|
-
: buildHttpRequest(input, selection, credential, diagnostics);
|
|
48
|
+
const request = buildProtocolRequest(input, selection, credential, diagnostics);
|
|
56
49
|
if (request === undefined || diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {
|
|
57
50
|
return failure(request, diagnostics);
|
|
58
51
|
}
|
|
59
52
|
return { ok: true, request, diagnostics };
|
|
60
53
|
}
|
|
54
|
+
function createEndpointTestResult(input, built, response) {
|
|
55
|
+
const diagnostics = [...built.diagnostics];
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
diagnostics.push(createDiagnostic(input, 'http-error', `Endpoint test request returned HTTP status ${response.status}.`));
|
|
58
|
+
return failure(built.request, diagnostics, response);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
ok: true,
|
|
62
|
+
request: built.request,
|
|
63
|
+
response,
|
|
64
|
+
data: response.parsedBody,
|
|
65
|
+
diagnostics,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
61
68
|
function selectEndpointOperation(input) {
|
|
62
|
-
const endpoint = input.
|
|
69
|
+
const endpoint = input.api.endpoints[input.endpointId];
|
|
63
70
|
const operation = endpoint?.operations[input.operationId];
|
|
64
71
|
return endpoint === undefined || operation === undefined ? undefined : { endpoint, operation };
|
|
65
72
|
}
|
|
66
73
|
async function resolveEndpointCredential(input, selection, diagnostics) {
|
|
67
|
-
const ref = selection.operation.credential ?? selection.endpoint.credential ?? input.
|
|
74
|
+
const ref = selection.operation.credential ?? selection.endpoint.credential ?? input.api.credential;
|
|
68
75
|
if (ref === undefined)
|
|
69
76
|
return undefined;
|
|
70
77
|
if (input.credentialResolver === undefined) {
|
|
@@ -77,39 +84,49 @@ async function resolveEndpointCredential(input, selection, diagnostics) {
|
|
|
77
84
|
}
|
|
78
85
|
return credential;
|
|
79
86
|
}
|
|
87
|
+
function buildProtocolRequest(input, selection, credential, diagnostics) {
|
|
88
|
+
return selection.operation.protocol === 'graphql'
|
|
89
|
+
? buildGraphQlRequest(input, selection, credential, diagnostics)
|
|
90
|
+
: buildHttpRequest(input, selection, credential, diagnostics);
|
|
91
|
+
}
|
|
80
92
|
function buildHttpRequest(input, selection, credential, diagnostics) {
|
|
81
|
-
const baseUrl =
|
|
93
|
+
const baseUrl = getRestBaseUrl(input.api, selection.endpoint);
|
|
82
94
|
const path = selection.operation.path ?? selection.endpoint.path;
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
diagnostics.push(createDiagnostic(input, 'invalid-config', 'HTTP operation requires a path.'));
|
|
95
|
+
if (baseUrl === undefined || path === undefined) {
|
|
96
|
+
const message = baseUrl === undefined
|
|
97
|
+
? 'HTTP endpoint requires a base URL.'
|
|
98
|
+
: 'HTTP operation requires a path.';
|
|
99
|
+
diagnostics.push(createDiagnostic(input, 'invalid-config', message));
|
|
89
100
|
return undefined;
|
|
90
101
|
}
|
|
91
102
|
const values = input.values ?? {};
|
|
92
103
|
const parameters = selection.operation.request?.parameters ?? [];
|
|
93
104
|
const resolvedPath = interpolatePath(path, parameters, values, input, diagnostics);
|
|
94
105
|
const query = collectQuery(parameters, values, credential?.query);
|
|
95
|
-
const
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
const headers = collectHeaders(parameters, values, credential?.headers);
|
|
107
|
+
const body = createHttpBody(selection.operation, parameters, values);
|
|
108
|
+
const requestHeaders = body === undefined
|
|
109
|
+
? headers
|
|
110
|
+
: {
|
|
111
|
+
...headers,
|
|
112
|
+
'content-type': headers['content-type'] ??
|
|
113
|
+
selection.operation.request?.contentType ??
|
|
114
|
+
'application/json',
|
|
115
|
+
};
|
|
99
116
|
return {
|
|
100
|
-
|
|
117
|
+
apiId: input.api.id,
|
|
101
118
|
endpointId: input.endpointId,
|
|
102
119
|
operationId: input.operationId,
|
|
103
120
|
url: appendQuery(joinUrl(baseUrl, resolvedPath), query),
|
|
104
121
|
method: selection.operation.method ?? 'GET',
|
|
105
|
-
headers,
|
|
122
|
+
headers: requestHeaders,
|
|
106
123
|
body,
|
|
107
124
|
dryRun: input.dryRun === true,
|
|
108
125
|
};
|
|
109
126
|
}
|
|
110
127
|
function buildGraphQlRequest(input, selection, credential, diagnostics) {
|
|
111
|
-
const endpointUrl = getGraphQlEndpointUrl(input.
|
|
112
|
-
if (
|
|
128
|
+
const endpointUrl = getGraphQlEndpointUrl(input.api, selection.endpoint);
|
|
129
|
+
if (endpointUrl === undefined) {
|
|
113
130
|
diagnostics.push(createDiagnostic(input, 'invalid-config', 'GraphQL endpoint requires an endpoint URL.'));
|
|
114
131
|
return undefined;
|
|
115
132
|
}
|
|
@@ -121,7 +138,7 @@ function buildGraphQlRequest(input, selection, credential, diagnostics) {
|
|
|
121
138
|
}
|
|
122
139
|
const variables = getRecordValue(input.values, 'variables');
|
|
123
140
|
return {
|
|
124
|
-
|
|
141
|
+
apiId: input.api.id,
|
|
125
142
|
endpointId: input.endpointId,
|
|
126
143
|
operationId: input.operationId,
|
|
127
144
|
url: appendQuery(endpointUrl, credential?.query ?? {}),
|
|
@@ -131,133 +148,14 @@ function buildGraphQlRequest(input, selection, credential, diagnostics) {
|
|
|
131
148
|
dryRun: input.dryRun === true,
|
|
132
149
|
};
|
|
133
150
|
}
|
|
134
|
-
function
|
|
151
|
+
function getRestBaseUrl(api, endpoint) {
|
|
135
152
|
if (endpoint.baseUrl !== undefined)
|
|
136
153
|
return endpoint.baseUrl;
|
|
137
|
-
|
|
138
|
-
return undefined;
|
|
139
|
-
return source.protocol === 'rest' ? source.baseUrl : source.endpointUrl;
|
|
154
|
+
return api.origin === 'external' && api.protocol === 'rest' ? api.baseUrl : undefined;
|
|
140
155
|
}
|
|
141
|
-
function getGraphQlEndpointUrl(
|
|
156
|
+
function getGraphQlEndpointUrl(api, endpoint) {
|
|
142
157
|
if (endpoint.baseUrl !== undefined)
|
|
143
158
|
return endpoint.baseUrl;
|
|
144
|
-
return
|
|
145
|
-
? source.endpointUrl
|
|
146
|
-
: undefined;
|
|
147
|
-
}
|
|
148
|
-
function interpolatePath(path, parameters, values, input, diagnostics) {
|
|
149
|
-
let next = path;
|
|
150
|
-
for (const parameter of parameters.filter((item) => item.location === 'path')) {
|
|
151
|
-
const value = values[parameter.name] ?? parameter.default;
|
|
152
|
-
if (value === undefined) {
|
|
153
|
-
diagnostics.push(createDiagnostic(input, 'invalid-config', `Missing required path parameter '${parameter.name}'.`));
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
const encoded = encodeURIComponent(serializeEndpointUrlValue(value));
|
|
157
|
-
next = next
|
|
158
|
-
.replaceAll(`{${parameter.name}}`, encoded)
|
|
159
|
-
.replaceAll(`:${parameter.name}`, encoded);
|
|
160
|
-
}
|
|
161
|
-
return next;
|
|
162
|
-
}
|
|
163
|
-
function collectQuery(parameters, values, credentialQuery) {
|
|
164
|
-
const query = { ...(credentialQuery ?? {}) };
|
|
165
|
-
for (const parameter of parameters) {
|
|
166
|
-
if (parameter.location !== 'query')
|
|
167
|
-
continue;
|
|
168
|
-
const value = values[parameter.name] ?? parameter.default;
|
|
169
|
-
if (value !== undefined)
|
|
170
|
-
query[parameter.name] = value;
|
|
171
|
-
}
|
|
172
|
-
return query;
|
|
173
|
-
}
|
|
174
|
-
function createHttpBody(operation, values) {
|
|
175
|
-
if (operation.method === 'GET' || operation.method === 'HEAD')
|
|
176
|
-
return undefined;
|
|
177
|
-
return values.body === undefined ? undefined : JSON.stringify(values.body);
|
|
178
|
-
}
|
|
179
|
-
async function createResponseDiagnostic(response) {
|
|
180
|
-
const bodyText = await response.text();
|
|
181
|
-
return {
|
|
182
|
-
status: response.status,
|
|
183
|
-
ok: response.status >= 200 && response.status < 300,
|
|
184
|
-
headers: response.headers,
|
|
185
|
-
bodyText,
|
|
186
|
-
parsedBody: parseResponseBody(bodyText),
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function parseResponseBody(bodyText) {
|
|
190
|
-
if (bodyText.trim().length === 0)
|
|
191
|
-
return undefined;
|
|
192
|
-
try {
|
|
193
|
-
const parsed = JSON.parse(bodyText);
|
|
194
|
-
return isDataContractValue(parsed) ? parsed : { raw: bodyText };
|
|
195
|
-
}
|
|
196
|
-
catch {
|
|
197
|
-
return { raw: bodyText };
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
function appendQuery(url, query) {
|
|
201
|
-
const entries = Object.entries(query);
|
|
202
|
-
if (entries.length === 0)
|
|
203
|
-
return url;
|
|
204
|
-
const search = entries
|
|
205
|
-
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(serializeEndpointUrlValue(value))}`)
|
|
206
|
-
.join('&');
|
|
207
|
-
return `${url}${url.includes('?') ? '&' : '?'}${search}`;
|
|
208
|
-
}
|
|
209
|
-
function serializeEndpointUrlValue(value) {
|
|
210
|
-
if (typeof value === 'string')
|
|
211
|
-
return value;
|
|
212
|
-
if (typeof value === 'number' || typeof value === 'boolean')
|
|
213
|
-
return value.toString();
|
|
214
|
-
if (value === null)
|
|
215
|
-
return '';
|
|
216
|
-
return JSON.stringify(value);
|
|
217
|
-
}
|
|
218
|
-
function joinUrl(baseUrl, path) {
|
|
219
|
-
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
220
|
-
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
221
|
-
return `${normalizedBaseUrl}${normalizedPath}`;
|
|
222
|
-
}
|
|
223
|
-
function getStringValue(values, key) {
|
|
224
|
-
const value = values?.[key];
|
|
225
|
-
return typeof value === 'string' ? value : undefined;
|
|
226
|
-
}
|
|
227
|
-
function getRecordValue(values, key) {
|
|
228
|
-
const value = values?.[key];
|
|
229
|
-
return isDataContractValue(value) ? value : undefined;
|
|
230
|
-
}
|
|
231
|
-
function getStringMetadataValue(metadata, key) {
|
|
232
|
-
if (!isDataContractRecord(metadata))
|
|
233
|
-
return undefined;
|
|
234
|
-
const value = metadata[key];
|
|
235
|
-
return typeof value === 'string' ? value : undefined;
|
|
236
|
-
}
|
|
237
|
-
function createDiagnostic(input, code, message) {
|
|
238
|
-
return {
|
|
239
|
-
code,
|
|
240
|
-
dataSourceId: input.dataSource.id,
|
|
241
|
-
endpointId: input.endpointId,
|
|
242
|
-
operationId: input.operationId,
|
|
243
|
-
message,
|
|
244
|
-
severity: code === 'missing-schema' ? 'info' : 'error',
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
function failure(request, diagnostics, response) {
|
|
248
|
-
return { ok: false, request, response, diagnostics };
|
|
249
|
-
}
|
|
250
|
-
function createNetworkErrorMessage(error) {
|
|
251
|
-
return error instanceof Error ? error.message : 'Endpoint test request failed.';
|
|
252
|
-
}
|
|
253
|
-
function isDataContractValue(value) {
|
|
254
|
-
if (value === null || ['string', 'number', 'boolean'].includes(typeof value))
|
|
255
|
-
return true;
|
|
256
|
-
if (Array.isArray(value))
|
|
257
|
-
return value.every(isDataContractValue);
|
|
258
|
-
return typeof value === 'object' && Object.values(value).every(isDataContractValue);
|
|
259
|
-
}
|
|
260
|
-
function isDataContractRecord(value) {
|
|
261
|
-
return (value !== undefined && typeof value === 'object' && value !== null && !Array.isArray(value));
|
|
159
|
+
return api.origin === 'external' && api.protocol === 'graphql' ? api.endpointUrl : undefined;
|
|
262
160
|
}
|
|
263
161
|
//# sourceMappingURL=index.js.map
|