@openapi-flow/core 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  Zod `^4.6.5` is a required peer, shared with the host rather than installed as a separately pinned runtime copy. Development tests use 4.6.5; the strict installed-consumer check also uses the host's 4.6.7. This preserves the public schema type boundary without casts or dependency overrides.
4
4
 
5
- Version **0.3.0**. Canonical draft, clarification and runtime-input APIs described below are included in this release. Ajv 8.20.0 does not correctly validate a declared `properties.__proto__`; generated validation may reject valid data or omit that property's constraints. This known limitation was explicitly accepted for release, without renaming data or skipping its failing regression. See the [release record](https://github.com/carefreelife98/openapi-flow/blob/main/docs/releases/0.3.0.md).
5
+ Version **0.3.1**. Canonical draft, clarification and runtime-input APIs described below are included in this release. Ajv 8.20.0 does not correctly validate a declared `properties.__proto__`; generated validation may reject valid data or omit that property's constraints. This previously accepted limitation remains unchanged, without renaming data or skipping its failing regression. See the [release record](https://github.com/carefreelife98/openapi-flow/blob/main/docs/releases/0.3.1.md).
6
+
7
+ Connection planning accepts explicit current `deferredApiInputIds` derived with `collectDeferredApiInputSlots`. Missing inputs remain absent and require canonical template preflight before execution; supplied values and the full DAG are still validated. See [input deferral](https://github.com/carefreelife98/openapi-flow/blob/main/docs/deferred-connection-planning.md).
6
8
 
7
9
  canonical `gapNodes` and the separate `createWorkflowDraftCapabilityGap`,
8
10
  `inspectWorkflowDraftCapabilityGap`, `describeWorkflowDraftCapabilityGap` functions
@@ -184,6 +184,7 @@ export type * from './types/api-bindings.js';
184
184
  export type * from './types/api-binding-planning.js';
185
185
  export type * from './types/native-node-planning.js';
186
186
  export type * from './types/workflow-connection-planning.js';
187
+ export type * from './types/workflow-api-input-readiness.js';
187
188
  export type * from './types/workflow-planning-materials.js';
188
189
  export type * from './types/workflow-graph-planning.js';
189
190
  export { describeWorkflowGraphPlanning } from './workflow/graphs/describe-workflow-graph-planning.js';
@@ -0,0 +1,2 @@
1
+ import { z } from 'zod';
2
+ export declare const workflowDeferredApiInputIdsSchema: z.ZodArray<z.ZodString>;
@@ -0,0 +1,6 @@
1
+ import { z } from 'zod';
2
+ export const workflowDeferredApiInputIdsSchema = z
3
+ .array(z.string().refine((value) => value.trim().length > 0))
4
+ .refine((ids) => new Set(ids).size === ids.length, {
5
+ message: 'deferredApiInputIds must contain distinct current input slot IDs',
6
+ });
@@ -2,6 +2,7 @@ import type { ApiOperationContract } from './api-operation.js';
2
2
  import type { ApiOperationKey } from './api-catalog.js';
3
3
  import type { OutputBinding } from './api-arguments.js';
4
4
  import type { WorkflowConnectionPlanningRecord } from './workflow-connection-planning.js';
5
+ import type { WorkflowApiInputDeferral } from './workflow-api-input-readiness.js';
5
6
  import type { WorkflowApiMaterial, WorkflowCapability, WorkflowGraphPlan, PlannedNativeNode, WorkflowPlanEdge } from './workflow-plan.js';
6
7
  export interface WorkflowReviewGap {
7
8
  id: string;
@@ -44,7 +45,7 @@ export interface ReviewableWorkflowGraphPlan extends WorkflowGraphPlan {
44
45
  /** Optional original connection-only decision and supplied-material evidence. */
45
46
  connectionPlanning?: WorkflowConnectionPlanningRecord;
46
47
  }
47
- export interface ReviewableWorkflowPlanningContext {
48
+ export interface ReviewableWorkflowPlanningContext extends WorkflowApiInputDeferral {
48
49
  materials: ReviewableWorkflowApiMaterial[];
49
50
  capabilities: WorkflowCapability[];
50
51
  }
@@ -0,0 +1,8 @@
1
+ import type { ReviewableWorkflowApiMaterial } from './reviewable-workflow.js';
2
+ export interface WorkflowApiInputDeferral {
3
+ /** Exact current OAS-derived input slot IDs explicitly deferred by the caller. */
4
+ deferredApiInputIds?: string[];
5
+ }
6
+ export interface WorkflowApiInputReadinessInput extends WorkflowApiInputDeferral {
7
+ materials: ReviewableWorkflowApiMaterial[];
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,7 +2,9 @@ import type { ReviewableWorkflowApiMaterial, ReviewableWorkflowGraphPlan, Review
2
2
  import type { PlannedNativeNode, WorkflowCapability, WorkflowPlanEdge, WorkflowPlanNodeContract } from './workflow-plan.js';
3
3
  import type { PreparedNativeNodeMaterial } from './native-node-planning.js';
4
4
  import type { WorkflowPlanningSourceEvidence } from './workflow-planning-materials.js';
5
- export interface WorkflowConnectionMaterialInput {
5
+ import type { WorkflowApiInputDeferral } from './workflow-api-input-readiness.js';
6
+ import type { DeferredApiInputSlot } from './deferred-api-inputs.js';
7
+ export interface WorkflowConnectionMaterialInput extends WorkflowApiInputDeferral {
6
8
  materials?: ReviewableWorkflowApiMaterial[];
7
9
  capabilities?: WorkflowCapability[];
8
10
  nativeNodes?: PlannedNativeNode[];
@@ -12,13 +14,14 @@ export interface WorkflowConnectionMaterialInput {
12
14
  export interface WorkflowConnectionPlanningInput extends WorkflowConnectionMaterialInput {
13
15
  scenario: string;
14
16
  }
15
- export interface WorkflowConnectionMaterials {
17
+ export interface WorkflowConnectionMaterials extends WorkflowApiInputDeferral {
16
18
  materials: ReviewableWorkflowApiMaterial[];
17
19
  capabilities: WorkflowCapability[];
18
20
  nativeNodes: PlannedNativeNode[];
19
21
  gaps: WorkflowReviewGap[];
20
22
  edges: WorkflowPlanEdge[];
21
23
  contracts: WorkflowPlanNodeContract[];
24
+ deferredApiInputs?: DeferredApiInputSlot[];
22
25
  }
23
26
  export interface WorkflowConnectionApiRole {
24
27
  callId: string;
@@ -39,6 +42,8 @@ export interface WorkflowConnectionPlanningContext {
39
42
  gaps: WorkflowReviewGap[];
40
43
  readyCallIds: string[];
41
44
  apiRoles: WorkflowConnectionApiRole[];
45
+ /** Code-derived missing values, never missing API capabilities or generated literals. */
46
+ deferredApiInputs?: DeferredApiInputSlot[];
42
47
  }
43
48
  export interface WorkflowConnectionPlanningSnapshot extends WorkflowConnectionMaterials {
44
49
  scenario: string;
@@ -30,6 +30,7 @@ export function describeWorkflowConnectionPlanning(input) {
30
30
  const materials = captured.materials;
31
31
  const prepared = prepareWorkflowConnectionMaterials({
32
32
  materials,
33
+ deferredApiInputIds: input.deferredApiInputIds,
33
34
  capabilities: captured.capabilities,
34
35
  nativeNodes: captured.preparedNativeNodes,
35
36
  gaps: structuredClone((input.gaps === undefined ? [] : input.gaps).map((gap) => workflowReviewGapSchema.parse(gap))),
@@ -65,6 +66,9 @@ export function describeWorkflowConnectionPlanning(input) {
65
66
  purpose: material.purpose,
66
67
  },
67
68
  ]),
69
+ ...(prepared.deferredApiInputs === undefined
70
+ ? {}
71
+ : { deferredApiInputs: structuredClone(prepared.deferredApiInputs) }),
68
72
  };
69
73
  return {
70
74
  input: { ...prepared, scenario },
@@ -1,7 +1,7 @@
1
1
  import { createReviewableNodeContracts } from '../create-reviewable-node-contracts.js';
2
2
  import { createNativeOutputContracts } from '../create-native-output-contracts.js';
3
3
  import { validateWorkflowEdges } from '../validate-workflow-edges.js';
4
- import { inspectApiArgumentRequirements } from '../../arguments/clarification/inspect-api-argument-requirements.js';
4
+ import { validateWorkflowApiInputReadiness } from '../validate-workflow-api-input-readiness.js';
5
5
  import { validateApiBindingAssignments } from '../../bindings/validate-api-binding-assignments.js';
6
6
  import { validateNativeApiResponseReferences } from '../validate-native-api-response-references.js';
7
7
  import { createNativeParameterGenerationContract } from '../../schemas/create-native-parameter-generation-contract.js';
@@ -57,17 +57,10 @@ export function prepareWorkflowConnectionMaterials(input) {
57
57
  nativeNodes,
58
58
  capabilities,
59
59
  });
60
- for (const material of materials) {
61
- if (material.status !== 'ready')
62
- continue;
63
- const args = material.arguments;
64
- const validation = inspectApiArgumentRequirements({
65
- operation: material.operation,
66
- ...args,
67
- });
68
- if (args.unresolvedInputs.length || validation.status !== 'ready')
69
- throw new Error(`materials[${args.callId}] has unresolved OAS request inputs or scenario-requested inputs`);
70
- }
60
+ const deferredApiInputs = validateWorkflowApiInputReadiness({
61
+ materials,
62
+ deferredApiInputIds: input.deferredApiInputIds,
63
+ });
71
64
  if (materials.length)
72
65
  validateApiBindingAssignments({
73
66
  nativeOutputs,
@@ -104,5 +97,16 @@ export function prepareWorkflowConnectionMaterials(input) {
104
97
  plan,
105
98
  });
106
99
  validateWorkflowEdges({ contracts, edges });
107
- return { materials, capabilities, nativeNodes, gaps, edges, contracts };
100
+ return {
101
+ materials,
102
+ capabilities,
103
+ nativeNodes,
104
+ gaps,
105
+ edges,
106
+ contracts,
107
+ ...(input.deferredApiInputIds === undefined
108
+ ? {}
109
+ : { deferredApiInputIds: [...input.deferredApiInputIds] }),
110
+ ...(deferredApiInputs.length ? { deferredApiInputs } : {}),
111
+ };
108
112
  }
@@ -1,4 +1,4 @@
1
- import { inspectApiArgumentRequirements } from '../arguments/clarification/inspect-api-argument-requirements.js';
1
+ import { validateWorkflowApiInputReadiness } from './validate-workflow-api-input-readiness.js';
2
2
  import { validateApiBindingAssignments } from '../bindings/validate-api-binding-assignments.js';
3
3
  import { validateApiBindingGaps } from '../bindings/validate-api-binding-gaps.js';
4
4
  import { createReviewableNodeContracts } from './create-reviewable-node-contracts.js';
@@ -31,20 +31,8 @@ export function validateReviewableWorkflowGraphPlan(input) {
31
31
  item.gapIds.some((id) => !blocked.get(item.callId)?.includes(id)))
32
32
  throw new Error(`review plan omitted blocked requirement for ${item.callId}`);
33
33
  }
34
- else {
35
- const args = item.arguments;
36
- const result = inspectApiArgumentRequirements({
37
- operation: item.operation,
38
- callId: args.callId,
39
- requestedInputs: args.requestedInputs,
40
- values: args.values,
41
- bindings: args.bindings,
42
- requestMediaType: args.requestMediaType,
43
- });
44
- if (args.unresolvedInputs.length || result.status !== 'ready')
45
- throw new Error(`review ready material ${args.callId} has unresolved request inputs`);
46
- }
47
34
  }
35
+ validateWorkflowApiInputReadiness(input);
48
36
  if (materials.length)
49
37
  validateApiBindingAssignments({
50
38
  nativeOutputs: createNativeOutputContracts({
@@ -0,0 +1,4 @@
1
+ import type { DeferredApiInputSlot } from '../types/deferred-api-inputs.js';
2
+ import type { WorkflowApiInputReadinessInput } from '../types/workflow-api-input-readiness.js';
3
+ /** Missing literals may be planned, but only with explicit, current slot ownership. */
4
+ export declare function validateWorkflowApiInputReadiness(input: WorkflowApiInputReadinessInput): DeferredApiInputSlot[];
@@ -0,0 +1,33 @@
1
+ import { collectDeferredApiInputSlots } from '../inputs/collect-deferred-api-input-slots.js';
2
+ import { workflowDeferredApiInputIdsSchema } from '../schemas/workflow-api-input-deferral-schema.js';
3
+ /** Missing literals may be planned, but only with explicit, current slot ownership. */
4
+ export function validateWorkflowApiInputReadiness(input) {
5
+ const ids = input.deferredApiInputIds === undefined
6
+ ? []
7
+ : workflowDeferredApiInputIdsSchema.parse(input.deferredApiInputIds);
8
+ const ready = input.materials.filter((material) => material.status === 'ready');
9
+ // This validates supplied values against their original OAS before deriving missing slots.
10
+ const slots = collectDeferredApiInputSlots({
11
+ materials: ready.map((material) => ({
12
+ operation: material.operation,
13
+ callId: material.arguments.callId,
14
+ values: material.arguments.values,
15
+ bindings: material.arguments.bindings,
16
+ requestMediaType: material.arguments.requestMediaType,
17
+ requestedInputs: material.arguments.requestedInputs,
18
+ })),
19
+ });
20
+ for (const id of ids)
21
+ if (!slots.some((slot) => slot.id === id))
22
+ throw new Error(`deferredApiInputIds contains unknown or stale slot ${id}`);
23
+ for (const slot of slots)
24
+ if (!ids.includes(slot.id))
25
+ throw new Error(`materials[${slot.callId}] has unresolved OAS request inputs or scenario-requested inputs: ${slot.targetPointer}; explicitly defer current slot ${slot.id} or supply its value`);
26
+ for (const material of ready) {
27
+ const args = material.arguments;
28
+ if (new Set(args.unresolvedInputs).size !== args.unresolvedInputs.length ||
29
+ args.unresolvedInputs.some((pointer) => !slots.some((slot) => slot.callId === args.callId && slot.targetPointer === pointer)))
30
+ throw new Error(`materials[${args.callId}].unresolvedInputs must name current OAS request input slots without duplicates`);
31
+ }
32
+ return slots;
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openapi-flow/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "license": "MIT",
5
5
  "description": "Engine-independent OpenAPI catalogs, operation contracts and typed request schemas",
6
6
  "keywords": [