@openapi-flow/core 0.1.0 → 0.2.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/README.md +27 -5
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/arguments/list-api-request-media-types.d.ts +2 -0
- package/dist/arguments/list-api-request-media-types.js +8 -0
- package/dist/arguments/request-contract.d.ts +4 -0
- package/dist/arguments/request-contract.js +38 -0
- package/dist/arguments/request-media-type-priority.d.ts +2 -0
- package/dist/arguments/request-media-type-priority.js +8 -0
- package/dist/arguments/select-default-api-request-media-type.d.ts +3 -0
- package/dist/arguments/select-default-api-request-media-type.js +17 -0
- package/dist/arguments/validate-api-arguments.d.ts +2 -0
- package/dist/arguments/validate-api-arguments.js +140 -0
- package/dist/bindings/combine-binding-schemas.d.ts +4 -0
- package/dist/bindings/combine-binding-schemas.js +17 -0
- package/dist/bindings/create-native-array-item-schema.d.ts +4 -0
- package/dist/bindings/create-native-array-item-schema.js +16 -0
- package/dist/bindings/json-pointer.d.ts +3 -0
- package/dist/bindings/json-pointer.js +24 -0
- package/dist/bindings/materialize-api-arguments.d.ts +4 -0
- package/dist/bindings/materialize-api-arguments.js +54 -0
- package/dist/bindings/native-binding-schema.d.ts +3 -0
- package/dist/bindings/native-binding-schema.js +6 -0
- package/dist/bindings/project-array-item-schema.d.ts +5 -0
- package/dist/bindings/project-array-item-schema.js +67 -0
- package/dist/bindings/request-binding-schema.d.ts +2 -0
- package/dist/bindings/request-binding-schema.js +23 -0
- package/dist/bindings/request-container-kind.d.ts +3 -0
- package/dist/bindings/request-container-kind.js +17 -0
- package/dist/bindings/resources/clone-schema-resource.d.ts +3 -0
- package/dist/bindings/resources/clone-schema-resource.js +38 -0
- package/dist/bindings/resources/create-schema-resource-context.d.ts +4 -0
- package/dist/bindings/resources/create-schema-resource-context.js +130 -0
- package/dist/bindings/response-binding-schema.d.ts +3 -0
- package/dist/bindings/response-binding-schema.js +21 -0
- package/dist/bindings/schema-allows-container.d.ts +3 -0
- package/dist/bindings/schema-allows-container.js +20 -0
- package/dist/bindings/schema-at-pointer.d.ts +4 -0
- package/dist/bindings/schema-at-pointer.js +89 -0
- package/dist/bindings/validate-api-binding-assignments.d.ts +2 -0
- package/dist/bindings/validate-api-binding-assignments.js +81 -0
- package/dist/bindings/validate-api-binding-gaps.d.ts +2 -0
- package/dist/bindings/validate-api-binding-gaps.js +10 -0
- package/dist/bindings/validate-api-binding-plan.d.ts +3 -0
- package/dist/bindings/validate-api-binding-plan.js +11 -0
- package/dist/bindings/validate-native-output-contracts.d.ts +3 -0
- package/dist/bindings/validate-native-output-contracts.js +16 -0
- package/dist/internal-api.d.ts +30 -0
- package/dist/internal-api.js +25 -0
- package/dist/openapi/catalog/create-api-catalog.d.ts +2 -0
- package/dist/openapi/catalog/create-api-catalog.js +34 -0
- package/dist/openapi/catalog/list-api-operations.d.ts +2 -0
- package/dist/openapi/catalog/list-api-operations.js +3 -0
- package/dist/openapi/common/check-oas-value.d.ts +3 -0
- package/dist/openapi/common/check-oas-value.js +6 -0
- package/dist/openapi/common/check-schema-value.d.ts +2 -0
- package/dist/openapi/common/check-schema-value.js +12 -0
- package/dist/openapi/common/create-oas-value-validator.d.ts +3 -0
- package/dist/openapi/common/create-oas-value-validator.js +39 -0
- package/dist/openapi/common/normalize-oas-value-schema.d.ts +4 -0
- package/dist/openapi/common/normalize-oas-value-schema.js +50 -0
- package/dist/openapi/common/operation-metadata.d.ts +2 -0
- package/dist/openapi/common/operation-metadata.js +25 -0
- package/dist/openapi/common/operation-reference.d.ts +3 -0
- package/dist/openapi/{operation-reference.js → common/operation-reference.js} +1 -4
- package/dist/openapi/common/parse-spec-utils.d.ts +3 -0
- package/dist/openapi/common/parse-spec-utils.js +12 -0
- package/dist/openapi/common/resolve-openapi-security.d.ts +3 -0
- package/dist/openapi/common/resolve-openapi-security.js +28 -0
- package/dist/openapi/common/unsupported-operation-error.d.ts +4 -0
- package/dist/openapi/common/unsupported-operation-error.js +8 -0
- package/dist/openapi/common/validate-spec.d.ts +3 -0
- package/dist/openapi/{validate-spec.js → common/validate-spec.js} +2 -1
- package/dist/openapi/inbound/callback/parse-callback-operations.d.ts +3 -0
- package/dist/openapi/inbound/callback/parse-callback-operations.js +31 -0
- package/dist/openapi/inbound/inbound-path-item-operations.d.ts +4 -0
- package/dist/openapi/inbound/inbound-path-item-operations.js +31 -0
- package/dist/openapi/inbound/list-inbound-operations.d.ts +4 -0
- package/dist/openapi/inbound/list-inbound-operations.js +13 -0
- package/dist/openapi/inbound/webhook/parse-webhook-operations.d.ts +3 -0
- package/dist/openapi/inbound/webhook/parse-webhook-operations.js +13 -0
- package/dist/openapi/request/create-operation-catalog.d.ts +2 -0
- package/dist/openapi/request/create-operation-catalog.js +24 -0
- package/dist/openapi/request/encode-form-field.d.ts +2 -0
- package/dist/openapi/request/encode-form-field.js +6 -0
- package/dist/openapi/request/map-http-operation-contract.d.ts +4 -0
- package/dist/openapi/request/map-http-operation-contract.js +21 -0
- package/dist/openapi/request/operation-mapping.d.ts +3 -0
- package/dist/openapi/request/operation-mapping.js +10 -0
- package/dist/openapi/request/parse-operation-responses.d.ts +3 -0
- package/dist/openapi/request/parse-operation-responses.js +30 -0
- package/dist/openapi/request/parse-request-body.d.ts +3 -0
- package/dist/openapi/request/parse-request-body.js +29 -0
- package/dist/openapi/request/parse-request-operations.d.ts +7 -0
- package/dist/openapi/request/parse-request-operations.js +50 -0
- package/dist/openapi/request/parse-request-parameters.d.ts +3 -0
- package/dist/openapi/request/parse-request-parameters.js +93 -0
- package/dist/openapi/request/parse-security.d.ts +3 -0
- package/dist/openapi/request/parse-security.js +31 -0
- package/dist/openapi/request/request-operation-reference.d.ts +1 -0
- package/dist/openapi/request/request-operation-reference.js +4 -0
- package/dist/openapi/request/response-contract.d.ts +6 -0
- package/dist/openapi/request/response-contract.js +32 -0
- package/dist/openapi/request/scalar-response-schema.d.ts +2 -0
- package/dist/openapi/request/scalar-response-schema.js +20 -0
- package/dist/openapi/request/serialize-form-body.d.ts +3 -0
- package/dist/openapi/request/serialize-form-body.js +89 -0
- package/dist/openapi/request/serialize-parameter.d.ts +5 -0
- package/dist/openapi/request/serialize-parameter.js +145 -0
- package/dist/openapi/resolve-api-operations.d.ts +3 -0
- package/dist/openapi/resolve-api-operations.js +84 -0
- package/dist/openapi/response/api-response-validation-value.d.ts +3 -0
- package/dist/openapi/response/api-response-validation-value.js +21 -0
- package/dist/openapi/response/create-api-response-schema.d.ts +4 -0
- package/dist/openapi/response/create-api-response-schema.js +114 -0
- package/dist/openapi/response/create-response-array-item-schema.d.ts +4 -0
- package/dist/openapi/response/create-response-array-item-schema.js +12 -0
- package/dist/openapi/response/create-response-value-schema.d.ts +4 -0
- package/dist/openapi/response/create-response-value-schema.js +8 -0
- package/dist/openapi/response/list-api-response-pointers.d.ts +4 -0
- package/dist/openapi/response/list-api-response-pointers.js +30 -0
- package/dist/openapi/response/list-declared-schema-pointers.d.ts +4 -0
- package/dist/openapi/response/list-declared-schema-pointers.js +91 -0
- package/dist/public-api.d.ts +49 -7
- package/dist/public-api.js +35 -5
- package/dist/runtime-api.d.ts +6 -0
- package/dist/runtime-api.js +7 -0
- package/dist/schemas/create-api-argument-generation-contract.d.ts +4 -0
- package/dist/schemas/create-api-argument-generation-contract.js +72 -0
- package/dist/schemas/create-api-arguments-schema.d.ts +3 -0
- package/dist/schemas/create-api-arguments-schema.js +4 -0
- package/dist/schemas/create-api-request-schema.d.ts +4 -0
- package/dist/schemas/create-api-request-schema.js +50 -0
- package/dist/schemas/create-oas-value-schema.d.ts +6 -0
- package/dist/schemas/create-oas-value-schema.js +25 -0
- package/dist/schemas/operation-plan-schema.d.ts +8 -0
- package/dist/schemas/operation-plan-schema.js +99 -0
- package/dist/schemas/project-literal-array-schema.d.ts +4 -0
- package/dist/schemas/project-literal-array-schema.js +55 -0
- package/dist/schemas/project-literal-input-schema.d.ts +3 -0
- package/dist/schemas/project-literal-input-schema.js +129 -0
- package/dist/types/api-argument-generation.d.ts +13 -0
- package/dist/types/api-arguments.d.ts +42 -0
- package/dist/types/api-arguments.js +1 -0
- package/dist/types/api-bindings.d.ts +34 -0
- package/dist/types/api-bindings.js +1 -0
- package/dist/types/api-catalog.d.ts +34 -0
- package/dist/types/api-catalog.js +1 -0
- package/dist/types/api-operation.d.ts +26 -0
- package/dist/types/api-operation.js +1 -0
- package/dist/types/api-response-pointers.d.ts +20 -0
- package/dist/types/api-response-pointers.js +1 -0
- package/dist/types/api-response.d.ts +14 -0
- package/dist/types/api-response.js +1 -0
- package/dist/types/array-projection.d.ts +5 -0
- package/dist/types/array-projection.js +1 -0
- package/dist/types/catalog.d.ts +17 -0
- package/dist/types/catalog.js +1 -0
- package/dist/types/inbound.d.ts +18 -0
- package/dist/types/inbound.js +1 -0
- package/dist/types/legacy-plan.d.ts +47 -0
- package/dist/types/legacy-plan.js +1 -0
- package/dist/types/node-output.d.ts +11 -0
- package/dist/types/node-output.js +1 -0
- package/dist/types/oas-value-validation.d.ts +8 -0
- package/dist/types/oas-value-validation.js +1 -0
- package/dist/types/openapi.d.ts +7 -23
- package/dist/types/request.d.ts +41 -0
- package/dist/types/request.js +1 -0
- package/dist/types/reviewable-workflow.d.ts +53 -0
- package/dist/types/reviewable-workflow.js +1 -0
- package/dist/types/schema-dialect.d.ts +1 -0
- package/dist/types/schema-dialect.js +1 -0
- package/dist/types/schema-json.d.ts +4 -0
- package/dist/types/schema-json.js +1 -0
- package/dist/types/schema-resource.d.ts +12 -0
- package/dist/types/schema-resource.js +1 -0
- package/dist/types/security.d.ts +17 -0
- package/dist/types/security.js +1 -0
- package/dist/types/workflow-capability-planning.d.ts +10 -0
- package/dist/types/workflow-capability-planning.js +1 -0
- package/dist/types/workflow-plan.d.ts +104 -0
- package/dist/types/workflow-plan.js +1 -0
- package/dist/utils/is-object.d.ts +2 -0
- package/dist/utils/is-object.js +3 -0
- package/dist/utils/json-values-equal.d.ts +2 -0
- package/dist/utils/json-values-equal.js +16 -0
- package/dist/workflow/assert-api-call-identities.d.ts +1 -0
- package/dist/workflow/assert-api-call-identities.js +6 -0
- package/dist/workflow/create-native-output-contracts.d.ts +3 -0
- package/dist/workflow/create-native-output-contracts.js +23 -0
- package/dist/workflow/create-reviewable-node-contracts.d.ts +3 -0
- package/dist/workflow/create-reviewable-node-contracts.js +36 -0
- package/dist/workflow/create-reviewable-workflow-graph-plan.d.ts +2 -0
- package/dist/workflow/create-reviewable-workflow-graph-plan.js +29 -0
- package/dist/workflow/create-workflow-graph-plan.d.ts +2 -0
- package/dist/workflow/create-workflow-graph-plan.js +17 -0
- package/dist/workflow/create-workflow-node-contracts.d.ts +2 -0
- package/dist/workflow/create-workflow-node-contracts.js +50 -0
- package/dist/workflow/create-workflow-planning-capabilities.d.ts +3 -0
- package/dist/workflow/create-workflow-planning-capabilities.js +20 -0
- package/dist/workflow/parse-native-node-parameters.d.ts +3 -0
- package/dist/workflow/parse-native-node-parameters.js +7 -0
- package/dist/workflow/validate-exclusive-output-rejoin.d.ts +3 -0
- package/dist/workflow/validate-exclusive-output-rejoin.js +26 -0
- package/dist/workflow/validate-native-api-response-references.d.ts +2 -0
- package/dist/workflow/validate-native-api-response-references.js +26 -0
- package/dist/workflow/validate-reviewable-workflow-graph-plan.d.ts +2 -0
- package/dist/workflow/validate-reviewable-workflow-graph-plan.js +98 -0
- package/dist/workflow/validate-workflow-edges.d.ts +2 -0
- package/dist/workflow/validate-workflow-edges.js +19 -0
- package/dist/workflow/validate-workflow-graph-plan.d.ts +3 -0
- package/dist/workflow/validate-workflow-graph-plan.js +41 -0
- package/dist/workflow/validate-workflow-topology.d.ts +2 -0
- package/dist/workflow/validate-workflow-topology.js +105 -0
- package/package.json +19 -25
- package/dist/openapi/operation-reference.d.ts +0 -3
- package/dist/openapi/parse-spec-utils.d.ts +0 -5
- package/dist/openapi/parse-spec-utils.js +0 -52
- package/dist/openapi/parse-spec.d.ts +0 -5
- package/dist/openapi/parse-spec.js +0 -182
- package/dist/openapi/validate-spec.d.ts +0 -3
- package/dist/planning/generate-workflow.d.ts +0 -2
- package/dist/planning/generate-workflow.js +0 -126
- package/dist/schemas/planning-schemas.d.ts +0 -62
- package/dist/schemas/planning-schemas.js +0 -48
- package/dist/types/workflow.d.ts +0 -75
- package/dist/utils/validation.d.ts +0 -7
- package/dist/utils/validation.js +0 -44
- package/dist/utils/workflow-id.d.ts +0 -1
- package/dist/utils/workflow-id.js +0 -8
- package/dist/workflow/compile-sequence.d.ts +0 -2
- package/dist/workflow/compile-sequence.js +0 -167
- package/dist/workflow/compile-workflow.d.ts +0 -4
- package/dist/workflow/compile-workflow.js +0 -128
- package/dist/workflow/sequence-url.d.ts +0 -3
- package/dist/workflow/sequence-url.js +0 -81
- package/dist/workflow/workflow-helpers.d.ts +0 -6
- package/dist/workflow/workflow-helpers.js +0 -81
- /package/dist/types/{workflow.js → api-argument-generation.js} +0 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BindingSchema } from '../../types/api-bindings.js';
|
|
2
|
+
import type { SchemaResourceContext } from '../../types/schema-resource.js';
|
|
3
|
+
/** Keep original resources; projected values reference their original locations. */
|
|
4
|
+
export declare function createSchemaResourceContext(schema: BindingSchema): SchemaResourceContext;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
3
|
+
import addFormats from 'ajv-formats';
|
|
4
|
+
import uri from 'fast-uri';
|
|
5
|
+
import { isObject } from '../../utils/is-object.js';
|
|
6
|
+
import { cloneSchemaResource } from './clone-schema-resource.js';
|
|
7
|
+
/** Keep original resources; projected values reference their original locations. */
|
|
8
|
+
export function createSchemaResourceContext(schema) {
|
|
9
|
+
if (typeof schema === 'boolean')
|
|
10
|
+
return {
|
|
11
|
+
root: schema,
|
|
12
|
+
reference: (value) => value,
|
|
13
|
+
resolve: (value) => value,
|
|
14
|
+
bundle: (value) => value,
|
|
15
|
+
};
|
|
16
|
+
const document = cloneSchemaResource(schema);
|
|
17
|
+
if (typeof document === 'boolean')
|
|
18
|
+
throw new Error('Native schema resource must be an object');
|
|
19
|
+
// JSON Schema permits an implementation-assigned initial retrieval URI.
|
|
20
|
+
if (document.$id !== undefined && typeof document.$id !== 'string')
|
|
21
|
+
throw new Error('Native schema.$id must be a URI-reference string');
|
|
22
|
+
const retrievalUri = `https://openapi-flow.invalid/schema/${createHash('sha256').update(JSON.stringify(document)).digest('hex')}`;
|
|
23
|
+
const rootUri = typeof document.$id === 'string'
|
|
24
|
+
? uri.resolve(retrievalUri, document.$id)
|
|
25
|
+
: retrievalUri;
|
|
26
|
+
const root = { ...document, $id: rootUri };
|
|
27
|
+
const locations = new WeakMap();
|
|
28
|
+
function index(current, pointer, baseUri) {
|
|
29
|
+
if (typeof current === 'boolean')
|
|
30
|
+
return;
|
|
31
|
+
const base = typeof current.$id === 'string'
|
|
32
|
+
? uri.resolve(baseUri, current.$id)
|
|
33
|
+
: baseUri;
|
|
34
|
+
locations.set(current, {
|
|
35
|
+
reference: uri.resolve(rootUri, '#' + pointer.split('/').map(encodeURIComponent).join('/')),
|
|
36
|
+
baseUri: base,
|
|
37
|
+
});
|
|
38
|
+
function child(value, suffix) {
|
|
39
|
+
if (typeof value === 'boolean' || isObject(value))
|
|
40
|
+
index(value, pointer + suffix, base);
|
|
41
|
+
}
|
|
42
|
+
// Traverse schema-valued keywords, not const/enum/default/example data.
|
|
43
|
+
for (const key of [
|
|
44
|
+
'$defs',
|
|
45
|
+
'definitions',
|
|
46
|
+
'properties',
|
|
47
|
+
'patternProperties',
|
|
48
|
+
'dependentSchemas',
|
|
49
|
+
'dependencies',
|
|
50
|
+
]) {
|
|
51
|
+
const children = current[key];
|
|
52
|
+
if (!isObject(children))
|
|
53
|
+
continue;
|
|
54
|
+
for (const [name, value] of Object.entries(children))
|
|
55
|
+
child(value, '/' + key + '/' + name.replaceAll('~', '~0').replaceAll('/', '~1'));
|
|
56
|
+
}
|
|
57
|
+
for (const key of [
|
|
58
|
+
'items',
|
|
59
|
+
'contains',
|
|
60
|
+
'additionalProperties',
|
|
61
|
+
'unevaluatedProperties',
|
|
62
|
+
'unevaluatedItems',
|
|
63
|
+
'propertyNames',
|
|
64
|
+
'not',
|
|
65
|
+
'if',
|
|
66
|
+
'then',
|
|
67
|
+
'else',
|
|
68
|
+
])
|
|
69
|
+
child(current[key], '/' + key);
|
|
70
|
+
for (const key of ['allOf', 'anyOf', 'oneOf', 'prefixItems']) {
|
|
71
|
+
const children = current[key];
|
|
72
|
+
if (Array.isArray(children))
|
|
73
|
+
children.forEach((value, position) => child(value, '/' + key + '/' + position));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
index(root, '', rootUri);
|
|
77
|
+
const ajv = new Ajv2020({ strict: false, discriminator: true });
|
|
78
|
+
addFormats.default(ajv);
|
|
79
|
+
ajv.addSchema(root);
|
|
80
|
+
// Resolve/validate on the host. No remote fetch and no runtime schema compiler.
|
|
81
|
+
ajv.getSchema(rootUri);
|
|
82
|
+
function resolveReference(current) {
|
|
83
|
+
if (typeof current === 'boolean' || typeof current.$ref !== 'string')
|
|
84
|
+
return current;
|
|
85
|
+
const location = locations.get(current);
|
|
86
|
+
// Generated projection references are already absolute; original references use lexical scope.
|
|
87
|
+
const reference = location
|
|
88
|
+
? uri.resolve(location.baseUri, current.$ref)
|
|
89
|
+
: current.$ref;
|
|
90
|
+
const target = ajv.getSchema(reference);
|
|
91
|
+
if (!target)
|
|
92
|
+
throw new Error(`Unresolved native schema reference ${reference}`);
|
|
93
|
+
const value = target.schema;
|
|
94
|
+
if (typeof value !== 'boolean' && !isObject(value))
|
|
95
|
+
throw new Error(`Native schema reference ${reference} does not identify a schema`);
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
function declaredType(current, visited = new Set()) {
|
|
99
|
+
if (typeof current === 'boolean' || visited.has(current))
|
|
100
|
+
return undefined;
|
|
101
|
+
if (typeof current.type === 'string')
|
|
102
|
+
return current.type;
|
|
103
|
+
if (Array.isArray(current.type) &&
|
|
104
|
+
current.type.every((type) => typeof type === 'string'))
|
|
105
|
+
return current.type;
|
|
106
|
+
visited.add(current);
|
|
107
|
+
return typeof current.$ref === 'string'
|
|
108
|
+
? declaredType(resolveReference(current), visited)
|
|
109
|
+
: undefined;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
root,
|
|
113
|
+
reference: (current) => {
|
|
114
|
+
if (typeof current === 'boolean')
|
|
115
|
+
return current;
|
|
116
|
+
const location = locations.get(current);
|
|
117
|
+
if (!location)
|
|
118
|
+
throw new Error('Schema projection requires an original resource location');
|
|
119
|
+
const type = declaredType(current);
|
|
120
|
+
return {
|
|
121
|
+
$ref: location.reference,
|
|
122
|
+
...(type === undefined ? {} : { type }),
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
resolve: resolveReference,
|
|
126
|
+
bundle: (projection) => typeof projection === 'boolean'
|
|
127
|
+
? { $defs: { resource: root }, allOf: [projection] }
|
|
128
|
+
: { ...projection, $defs: { resource: root } },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isObject } from '../utils/is-object.js';
|
|
2
|
+
import { schemasAtPointer } from './schema-at-pointer.js';
|
|
3
|
+
import { normalizeOasValueSchema } from '../openapi/common/normalize-oas-value-schema.js';
|
|
4
|
+
export function responseBindingSchemas(operation, pointer) {
|
|
5
|
+
return Object.values(operation.operation.responses ?? {}).flatMap((response) => {
|
|
6
|
+
if (!isObject(response) || !isObject(response.content))
|
|
7
|
+
return [];
|
|
8
|
+
return Object.values(response.content).flatMap((media) => {
|
|
9
|
+
if (!isObject(media))
|
|
10
|
+
return [];
|
|
11
|
+
const schema = media.schema;
|
|
12
|
+
return typeof schema === 'boolean' || isObject(schema)
|
|
13
|
+
? schemasAtPointer(normalizeOasValueSchema(schema, operation.openapiVersion.startsWith('3.0.')
|
|
14
|
+
? 'openapi-3.0'
|
|
15
|
+
: 'draft-2020-12'), pointer)
|
|
16
|
+
: pointer === ''
|
|
17
|
+
? [true]
|
|
18
|
+
: [];
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { BindingSchema, RequestContainerKind } from '../types/api-bindings.js';
|
|
2
|
+
/** Necessary type conditions only; full schema satisfiability is a runtime check. */
|
|
3
|
+
export declare function schemaAllowsContainer(schema: BindingSchema, kind: RequestContainerKind): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isObject } from '../utils/is-object.js';
|
|
2
|
+
/** Necessary type conditions only; full schema satisfiability is a runtime check. */
|
|
3
|
+
export function schemaAllowsContainer(schema, kind) {
|
|
4
|
+
if (typeof schema === 'boolean')
|
|
5
|
+
return schema;
|
|
6
|
+
if (schema.type !== undefined) {
|
|
7
|
+
const types = Array.isArray(schema.type) ? schema.type : [schema.type];
|
|
8
|
+
if (!types.includes(kind))
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
for (const key of ['allOf', 'anyOf', 'oneOf']) {
|
|
12
|
+
if (!Array.isArray(schema[key]))
|
|
13
|
+
continue;
|
|
14
|
+
const branches = schema[key].map((child) => (typeof child === 'boolean' || isObject(child)) &&
|
|
15
|
+
schemaAllowsContainer(child, kind));
|
|
16
|
+
if (key === 'allOf' ? !branches.every(Boolean) : !branches.some(Boolean))
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BindingSchema } from '../types/api-bindings.js';
|
|
2
|
+
import type { SchemaResourceContext } from '../types/schema-resource.js';
|
|
3
|
+
/** Resolve declared object fields, array items and composition alternatives. */
|
|
4
|
+
export declare function schemasAtPointer(schema: BindingSchema, pointer: string, resources?: SchemaResourceContext): BindingSchema[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { pointerTokens } from './json-pointer.js';
|
|
2
|
+
import { isObject } from '../utils/is-object.js';
|
|
3
|
+
import { intersectBindingSchemas, unionBindingSchemas, } from './combine-binding-schemas.js';
|
|
4
|
+
import { schemaAllowsContainer } from './schema-allows-container.js';
|
|
5
|
+
/** Resolve declared object fields, array items and composition alternatives. */
|
|
6
|
+
export function schemasAtPointer(schema, pointer, resources) {
|
|
7
|
+
const active = new Map();
|
|
8
|
+
function visit(current, tokens, inheritedKinds = ['object', 'array']) {
|
|
9
|
+
if (typeof current === 'boolean')
|
|
10
|
+
return current;
|
|
11
|
+
if (!tokens.length)
|
|
12
|
+
return resources ? resources.reference(current) : current;
|
|
13
|
+
if (resources && typeof current.$ref === 'string') {
|
|
14
|
+
const key = JSON.stringify([tokens, inheritedKinds]);
|
|
15
|
+
const pending = active.get(current) ?? new Set();
|
|
16
|
+
if (pending.has(key))
|
|
17
|
+
throw new Error(`Native pointer projection has a non-progressing reference cycle at ${pointer}`);
|
|
18
|
+
pending.add(key);
|
|
19
|
+
active.set(current, pending);
|
|
20
|
+
const siblings = { ...current };
|
|
21
|
+
delete siblings.$ref;
|
|
22
|
+
try {
|
|
23
|
+
return intersectBindingSchemas([
|
|
24
|
+
visit(resources.resolve(current), tokens, inheritedKinds),
|
|
25
|
+
visit(siblings, tokens, inheritedKinds),
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
pending.delete(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const [token, ...rest] = tokens;
|
|
33
|
+
const kinds = inheritedKinds.filter((kind) => schemaAllowsContainer(current, kind));
|
|
34
|
+
const containers = [];
|
|
35
|
+
if (kinds.includes('object')) {
|
|
36
|
+
const children = [];
|
|
37
|
+
if (isObject(current.properties) &&
|
|
38
|
+
Object.hasOwn(current.properties, token)) {
|
|
39
|
+
const child = current.properties[token];
|
|
40
|
+
if (typeof child === 'boolean' || isObject(child))
|
|
41
|
+
children.push(visit(child, rest));
|
|
42
|
+
}
|
|
43
|
+
if (isObject(current.patternProperties))
|
|
44
|
+
for (const [pattern, child] of Object.entries(current.patternProperties))
|
|
45
|
+
if (new RegExp(pattern).test(token) &&
|
|
46
|
+
(typeof child === 'boolean' || isObject(child)))
|
|
47
|
+
children.push(visit(child, rest));
|
|
48
|
+
if (!children.length) {
|
|
49
|
+
// JSON Schema leaves unspecified additionalProperties open.
|
|
50
|
+
const child = current.additionalProperties;
|
|
51
|
+
children.push(child === undefined
|
|
52
|
+
? true
|
|
53
|
+
: typeof child === 'boolean' || isObject(child)
|
|
54
|
+
? visit(child, rest)
|
|
55
|
+
: false);
|
|
56
|
+
}
|
|
57
|
+
containers.push(intersectBindingSchemas(children));
|
|
58
|
+
}
|
|
59
|
+
if (kinds.includes('array') && /^(0|[1-9][0-9]*)$/.test(token)) {
|
|
60
|
+
const index = Number(token);
|
|
61
|
+
const prefix = Array.isArray(current.prefixItems)
|
|
62
|
+
? current.prefixItems
|
|
63
|
+
: [];
|
|
64
|
+
const child = index < prefix.length ? prefix[index] : current.items;
|
|
65
|
+
containers.push(typeof current.maxItems === 'number' && index >= current.maxItems
|
|
66
|
+
? false
|
|
67
|
+
: child === undefined
|
|
68
|
+
? true
|
|
69
|
+
: typeof child === 'boolean' || isObject(child)
|
|
70
|
+
? visit(child, rest)
|
|
71
|
+
: false);
|
|
72
|
+
}
|
|
73
|
+
const constraints = [unionBindingSchemas(containers)];
|
|
74
|
+
for (const key of ['allOf', 'anyOf', 'oneOf']) {
|
|
75
|
+
if (!Array.isArray(current[key]))
|
|
76
|
+
continue;
|
|
77
|
+
const children = current[key].map((child) => typeof child === 'boolean' || isObject(child)
|
|
78
|
+
? visit(child, tokens, kinds)
|
|
79
|
+
: false);
|
|
80
|
+
// Parent oneOf branches can share child values once their discriminators disappear.
|
|
81
|
+
constraints.push(key === 'allOf'
|
|
82
|
+
? intersectBindingSchemas(children)
|
|
83
|
+
: unionBindingSchemas(children));
|
|
84
|
+
}
|
|
85
|
+
return intersectBindingSchemas(constraints);
|
|
86
|
+
}
|
|
87
|
+
const projected = visit(schema, pointerTokens(pointer));
|
|
88
|
+
return projected === false ? [] : [projected];
|
|
89
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { pointerTokens } from './json-pointer.js';
|
|
2
|
+
import { requestBindingSchemas } from './request-binding-schema.js';
|
|
3
|
+
import { responseBindingSchemas } from './response-binding-schema.js';
|
|
4
|
+
import { nativeBindingSchemas } from './native-binding-schema.js';
|
|
5
|
+
import { validateNativeOutputContracts } from './validate-native-output-contracts.js';
|
|
6
|
+
function declaredTypes(schemas) {
|
|
7
|
+
const types = new Set();
|
|
8
|
+
for (const schema of schemas) {
|
|
9
|
+
if (typeof schema === 'boolean' || schema.type === undefined)
|
|
10
|
+
return new Set();
|
|
11
|
+
for (const type of Array.isArray(schema.type) ? schema.type : [schema.type])
|
|
12
|
+
if (typeof type === 'string')
|
|
13
|
+
types.add(type);
|
|
14
|
+
if (schema.nullable === true)
|
|
15
|
+
types.add('null');
|
|
16
|
+
}
|
|
17
|
+
return types;
|
|
18
|
+
}
|
|
19
|
+
export function validateApiBindingAssignments({ calls, materials, nativeOutputs = [], }) {
|
|
20
|
+
const byId = new Map(materials.map((material) => [material.callId, material]));
|
|
21
|
+
if (!materials.length ||
|
|
22
|
+
byId.size !== materials.length ||
|
|
23
|
+
materials.some((item) => !item.callId.trim()))
|
|
24
|
+
throw new Error('binding materials require unique non-empty callIds');
|
|
25
|
+
validateNativeOutputContracts(nativeOutputs);
|
|
26
|
+
const nativeById = new Map(nativeOutputs.map((item) => [item.nodeId, item]));
|
|
27
|
+
for (const output of nativeOutputs)
|
|
28
|
+
if (byId.has(output.nodeId))
|
|
29
|
+
throw new Error(`native output ${output.nodeId} duplicates an API callId`);
|
|
30
|
+
if (calls.length !== materials.length ||
|
|
31
|
+
new Set(calls.map((call) => call.callId)).size !== materials.length)
|
|
32
|
+
throw new Error('binding plan must name every material callId exactly once');
|
|
33
|
+
const dependencies = new Map();
|
|
34
|
+
for (const call of calls) {
|
|
35
|
+
const target = byId.get(call.callId);
|
|
36
|
+
if (!target)
|
|
37
|
+
throw new Error(`bindings: unknown target callId ${call.callId}`);
|
|
38
|
+
const pointers = [];
|
|
39
|
+
dependencies.set(call.callId, []);
|
|
40
|
+
for (const binding of call.bindings) {
|
|
41
|
+
if (binding.kind !== 'node-output')
|
|
42
|
+
throw new Error('bindings.kind must be node-output');
|
|
43
|
+
pointerTokens(binding.targetPointer);
|
|
44
|
+
pointerTokens(binding.sourcePointer);
|
|
45
|
+
const source = byId.get(binding.sourceNodeId);
|
|
46
|
+
const native = nativeById.get(binding.sourceNodeId);
|
|
47
|
+
if (!source && !native)
|
|
48
|
+
throw new Error(`bindings: unknown sourceNodeId ${binding.sourceNodeId}`);
|
|
49
|
+
if (binding.sourceNodeId === call.callId)
|
|
50
|
+
throw new Error(`bindings: self-reference ${call.callId}`);
|
|
51
|
+
if (pointers.some((pointer) => pointer === binding.targetPointer ||
|
|
52
|
+
pointer.startsWith(binding.targetPointer + '/') ||
|
|
53
|
+
binding.targetPointer.startsWith(pointer + '/')))
|
|
54
|
+
throw new Error(`bindings overlap at ${call.callId}${binding.targetPointer}`);
|
|
55
|
+
pointers.push(binding.targetPointer);
|
|
56
|
+
const targets = requestBindingSchemas(target, binding.targetPointer);
|
|
57
|
+
const sources = native
|
|
58
|
+
? nativeBindingSchemas(native, binding.sourcePointer)
|
|
59
|
+
: responseBindingSchemas(source.operation, binding.sourcePointer);
|
|
60
|
+
if (!targets.length)
|
|
61
|
+
throw new Error(`bindings: ${call.callId}${binding.targetPointer} is not declared by the request OAS`);
|
|
62
|
+
if (!sources.length)
|
|
63
|
+
throw new Error(`bindings: ${binding.sourceNodeId}${binding.sourcePointer} is not declared by the ${native ? 'native output contract' : 'response OAS'}`);
|
|
64
|
+
const from = declaredTypes(sources);
|
|
65
|
+
const to = declaredTypes(targets);
|
|
66
|
+
if (from.size &&
|
|
67
|
+
to.size &&
|
|
68
|
+
![...from].some((type) => to.has(type) || (type === 'integer' && to.has('number'))))
|
|
69
|
+
throw new Error(`bindings: incompatible OAS types ${binding.sourceNodeId}${binding.sourcePointer} -> ${call.callId}${binding.targetPointer}`);
|
|
70
|
+
dependencies.get(call.callId).push(binding.sourceNodeId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const pending = new Set(byId.keys());
|
|
74
|
+
while (pending.size) {
|
|
75
|
+
const ready = [...pending].filter((id) => dependencies.get(id).every((source) => !pending.has(source)));
|
|
76
|
+
if (!ready.length)
|
|
77
|
+
throw new Error('binding dependencies have a cycle');
|
|
78
|
+
for (const id of ready)
|
|
79
|
+
pending.delete(id);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { requestBindingSchemas } from './request-binding-schema.js';
|
|
2
|
+
export function validateApiBindingGaps({ plan, materials, }) {
|
|
3
|
+
for (const gap of plan.gaps) {
|
|
4
|
+
const material = materials.find((item) => item.callId === gap.callId);
|
|
5
|
+
if (!material || !gap.description.trim())
|
|
6
|
+
throw new Error('binding gap requires a declared callId and description');
|
|
7
|
+
if (!requestBindingSchemas(material, gap.targetPointer).length)
|
|
8
|
+
throw new Error(`binding gap ${gap.callId}${gap.targetPointer} is not declared by the request OAS`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ValidateApiBindingPlanInput } from '../types/api-bindings.js';
|
|
2
|
+
/** Check identities/contracts without guessing edges or substituting values. */
|
|
3
|
+
export declare function validateApiBindingPlan({ plan, materials, nativeOutputs, }: ValidateApiBindingPlanInput): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { validateApiBindingAssignments } from './validate-api-binding-assignments.js';
|
|
2
|
+
/** Check identities/contracts without guessing edges or substituting values. */
|
|
3
|
+
export function validateApiBindingPlan({ plan, materials, nativeOutputs, }) {
|
|
4
|
+
if (plan.gaps.length)
|
|
5
|
+
throw new Error(`API bindings need review: ${JSON.stringify(plan.gaps)}`);
|
|
6
|
+
validateApiBindingAssignments({
|
|
7
|
+
calls: plan.calls,
|
|
8
|
+
materials,
|
|
9
|
+
nativeOutputs,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isObject } from '../utils/is-object.js';
|
|
2
|
+
/** Validate the declaration boundary; the adapter compiles the JSON Schemas. */
|
|
3
|
+
export function validateNativeOutputContracts(outputs) {
|
|
4
|
+
if (!Array.isArray(outputs))
|
|
5
|
+
throw new Error('nativeOutputs must be an array');
|
|
6
|
+
const ids = new Set();
|
|
7
|
+
for (const output of outputs) {
|
|
8
|
+
if (!output || typeof output.nodeId !== 'string' || !output.nodeId.trim())
|
|
9
|
+
throw new Error('nativeOutputs.nodeId must be a non-empty string');
|
|
10
|
+
if (ids.has(output.nodeId))
|
|
11
|
+
throw new Error('native outputs require unique node IDs');
|
|
12
|
+
ids.add(output.nodeId);
|
|
13
|
+
if (typeof output.schema !== 'boolean' && !isObject(output.schema))
|
|
14
|
+
throw new Error(`nativeOutputs[${output.nodeId}].schema must be a JSON Schema object or boolean`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export * from './openapi/common/check-schema-value.js';
|
|
2
|
+
export * from './openapi/common/operation-metadata.js';
|
|
3
|
+
export * from './openapi/common/operation-reference.js';
|
|
4
|
+
export * from './openapi/common/parse-spec-utils.js';
|
|
5
|
+
export * from './openapi/common/unsupported-operation-error.js';
|
|
6
|
+
export * from './openapi/common/validate-spec.js';
|
|
7
|
+
export * from './openapi/inbound/callback/parse-callback-operations.js';
|
|
8
|
+
export * from './openapi/inbound/inbound-path-item-operations.js';
|
|
9
|
+
export * from './openapi/inbound/list-inbound-operations.js';
|
|
10
|
+
export * from './openapi/inbound/webhook/parse-webhook-operations.js';
|
|
11
|
+
export * from './openapi/request/create-operation-catalog.js';
|
|
12
|
+
export * from './openapi/request/operation-mapping.js';
|
|
13
|
+
export * from './openapi/request/map-http-operation-contract.js';
|
|
14
|
+
export * from './openapi/request/parse-operation-responses.js';
|
|
15
|
+
export * from './openapi/request/parse-request-body.js';
|
|
16
|
+
export * from './openapi/request/parse-request-operations.js';
|
|
17
|
+
export * from './openapi/request/parse-request-parameters.js';
|
|
18
|
+
export * from './openapi/request/parse-security.js';
|
|
19
|
+
export * from './openapi/request/request-operation-reference.js';
|
|
20
|
+
export * from './openapi/request/response-contract.js';
|
|
21
|
+
export * from './openapi/request/scalar-response-schema.js';
|
|
22
|
+
export * from './openapi/request/serialize-form-body.js';
|
|
23
|
+
export * from './openapi/request/serialize-parameter.js';
|
|
24
|
+
export * from './schemas/operation-plan-schema.js';
|
|
25
|
+
export type * from './types/catalog.js';
|
|
26
|
+
export type * from './types/inbound.js';
|
|
27
|
+
export type * from './types/legacy-plan.js';
|
|
28
|
+
export type * from './types/openapi.js';
|
|
29
|
+
export type * from './types/request.js';
|
|
30
|
+
export * from './utils/is-object.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export * from './openapi/common/check-schema-value.js';
|
|
2
|
+
export * from './openapi/common/operation-metadata.js';
|
|
3
|
+
export * from './openapi/common/operation-reference.js';
|
|
4
|
+
export * from './openapi/common/parse-spec-utils.js';
|
|
5
|
+
export * from './openapi/common/unsupported-operation-error.js';
|
|
6
|
+
export * from './openapi/common/validate-spec.js';
|
|
7
|
+
export * from './openapi/inbound/callback/parse-callback-operations.js';
|
|
8
|
+
export * from './openapi/inbound/inbound-path-item-operations.js';
|
|
9
|
+
export * from './openapi/inbound/list-inbound-operations.js';
|
|
10
|
+
export * from './openapi/inbound/webhook/parse-webhook-operations.js';
|
|
11
|
+
export * from './openapi/request/create-operation-catalog.js';
|
|
12
|
+
export * from './openapi/request/operation-mapping.js';
|
|
13
|
+
export * from './openapi/request/map-http-operation-contract.js';
|
|
14
|
+
export * from './openapi/request/parse-operation-responses.js';
|
|
15
|
+
export * from './openapi/request/parse-request-body.js';
|
|
16
|
+
export * from './openapi/request/parse-request-operations.js';
|
|
17
|
+
export * from './openapi/request/parse-request-parameters.js';
|
|
18
|
+
export * from './openapi/request/parse-security.js';
|
|
19
|
+
export * from './openapi/request/request-operation-reference.js';
|
|
20
|
+
export * from './openapi/request/response-contract.js';
|
|
21
|
+
export * from './openapi/request/scalar-response-schema.js';
|
|
22
|
+
export * from './openapi/request/serialize-form-body.js';
|
|
23
|
+
export * from './openapi/request/serialize-parameter.js';
|
|
24
|
+
export * from './schemas/operation-plan-schema.js';
|
|
25
|
+
export * from './utils/is-object.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { validateOpenApi, validateAndResolveOpenApiDocument, } from '../common/validate-spec.js';
|
|
3
|
+
import { operationsFromDocument } from '../request/parse-request-operations.js';
|
|
4
|
+
export async function createApiCatalog(sources) {
|
|
5
|
+
if (!Array.isArray(sources) || sources.length === 0)
|
|
6
|
+
throw new Error('sources must contain at least one OpenAPI document');
|
|
7
|
+
const catalog = { documents: [], operations: [] };
|
|
8
|
+
for (const [index, source] of sources.entries()) {
|
|
9
|
+
if (!source || typeof source.id !== 'string' || !source.id.trim())
|
|
10
|
+
throw new Error(`sources[${index}].id must be non-empty`);
|
|
11
|
+
if (catalog.documents.some((item) => item.id === source.id))
|
|
12
|
+
throw new Error(`sources[${index}].id duplicates ${source.id}`);
|
|
13
|
+
try {
|
|
14
|
+
const spec = validateOpenApi(source.spec);
|
|
15
|
+
const snapshotId = createHash('sha256')
|
|
16
|
+
.update(JSON.stringify(spec))
|
|
17
|
+
.digest('hex');
|
|
18
|
+
const parsed = await validateAndResolveOpenApiDocument(spec);
|
|
19
|
+
catalog.documents.push({ id: source.id, snapshotId, spec });
|
|
20
|
+
catalog.operations.push(...operationsFromDocument(parsed).map((operation) => ({
|
|
21
|
+
...operation,
|
|
22
|
+
key: {
|
|
23
|
+
documentId: source.id,
|
|
24
|
+
snapshotId,
|
|
25
|
+
operationRef: operation.operationRef,
|
|
26
|
+
},
|
|
27
|
+
})));
|
|
28
|
+
}
|
|
29
|
+
catch (cause) {
|
|
30
|
+
throw new Error(`sources[${source.id}].spec is invalid`, { cause });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return catalog;
|
|
34
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { createOasValueValidator } from './create-oas-value-validator.js';
|
|
2
|
+
export function checkOasValue(value, schema, dialect, source) {
|
|
3
|
+
const result = createOasValueValidator(schema, dialect, source).validate(value);
|
|
4
|
+
if (!result.valid)
|
|
5
|
+
throw new Error(`${source} does not match the OAS schema: ${result.errors.map((error) => error.message).join('; ')}`);
|
|
6
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { validate } from '@scalar/json-schema-validator';
|
|
2
|
+
export function checkSchemaValue(value, schema, source) {
|
|
3
|
+
if (schema === true)
|
|
4
|
+
return;
|
|
5
|
+
if (schema === false)
|
|
6
|
+
throw new Error(`${source} does not match the OAS schema`);
|
|
7
|
+
// Wrapping also keeps a literal string such as "null" from being parsed as YAML.
|
|
8
|
+
const result = validate([value], { type: 'array', items: schema });
|
|
9
|
+
if (!result.valid) {
|
|
10
|
+
throw new Error(`${source} does not match the OAS schema: ${result.errors.map((error) => error.message).join('; ')}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SchemaDialect } from '../../types/schema-dialect.js';
|
|
2
|
+
import type { OasValueSchema, OasValueValidator } from '../../types/oas-value-validation.js';
|
|
3
|
+
export declare function createOasValueValidator(input: OasValueSchema, dialect: SchemaDialect, source: string): OasValueValidator;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createValidator } from '@scalar/json-schema-validator';
|
|
3
|
+
import { normalizeOasValueSchema } from './normalize-oas-value-schema.js';
|
|
4
|
+
import { isObject } from '../../utils/is-object.js';
|
|
5
|
+
export function createOasValueValidator(input, dialect, source) {
|
|
6
|
+
if (typeof input !== 'boolean' && !isObject(input))
|
|
7
|
+
throw new Error(`${source} must be an OAS schema object or boolean`);
|
|
8
|
+
if (dialect !== 'openapi-3.0' && dialect !== 'draft-2020-12')
|
|
9
|
+
throw new Error(`${source} has an unsupported OAS schema dialect: ${dialect}`);
|
|
10
|
+
const normalized = normalizeOasValueSchema(input, dialect);
|
|
11
|
+
const assertions = typeof normalized === 'boolean'
|
|
12
|
+
? normalized
|
|
13
|
+
? {}
|
|
14
|
+
: { not: {} }
|
|
15
|
+
: normalized;
|
|
16
|
+
// Each embedded input is a JSON Schema resource: fragment refs stay local to it.
|
|
17
|
+
const schema = {
|
|
18
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
19
|
+
$id: `urn:openapi-flow:input:${createHash('sha256')
|
|
20
|
+
.update(source)
|
|
21
|
+
.update(JSON.stringify(assertions))
|
|
22
|
+
.digest('hex')}`,
|
|
23
|
+
...assertions,
|
|
24
|
+
};
|
|
25
|
+
let validate;
|
|
26
|
+
try {
|
|
27
|
+
validate = createValidator(schema);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`${source} cannot compile its OAS value schema`, {
|
|
31
|
+
cause: error,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
schema,
|
|
36
|
+
// Scalar parses string documents as YAML; encode actual string values first.
|
|
37
|
+
validate: (value) => validate(typeof value === 'string' ? JSON.stringify(value) : value),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OasValueSchema } from '../../types/oas-value-validation.js';
|
|
2
|
+
import type { SchemaDialect } from '../../types/schema-dialect.js';
|
|
3
|
+
/** Convert only OAS 3.0 assertion syntax, not formats, annotations or data. */
|
|
4
|
+
export declare function normalizeOasValueSchema(input: OasValueSchema, dialect: SchemaDialect): OasValueSchema;
|