@ankhorage/data-sources 1.0.1 → 2.0.1
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 +12 -13
- 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 -274
- package/dist/generated-api/index.js.map +0 -1
- package/dist/generated-api/validateGeneratedApiCollection.d.ts +0 -3
- package/dist/generated-api/validateGeneratedApiCollection.d.ts.map +0 -1
- package/dist/generated-api/validateGeneratedApiCollection.js +0 -35
- package/dist/generated-api/validateGeneratedApiCollection.js.map +0 -1
- package/src/generated-api/index.test.ts +0 -173
- package/src/generated-api/index.ts +0 -414
- package/src/generated-api/validateGeneratedApiCollection.test.ts +0 -91
- package/src/generated-api/validateGeneratedApiCollection.ts +0 -76
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test-runner/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CredentialRef,\n DataContractValue,\n DataEndpointConfig,\n DataOperationConfig,\n DataOperationParameter,\n DataSourceConfig,\n DataSourceDiagnostic,\n EndpointId,\n OperationId,\n} from '@ankhorage/contracts/data';\n\nexport type EndpointTestInputValues = Readonly<Record<string, DataContractValue>>;\nexport type EndpointTestHeaders = Readonly<Record<string, string>>;\n\nexport interface EndpointTestCredential {\n readonly headers?: EndpointTestHeaders;\n readonly query?: EndpointTestInputValues;\n}\n\nexport type EndpointTestCredentialResolver = (\n credential: CredentialRef,\n) => EndpointTestCredential | Promise<EndpointTestCredential | undefined> | undefined;\n\nexport interface EndpointTestFetchInit {\n readonly method: string;\n readonly headers: EndpointTestHeaders;\n readonly body?: string;\n}\n\nexport interface EndpointTestFetchResponse {\n readonly status: number;\n readonly headers?: EndpointTestHeaders;\n text(): Promise<string>;\n}\n\nexport type EndpointTestFetch = (\n url: string,\n init: EndpointTestFetchInit,\n) => Promise<EndpointTestFetchResponse>;\n\nexport interface EndpointTestInput {\n readonly dataSource: DataSourceConfig;\n readonly endpointId: EndpointId;\n readonly operationId: OperationId;\n readonly values?: EndpointTestInputValues;\n readonly dryRun?: boolean;\n readonly fetch?: EndpointTestFetch;\n readonly credentialResolver?: EndpointTestCredentialResolver;\n}\n\nexport interface EndpointTestRequestDiagnostic {\n readonly dataSourceId: string;\n readonly endpointId: EndpointId;\n readonly operationId: OperationId;\n readonly url: string;\n readonly method: string;\n readonly headers: EndpointTestHeaders;\n readonly body?: string;\n readonly dryRun: boolean;\n}\n\nexport interface EndpointTestResponseDiagnostic {\n readonly status: number;\n readonly ok: boolean;\n readonly headers?: EndpointTestHeaders;\n readonly bodyText?: string;\n readonly parsedBody?: DataContractValue;\n}\n\nexport type EndpointTestResult =\n | {\n readonly ok: true;\n readonly request: EndpointTestRequestDiagnostic;\n readonly response?: EndpointTestResponseDiagnostic;\n readonly data?: DataContractValue;\n readonly diagnostics: readonly DataSourceDiagnostic[];\n }\n | {\n readonly ok: false;\n readonly request?: EndpointTestRequestDiagnostic;\n readonly response?: EndpointTestResponseDiagnostic;\n readonly diagnostics: readonly DataSourceDiagnostic[];\n };\n\ninterface EndpointOperationSelection {\n readonly endpoint: DataEndpointConfig;\n readonly operation: DataOperationConfig;\n}\n\nexport async function testEndpoint(input: EndpointTestInput): Promise<EndpointTestResult> {\n const built = await buildEndpointTestRequest(input);\n if (!built.ok || input.dryRun === true) return built;\n\n if (input.fetch === undefined) {\n return failure(built.request, [\n ...built.diagnostics,\n createDiagnostic(\n input,\n 'invalid-config',\n 'Endpoint test runner requires an injected fetch function.',\n ),\n ]);\n }\n\n try {\n const response = await input.fetch(built.request.url, {\n method: built.request.method,\n headers: built.request.headers,\n body: built.request.body,\n });\n const responseDiagnostic = await createResponseDiagnostic(response);\n const diagnostics = [...built.diagnostics];\n if (!responseDiagnostic.ok) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'http-error',\n `Endpoint test request returned HTTP status ${responseDiagnostic.status}.`,\n ),\n );\n }\n return responseDiagnostic.ok\n ? {\n ok: true,\n request: built.request,\n response: responseDiagnostic,\n data: responseDiagnostic.parsedBody,\n diagnostics,\n }\n : failure(built.request, diagnostics, responseDiagnostic);\n } catch (error) {\n return failure(built.request, [\n ...built.diagnostics,\n createDiagnostic(input, 'network-error', createNetworkErrorMessage(error)),\n ]);\n }\n}\n\nexport async function buildEndpointTestRequest(\n input: EndpointTestInput,\n): Promise<EndpointTestResult> {\n const selection = selectEndpointOperation(input);\n if (selection === undefined) {\n return failure(undefined, [\n createDiagnostic(input, 'missing-operation', 'Endpoint or operation could not be found.'),\n ]);\n }\n\n if (selection.operation.protocol === 'database') {\n return failure(undefined, [\n createDiagnostic(\n input,\n 'invalid-config',\n 'Database-backed generated API operations require an adapter executor and cannot be tested through the HTTP endpoint runner.',\n ),\n ]);\n }\n\n const diagnostics: DataSourceDiagnostic[] = [];\n const credential = await resolveEndpointCredential(input, selection, diagnostics);\n const request =\n selection.operation.protocol === 'graphql'\n ? buildGraphQlRequest(input, selection, credential, diagnostics)\n : buildHttpRequest(input, selection, credential, diagnostics);\n\n if (request === undefined || diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return failure(request, diagnostics);\n }\n return { ok: true, request, diagnostics };\n}\n\nfunction selectEndpointOperation(input: EndpointTestInput): EndpointOperationSelection | undefined {\n const endpoint = input.dataSource.endpoints[input.endpointId];\n const operation = endpoint?.operations[input.operationId];\n return endpoint === undefined || operation === undefined ? undefined : { endpoint, operation };\n}\n\nasync function resolveEndpointCredential(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n diagnostics: DataSourceDiagnostic[],\n): Promise<EndpointTestCredential | undefined> {\n const ref =\n selection.operation.credential ?? selection.endpoint.credential ?? input.dataSource.credential;\n if (ref === undefined) return undefined;\n if (input.credentialResolver === undefined) {\n diagnostics.push(\n createDiagnostic(input, 'missing-credential', `Credential '${ref.id}' requires a resolver.`),\n );\n return undefined;\n }\n const credential = await input.credentialResolver(ref);\n if (credential === undefined) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'missing-credential',\n `Credential '${ref.id}' could not be resolved.`,\n ),\n );\n }\n return credential;\n}\n\nfunction buildHttpRequest(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n credential: EndpointTestCredential | undefined,\n diagnostics: DataSourceDiagnostic[],\n): EndpointTestRequestDiagnostic | undefined {\n const baseUrl = getDataSourceBaseUrl(input.dataSource, selection.endpoint);\n const path = selection.operation.path ?? selection.endpoint.path;\n if (!baseUrl) {\n diagnostics.push(\n createDiagnostic(input, 'invalid-config', 'HTTP endpoint requires a base URL.'),\n );\n return undefined;\n }\n if (path === undefined) {\n diagnostics.push(createDiagnostic(input, 'invalid-config', 'HTTP operation requires a path.'));\n return undefined;\n }\n\n const values = input.values ?? {};\n const parameters = selection.operation.request?.parameters ?? [];\n const resolvedPath = interpolatePath(path, parameters, values, input, diagnostics);\n const query = collectQuery(parameters, values, credential?.query);\n const body = createHttpBody(selection.operation, values);\n const headers: Record<string, string> = { ...(credential?.headers ?? {}) };\n if (body !== undefined) headers['content-type'] = headers['content-type'] ?? 'application/json';\n\n return {\n dataSourceId: input.dataSource.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n url: appendQuery(joinUrl(baseUrl, resolvedPath), query),\n method: selection.operation.method ?? 'GET',\n headers,\n body,\n dryRun: input.dryRun === true,\n };\n}\n\nfunction buildGraphQlRequest(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n credential: EndpointTestCredential | undefined,\n diagnostics: DataSourceDiagnostic[],\n): EndpointTestRequestDiagnostic | undefined {\n const endpointUrl = getGraphQlEndpointUrl(input.dataSource, selection.endpoint);\n if (!endpointUrl) {\n diagnostics.push(\n createDiagnostic(input, 'invalid-config', 'GraphQL endpoint requires an endpoint URL.'),\n );\n return undefined;\n }\n\n const query =\n getStringMetadataValue(selection.operation.metadata, 'document') ??\n getStringValue(input.values, 'query');\n if (query === undefined) {\n diagnostics.push(\n createDiagnostic(input, 'invalid-config', 'GraphQL operation requires a query document.'),\n );\n return undefined;\n }\n\n const variables = getRecordValue(input.values, 'variables');\n return {\n dataSourceId: input.dataSource.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n url: appendQuery(endpointUrl, credential?.query ?? {}),\n method: 'POST',\n headers: { ...(credential?.headers ?? {}), 'content-type': 'application/json' },\n body: JSON.stringify({ query, variables: variables ?? {} }),\n dryRun: input.dryRun === true,\n };\n}\n\nfunction getDataSourceBaseUrl(\n source: DataSourceConfig,\n endpoint: DataEndpointConfig,\n): string | undefined {\n if (endpoint.baseUrl !== undefined) return endpoint.baseUrl;\n if (source.kind !== 'api' || source.origin !== 'external') return undefined;\n return source.protocol === 'rest' ? source.baseUrl : source.endpointUrl;\n}\n\nfunction getGraphQlEndpointUrl(\n source: DataSourceConfig,\n endpoint: DataEndpointConfig,\n): string | undefined {\n if (endpoint.baseUrl !== undefined) return endpoint.baseUrl;\n return source.kind === 'api' && source.origin === 'external' && source.protocol === 'graphql'\n ? source.endpointUrl\n : undefined;\n}\n\nfunction interpolatePath(\n path: string,\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n input: EndpointTestInput,\n diagnostics: DataSourceDiagnostic[],\n): string {\n let next = path;\n for (const parameter of parameters.filter((item) => item.location === 'path')) {\n const value = values[parameter.name] ?? parameter.default;\n if (value === undefined) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'invalid-config',\n `Missing required path parameter '${parameter.name}'.`,\n ),\n );\n continue;\n }\n const encoded = encodeURIComponent(serializeEndpointUrlValue(value));\n next = next\n .replaceAll(`{${parameter.name}}`, encoded)\n .replaceAll(`:${parameter.name}`, encoded);\n }\n return next;\n}\n\nfunction collectQuery(\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n credentialQuery: EndpointTestInputValues | undefined,\n): EndpointTestInputValues {\n const query: Record<string, DataContractValue> = { ...(credentialQuery ?? {}) };\n for (const parameter of parameters) {\n if (parameter.location !== 'query') continue;\n const value = values[parameter.name] ?? parameter.default;\n if (value !== undefined) query[parameter.name] = value;\n }\n return query;\n}\n\nfunction createHttpBody(\n operation: DataOperationConfig,\n values: EndpointTestInputValues,\n): string | undefined {\n if (operation.method === 'GET' || operation.method === 'HEAD') return undefined;\n return values.body === undefined ? undefined : JSON.stringify(values.body);\n}\n\nasync function createResponseDiagnostic(\n response: EndpointTestFetchResponse,\n): Promise<EndpointTestResponseDiagnostic> {\n const bodyText = await response.text();\n return {\n status: response.status,\n ok: response.status >= 200 && response.status < 300,\n headers: response.headers,\n bodyText,\n parsedBody: parseResponseBody(bodyText),\n };\n}\n\nfunction parseResponseBody(bodyText: string): DataContractValue | undefined {\n if (bodyText.trim().length === 0) return undefined;\n try {\n const parsed: unknown = JSON.parse(bodyText);\n return isDataContractValue(parsed) ? parsed : { raw: bodyText };\n } catch {\n return { raw: bodyText };\n }\n}\n\nfunction appendQuery(url: string, query: EndpointTestInputValues): string {\n const entries = Object.entries(query);\n if (entries.length === 0) return url;\n const search = entries\n .map(\n ([key, value]) =>\n `${encodeURIComponent(key)}=${encodeURIComponent(serializeEndpointUrlValue(value))}`,\n )\n .join('&');\n return `${url}${url.includes('?') ? '&' : '?'}${search}`;\n}\n\nfunction serializeEndpointUrlValue(value: DataContractValue): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return value.toString();\n if (value === null) return '';\n return JSON.stringify(value);\n}\n\nfunction joinUrl(baseUrl: string, path: string): string {\n const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${normalizedBaseUrl}${normalizedPath}`;\n}\n\nfunction getStringValue(\n values: EndpointTestInputValues | undefined,\n key: string,\n): string | undefined {\n const value = values?.[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction getRecordValue(\n values: EndpointTestInputValues | undefined,\n key: string,\n): DataContractValue | undefined {\n const value = values?.[key];\n return isDataContractValue(value) ? value : undefined;\n}\n\nfunction getStringMetadataValue(\n metadata: DataContractValue | undefined,\n key: string,\n): string | undefined {\n if (!isDataContractRecord(metadata)) return undefined;\n const value = metadata[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction createDiagnostic(\n input: EndpointTestInput,\n code: string,\n message: string,\n): DataSourceDiagnostic {\n return {\n code,\n dataSourceId: input.dataSource.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n message,\n severity: code === 'missing-schema' ? 'info' : 'error',\n };\n}\n\nfunction failure(\n request: EndpointTestRequestDiagnostic | undefined,\n diagnostics: readonly DataSourceDiagnostic[],\n response?: EndpointTestResponseDiagnostic,\n): EndpointTestResult {\n return { ok: false, request, response, diagnostics };\n}\n\nfunction createNetworkErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'Endpoint test request failed.';\n}\n\nfunction isDataContractValue(value: unknown): value is DataContractValue {\n if (value === null || ['string', 'number', 'boolean'].includes(typeof value)) return true;\n if (Array.isArray(value)) return value.every(isDataContractValue);\n return typeof value === 'object' && Object.values(value).every(isDataContractValue);\n}\n\nfunction isDataContractRecord(\n value: DataContractValue | undefined,\n): value is Record<string, DataContractValue> {\n return (\n value !== undefined && typeof value === 'object' && value !== null && !Array.isArray(value)\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/test-runner/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAChF,OAAO,EACL,WAAW,EACX,cAAc,EACd,YAAY,EACZ,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,eAAe,EACf,OAAO,GACR,MAAM,iBAAiB,CAAC;AAezB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAwB;IACzD,MAAM,KAAK,GAAG,MAAM,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAErD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE;YAC5B,GAAG,KAAK,CAAC,WAAW;YACpB,gBAAgB,CACd,KAAK,EACL,gBAAgB,EAChB,2DAA2D,CAC5D;SACF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACpD,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM;YAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO;YAC9B,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI;SACzB,CAAC,CAAC;QACH,OAAO,wBAAwB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE;YAC5B,GAAG,KAAK,CAAC,WAAW;YACpB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,yBAAyB,CAAC,KAAK,CAAC,CAAC;SAC3E,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,KAAwB;IAExB,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC,SAAS,EAAE;YACxB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,kDAAkD,CAAC;SAC9F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,OAAO,CAAC,SAAS,EAAE;YACxB,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,EAAE,2CAA2C,CAAC;SAC1F,CAAC,CAAC;IACL,CAAC;IACD,IAAI,SAAS,CAAC,SAAS,CAAC,QAAQ,KAAK,MAAM,IAAI,SAAS,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC1F,OAAO,OAAO,CAAC,SAAS,EAAE;YACxB,gBAAgB,CACd,KAAK,EACL,gBAAgB,EAChB,2BAA2B,SAAS,CAAC,SAAS,CAAC,QAAQ,qBAAqB,CAC7E;SACF,CAAC,CAAC;IACL,CAAC;IAED,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,MAAM,yBAAyB,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAClF,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAChF,IAAI,OAAO,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,CAAC;QAC/F,OAAO,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAwB,EACxB,KAAyD,EACzD,QAA8D;IAE9D,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,WAAW,CAAC,IAAI,CACd,gBAAgB,CACd,KAAK,EACL,YAAY,EACZ,8CAA8C,QAAQ,CAAC,MAAM,GAAG,CACjE,CACF,CAAC;QACF,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ;QACR,IAAI,EAAE,QAAQ,CAAC,UAAU;QACzB,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAwB;IACvD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC1D,OAAO,QAAQ,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjG,CAAC;AAED,KAAK,UAAU,yBAAyB,CACtC,KAAwB,EACxB,SAAqC,EACrC,WAAmC;IAEnC,MAAM,GAAG,GACP,SAAS,CAAC,SAAS,CAAC,UAAU,IAAI,SAAS,CAAC,QAAQ,CAAC,UAAU,IAAI,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;IAC1F,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,KAAK,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QAC3C,WAAW,CAAC,IAAI,CACd,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,EAAE,eAAe,GAAG,CAAC,EAAE,wBAAwB,CAAC,CAC7F,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,WAAW,CAAC,IAAI,CACd,gBAAgB,CACd,KAAK,EACL,oBAAoB,EACpB,eAAe,GAAG,CAAC,EAAE,0BAA0B,CAChD,CACF,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,oBAAoB,CAC3B,KAAwB,EACxB,SAAqC,EACrC,UAA8C,EAC9C,WAAmC;IAEnC,OAAO,SAAS,CAAC,SAAS,CAAC,QAAQ,KAAK,SAAS;QAC/C,CAAC,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC;QAChE,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,gBAAgB,CACvB,KAAwB,EACxB,SAAqC,EACrC,UAA8C,EAC9C,WAAmC;IAEnC,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;IACjE,IAAI,OAAO,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAChD,MAAM,OAAO,GACX,OAAO,KAAK,SAAS;YACnB,CAAC,CAAC,oCAAoC;YACtC,CAAC,CAAC,iCAAiC,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;QACrE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;IACjE,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IACrE,MAAM,cAAc,GAClB,IAAI,KAAK,SAAS;QAChB,CAAC,CAAC,OAAO;QACT,CAAC,CAAC;YACE,GAAG,OAAO;YACV,cAAc,EACZ,OAAO,CAAC,cAAc,CAAC;gBACvB,SAAS,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW;gBACxC,kBAAkB;SACrB,CAAC;IACR,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QACnB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,KAAK,CAAC;QACvD,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,IAAI,KAAK;QAC3C,OAAO,EAAE,cAAc;QACvB,IAAI;QACJ,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAwB,EACxB,SAAqC,EACrC,UAA8C,EAC9C,WAAmC;IAEnC,MAAM,WAAW,GAAG,qBAAqB,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IACzE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,WAAW,CAAC,IAAI,CACd,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,4CAA4C,CAAC,CACxF,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GACT,sBAAsB,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC;QAChE,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,WAAW,CAAC,IAAI,CACd,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,8CAA8C,CAAC,CAC1F,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC5D,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QACnB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,GAAG,EAAE,WAAW,CAAC,WAAW,EAAE,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;QAC3D,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,GAAkB,EAAE,QAA4B;IACtE,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC5D,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,IAAI,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACxF,CAAC;AAED,SAAS,qBAAqB,CAC5B,GAAkB,EAClB,QAA4B;IAE5B,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC;IAC5D,OAAO,GAAG,CAAC,MAAM,KAAK,UAAU,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/F,CAAC","sourcesContent":["import type {\n ApiDefinition,\n DataEndpointConfig,\n DataOperationConfig,\n DataSourceDiagnostic,\n} from '@ankhorage/contracts/data';\n\nimport { createResponseDiagnostic } from './response';\nimport { createDiagnostic, createNetworkErrorMessage, failure } from './result';\nimport {\n appendQuery,\n collectHeaders,\n collectQuery,\n createHttpBody,\n getRecordValue,\n getStringMetadataValue,\n getStringValue,\n interpolatePath,\n joinUrl,\n} from './serialization';\nimport type {\n EndpointTestCredential,\n EndpointTestInput,\n EndpointTestRequestDiagnostic,\n EndpointTestResult,\n} from './types';\n\nexport type * from './types';\n\ninterface EndpointOperationSelection {\n readonly endpoint: DataEndpointConfig;\n readonly operation: DataOperationConfig;\n}\n\nexport async function testEndpoint(input: EndpointTestInput): Promise<EndpointTestResult> {\n const built = await buildEndpointTestRequest(input);\n if (!built.ok || input.dryRun === true) return built;\n\n if (input.fetch === undefined) {\n return failure(built.request, [\n ...built.diagnostics,\n createDiagnostic(\n input,\n 'invalid-config',\n 'Endpoint test runner requires an injected fetch function.',\n ),\n ]);\n }\n\n try {\n const response = await input.fetch(built.request.url, {\n method: built.request.method,\n headers: built.request.headers,\n body: built.request.body,\n });\n return createEndpointTestResult(input, built, await createResponseDiagnostic(response));\n } catch (error) {\n return failure(built.request, [\n ...built.diagnostics,\n createDiagnostic(input, 'network-error', createNetworkErrorMessage(error)),\n ]);\n }\n}\n\nexport async function buildEndpointTestRequest(\n input: EndpointTestInput,\n): Promise<EndpointTestResult> {\n if (input.api.origin === 'internal') {\n return failure(undefined, [\n createDiagnostic(input, 'invalid-config', 'Internal APIs are not executable in API phase 1.'),\n ]);\n }\n\n const selection = selectEndpointOperation(input);\n if (selection === undefined) {\n return failure(undefined, [\n createDiagnostic(input, 'missing-operation', 'Endpoint or operation could not be found.'),\n ]);\n }\n if (selection.operation.protocol !== 'http' && selection.operation.protocol !== 'graphql') {\n return failure(undefined, [\n createDiagnostic(\n input,\n 'invalid-config',\n `API operation protocol '${selection.operation.protocol}' is not supported.`,\n ),\n ]);\n }\n\n const diagnostics: DataSourceDiagnostic[] = [];\n const credential = await resolveEndpointCredential(input, selection, diagnostics);\n const request = buildProtocolRequest(input, selection, credential, diagnostics);\n if (request === undefined || diagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return failure(request, diagnostics);\n }\n return { ok: true, request, diagnostics };\n}\n\nfunction createEndpointTestResult(\n input: EndpointTestInput,\n built: Extract<EndpointTestResult, { readonly ok: true }>,\n response: Awaited<ReturnType<typeof createResponseDiagnostic>>,\n): EndpointTestResult {\n const diagnostics = [...built.diagnostics];\n if (!response.ok) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'http-error',\n `Endpoint test request returned HTTP status ${response.status}.`,\n ),\n );\n return failure(built.request, diagnostics, response);\n }\n return {\n ok: true,\n request: built.request,\n response,\n data: response.parsedBody,\n diagnostics,\n };\n}\n\nfunction selectEndpointOperation(input: EndpointTestInput): EndpointOperationSelection | undefined {\n const endpoint = input.api.endpoints[input.endpointId];\n const operation = endpoint?.operations[input.operationId];\n return endpoint === undefined || operation === undefined ? undefined : { endpoint, operation };\n}\n\nasync function resolveEndpointCredential(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n diagnostics: DataSourceDiagnostic[],\n): Promise<EndpointTestCredential | undefined> {\n const ref =\n selection.operation.credential ?? selection.endpoint.credential ?? input.api.credential;\n if (ref === undefined) return undefined;\n if (input.credentialResolver === undefined) {\n diagnostics.push(\n createDiagnostic(input, 'missing-credential', `Credential '${ref.id}' requires a resolver.`),\n );\n return undefined;\n }\n const credential = await input.credentialResolver(ref);\n if (credential === undefined) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'missing-credential',\n `Credential '${ref.id}' could not be resolved.`,\n ),\n );\n }\n return credential;\n}\n\nfunction buildProtocolRequest(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n credential: EndpointTestCredential | undefined,\n diagnostics: DataSourceDiagnostic[],\n): EndpointTestRequestDiagnostic | undefined {\n return selection.operation.protocol === 'graphql'\n ? buildGraphQlRequest(input, selection, credential, diagnostics)\n : buildHttpRequest(input, selection, credential, diagnostics);\n}\n\nfunction buildHttpRequest(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n credential: EndpointTestCredential | undefined,\n diagnostics: DataSourceDiagnostic[],\n): EndpointTestRequestDiagnostic | undefined {\n const baseUrl = getRestBaseUrl(input.api, selection.endpoint);\n const path = selection.operation.path ?? selection.endpoint.path;\n if (baseUrl === undefined || path === undefined) {\n const message =\n baseUrl === undefined\n ? 'HTTP endpoint requires a base URL.'\n : 'HTTP operation requires a path.';\n diagnostics.push(createDiagnostic(input, 'invalid-config', message));\n return undefined;\n }\n\n const values = input.values ?? {};\n const parameters = selection.operation.request?.parameters ?? [];\n const resolvedPath = interpolatePath(path, parameters, values, input, diagnostics);\n const query = collectQuery(parameters, values, credential?.query);\n const headers = collectHeaders(parameters, values, credential?.headers);\n const body = createHttpBody(selection.operation, parameters, values);\n const requestHeaders =\n body === undefined\n ? headers\n : {\n ...headers,\n 'content-type':\n headers['content-type'] ??\n selection.operation.request?.contentType ??\n 'application/json',\n };\n return {\n apiId: input.api.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n url: appendQuery(joinUrl(baseUrl, resolvedPath), query),\n method: selection.operation.method ?? 'GET',\n headers: requestHeaders,\n body,\n dryRun: input.dryRun === true,\n };\n}\n\nfunction buildGraphQlRequest(\n input: EndpointTestInput,\n selection: EndpointOperationSelection,\n credential: EndpointTestCredential | undefined,\n diagnostics: DataSourceDiagnostic[],\n): EndpointTestRequestDiagnostic | undefined {\n const endpointUrl = getGraphQlEndpointUrl(input.api, selection.endpoint);\n if (endpointUrl === undefined) {\n diagnostics.push(\n createDiagnostic(input, 'invalid-config', 'GraphQL endpoint requires an endpoint URL.'),\n );\n return undefined;\n }\n\n const query =\n getStringMetadataValue(selection.operation.metadata, 'document') ??\n getStringValue(input.values, 'query');\n if (query === undefined) {\n diagnostics.push(\n createDiagnostic(input, 'invalid-config', 'GraphQL operation requires a query document.'),\n );\n return undefined;\n }\n\n const variables = getRecordValue(input.values, 'variables');\n return {\n apiId: input.api.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n url: appendQuery(endpointUrl, credential?.query ?? {}),\n method: 'POST',\n headers: { ...(credential?.headers ?? {}), 'content-type': 'application/json' },\n body: JSON.stringify({ query, variables: variables ?? {} }),\n dryRun: input.dryRun === true,\n };\n}\n\nfunction getRestBaseUrl(api: ApiDefinition, endpoint: DataEndpointConfig): string | undefined {\n if (endpoint.baseUrl !== undefined) return endpoint.baseUrl;\n return api.origin === 'external' && api.protocol === 'rest' ? api.baseUrl : undefined;\n}\n\nfunction getGraphQlEndpointUrl(\n api: ApiDefinition,\n endpoint: DataEndpointConfig,\n): string | undefined {\n if (endpoint.baseUrl !== undefined) return endpoint.baseUrl;\n return api.origin === 'external' && api.protocol === 'graphql' ? api.endpointUrl : undefined;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../../src/test-runner/response.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,SAAS,CAAC;AAEzF,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,yBAAyB,GAClC,OAAO,CAAC,8BAA8B,CAAC,CASzC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export async function createResponseDiagnostic(response) {
|
|
2
|
+
const bodyText = await response.text();
|
|
3
|
+
return {
|
|
4
|
+
status: response.status,
|
|
5
|
+
ok: response.status >= 200 && response.status < 300,
|
|
6
|
+
headers: response.headers,
|
|
7
|
+
bodyText,
|
|
8
|
+
parsedBody: parseResponseBody(bodyText),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function parseResponseBody(bodyText) {
|
|
12
|
+
if (bodyText.trim().length === 0)
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(bodyText);
|
|
16
|
+
return isDataContractValue(parsed) ? parsed : { raw: bodyText };
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return { raw: bodyText };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function isDataContractValue(value) {
|
|
23
|
+
if (value === null || ['string', 'number', 'boolean'].includes(typeof value))
|
|
24
|
+
return true;
|
|
25
|
+
if (Array.isArray(value))
|
|
26
|
+
return value.every(isDataContractValue);
|
|
27
|
+
return typeof value === 'object' && Object.values(value).every(isDataContractValue);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/test-runner/response.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,QAAmC;IAEnC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACvC,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,EAAE,EAAE,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;QACnD,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,QAAQ;QACR,UAAU,EAAE,iBAAiB,CAAC,QAAQ,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB;IACzC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACnD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1F,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAClE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;AACtF,CAAC","sourcesContent":["import type { DataContractValue } from '@ankhorage/contracts/data';\n\nimport type { EndpointTestFetchResponse, EndpointTestResponseDiagnostic } from './types';\n\nexport async function createResponseDiagnostic(\n response: EndpointTestFetchResponse,\n): Promise<EndpointTestResponseDiagnostic> {\n const bodyText = await response.text();\n return {\n status: response.status,\n ok: response.status >= 200 && response.status < 300,\n headers: response.headers,\n bodyText,\n parsedBody: parseResponseBody(bodyText),\n };\n}\n\nfunction parseResponseBody(bodyText: string): DataContractValue | undefined {\n if (bodyText.trim().length === 0) return undefined;\n try {\n const parsed: unknown = JSON.parse(bodyText);\n return isDataContractValue(parsed) ? parsed : { raw: bodyText };\n } catch {\n return { raw: bodyText };\n }\n}\n\nfunction isDataContractValue(value: unknown): value is DataContractValue {\n if (value === null || ['string', 'number', 'boolean'].includes(typeof value)) return true;\n if (Array.isArray(value)) return value.every(isDataContractValue);\n return typeof value === 'object' && Object.values(value).every(isDataContractValue);\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DataSourceDiagnostic } from '@ankhorage/contracts/data';
|
|
2
|
+
import type { EndpointTestInput, EndpointTestRequestDiagnostic, EndpointTestResponseDiagnostic, EndpointTestResult } from './types';
|
|
3
|
+
export declare function createDiagnostic(input: EndpointTestInput, code: string, message: string): DataSourceDiagnostic;
|
|
4
|
+
export declare function failure(request: EndpointTestRequestDiagnostic | undefined, diagnostics: readonly DataSourceDiagnostic[], response?: EndpointTestResponseDiagnostic): EndpointTestResult;
|
|
5
|
+
export declare function createNetworkErrorMessage(error: unknown): string;
|
|
6
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/test-runner/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,OAAO,KAAK,EACV,iBAAiB,EACjB,6BAA6B,EAC7B,8BAA8B,EAC9B,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,iBAAiB,EACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,oBAAoB,CAStB;AAED,wBAAgB,OAAO,CACrB,OAAO,EAAE,6BAA6B,GAAG,SAAS,EAClD,WAAW,EAAE,SAAS,oBAAoB,EAAE,EAC5C,QAAQ,CAAC,EAAE,8BAA8B,GACxC,kBAAkB,CAEpB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function createDiagnostic(input, code, message) {
|
|
2
|
+
return {
|
|
3
|
+
code,
|
|
4
|
+
apiId: input.api.id,
|
|
5
|
+
endpointId: input.endpointId,
|
|
6
|
+
operationId: input.operationId,
|
|
7
|
+
message,
|
|
8
|
+
severity: code === 'missing-schema' ? 'info' : 'error',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function failure(request, diagnostics, response) {
|
|
12
|
+
return { ok: false, request, response, diagnostics };
|
|
13
|
+
}
|
|
14
|
+
export function createNetworkErrorMessage(error) {
|
|
15
|
+
return error instanceof Error ? error.message : 'Endpoint test request failed.';
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/test-runner/result.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,gBAAgB,CAC9B,KAAwB,EACxB,IAAY,EACZ,OAAe;IAEf,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;QACnB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,OAAO;QACP,QAAQ,EAAE,IAAI,KAAK,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;KACvD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,OAAkD,EAClD,WAA4C,EAC5C,QAAyC;IAEzC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;AAClF,CAAC","sourcesContent":["import type { DataSourceDiagnostic } from '@ankhorage/contracts/data';\n\nimport type {\n EndpointTestInput,\n EndpointTestRequestDiagnostic,\n EndpointTestResponseDiagnostic,\n EndpointTestResult,\n} from './types';\n\nexport function createDiagnostic(\n input: EndpointTestInput,\n code: string,\n message: string,\n): DataSourceDiagnostic {\n return {\n code,\n apiId: input.api.id,\n endpointId: input.endpointId,\n operationId: input.operationId,\n message,\n severity: code === 'missing-schema' ? 'info' : 'error',\n };\n}\n\nexport function failure(\n request: EndpointTestRequestDiagnostic | undefined,\n diagnostics: readonly DataSourceDiagnostic[],\n response?: EndpointTestResponseDiagnostic,\n): EndpointTestResult {\n return { ok: false, request, response, diagnostics };\n}\n\nexport function createNetworkErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'Endpoint test request failed.';\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DataContractValue, DataOperationConfig, DataOperationParameter, DataSourceDiagnostic } from '@ankhorage/contracts/data';
|
|
2
|
+
import type { EndpointTestHeaders, EndpointTestInput, EndpointTestInputValues } from './types';
|
|
3
|
+
export declare function interpolatePath(path: string, parameters: readonly DataOperationParameter[], values: EndpointTestInputValues, input: EndpointTestInput, diagnostics: DataSourceDiagnostic[]): string;
|
|
4
|
+
export declare function collectQuery(parameters: readonly DataOperationParameter[], values: EndpointTestInputValues, credentialQuery: EndpointTestInputValues | undefined): EndpointTestInputValues;
|
|
5
|
+
export declare function collectHeaders(parameters: readonly DataOperationParameter[], values: EndpointTestInputValues, credentialHeaders: EndpointTestHeaders | undefined): Record<string, string>;
|
|
6
|
+
export declare function createHttpBody(operation: DataOperationConfig, parameters: readonly DataOperationParameter[], values: EndpointTestInputValues): string | undefined;
|
|
7
|
+
export declare function appendQuery(url: string, query: EndpointTestInputValues): string;
|
|
8
|
+
export declare function joinUrl(baseUrl: string, path: string): string;
|
|
9
|
+
export declare function getStringValue(values: EndpointTestInputValues | undefined, key: string): string | undefined;
|
|
10
|
+
export declare function getRecordValue(values: EndpointTestInputValues | undefined, key: string): DataContractValue | undefined;
|
|
11
|
+
export declare function getStringMetadataValue(metadata: DataContractValue | undefined, key: string): string | undefined;
|
|
12
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/test-runner/serialization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAE/F,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,sBAAsB,EAAE,EAC7C,MAAM,EAAE,uBAAuB,EAC/B,KAAK,EAAE,iBAAiB,EACxB,WAAW,EAAE,oBAAoB,EAAE,GAClC,MAAM,CAoBR;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,SAAS,sBAAsB,EAAE,EAC7C,MAAM,EAAE,uBAAuB,EAC/B,eAAe,EAAE,uBAAuB,GAAG,SAAS,GACnD,uBAAuB,CAOzB;AAED,wBAAgB,cAAc,CAC5B,UAAU,EAAE,SAAS,sBAAsB,EAAE,EAC7C,MAAM,EAAE,uBAAuB,EAC/B,iBAAiB,EAAE,mBAAmB,GAAG,SAAS,GACjD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOxB;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,mBAAmB,EAC9B,UAAU,EAAE,SAAS,sBAAsB,EAAE,EAC7C,MAAM,EAAE,uBAAuB,GAC9B,MAAM,GAAG,SAAS,CAWpB;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAU/E;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,uBAAuB,GAAG,SAAS,EAC3C,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAGpB;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,uBAAuB,GAAG,SAAS,EAC3C,GAAG,EAAE,MAAM,GACV,iBAAiB,GAAG,SAAS,CAG/B;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,SAAS,CAIpB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createDiagnostic } from './result';
|
|
2
|
+
export function interpolatePath(path, parameters, values, input, diagnostics) {
|
|
3
|
+
let next = path;
|
|
4
|
+
for (const parameter of parameters.filter((item) => item.location === 'path')) {
|
|
5
|
+
const value = readValue(values, parameter.name) ?? parameter.default;
|
|
6
|
+
if (value === undefined) {
|
|
7
|
+
diagnostics.push(createDiagnostic(input, 'invalid-config', `Missing required path parameter '${parameter.name}'.`));
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
const encoded = encodeURIComponent(serializeEndpointUrlValue(value));
|
|
11
|
+
next = next
|
|
12
|
+
.replaceAll(`{${parameter.name}}`, encoded)
|
|
13
|
+
.replaceAll(`:${parameter.name}`, encoded);
|
|
14
|
+
}
|
|
15
|
+
return next;
|
|
16
|
+
}
|
|
17
|
+
export function collectQuery(parameters, values, credentialQuery) {
|
|
18
|
+
const parameterEntries = parameters.flatMap((parameter) => {
|
|
19
|
+
if (parameter.location !== 'query')
|
|
20
|
+
return [];
|
|
21
|
+
const value = readValue(values, parameter.name) ?? parameter.default;
|
|
22
|
+
return value === undefined ? [] : [[parameter.name, value]];
|
|
23
|
+
});
|
|
24
|
+
return Object.fromEntries([...Object.entries(credentialQuery ?? {}), ...parameterEntries]);
|
|
25
|
+
}
|
|
26
|
+
export function collectHeaders(parameters, values, credentialHeaders) {
|
|
27
|
+
const parameterEntries = parameters.flatMap((parameter) => {
|
|
28
|
+
if (parameter.location !== 'header')
|
|
29
|
+
return [];
|
|
30
|
+
const value = readValue(values, parameter.name) ?? parameter.default;
|
|
31
|
+
return value === undefined ? [] : [[parameter.name, serializeEndpointUrlValue(value)]];
|
|
32
|
+
});
|
|
33
|
+
return Object.fromEntries([...Object.entries(credentialHeaders ?? {}), ...parameterEntries]);
|
|
34
|
+
}
|
|
35
|
+
export function createHttpBody(operation, parameters, values) {
|
|
36
|
+
if (operation.method === 'GET' || operation.method === 'HEAD')
|
|
37
|
+
return undefined;
|
|
38
|
+
const explicitBody = readValue(values, 'body');
|
|
39
|
+
if (explicitBody !== undefined)
|
|
40
|
+
return JSON.stringify(explicitBody);
|
|
41
|
+
const entries = parameters.flatMap((parameter) => {
|
|
42
|
+
if (parameter.location !== 'body')
|
|
43
|
+
return [];
|
|
44
|
+
const value = readValue(values, parameter.name) ?? parameter.default;
|
|
45
|
+
return value === undefined ? [] : [[parameter.name, value]];
|
|
46
|
+
});
|
|
47
|
+
return entries.length === 0 ? undefined : JSON.stringify(Object.fromEntries(entries));
|
|
48
|
+
}
|
|
49
|
+
export function appendQuery(url, query) {
|
|
50
|
+
const entries = Object.entries(query);
|
|
51
|
+
if (entries.length === 0)
|
|
52
|
+
return url;
|
|
53
|
+
const search = entries
|
|
54
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(serializeEndpointUrlValue(value))}`)
|
|
55
|
+
.join('&');
|
|
56
|
+
return `${url}${url.includes('?') ? '&' : '?'}${search}`;
|
|
57
|
+
}
|
|
58
|
+
export function joinUrl(baseUrl, path) {
|
|
59
|
+
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
60
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
61
|
+
return `${normalizedBaseUrl}${normalizedPath}`;
|
|
62
|
+
}
|
|
63
|
+
export function getStringValue(values, key) {
|
|
64
|
+
const value = readValue(values, key);
|
|
65
|
+
return typeof value === 'string' ? value : undefined;
|
|
66
|
+
}
|
|
67
|
+
export function getRecordValue(values, key) {
|
|
68
|
+
const value = readValue(values, key);
|
|
69
|
+
return isDataContractValue(value) ? value : undefined;
|
|
70
|
+
}
|
|
71
|
+
export function getStringMetadataValue(metadata, key) {
|
|
72
|
+
if (!isDataContractRecord(metadata))
|
|
73
|
+
return undefined;
|
|
74
|
+
const value = readValue(metadata, key);
|
|
75
|
+
return typeof value === 'string' ? value : undefined;
|
|
76
|
+
}
|
|
77
|
+
function serializeEndpointUrlValue(value) {
|
|
78
|
+
if (typeof value === 'string')
|
|
79
|
+
return value;
|
|
80
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
81
|
+
return value.toString();
|
|
82
|
+
if (value === null)
|
|
83
|
+
return '';
|
|
84
|
+
return JSON.stringify(value);
|
|
85
|
+
}
|
|
86
|
+
function readValue(values, key) {
|
|
87
|
+
return Object.entries(values ?? {}).find(([entryKey]) => entryKey === key)?.[1];
|
|
88
|
+
}
|
|
89
|
+
function isDataContractValue(value) {
|
|
90
|
+
if (value === null || ['string', 'number', 'boolean'].includes(typeof value))
|
|
91
|
+
return true;
|
|
92
|
+
if (Array.isArray(value))
|
|
93
|
+
return value.every(isDataContractValue);
|
|
94
|
+
return typeof value === 'object' && Object.values(value).every(isDataContractValue);
|
|
95
|
+
}
|
|
96
|
+
function isDataContractRecord(value) {
|
|
97
|
+
return (value !== undefined && typeof value === 'object' && value !== null && !Array.isArray(value));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/test-runner/serialization.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n DataContractValue,\n DataOperationConfig,\n DataOperationParameter,\n DataSourceDiagnostic,\n} from '@ankhorage/contracts/data';\n\nimport { createDiagnostic } from './result';\nimport type { EndpointTestHeaders, EndpointTestInput, EndpointTestInputValues } from './types';\n\nexport function interpolatePath(\n path: string,\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n input: EndpointTestInput,\n diagnostics: DataSourceDiagnostic[],\n): string {\n let next = path;\n for (const parameter of parameters.filter((item) => item.location === 'path')) {\n const value = readValue(values, parameter.name) ?? parameter.default;\n if (value === undefined) {\n diagnostics.push(\n createDiagnostic(\n input,\n 'invalid-config',\n `Missing required path parameter '${parameter.name}'.`,\n ),\n );\n continue;\n }\n const encoded = encodeURIComponent(serializeEndpointUrlValue(value));\n next = next\n .replaceAll(`{${parameter.name}}`, encoded)\n .replaceAll(`:${parameter.name}`, encoded);\n }\n return next;\n}\n\nexport function collectQuery(\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n credentialQuery: EndpointTestInputValues | undefined,\n): EndpointTestInputValues {\n const parameterEntries = parameters.flatMap((parameter) => {\n if (parameter.location !== 'query') return [];\n const value = readValue(values, parameter.name) ?? parameter.default;\n return value === undefined ? [] : [[parameter.name, value] as const];\n });\n return Object.fromEntries([...Object.entries(credentialQuery ?? {}), ...parameterEntries]);\n}\n\nexport function collectHeaders(\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n credentialHeaders: EndpointTestHeaders | undefined,\n): Record<string, string> {\n const parameterEntries = parameters.flatMap((parameter) => {\n if (parameter.location !== 'header') return [];\n const value = readValue(values, parameter.name) ?? parameter.default;\n return value === undefined ? [] : [[parameter.name, serializeEndpointUrlValue(value)] as const];\n });\n return Object.fromEntries([...Object.entries(credentialHeaders ?? {}), ...parameterEntries]);\n}\n\nexport function createHttpBody(\n operation: DataOperationConfig,\n parameters: readonly DataOperationParameter[],\n values: EndpointTestInputValues,\n): string | undefined {\n if (operation.method === 'GET' || operation.method === 'HEAD') return undefined;\n const explicitBody = readValue(values, 'body');\n if (explicitBody !== undefined) return JSON.stringify(explicitBody);\n\n const entries = parameters.flatMap((parameter) => {\n if (parameter.location !== 'body') return [];\n const value = readValue(values, parameter.name) ?? parameter.default;\n return value === undefined ? [] : [[parameter.name, value] as const];\n });\n return entries.length === 0 ? undefined : JSON.stringify(Object.fromEntries(entries));\n}\n\nexport function appendQuery(url: string, query: EndpointTestInputValues): string {\n const entries = Object.entries(query);\n if (entries.length === 0) return url;\n const search = entries\n .map(\n ([key, value]) =>\n `${encodeURIComponent(key)}=${encodeURIComponent(serializeEndpointUrlValue(value))}`,\n )\n .join('&');\n return `${url}${url.includes('?') ? '&' : '?'}${search}`;\n}\n\nexport function joinUrl(baseUrl: string, path: string): string {\n const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;\n const normalizedPath = path.startsWith('/') ? path : `/${path}`;\n return `${normalizedBaseUrl}${normalizedPath}`;\n}\n\nexport function getStringValue(\n values: EndpointTestInputValues | undefined,\n key: string,\n): string | undefined {\n const value = readValue(values, key);\n return typeof value === 'string' ? value : undefined;\n}\n\nexport function getRecordValue(\n values: EndpointTestInputValues | undefined,\n key: string,\n): DataContractValue | undefined {\n const value = readValue(values, key);\n return isDataContractValue(value) ? value : undefined;\n}\n\nexport function getStringMetadataValue(\n metadata: DataContractValue | undefined,\n key: string,\n): string | undefined {\n if (!isDataContractRecord(metadata)) return undefined;\n const value = readValue(metadata, key);\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction serializeEndpointUrlValue(value: DataContractValue): string {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return value.toString();\n if (value === null) return '';\n return JSON.stringify(value);\n}\n\nfunction readValue(\n values: Readonly<Record<string, DataContractValue>> | undefined,\n key: string,\n): DataContractValue | undefined {\n return Object.entries(values ?? {}).find(([entryKey]) => entryKey === key)?.[1];\n}\n\nfunction isDataContractValue(value: unknown): value is DataContractValue {\n if (value === null || ['string', 'number', 'boolean'].includes(typeof value)) return true;\n if (Array.isArray(value)) return value.every(isDataContractValue);\n return typeof value === 'object' && Object.values(value).every(isDataContractValue);\n}\n\nfunction isDataContractRecord(\n value: DataContractValue | undefined,\n): value is Record<string, DataContractValue> {\n return (\n value !== undefined && typeof value === 'object' && value !== null && !Array.isArray(value)\n );\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ApiDefinition, CredentialRef, DataContractValue, DataSourceDiagnostic, EndpointId, OperationId } from '@ankhorage/contracts/data';
|
|
2
|
+
export type EndpointTestInputValues = Readonly<Record<string, DataContractValue>>;
|
|
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 api: ApiDefinition;
|
|
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 apiId: 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
|
+
};
|
|
58
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/test-runner/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/test-runner/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ApiDefinition,\n CredentialRef,\n DataContractValue,\n DataSourceDiagnostic,\n EndpointId,\n OperationId,\n} from '@ankhorage/contracts/data';\n\nexport type EndpointTestInputValues = Readonly<Record<string, DataContractValue>>;\nexport type EndpointTestHeaders = Readonly<Record<string, string>>;\n\nexport interface EndpointTestCredential {\n readonly headers?: EndpointTestHeaders;\n readonly query?: EndpointTestInputValues;\n}\n\nexport type EndpointTestCredentialResolver = (\n credential: CredentialRef,\n) => EndpointTestCredential | Promise<EndpointTestCredential | undefined> | undefined;\n\nexport interface EndpointTestFetchInit {\n readonly method: string;\n readonly headers: EndpointTestHeaders;\n readonly body?: string;\n}\n\nexport interface EndpointTestFetchResponse {\n readonly status: number;\n readonly headers?: EndpointTestHeaders;\n text(): Promise<string>;\n}\n\nexport type EndpointTestFetch = (\n url: string,\n init: EndpointTestFetchInit,\n) => Promise<EndpointTestFetchResponse>;\n\nexport interface EndpointTestInput {\n readonly api: ApiDefinition;\n readonly endpointId: EndpointId;\n readonly operationId: OperationId;\n readonly values?: EndpointTestInputValues;\n readonly dryRun?: boolean;\n readonly fetch?: EndpointTestFetch;\n readonly credentialResolver?: EndpointTestCredentialResolver;\n}\n\nexport interface EndpointTestRequestDiagnostic {\n readonly apiId: string;\n readonly endpointId: EndpointId;\n readonly operationId: OperationId;\n readonly url: string;\n readonly method: string;\n readonly headers: EndpointTestHeaders;\n readonly body?: string;\n readonly dryRun: boolean;\n}\n\nexport interface EndpointTestResponseDiagnostic {\n readonly status: number;\n readonly ok: boolean;\n readonly headers?: EndpointTestHeaders;\n readonly bodyText?: string;\n readonly parsedBody?: DataContractValue;\n}\n\nexport type EndpointTestResult =\n | {\n readonly ok: true;\n readonly request: EndpointTestRequestDiagnostic;\n readonly response?: EndpointTestResponseDiagnostic;\n readonly data?: DataContractValue;\n readonly diagnostics: readonly DataSourceDiagnostic[];\n }\n | {\n readonly ok: false;\n readonly request?: EndpointTestRequestDiagnostic;\n readonly response?: EndpointTestResponseDiagnostic;\n readonly diagnostics: readonly DataSourceDiagnostic[];\n };\n"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/data-sources",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "Headless toolkit for importing,
|
|
4
|
+
"version": "2.0.1",
|
|
5
|
+
"description": "Headless toolkit for importing, normalizing, and executing canonical Ankhorage API and data-source configs.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/data-sources#readme",
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/ankhorage/data-sources/issues"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typescript"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@ankhorage/contracts": "^
|
|
28
|
+
"@ankhorage/contracts": "^8.0.1"
|
|
29
29
|
},
|
|
30
30
|
"ankh": {
|
|
31
31
|
"category": "data-sources",
|
|
@@ -64,26 +64,25 @@
|
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.build.json",
|
|
67
|
-
"changeset": "changeset",
|
|
68
|
-
"changeset:status": "changeset status --since=origin/main",
|
|
67
|
+
"changeset": "ankhorage-changeset",
|
|
68
|
+
"changeset:status": "ankhorage-changeset status --since=origin/main",
|
|
69
69
|
"docs": "paradox",
|
|
70
|
-
"knip": "ankhorage-knip",
|
|
71
70
|
"lint": "ankhorage-eslint . --max-warnings=0",
|
|
72
|
-
"lint:fix": "ankhorage-eslint . --fix",
|
|
71
|
+
"lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
|
|
73
72
|
"format": "ankhorage-prettier --write .",
|
|
74
73
|
"format:check": "ankhorage-prettier --check .",
|
|
75
74
|
"prepack": "bun run build",
|
|
76
75
|
"test": "bun test src",
|
|
77
76
|
"typecheck": "bun x tsc --noEmit -p tsconfig.json",
|
|
78
|
-
"version-packages": "changeset version"
|
|
77
|
+
"version-packages": "ankhorage-changeset version",
|
|
78
|
+
"knip:check": "ankhorage-knip"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@ankhorage/devtools": "^1.
|
|
82
|
-
"@ankhorage/paradox": "^0.1.
|
|
83
|
-
"@
|
|
84
|
-
"@types/bun": "^1.3.13",
|
|
81
|
+
"@ankhorage/devtools": "^1.9.2",
|
|
82
|
+
"@ankhorage/paradox": "^0.1.24",
|
|
83
|
+
"@types/bun": "^1.4.0",
|
|
85
84
|
"@types/node": "^25.6.0",
|
|
86
85
|
"typescript": "^5.9.3"
|
|
87
86
|
},
|
|
88
|
-
"packageManager": "bun@1.
|
|
87
|
+
"packageManager": "bun@1.4.0"
|
|
89
88
|
}
|
package/src/ankh.provider.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DATA_SOURCES_PACKAGE_NAME, SUPPORTED_DATA_SOURCE_KINDS } from './
|
|
1
|
+
import { DATA_SOURCES_PACKAGE_NAME, SUPPORTED_DATA_SOURCE_KINDS } from './packageInfo';
|
|
2
2
|
|
|
3
3
|
const DATA_SOURCES_PACKAGE_VERSION = '0.5.1';
|
|
4
4
|
const DATA_SOURCES_COMMAND_CATEGORY = 'data-sources';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import * as dataSources from './index';
|
|
4
|
+
|
|
5
|
+
describe('API phase 1 public surface', () => {
|
|
6
|
+
it('does not export generated API database projection helpers', () => {
|
|
7
|
+
const publicApi = dataSources as Readonly<Record<string, unknown>>;
|
|
8
|
+
|
|
9
|
+
expect(publicApi.createGeneratedApiDataSource).toBeUndefined();
|
|
10
|
+
expect(publicApi.normalizeGeneratedApiDataSource).toBeUndefined();
|
|
11
|
+
expect(publicApi.validateGeneratedApiCollection).toBeUndefined();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('exports canonical API helpers instead of data-source aliases', () => {
|
|
15
|
+
const publicApi = dataSources as Readonly<Record<string, unknown>>;
|
|
16
|
+
|
|
17
|
+
expect(typeof publicApi.createManualRestApi).toBe('function');
|
|
18
|
+
expect(typeof publicApi.createGraphQlApi).toBe('function');
|
|
19
|
+
expect(typeof publicApi.discoverOpenApi).toBe('function');
|
|
20
|
+
expect(typeof publicApi.introspectGraphQlApi).toBe('function');
|
|
21
|
+
expect(publicApi.createManualRestDataSource).toBeUndefined();
|
|
22
|
+
expect(publicApi.createGraphQlDataSource).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
interface TextResponse {
|
|
2
|
+
text(): Promise<string>;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function parseHttpUrl(rawUrl: string): URL | undefined {
|
|
6
|
+
try {
|
|
7
|
+
const parsed = new URL(rawUrl.trim());
|
|
8
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return undefined;
|
|
9
|
+
if (parsed.username.length > 0 || parsed.password.length > 0) return undefined;
|
|
10
|
+
return parsed;
|
|
11
|
+
} catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function normalizeCandidateUrl(url: URL): string {
|
|
17
|
+
const normalized = new URL(url.toString());
|
|
18
|
+
normalized.hash = '';
|
|
19
|
+
return normalized.toString();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isSuccessfulStatus(status: number): boolean {
|
|
23
|
+
return status >= 200 && status < 300;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function parseJsonResponse(response: TextResponse): Promise<unknown> {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(await response.text()) as unknown;
|
|
29
|
+
} catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function readRecord(value: unknown): Readonly<Record<string, unknown>> | undefined {
|
|
35
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
36
|
+
? (value as Readonly<Record<string, unknown>>)
|
|
37
|
+
: undefined;
|
|
38
|
+
}
|