@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.
Files changed (239) hide show
  1. package/README.md +27 -5
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/dist/arguments/list-api-request-media-types.d.ts +2 -0
  4. package/dist/arguments/list-api-request-media-types.js +8 -0
  5. package/dist/arguments/request-contract.d.ts +4 -0
  6. package/dist/arguments/request-contract.js +38 -0
  7. package/dist/arguments/request-media-type-priority.d.ts +2 -0
  8. package/dist/arguments/request-media-type-priority.js +8 -0
  9. package/dist/arguments/select-default-api-request-media-type.d.ts +3 -0
  10. package/dist/arguments/select-default-api-request-media-type.js +17 -0
  11. package/dist/arguments/validate-api-arguments.d.ts +2 -0
  12. package/dist/arguments/validate-api-arguments.js +140 -0
  13. package/dist/bindings/combine-binding-schemas.d.ts +4 -0
  14. package/dist/bindings/combine-binding-schemas.js +17 -0
  15. package/dist/bindings/create-native-array-item-schema.d.ts +4 -0
  16. package/dist/bindings/create-native-array-item-schema.js +16 -0
  17. package/dist/bindings/json-pointer.d.ts +3 -0
  18. package/dist/bindings/json-pointer.js +24 -0
  19. package/dist/bindings/materialize-api-arguments.d.ts +4 -0
  20. package/dist/bindings/materialize-api-arguments.js +54 -0
  21. package/dist/bindings/native-binding-schema.d.ts +3 -0
  22. package/dist/bindings/native-binding-schema.js +6 -0
  23. package/dist/bindings/project-array-item-schema.d.ts +5 -0
  24. package/dist/bindings/project-array-item-schema.js +67 -0
  25. package/dist/bindings/request-binding-schema.d.ts +2 -0
  26. package/dist/bindings/request-binding-schema.js +23 -0
  27. package/dist/bindings/request-container-kind.d.ts +3 -0
  28. package/dist/bindings/request-container-kind.js +17 -0
  29. package/dist/bindings/resources/clone-schema-resource.d.ts +3 -0
  30. package/dist/bindings/resources/clone-schema-resource.js +38 -0
  31. package/dist/bindings/resources/create-schema-resource-context.d.ts +4 -0
  32. package/dist/bindings/resources/create-schema-resource-context.js +130 -0
  33. package/dist/bindings/response-binding-schema.d.ts +3 -0
  34. package/dist/bindings/response-binding-schema.js +21 -0
  35. package/dist/bindings/schema-allows-container.d.ts +3 -0
  36. package/dist/bindings/schema-allows-container.js +20 -0
  37. package/dist/bindings/schema-at-pointer.d.ts +4 -0
  38. package/dist/bindings/schema-at-pointer.js +89 -0
  39. package/dist/bindings/validate-api-binding-assignments.d.ts +2 -0
  40. package/dist/bindings/validate-api-binding-assignments.js +81 -0
  41. package/dist/bindings/validate-api-binding-gaps.d.ts +2 -0
  42. package/dist/bindings/validate-api-binding-gaps.js +10 -0
  43. package/dist/bindings/validate-api-binding-plan.d.ts +3 -0
  44. package/dist/bindings/validate-api-binding-plan.js +11 -0
  45. package/dist/bindings/validate-native-output-contracts.d.ts +3 -0
  46. package/dist/bindings/validate-native-output-contracts.js +16 -0
  47. package/dist/internal-api.d.ts +30 -0
  48. package/dist/internal-api.js +25 -0
  49. package/dist/openapi/catalog/create-api-catalog.d.ts +2 -0
  50. package/dist/openapi/catalog/create-api-catalog.js +34 -0
  51. package/dist/openapi/catalog/list-api-operations.d.ts +2 -0
  52. package/dist/openapi/catalog/list-api-operations.js +3 -0
  53. package/dist/openapi/common/check-oas-value.d.ts +3 -0
  54. package/dist/openapi/common/check-oas-value.js +6 -0
  55. package/dist/openapi/common/check-schema-value.d.ts +2 -0
  56. package/dist/openapi/common/check-schema-value.js +12 -0
  57. package/dist/openapi/common/create-oas-value-validator.d.ts +3 -0
  58. package/dist/openapi/common/create-oas-value-validator.js +39 -0
  59. package/dist/openapi/common/normalize-oas-value-schema.d.ts +4 -0
  60. package/dist/openapi/common/normalize-oas-value-schema.js +50 -0
  61. package/dist/openapi/common/operation-metadata.d.ts +2 -0
  62. package/dist/openapi/common/operation-metadata.js +25 -0
  63. package/dist/openapi/common/operation-reference.d.ts +3 -0
  64. package/dist/openapi/{operation-reference.js → common/operation-reference.js} +1 -4
  65. package/dist/openapi/common/parse-spec-utils.d.ts +3 -0
  66. package/dist/openapi/common/parse-spec-utils.js +12 -0
  67. package/dist/openapi/common/resolve-openapi-security.d.ts +3 -0
  68. package/dist/openapi/common/resolve-openapi-security.js +28 -0
  69. package/dist/openapi/common/unsupported-operation-error.d.ts +4 -0
  70. package/dist/openapi/common/unsupported-operation-error.js +8 -0
  71. package/dist/openapi/common/validate-spec.d.ts +3 -0
  72. package/dist/openapi/{validate-spec.js → common/validate-spec.js} +2 -1
  73. package/dist/openapi/inbound/callback/parse-callback-operations.d.ts +3 -0
  74. package/dist/openapi/inbound/callback/parse-callback-operations.js +31 -0
  75. package/dist/openapi/inbound/inbound-path-item-operations.d.ts +4 -0
  76. package/dist/openapi/inbound/inbound-path-item-operations.js +31 -0
  77. package/dist/openapi/inbound/list-inbound-operations.d.ts +4 -0
  78. package/dist/openapi/inbound/list-inbound-operations.js +13 -0
  79. package/dist/openapi/inbound/webhook/parse-webhook-operations.d.ts +3 -0
  80. package/dist/openapi/inbound/webhook/parse-webhook-operations.js +13 -0
  81. package/dist/openapi/request/create-operation-catalog.d.ts +2 -0
  82. package/dist/openapi/request/create-operation-catalog.js +24 -0
  83. package/dist/openapi/request/encode-form-field.d.ts +2 -0
  84. package/dist/openapi/request/encode-form-field.js +6 -0
  85. package/dist/openapi/request/map-http-operation-contract.d.ts +4 -0
  86. package/dist/openapi/request/map-http-operation-contract.js +21 -0
  87. package/dist/openapi/request/operation-mapping.d.ts +3 -0
  88. package/dist/openapi/request/operation-mapping.js +10 -0
  89. package/dist/openapi/request/parse-operation-responses.d.ts +3 -0
  90. package/dist/openapi/request/parse-operation-responses.js +30 -0
  91. package/dist/openapi/request/parse-request-body.d.ts +3 -0
  92. package/dist/openapi/request/parse-request-body.js +29 -0
  93. package/dist/openapi/request/parse-request-operations.d.ts +7 -0
  94. package/dist/openapi/request/parse-request-operations.js +50 -0
  95. package/dist/openapi/request/parse-request-parameters.d.ts +3 -0
  96. package/dist/openapi/request/parse-request-parameters.js +93 -0
  97. package/dist/openapi/request/parse-security.d.ts +3 -0
  98. package/dist/openapi/request/parse-security.js +31 -0
  99. package/dist/openapi/request/request-operation-reference.d.ts +1 -0
  100. package/dist/openapi/request/request-operation-reference.js +4 -0
  101. package/dist/openapi/request/response-contract.d.ts +6 -0
  102. package/dist/openapi/request/response-contract.js +32 -0
  103. package/dist/openapi/request/scalar-response-schema.d.ts +2 -0
  104. package/dist/openapi/request/scalar-response-schema.js +20 -0
  105. package/dist/openapi/request/serialize-form-body.d.ts +3 -0
  106. package/dist/openapi/request/serialize-form-body.js +89 -0
  107. package/dist/openapi/request/serialize-parameter.d.ts +5 -0
  108. package/dist/openapi/request/serialize-parameter.js +145 -0
  109. package/dist/openapi/resolve-api-operations.d.ts +3 -0
  110. package/dist/openapi/resolve-api-operations.js +84 -0
  111. package/dist/openapi/response/api-response-validation-value.d.ts +3 -0
  112. package/dist/openapi/response/api-response-validation-value.js +21 -0
  113. package/dist/openapi/response/create-api-response-schema.d.ts +4 -0
  114. package/dist/openapi/response/create-api-response-schema.js +114 -0
  115. package/dist/openapi/response/create-response-array-item-schema.d.ts +4 -0
  116. package/dist/openapi/response/create-response-array-item-schema.js +12 -0
  117. package/dist/openapi/response/create-response-value-schema.d.ts +4 -0
  118. package/dist/openapi/response/create-response-value-schema.js +8 -0
  119. package/dist/openapi/response/list-api-response-pointers.d.ts +4 -0
  120. package/dist/openapi/response/list-api-response-pointers.js +30 -0
  121. package/dist/openapi/response/list-declared-schema-pointers.d.ts +4 -0
  122. package/dist/openapi/response/list-declared-schema-pointers.js +91 -0
  123. package/dist/public-api.d.ts +49 -7
  124. package/dist/public-api.js +35 -5
  125. package/dist/runtime-api.d.ts +6 -0
  126. package/dist/runtime-api.js +7 -0
  127. package/dist/schemas/create-api-argument-generation-contract.d.ts +4 -0
  128. package/dist/schemas/create-api-argument-generation-contract.js +72 -0
  129. package/dist/schemas/create-api-arguments-schema.d.ts +3 -0
  130. package/dist/schemas/create-api-arguments-schema.js +4 -0
  131. package/dist/schemas/create-api-request-schema.d.ts +4 -0
  132. package/dist/schemas/create-api-request-schema.js +50 -0
  133. package/dist/schemas/create-oas-value-schema.d.ts +6 -0
  134. package/dist/schemas/create-oas-value-schema.js +25 -0
  135. package/dist/schemas/operation-plan-schema.d.ts +8 -0
  136. package/dist/schemas/operation-plan-schema.js +99 -0
  137. package/dist/schemas/project-literal-array-schema.d.ts +4 -0
  138. package/dist/schemas/project-literal-array-schema.js +55 -0
  139. package/dist/schemas/project-literal-input-schema.d.ts +3 -0
  140. package/dist/schemas/project-literal-input-schema.js +129 -0
  141. package/dist/types/api-argument-generation.d.ts +13 -0
  142. package/dist/types/api-arguments.d.ts +42 -0
  143. package/dist/types/api-arguments.js +1 -0
  144. package/dist/types/api-bindings.d.ts +34 -0
  145. package/dist/types/api-bindings.js +1 -0
  146. package/dist/types/api-catalog.d.ts +34 -0
  147. package/dist/types/api-catalog.js +1 -0
  148. package/dist/types/api-operation.d.ts +26 -0
  149. package/dist/types/api-operation.js +1 -0
  150. package/dist/types/api-response-pointers.d.ts +20 -0
  151. package/dist/types/api-response-pointers.js +1 -0
  152. package/dist/types/api-response.d.ts +14 -0
  153. package/dist/types/api-response.js +1 -0
  154. package/dist/types/array-projection.d.ts +5 -0
  155. package/dist/types/array-projection.js +1 -0
  156. package/dist/types/catalog.d.ts +17 -0
  157. package/dist/types/catalog.js +1 -0
  158. package/dist/types/inbound.d.ts +18 -0
  159. package/dist/types/inbound.js +1 -0
  160. package/dist/types/legacy-plan.d.ts +47 -0
  161. package/dist/types/legacy-plan.js +1 -0
  162. package/dist/types/node-output.d.ts +11 -0
  163. package/dist/types/node-output.js +1 -0
  164. package/dist/types/oas-value-validation.d.ts +8 -0
  165. package/dist/types/oas-value-validation.js +1 -0
  166. package/dist/types/openapi.d.ts +7 -23
  167. package/dist/types/request.d.ts +41 -0
  168. package/dist/types/request.js +1 -0
  169. package/dist/types/reviewable-workflow.d.ts +53 -0
  170. package/dist/types/reviewable-workflow.js +1 -0
  171. package/dist/types/schema-dialect.d.ts +1 -0
  172. package/dist/types/schema-dialect.js +1 -0
  173. package/dist/types/schema-json.d.ts +4 -0
  174. package/dist/types/schema-json.js +1 -0
  175. package/dist/types/schema-resource.d.ts +12 -0
  176. package/dist/types/schema-resource.js +1 -0
  177. package/dist/types/security.d.ts +17 -0
  178. package/dist/types/security.js +1 -0
  179. package/dist/types/workflow-capability-planning.d.ts +10 -0
  180. package/dist/types/workflow-capability-planning.js +1 -0
  181. package/dist/types/workflow-plan.d.ts +104 -0
  182. package/dist/types/workflow-plan.js +1 -0
  183. package/dist/utils/is-object.d.ts +2 -0
  184. package/dist/utils/is-object.js +3 -0
  185. package/dist/utils/json-values-equal.d.ts +2 -0
  186. package/dist/utils/json-values-equal.js +16 -0
  187. package/dist/workflow/assert-api-call-identities.d.ts +1 -0
  188. package/dist/workflow/assert-api-call-identities.js +6 -0
  189. package/dist/workflow/create-native-output-contracts.d.ts +3 -0
  190. package/dist/workflow/create-native-output-contracts.js +23 -0
  191. package/dist/workflow/create-reviewable-node-contracts.d.ts +3 -0
  192. package/dist/workflow/create-reviewable-node-contracts.js +36 -0
  193. package/dist/workflow/create-reviewable-workflow-graph-plan.d.ts +2 -0
  194. package/dist/workflow/create-reviewable-workflow-graph-plan.js +29 -0
  195. package/dist/workflow/create-workflow-graph-plan.d.ts +2 -0
  196. package/dist/workflow/create-workflow-graph-plan.js +17 -0
  197. package/dist/workflow/create-workflow-node-contracts.d.ts +2 -0
  198. package/dist/workflow/create-workflow-node-contracts.js +50 -0
  199. package/dist/workflow/create-workflow-planning-capabilities.d.ts +3 -0
  200. package/dist/workflow/create-workflow-planning-capabilities.js +20 -0
  201. package/dist/workflow/parse-native-node-parameters.d.ts +3 -0
  202. package/dist/workflow/parse-native-node-parameters.js +7 -0
  203. package/dist/workflow/validate-exclusive-output-rejoin.d.ts +3 -0
  204. package/dist/workflow/validate-exclusive-output-rejoin.js +26 -0
  205. package/dist/workflow/validate-native-api-response-references.d.ts +2 -0
  206. package/dist/workflow/validate-native-api-response-references.js +26 -0
  207. package/dist/workflow/validate-reviewable-workflow-graph-plan.d.ts +2 -0
  208. package/dist/workflow/validate-reviewable-workflow-graph-plan.js +98 -0
  209. package/dist/workflow/validate-workflow-edges.d.ts +2 -0
  210. package/dist/workflow/validate-workflow-edges.js +19 -0
  211. package/dist/workflow/validate-workflow-graph-plan.d.ts +3 -0
  212. package/dist/workflow/validate-workflow-graph-plan.js +41 -0
  213. package/dist/workflow/validate-workflow-topology.d.ts +2 -0
  214. package/dist/workflow/validate-workflow-topology.js +105 -0
  215. package/package.json +19 -25
  216. package/dist/openapi/operation-reference.d.ts +0 -3
  217. package/dist/openapi/parse-spec-utils.d.ts +0 -5
  218. package/dist/openapi/parse-spec-utils.js +0 -52
  219. package/dist/openapi/parse-spec.d.ts +0 -5
  220. package/dist/openapi/parse-spec.js +0 -182
  221. package/dist/openapi/validate-spec.d.ts +0 -3
  222. package/dist/planning/generate-workflow.d.ts +0 -2
  223. package/dist/planning/generate-workflow.js +0 -126
  224. package/dist/schemas/planning-schemas.d.ts +0 -62
  225. package/dist/schemas/planning-schemas.js +0 -48
  226. package/dist/types/workflow.d.ts +0 -75
  227. package/dist/utils/validation.d.ts +0 -7
  228. package/dist/utils/validation.js +0 -44
  229. package/dist/utils/workflow-id.d.ts +0 -1
  230. package/dist/utils/workflow-id.js +0 -8
  231. package/dist/workflow/compile-sequence.d.ts +0 -2
  232. package/dist/workflow/compile-sequence.js +0 -167
  233. package/dist/workflow/compile-workflow.d.ts +0 -4
  234. package/dist/workflow/compile-workflow.js +0 -128
  235. package/dist/workflow/sequence-url.d.ts +0 -3
  236. package/dist/workflow/sequence-url.js +0 -81
  237. package/dist/workflow/workflow-helpers.d.ts +0 -6
  238. package/dist/workflow/workflow-helpers.js +0 -81
  239. /package/dist/types/{workflow.js → api-argument-generation.js} +0 -0
package/README.md CHANGED
@@ -1,11 +1,33 @@
1
1
  # @openapi-flow/core
2
2
 
3
- An importable Node.js library for turning a natural-language scenario and an OpenAPI document into a reviewable n8n workflow. It does not provide a server, connect to an n8n instance, or execute workflows.
3
+ Engine-independent OpenAPI catalog, full operation contract lookup, OAS-derived Zod request schemas and argument validation. This is unreleased `0.2.0` source; published `0.1.0` has a different API.
4
4
 
5
- ```sh
6
- npm install @openapi-flow/core @langchain/core @langchain/openai
5
+ `createWorkflowPlanningCapabilities({ capabilities, apiCallIds })` specializes only capabilities that explicitly provide `createPlanningParametersSchema(context)`. Existing runtime schemas and capability objects are not mutated; custom definitions without the hook retain their schema. `validateNativeApiResponseReferences({ nativeNodes, capabilities, apiCallIds })` checks the API identities declared by each implementation's `responseReferences` and per-port `inputReferences`. It does not inspect arbitrary JSON field names, validate native-output identities as API IDs, infer a missing producer or repair a reference. These functions establish early planning boundaries; execution order and response contract validation remain separate.
6
+
7
+ `createApiArgumentGenerationContract({ operation, bindings, requestMediaType })` is the shared literal-generation boundary. It returns the Zod `schema`, its matching `literalInputSchema` JSON Schema, and `hasLiteralInputs`. Bound paths have no original value definition and are forbidden (including through open additional properties); unbound OAS-approved fields stay available. Fully bound closed nested objects have no remaining literal decision. Open objects can still accept additional scenario values, so binding every named property does not close that OAS contract. The original operation and complete runtime request schema remain unchanged.
8
+
9
+ Dynamic OAS assertions are no longer round-tripped through experimental `z.fromJSONSchema`. `createOasValueSchema` uses Zod's public refinement and metadata APIs: Scalar's JSON Schema validator checks the preserved assertions, and Zod exports those same assertions to LangChain. Type-less constraints, enum siblings and simultaneous compositions are not replaced by inferred types or weaker schemas. OAS 3.0 `nullable` and boolean exclusive bounds are explicitly translated to Draft 2020-12 syntax; formats, annotations and enum/example data are retained. Each embedded schema has a resource ID so fragment references keep their original scope. These IDs are schema identifiers, not inferred API input values. `validateApiArguments` and the complete `createApiRequestSchema` use the same dialect conversion; the latter retains required fields for the n8n standalone validator. Uncompileable selected schemas fail with their source before a model call. Provider-specific schema support is still an external boundary, not a reason to trim the OAS contract.
10
+
11
+ See [Zod's JSON Schema and metadata APIs](https://zod.dev/json-schema#metadata) and the [OAS 3.0 Schema Object](https://spec.openapis.org/oas/v3.0.4.html#schema-object) for the conversion boundary and nullable semantics. This does not claim exhaustive support for every schema dialect or provider.
12
+
13
+ ```ts
14
+ import {
15
+ createApiCatalog,
16
+ listApiOperations,
17
+ resolveApiOperations,
18
+ } from '@openapi-flow/core';
7
19
  ```
8
20
 
9
- The host supplies an OpenAPI JSON object, a LangChain chat model, and a trusted API origin. See the [usage and current limitations](https://github.com/carefreelife98/openapi-flow#current-api) before generating workflows. `generateWorkflow` sends operation metadata to the host-supplied model. Review the resulting plan and workflow before importing it into n8n.
21
+ The host supplies `{ id, spec }` documents. Catalog creation requires neither deployment credentials nor a per-path effect policy. The selected full OAS contract remains available before any engine-specific conversion. Operation keys carry document ID, snapshot hash and OAS JSON Pointer; changed documents fail lookup.
22
+
23
+ `createApiArgumentsSchema` preserves OAS request types and excludes bound fields from model proposals. `validateApiArguments` checks literal constraints and returns missing-input pointers. `validateApiBindingPlan` checks response-to-request identities, pointers, known incompatible types and cycles. `materializeApiArguments(values, bindings, responses, material)` copies actual values without coercion or defaults; the OAS material determines missing container kinds. `createApiRequestSchema` supplies the complete final request schema for runtime validation. The `/runtime` entrypoint contains execution-only materialization and serializers without catalog/document intake. Core does not call an LLM, import LangChain/n8n, execute APIs or provide a server. The `/internal` export is an unstable adapter boundary. See the [workspace guide](https://github.com/carefreelife98/openapi-flow#independent-stages).
24
+
25
+ `listApiResponsePointers(operation)` describes finite response-body declarations grouped by the original response key and media type. Each `declaredPointers` entry has an exact RFC 6901 body pointer, its `schemaLocation`, and the type/description actually declared by the schema. Empty pointer means the entire response body. Composition and conditional branch locations stay distinct; enum/example/default data are not traversed as schemas. OAS 3.0 nullable syntax is normalized without changing the operation.
26
+
27
+ `dynamicLocations` identifies dictionaries, pattern keys, homogeneous array items, unexpanded references, recursive schema boundaries and unconstrained values. It never invents a dictionary key or a sample item index. A tuple's explicitly declared positions can be listed, but their runtime existence is not guaranteed. This catalog is advisory, not an exhaustive schema projection, a whitelist, a schema satisfiability proof or a promise that optional/conditional fields exist. The full OAS and existing binding/runtime validators remain authoritative; missing response values still fail without substitution.
28
+
29
+ `WorkflowGraphPlan` describes native capability settings, named-port edges, starts and unmet requirements. `validateWorkflowGraphPlan` uses host-supplied capability contracts to check graph identity/ports/cycles, exclusive-branch join compatibility and API response availability on every incoming route. It does not prove scenario coverage or exhaustively validate response pointer types against every OAS schema dialect; missing fields fail in the runtime compiler. This contract is engine-independent and does not import an n8n node registry.
30
+
31
+ Our code is MIT-licensed. Core has no n8n SDK dependency. Dependency licenses remain separate; see [third-party notices](./THIRD_PARTY_NOTICES.md).
10
32
 
11
- This package's own code is MIT-licensed. Its `@n8n/workflow-sdk` dependency is separately licensed under [n8n's Sustainable Use License](https://docs.n8n.io/n8n-community-license/), which places conditions on use and redistribution. The MIT license for this package does not change those conditions. See [third-party notices](./THIRD_PARTY_NOTICES.md).
33
+ `ReviewableWorkflowApiMaterial` discriminates ready calls with real arguments from blocked calls with OAS identity, declared bindings and causal gap IDs, but no fabricated arguments. `createReviewableWorkflowGraphPlan` adds explicitly identified gaps and blocked calls to the proposed DAG, derives its actual roots, and invokes `validateReviewableWorkflowGraphPlan`. Topology and binding-contract validation are never skipped because of gaps. Blocked/gap nodes have ports but no available API response. `validateApiBindingAssignments` checks assignments independently of execution readiness; `validateApiBindingGaps` requires every reported gap to identify a known call and an OAS-declared request pointer. The strict `validateApiBindingPlan` still rejects all gaps. These contracts do not imply that review workflows may be executed.
@@ -1,5 +1,5 @@
1
1
  # Third-party notices
2
2
 
3
- `@openapi-flow/core` depends on `@n8n/workflow-sdk`, which is licensed separately under n8n's [Sustainable Use License](https://github.com/n8n-io/n8n/blob/master/LICENSE.md). Its terms restrict use and redistribution; check them for your intended use. This package does not bundle the SDK's source code.
3
+ The unreleased `@openapi-flow/core@0.2.0` source depends on Scalar OpenAPI/JSON Schema libraries, Zod, Ajv, ajv-formats and fast-uri. Ajv's public schema registry and fast-uri preserve JSON Schema reference scope during native contract projection. It does not depend on `@n8n/workflow-sdk` or LangChain. This dependency boundary differs from the previously published `0.1.0` package.
4
4
 
5
5
  Other dependencies retain their own licenses. The MIT license in this package applies to openapi-flow's code only.
@@ -0,0 +1,2 @@
1
+ import type { ApiOperationContract } from '../types/api-operation.js';
2
+ export declare function listApiRequestMediaTypes(operation: ApiOperationContract): string[];
@@ -0,0 +1,8 @@
1
+ import { object } from '../openapi/common/parse-spec-utils.js';
2
+ export function listApiRequestMediaTypes(operation) {
3
+ if (operation.operation.requestBody === undefined)
4
+ return [];
5
+ const source = `${operation.key.operationRef}.requestBody`;
6
+ const body = object(operation.operation.requestBody, source);
7
+ return Object.keys(object(body.content, `${source}.content`));
8
+ }
@@ -0,0 +1,4 @@
1
+ import type { ApiOperationContract } from '../types/api-operation.js';
2
+ import type { JsonObject } from '../types/openapi.js';
3
+ export declare function bodyMediaSchema(operation: ApiOperationContract, mediaType?: string): JsonObject | boolean | undefined;
4
+ export declare function parameterSchema(parameter: JsonObject, source: string): JsonObject | boolean;
@@ -0,0 +1,38 @@
1
+ import { object } from '../openapi/common/parse-spec-utils.js';
2
+ export function bodyMediaSchema(operation, mediaType) {
3
+ if (operation.operation.requestBody === undefined) {
4
+ if (mediaType !== undefined)
5
+ throw new Error(`${operation.key.operationRef} has no requestBody for ${mediaType}`);
6
+ return undefined;
7
+ }
8
+ const body = object(operation.operation.requestBody, `${operation.key.operationRef}.requestBody`);
9
+ const content = object(body.content, `${operation.key.operationRef}.requestBody.content`);
10
+ const names = Object.keys(content);
11
+ const selected = mediaType === undefined && names.length === 1 ? names[0] : mediaType;
12
+ if (selected === undefined)
13
+ throw new Error(`${operation.key.operationRef}.requestMediaType must explicitly select one of ${names.join(', ')}`);
14
+ if (!Object.hasOwn(content, selected))
15
+ throw new Error(`${operation.key.operationRef}.requestBody.content has no ${selected}`);
16
+ const media = object(content[selected], `${operation.key.operationRef}.requestBody.content.${selected}`);
17
+ if (media.schema === undefined)
18
+ return true;
19
+ return typeof media.schema === 'boolean'
20
+ ? media.schema
21
+ : object(media.schema, `${selected}.schema`);
22
+ }
23
+ export function parameterSchema(parameter, source) {
24
+ if (parameter.schema !== undefined)
25
+ return typeof parameter.schema === 'boolean'
26
+ ? parameter.schema
27
+ : object(parameter.schema, `${source}.schema`);
28
+ const content = object(parameter.content, `${source}.content`);
29
+ const names = Object.keys(content);
30
+ if (names.length !== 1)
31
+ throw new Error(`${source}.content must have one media type`);
32
+ const media = object(content[names[0]], `${source}.content.${names[0]}`);
33
+ return media.schema === undefined
34
+ ? true
35
+ : typeof media.schema === 'boolean'
36
+ ? media.schema
37
+ : object(media.schema, `${source}.schema`);
38
+ }
@@ -0,0 +1,2 @@
1
+ /** Product preference, not an OpenAPI restriction or transport support check. */
2
+ export declare function requestMediaTypePriority(mediaType: string): number;
@@ -0,0 +1,8 @@
1
+ /** Product preference, not an OpenAPI restriction or transport support check. */
2
+ export function requestMediaTypePriority(mediaType) {
3
+ if (mediaType === 'application/json')
4
+ return 0;
5
+ if (mediaType === 'application/x-www-form-urlencoded')
6
+ return 1;
7
+ return mediaType.includes('*') ? 3 : 2;
8
+ }
@@ -0,0 +1,3 @@
1
+ import type { ApiOperationContract } from '../types/api-operation.js';
2
+ /** Select only an OAS-declared key; never synthesize a request media type. */
3
+ export declare function selectDefaultApiRequestMediaType(operation: ApiOperationContract): string | undefined;
@@ -0,0 +1,17 @@
1
+ import { listApiRequestMediaTypes } from './list-api-request-media-types.js';
2
+ import { requestMediaTypePriority } from './request-media-type-priority.js';
3
+ /** Select only an OAS-declared key; never synthesize a request media type. */
4
+ export function selectDefaultApiRequestMediaType(operation) {
5
+ if (operation.operation.requestBody === undefined)
6
+ return undefined;
7
+ const mediaTypes = listApiRequestMediaTypes(operation);
8
+ const [selected] = mediaTypes.sort((left, right) => {
9
+ const priority = requestMediaTypePriority(left) - requestMediaTypePriority(right);
10
+ if (priority !== 0)
11
+ return priority;
12
+ return left < right ? -1 : left > right ? 1 : 0;
13
+ });
14
+ if (selected === undefined)
15
+ throw new Error(`${operation.key.operationRef}.requestBody.content has no request media type`);
16
+ return selected;
17
+ }
@@ -0,0 +1,2 @@
1
+ import type { ApiArgumentValidation, ValidateApiArgumentsInput } from '../types/api-arguments.js';
2
+ export declare function validateApiArguments({ operation, values, bindings, requestMediaType, }: ValidateApiArgumentsInput): ApiArgumentValidation;
@@ -0,0 +1,140 @@
1
+ import { hasPointer, pointerTokens, pointerValue, } from '../bindings/json-pointer.js';
2
+ import { checkOasValue } from '../openapi/common/check-oas-value.js';
3
+ import { object } from '../openapi/common/parse-spec-utils.js';
4
+ import { optionalRequestProperties } from '../schemas/operation-plan-schema.js';
5
+ import { projectLiteralInputSchema } from '../schemas/project-literal-input-schema.js';
6
+ import { bodyMediaSchema, parameterSchema } from './request-contract.js';
7
+ function requiredPointers(schema, value, pointer, missing, bound) {
8
+ if (bound.includes(pointer) || typeof schema === 'boolean')
9
+ return;
10
+ if (Array.isArray(schema.allOf))
11
+ for (const item of schema.allOf)
12
+ requiredPointers(object(item, `${pointer}.allOf`), value, pointer, missing, bound);
13
+ if (Array.isArray(schema.required))
14
+ for (const name of schema.required) {
15
+ const child = `${pointer}/${String(name).replaceAll('~', '~0').replaceAll('/', '~1')}`;
16
+ if ((value === null ||
17
+ typeof value !== 'object' ||
18
+ !Object.hasOwn(value, String(name))) &&
19
+ !bound.includes(child))
20
+ if (!bound.some((target) => target.startsWith(child + '/')))
21
+ missing.push(child);
22
+ }
23
+ if ((value === undefined ||
24
+ (value !== null && typeof value === 'object' && !Array.isArray(value))) &&
25
+ schema.properties !== undefined) {
26
+ for (const [name, child] of Object.entries(object(schema.properties, `${pointer}.properties`))) {
27
+ const childPointer = `${pointer}/${name.replaceAll('~', '~0').replaceAll('/', '~1')}`;
28
+ const suppliedChild = value !== undefined && Object.hasOwn(value, name);
29
+ if (!suppliedChild &&
30
+ !bound.some((target) => target.startsWith(childPointer + '/')))
31
+ continue;
32
+ requiredPointers(typeof child === 'boolean'
33
+ ? child
34
+ : object(child, `${pointer}.${name}`), suppliedChild ? Reflect.get(value, name) : undefined, childPointer, missing, bound);
35
+ }
36
+ }
37
+ if (Array.isArray(value) &&
38
+ schema.items !== undefined &&
39
+ !Array.isArray(schema.items))
40
+ for (const [index, item] of value.entries()) {
41
+ requiredPointers(typeof schema.items === 'boolean'
42
+ ? schema.items
43
+ : object(schema.items, `${pointer}.items`), item, `${pointer}/${index}`, missing, bound);
44
+ }
45
+ }
46
+ export function validateApiArguments({ operation, values, bindings, requestMediaType, }) {
47
+ if (!Array.isArray(bindings))
48
+ throw new Error('arguments.bindings must be an array');
49
+ const supplied = object(values, 'arguments.values');
50
+ const dialect = operation.openapiVersion.startsWith('3.0.')
51
+ ? 'openapi-3.0'
52
+ : 'draft-2020-12';
53
+ const allowed = new Set(operation.effective.parameters.map((parameter) => parameter.in));
54
+ if (operation.operation.requestBody !== undefined)
55
+ allowed.add('body');
56
+ for (const group of Object.keys(supplied))
57
+ if (!allowed.has(group))
58
+ throw new Error(`arguments.values.${group} is not declared by ${operation.key.operationRef}`);
59
+ const targets = [];
60
+ for (const binding of bindings) {
61
+ if (binding.kind !== 'node-output' ||
62
+ typeof binding.sourceNodeId !== 'string' ||
63
+ !binding.sourceNodeId.trim())
64
+ throw new Error('bindings require kind and non-empty sourceNodeId');
65
+ const tokens = pointerTokens(binding.targetPointer);
66
+ pointerTokens(binding.sourcePointer);
67
+ if (tokens.length === 0)
68
+ throw new Error('bindings.targetPointer must identify a request field');
69
+ if (targets.some((target) => target === binding.targetPointer ||
70
+ target.startsWith(binding.targetPointer + '/') ||
71
+ binding.targetPointer.startsWith(target + '/')))
72
+ throw new Error(`bindings overlap at ${binding.targetPointer}`);
73
+ if (hasPointer(values, binding.targetPointer))
74
+ throw new Error(`arguments supply both a literal and binding at ${binding.targetPointer}`);
75
+ if (tokens[0] !== 'body' &&
76
+ !operation.effective.parameters.some((parameter) => parameter.in === tokens[0] && parameter.name === tokens[1]))
77
+ throw new Error(`binding ${binding.targetPointer} is not declared by ${operation.key.operationRef}`);
78
+ if (tokens[0] === 'body' && operation.operation.requestBody === undefined)
79
+ throw new Error(`${operation.key.operationRef} has no body for ${binding.targetPointer}`);
80
+ targets.push(binding.targetPointer);
81
+ }
82
+ const missing = [];
83
+ for (const raw of operation.effective.parameters) {
84
+ const parameter = object(raw, `${operation.key.operationRef}.parameters`);
85
+ if (parameter.in === 'header' &&
86
+ ['accept', 'content-type', 'authorization'].includes(String(parameter.name).toLowerCase()))
87
+ continue;
88
+ const location = String(parameter.in);
89
+ const name = String(parameter.name);
90
+ const group = supplied[location];
91
+ if (group !== undefined) {
92
+ for (const key of Object.keys(object(group, `arguments.values.${location}`)))
93
+ if (!operation.effective.parameters.some((item) => item.in === location && item.name === key))
94
+ throw new Error(`arguments.values.${location}.${key} is not declared by ${operation.key.operationRef}`);
95
+ }
96
+ const pointer = `/${location}/${name.replaceAll('~', '~0').replaceAll('/', '~1')}`;
97
+ const value = pointerValue(values, pointer);
98
+ const schema = parameterSchema(parameter, pointer);
99
+ if (value === undefined) {
100
+ if (targets.some((target) => target.startsWith(pointer + '/')))
101
+ requiredPointers(schema, undefined, pointer, missing, targets);
102
+ else if (parameter.required === true && !targets.includes(pointer))
103
+ missing.push(pointer);
104
+ continue;
105
+ }
106
+ requiredPointers(schema, value, pointer, missing, targets);
107
+ checkOasValue(value, targets.some((item) => item.startsWith(pointer + '/')) ||
108
+ missing.some((item) => item.startsWith(pointer + '/'))
109
+ ? projectLiteralInputSchema(optionalRequestProperties(schema), bindings
110
+ .filter((entry) => entry.targetPointer.startsWith(pointer + '/'))
111
+ .map((entry) => pointerTokens(entry.targetPointer).slice(2)), pointer).schema
112
+ : schema, dialect, pointer);
113
+ }
114
+ const bodySchema = bodyMediaSchema(operation, requestMediaType);
115
+ if (bodySchema !== undefined) {
116
+ const requestBody = object(operation.operation.requestBody, `${operation.key.operationRef}.requestBody`);
117
+ if (values.body === undefined &&
118
+ requestBody.required === true &&
119
+ !targets.some((pointer) => pointer === '/body' || pointer.startsWith('/body/')))
120
+ missing.push('/body');
121
+ if (values.body !== undefined ||
122
+ targets.some((pointer) => pointer.startsWith('/body/'))) {
123
+ requiredPointers(bodySchema, values.body, '/body', missing, targets);
124
+ }
125
+ if (values.body !== undefined) {
126
+ const incomplete = targets.some((pointer) => pointer.startsWith('/body/')) ||
127
+ missing.some((pointer) => pointer.startsWith('/body/'));
128
+ checkOasValue(values.body, incomplete
129
+ ? projectLiteralInputSchema(optionalRequestProperties(bodySchema), bindings
130
+ .filter((entry) => entry.targetPointer.startsWith('/body/'))
131
+ .map((entry) => pointerTokens(entry.targetPointer).slice(1)), '/body').schema
132
+ : bodySchema, dialect, '/body');
133
+ }
134
+ }
135
+ return {
136
+ valid: missing.length === 0,
137
+ missingInputs: [...new Set(missing)],
138
+ requiresRuntimeValidation: bindings.length > 0,
139
+ };
140
+ }
@@ -0,0 +1,4 @@
1
+ import type { BindingSchema } from '../types/api-bindings.js';
2
+ /** Boolean identities belong to the schema algebra, not to runtime data defaults. */
3
+ export declare function intersectBindingSchemas(schemas: BindingSchema[]): BindingSchema;
4
+ export declare function unionBindingSchemas(schemas: BindingSchema[]): BindingSchema;
@@ -0,0 +1,17 @@
1
+ /** Boolean identities belong to the schema algebra, not to runtime data defaults. */
2
+ export function intersectBindingSchemas(schemas) {
3
+ if (schemas.includes(false))
4
+ return false;
5
+ const assertions = schemas.filter((schema) => schema !== true);
6
+ if (!assertions.length)
7
+ return true;
8
+ return assertions.length === 1 ? assertions[0] : { allOf: assertions };
9
+ }
10
+ export function unionBindingSchemas(schemas) {
11
+ if (schemas.includes(true))
12
+ return true;
13
+ const alternatives = schemas.filter((schema) => schema !== false);
14
+ if (!alternatives.length)
15
+ return false;
16
+ return alternatives.length === 1 ? alternatives[0] : { anyOf: alternatives };
17
+ }
@@ -0,0 +1,4 @@
1
+ import type { BindingSchema } from '../types/api-bindings.js';
2
+ import type { NativeOutputContract } from '../types/node-output.js';
3
+ /** Native JSON roots are not HTTP envelopes or OAS response definitions. */
4
+ export declare function createNativeArrayItemSchema(output: NativeOutputContract, pointer: string): BindingSchema;
@@ -0,0 +1,16 @@
1
+ import { validateNativeOutputContracts } from './validate-native-output-contracts.js';
2
+ import { schemasAtPointer } from './schema-at-pointer.js';
3
+ import { projectArrayItemSchema } from './project-array-item-schema.js';
4
+ import { createSchemaResourceContext } from './resources/create-schema-resource-context.js';
5
+ /** Native JSON roots are not HTTP envelopes or OAS response definitions. */
6
+ export function createNativeArrayItemSchema(output, pointer) {
7
+ validateNativeOutputContracts([output]);
8
+ const resources = createSchemaResourceContext(output.schema);
9
+ const items = schemasAtPointer(resources.root, pointer, resources).flatMap((schema) => {
10
+ const projection = projectArrayItemSchema(schema, resources);
11
+ return projection.allowsArray ? [projection.schema] : [];
12
+ });
13
+ if (!items.length)
14
+ throw new Error(`native output ${output.nodeId}${pointer} has no declared array`);
15
+ return resources.bundle({ anyOf: items });
16
+ }
@@ -0,0 +1,3 @@
1
+ export declare function pointerTokens(pointer: string): string[];
2
+ export declare function pointerValue(value: unknown, pointer: string): unknown;
3
+ export declare function hasPointer(value: unknown, pointer: string): boolean;
@@ -0,0 +1,24 @@
1
+ export function pointerTokens(pointer) {
2
+ if (pointer === '')
3
+ return [];
4
+ if (!pointer.startsWith('/') || /~(?![01])/u.test(pointer))
5
+ throw new Error(`Invalid JSON Pointer: ${pointer}`);
6
+ return pointer
7
+ .slice(1)
8
+ .split('/')
9
+ .map((part) => part.replaceAll('~1', '/').replaceAll('~0', '~'));
10
+ }
11
+ export function pointerValue(value, pointer) {
12
+ let result = value;
13
+ for (const token of pointerTokens(pointer)) {
14
+ if (result === null ||
15
+ typeof result !== 'object' ||
16
+ !Object.hasOwn(result, token))
17
+ return undefined;
18
+ result = Reflect.get(result, token);
19
+ }
20
+ return result;
21
+ }
22
+ export function hasPointer(value, pointer) {
23
+ return pointerValue(value, pointer) !== undefined;
24
+ }
@@ -0,0 +1,4 @@
1
+ import type { ApiArgumentValues, JsonValue, OutputBinding } from '../types/api-arguments.js';
2
+ import type { ApiBindingMaterial } from '../types/api-bindings.js';
3
+ /** Copy response values without coercion, defaults or missing-value recovery. */
4
+ export declare function materializeApiArguments(values: ApiArgumentValues, bindings: OutputBinding[], responses: Record<string, JsonValue>, material: ApiBindingMaterial): ApiArgumentValues;
@@ -0,0 +1,54 @@
1
+ import { pointerTokens, pointerValue } from './json-pointer.js';
2
+ import { requestContainerKind } from './request-container-kind.js';
3
+ /** Copy response values without coercion, defaults or missing-value recovery. */
4
+ export function materializeApiArguments(values, bindings, responses, material) {
5
+ function copy(value) {
6
+ if (Array.isArray(value))
7
+ return value.map(copy);
8
+ if (value === null || typeof value !== 'object')
9
+ return value;
10
+ const result = Object.create(null);
11
+ for (const [key, child] of Object.entries(value))
12
+ result[key] = copy(child);
13
+ return result;
14
+ }
15
+ const result = copy(JSON.parse(JSON.stringify(values)));
16
+ for (const binding of bindings) {
17
+ if (!Object.hasOwn(responses, binding.sourceNodeId))
18
+ throw new Error(`Missing response node ${binding.sourceNodeId}`);
19
+ const value = pointerValue(responses[binding.sourceNodeId], binding.sourcePointer);
20
+ if (value === undefined)
21
+ throw new Error(`Missing response pointer ${binding.sourceNodeId}${binding.sourcePointer}`);
22
+ const tokens = pointerTokens(binding.targetPointer);
23
+ if (!tokens.length)
24
+ throw new Error('binding target must identify a request field');
25
+ let container = result;
26
+ for (const [index, token] of tokens.entries()) {
27
+ if (index === tokens.length - 1) {
28
+ if (Object.hasOwn(container, token))
29
+ throw new Error(`Literal conflicts with binding ${binding.targetPointer}`);
30
+ if (Array.isArray(container) && !/^(0|[1-9][0-9]*)$/.test(token))
31
+ throw new Error(`Binding array index is invalid ${binding.targetPointer}`);
32
+ Reflect.set(container, token, copy(value));
33
+ }
34
+ else {
35
+ if (!Object.hasOwn(container, token)) {
36
+ const pointer = '/' +
37
+ tokens
38
+ .slice(0, index + 1)
39
+ .map((part) => part.replaceAll('~', '~0').replaceAll('/', '~1'))
40
+ .join('/');
41
+ const next = requestContainerKind(material, pointer) === 'array'
42
+ ? []
43
+ : Object.create(null);
44
+ Reflect.set(container, token, next);
45
+ }
46
+ const child = Reflect.get(container, token);
47
+ if (!child || typeof child !== 'object')
48
+ throw new Error(`Binding traverses non-container ${binding.targetPointer}`);
49
+ container = child;
50
+ }
51
+ }
52
+ }
53
+ return JSON.parse(JSON.stringify(result));
54
+ }
@@ -0,0 +1,3 @@
1
+ import type { BindingSchema } from '../types/api-bindings.js';
2
+ import type { NativeOutputContract } from '../types/node-output.js';
3
+ export declare function nativeBindingSchemas(output: NativeOutputContract, pointer: string): BindingSchema[];
@@ -0,0 +1,6 @@
1
+ import { createSchemaResourceContext } from './resources/create-schema-resource-context.js';
2
+ import { schemasAtPointer } from './schema-at-pointer.js';
3
+ export function nativeBindingSchemas(output, pointer) {
4
+ const resources = createSchemaResourceContext(output.schema);
5
+ return schemasAtPointer(resources.root, pointer, resources).map(resources.bundle);
6
+ }
@@ -0,0 +1,5 @@
1
+ import type { BindingSchema } from '../types/api-bindings.js';
2
+ import type { ArrayItemProjection } from '../types/array-projection.js';
3
+ import type { SchemaResourceContext } from '../types/schema-resource.js';
4
+ /** Necessary item candidates; the original container remains the validation authority. */
5
+ export declare function projectArrayItemSchema(schema: BindingSchema, resources?: SchemaResourceContext, active?: Set<BindingSchema>): ArrayItemProjection;
@@ -0,0 +1,67 @@
1
+ import { isObject } from '../utils/is-object.js';
2
+ import { intersectBindingSchemas, unionBindingSchemas, } from './combine-binding-schemas.js';
3
+ /** Necessary item candidates; the original container remains the validation authority. */
4
+ export function projectArrayItemSchema(schema, resources, active = new Set()) {
5
+ if (typeof schema === 'boolean')
6
+ return { allowsArray: schema, schema };
7
+ if (resources && typeof schema.$ref === 'string') {
8
+ if (active.has(schema))
9
+ throw new Error('Native array projection has a non-progressing reference cycle');
10
+ active.add(schema);
11
+ const siblings = { ...schema };
12
+ delete siblings.$ref;
13
+ try {
14
+ const target = projectArrayItemSchema(resources.resolve(schema), resources, active);
15
+ const sibling = projectArrayItemSchema(siblings, resources, active);
16
+ const allowsArray = target.allowsArray && sibling.allowsArray;
17
+ return {
18
+ allowsArray,
19
+ schema: allowsArray
20
+ ? intersectBindingSchemas([target.schema, sibling.schema])
21
+ : false,
22
+ };
23
+ }
24
+ finally {
25
+ active.delete(schema);
26
+ }
27
+ }
28
+ const types = schema.type === undefined
29
+ ? undefined
30
+ : Array.isArray(schema.type)
31
+ ? schema.type
32
+ : [schema.type];
33
+ let allowsArray = !types || types.includes('array');
34
+ const items = [];
35
+ if (Array.isArray(schema.prefixItems))
36
+ for (const child of schema.prefixItems)
37
+ if (typeof child === 'boolean' || isObject(child))
38
+ items.push(resources ? resources.reference(child) : child);
39
+ if (schema.items === undefined)
40
+ items.push(true);
41
+ else if (typeof schema.items === 'boolean' || isObject(schema.items))
42
+ items.push(resources ? resources.reference(schema.items) : schema.items);
43
+ const constraints = [
44
+ schema.maxItems === 0 ? false : unionBindingSchemas(items),
45
+ ];
46
+ for (const key of ['allOf', 'anyOf', 'oneOf']) {
47
+ if (!Array.isArray(schema[key]))
48
+ continue;
49
+ const branches = schema[key].flatMap((child) => typeof child === 'boolean' || isObject(child)
50
+ ? [projectArrayItemSchema(child, resources, active)]
51
+ : []);
52
+ if (key === 'allOf') {
53
+ allowsArray &&= branches.every((branch) => branch.allowsArray);
54
+ constraints.push(intersectBindingSchemas(branches.map((branch) => branch.schema)));
55
+ }
56
+ else {
57
+ allowsArray &&= branches.some((branch) => branch.allowsArray);
58
+ constraints.push(unionBindingSchemas(branches
59
+ .filter((branch) => branch.allowsArray)
60
+ .map((branch) => branch.schema)));
61
+ }
62
+ }
63
+ return {
64
+ allowsArray,
65
+ schema: allowsArray ? intersectBindingSchemas(constraints) : false,
66
+ };
67
+ }
@@ -0,0 +1,2 @@
1
+ import type { ApiBindingMaterial, BindingSchema } from '../types/api-bindings.js';
2
+ export declare function requestBindingSchemas(material: ApiBindingMaterial, pointer: string): BindingSchema[];
@@ -0,0 +1,23 @@
1
+ import { pointerTokens } from './json-pointer.js';
2
+ import { schemasAtPointer } from './schema-at-pointer.js';
3
+ import { bodyMediaSchema, parameterSchema, } from '../arguments/request-contract.js';
4
+ export function requestBindingSchemas(material, pointer) {
5
+ const [location, name, ...children] = pointerTokens(pointer);
6
+ if (location === 'body') {
7
+ const schema = bodyMediaSchema(material.operation, material.requestMediaType);
8
+ return schema === undefined
9
+ ? []
10
+ : schemasAtPointer(schema, pointer.slice(5));
11
+ }
12
+ const parameter = material.operation.effective.parameters.find((item) => item.in === location && item.name === name);
13
+ if (!parameter)
14
+ return [];
15
+ const schema = parameterSchema(parameter, pointer);
16
+ const childPointer = children.length
17
+ ? '/' +
18
+ children
19
+ .map((token) => token.replaceAll('~', '~0').replaceAll('/', '~1'))
20
+ .join('/')
21
+ : '';
22
+ return schemasAtPointer(schema, childPointer);
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { ApiBindingMaterial, RequestContainerKind } from '../types/api-bindings.js';
2
+ /** Container identity comes from the OAS, never from a numeric property name. */
3
+ export declare function requestContainerKind(material: ApiBindingMaterial, pointer: string): RequestContainerKind;
@@ -0,0 +1,17 @@
1
+ import { requestBindingSchemas } from './request-binding-schema.js';
2
+ import { schemaAllowsContainer } from './schema-allows-container.js';
3
+ /** Container identity comes from the OAS, never from a numeric property name. */
4
+ export function requestContainerKind(material, pointer) {
5
+ if (['/path', '/query', '/header', '/cookie'].includes(pointer))
6
+ return 'object';
7
+ const kinds = new Set();
8
+ for (const schema of requestBindingSchemas(material, pointer)) {
9
+ if (schemaAllowsContainer(schema, 'object'))
10
+ kinds.add('object');
11
+ if (schemaAllowsContainer(schema, 'array'))
12
+ kinds.add('array');
13
+ }
14
+ if (kinds.size !== 1)
15
+ throw new Error(`Request ${material.callId}${pointer} needs an explicit literal container: OAS does not determine object versus array`);
16
+ return kinds.has('array') ? 'array' : 'object';
17
+ }
@@ -0,0 +1,3 @@
1
+ import type { BindingSchema } from '../../types/api-bindings.js';
2
+ /** JSON has locations, not shared JavaScript object identity or object cycles. */
3
+ export declare function cloneSchemaResource(schema: BindingSchema): BindingSchema;
@@ -0,0 +1,38 @@
1
+ /** JSON has locations, not shared JavaScript object identity or object cycles. */
2
+ export function cloneSchemaResource(schema) {
3
+ const active = new Set();
4
+ function copy(value, path) {
5
+ if (value === null ||
6
+ typeof value === 'string' ||
7
+ typeof value === 'boolean')
8
+ return value;
9
+ if (typeof value === 'number' && Number.isFinite(value))
10
+ return value;
11
+ if (typeof value !== 'object' || value === null)
12
+ throw new Error(`Native schema${path} must contain JSON values`);
13
+ if (active.has(value))
14
+ throw new Error(`Native schema${path} has a JavaScript object cycle; use a schema reference`);
15
+ if (!Array.isArray(value) &&
16
+ Object.getPrototypeOf(value) !== Object.prototype &&
17
+ Object.getPrototypeOf(value) !== null)
18
+ throw new Error(`Native schema${path} must contain JSON objects`);
19
+ active.add(value);
20
+ try {
21
+ return Array.isArray(value)
22
+ ? Array.from(value, (child, index) => copy(child, `${path}/${index}`))
23
+ : Object.fromEntries(Object.entries(value).map(([key, child]) => [
24
+ key,
25
+ copy(child, `${path}/${key}`),
26
+ ]));
27
+ }
28
+ finally {
29
+ active.delete(value);
30
+ }
31
+ }
32
+ const result = copy(schema, '');
33
+ if (typeof result === 'boolean')
34
+ return result;
35
+ if (result === null || typeof result !== 'object' || Array.isArray(result))
36
+ throw new Error('Native schema resource must be a JSON object or boolean');
37
+ return result;
38
+ }