@kadoa/node-sdk 0.2.0 → 0.4.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/README.md +19 -21
- package/dist/index.d.mts +171 -52
- package/dist/index.d.ts +171 -52
- package/dist/index.js +585 -418
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +610 -440
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import globalAxios2, {
|
|
2
|
+
import globalAxios2, { isAxiosError } from 'axios';
|
|
3
|
+
import { URL, URLSearchParams } from 'url';
|
|
3
4
|
import { merge } from 'es-toolkit/object';
|
|
4
|
-
import { URL as URL$1, URLSearchParams } from 'url';
|
|
5
5
|
|
|
6
|
-
// src/events/
|
|
6
|
+
// src/core/events/event-emitter.ts
|
|
7
7
|
var KadoaEventEmitter = class extends EventEmitter {
|
|
8
8
|
/**
|
|
9
9
|
* Emit a typed SDK event
|
|
@@ -44,8 +44,8 @@ var KadoaEventEmitter = class extends EventEmitter {
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
// src/exceptions/
|
|
48
|
-
var
|
|
47
|
+
// src/core/exceptions/base.exception.ts
|
|
48
|
+
var _KadoaSdkException = class _KadoaSdkException extends Error {
|
|
49
49
|
constructor(message, options) {
|
|
50
50
|
super(message);
|
|
51
51
|
this.name = "KadoaSdkException";
|
|
@@ -74,9 +74,54 @@ var KadoaSdkException = class _KadoaSdkException extends Error {
|
|
|
74
74
|
toString() {
|
|
75
75
|
return [this.name, this.code, this.message].filter(Boolean).join(": ");
|
|
76
76
|
}
|
|
77
|
+
toDetailedString() {
|
|
78
|
+
const parts = [`${this.name}: ${this.message}`, `Code: ${this.code}`];
|
|
79
|
+
if (this.details && Object.keys(this.details).length > 0) {
|
|
80
|
+
parts.push(`Details: ${JSON.stringify(this.details, null, 2)}`);
|
|
81
|
+
}
|
|
82
|
+
if (this.cause) {
|
|
83
|
+
parts.push(`Cause: ${this.cause}`);
|
|
84
|
+
}
|
|
85
|
+
return parts.join("\n");
|
|
86
|
+
}
|
|
87
|
+
static isInstance(error) {
|
|
88
|
+
return error instanceof _KadoaSdkException;
|
|
89
|
+
}
|
|
90
|
+
static wrap(error, extra) {
|
|
91
|
+
if (error instanceof _KadoaSdkException) return error;
|
|
92
|
+
const message = extra?.message || (error instanceof Error ? error.message : typeof error === "string" ? error : "Unexpected error");
|
|
93
|
+
return new _KadoaSdkException(message, {
|
|
94
|
+
code: "UNKNOWN",
|
|
95
|
+
details: extra?.details,
|
|
96
|
+
cause: error
|
|
97
|
+
});
|
|
98
|
+
}
|
|
77
99
|
};
|
|
78
|
-
|
|
79
|
-
//
|
|
100
|
+
_KadoaSdkException.ERROR_MESSAGES = {
|
|
101
|
+
// General errors
|
|
102
|
+
CONFIG_ERROR: "Invalid configuration provided",
|
|
103
|
+
AUTH_FAILED: "Authentication failed. Please check your API key",
|
|
104
|
+
RATE_LIMITED: "Rate limit exceeded. Please try again later",
|
|
105
|
+
NETWORK_ERROR: "Network error occurred",
|
|
106
|
+
SERVER_ERROR: "Server error occurred",
|
|
107
|
+
PARSE_ERROR: "Failed to parse response",
|
|
108
|
+
// Workflow specific errors
|
|
109
|
+
NO_WORKFLOW_ID: "Failed to start extraction process - no ID received",
|
|
110
|
+
WORKFLOW_CREATE_FAILED: "Failed to create workflow",
|
|
111
|
+
WORKFLOW_TIMEOUT: "Workflow processing timed out",
|
|
112
|
+
WORKFLOW_UNEXPECTED_STATUS: "Extraction completed with unexpected status",
|
|
113
|
+
PROGRESS_CHECK_FAILED: "Failed to check extraction progress",
|
|
114
|
+
DATA_FETCH_FAILED: "Failed to retrieve extracted data from workflow",
|
|
115
|
+
// Extraction specific errors
|
|
116
|
+
NO_URLS: "At least one URL is required for extraction",
|
|
117
|
+
NO_API_KEY: "API key is required for entity detection",
|
|
118
|
+
LINK_REQUIRED: "Link is required for entity field detection",
|
|
119
|
+
NO_PREDICTIONS: "No entity predictions returned from the API",
|
|
120
|
+
EXTRACTION_FAILED: "Data extraction failed for the provided URLs",
|
|
121
|
+
ENTITY_FETCH_FAILED: "Failed to fetch entity fields"
|
|
122
|
+
};
|
|
123
|
+
var KadoaSdkException = _KadoaSdkException;
|
|
124
|
+
var ERROR_MESSAGES = KadoaSdkException.ERROR_MESSAGES;
|
|
80
125
|
var KadoaHttpException = class _KadoaHttpException extends KadoaSdkException {
|
|
81
126
|
constructor(message, options) {
|
|
82
127
|
super(message, {
|
|
@@ -117,10 +162,43 @@ var KadoaHttpException = class _KadoaHttpException extends KadoaSdkException {
|
|
|
117
162
|
responseBody: this.responseBody
|
|
118
163
|
};
|
|
119
164
|
}
|
|
120
|
-
|
|
121
|
-
const
|
|
165
|
+
toDetailedString() {
|
|
166
|
+
const parts = [`${this.name}: ${this.message}`, `Code: ${this.code}`];
|
|
167
|
+
if (this.httpStatus) {
|
|
168
|
+
parts.push(`HTTP Status: ${this.httpStatus}`);
|
|
169
|
+
}
|
|
170
|
+
if (this.method && this.endpoint) {
|
|
171
|
+
parts.push(`Request: ${this.method} ${this.endpoint}`);
|
|
172
|
+
}
|
|
173
|
+
if (this.requestId) {
|
|
174
|
+
parts.push(`Request ID: ${this.requestId}`);
|
|
175
|
+
}
|
|
176
|
+
if (this.responseBody) {
|
|
177
|
+
parts.push(
|
|
178
|
+
`Response Body: ${JSON.stringify(this.responseBody, null, 2)}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (this.details && Object.keys(this.details).length > 0) {
|
|
182
|
+
parts.push(`Details: ${JSON.stringify(this.details, null, 2)}`);
|
|
183
|
+
}
|
|
184
|
+
if (this.cause) {
|
|
185
|
+
parts.push(`Cause: ${this.cause}`);
|
|
186
|
+
}
|
|
187
|
+
return parts.join("\n");
|
|
188
|
+
}
|
|
189
|
+
static wrap(error, extra) {
|
|
190
|
+
if (error instanceof _KadoaHttpException) return error;
|
|
191
|
+
if (error instanceof KadoaSdkException) return error;
|
|
192
|
+
if (isAxiosError(error)) {
|
|
193
|
+
return _KadoaHttpException.fromAxiosError(error, extra);
|
|
194
|
+
}
|
|
195
|
+
return KadoaSdkException.wrap(error, extra);
|
|
196
|
+
}
|
|
197
|
+
static mapStatusToCode(errorOrStatus) {
|
|
198
|
+
const status = typeof errorOrStatus === "number" ? errorOrStatus : errorOrStatus.response?.status;
|
|
122
199
|
if (!status) {
|
|
123
|
-
|
|
200
|
+
if (typeof errorOrStatus === "number") return "UNKNOWN";
|
|
201
|
+
return errorOrStatus.code === "ECONNABORTED" ? "TIMEOUT" : errorOrStatus.request ? "NETWORK_ERROR" : "UNKNOWN";
|
|
124
202
|
}
|
|
125
203
|
if (status === 401 || status === 403) return "AUTH_ERROR";
|
|
126
204
|
if (status === 404) return "NOT_FOUND";
|
|
@@ -131,54 +209,6 @@ var KadoaHttpException = class _KadoaHttpException extends KadoaSdkException {
|
|
|
131
209
|
return "UNKNOWN";
|
|
132
210
|
}
|
|
133
211
|
};
|
|
134
|
-
function isKadoaSdkException(error) {
|
|
135
|
-
return error instanceof KadoaSdkException;
|
|
136
|
-
}
|
|
137
|
-
function isKadoaHttpException(error) {
|
|
138
|
-
return error instanceof KadoaHttpException;
|
|
139
|
-
}
|
|
140
|
-
function wrapKadoaError(error, extra) {
|
|
141
|
-
if (error instanceof AxiosError)
|
|
142
|
-
return KadoaHttpException.fromAxiosError(error, extra);
|
|
143
|
-
return KadoaSdkException.from(error, extra?.details);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// src/extraction/constants.ts
|
|
147
|
-
var DEFAULT_OPTIONS = {
|
|
148
|
-
pollingInterval: 5e3,
|
|
149
|
-
maxWaitTime: 3e5,
|
|
150
|
-
navigationMode: "single-page",
|
|
151
|
-
location: { type: "auto" },
|
|
152
|
-
name: "Untitled Workflow",
|
|
153
|
-
dataLimit: 100
|
|
154
|
-
};
|
|
155
|
-
var MAX_DATA_LIMIT = 99999;
|
|
156
|
-
var TERMINAL_RUN_STATES = /* @__PURE__ */ new Set([
|
|
157
|
-
"FINISHED",
|
|
158
|
-
"SUCCESS",
|
|
159
|
-
"FAILED",
|
|
160
|
-
"ERROR",
|
|
161
|
-
"STOPPED",
|
|
162
|
-
"CANCELLED"
|
|
163
|
-
]);
|
|
164
|
-
var SUCCESSFUL_RUN_STATES = /* @__PURE__ */ new Set(["FINISHED", "SUCCESS"]);
|
|
165
|
-
var ENTITY_API_ENDPOINT = "/v4/entity";
|
|
166
|
-
var DEFAULT_API_BASE_URL = "https://api.kadoa.com";
|
|
167
|
-
var ERROR_MESSAGES = {
|
|
168
|
-
NO_URLS: "At least one URL is required for extraction",
|
|
169
|
-
NO_API_KEY: "API key is required for entity detection",
|
|
170
|
-
LINK_REQUIRED: "Link is required for entity field detection",
|
|
171
|
-
NO_WORKFLOW_ID: "Failed to start extraction process - no ID received",
|
|
172
|
-
NO_PREDICTIONS: "No entity predictions returned from the API",
|
|
173
|
-
PARSE_ERROR: "Failed to parse entity response",
|
|
174
|
-
NETWORK_ERROR: "Network error while fetching entity fields",
|
|
175
|
-
AUTH_FAILED: "Authentication failed. Please check your API key",
|
|
176
|
-
RATE_LIMITED: "Rate limit exceeded. Please try again later",
|
|
177
|
-
SERVER_ERROR: "Server error while fetching entity fields",
|
|
178
|
-
DATA_FETCH_FAILED: "Failed to retrieve extracted data from workflow",
|
|
179
|
-
PROGRESS_CHECK_FAILED: "Failed to check extraction progress",
|
|
180
|
-
EXTRACTION_FAILED: "Data extraction failed for the provided URLs"
|
|
181
|
-
};
|
|
182
212
|
var BASE_PATH = "https://api.kadoa.com".replace(/\/+$/, "");
|
|
183
213
|
var BaseAPI = class {
|
|
184
214
|
constructor(configuration, basePath = BASE_PATH, axios2 = globalAxios2) {
|
|
@@ -267,7 +297,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
267
297
|
v4ChangesChangeIdGet: async (changeId, xApiKey, authorization, options = {}) => {
|
|
268
298
|
assertParamExists("v4ChangesChangeIdGet", "changeId", changeId);
|
|
269
299
|
const localVarPath = `/v4/changes/{changeId}`.replace(`{${"changeId"}}`, encodeURIComponent(String(changeId)));
|
|
270
|
-
const localVarUrlObj = new URL
|
|
300
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
271
301
|
let baseOptions;
|
|
272
302
|
if (configuration) {
|
|
273
303
|
baseOptions = configuration.baseOptions;
|
|
@@ -306,7 +336,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
306
336
|
*/
|
|
307
337
|
v4ChangesGet: async (xApiKey, authorization, workflowIds, startDate, endDate, skip, limit, options = {}) => {
|
|
308
338
|
const localVarPath = `/v4/changes`;
|
|
309
|
-
const localVarUrlObj = new URL
|
|
339
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
310
340
|
let baseOptions;
|
|
311
341
|
if (configuration) {
|
|
312
342
|
baseOptions = configuration.baseOptions;
|
|
@@ -363,7 +393,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
363
393
|
*/
|
|
364
394
|
v4WorkflowsGet: async (search, skip, limit, state, tags, monitoring, updateInterval, templateId, includeDeleted, format, options = {}) => {
|
|
365
395
|
const localVarPath = `/v4/workflows`;
|
|
366
|
-
const localVarUrlObj = new URL
|
|
396
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
367
397
|
let baseOptions;
|
|
368
398
|
if (configuration) {
|
|
369
399
|
baseOptions = configuration.baseOptions;
|
|
@@ -420,7 +450,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
420
450
|
v4WorkflowsPost: async (v4WorkflowsPostRequest, options = {}) => {
|
|
421
451
|
assertParamExists("v4WorkflowsPost", "v4WorkflowsPostRequest", v4WorkflowsPostRequest);
|
|
422
452
|
const localVarPath = `/v4/workflows`;
|
|
423
|
-
const localVarUrlObj = new URL
|
|
453
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
424
454
|
let baseOptions;
|
|
425
455
|
if (configuration) {
|
|
426
456
|
baseOptions = configuration.baseOptions;
|
|
@@ -450,7 +480,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
450
480
|
v4WorkflowsSetupEditPost: async (v4WorkflowsSetupEditPostRequest, options = {}) => {
|
|
451
481
|
assertParamExists("v4WorkflowsSetupEditPost", "v4WorkflowsSetupEditPostRequest", v4WorkflowsSetupEditPostRequest);
|
|
452
482
|
const localVarPath = `/v4/workflows/setup/edit`;
|
|
453
|
-
const localVarUrlObj = new URL
|
|
483
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
454
484
|
let baseOptions;
|
|
455
485
|
if (configuration) {
|
|
456
486
|
baseOptions = configuration.baseOptions;
|
|
@@ -479,7 +509,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
479
509
|
v4WorkflowsSetupPost: async (v4WorkflowsSetupPostRequest, options = {}) => {
|
|
480
510
|
assertParamExists("v4WorkflowsSetupPost", "v4WorkflowsSetupPostRequest", v4WorkflowsSetupPostRequest);
|
|
481
511
|
const localVarPath = `/v4/workflows/setup`;
|
|
482
|
-
const localVarUrlObj = new URL
|
|
512
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
483
513
|
let baseOptions;
|
|
484
514
|
if (configuration) {
|
|
485
515
|
baseOptions = configuration.baseOptions;
|
|
@@ -512,7 +542,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
512
542
|
v4WorkflowsWorkflowIdAuditlogGet: async (workflowId, xApiKey, authorization, page, limit, options = {}) => {
|
|
513
543
|
assertParamExists("v4WorkflowsWorkflowIdAuditlogGet", "workflowId", workflowId);
|
|
514
544
|
const localVarPath = `/v4/workflows/{workflowId}/auditlog`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
515
|
-
const localVarUrlObj = new URL
|
|
545
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
516
546
|
let baseOptions;
|
|
517
547
|
if (configuration) {
|
|
518
548
|
baseOptions = configuration.baseOptions;
|
|
@@ -554,7 +584,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
554
584
|
v4WorkflowsWorkflowIdComplianceApprovePut: async (workflowId, xApiKey, authorization, options = {}) => {
|
|
555
585
|
assertParamExists("v4WorkflowsWorkflowIdComplianceApprovePut", "workflowId", workflowId);
|
|
556
586
|
const localVarPath = `/v4/workflows/{workflowId}/compliance-approve`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
557
|
-
const localVarUrlObj = new URL
|
|
587
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
558
588
|
let baseOptions;
|
|
559
589
|
if (configuration) {
|
|
560
590
|
baseOptions = configuration.baseOptions;
|
|
@@ -591,7 +621,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
591
621
|
assertParamExists("v4WorkflowsWorkflowIdComplianceRejectPut", "workflowId", workflowId);
|
|
592
622
|
assertParamExists("v4WorkflowsWorkflowIdComplianceRejectPut", "v4WorkflowsWorkflowIdComplianceRejectPutRequest", v4WorkflowsWorkflowIdComplianceRejectPutRequest);
|
|
593
623
|
const localVarPath = `/v4/workflows/{workflowId}/compliance-reject`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
594
|
-
const localVarUrlObj = new URL
|
|
624
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
595
625
|
let baseOptions;
|
|
596
626
|
if (configuration) {
|
|
597
627
|
baseOptions = configuration.baseOptions;
|
|
@@ -638,7 +668,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
638
668
|
v4WorkflowsWorkflowIdDataGet: async (workflowId, xApiKey, authorization, runId, format, sortBy, order, filters, page, limit, gzip, rowIds, includeAnomalies, options = {}) => {
|
|
639
669
|
assertParamExists("v4WorkflowsWorkflowIdDataGet", "workflowId", workflowId);
|
|
640
670
|
const localVarPath = `/v4/workflows/{workflowId}/data`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
641
|
-
const localVarUrlObj = new URL
|
|
671
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
642
672
|
let baseOptions;
|
|
643
673
|
if (configuration) {
|
|
644
674
|
baseOptions = configuration.baseOptions;
|
|
@@ -702,7 +732,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
702
732
|
v4WorkflowsWorkflowIdDelete: async (workflowId, options = {}) => {
|
|
703
733
|
assertParamExists("v4WorkflowsWorkflowIdDelete", "workflowId", workflowId);
|
|
704
734
|
const localVarPath = `/v4/workflows/{workflowId}`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
705
|
-
const localVarUrlObj = new URL
|
|
735
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
706
736
|
let baseOptions;
|
|
707
737
|
if (configuration) {
|
|
708
738
|
baseOptions = configuration.baseOptions;
|
|
@@ -729,7 +759,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
729
759
|
v4WorkflowsWorkflowIdGet: async (workflowId, options = {}) => {
|
|
730
760
|
assertParamExists("v4WorkflowsWorkflowIdGet", "workflowId", workflowId);
|
|
731
761
|
const localVarPath = `/v4/workflows/{workflowId}`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
732
|
-
const localVarUrlObj = new URL
|
|
762
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
733
763
|
let baseOptions;
|
|
734
764
|
if (configuration) {
|
|
735
765
|
baseOptions = configuration.baseOptions;
|
|
@@ -756,7 +786,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
756
786
|
v4WorkflowsWorkflowIdHistoryGet: async (workflowId, options = {}) => {
|
|
757
787
|
assertParamExists("v4WorkflowsWorkflowIdHistoryGet", "workflowId", workflowId);
|
|
758
788
|
const localVarPath = `/v4/workflows/{workflowId}/history`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
759
|
-
const localVarUrlObj = new URL
|
|
789
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
760
790
|
let baseOptions;
|
|
761
791
|
if (configuration) {
|
|
762
792
|
baseOptions = configuration.baseOptions;
|
|
@@ -785,7 +815,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
785
815
|
assertParamExists("v4WorkflowsWorkflowIdMetadataPut", "workflowId", workflowId);
|
|
786
816
|
assertParamExists("v4WorkflowsWorkflowIdMetadataPut", "v4WorkflowsWorkflowIdMetadataPutRequest", v4WorkflowsWorkflowIdMetadataPutRequest);
|
|
787
817
|
const localVarPath = `/v4/workflows/{workflowId}/metadata`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
788
|
-
const localVarUrlObj = new URL
|
|
818
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
789
819
|
let baseOptions;
|
|
790
820
|
if (configuration) {
|
|
791
821
|
baseOptions = configuration.baseOptions;
|
|
@@ -814,7 +844,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
814
844
|
v4WorkflowsWorkflowIdPausePut: async (workflowId, options = {}) => {
|
|
815
845
|
assertParamExists("v4WorkflowsWorkflowIdPausePut", "workflowId", workflowId);
|
|
816
846
|
const localVarPath = `/v4/workflows/{workflowId}/pause`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
817
|
-
const localVarUrlObj = new URL
|
|
847
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
818
848
|
let baseOptions;
|
|
819
849
|
if (configuration) {
|
|
820
850
|
baseOptions = configuration.baseOptions;
|
|
@@ -841,7 +871,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
841
871
|
v4WorkflowsWorkflowIdResumePut: async (workflowId, options = {}) => {
|
|
842
872
|
assertParamExists("v4WorkflowsWorkflowIdResumePut", "workflowId", workflowId);
|
|
843
873
|
const localVarPath = `/v4/workflows/{workflowId}/resume`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
844
|
-
const localVarUrlObj = new URL
|
|
874
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
845
875
|
let baseOptions;
|
|
846
876
|
if (configuration) {
|
|
847
877
|
baseOptions = configuration.baseOptions;
|
|
@@ -868,7 +898,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
868
898
|
v4WorkflowsWorkflowIdRunPut: async (workflowId, options = {}) => {
|
|
869
899
|
assertParamExists("v4WorkflowsWorkflowIdRunPut", "workflowId", workflowId);
|
|
870
900
|
const localVarPath = `/v4/workflows/{workflowId}/run`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
871
|
-
const localVarUrlObj = new URL
|
|
901
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
872
902
|
let baseOptions;
|
|
873
903
|
if (configuration) {
|
|
874
904
|
baseOptions = configuration.baseOptions;
|
|
@@ -897,7 +927,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
897
927
|
assertParamExists("v4WorkflowsWorkflowIdSchedulePut", "workflowId", workflowId);
|
|
898
928
|
assertParamExists("v4WorkflowsWorkflowIdSchedulePut", "v4WorkflowsWorkflowIdSchedulePutRequest", v4WorkflowsWorkflowIdSchedulePutRequest);
|
|
899
929
|
const localVarPath = `/v4/workflows/{workflowId}/schedule`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
900
|
-
const localVarUrlObj = new URL
|
|
930
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
901
931
|
let baseOptions;
|
|
902
932
|
if (configuration) {
|
|
903
933
|
baseOptions = configuration.baseOptions;
|
|
@@ -928,7 +958,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
928
958
|
v5ChangesChangeIdGet: async (changeId, xApiKey, authorization, options = {}) => {
|
|
929
959
|
assertParamExists("v5ChangesChangeIdGet", "changeId", changeId);
|
|
930
960
|
const localVarPath = `/v5/changes/{changeId}`.replace(`{${"changeId"}}`, encodeURIComponent(String(changeId)));
|
|
931
|
-
const localVarUrlObj = new URL
|
|
961
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
932
962
|
let baseOptions;
|
|
933
963
|
if (configuration) {
|
|
934
964
|
baseOptions = configuration.baseOptions;
|
|
@@ -967,7 +997,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
967
997
|
*/
|
|
968
998
|
v5ChangesGet: async (xApiKey, authorization, workflowIds, startDate, endDate, skip, limit, options = {}) => {
|
|
969
999
|
const localVarPath = `/v5/changes`;
|
|
970
|
-
const localVarUrlObj = new URL
|
|
1000
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
971
1001
|
let baseOptions;
|
|
972
1002
|
if (configuration) {
|
|
973
1003
|
baseOptions = configuration.baseOptions;
|
|
@@ -1016,7 +1046,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
1016
1046
|
v5WorkflowsIdDelete: async (id, options = {}) => {
|
|
1017
1047
|
assertParamExists("v5WorkflowsIdDelete", "id", id);
|
|
1018
1048
|
const localVarPath = `/v5/workflows/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
|
1019
|
-
const localVarUrlObj = new URL
|
|
1049
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
1020
1050
|
let baseOptions;
|
|
1021
1051
|
if (configuration) {
|
|
1022
1052
|
baseOptions = configuration.baseOptions;
|
|
@@ -1044,7 +1074,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
1044
1074
|
v5WorkflowsIdGet: async (id, options = {}) => {
|
|
1045
1075
|
assertParamExists("v5WorkflowsIdGet", "id", id);
|
|
1046
1076
|
const localVarPath = `/v5/workflows/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
|
1047
|
-
const localVarUrlObj = new URL
|
|
1077
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
1048
1078
|
let baseOptions;
|
|
1049
1079
|
if (configuration) {
|
|
1050
1080
|
baseOptions = configuration.baseOptions;
|
|
@@ -1074,7 +1104,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
1074
1104
|
assertParamExists("v5WorkflowsIdPut", "id", id);
|
|
1075
1105
|
assertParamExists("v5WorkflowsIdPut", "v5WorkflowsIdPutRequest", v5WorkflowsIdPutRequest);
|
|
1076
1106
|
const localVarPath = `/v5/workflows/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
|
1077
|
-
const localVarUrlObj = new URL
|
|
1107
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
1078
1108
|
let baseOptions;
|
|
1079
1109
|
if (configuration) {
|
|
1080
1110
|
baseOptions = configuration.baseOptions;
|
|
@@ -1104,7 +1134,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
1104
1134
|
v5WorkflowsPost: async (v5WorkflowsPostRequest, options = {}) => {
|
|
1105
1135
|
assertParamExists("v5WorkflowsPost", "v5WorkflowsPostRequest", v5WorkflowsPostRequest);
|
|
1106
1136
|
const localVarPath = `/v5/workflows`;
|
|
1107
|
-
const localVarUrlObj = new URL
|
|
1137
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
1108
1138
|
let baseOptions;
|
|
1109
1139
|
if (configuration) {
|
|
1110
1140
|
baseOptions = configuration.baseOptions;
|
|
@@ -1138,7 +1168,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
1138
1168
|
v5WorkflowsWorkflowIdAuditlogGet: async (workflowId, xApiKey, authorization, page, limit, options = {}) => {
|
|
1139
1169
|
assertParamExists("v5WorkflowsWorkflowIdAuditlogGet", "workflowId", workflowId);
|
|
1140
1170
|
const localVarPath = `/v5/workflows/{workflowId}/auditlog`.replace(`{${"workflowId"}}`, encodeURIComponent(String(workflowId)));
|
|
1141
|
-
const localVarUrlObj = new URL
|
|
1171
|
+
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
|
1142
1172
|
let baseOptions;
|
|
1143
1173
|
if (configuration) {
|
|
1144
1174
|
baseOptions = configuration.baseOptions;
|
|
@@ -1864,405 +1894,545 @@ var Configuration = class {
|
|
|
1864
1894
|
}
|
|
1865
1895
|
};
|
|
1866
1896
|
|
|
1867
|
-
// src/
|
|
1897
|
+
// src/core/patterns/command.ts
|
|
1898
|
+
var Command = class {
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
// src/core/http/client-factory.ts
|
|
1868
1902
|
var workflowsApiCache = /* @__PURE__ */ new WeakMap();
|
|
1869
|
-
function getWorkflowsApi(
|
|
1870
|
-
let api = workflowsApiCache.get(
|
|
1903
|
+
function getWorkflowsApi(client) {
|
|
1904
|
+
let api = workflowsApiCache.get(client);
|
|
1871
1905
|
if (!api) {
|
|
1872
|
-
api = new WorkflowsApi(
|
|
1873
|
-
|
|
1906
|
+
api = new WorkflowsApi(
|
|
1907
|
+
client.configuration,
|
|
1908
|
+
client.baseUrl,
|
|
1909
|
+
client.axiosInstance
|
|
1910
|
+
);
|
|
1911
|
+
workflowsApiCache.set(client, api);
|
|
1874
1912
|
}
|
|
1875
1913
|
return api;
|
|
1876
1914
|
}
|
|
1877
1915
|
|
|
1878
|
-
// src/extraction/data-fetcher.ts
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
const response = await workflowsApi.v4WorkflowsWorkflowIdDataGet({
|
|
1883
|
-
workflowId,
|
|
1884
|
-
limit
|
|
1885
|
-
});
|
|
1886
|
-
return response.data.data ?? [];
|
|
1887
|
-
} catch (error) {
|
|
1888
|
-
throw wrapKadoaError(error, {
|
|
1889
|
-
message: ERROR_MESSAGES.DATA_FETCH_FAILED,
|
|
1890
|
-
details: { workflowId, limit }
|
|
1891
|
-
});
|
|
1916
|
+
// src/modules/extraction/services/data-fetcher.service.ts
|
|
1917
|
+
var DataFetcherService = class {
|
|
1918
|
+
constructor(client) {
|
|
1919
|
+
this.client = client;
|
|
1892
1920
|
}
|
|
1893
|
-
|
|
1921
|
+
/**
|
|
1922
|
+
* Fetch extracted data from a workflow
|
|
1923
|
+
*
|
|
1924
|
+
* @param workflowId The workflow ID to fetch data from
|
|
1925
|
+
* @param limit Maximum number of records to retrieve
|
|
1926
|
+
* @returns Array of extracted data objects
|
|
1927
|
+
*/
|
|
1928
|
+
async fetchWorkflowData(workflowId, limit) {
|
|
1929
|
+
const workflowsApi = getWorkflowsApi(this.client);
|
|
1930
|
+
try {
|
|
1931
|
+
const response = await workflowsApi.v4WorkflowsWorkflowIdDataGet({
|
|
1932
|
+
workflowId,
|
|
1933
|
+
limit
|
|
1934
|
+
});
|
|
1935
|
+
return response.data.data ?? [];
|
|
1936
|
+
} catch (error) {
|
|
1937
|
+
throw KadoaHttpException.wrap(error, {
|
|
1938
|
+
message: ERROR_MESSAGES.DATA_FETCH_FAILED,
|
|
1939
|
+
details: { workflowId, limit }
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1894
1944
|
|
|
1895
|
-
// src/
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1945
|
+
// src/core/config/constants.ts
|
|
1946
|
+
var DEFAULT_API_BASE_URL = "https://api.kadoa.com";
|
|
1947
|
+
|
|
1948
|
+
// src/modules/extraction/services/entity-detector.service.ts
|
|
1949
|
+
var ENTITY_API_ENDPOINT = "/v4/entity";
|
|
1950
|
+
var EntityDetectorService = class {
|
|
1951
|
+
constructor(client) {
|
|
1952
|
+
this.client = client;
|
|
1902
1953
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1954
|
+
/**
|
|
1955
|
+
* Fetches entity fields dynamically from the /v4/entity endpoint.
|
|
1956
|
+
* This is a workaround implementation using native fetch since the endpoint
|
|
1957
|
+
* is not yet included in the OpenAPI specification.
|
|
1958
|
+
*
|
|
1959
|
+
* @param options Request options including the link to analyze
|
|
1960
|
+
* @returns EntityPrediction containing the detected entity type and fields
|
|
1961
|
+
*/
|
|
1962
|
+
async fetchEntityFields(options) {
|
|
1963
|
+
this.validateEntityOptions(options);
|
|
1964
|
+
const url = `${this.client.baseUrl || DEFAULT_API_BASE_URL}${ENTITY_API_ENDPOINT}`;
|
|
1965
|
+
const headers = await this.buildRequestHeaders();
|
|
1966
|
+
const requestBody = options;
|
|
1967
|
+
try {
|
|
1968
|
+
const response = await this.client.axiosInstance.post(url, requestBody, {
|
|
1969
|
+
headers
|
|
1970
|
+
});
|
|
1971
|
+
const data = response.data;
|
|
1972
|
+
if (!data.success || !data.entityPrediction || data.entityPrediction.length === 0) {
|
|
1973
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_PREDICTIONS, {
|
|
1974
|
+
code: "NOT_FOUND",
|
|
1975
|
+
details: {
|
|
1976
|
+
success: data.success,
|
|
1977
|
+
hasPredictions: !!data.entityPrediction,
|
|
1978
|
+
predictionCount: data.entityPrediction?.length || 0,
|
|
1979
|
+
link: options.link
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
}
|
|
1983
|
+
return data.entityPrediction[0];
|
|
1984
|
+
} catch (error) {
|
|
1985
|
+
throw KadoaHttpException.wrap(error, {
|
|
1986
|
+
details: {
|
|
1987
|
+
url,
|
|
1988
|
+
link: options.link
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1917
1991
|
}
|
|
1918
|
-
} else {
|
|
1919
|
-
throw new KadoaSdkException(ERROR_MESSAGES.NO_API_KEY, {
|
|
1920
|
-
code: "AUTH_ERROR",
|
|
1921
|
-
details: { hasConfig: !!config, hasApiKey: !!config?.apiKey }
|
|
1922
|
-
});
|
|
1923
1992
|
}
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
}
|
|
1934
|
-
async function handleErrorResponse(response, url, link) {
|
|
1935
|
-
let errorData;
|
|
1936
|
-
let errorText = "";
|
|
1937
|
-
try {
|
|
1938
|
-
errorText = await response.text();
|
|
1939
|
-
errorData = JSON.parse(errorText);
|
|
1940
|
-
} catch {
|
|
1941
|
-
errorData = { message: errorText || response.statusText };
|
|
1942
|
-
}
|
|
1943
|
-
const baseErrorOptions = {
|
|
1944
|
-
httpStatus: response.status,
|
|
1945
|
-
endpoint: url.toString(),
|
|
1946
|
-
method: "POST",
|
|
1947
|
-
responseBody: errorData,
|
|
1948
|
-
details: {
|
|
1949
|
-
url: url.toString(),
|
|
1950
|
-
link
|
|
1993
|
+
/**
|
|
1994
|
+
* Validates entity request options
|
|
1995
|
+
*/
|
|
1996
|
+
validateEntityOptions(options) {
|
|
1997
|
+
if (!options.link) {
|
|
1998
|
+
throw new KadoaSdkException(ERROR_MESSAGES.LINK_REQUIRED, {
|
|
1999
|
+
code: "VALIDATION_ERROR",
|
|
2000
|
+
details: { options }
|
|
2001
|
+
});
|
|
1951
2002
|
}
|
|
1952
|
-
};
|
|
1953
|
-
if (response.status === 401) {
|
|
1954
|
-
throw new KadoaHttpException(ERROR_MESSAGES.AUTH_FAILED, {
|
|
1955
|
-
...baseErrorOptions,
|
|
1956
|
-
code: "AUTH_ERROR"
|
|
1957
|
-
});
|
|
1958
2003
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
2004
|
+
/**
|
|
2005
|
+
* Builds request headers including API key authentication
|
|
2006
|
+
*/
|
|
2007
|
+
async buildRequestHeaders() {
|
|
2008
|
+
const headers = {
|
|
2009
|
+
"Content-Type": "application/json",
|
|
2010
|
+
Accept: "application/json"
|
|
2011
|
+
};
|
|
2012
|
+
const config = this.client.configuration;
|
|
2013
|
+
if (config?.apiKey) {
|
|
2014
|
+
if (typeof config.apiKey === "function") {
|
|
2015
|
+
const apiKeyValue = await config.apiKey("X-API-Key");
|
|
2016
|
+
if (apiKeyValue) {
|
|
2017
|
+
headers["X-API-Key"] = apiKeyValue;
|
|
2018
|
+
}
|
|
2019
|
+
} else if (typeof config.apiKey === "string") {
|
|
2020
|
+
headers["X-API-Key"] = config.apiKey;
|
|
2021
|
+
}
|
|
2022
|
+
} else {
|
|
2023
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_API_KEY, {
|
|
2024
|
+
code: "AUTH_ERROR",
|
|
2025
|
+
details: { hasConfig: !!config, hasApiKey: !!config?.apiKey }
|
|
2026
|
+
});
|
|
1976
2027
|
}
|
|
1977
|
-
|
|
1978
|
-
}
|
|
1979
|
-
async function fetchEntityFields(app, options) {
|
|
1980
|
-
validateEntityOptions(options);
|
|
1981
|
-
const url = new URL(ENTITY_API_ENDPOINT, app.baseUrl || DEFAULT_API_BASE_URL);
|
|
1982
|
-
const headers = await buildRequestHeaders(app.configuration);
|
|
1983
|
-
const requestBody = options;
|
|
1984
|
-
let response;
|
|
1985
|
-
try {
|
|
1986
|
-
response = await fetch(url.toString(), {
|
|
1987
|
-
method: "POST",
|
|
1988
|
-
headers,
|
|
1989
|
-
body: JSON.stringify(requestBody)
|
|
1990
|
-
});
|
|
1991
|
-
} catch (error) {
|
|
1992
|
-
throw new KadoaSdkException(ERROR_MESSAGES.NETWORK_ERROR, {
|
|
1993
|
-
code: "NETWORK_ERROR",
|
|
1994
|
-
details: {
|
|
1995
|
-
url: url.toString(),
|
|
1996
|
-
link: options.link
|
|
1997
|
-
},
|
|
1998
|
-
cause: error
|
|
1999
|
-
});
|
|
2000
|
-
}
|
|
2001
|
-
if (!response.ok) {
|
|
2002
|
-
await handleErrorResponse(response, url, options.link);
|
|
2028
|
+
return headers;
|
|
2003
2029
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2030
|
+
};
|
|
2031
|
+
|
|
2032
|
+
// src/modules/extraction/services/workflow-manager.service.ts
|
|
2033
|
+
var TERMINAL_RUN_STATES = /* @__PURE__ */ new Set([
|
|
2034
|
+
"FINISHED",
|
|
2035
|
+
"SUCCESS",
|
|
2036
|
+
"FAILED",
|
|
2037
|
+
"ERROR",
|
|
2038
|
+
"STOPPED",
|
|
2039
|
+
"CANCELLED"
|
|
2040
|
+
]);
|
|
2041
|
+
var WorkflowManagerService = class {
|
|
2042
|
+
constructor(client) {
|
|
2043
|
+
this.client = client;
|
|
2016
2044
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
predictionCount: data.entityPrediction?.length || 0,
|
|
2024
|
-
link: options.link
|
|
2025
|
-
}
|
|
2026
|
-
});
|
|
2045
|
+
/**
|
|
2046
|
+
* Check if a workflow runState is terminal (finished processing)
|
|
2047
|
+
*/
|
|
2048
|
+
isTerminalRunState(runState) {
|
|
2049
|
+
if (!runState) return false;
|
|
2050
|
+
return TERMINAL_RUN_STATES.has(runState.toUpperCase());
|
|
2027
2051
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2052
|
+
/**
|
|
2053
|
+
* Creates a new workflow with the provided configuration
|
|
2054
|
+
*/
|
|
2055
|
+
async createWorkflow(config) {
|
|
2056
|
+
const workflowsApi = getWorkflowsApi(this.client);
|
|
2057
|
+
const request = {
|
|
2058
|
+
urls: config.urls,
|
|
2059
|
+
navigationMode: config.navigationMode,
|
|
2060
|
+
entity: config.entity,
|
|
2061
|
+
name: config.name,
|
|
2062
|
+
fields: config.fields,
|
|
2063
|
+
bypassPreview: true,
|
|
2064
|
+
limit: config.maxRecords,
|
|
2065
|
+
tags: ["sdk"]
|
|
2066
|
+
};
|
|
2067
|
+
try {
|
|
2068
|
+
const response = await workflowsApi.v4WorkflowsPost({
|
|
2069
|
+
v4WorkflowsPostRequest: request
|
|
2070
|
+
});
|
|
2071
|
+
const workflowId = response.data.workflowId;
|
|
2072
|
+
if (!workflowId) {
|
|
2073
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_WORKFLOW_ID, {
|
|
2074
|
+
code: "INTERNAL_ERROR",
|
|
2075
|
+
details: { response: response.data }
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
return workflowId;
|
|
2079
|
+
} catch (error) {
|
|
2080
|
+
throw KadoaHttpException.wrap(error, {
|
|
2081
|
+
message: ERROR_MESSAGES.WORKFLOW_CREATE_FAILED,
|
|
2082
|
+
details: config
|
|
2057
2083
|
});
|
|
2058
2084
|
}
|
|
2059
|
-
return workflowId;
|
|
2060
|
-
} catch (error) {
|
|
2061
|
-
throw wrapKadoaError(error, {
|
|
2062
|
-
message: "Failed to create workflow",
|
|
2063
|
-
details: config
|
|
2064
|
-
});
|
|
2065
2085
|
}
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2086
|
+
/**
|
|
2087
|
+
* Gets the current status of a workflow
|
|
2088
|
+
*/
|
|
2089
|
+
async getWorkflowStatus(workflowId) {
|
|
2090
|
+
const workflowsApi = getWorkflowsApi(this.client);
|
|
2091
|
+
try {
|
|
2092
|
+
const response = await workflowsApi.v4WorkflowsWorkflowIdGet({
|
|
2093
|
+
workflowId
|
|
2094
|
+
});
|
|
2095
|
+
return response.data;
|
|
2096
|
+
} catch (error) {
|
|
2097
|
+
throw KadoaHttpException.wrap(error, {
|
|
2098
|
+
message: ERROR_MESSAGES.PROGRESS_CHECK_FAILED,
|
|
2099
|
+
details: { workflowId }
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2079
2102
|
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2103
|
+
/**
|
|
2104
|
+
* Waits for a workflow to complete processing
|
|
2105
|
+
*
|
|
2106
|
+
* @param workflowId The workflow ID to monitor
|
|
2107
|
+
* @param pollingInterval How often to check the status (in milliseconds)
|
|
2108
|
+
* @param maxWaitTime Maximum time to wait before timing out (in milliseconds)
|
|
2109
|
+
* @param onStatusChange Optional callback for status changes
|
|
2110
|
+
* @returns The final workflow status
|
|
2111
|
+
*/
|
|
2112
|
+
async waitForWorkflowCompletion(workflowId, pollingInterval, maxWaitTime, onStatusChange) {
|
|
2113
|
+
const startTime = Date.now();
|
|
2114
|
+
let lastStatus;
|
|
2115
|
+
while (Date.now() - startTime < maxWaitTime) {
|
|
2116
|
+
const currentStatus = await this.getWorkflowStatus(workflowId);
|
|
2117
|
+
if (lastStatus?.state !== currentStatus.state || lastStatus?.runState !== currentStatus.runState) {
|
|
2118
|
+
const eventPayload = {
|
|
2119
|
+
workflowId,
|
|
2120
|
+
previousState: lastStatus?.state,
|
|
2121
|
+
previousRunState: lastStatus?.runState,
|
|
2122
|
+
currentState: currentStatus.state,
|
|
2123
|
+
currentRunState: currentStatus.runState
|
|
2124
|
+
};
|
|
2125
|
+
this.client.emit(
|
|
2126
|
+
"extraction:status_changed",
|
|
2127
|
+
eventPayload,
|
|
2128
|
+
"extraction"
|
|
2129
|
+
);
|
|
2130
|
+
if (onStatusChange) {
|
|
2131
|
+
onStatusChange(lastStatus, currentStatus);
|
|
2132
|
+
}
|
|
2100
2133
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2134
|
+
if (this.isTerminalRunState(currentStatus.runState)) {
|
|
2135
|
+
return currentStatus;
|
|
2136
|
+
}
|
|
2137
|
+
lastStatus = currentStatus;
|
|
2138
|
+
await new Promise((resolve) => setTimeout(resolve, pollingInterval));
|
|
2106
2139
|
}
|
|
2107
|
-
|
|
2140
|
+
throw new KadoaSdkException(ERROR_MESSAGES.WORKFLOW_TIMEOUT, {
|
|
2141
|
+
code: "TIMEOUT",
|
|
2142
|
+
details: {
|
|
2143
|
+
workflowId,
|
|
2144
|
+
maxWaitTime,
|
|
2145
|
+
lastState: lastStatus?.state,
|
|
2146
|
+
lastRunState: lastStatus?.runState
|
|
2147
|
+
}
|
|
2148
|
+
});
|
|
2108
2149
|
}
|
|
2109
|
-
|
|
2110
|
-
`Extraction did not complete within ${maxWaitTime / 1e3} seconds`,
|
|
2111
|
-
{ code: "TIMEOUT", details: { workflowId, maxWaitTime } }
|
|
2112
|
-
);
|
|
2113
|
-
}
|
|
2150
|
+
};
|
|
2114
2151
|
|
|
2115
|
-
// src/extraction/extraction
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2152
|
+
// src/modules/extraction/commands/run-extraction.command.ts
|
|
2153
|
+
var SUCCESSFUL_RUN_STATES = /* @__PURE__ */ new Set(["FINISHED", "SUCCESS"]);
|
|
2154
|
+
var DEFAULT_OPTIONS = {
|
|
2155
|
+
pollingInterval: 5e3,
|
|
2156
|
+
maxWaitTime: 3e5,
|
|
2157
|
+
navigationMode: "single-page",
|
|
2158
|
+
location: { type: "auto" },
|
|
2159
|
+
name: "Untitled Workflow",
|
|
2160
|
+
maxRecords: 1e3
|
|
2161
|
+
};
|
|
2162
|
+
var RunExtractionCommand = class extends Command {
|
|
2163
|
+
constructor(client) {
|
|
2164
|
+
super();
|
|
2165
|
+
this.client = client;
|
|
2166
|
+
this.dataFetcher = new DataFetcherService(client);
|
|
2167
|
+
this.entityDetector = new EntityDetectorService(client);
|
|
2168
|
+
this.workflowManager = new WorkflowManagerService(client);
|
|
2121
2169
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
options
|
|
2131
|
-
);
|
|
2132
|
-
try {
|
|
2133
|
-
const entityPrediction = await fetchEntityFields(sdkInstance, {
|
|
2134
|
-
link: config.urls[0],
|
|
2135
|
-
location: config.location,
|
|
2136
|
-
navigationMode: config.navigationMode
|
|
2137
|
-
});
|
|
2138
|
-
sdkInstance.emit(
|
|
2139
|
-
"entity:detected",
|
|
2140
|
-
{
|
|
2141
|
-
entity: entityPrediction.entity,
|
|
2142
|
-
fields: entityPrediction.fields,
|
|
2143
|
-
url: config.urls[0]
|
|
2144
|
-
},
|
|
2145
|
-
"extraction",
|
|
2146
|
-
{
|
|
2147
|
-
navigationMode: config.navigationMode,
|
|
2148
|
-
location: config.location
|
|
2149
|
-
}
|
|
2150
|
-
);
|
|
2151
|
-
const workflowId = await createWorkflow(sdkInstance, {
|
|
2152
|
-
urls: config.urls,
|
|
2153
|
-
navigationMode: config.navigationMode,
|
|
2154
|
-
entity: entityPrediction.entity,
|
|
2155
|
-
fields: entityPrediction.fields,
|
|
2156
|
-
name: config.name
|
|
2157
|
-
});
|
|
2158
|
-
sdkInstance.emit(
|
|
2159
|
-
"extraction:started",
|
|
2160
|
-
{
|
|
2161
|
-
workflowId,
|
|
2162
|
-
name: config.name,
|
|
2163
|
-
urls: config.urls
|
|
2164
|
-
},
|
|
2165
|
-
"extraction"
|
|
2170
|
+
/**
|
|
2171
|
+
* Execute the extraction workflow
|
|
2172
|
+
*/
|
|
2173
|
+
async execute(options) {
|
|
2174
|
+
this.validateOptions(options);
|
|
2175
|
+
const config = merge(
|
|
2176
|
+
DEFAULT_OPTIONS,
|
|
2177
|
+
options
|
|
2166
2178
|
);
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
if (data) {
|
|
2176
|
-
sdkInstance.emit(
|
|
2177
|
-
"extraction:data_available",
|
|
2178
|
-
{
|
|
2179
|
-
workflowId,
|
|
2180
|
-
recordCount: data.length,
|
|
2181
|
-
isPartial: false
|
|
2182
|
-
},
|
|
2183
|
-
"extraction"
|
|
2184
|
-
);
|
|
2185
|
-
}
|
|
2186
|
-
sdkInstance.emit(
|
|
2187
|
-
"extraction:completed",
|
|
2179
|
+
try {
|
|
2180
|
+
const entityPrediction = await this.entityDetector.fetchEntityFields({
|
|
2181
|
+
link: config.urls[0],
|
|
2182
|
+
location: config.location,
|
|
2183
|
+
navigationMode: config.navigationMode
|
|
2184
|
+
});
|
|
2185
|
+
this.client.emit(
|
|
2186
|
+
"entity:detected",
|
|
2188
2187
|
{
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
finalState: workflow.state,
|
|
2193
|
-
recordCount: data?.length
|
|
2188
|
+
entity: entityPrediction.entity,
|
|
2189
|
+
fields: entityPrediction.fields,
|
|
2190
|
+
url: config.urls[0]
|
|
2194
2191
|
},
|
|
2195
|
-
"extraction"
|
|
2192
|
+
"extraction",
|
|
2193
|
+
{
|
|
2194
|
+
navigationMode: config.navigationMode,
|
|
2195
|
+
location: config.location
|
|
2196
|
+
}
|
|
2196
2197
|
);
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2198
|
+
const workflowId = await this.workflowManager.createWorkflow({
|
|
2199
|
+
entity: entityPrediction.entity,
|
|
2200
|
+
fields: entityPrediction.fields,
|
|
2201
|
+
...config
|
|
2202
|
+
});
|
|
2203
|
+
this.client.emit(
|
|
2204
|
+
"extraction:started",
|
|
2200
2205
|
{
|
|
2201
2206
|
workflowId,
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
finalState: workflow.state,
|
|
2205
|
-
error: `Extraction completed with unexpected status: ${workflow.runState}`
|
|
2207
|
+
name: config.name,
|
|
2208
|
+
urls: config.urls
|
|
2206
2209
|
},
|
|
2207
2210
|
"extraction"
|
|
2208
2211
|
);
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2212
|
+
const workflow = await this.workflowManager.waitForWorkflowCompletion(
|
|
2213
|
+
workflowId,
|
|
2214
|
+
config.pollingInterval,
|
|
2215
|
+
config.maxWaitTime
|
|
2216
|
+
);
|
|
2217
|
+
let data;
|
|
2218
|
+
const isSuccess = this.isExtractionSuccessful(workflow.runState);
|
|
2219
|
+
if (isSuccess) {
|
|
2220
|
+
data = await this.dataFetcher.fetchWorkflowData(
|
|
2221
|
+
workflowId,
|
|
2222
|
+
config.maxRecords
|
|
2223
|
+
);
|
|
2224
|
+
if (data) {
|
|
2225
|
+
this.client.emit(
|
|
2226
|
+
"extraction:data_available",
|
|
2227
|
+
{
|
|
2228
|
+
workflowId,
|
|
2229
|
+
recordCount: data.length,
|
|
2230
|
+
isPartial: false
|
|
2231
|
+
},
|
|
2232
|
+
"extraction"
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2235
|
+
this.client.emit(
|
|
2236
|
+
"extraction:completed",
|
|
2237
|
+
{
|
|
2214
2238
|
workflowId,
|
|
2215
|
-
|
|
2216
|
-
|
|
2239
|
+
success: true,
|
|
2240
|
+
finalRunState: workflow.runState,
|
|
2241
|
+
finalState: workflow.state,
|
|
2242
|
+
recordCount: data?.length
|
|
2243
|
+
},
|
|
2244
|
+
"extraction"
|
|
2245
|
+
);
|
|
2246
|
+
} else {
|
|
2247
|
+
this.client.emit(
|
|
2248
|
+
"extraction:completed",
|
|
2249
|
+
{
|
|
2250
|
+
workflowId,
|
|
2251
|
+
success: false,
|
|
2252
|
+
finalRunState: workflow.runState,
|
|
2253
|
+
finalState: workflow.state,
|
|
2254
|
+
error: `Extraction completed with unexpected status: ${workflow.runState}`
|
|
2255
|
+
},
|
|
2256
|
+
"extraction"
|
|
2257
|
+
);
|
|
2258
|
+
throw new KadoaSdkException(
|
|
2259
|
+
`${ERROR_MESSAGES.WORKFLOW_UNEXPECTED_STATUS}: ${workflow.runState}`,
|
|
2260
|
+
{
|
|
2261
|
+
code: "INTERNAL_ERROR",
|
|
2262
|
+
details: {
|
|
2263
|
+
workflowId,
|
|
2264
|
+
runState: workflow.runState,
|
|
2265
|
+
state: workflow.state
|
|
2266
|
+
}
|
|
2217
2267
|
}
|
|
2218
|
-
|
|
2219
|
-
|
|
2268
|
+
);
|
|
2269
|
+
}
|
|
2270
|
+
return {
|
|
2271
|
+
workflowId,
|
|
2272
|
+
workflow,
|
|
2273
|
+
data
|
|
2274
|
+
};
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
throw KadoaHttpException.wrap(error, {
|
|
2277
|
+
message: ERROR_MESSAGES.EXTRACTION_FAILED,
|
|
2278
|
+
details: { urls: options.urls }
|
|
2279
|
+
});
|
|
2220
2280
|
}
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2281
|
+
}
|
|
2282
|
+
/**
|
|
2283
|
+
* Validates extraction options
|
|
2284
|
+
* @private
|
|
2285
|
+
*/
|
|
2286
|
+
validateOptions(options) {
|
|
2287
|
+
if (!options.urls || options.urls.length === 0) {
|
|
2288
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_URLS, {
|
|
2289
|
+
code: "VALIDATION_ERROR"
|
|
2290
|
+
});
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
/**
|
|
2294
|
+
* Checks if extraction was successful
|
|
2295
|
+
* @private
|
|
2296
|
+
*/
|
|
2297
|
+
isExtractionSuccessful(runState) {
|
|
2298
|
+
return runState ? SUCCESSFUL_RUN_STATES.has(runState.toUpperCase()) : false;
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
|
|
2302
|
+
// src/modules/extraction/extraction.module.ts
|
|
2303
|
+
var ExtractionModule = class {
|
|
2304
|
+
constructor(client) {
|
|
2305
|
+
this.runExtractionCommand = new RunExtractionCommand(client);
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Run extraction workflow using dynamic entity detection
|
|
2309
|
+
*
|
|
2310
|
+
* @param options Extraction configuration options
|
|
2311
|
+
* @returns ExtractionResult containing workflow ID, workflow details, and extracted data
|
|
2312
|
+
*
|
|
2313
|
+
* @example
|
|
2314
|
+
* ```typescript
|
|
2315
|
+
* const result = await client.extraction.run({
|
|
2316
|
+
* urls: ['https://example.com'],
|
|
2317
|
+
* name: 'My Extraction'
|
|
2318
|
+
* });
|
|
2319
|
+
* ```
|
|
2320
|
+
*/
|
|
2321
|
+
async run(options) {
|
|
2322
|
+
return this.runExtractionCommand.execute(options);
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
|
|
2326
|
+
// src/version.ts
|
|
2327
|
+
var SDK_VERSION = "0.4.0";
|
|
2328
|
+
var SDK_NAME = "kadoa-node-sdk";
|
|
2329
|
+
var SDK_LANGUAGE = "node";
|
|
2330
|
+
|
|
2331
|
+
// src/kadoa-client.ts
|
|
2332
|
+
var KadoaClient = class {
|
|
2333
|
+
constructor(config) {
|
|
2334
|
+
this._baseUrl = config.baseUrl || "https://api.kadoa.com";
|
|
2335
|
+
this._timeout = config.timeout || 3e4;
|
|
2336
|
+
const configParams = {
|
|
2337
|
+
apiKey: config.apiKey,
|
|
2338
|
+
basePath: this._baseUrl,
|
|
2339
|
+
baseOptions: {
|
|
2340
|
+
headers: {
|
|
2341
|
+
"User-Agent": `${SDK_NAME}/${SDK_VERSION}`,
|
|
2342
|
+
"X-SDK-Version": SDK_VERSION,
|
|
2343
|
+
"X-SDK-Language": SDK_LANGUAGE
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2225
2346
|
};
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2347
|
+
this._configuration = new Configuration(configParams);
|
|
2348
|
+
this._axiosInstance = globalAxios2.create({
|
|
2349
|
+
timeout: this._timeout,
|
|
2350
|
+
headers: {
|
|
2351
|
+
"User-Agent": `${SDK_NAME}/${SDK_VERSION}`,
|
|
2352
|
+
"X-SDK-Version": SDK_VERSION,
|
|
2353
|
+
"X-SDK-Language": SDK_LANGUAGE
|
|
2354
|
+
}
|
|
2230
2355
|
});
|
|
2356
|
+
this._events = new KadoaEventEmitter();
|
|
2357
|
+
this.extraction = new ExtractionModule(this);
|
|
2231
2358
|
}
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
const configuration = new Configuration(configParams);
|
|
2240
|
-
const axiosInstance = globalAxios2.create({
|
|
2241
|
-
timeout: config.timeout || 3e4
|
|
2242
|
-
});
|
|
2243
|
-
const events = new KadoaEventEmitter();
|
|
2244
|
-
return {
|
|
2245
|
-
configuration,
|
|
2246
|
-
axiosInstance,
|
|
2247
|
-
baseUrl,
|
|
2248
|
-
events,
|
|
2249
|
-
emit: (eventName, payload, source, metadata) => {
|
|
2250
|
-
events.emit(eventName, payload, source, metadata);
|
|
2251
|
-
},
|
|
2252
|
-
onEvent: (listener) => {
|
|
2253
|
-
events.onEvent(listener);
|
|
2254
|
-
},
|
|
2255
|
-
offEvent: (listener) => {
|
|
2256
|
-
events.offEvent(listener);
|
|
2257
|
-
}
|
|
2258
|
-
};
|
|
2259
|
-
}
|
|
2260
|
-
function dispose(sdkInstance) {
|
|
2261
|
-
if (sdkInstance?.events) {
|
|
2262
|
-
sdkInstance.events.removeAllListeners();
|
|
2359
|
+
/**
|
|
2360
|
+
* Register an event listener
|
|
2361
|
+
*
|
|
2362
|
+
* @param listener Function to handle events
|
|
2363
|
+
*/
|
|
2364
|
+
onEvent(listener) {
|
|
2365
|
+
this._events.onEvent(listener);
|
|
2263
2366
|
}
|
|
2264
|
-
|
|
2367
|
+
/**
|
|
2368
|
+
* Remove an event listener
|
|
2369
|
+
*
|
|
2370
|
+
* @param listener Function to remove from event handlers
|
|
2371
|
+
*/
|
|
2372
|
+
offEvent(listener) {
|
|
2373
|
+
this._events.offEvent(listener);
|
|
2374
|
+
}
|
|
2375
|
+
/**
|
|
2376
|
+
* Emit an event
|
|
2377
|
+
* @internal
|
|
2378
|
+
*
|
|
2379
|
+
* @param eventName The name of the event
|
|
2380
|
+
* @param payload The event payload
|
|
2381
|
+
* @param source Optional source identifier
|
|
2382
|
+
* @param metadata Optional metadata
|
|
2383
|
+
*/
|
|
2384
|
+
emit(eventName, payload, source, metadata) {
|
|
2385
|
+
this._events.emit(eventName, payload, source, metadata);
|
|
2386
|
+
}
|
|
2387
|
+
/**
|
|
2388
|
+
* Get the underlying configuration
|
|
2389
|
+
*
|
|
2390
|
+
* @returns The configuration object
|
|
2391
|
+
*/
|
|
2392
|
+
get configuration() {
|
|
2393
|
+
return this._configuration;
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* Get the axios instance
|
|
2397
|
+
*
|
|
2398
|
+
* @returns The axios instance
|
|
2399
|
+
*/
|
|
2400
|
+
get axiosInstance() {
|
|
2401
|
+
return this._axiosInstance;
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2404
|
+
* Get the base URL
|
|
2405
|
+
*
|
|
2406
|
+
* @returns The base URL
|
|
2407
|
+
*/
|
|
2408
|
+
get baseUrl() {
|
|
2409
|
+
return this._baseUrl;
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2412
|
+
* Get the timeout value
|
|
2413
|
+
*
|
|
2414
|
+
* @returns The timeout in milliseconds
|
|
2415
|
+
*/
|
|
2416
|
+
get timeout() {
|
|
2417
|
+
return this._timeout;
|
|
2418
|
+
}
|
|
2419
|
+
/**
|
|
2420
|
+
* Get the event emitter
|
|
2421
|
+
* @internal
|
|
2422
|
+
*
|
|
2423
|
+
* @returns The event emitter
|
|
2424
|
+
*/
|
|
2425
|
+
get events() {
|
|
2426
|
+
return this._events;
|
|
2427
|
+
}
|
|
2428
|
+
/**
|
|
2429
|
+
* Dispose of the client and clean up resources
|
|
2430
|
+
*/
|
|
2431
|
+
dispose() {
|
|
2432
|
+
this._events?.removeAllListeners();
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2265
2435
|
|
|
2266
|
-
export {
|
|
2436
|
+
export { ERROR_MESSAGES, KadoaClient, KadoaEventEmitter, KadoaHttpException, KadoaSdkException };
|
|
2267
2437
|
//# sourceMappingURL=index.mjs.map
|
|
2268
2438
|
//# sourceMappingURL=index.mjs.map
|