@izara_project/izara-core-library-asynchronous-flow 1.0.40 → 1.0.41
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/package.json +1 -1
- package/src/asyncFlowSharedLib.js +40 -3
- package/src/awaitingMultipleSteps.js +39 -50
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "Sven Mason <thebarbariansven@gmail.com>",
|
|
4
4
|
"license": "AGPL-3.0-or-later",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-libraries/izara-core-library-asynchronous-flow#readme",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.41",
|
|
7
7
|
"description": "Shared asynchronous flow logic",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "index.js",
|
|
@@ -28,11 +28,48 @@ import { sqs } from '@izara_project/izara-core-library-external-request';
|
|
|
28
28
|
|
|
29
29
|
import { identifierUuid } from '@izara_project/izara-shared-core';
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Helper to safely join a prefix and an ID with a single underscore.
|
|
33
|
+
* Ensures no duplicate underscores between them.
|
|
34
|
+
* @param {string} id
|
|
35
|
+
* @param {string} [prefix='']
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function _joinPrefixAndId(id, prefix = '') {
|
|
39
|
+
if (!prefix) return id;
|
|
40
|
+
|
|
41
|
+
const cleanPrefix = prefix.endsWith('_') ? prefix.slice(0, -1) : prefix;
|
|
42
|
+
const cleanId = id.startsWith('_') ? id.slice(1) : id;
|
|
43
|
+
|
|
44
|
+
return `${cleanPrefix}_${cleanId}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create awaitingStepId by concatenating prefix and partitionKey.
|
|
49
|
+
* If prefix ends with an underscore, it's removed before concatenation.
|
|
50
|
+
* If partitionKey starts with an underscore, it's removed before concatenation.
|
|
51
|
+
* This ensures a clean "PREFIX_PARTITIONKEY" format without double underscores.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} partitionKey
|
|
54
|
+
* @param {string} [prefix='']
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
31
57
|
function createAwaitingStepId(partitionKey, prefix = '') {
|
|
32
|
-
return prefix
|
|
58
|
+
return _joinPrefixAndId(partitionKey, prefix);
|
|
33
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create pendingStepId by concatenating prefix and identifierId.
|
|
63
|
+
* If prefix ends with an underscore, it's removed before concatenation.
|
|
64
|
+
* If identifierId starts with an underscore, it's removed before concatenation.
|
|
65
|
+
* This ensures a clean "PREFIX_IDENTIFIER" format without double underscores.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} identifierId
|
|
68
|
+
* @param {string} [prefix='']
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
34
71
|
function createPendingStepId(identifierId, prefix = '') {
|
|
35
|
-
return prefix
|
|
72
|
+
return _joinPrefixAndId(identifierId, prefix);
|
|
36
73
|
}
|
|
37
74
|
|
|
38
75
|
/**
|
|
@@ -76,7 +113,7 @@ function createConcatenatedPendingStepId(parentId, childId) {
|
|
|
76
113
|
* @returns {string} The parent Flow Id created.
|
|
77
114
|
*/
|
|
78
115
|
function createParentFlowId(prefix = '') {
|
|
79
|
-
return (
|
|
116
|
+
return _joinPrefixAndId(identifierUuid(), prefix);
|
|
80
117
|
}
|
|
81
118
|
|
|
82
119
|
/**
|
|
@@ -19,7 +19,10 @@ import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
|
19
19
|
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
20
20
|
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
createParentFlowId,
|
|
24
|
+
createPendingStepId
|
|
25
|
+
} from './asyncFlowSharedLib.js';
|
|
23
26
|
|
|
24
27
|
function _assertPendingStepId(pendingStepId) {
|
|
25
28
|
if (!pendingStepId) {
|
|
@@ -97,15 +100,18 @@ async function _queryAwaitingStepsByPendingStepId(_izContext, pendingStepId) {
|
|
|
97
100
|
* @async
|
|
98
101
|
* @param {IzContext} _izContext - The Izara context.
|
|
99
102
|
* @param {string} pendingStepId - The ID of the pending step that is waiting.
|
|
100
|
-
* @param {Array<object>} [records=[]] - Array of step items
|
|
103
|
+
* @param {Array<object>} [records=[]] - Array of step items.
|
|
104
|
+
* @param {string} [records[].awaitingStepId] - Optional ID of the awaiting step. If not provided, a random UUID will be generated.
|
|
105
|
+
* @param {object} [records[].message] - Optional message payload to publish if flowType is provided.
|
|
106
|
+
* @param {object} [records[].flowType] - Optional flowType override for this specific step record.
|
|
107
|
+
* @param {string} records[].flowType.flowTag - Tag identifying the flow.
|
|
108
|
+
* @param {string} records[].flowType.serviceTag - Tag identifying the service.
|
|
101
109
|
* @param {object} [options={}] - Optional configurations.
|
|
102
110
|
* @param {string} [options.prefix=''] - Prefix to prepend to pendingStepId.
|
|
103
|
-
* @param {object} [options.additionalAttributes={}] -
|
|
104
|
-
* @param {object} [options.
|
|
105
|
-
* @param {
|
|
106
|
-
* @param {
|
|
107
|
-
* @param {string} options.publishConfig.flowType.flowTag - Tag identifying the flow.
|
|
108
|
-
* @param {string} options.publishConfig.flowType.serviceTag - Tag identifying the service.
|
|
111
|
+
* @param {object} [options.additionalAttributes={}] - Default additional attributes to associate with each pending step record.
|
|
112
|
+
* @param {object|null} [options.flowType=null] - Default flow schema/service metadata if starting external tasks.
|
|
113
|
+
* @param {string} [options.flowType.flowTag] - Tag identifying the default flow.
|
|
114
|
+
* @param {string} [options.flowType.serviceTag] - Tag identifying the default service.
|
|
109
115
|
* @returns {Promise<string|undefined>} The awaitingStepId of the first mapped record.
|
|
110
116
|
*/
|
|
111
117
|
export async function createAwaitingMultipleSteps(
|
|
@@ -114,30 +120,20 @@ export async function createAwaitingMultipleSteps(
|
|
|
114
120
|
records = [],
|
|
115
121
|
options = {}
|
|
116
122
|
) {
|
|
117
|
-
const {
|
|
118
|
-
prefix = '',
|
|
119
|
-
additionalAttributes = {},
|
|
120
|
-
publishConfig = null
|
|
121
|
-
} = options;
|
|
123
|
+
const { prefix = '', additionalAttributes = {}, flowType = null } = options;
|
|
122
124
|
|
|
123
125
|
_izContext.logger.debug('[Lib:AsyncFlow:createAwaitingMultipleSteps] Input', {
|
|
124
126
|
pendingStepId,
|
|
125
127
|
options
|
|
126
128
|
});
|
|
127
129
|
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
: `${prefix}_`
|
|
132
|
-
: '';
|
|
133
|
-
const finalPendingStepId =
|
|
134
|
-
formattedPrefix && !pendingStepId.startsWith(formattedPrefix)
|
|
135
|
-
? formattedPrefix + pendingStepId
|
|
136
|
-
: pendingStepId;
|
|
130
|
+
const finalPendingStepId = createPendingStepId(pendingStepId, prefix);
|
|
131
|
+
|
|
132
|
+
const hasFlowPublish = flowType || records.some(r => r.flowType);
|
|
137
133
|
|
|
138
134
|
let finalRecords = records;
|
|
139
135
|
|
|
140
|
-
if (finalRecords.length === 0 && !
|
|
136
|
+
if (finalRecords.length === 0 && !hasFlowPublish) {
|
|
141
137
|
finalRecords = [
|
|
142
138
|
{
|
|
143
139
|
awaitingStepId: createParentFlowId(prefix),
|
|
@@ -146,28 +142,28 @@ export async function createAwaitingMultipleSteps(
|
|
|
146
142
|
];
|
|
147
143
|
}
|
|
148
144
|
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!Array.isArray(messages)) {
|
|
154
|
-
throw new NoRetryError('messages must be an array');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (!flowTag || !serviceTag) {
|
|
158
|
-
throw new NoRetryError('flowType must both flowTag serviceTag');
|
|
159
|
-
}
|
|
145
|
+
if (hasFlowPublish) {
|
|
146
|
+
finalRecords = records.map(record => {
|
|
147
|
+
const recordFlowType = record.flowType || flowType;
|
|
160
148
|
|
|
161
|
-
|
|
162
|
-
|
|
149
|
+
if (!recordFlowType || !recordFlowType.flowTag || !recordFlowType.serviceTag) {
|
|
150
|
+
throw new NoRetryError('record.flowType must have both flowTag and serviceTag');
|
|
151
|
+
}
|
|
163
152
|
|
|
153
|
+
const awaitingStepId =
|
|
154
|
+
record.awaitingStepId || createParentFlowId(prefix);
|
|
164
155
|
return {
|
|
165
|
-
awaitingStepId
|
|
156
|
+
awaitingStepId,
|
|
166
157
|
additionalAttributes,
|
|
167
158
|
message: {
|
|
168
|
-
...message,
|
|
169
|
-
parentFlowId
|
|
170
|
-
}
|
|
159
|
+
...record.message,
|
|
160
|
+
parentFlowId: awaitingStepId
|
|
161
|
+
},
|
|
162
|
+
topicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
163
|
+
_izContext,
|
|
164
|
+
recordFlowType.flowTag,
|
|
165
|
+
recordFlowType.serviceTag
|
|
166
|
+
)
|
|
171
167
|
};
|
|
172
168
|
});
|
|
173
169
|
}
|
|
@@ -194,19 +190,12 @@ export async function createAwaitingMultipleSteps(
|
|
|
194
190
|
}
|
|
195
191
|
);
|
|
196
192
|
|
|
197
|
-
if (
|
|
198
|
-
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
199
|
-
_izContext,
|
|
200
|
-
publishConfig.flowType.flowTag,
|
|
201
|
-
publishConfig.flowType.serviceTag
|
|
202
|
-
);
|
|
203
|
-
|
|
193
|
+
if (hasFlowPublish) {
|
|
204
194
|
await Promise.all(
|
|
205
|
-
finalRecords.map(({ message }) =>
|
|
195
|
+
finalRecords.map(({ message, topicArn }) =>
|
|
206
196
|
sns.publishAsync(_izContext, {
|
|
207
197
|
TopicArn: `${topicArn}_In`,
|
|
208
|
-
Message: JSON.stringify(message)
|
|
209
|
-
MessageAttributes: {}
|
|
198
|
+
Message: JSON.stringify(message)
|
|
210
199
|
})
|
|
211
200
|
)
|
|
212
201
|
);
|