@minded-ai/mindedjs 3.1.46 → 3.1.49
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/browserTask/resolveRpaBrowserSessionOptions.d.ts +13 -0
- package/dist/browserTask/resolveRpaBrowserSessionOptions.d.ts.map +1 -0
- package/dist/browserTask/resolveRpaBrowserSessionOptions.js +14 -0
- package/dist/browserTask/resolveRpaBrowserSessionOptions.js.map +1 -0
- package/dist/nodes/addBrowserTaskNode.js +7 -7
- package/dist/nodes/addBrowserTaskNode.js.map +1 -1
- package/dist/nodes/addPromptNode.d.ts.map +1 -1
- package/dist/nodes/addPromptNode.js +7 -20
- package/dist/nodes/addPromptNode.js.map +1 -1
- package/dist/nodes/addToolRunNode.d.ts.map +1 -1
- package/dist/nodes/addToolRunNode.js +8 -4
- package/dist/nodes/addToolRunNode.js.map +1 -1
- package/dist/platform/config.d.ts +2 -0
- package/dist/platform/config.d.ts.map +1 -1
- package/dist/platform/config.js +70 -4
- package/dist/platform/config.js.map +1 -1
- package/dist/platform/mindedConnectionTypes.d.ts +21 -0
- package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
- package/dist/platform/mindedConnectionTypes.js +2 -0
- package/dist/platform/mindedConnectionTypes.js.map +1 -1
- package/dist/platform/toolExecutor.d.ts.map +1 -1
- package/dist/platform/toolExecutor.js +7 -6
- package/dist/platform/toolExecutor.js.map +1 -1
- package/dist/toolsLibrary/distributedLock.d.ts +27 -0
- package/dist/toolsLibrary/distributedLock.d.ts.map +1 -0
- package/dist/toolsLibrary/distributedLock.js +110 -0
- package/dist/toolsLibrary/distributedLock.js.map +1 -0
- package/dist/toolsLibrary/extraction.d.ts +2 -2
- package/dist/toolsLibrary/index.d.ts +1 -0
- package/dist/toolsLibrary/index.d.ts.map +1 -1
- package/dist/toolsLibrary/index.js +2 -1
- package/dist/toolsLibrary/index.js.map +1 -1
- package/docs/low-code-editor/rpa-tools.md +18 -1
- package/package.json +1 -1
- package/src/browserTask/resolveRpaBrowserSessionOptions.ts +26 -0
- package/src/nodes/addBrowserTaskNode.ts +2 -2
- package/src/nodes/addPromptNode.ts +7 -22
- package/src/nodes/addToolRunNode.ts +8 -3
- package/src/platform/config.ts +75 -4
- package/src/platform/mindedConnectionTypes.ts +25 -0
- package/src/platform/toolExecutor.ts +6 -5
- package/src/toolsLibrary/distributedLock.ts +160 -0
- package/src/toolsLibrary/index.ts +2 -0
package/src/platform/config.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { config } from 'dotenv';
|
|
|
3
3
|
import { Environment } from '../types/Platform.types';
|
|
4
4
|
import { BrowserTaskMode } from '../browserTask/types';
|
|
5
5
|
import { logger } from '../utils/logger';
|
|
6
|
+
import { MindedProxyMode, ProxyConfig, ProxyProvider } from '../types/Tools.types';
|
|
6
7
|
const path = resolve(__dirname, '../../.env');
|
|
7
8
|
config({ path });
|
|
8
9
|
|
|
@@ -18,6 +19,7 @@ type MindedConfig = {
|
|
|
18
19
|
elevenLabsKey: string | null;
|
|
19
20
|
elevenLabsAgentId: string | null;
|
|
20
21
|
browserTaskMode: BrowserTaskMode;
|
|
22
|
+
proxyConfig: ProxyConfig | null;
|
|
21
23
|
isDeprioritizedSocket: boolean;
|
|
22
24
|
};
|
|
23
25
|
|
|
@@ -37,8 +39,73 @@ const parseBrowserTaskMode = (value: string | undefined): BrowserTaskMode => {
|
|
|
37
39
|
return BrowserTaskMode.CLOUD;
|
|
38
40
|
};
|
|
39
41
|
|
|
42
|
+
const parseProxyConfig = (): ProxyConfig | null => {
|
|
43
|
+
const provider = process.env.BROWSER_PROXY_PROVIDER?.trim();
|
|
44
|
+
if (!provider) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (provider === ProxyProvider.MINDED) {
|
|
49
|
+
const mode = process.env.BROWSER_PROXY_MODE?.trim();
|
|
50
|
+
if (mode === MindedProxyMode.TRUSTED_IP) {
|
|
51
|
+
return {
|
|
52
|
+
provider: ProxyProvider.MINDED,
|
|
53
|
+
mode: MindedProxyMode.TRUSTED_IP,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (mode === MindedProxyMode.REGION) {
|
|
57
|
+
const countryCode = process.env.BROWSER_PROXY_COUNTRY_CODE?.trim();
|
|
58
|
+
if (!countryCode) {
|
|
59
|
+
logger.warn({
|
|
60
|
+
message: 'BROWSER_PROXY_COUNTRY_CODE is required when BROWSER_PROXY_MODE is region; ignoring proxy config',
|
|
61
|
+
});
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
provider: ProxyProvider.MINDED,
|
|
66
|
+
mode: MindedProxyMode.REGION,
|
|
67
|
+
countryCode,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
logger.warn({
|
|
71
|
+
message: 'Invalid BROWSER_PROXY_MODE provided; ignoring proxy config',
|
|
72
|
+
provided: mode,
|
|
73
|
+
allowed: [MindedProxyMode.TRUSTED_IP, MindedProxyMode.REGION],
|
|
74
|
+
});
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (provider === ProxyProvider.CUSTOM) {
|
|
79
|
+
const server = process.env.BROWSER_PROXY_SERVER?.trim();
|
|
80
|
+
if (!server) {
|
|
81
|
+
logger.warn({
|
|
82
|
+
message: 'BROWSER_PROXY_SERVER is required when BROWSER_PROXY_PROVIDER is custom; ignoring proxy config',
|
|
83
|
+
});
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const username = process.env.BROWSER_PROXY_USERNAME?.trim();
|
|
87
|
+
const password = process.env.BROWSER_PROXY_PASSWORD?.trim();
|
|
88
|
+
return {
|
|
89
|
+
provider: ProxyProvider.CUSTOM,
|
|
90
|
+
server,
|
|
91
|
+
...(username ? { username } : {}),
|
|
92
|
+
...(password ? { password } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
logger.warn({
|
|
97
|
+
message: 'Invalid BROWSER_PROXY_PROVIDER provided; ignoring proxy config',
|
|
98
|
+
provided: provider,
|
|
99
|
+
allowed: [ProxyProvider.MINDED, ProxyProvider.CUSTOM],
|
|
100
|
+
});
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
|
|
40
104
|
export const getConfig = (): MindedConfig => {
|
|
41
105
|
const environment = (process.env.NODE_ENV as Environment) || Environment.DEVELOPMENT;
|
|
106
|
+
const browserTaskMode = parseBrowserTaskMode(process.env.BROWSER_TASK_MODE);
|
|
107
|
+
const proxyConfig = parseProxyConfig();
|
|
108
|
+
|
|
42
109
|
switch (environment) {
|
|
43
110
|
case Environment.TEST:
|
|
44
111
|
return {
|
|
@@ -52,7 +119,8 @@ export const getConfig = (): MindedConfig => {
|
|
|
52
119
|
dashboardConnected: false,
|
|
53
120
|
elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
|
|
54
121
|
elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || null,
|
|
55
|
-
browserTaskMode
|
|
122
|
+
browserTaskMode,
|
|
123
|
+
proxyConfig,
|
|
56
124
|
isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
|
|
57
125
|
};
|
|
58
126
|
case Environment.DEVELOPMENT:
|
|
@@ -67,7 +135,8 @@ export const getConfig = (): MindedConfig => {
|
|
|
67
135
|
elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
|
|
68
136
|
dashboardConnected: true,
|
|
69
137
|
elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye194psezr909nwec27m2t9',
|
|
70
|
-
browserTaskMode
|
|
138
|
+
browserTaskMode,
|
|
139
|
+
proxyConfig,
|
|
71
140
|
isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
|
|
72
141
|
};
|
|
73
142
|
case Environment.STAGING:
|
|
@@ -82,7 +151,8 @@ export const getConfig = (): MindedConfig => {
|
|
|
82
151
|
elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
|
|
83
152
|
dashboardConnected: false,
|
|
84
153
|
elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye1ajkaf17axpcxg220qwcm',
|
|
85
|
-
browserTaskMode
|
|
154
|
+
browserTaskMode,
|
|
155
|
+
proxyConfig,
|
|
86
156
|
isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
|
|
87
157
|
};
|
|
88
158
|
case Environment.PRODUCTION:
|
|
@@ -97,7 +167,8 @@ export const getConfig = (): MindedConfig => {
|
|
|
97
167
|
elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
|
|
98
168
|
dashboardConnected: false,
|
|
99
169
|
elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye1ajkaf17axpcxg220qwcm',
|
|
100
|
-
browserTaskMode
|
|
170
|
+
browserTaskMode,
|
|
171
|
+
proxyConfig,
|
|
101
172
|
isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
|
|
102
173
|
};
|
|
103
174
|
}
|
|
@@ -18,6 +18,8 @@ export enum mindedConnectionSocketMessageType {
|
|
|
18
18
|
SAVE_STORAGE_RECORD = 'save-storage-record',
|
|
19
19
|
GET_STORAGE_RECORDS = 'get-storage-records',
|
|
20
20
|
DELETE_STORAGE_RECORD = 'delete-storage-record',
|
|
21
|
+
ACQUIRE_DISTRIBUTED_LOCK = 'acquire-distributed-lock',
|
|
22
|
+
RELEASE_DISTRIBUTED_LOCK = 'release-distributed-lock',
|
|
21
23
|
GET_AGENT_CONFIGURATION = 'get-agent-configuration',
|
|
22
24
|
GET_FLOWS = 'get-flows',
|
|
23
25
|
GET_PLAYBOOKS = 'get-playbooks',
|
|
@@ -99,6 +101,8 @@ export type mindedConnectionSocketMessageTypeMap = {
|
|
|
99
101
|
[mindedConnectionSocketMessageType.SAVE_STORAGE_RECORD]: SaveStorageRecordRequest;
|
|
100
102
|
[mindedConnectionSocketMessageType.GET_STORAGE_RECORDS]: GetStorageRecordsRequest;
|
|
101
103
|
[mindedConnectionSocketMessageType.DELETE_STORAGE_RECORD]: DeleteStorageRecordRequest;
|
|
104
|
+
[mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK]: AcquireDistributedLockRequest;
|
|
105
|
+
[mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK]: ReleaseDistributedLockRequest;
|
|
102
106
|
[mindedConnectionSocketMessageType.GET_FLOWS]: BasemindedConnectionSocketMessage;
|
|
103
107
|
[mindedConnectionSocketMessageType.GET_PLAYBOOKS]: BasemindedConnectionSocketMessage;
|
|
104
108
|
[mindedConnectionSocketMessageType.INVOKE]: InvokeMessage;
|
|
@@ -813,6 +817,27 @@ export interface DeleteStorageRecordResponse extends BaseSdkConnectionSocketMess
|
|
|
813
817
|
success?: boolean;
|
|
814
818
|
}
|
|
815
819
|
|
|
820
|
+
export interface AcquireDistributedLockRequest extends BasemindedConnectionSocketMessage {
|
|
821
|
+
type: mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK;
|
|
822
|
+
key: string;
|
|
823
|
+
ttlSeconds?: number;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
export interface AcquireDistributedLockResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
|
|
827
|
+
acquired?: boolean;
|
|
828
|
+
lockId?: string;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
export interface ReleaseDistributedLockRequest extends BasemindedConnectionSocketMessage {
|
|
832
|
+
type: mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK;
|
|
833
|
+
key: string;
|
|
834
|
+
lockId: string;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
export interface ReleaseDistributedLockResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
|
|
838
|
+
released?: boolean;
|
|
839
|
+
}
|
|
840
|
+
|
|
816
841
|
export interface RPAErrorUploadRequest extends BasemindedConnectionSocketMessage {
|
|
817
842
|
type: mindedConnectionSocketMessageType.RPA_ERROR_UPLOAD;
|
|
818
843
|
sessionId: string;
|
|
@@ -2,7 +2,7 @@ import { Tool } from '../types/Tools.types';
|
|
|
2
2
|
import { Agent } from '../agent';
|
|
3
3
|
import { logger } from '../utils/logger';
|
|
4
4
|
import { withBrowserSession } from '../toolsLibrary/withBrowserSession';
|
|
5
|
-
import {
|
|
5
|
+
import { resolveRpaBrowserSessionOptions } from '../browserTask/resolveRpaBrowserSessionOptions';
|
|
6
6
|
|
|
7
7
|
export interface ToolExecutionRequest {
|
|
8
8
|
toolName: string;
|
|
@@ -86,9 +86,10 @@ export class ToolExecutor {
|
|
|
86
86
|
|
|
87
87
|
// Check if this is an RPA tool
|
|
88
88
|
if (tool.type === 'rpa') {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
const { browserTaskMode, proxyConfig } = resolveRpaBrowserSessionOptions({
|
|
90
|
+
toolBrowserTaskMode: tool.browserTaskMode,
|
|
91
|
+
toolProxyConfig: tool.proxyConfig,
|
|
92
|
+
});
|
|
92
93
|
|
|
93
94
|
// Wrap with browser session and screenshot capture
|
|
94
95
|
const { result, breakpointHit, breakpointInfo } = await withBrowserSession(
|
|
@@ -96,7 +97,7 @@ export class ToolExecutor {
|
|
|
96
97
|
sessionId,
|
|
97
98
|
browserTaskMode,
|
|
98
99
|
toolCallId: requestId, // Use requestId as toolCallId for tracking
|
|
99
|
-
proxyConfig
|
|
100
|
+
proxyConfig,
|
|
100
101
|
toolName,
|
|
101
102
|
persistSession: tool.persistSession,
|
|
102
103
|
},
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { awaitEmit } from '../platform/mindedConnection';
|
|
2
|
+
import {
|
|
3
|
+
mindedConnectionSocketMessageType,
|
|
4
|
+
AcquireDistributedLockRequest,
|
|
5
|
+
AcquireDistributedLockResponse,
|
|
6
|
+
ReleaseDistributedLockRequest,
|
|
7
|
+
ReleaseDistributedLockResponse,
|
|
8
|
+
} from '../platform/mindedConnectionTypes';
|
|
9
|
+
import { logger } from '../utils/logger';
|
|
10
|
+
import { wait } from '../utils/wait';
|
|
11
|
+
|
|
12
|
+
const LOCK_KEY_PATTERN = /^[a-zA-Z0-9:_-]{1,128}$/;
|
|
13
|
+
const DEFAULT_TTL_SECONDS = 90;
|
|
14
|
+
const DEFAULT_WAIT_MS = 60_000;
|
|
15
|
+
const DEFAULT_RETRY_INTERVAL_MS = 500;
|
|
16
|
+
const SOCKET_TIMEOUT_MS = 10_000;
|
|
17
|
+
|
|
18
|
+
interface AcquireLockParams {
|
|
19
|
+
key: string;
|
|
20
|
+
ttlSeconds?: number;
|
|
21
|
+
waitMs?: number;
|
|
22
|
+
retryIntervalMs?: number;
|
|
23
|
+
sessionId?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ReleaseLockParams {
|
|
27
|
+
key: string;
|
|
28
|
+
lockId: string;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface WithLockParams {
|
|
33
|
+
key: string;
|
|
34
|
+
ttlSeconds?: number;
|
|
35
|
+
waitMs?: number;
|
|
36
|
+
retryIntervalMs?: number;
|
|
37
|
+
sessionId?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class DistributedLockTimeoutError extends Error {
|
|
41
|
+
constructor(key: string, waitMs: number) {
|
|
42
|
+
super(`Timed out waiting ${waitMs}ms to acquire distributed lock "${key}"`);
|
|
43
|
+
this.name = 'DistributedLockTimeoutError';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const assertValidLockKey = (key: string) => {
|
|
48
|
+
if (!LOCK_KEY_PATTERN.test(key)) {
|
|
49
|
+
throw new Error('Lock key must be 1-128 characters of letters, numbers, colon, underscore, or hyphen');
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const tryAcquireOnce = async ({ key, ttlSeconds }: { key: string; ttlSeconds: number }): Promise<string | null> => {
|
|
54
|
+
const request: AcquireDistributedLockRequest = {
|
|
55
|
+
type: mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK,
|
|
56
|
+
key,
|
|
57
|
+
ttlSeconds,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const response = await awaitEmit<AcquireDistributedLockRequest, AcquireDistributedLockResponse>(
|
|
61
|
+
mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK,
|
|
62
|
+
request,
|
|
63
|
+
SOCKET_TIMEOUT_MS,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (response.error) {
|
|
67
|
+
throw new Error(response.error);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (response.acquired === true && response.lockId) {
|
|
71
|
+
return response.lockId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const acquireLock = async ({
|
|
78
|
+
key,
|
|
79
|
+
ttlSeconds = DEFAULT_TTL_SECONDS,
|
|
80
|
+
waitMs = DEFAULT_WAIT_MS,
|
|
81
|
+
retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
|
|
82
|
+
sessionId,
|
|
83
|
+
}: AcquireLockParams): Promise<string> => {
|
|
84
|
+
assertValidLockKey(key);
|
|
85
|
+
const deadline = Date.now() + waitMs;
|
|
86
|
+
|
|
87
|
+
const initialLockId = await tryAcquireOnce({ key, ttlSeconds });
|
|
88
|
+
if (initialLockId !== null) {
|
|
89
|
+
logger.info({
|
|
90
|
+
message: 'Acquired distributed lock',
|
|
91
|
+
key,
|
|
92
|
+
sessionId,
|
|
93
|
+
});
|
|
94
|
+
return initialLockId;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
while (Date.now() < deadline) {
|
|
98
|
+
await wait(retryIntervalMs);
|
|
99
|
+
const lockId = await tryAcquireOnce({ key, ttlSeconds });
|
|
100
|
+
if (lockId !== null) {
|
|
101
|
+
logger.info({
|
|
102
|
+
message: 'Acquired distributed lock',
|
|
103
|
+
key,
|
|
104
|
+
sessionId,
|
|
105
|
+
});
|
|
106
|
+
return lockId;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
throw new DistributedLockTimeoutError(key, waitMs);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const releaseLock = async ({ key, lockId, sessionId }: ReleaseLockParams): Promise<void> => {
|
|
114
|
+
assertValidLockKey(key);
|
|
115
|
+
if (!lockId) {
|
|
116
|
+
throw new Error('lockId is required in releaseLock params');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const request: ReleaseDistributedLockRequest = {
|
|
120
|
+
type: mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK,
|
|
121
|
+
key,
|
|
122
|
+
lockId,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const response = await awaitEmit<ReleaseDistributedLockRequest, ReleaseDistributedLockResponse>(
|
|
126
|
+
mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK,
|
|
127
|
+
request,
|
|
128
|
+
SOCKET_TIMEOUT_MS,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (response.error) {
|
|
132
|
+
throw new Error(response.error);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (response.released === false) {
|
|
136
|
+
logger.warn({
|
|
137
|
+
message: 'Distributed lock was not released; it may have expired',
|
|
138
|
+
key,
|
|
139
|
+
sessionId,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const withLock = async <T>(params: WithLockParams, callback: () => Promise<T>): Promise<T> => {
|
|
145
|
+
const lockId = await acquireLock(params);
|
|
146
|
+
try {
|
|
147
|
+
return await callback();
|
|
148
|
+
} finally {
|
|
149
|
+
try {
|
|
150
|
+
await releaseLock({ key: params.key, lockId, sessionId: params.sessionId });
|
|
151
|
+
} catch (error) {
|
|
152
|
+
logger.warn({
|
|
153
|
+
message: 'Failed to release distributed lock',
|
|
154
|
+
key: params.key,
|
|
155
|
+
sessionId: params.sessionId,
|
|
156
|
+
error,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
};
|
|
@@ -4,6 +4,8 @@ import * as extraction from './extraction';
|
|
|
4
4
|
import * as resolveCaptcha from './resolveCaptcha';
|
|
5
5
|
import * as storage from './storage';
|
|
6
6
|
|
|
7
|
+
export * as lock from './distributedLock';
|
|
8
|
+
|
|
7
9
|
// Export all tools as a collection for easy discovery
|
|
8
10
|
export const tools = {
|
|
9
11
|
'minded-parse-documents': parseDocument,
|