@octaviaflow/flow-rules 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog/general/transform/config.d.ts +24 -0
- package/dist/index.cjs +29 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +29 -2
- package/package.json +1 -1
|
@@ -67,6 +67,18 @@ export interface TransformUnwind {
|
|
|
67
67
|
/** Keep a row whose list is empty, as one row with no element. Default false. */
|
|
68
68
|
keepEmpty?: boolean;
|
|
69
69
|
}
|
|
70
|
+
/** How rows are written — the Transform panel's "Advanced options" (DEV-267/268). */
|
|
71
|
+
export interface TransformWriteSettings {
|
|
72
|
+
/** Rows per write call. Empty = the connector's own default. */
|
|
73
|
+
batchSize?: number;
|
|
74
|
+
/** `continue` (default): failed rows are reported and the rest are written. `fail`: the step stops at the first failed row. */
|
|
75
|
+
onError?: 'continue' | 'fail';
|
|
76
|
+
/** Map and validate, write nothing. */
|
|
77
|
+
dryRun?: boolean;
|
|
78
|
+
/** Put the failed rows on the step's output. */
|
|
79
|
+
exposeFailedRows?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export declare const TRANSFORM_ON_ERROR: readonly NonNullable<TransformWriteSettings['onError']>[];
|
|
70
82
|
export type TransformMode = 'visual' | 'expression';
|
|
71
83
|
/**
|
|
72
84
|
* The authoring modes. `visual` is the Field Mapper and the only mode the panel
|
|
@@ -111,6 +123,8 @@ export interface TransformConfigType {
|
|
|
111
123
|
groupBy?: TransformGroupBy;
|
|
112
124
|
/** One row per element of a list on each row, before mapping (DEV-484). */
|
|
113
125
|
unwind?: TransformUnwind;
|
|
126
|
+
/** How rows are written (the panel's "Advanced options", DEV-267/268). */
|
|
127
|
+
writeSettings?: TransformWriteSettings;
|
|
114
128
|
/** Ordered column header names — the exact columns + header text written. */
|
|
115
129
|
sheetHeaders?: string[];
|
|
116
130
|
/** Create the target tab on first write if it doesn't exist (default true). */
|
|
@@ -139,6 +153,16 @@ export declare const TransformConfig: {
|
|
|
139
153
|
options: readonly TransformOperation[];
|
|
140
154
|
description: string;
|
|
141
155
|
};
|
|
156
|
+
upsertMatchKey: {
|
|
157
|
+
type: string;
|
|
158
|
+
required: boolean;
|
|
159
|
+
description: string;
|
|
160
|
+
};
|
|
161
|
+
writeSettings: {
|
|
162
|
+
type: string;
|
|
163
|
+
required: boolean;
|
|
164
|
+
description: string;
|
|
165
|
+
};
|
|
142
166
|
connectorId: {
|
|
143
167
|
type: string;
|
|
144
168
|
required: boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -107,6 +107,7 @@ __export(exports_src, {
|
|
|
107
107
|
SortDirection: () => SortDirection,
|
|
108
108
|
StorageActionConfig: () => StorageActionConfig,
|
|
109
109
|
TRANSFORM_MODES: () => TRANSFORM_MODES,
|
|
110
|
+
TRANSFORM_ON_ERROR: () => TRANSFORM_ON_ERROR,
|
|
110
111
|
TRANSFORM_OPERATIONS: () => TRANSFORM_OPERATIONS,
|
|
111
112
|
TransformConfig: () => TransformConfig,
|
|
112
113
|
USER_FUNCTION_PREFIX: () => USER_FUNCTION_PREFIX,
|
|
@@ -3387,6 +3388,7 @@ var WhatsappSendConfig = {
|
|
|
3387
3388
|
};
|
|
3388
3389
|
|
|
3389
3390
|
// src/catalog/general/transform/config.ts
|
|
3391
|
+
var TRANSFORM_ON_ERROR = ["continue", "fail"];
|
|
3390
3392
|
var TRANSFORM_MODES = ["visual", "expression"];
|
|
3391
3393
|
var TRANSFORM_OPERATIONS = [
|
|
3392
3394
|
{ id: "upsert", label: "Upsert" },
|
|
@@ -3411,6 +3413,21 @@ function groupByErrors(config) {
|
|
|
3411
3413
|
}
|
|
3412
3414
|
return errors;
|
|
3413
3415
|
}
|
|
3416
|
+
function writeSettingsErrors(config) {
|
|
3417
|
+
const ws = config.writeSettings;
|
|
3418
|
+
if (ws === undefined || ws === null)
|
|
3419
|
+
return [];
|
|
3420
|
+
if (typeof ws !== "object" || Array.isArray(ws))
|
|
3421
|
+
return ["Write settings must be an object (writeSettings)"];
|
|
3422
|
+
const errors = [];
|
|
3423
|
+
if (ws.onError !== undefined && !isOneOf(TRANSFORM_ON_ERROR, ws.onError)) {
|
|
3424
|
+
errors.push(`Write settings: onError must be one of: ${TRANSFORM_ON_ERROR.join(", ")} (got "${String(ws.onError)}")`);
|
|
3425
|
+
}
|
|
3426
|
+
if (ws.batchSize !== undefined && !(Number.isInteger(ws.batchSize) && ws.batchSize > 0)) {
|
|
3427
|
+
errors.push(`Write settings: batchSize must be a whole number above 0 (got "${String(ws.batchSize)}")`);
|
|
3428
|
+
}
|
|
3429
|
+
return errors;
|
|
3430
|
+
}
|
|
3414
3431
|
function unwindErrors(config) {
|
|
3415
3432
|
const unwind = config.unwind;
|
|
3416
3433
|
if (!unwind)
|
|
@@ -3452,6 +3469,16 @@ var TransformConfig = {
|
|
|
3452
3469
|
options: TRANSFORM_OPERATION_IDS,
|
|
3453
3470
|
description: "What to do with each mapped record at the target: upsert, insert, update or delete"
|
|
3454
3471
|
},
|
|
3472
|
+
upsertMatchKey: {
|
|
3473
|
+
type: "text",
|
|
3474
|
+
required: false,
|
|
3475
|
+
description: "For upsert and update: the TARGET field that says which existing record a row is (DEV-646). A row whose value matches a record updates it; " + "no match creates one (upsert). Empty = the connector decides: Salesforce Id, MongoDB _id, the SQL primary key. " + "A sync that may run more than once must upsert on a key that is stable and unique for the SOURCE record, or every run creates the records again. " + "Salesforce: the key must be an External ID field on the object (describe_connector_object) — mapping a source id into a normal field is not enough, and " + 'without one the upsert fails with "External ID is not found in record". If the object has no External ID field for this source, say so and ask the person: ' + "they create one in Salesforce (for example a HubSpot Contact Id text field marked External ID and Unique), or choose insert knowing re-runs duplicate."
|
|
3476
|
+
},
|
|
3477
|
+
writeSettings: {
|
|
3478
|
+
type: "json",
|
|
3479
|
+
required: false,
|
|
3480
|
+
description: 'How rows are written: { "batchSize"?: number, "onError"?: "continue" | "fail", "dryRun"?: boolean, "exposeFailedRows"?: boolean }. ' + 'onError "continue" (the default) writes every row it can and reports the failures (the run ends as partial success); "fail" stops the step at the first failed row. ' + "dryRun maps and validates without writing."
|
|
3481
|
+
},
|
|
3455
3482
|
connectorId: { type: "connection", required: true },
|
|
3456
3483
|
database: {
|
|
3457
3484
|
type: "text",
|
|
@@ -3473,7 +3500,7 @@ var TransformConfig = {
|
|
|
3473
3500
|
mappings: {
|
|
3474
3501
|
type: "array",
|
|
3475
3502
|
required: false,
|
|
3476
|
-
description: "Field mappings: [{ id, sourceField, targetField, targetType, transform? }]. sourceField is a token like {{orders[].email}}; " + "an index picks one list element ({{products[].variants[0].price}}). With groupBy, set lineField: true on the mappings that make each line. " + 'When the target field holds a record id but you have a reference (an email, SHOP-123), add lookup: { "object": "product.product", "matchField": "default_code" } — ' + "the write uses the id of the one record whose matchField equals the value; no match, or more than one, fails that row. Odoo and QuickBooks Online (e.g. CustomerRef.value → Customer by DisplayName; " + "Line.SalesItemLineDetail.ItemRef.value → Item by Name). A QuickBooks transaction upsert matches on DocNumber unless upsertMatchKey says otherwise."
|
|
3503
|
+
description: "Field mappings: [{ id, sourceField, targetField, targetType, transform? }]. sourceField is a token like {{orders[].email}}; " + "targetField is the target app's own field name, normally one describe_connector_object lists; a name it does not list is written as given, so the field must exist in the target app (a custom field the person created). " + "A field the target requires (Salesforce Account Name) must be mapped, and a source value that can be empty needs a fallback or the row fails. " + "an index picks one list element ({{products[].variants[0].price}}). With groupBy, set lineField: true on the mappings that make each line. " + 'When the target field holds a record id but you have a reference (an email, SHOP-123), add lookup: { "object": "product.product", "matchField": "default_code" } — ' + "the write uses the id of the one record whose matchField equals the value; no match, or more than one, fails that row. Odoo and QuickBooks Online (e.g. CustomerRef.value → Customer by DisplayName; " + "Line.SalesItemLineDetail.ItemRef.value → Item by Name). A QuickBooks transaction upsert matches on DocNumber unless upsertMatchKey says otherwise."
|
|
3477
3504
|
},
|
|
3478
3505
|
groupBy: {
|
|
3479
3506
|
type: "json",
|
|
@@ -3529,7 +3556,7 @@ var TransformConfig = {
|
|
|
3529
3556
|
});
|
|
3530
3557
|
}
|
|
3531
3558
|
}
|
|
3532
|
-
errors.push(...groupByErrors(config), ...unwindErrors(config));
|
|
3559
|
+
errors.push(...groupByErrors(config), ...unwindErrors(config), ...writeSettingsErrors(config));
|
|
3533
3560
|
return { valid: errors.length === 0, errors };
|
|
3534
3561
|
},
|
|
3535
3562
|
merge: (userConfig) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export { EmailConfig, } from "./catalog/communication/email-send/config";
|
|
|
36
36
|
export { queryDefinition, } from "./catalog/general/query/index";
|
|
37
37
|
export { isQueryableConnector, queryFieldsSatisfied, queryTablesSatisfied, validateBuildQueryConfig, validateVisualConfig, QUERY_AUTHORED_SQL_MESSAGE, QUERY_VISUAL_ONLY_MESSAGE, } from "./catalog/general/query/config";
|
|
38
38
|
export { type BuildQueryConfig, type ColumnSchema, type CompiledQuery, type Condition, type ConditionGroup, type ConditionRow, type ConnectorSchema, isConditionGroup, MAX_CONDITION_DEPTH, QUERY_AGGREGATE_FUNCTIONS, QUERY_COMPARISON_OPERATORS, QUERY_CONDITION_OPERATORS, QUERY_MODES, QUERY_RELATIVE_DATE_OPERATORS, QUERY_TYPES, type QueryAggregate, type QueryAggregateFn, type QueryComparisonOperator, type QueryConditionOperator, type QueryExecutionResult, type QueryJoin, type QueryJoinOperator, type QuerySort, RELATIVE_DATE_DIRECTIONS, RELATIVE_DATE_MAX_AMOUNT, RELATIVE_DATE_UNITS, type RelativeDate, type RelativeDateDirection, type RelativeDateUnit, SortDirection, type VisualConfigV2, type VisualQueryConfig, } from "./catalog/general/query/types";
|
|
39
|
-
export { DATABASE_CONNECTOR_IDS, type FieldMapping, TRANSFORM_MODES, TRANSFORM_OPERATIONS, TransformConfig, type TransformConfigType, type TransformGroupBy, type TransformLookup, type TransformUnwind, type TransformOperation, } from "./catalog/general/transform/config";
|
|
39
|
+
export { DATABASE_CONNECTOR_IDS, type FieldMapping, TRANSFORM_MODES, TRANSFORM_ON_ERROR, TRANSFORM_OPERATIONS, TransformConfig, type TransformConfigType, type TransformGroupBy, type TransformLookup, type TransformUnwind, type TransformOperation, type TransformWriteSettings, } from "./catalog/general/transform/config";
|
|
40
40
|
export { AGGREGATE_FUNCTIONS, AGGREGATE_FUNCTION_DESCRIPTIONS, AggregateConfig, type AggregateConfigType, type AggregateFn, type AggregateMetric, type AggregateSchemaNode, groupKeyName, } from "./catalog/general/aggregate/config";
|
|
41
41
|
export { detectRecordFields, resolveRecordSchema, type RecordSchemaLike, } from "./catalog/logic/for-each/recordSchema";
|
|
42
42
|
export { STORAGE_CONNECTOR_IDS, type StorageExtraField, type StoragePathField, getStorageProvider, storageConfigKeys, } from "./catalog/storage/storageCapabilities";
|
package/dist/index.js
CHANGED
|
@@ -3210,6 +3210,7 @@ var WhatsappSendConfig = {
|
|
|
3210
3210
|
};
|
|
3211
3211
|
|
|
3212
3212
|
// src/catalog/general/transform/config.ts
|
|
3213
|
+
var TRANSFORM_ON_ERROR = ["continue", "fail"];
|
|
3213
3214
|
var TRANSFORM_MODES = ["visual", "expression"];
|
|
3214
3215
|
var TRANSFORM_OPERATIONS = [
|
|
3215
3216
|
{ id: "upsert", label: "Upsert" },
|
|
@@ -3234,6 +3235,21 @@ function groupByErrors(config) {
|
|
|
3234
3235
|
}
|
|
3235
3236
|
return errors;
|
|
3236
3237
|
}
|
|
3238
|
+
function writeSettingsErrors(config) {
|
|
3239
|
+
const ws = config.writeSettings;
|
|
3240
|
+
if (ws === undefined || ws === null)
|
|
3241
|
+
return [];
|
|
3242
|
+
if (typeof ws !== "object" || Array.isArray(ws))
|
|
3243
|
+
return ["Write settings must be an object (writeSettings)"];
|
|
3244
|
+
const errors = [];
|
|
3245
|
+
if (ws.onError !== undefined && !isOneOf(TRANSFORM_ON_ERROR, ws.onError)) {
|
|
3246
|
+
errors.push(`Write settings: onError must be one of: ${TRANSFORM_ON_ERROR.join(", ")} (got "${String(ws.onError)}")`);
|
|
3247
|
+
}
|
|
3248
|
+
if (ws.batchSize !== undefined && !(Number.isInteger(ws.batchSize) && ws.batchSize > 0)) {
|
|
3249
|
+
errors.push(`Write settings: batchSize must be a whole number above 0 (got "${String(ws.batchSize)}")`);
|
|
3250
|
+
}
|
|
3251
|
+
return errors;
|
|
3252
|
+
}
|
|
3237
3253
|
function unwindErrors(config) {
|
|
3238
3254
|
const unwind = config.unwind;
|
|
3239
3255
|
if (!unwind)
|
|
@@ -3275,6 +3291,16 @@ var TransformConfig = {
|
|
|
3275
3291
|
options: TRANSFORM_OPERATION_IDS,
|
|
3276
3292
|
description: "What to do with each mapped record at the target: upsert, insert, update or delete"
|
|
3277
3293
|
},
|
|
3294
|
+
upsertMatchKey: {
|
|
3295
|
+
type: "text",
|
|
3296
|
+
required: false,
|
|
3297
|
+
description: "For upsert and update: the TARGET field that says which existing record a row is (DEV-646). A row whose value matches a record updates it; " + "no match creates one (upsert). Empty = the connector decides: Salesforce Id, MongoDB _id, the SQL primary key. " + "A sync that may run more than once must upsert on a key that is stable and unique for the SOURCE record, or every run creates the records again. " + "Salesforce: the key must be an External ID field on the object (describe_connector_object) — mapping a source id into a normal field is not enough, and " + 'without one the upsert fails with "External ID is not found in record". If the object has no External ID field for this source, say so and ask the person: ' + "they create one in Salesforce (for example a HubSpot Contact Id text field marked External ID and Unique), or choose insert knowing re-runs duplicate."
|
|
3298
|
+
},
|
|
3299
|
+
writeSettings: {
|
|
3300
|
+
type: "json",
|
|
3301
|
+
required: false,
|
|
3302
|
+
description: 'How rows are written: { "batchSize"?: number, "onError"?: "continue" | "fail", "dryRun"?: boolean, "exposeFailedRows"?: boolean }. ' + 'onError "continue" (the default) writes every row it can and reports the failures (the run ends as partial success); "fail" stops the step at the first failed row. ' + "dryRun maps and validates without writing."
|
|
3303
|
+
},
|
|
3278
3304
|
connectorId: { type: "connection", required: true },
|
|
3279
3305
|
database: {
|
|
3280
3306
|
type: "text",
|
|
@@ -3296,7 +3322,7 @@ var TransformConfig = {
|
|
|
3296
3322
|
mappings: {
|
|
3297
3323
|
type: "array",
|
|
3298
3324
|
required: false,
|
|
3299
|
-
description: "Field mappings: [{ id, sourceField, targetField, targetType, transform? }]. sourceField is a token like {{orders[].email}}; " + "an index picks one list element ({{products[].variants[0].price}}). With groupBy, set lineField: true on the mappings that make each line. " + 'When the target field holds a record id but you have a reference (an email, SHOP-123), add lookup: { "object": "product.product", "matchField": "default_code" } — ' + "the write uses the id of the one record whose matchField equals the value; no match, or more than one, fails that row. Odoo and QuickBooks Online (e.g. CustomerRef.value → Customer by DisplayName; " + "Line.SalesItemLineDetail.ItemRef.value → Item by Name). A QuickBooks transaction upsert matches on DocNumber unless upsertMatchKey says otherwise."
|
|
3325
|
+
description: "Field mappings: [{ id, sourceField, targetField, targetType, transform? }]. sourceField is a token like {{orders[].email}}; " + "targetField is the target app's own field name, normally one describe_connector_object lists; a name it does not list is written as given, so the field must exist in the target app (a custom field the person created). " + "A field the target requires (Salesforce Account Name) must be mapped, and a source value that can be empty needs a fallback or the row fails. " + "an index picks one list element ({{products[].variants[0].price}}). With groupBy, set lineField: true on the mappings that make each line. " + 'When the target field holds a record id but you have a reference (an email, SHOP-123), add lookup: { "object": "product.product", "matchField": "default_code" } — ' + "the write uses the id of the one record whose matchField equals the value; no match, or more than one, fails that row. Odoo and QuickBooks Online (e.g. CustomerRef.value → Customer by DisplayName; " + "Line.SalesItemLineDetail.ItemRef.value → Item by Name). A QuickBooks transaction upsert matches on DocNumber unless upsertMatchKey says otherwise."
|
|
3300
3326
|
},
|
|
3301
3327
|
groupBy: {
|
|
3302
3328
|
type: "json",
|
|
@@ -3352,7 +3378,7 @@ var TransformConfig = {
|
|
|
3352
3378
|
});
|
|
3353
3379
|
}
|
|
3354
3380
|
}
|
|
3355
|
-
errors.push(...groupByErrors(config), ...unwindErrors(config));
|
|
3381
|
+
errors.push(...groupByErrors(config), ...unwindErrors(config), ...writeSettingsErrors(config));
|
|
3356
3382
|
return { valid: errors.length === 0, errors };
|
|
3357
3383
|
},
|
|
3358
3384
|
merge: (userConfig) => {
|
|
@@ -6243,6 +6269,7 @@ export {
|
|
|
6243
6269
|
SortDirection,
|
|
6244
6270
|
StorageActionConfig,
|
|
6245
6271
|
TRANSFORM_MODES,
|
|
6272
|
+
TRANSFORM_ON_ERROR,
|
|
6246
6273
|
TRANSFORM_OPERATIONS,
|
|
6247
6274
|
TransformConfig,
|
|
6248
6275
|
USER_FUNCTION_PREFIX,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octaviaflow/flow-rules",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
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",
|