@octaviaflow/flow-rules 0.10.0 → 0.11.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
@@ -43,32 +43,64 @@ __export(exports_src, {
43
43
  ActionStatus: () => ActionStatus,
44
44
  ActionType: () => ActionType,
45
45
  AggregateFunction: () => AggregateFunction,
46
+ AiAgentConfig: () => AiAgentConfig,
46
47
  CONDITION_OPERATORS: () => CONDITION_OPERATORS,
47
48
  CONFIG_CONTRACTS: () => CONFIG_CONTRACTS,
48
49
  CONNECTOR_EVENT_ENTITIES: () => CONNECTOR_EVENT_ENTITIES,
49
50
  ConditionConfig: () => ConditionConfig,
51
+ ConnectorTriggerConfig: () => ConnectorTriggerConfig,
52
+ CsvActionConfig: () => CsvActionConfig,
50
53
  DATABASE_CONNECTOR_IDS: () => DATABASE_CONNECTOR_IDS,
54
+ DROPBOX_OPERATIONS: () => DROPBOX_OPERATIONS,
51
55
  DebugConfig: () => DebugConfig,
56
+ DropboxActionConfig: () => DropboxActionConfig,
52
57
  EVENT_CAPABLE_CONNECTOR_IDS: () => EVENT_CAPABLE_CONNECTOR_IDS,
53
58
  EdgeType: () => EdgeType,
54
59
  EmailConfig: () => EmailConfig,
60
+ ExcelActionConfig: () => ExcelActionConfig,
61
+ FILE_ACTION_FORMATS: () => FILE_ACTION_FORMATS,
62
+ FILE_ACTION_MODES: () => FILE_ACTION_MODES,
63
+ FILE_ACTION_OUTPUT_FORMATS: () => FILE_ACTION_OUTPUT_FORMATS,
64
+ FILE_ACTION_SOURCES: () => FILE_ACTION_SOURCES,
65
+ FILE_EDIT_DESTINATIONS: () => FILE_EDIT_DESTINATIONS,
66
+ FILE_EDIT_MATCH_OPS: () => FILE_EDIT_MATCH_OPS,
67
+ FILE_EDIT_OPERATIONS: () => FILE_EDIT_OPERATIONS,
68
+ FILE_EDIT_SCHEMA: () => FILE_EDIT_SCHEMA,
69
+ FILE_EDIT_SOURCES: () => FILE_EDIT_SOURCES,
70
+ FILE_FORMAT_OPERATIONS: () => FILE_FORMAT_OPERATIONS,
71
+ FTP_OPERATIONS: () => FTP_OPERATIONS,
55
72
  FieldType: () => FieldType,
73
+ FileActionConfig: () => FileActionConfig,
56
74
  ForEachConfig: () => ForEachConfig,
75
+ FtpActionConfig: () => FtpActionConfig,
76
+ GOOGLE_DRIVE_OPERATIONS: () => GOOGLE_DRIVE_OPERATIONS,
77
+ GoogleDriveActionConfig: () => GoogleDriveActionConfig,
78
+ GroupConfig: () => GroupConfig,
79
+ IDP_EXTRACT_STRATEGIES: () => IDP_EXTRACT_STRATEGIES,
80
+ IdpExtractConfig: () => IdpExtractConfig,
57
81
  JoinType: () => JoinType,
82
+ JsonActionConfig: () => JsonActionConfig,
58
83
  LogicalOperator: () => LogicalOperator,
59
84
  MAPPING_FUNCTIONS: () => MAPPING_FUNCTIONS,
60
85
  MAPPING_FUNCTION_SPECS: () => MAPPING_FUNCTION_SPECS,
61
86
  MAX_STEP_CONFIG_BYTES: () => MAX_STEP_CONFIG_BYTES,
62
87
  ManualTriggerConfig: () => ManualTriggerConfig,
63
88
  NodeStatus: () => NodeStatus,
89
+ ONEDRIVE_OPERATIONS: () => ONEDRIVE_OPERATIONS,
90
+ OneDriveActionConfig: () => OneDriveActionConfig,
91
+ PLATFORM_CONFIG_KEYS: () => PLATFORM_CONFIG_KEYS,
64
92
  QueryMode: () => QueryMode,
65
93
  QueryType: () => QueryType,
94
+ S3ActionConfig: () => S3ActionConfig,
95
+ S3_OPERATIONS: () => S3_OPERATIONS,
66
96
  STORAGE_CONNECTOR_IDS: () => STORAGE_CONNECTOR_IDS,
67
97
  SortDirection: () => SortDirection,
98
+ StorageActionConfig: () => StorageActionConfig,
68
99
  TRANSFORM_OPERATIONS: () => TRANSFORM_OPERATIONS,
69
100
  TransformConfig: () => TransformConfig,
70
101
  USER_FUNCTION_PREFIX: () => USER_FUNCTION_PREFIX,
71
102
  VariablesConfig: () => VariablesConfig,
103
+ XmlActionConfig: () => XmlActionConfig,
72
104
  actionsRegistry: () => actionsRegistry,
73
105
  buildPathOptions: () => buildPathOptions,
74
106
  collectArrayPaths: () => collectArrayPaths,
@@ -81,6 +113,8 @@ __export(exports_src, {
81
113
  contractVocabularyDrift: () => contractVocabularyDrift,
82
114
  declaredKeys: () => declaredKeys,
83
115
  emailDefinition: () => emailDefinition,
116
+ fileEditErrors: () => fileEditErrors,
117
+ fileFormatErrors: () => fileFormatErrors,
84
118
  flattenNestedWorkflow: () => flattenNestedWorkflow,
85
119
  generateConnectionsFromSteps: () => generateConnectionsFromSteps,
86
120
  generateEdgeId: () => generateEdgeId,
@@ -104,6 +138,7 @@ __export(exports_src, {
104
138
  migrateDelayConfig: () => migrateDelayConfig,
105
139
  queryDefinition: () => queryDefinition,
106
140
  storageConfigKeys: () => storageConfigKeys,
141
+ storageOperations: () => storageOperations,
107
142
  summarizeConnectorTriggerEvents: () => summarizeConnectorTriggerEvents,
108
143
  transformConnectionToEdge: () => transformConnectionToEdge,
109
144
  transformFlowToWorkflow: () => transformFlowToWorkflow,
@@ -1710,7 +1745,7 @@ var csvActionDefinition = {
1710
1745
  color: "#198038",
1711
1746
  inputSchema: {
1712
1747
  fields: [
1713
- { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (CSV → Records)", value: "parse" }, { label: "Generate (Records → CSV)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1748
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (CSV → Records)", value: "parse" }, { label: "Generate (Records → CSV)", value: "generate" }, { label: "Edit existing file", value: "edit" }], defaultValue: "parse", validation: { required: true } },
1714
1749
  { key: "content", label: "CSV Content", type: "string" /* String */, description: "Paste CSV content or use FX token from upstream step" },
1715
1750
  { key: "delimiter", label: "Delimiter", type: "select" /* Select */, options: [{ label: "Comma (,)", value: "," }, { label: "Semicolon (;)", value: ";" }, { label: "Tab", value: "\t" }, { label: "Pipe (|)", value: "|" }], defaultValue: "," },
1716
1751
  { key: "headerRow", label: "Header Row", type: "number" /* Number */, description: "Row number containing column headers (default: 1)", defaultValue: 1 },
@@ -1749,7 +1784,7 @@ var jsonActionDefinition = {
1749
1784
  color: "#f1c21b",
1750
1785
  inputSchema: {
1751
1786
  fields: [
1752
- { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (JSON → Records)", value: "parse" }, { label: "Generate (Records → JSON)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1787
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (JSON → Records)", value: "parse" }, { label: "Generate (Records → JSON)", value: "generate" }, { label: "Edit existing file", value: "edit" }], defaultValue: "parse", validation: { required: true } },
1753
1788
  { key: "format", label: "Format", type: "select" /* Select */, options: [{ label: "JSON (array)", value: "json" }, { label: "JSONL (one object per line)", value: "jsonl" }], defaultValue: "json" },
1754
1789
  { key: "content", label: "JSON Content", type: "string" /* String */, description: "Paste JSON content or use FX token from upstream step" },
1755
1790
  { key: "prettyPrint", label: "Pretty Print", type: "boolean" /* Boolean */, description: "Format output with indentation", defaultValue: true },
@@ -1786,7 +1821,7 @@ var xmlActionDefinition = {
1786
1821
  color: "#e65100",
1787
1822
  inputSchema: {
1788
1823
  fields: [
1789
- { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (XML → Records)", value: "parse" }, { label: "Generate (Records → XML)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1824
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (XML → Records)", value: "parse" }, { label: "Generate (Records → XML)", value: "generate" }, { label: "Edit existing file", value: "edit" }], defaultValue: "parse", validation: { required: true } },
1790
1825
  { key: "content", label: "XML Content", type: "string" /* String */, description: "Paste XML or use FX token" },
1791
1826
  { key: "rootElement", label: "Root Element", type: "string" /* String */, description: "Root XML element name (for generate)", defaultValue: "data" },
1792
1827
  { key: "rowElement", label: "Row Element", type: "string" /* String */, description: "Element name per record (for generate)", defaultValue: "row" },
@@ -1823,7 +1858,7 @@ var excelActionDefinition = {
1823
1858
  color: "#217346",
1824
1859
  inputSchema: {
1825
1860
  fields: [
1826
- { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (Excel → Records)", value: "parse" }, { label: "Generate (Records → Excel)", value: "generate" }], defaultValue: "parse", validation: { required: true } },
1861
+ { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "Parse (Excel → Records)", value: "parse" }, { label: "Generate (Records → Excel)", value: "generate" }, { label: "Edit existing file", value: "edit" }], defaultValue: "parse", validation: { required: true } },
1827
1862
  { key: "content", label: "Excel File", type: "string" /* String */, description: "S3 key of uploaded Excel file or FX token from upstream" },
1828
1863
  { key: "sheetName", label: "Sheet Name", type: "string" /* String */, description: "Name of sheet to read (default: first sheet)" },
1829
1864
  { key: "headerRow", label: "Header Row", type: "number" /* Number */, description: "Row number containing headers", defaultValue: 1 },
@@ -1861,6 +1896,7 @@ var s3ActionDefinition = {
1861
1896
  color: "#569A31",
1862
1897
  inputSchema: {
1863
1898
  fields: [
1899
+ { key: "connector", label: "S3 Connection", type: "connection" /* Connection */, description: "Select a connected S3 account", validation: { required: true } },
1864
1900
  { key: "operation", label: "Operation", type: "select" /* Select */, options: [{ label: "List Files", value: "list" }, { label: "Upload File", value: "upload" }, { label: "Download File", value: "download" }, { label: "Delete File", value: "delete" }, { label: "Copy File", value: "copy" }, { label: "Move / Rename", value: "move" }, { label: "Get Signed URL", value: "presign" }], defaultValue: "download", validation: { required: true } },
1865
1901
  { key: "bucket", label: "Bucket Name", type: "string" /* String */, description: "S3 bucket name (defaults to the connector’s bucket)" },
1866
1902
  { key: "key", label: "Object Key (Path)", type: "string" /* String */, description: "S3 object key, e.g. data/reports/monthly.csv" },
@@ -2079,7 +2115,8 @@ var storageActionDefinition = {
2079
2115
  { label: "Get signed URL", value: "presign" },
2080
2116
  { label: "Share", value: "share" },
2081
2117
  { label: "Create folder", value: "create_folder" },
2082
- { label: "Transfer to another connector", value: "transfer" }
2118
+ { label: "Transfer to another connector", value: "transfer" },
2119
+ { label: "Sync folder to another connector", value: "sync" }
2083
2120
  ],
2084
2121
  defaultValue: "download",
2085
2122
  validation: { required: true }
@@ -3980,6 +4017,69 @@ function storageConfigKeys() {
3980
4017
  }
3981
4018
  return [...keys];
3982
4019
  }
4020
+ // src/catalog/ai/ai-agent/config.ts
4021
+ var AiAgentConfig = {
4022
+ defaults: {
4023
+ agentId: ""
4024
+ },
4025
+ schema: {
4026
+ agentId: { type: "string", required: true, description: "Public id of a saved agent (agt_…)" },
4027
+ input: { type: "text", required: false, description: "The prompt; may reference upstream data with {{ods://…}} tokens. Empty uses the first upstream output." },
4028
+ overrides: { type: "object", required: false, description: "Per-step overrides: model, temperature, topP, maxTokens, reasoningEffort, verbosity, batchSize, instructions, instructionsMode, expectedSchema" }
4029
+ },
4030
+ validate: (config) => {
4031
+ const errors = [];
4032
+ if (!config.agentId || typeof config.agentId !== "string")
4033
+ errors.push("Select an agent");
4034
+ if (config.overrides !== undefined && (typeof config.overrides !== "object" || config.overrides === null || Array.isArray(config.overrides))) {
4035
+ errors.push("overrides must be an object");
4036
+ }
4037
+ return { valid: errors.length === 0, errors };
4038
+ },
4039
+ merge: (userConfig) => ({ ...AiAgentConfig.defaults, ...userConfig }),
4040
+ getLabel: (config) => config.agentId ? `Agent ${config.agentId}` : "AI Agent"
4041
+ };
4042
+ // src/catalog/ai/idp-extract/config.ts
4043
+ var IDP_EXTRACT_STRATEGIES = ["vision-direct", "auto"];
4044
+ var IdpExtractConfig = {
4045
+ defaults: {
4046
+ llmConnectorId: "",
4047
+ model: "",
4048
+ strategy: "vision-direct"
4049
+ },
4050
+ schema: {
4051
+ llmConnectorId: { type: "connection", required: true, description: "AI connector instance (its key and model run the extraction)" },
4052
+ model: { type: "string", required: true, description: "Model id offered by the connector" },
4053
+ expectedSchema: { type: "json", required: false, description: "JSON Schema of the fields to extract; empty extracts every field" },
4054
+ systemPromptOverride: { type: "text", required: false },
4055
+ strategy: { type: "select", required: false, options: IDP_EXTRACT_STRATEGIES }
4056
+ },
4057
+ validate: (config) => {
4058
+ const errors = [];
4059
+ if (!config.llmConnectorId)
4060
+ errors.push("Select an AI connection");
4061
+ if (!config.model)
4062
+ errors.push("Select a model");
4063
+ if (typeof config.expectedSchema === "string" && config.expectedSchema.trim() !== "") {
4064
+ try {
4065
+ JSON.parse(config.expectedSchema);
4066
+ } catch {
4067
+ errors.push("expectedSchema is not valid JSON");
4068
+ }
4069
+ }
4070
+ return { valid: errors.length === 0, errors };
4071
+ },
4072
+ merge: (userConfig) => ({ ...IdpExtractConfig.defaults, ...userConfig }),
4073
+ getLabel: (config) => config.model ? `IDP: ${config.model}` : "IDP Extract"
4074
+ };
4075
+ // src/catalog/logic/group/config.ts
4076
+ var GroupConfig = {
4077
+ defaults: {},
4078
+ schema: {},
4079
+ validate: (_config) => ({ valid: true, errors: [] }),
4080
+ merge: (_userConfig) => ({}),
4081
+ getLabel: () => "Group"
4082
+ };
3983
4083
  // src/catalog/triggers/connector-trigger/events.ts
3984
4084
  var EVENT_CAPABLE_CONNECTOR_IDS = new Set([
3985
4085
  "quickbooks_online",
@@ -4098,6 +4198,491 @@ function validateConnectorTriggerEvents(connectorId, events) {
4098
4198
  }
4099
4199
  return null;
4100
4200
  }
4201
+
4202
+ // src/catalog/triggers/connector-trigger/config.ts
4203
+ var ConnectorTriggerConfig = {
4204
+ defaults: {
4205
+ connectorInstanceId: ""
4206
+ },
4207
+ schema: {
4208
+ connectorInstanceId: { type: "connection", required: true, description: "The connected app instance that emits the events" },
4209
+ events: { type: "array", required: true, description: "[{ entity, operations }] — exact names from the connector vocabulary; registers the trigger" },
4210
+ connectorId: { type: "string", required: false, description: "Connector type of the instance (hubspot, google_sheets, …)" },
4211
+ connectorName: { type: "string", required: false, description: "Display name of the instance" },
4212
+ subscribed: { type: "boolean", required: false, description: "Registration snapshot" },
4213
+ eventCount: { type: "number", required: false, description: "Registration snapshot" },
4214
+ summary: { type: "string", required: false, description: "Registration snapshot shown on the canvas" },
4215
+ sheetFileId: { type: "string", required: false, description: "Google Sheets: spreadsheet id" },
4216
+ sheetFileLabel: { type: "string", required: false, description: "Google Sheets: spreadsheet name" },
4217
+ sheetName: { type: "string", required: false, description: "Google Sheets: tab name" },
4218
+ sheetKeyColumn: { type: "string", required: false, description: "Google Sheets: row key column" },
4219
+ description: { type: "string", required: false, description: "Added to the trigger output when set" }
4220
+ },
4221
+ validate: (config) => {
4222
+ const errors = [];
4223
+ if (!config.connectorInstanceId)
4224
+ errors.push("Select a connected app");
4225
+ if (config.events !== undefined && !Array.isArray(config.events)) {
4226
+ errors.push("events must be an array of { entity, operations }");
4227
+ } else if (config.connectorId && Array.isArray(config.events) && config.events.length > 0) {
4228
+ const why = validateConnectorTriggerEvents(config.connectorId, config.events);
4229
+ if (why)
4230
+ errors.push(why);
4231
+ }
4232
+ if (config.connectorId === "google_sheets") {
4233
+ if (!config.sheetFileId)
4234
+ errors.push("Select a spreadsheet");
4235
+ if (!config.sheetName)
4236
+ errors.push("Select a sheet");
4237
+ }
4238
+ return { valid: errors.length === 0, errors };
4239
+ },
4240
+ merge: (userConfig) => ({ ...ConnectorTriggerConfig.defaults, ...userConfig }),
4241
+ getLabel: (config) => config.summary || config.connectorName || "Connector Trigger"
4242
+ };
4243
+ // src/catalog/storage/fileEditContract.ts
4244
+ var FILE_FORMAT_OPERATIONS = ["parse", "generate", "edit"];
4245
+ var FILE_EDIT_OPERATIONS = ["append", "update", "upsert", "set_fields"];
4246
+ var FILE_EDIT_MATCH_OPS = ["=", "!=", ">", "<", ">=", "<=", "contains"];
4247
+ var FILE_EDIT_DESTINATIONS = ["new", "in_place"];
4248
+ var FILE_EDIT_SOURCES = ["inline", "s3", "url"];
4249
+ var FILE_EDIT_SCHEMA = {
4250
+ editOperation: { type: "select", required: false, options: FILE_EDIT_OPERATIONS, description: "How the file is edited: append rows, update rows by key, upsert, or set fields on matching rows" },
4251
+ keyField: { type: "string", required: false, description: "Match key column for update / upsert" },
4252
+ mergeUpdate: { type: "boolean", required: false, description: "false replaces the whole matched row; default merges" },
4253
+ matchField: { type: "string", required: false, description: "set_fields: column the row filter reads" },
4254
+ matchOp: { type: "select", required: false, options: FILE_EDIT_MATCH_OPS, description: 'set_fields: comparison; "=" by default' },
4255
+ matchValue: { type: "string", required: false, description: "set_fields: value compared against" },
4256
+ setFields: { type: "object", required: false, description: "set_fields: { column: newValue } applied to matching rows" },
4257
+ destination: { type: "select", required: false, options: FILE_EDIT_DESTINATIONS, description: '"new" writes an edited copy (default); "in_place" overwrites an S3 source' },
4258
+ outputFileName: { type: "string", required: false, description: 'Name of the edited copy when destination is "new"' },
4259
+ source: { type: "select", required: false, options: FILE_EDIT_SOURCES, description: "Where the file to edit comes from; inferred from content when absent" },
4260
+ s3Key: { type: "string", required: false, description: 'source "s3": platform-bucket key of the file to edit' },
4261
+ url: { type: "url", required: false, description: 'source "url": the file to edit is fetched from here' }
4262
+ };
4263
+ function fileEditErrors(config) {
4264
+ const errors = [];
4265
+ if (config.operation !== "edit")
4266
+ return errors;
4267
+ const op = config.editOperation ?? "append";
4268
+ if (!FILE_EDIT_OPERATIONS.includes(op))
4269
+ errors.push(`Unknown edit operation "${op}"`);
4270
+ if ((op === "update" || op === "upsert") && !config.keyField)
4271
+ errors.push(`File edit "${op}" needs a Match key field`);
4272
+ return errors;
4273
+ }
4274
+ function fileFormatErrors(config) {
4275
+ const errors = [];
4276
+ if (config.operation !== undefined && config.operation !== "" && !FILE_FORMAT_OPERATIONS.includes(config.operation)) {
4277
+ errors.push(`Unknown operation "${config.operation}" — use parse, generate or edit`);
4278
+ }
4279
+ return [...errors, ...fileEditErrors(config)];
4280
+ }
4281
+ // src/catalog/storage/csv-action/config.ts
4282
+ var CsvActionConfig = {
4283
+ defaults: {
4284
+ operation: "parse",
4285
+ delimiter: ",",
4286
+ headerRow: 1,
4287
+ includeHeader: true,
4288
+ fileName: "export.csv"
4289
+ },
4290
+ schema: {
4291
+ operation: { type: "select", required: true, options: FILE_FORMAT_OPERATIONS, description: "parse (CSV → records), generate (records → CSV) or edit an existing file" },
4292
+ content: { type: "text", required: false, description: "CSV text, or an FX token from an upstream step" },
4293
+ delimiter: { type: "select", required: false, options: [",", ";", "\t", "|"] },
4294
+ headerRow: { type: "number", required: false, min: 1, description: "1-based row that holds the column headers" },
4295
+ encoding: { type: "string", required: false, description: "Text encoding (utf-8 by default)" },
4296
+ includeHeader: { type: "boolean", required: false, description: "generate: write the header row" },
4297
+ fileName: { type: "string", required: false, description: "generate: name of the produced file" },
4298
+ ...FILE_EDIT_SCHEMA
4299
+ },
4300
+ validate: (config) => {
4301
+ const errors = fileFormatErrors(config);
4302
+ return { valid: errors.length === 0, errors };
4303
+ },
4304
+ merge: (userConfig) => ({ ...CsvActionConfig.defaults, ...userConfig }),
4305
+ getLabel: (config) => `CSV: ${config.operation || "parse"}`
4306
+ };
4307
+ // src/catalog/storage/json-action/config.ts
4308
+ var JsonActionConfig = {
4309
+ defaults: {
4310
+ operation: "parse",
4311
+ format: "json",
4312
+ prettyPrint: true,
4313
+ fileName: "export.json"
4314
+ },
4315
+ schema: {
4316
+ operation: { type: "select", required: true, options: FILE_FORMAT_OPERATIONS, description: "parse (JSON → records), generate (records → JSON) or edit an existing file" },
4317
+ format: { type: "select", required: false, options: ["json", "jsonl"], description: "json (array) or jsonl (one object per line)" },
4318
+ content: { type: "text", required: false, description: "JSON text, or an FX token from an upstream step" },
4319
+ prettyPrint: { type: "boolean", required: false, description: "generate: indent the output" },
4320
+ fileName: { type: "string", required: false, description: "generate: name of the produced file" },
4321
+ jsonl: { type: "boolean", required: false, description: "edit: treat the file as JSONL" },
4322
+ ...FILE_EDIT_SCHEMA
4323
+ },
4324
+ validate: (config) => {
4325
+ const errors = fileFormatErrors(config);
4326
+ const format = config.format;
4327
+ if (format !== undefined && format !== "" && !["json", "jsonl"].includes(format)) {
4328
+ errors.push(`Unknown format "${format}" — use json or jsonl`);
4329
+ }
4330
+ return { valid: errors.length === 0, errors };
4331
+ },
4332
+ merge: (userConfig) => ({ ...JsonActionConfig.defaults, ...userConfig }),
4333
+ getLabel: (config) => `JSON: ${config.operation || "parse"}`
4334
+ };
4335
+ // src/catalog/storage/xml-action/config.ts
4336
+ var XmlActionConfig = {
4337
+ defaults: {
4338
+ operation: "parse",
4339
+ rootElement: "data",
4340
+ rowElement: "row",
4341
+ fileName: "export.xml"
4342
+ },
4343
+ schema: {
4344
+ operation: { type: "select", required: true, options: FILE_FORMAT_OPERATIONS, description: "parse (XML → records), generate (records → XML) or edit an existing file" },
4345
+ content: { type: "text", required: false, description: "XML text, or an FX token from an upstream step" },
4346
+ rootElement: { type: "string", required: false, description: "generate: root element name" },
4347
+ rowElement: { type: "string", required: false, description: "Element that holds one record" },
4348
+ fileName: { type: "string", required: false, description: "generate: name of the produced file" },
4349
+ ...FILE_EDIT_SCHEMA
4350
+ },
4351
+ validate: (config) => {
4352
+ const errors = fileFormatErrors(config);
4353
+ return { valid: errors.length === 0, errors };
4354
+ },
4355
+ merge: (userConfig) => ({ ...XmlActionConfig.defaults, ...userConfig }),
4356
+ getLabel: (config) => `XML: ${config.operation || "parse"}`
4357
+ };
4358
+ // src/catalog/storage/excel-action/config.ts
4359
+ var ExcelActionConfig = {
4360
+ defaults: {
4361
+ operation: "parse",
4362
+ headerRow: 1,
4363
+ fileName: "export.xlsx"
4364
+ },
4365
+ schema: {
4366
+ operation: { type: "select", required: true, options: FILE_FORMAT_OPERATIONS, description: "parse (Excel → records), generate (records → Excel) or edit an existing file" },
4367
+ content: { type: "text", required: false, description: "Platform-bucket key of the workbook, base64 bytes, or an FX token from an upstream step" },
4368
+ sheetName: { type: "string", required: false, description: "Sheet to read; the first sheet when absent" },
4369
+ headerRow: { type: "number", required: false, min: 1, description: "1-based row that holds the column headers" },
4370
+ fileName: { type: "string", required: false, description: "generate: name of the produced file" },
4371
+ ...FILE_EDIT_SCHEMA
4372
+ },
4373
+ validate: (config) => {
4374
+ const errors = fileFormatErrors(config);
4375
+ return { valid: errors.length === 0, errors };
4376
+ },
4377
+ merge: (userConfig) => ({ ...ExcelActionConfig.defaults, ...userConfig }),
4378
+ getLabel: (config) => `Excel: ${config.operation || "parse"}`
4379
+ };
4380
+ // src/catalog/storage/file-action/config.ts
4381
+ var FILE_ACTION_MODES = ["parse", "generate", "convert", "edit"];
4382
+ var FILE_ACTION_SOURCES = ["inline", "s3", "url", "previous_step", "upload"];
4383
+ var FILE_ACTION_FORMATS = ["auto", "csv", "tsv", "json", "jsonl", "xml", "excel"];
4384
+ var FILE_ACTION_OUTPUT_FORMATS = ["csv", "json", "excel", "xml", "tsv"];
4385
+ var FileActionConfig = {
4386
+ defaults: {
4387
+ mode: "parse",
4388
+ source: "inline",
4389
+ format: "auto"
4390
+ },
4391
+ schema: {
4392
+ ...FILE_EDIT_SCHEMA,
4393
+ mode: { type: "select", required: true, options: FILE_ACTION_MODES, description: "parse, generate, convert or edit" },
4394
+ operation: { type: "select", required: false, options: FILE_ACTION_MODES, description: "Alias of mode; read first when both are set" },
4395
+ source: { type: "select", required: false, options: FILE_ACTION_SOURCES, description: "Where the file comes from (inline by default)" },
4396
+ format: { type: "select", required: false, options: FILE_ACTION_FORMATS, description: "File format; auto-detected from the name, then the content" },
4397
+ inlineContent: { type: "text", required: false, description: 'source "inline": the text (base64 for Excel)' },
4398
+ content: { type: "text", required: false, description: "Alias of inlineContent" },
4399
+ outputFormat: { type: "select", required: false, options: FILE_ACTION_OUTPUT_FORMATS, description: "generate / convert: format to write" },
4400
+ outputFileName: { type: "string", required: false, description: "generate / convert: name of the produced file" },
4401
+ fileName: { type: "string", required: false, description: "Name used to detect the format" },
4402
+ encoding: { type: "string", required: false },
4403
+ delimiter: { type: "string", required: false, description: "CSV / TSV delimiter" },
4404
+ headerRow: { type: "number", required: false, min: 1 },
4405
+ rowElement: { type: "string", required: false, description: "XML element that holds one record" },
4406
+ sheetName: { type: "string", required: false, description: "Excel sheet to read" },
4407
+ includeHeader: { type: "boolean", required: false },
4408
+ options: { type: "json", required: false, description: "Parser options read ahead of the top-level keys" }
4409
+ },
4410
+ validate: (config) => {
4411
+ const errors = [];
4412
+ const mode = config.operation || config.mode;
4413
+ if (mode !== undefined && mode !== "" && !FILE_ACTION_MODES.includes(mode)) {
4414
+ errors.push(`Unknown mode "${mode}" — use parse, generate, convert or edit`);
4415
+ }
4416
+ if (config.source === "upload")
4417
+ errors.push('source "upload" is not supported at run time');
4418
+ errors.push(...fileEditErrors({ ...config, operation: mode, source: undefined }));
4419
+ return { valid: errors.length === 0, errors };
4420
+ },
4421
+ merge: (userConfig) => ({ ...FileActionConfig.defaults, ...userConfig }),
4422
+ getLabel: (config) => `File: ${config.operation || config.mode || "parse"}`
4423
+ };
4424
+ // src/catalog/storage/storage-action/config.ts
4425
+ var FIXED_SCHEMA = {
4426
+ connector: { type: "connection", required: true, description: "Storage connector instance; its provider decides the operations" },
4427
+ operation: { type: "select", required: true, description: "Per provider: list, download, upload, delete, copy, move, presign, share, create_folder, transfer, sync" },
4428
+ outputAs: { type: "string", required: false, description: "Name of this step's output in the run's data bag" },
4429
+ content: { type: "text", required: false, description: "upload: the body" },
4430
+ destConnector: { type: "connection", required: false, description: "transfer / sync: destination connector instance" },
4431
+ destPath: { type: "string", required: false, description: "transfer / sync: destination path; also move / copy destination on path-based providers" },
4432
+ sourceIsDirectory: { type: "boolean", required: false, description: "transfer: copy a folder recursively" },
4433
+ cursor: { type: "json", required: false, description: "sync: walk cursor threaded by a cursor ForEach ({{$item.cursor}})" },
4434
+ fileBudget: { type: "number", required: false, min: 1, description: "sync: files per pass" },
4435
+ timeBudgetMs: { type: "number", required: false, min: 1, description: "sync: milliseconds per pass" },
4436
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4437
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" },
4438
+ bucket: { type: "string", required: false, description: "S3 / GCS: overrides the connector's bucket" },
4439
+ container: { type: "string", required: false, description: "Azure: overrides the connector's container" },
4440
+ region: { type: "string", required: false, description: "S3: overrides the connector's region" }
4441
+ };
4442
+ var EXTRA_TYPE = {
4443
+ string: "string",
4444
+ number: "number",
4445
+ select: "select",
4446
+ boolean: "boolean"
4447
+ };
4448
+ function extraField(f) {
4449
+ const field = { type: EXTRA_TYPE[f.type] ?? "string", required: false };
4450
+ if (f.type === "select" && f.options)
4451
+ field.options = f.options.map((o) => o.value);
4452
+ if (f.label)
4453
+ field.description = f.label;
4454
+ return field;
4455
+ }
4456
+ function storageOperations() {
4457
+ const seen = new Set;
4458
+ for (const provider of Object.values(STORAGE_PROVIDERS)) {
4459
+ for (const op of provider.operations)
4460
+ seen.add(op.value);
4461
+ }
4462
+ return [...seen];
4463
+ }
4464
+ function buildSchema() {
4465
+ const schema = { ...FIXED_SCHEMA };
4466
+ schema.operation = { ...schema.operation, options: storageOperations() };
4467
+ const pathKey = (key, label) => {
4468
+ if (!schema[key])
4469
+ schema[key] = { type: "string", required: false, description: label };
4470
+ const name = `${key}Name`;
4471
+ if (!schema[name])
4472
+ schema[name] = { type: "string", required: false, description: `Display name of the item picked for ${key}` };
4473
+ };
4474
+ for (const provider of Object.values(STORAGE_PROVIDERS)) {
4475
+ for (const op of provider.operations) {
4476
+ if (op.path)
4477
+ pathKey(op.path.key, op.path.label);
4478
+ if (op.dest)
4479
+ pathKey(op.dest.key, op.dest.label);
4480
+ for (const f of op.fields ?? []) {
4481
+ if (!schema[f.key])
4482
+ schema[f.key] = extraField(f);
4483
+ }
4484
+ }
4485
+ }
4486
+ return schema;
4487
+ }
4488
+ var StorageActionConfig = {
4489
+ defaults: {
4490
+ connector: "",
4491
+ operation: "download"
4492
+ },
4493
+ schema: buildSchema(),
4494
+ validate: (config) => {
4495
+ const errors = [];
4496
+ if (!config.connector)
4497
+ errors.push("Select a storage connector");
4498
+ if (!config.operation)
4499
+ errors.push("Select an operation");
4500
+ else if (!storageOperations().includes(config.operation))
4501
+ errors.push(`Unknown operation "${config.operation}"`);
4502
+ if (config.operation === "transfer" || config.operation === "sync") {
4503
+ if (!config.destConnector)
4504
+ errors.push("Select a destination connector");
4505
+ if (!config.path)
4506
+ errors.push(config.operation === "transfer" ? "Select a source path" : "Select a source folder");
4507
+ }
4508
+ if (config.fileBudget !== undefined && typeof config.fileBudget !== "number")
4509
+ errors.push("fileBudget must be a number");
4510
+ if (config.timeBudgetMs !== undefined && typeof config.timeBudgetMs !== "number")
4511
+ errors.push("timeBudgetMs must be a number");
4512
+ return { valid: errors.length === 0, errors };
4513
+ },
4514
+ merge: (userConfig) => ({ ...StorageActionConfig.defaults, ...userConfig }),
4515
+ getLabel: (config) => `Storage: ${config.operation || "download"}`
4516
+ };
4517
+ // src/catalog/storage/s3-action/config.ts
4518
+ var S3_OPERATIONS = ["list", "download", "upload", "delete", "copy", "move", "presign"];
4519
+ var S3ActionConfig = {
4520
+ defaults: {
4521
+ connector: "",
4522
+ operation: "download",
4523
+ contentType: "application/octet-stream",
4524
+ expiresIn: 3600,
4525
+ maxKeys: 100
4526
+ },
4527
+ schema: {
4528
+ connector: { type: "connection", required: true, description: "S3 connector instance" },
4529
+ operation: { type: "select", required: true, options: S3_OPERATIONS },
4530
+ bucket: { type: "string", required: false, description: "Overrides the connector's bucket" },
4531
+ region: { type: "string", required: false, description: "Overrides the connector's region" },
4532
+ key: { type: "string", required: false, description: "Object key" },
4533
+ prefix: { type: "string", required: false, description: "list: key prefix" },
4534
+ content: { type: "text", required: false, description: "upload: the body" },
4535
+ contentType: { type: "string", required: false, description: "upload: MIME type" },
4536
+ destBucket: { type: "string", required: false, description: "copy / move: destination bucket" },
4537
+ destKey: { type: "string", required: false, description: "copy / move: destination key" },
4538
+ expiresIn: { type: "number", required: false, min: 1, description: "presign: URL lifetime in seconds" },
4539
+ maxKeys: { type: "number", required: false, min: 1, description: "list: page size" },
4540
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4541
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" }
4542
+ },
4543
+ validate: (config) => {
4544
+ const errors = [];
4545
+ if (!config.connector)
4546
+ errors.push("Select an S3 connection");
4547
+ if (config.operation && !S3_OPERATIONS.includes(config.operation))
4548
+ errors.push(`Unknown operation "${config.operation}"`);
4549
+ return { valid: errors.length === 0, errors };
4550
+ },
4551
+ merge: (userConfig) => ({ ...S3ActionConfig.defaults, ...userConfig }),
4552
+ getLabel: (config) => `S3: ${config.operation || "download"}`
4553
+ };
4554
+ // src/catalog/storage/ftp-action/config.ts
4555
+ var FTP_OPERATIONS = ["download", "upload", "list", "delete", "move"];
4556
+ var FtpActionConfig = {
4557
+ defaults: {
4558
+ connector: "",
4559
+ operation: "download",
4560
+ ifExists: "overwrite"
4561
+ },
4562
+ schema: {
4563
+ connector: { type: "connection", required: true, description: "FTP / SFTP connector instance" },
4564
+ operation: { type: "select", required: true, options: FTP_OPERATIONS },
4565
+ remotePath: { type: "string", required: false, description: "File or folder path on the server" },
4566
+ content: { type: "text", required: false, description: "upload: the body" },
4567
+ fileName: { type: "string", required: false, description: "upload: file name" },
4568
+ destPath: { type: "string", required: false, description: "move: the new path" },
4569
+ ifExists: { type: "select", required: false, options: ["overwrite", "skip"], description: "upload: when the file exists" },
4570
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4571
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" }
4572
+ },
4573
+ validate: (config) => {
4574
+ const errors = [];
4575
+ if (!config.connector)
4576
+ errors.push("Select an FTP/SFTP connection");
4577
+ if (config.operation && !FTP_OPERATIONS.includes(config.operation))
4578
+ errors.push(`Unknown operation "${config.operation}"`);
4579
+ return { valid: errors.length === 0, errors };
4580
+ },
4581
+ merge: (userConfig) => ({ ...FtpActionConfig.defaults, ...userConfig }),
4582
+ getLabel: (config) => `FTP: ${config.operation || "download"}`
4583
+ };
4584
+ // src/catalog/storage/google-drive-action/config.ts
4585
+ var GOOGLE_DRIVE_OPERATIONS = ["upload", "download", "list", "delete", "move", "copy", "share", "create_folder"];
4586
+ var GoogleDriveActionConfig = {
4587
+ defaults: {
4588
+ connector: "",
4589
+ operation: "upload",
4590
+ mimeType: "application/octet-stream",
4591
+ shareRole: "reader",
4592
+ pageSize: 50
4593
+ },
4594
+ schema: {
4595
+ connector: { type: "connection", required: true, description: "Google Drive connector instance" },
4596
+ operation: { type: "select", required: true, options: GOOGLE_DRIVE_OPERATIONS },
4597
+ fileId: { type: "string", required: false, description: "download / delete / move / copy / share: the file" },
4598
+ folderId: { type: "string", required: false, description: "upload / list / create_folder: the folder (root when empty)" },
4599
+ folderName: { type: "string", required: false, description: "upload: folder path resolved or created when folderId is empty" },
4600
+ fileName: { type: "string", required: false, description: "upload / copy / create_folder: the name" },
4601
+ content: { type: "text", required: false, description: "upload: the body" },
4602
+ mimeType: { type: "string", required: false, description: "upload: MIME type" },
4603
+ createFolderIfNotExists: { type: "boolean", required: false, description: "upload: create folderName when missing" },
4604
+ destFolderId: { type: "string", required: false, description: "move / copy: destination folder" },
4605
+ shareEmail: { type: "string", required: false, description: "share: who" },
4606
+ shareRole: { type: "select", required: false, options: ["reader", "writer"], description: "share: permission" },
4607
+ query: { type: "string", required: false, description: "list: Drive search query" },
4608
+ pageSize: { type: "number", required: false, min: 1, description: "list: page size" },
4609
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4610
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" }
4611
+ },
4612
+ validate: (config) => {
4613
+ const errors = [];
4614
+ if (!config.connector)
4615
+ errors.push("Select a Google Drive connection");
4616
+ if (config.operation && !GOOGLE_DRIVE_OPERATIONS.includes(config.operation))
4617
+ errors.push(`Unknown operation "${config.operation}"`);
4618
+ if (config.operation === "share" && !config.shareEmail)
4619
+ errors.push("share: an email address is required");
4620
+ return { valid: errors.length === 0, errors };
4621
+ },
4622
+ merge: (userConfig) => ({ ...GoogleDriveActionConfig.defaults, ...userConfig }),
4623
+ getLabel: (config) => `Drive: ${config.operation || "upload"}`
4624
+ };
4625
+ // src/catalog/storage/dropbox-action/config.ts
4626
+ var DROPBOX_OPERATIONS = ["list", "download", "upload", "delete", "move", "copy"];
4627
+ var DropboxActionConfig = {
4628
+ defaults: {
4629
+ connector: "",
4630
+ operation: "download",
4631
+ mode: "overwrite"
4632
+ },
4633
+ schema: {
4634
+ connector: { type: "connection", required: true, description: "Dropbox connector instance" },
4635
+ operation: { type: "select", required: true, options: DROPBOX_OPERATIONS },
4636
+ path: { type: "string", required: false, description: "File path, or the folder to list" },
4637
+ content: { type: "text", required: false, description: "upload: the body" },
4638
+ fileName: { type: "string", required: false, description: "upload: file name" },
4639
+ destPath: { type: "string", required: false, description: "move / copy: destination path" },
4640
+ mode: { type: "select", required: false, options: ["overwrite", "add"], description: "upload: write mode" },
4641
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4642
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" }
4643
+ },
4644
+ validate: (config) => {
4645
+ const errors = [];
4646
+ if (!config.connector)
4647
+ errors.push("Select a Dropbox connection");
4648
+ if (config.operation && !DROPBOX_OPERATIONS.includes(config.operation))
4649
+ errors.push(`Unknown operation "${config.operation}"`);
4650
+ return { valid: errors.length === 0, errors };
4651
+ },
4652
+ merge: (userConfig) => ({ ...DropboxActionConfig.defaults, ...userConfig }),
4653
+ getLabel: (config) => `Dropbox: ${config.operation || "download"}`
4654
+ };
4655
+ // src/catalog/storage/onedrive-action/config.ts
4656
+ var ONEDRIVE_OPERATIONS = ["download", "upload", "list", "delete", "move", "copy"];
4657
+ var OneDriveActionConfig = {
4658
+ defaults: {
4659
+ connector: "",
4660
+ operation: "download",
4661
+ contentType: "application/octet-stream"
4662
+ },
4663
+ schema: {
4664
+ connector: { type: "connection", required: true, description: "Microsoft / OneDrive connector instance" },
4665
+ operation: { type: "select", required: true, options: ONEDRIVE_OPERATIONS },
4666
+ path: { type: "string", required: false, description: "Path from the drive root" },
4667
+ itemId: { type: "string", required: false, description: "Item id, as an alternative to path" },
4668
+ content: { type: "text", required: false, description: "upload: the body" },
4669
+ fileName: { type: "string", required: false, description: "upload: file name" },
4670
+ destPath: { type: "string", required: false, description: "move / copy: full destination path" },
4671
+ contentType: { type: "string", required: false, description: "upload: MIME type" },
4672
+ fileTypes: { type: "array", required: false, description: "list: keep only these extensions" },
4673
+ filePattern: { type: "string", required: false, description: "list: keep only names matching this glob" }
4674
+ },
4675
+ validate: (config) => {
4676
+ const errors = [];
4677
+ if (!config.connector)
4678
+ errors.push("Select a OneDrive connection");
4679
+ if (config.operation && !ONEDRIVE_OPERATIONS.includes(config.operation))
4680
+ errors.push(`Unknown operation "${config.operation}"`);
4681
+ return { valid: errors.length === 0, errors };
4682
+ },
4683
+ merge: (userConfig) => ({ ...OneDriveActionConfig.defaults, ...userConfig }),
4684
+ getLabel: (config) => `OneDrive: ${config.operation || "download"}`
4685
+ };
4101
4686
  // src/catalog/workflow.ts
4102
4687
  var NodeStatus;
4103
4688
  ((NodeStatus) => {
@@ -4985,7 +5570,22 @@ var CONFIG_CONTRACTS = {
4985
5570
  webhook_trigger: { schema: WebhookTriggerConfig.schema, validate: asValidator(WebhookTriggerConfig.validate) },
4986
5571
  debug: { schema: DebugConfig.schema, validate: asValidator(DebugConfig.validate) },
4987
5572
  error: { schema: ErrorConfig.schema, validate: asValidator(ErrorConfig.validate) },
4988
- variables: { schema: VariablesConfig.schema, validate: asValidator(VariablesConfig.validate) }
5573
+ variables: { schema: VariablesConfig.schema, validate: asValidator(VariablesConfig.validate) },
5574
+ ai_agent: { schema: AiAgentConfig.schema, validate: asValidator(AiAgentConfig.validate) },
5575
+ idp_extract: { schema: IdpExtractConfig.schema, validate: asValidator(IdpExtractConfig.validate) },
5576
+ group: { schema: GroupConfig.schema, validate: asValidator(GroupConfig.validate) },
5577
+ connector_trigger: { schema: ConnectorTriggerConfig.schema, validate: asValidator(ConnectorTriggerConfig.validate) },
5578
+ csv_action: { schema: CsvActionConfig.schema, validate: asValidator(CsvActionConfig.validate) },
5579
+ json_action: { schema: JsonActionConfig.schema, validate: asValidator(JsonActionConfig.validate) },
5580
+ xml_action: { schema: XmlActionConfig.schema, validate: asValidator(XmlActionConfig.validate) },
5581
+ excel_action: { schema: ExcelActionConfig.schema, validate: asValidator(ExcelActionConfig.validate) },
5582
+ file_action: { schema: FileActionConfig.schema, validate: asValidator(FileActionConfig.validate) },
5583
+ storage_action: { schema: StorageActionConfig.schema, validate: asValidator(StorageActionConfig.validate) },
5584
+ s3_action: { schema: S3ActionConfig.schema, validate: asValidator(S3ActionConfig.validate) },
5585
+ ftp_action: { schema: FtpActionConfig.schema, validate: asValidator(FtpActionConfig.validate) },
5586
+ google_drive_action: { schema: GoogleDriveActionConfig.schema, validate: asValidator(GoogleDriveActionConfig.validate) },
5587
+ dropbox_action: { schema: DropboxActionConfig.schema, validate: asValidator(DropboxActionConfig.validate) },
5588
+ onedrive_action: { schema: OneDriveActionConfig.schema, validate: asValidator(OneDriveActionConfig.validate) }
4989
5589
  };
4990
5590
  function contractFor(actionId) {
4991
5591
  return actionId ? CONFIG_CONTRACTS[actionId] : undefined;
@@ -5065,6 +5665,10 @@ function contractDerivedKeys(definition) {
5065
5665
  var MAX_STEP_CONFIG_BYTES = 256 * 1024;
5066
5666
  var FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
5067
5667
  var MAX_DEPTH = 12;
5668
+ var PLATFORM_CONFIG_KEYS = {
5669
+ flowId: { key: "flowId", label: "Flow", type: "string" /* String */, validation: { required: false } },
5670
+ outputAs: { key: "outputAs", label: "Output as", type: "string" /* String */, validation: { required: false } }
5671
+ };
5068
5672
  function typeMatches(field, value) {
5069
5673
  if (value === null || value === undefined || value === "")
5070
5674
  return true;
@@ -5172,8 +5776,10 @@ function validateStepConfig(step) {
5172
5776
  const declared = new Map(contractFieldsFor(definition).map((f) => [f.key, f]));
5173
5777
  const entries = Object.entries(config);
5174
5778
  for (const [key, value] of entries) {
5175
- const field = declared.get(key);
5779
+ const field = declared.get(key) ?? PLATFORM_CONFIG_KEYS[key];
5176
5780
  if (!field) {
5781
+ if (isEditorPrivateKey(key))
5782
+ continue;
5177
5783
  issues.push({
5178
5784
  severity: "warning",
5179
5785
  code: "UNDECLARED_FIELD",