@octaviaflow/flow-rules 0.8.0 → 0.8.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/dist/index.cjs CHANGED
@@ -72,6 +72,7 @@ __export(exports_src, {
72
72
  collectArrayPaths: () => collectArrayPaths,
73
73
  collectArrayPathsFromSample: () => collectArrayPathsFromSample,
74
74
  configErrors: () => configErrors,
75
+ contractDerivedKeys: () => contractDerivedKeys,
75
76
  contractDrift: () => contractDrift,
76
77
  contractFieldsFor: () => contractFieldsFor,
77
78
  contractFor: () => contractFor,
@@ -4931,6 +4932,10 @@ function contractVocabularyDrift(actionId) {
4931
4932
  const known = new Set([...Object.keys(CONTRACT_TYPE_TO_FIELD_TYPE), "none"]);
4932
4933
  return Object.entries(c.schema).filter(([, f]) => !known.has(f.type)).map(([k, f]) => `${k}:${f.type}`);
4933
4934
  }
4935
+ function contractDerivedKeys(definition) {
4936
+ const own = new Set((definition.inputSchema?.fields ?? []).map((f) => f.key));
4937
+ return new Set(contractFieldsFor(definition).map((f) => f.key).filter((k) => !own.has(k)));
4938
+ }
4934
4939
 
4935
4940
  // src/rules/configSafety.ts
4936
4941
  var MAX_STEP_CONFIG_BYTES = 256 * 1024;
@@ -5041,6 +5046,7 @@ function validateStepConfig(step) {
5041
5046
  if (!definition)
5042
5047
  return issues;
5043
5048
  const declared = new Map(contractFieldsFor(definition).map((f) => [f.key, f]));
5049
+ const derived = contractDerivedKeys(definition);
5044
5050
  const entries = Object.entries(config);
5045
5051
  for (const [key, value] of entries) {
5046
5052
  const field = declared.get(key);
@@ -5056,7 +5062,7 @@ function validateStepConfig(step) {
5056
5062
  }
5057
5063
  if (!typeMatches(field, value)) {
5058
5064
  issues.push({
5059
- severity: "error",
5065
+ severity: derived.has(key) ? "warning" : "error",
5060
5066
  code: "FIELD_WRONG_TYPE",
5061
5067
  stepId,
5062
5068
  field: key,
package/dist/index.d.ts CHANGED
@@ -45,4 +45,4 @@ export { type FlowConnection, type FlowData, type FlowStep, generateConnectionsF
45
45
  export { flattenNestedWorkflow } from "./rules/flattenNestedWorkflow";
46
46
  export { configErrors, MAX_STEP_CONFIG_BYTES, validateStepConfig, validateStepConfigs, type ConfigIssue, type ConfigIssueCode, } from "./rules/configSafety";
47
47
  export { isMappingFunction, MAPPING_FUNCTION_SPECS, MAPPING_FUNCTIONS, mappingTransformFunctionName, USER_FUNCTION_PREFIX, type MappingFunction, type MappingFunctionSpec, } from "./rules/mappingFunctions";
48
- export { CONFIG_CONTRACTS, contractDrift, contractFieldsFor, contractVocabularyDrift, contractFor, declaredKeys, isEditorPrivateKey, type ConfigContract, type ContractField, type ContractFieldType, } from "./rules/configContracts";
48
+ export { CONFIG_CONTRACTS, contractDerivedKeys, contractDrift, contractFieldsFor, contractVocabularyDrift, contractFor, declaredKeys, isEditorPrivateKey, type ConfigContract, type ContractField, type ContractFieldType, } from "./rules/configContracts";
package/dist/index.js CHANGED
@@ -4818,6 +4818,10 @@ function contractVocabularyDrift(actionId) {
4818
4818
  const known = new Set([...Object.keys(CONTRACT_TYPE_TO_FIELD_TYPE), "none"]);
4819
4819
  return Object.entries(c.schema).filter(([, f]) => !known.has(f.type)).map(([k, f]) => `${k}:${f.type}`);
4820
4820
  }
4821
+ function contractDerivedKeys(definition) {
4822
+ const own = new Set((definition.inputSchema?.fields ?? []).map((f) => f.key));
4823
+ return new Set(contractFieldsFor(definition).map((f) => f.key).filter((k) => !own.has(k)));
4824
+ }
4821
4825
 
4822
4826
  // src/rules/configSafety.ts
4823
4827
  var MAX_STEP_CONFIG_BYTES = 256 * 1024;
@@ -4928,6 +4932,7 @@ function validateStepConfig(step) {
4928
4932
  if (!definition)
4929
4933
  return issues;
4930
4934
  const declared = new Map(contractFieldsFor(definition).map((f) => [f.key, f]));
4935
+ const derived = contractDerivedKeys(definition);
4931
4936
  const entries = Object.entries(config);
4932
4937
  for (const [key, value] of entries) {
4933
4938
  const field = declared.get(key);
@@ -4943,7 +4948,7 @@ function validateStepConfig(step) {
4943
4948
  }
4944
4949
  if (!typeMatches(field, value)) {
4945
4950
  issues.push({
4946
- severity: "error",
4951
+ severity: derived.has(key) ? "warning" : "error",
4947
4952
  code: "FIELD_WRONG_TYPE",
4948
4953
  stepId,
4949
4954
  field: key,
@@ -5090,6 +5095,7 @@ export {
5090
5095
  collectArrayPaths,
5091
5096
  collectArrayPathsFromSample,
5092
5097
  configErrors,
5098
+ contractDerivedKeys,
5093
5099
  contractDrift,
5094
5100
  contractFieldsFor,
5095
5101
  contractFor,
@@ -90,3 +90,15 @@ export declare function contractFieldsFor(definition: ActionDefinition): FieldCo
90
90
  export declare function contractDrift(definition: ActionDefinition): string[];
91
91
  /** Contract fields whose `type` is not in the vocabulary — a typo, not a new kind. */
92
92
  export declare function contractVocabularyDrift(actionId: string): string[];
93
+ /**
94
+ * Keys `contractFieldsFor` ADDED — declared by config.ts but not by inputSchema.
95
+ *
96
+ * The fence treats a type mismatch on one of these as a WARNING, not an error,
97
+ * until it has been measured against real flows. The reason is concrete: the
98
+ * moment http_request's contract declared `queryParams: array`, a fixture that
99
+ * stored it as an object stopped saving. On beta 71 of 131 real config keys
100
+ * were undeclared, so any of them may be stored in a shape the contract does
101
+ * not expect — and refusing the save would leave whoever opens that flow
102
+ * unable to save it. inputSchema-declared keys keep their existing error.
103
+ */
104
+ export declare function contractDerivedKeys(definition: ActionDefinition): Set<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octaviaflow/flow-rules",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "The flow action catalog and the rules engine behind Flow Doctor \u2014 one definition of what a step accepts and what makes a flow valid, shared by the editor and the server",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",