@kadoa/node-sdk 0.13.0 → 0.15.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/browser/index.global.js +13 -13
- package/dist/browser/index.global.js.map +1 -1
- package/dist/index.d.mts +1014 -856
- package/dist/index.d.ts +1014 -856
- package/dist/index.js +1296 -1536
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1280 -1535
- package/dist/index.mjs.map +1 -1
- package/package.json +68 -65
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var globalAxios5 = require('axios');
|
|
4
|
-
var uuid = require('uuid');
|
|
5
|
-
var url = require('url');
|
|
6
4
|
var createDebug = require('debug');
|
|
7
5
|
var esToolkit = require('es-toolkit');
|
|
8
|
-
var
|
|
6
|
+
var url = require('url');
|
|
9
7
|
var assert = require('assert');
|
|
8
|
+
var zod = require('zod');
|
|
9
|
+
var uuid = require('uuid');
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
12
|
|
|
@@ -21,7 +21,120 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
21
21
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
// src/
|
|
24
|
+
// src/domains/extraction/extraction.acl.ts
|
|
25
|
+
var FetchDataOptions = class {
|
|
26
|
+
};
|
|
27
|
+
var SchemaFieldDataType = {
|
|
28
|
+
Text: "TEXT",
|
|
29
|
+
Number: "NUMBER",
|
|
30
|
+
Date: "DATE",
|
|
31
|
+
Url: "URL",
|
|
32
|
+
Email: "EMAIL",
|
|
33
|
+
Image: "IMAGE",
|
|
34
|
+
Video: "VIDEO",
|
|
35
|
+
Phone: "PHONE",
|
|
36
|
+
Boolean: "BOOLEAN",
|
|
37
|
+
Location: "LOCATION",
|
|
38
|
+
Array: "ARRAY",
|
|
39
|
+
Object: "OBJECT"
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/runtime/pagination/paginator.ts
|
|
43
|
+
var PagedIterator = class {
|
|
44
|
+
constructor(fetchPage) {
|
|
45
|
+
this.fetchPage = fetchPage;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fetch all items across all pages
|
|
49
|
+
* @param options Base options (page will be overridden)
|
|
50
|
+
* @returns Array of all items
|
|
51
|
+
*/
|
|
52
|
+
async fetchAll(options = {}) {
|
|
53
|
+
const allItems = [];
|
|
54
|
+
let currentPage = 1;
|
|
55
|
+
let hasMore = true;
|
|
56
|
+
while (hasMore) {
|
|
57
|
+
const result = await this.fetchPage({ ...options, page: currentPage });
|
|
58
|
+
allItems.push(...result.data);
|
|
59
|
+
const pagination = result.pagination;
|
|
60
|
+
hasMore = pagination.page !== void 0 && pagination.totalPages !== void 0 && pagination.page < pagination.totalPages;
|
|
61
|
+
currentPage++;
|
|
62
|
+
}
|
|
63
|
+
return allItems;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create an async iterator for pages
|
|
67
|
+
* @param options Base options (page will be overridden)
|
|
68
|
+
* @returns Async generator that yields pages
|
|
69
|
+
*/
|
|
70
|
+
async *pages(options = {}) {
|
|
71
|
+
let currentPage = 1;
|
|
72
|
+
let hasMore = true;
|
|
73
|
+
while (hasMore) {
|
|
74
|
+
const result = await this.fetchPage({ ...options, page: currentPage });
|
|
75
|
+
yield result;
|
|
76
|
+
const pagination = result.pagination;
|
|
77
|
+
hasMore = pagination.page !== void 0 && pagination.totalPages !== void 0 && pagination.page < pagination.totalPages;
|
|
78
|
+
currentPage++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create an async iterator for individual items
|
|
83
|
+
* @param options Base options (page will be overridden)
|
|
84
|
+
* @returns Async generator that yields items
|
|
85
|
+
*/
|
|
86
|
+
async *items(options = {}) {
|
|
87
|
+
for await (const page of this.pages(options)) {
|
|
88
|
+
for (const item of page.data) {
|
|
89
|
+
yield item;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// src/domains/extraction/services/data-fetcher.service.ts
|
|
96
|
+
var DataFetcherService = class {
|
|
97
|
+
constructor(workflowsApi) {
|
|
98
|
+
this.workflowsApi = workflowsApi;
|
|
99
|
+
this.defaultLimit = 100;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Fetch a page of workflow data
|
|
103
|
+
*/
|
|
104
|
+
async fetchData(options) {
|
|
105
|
+
const response = await this.workflowsApi.v4WorkflowsWorkflowIdDataGet({
|
|
106
|
+
...options,
|
|
107
|
+
page: options.page ?? 1,
|
|
108
|
+
limit: options.limit ?? this.defaultLimit
|
|
109
|
+
});
|
|
110
|
+
const result = response.data;
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Fetch all pages of workflow data
|
|
115
|
+
*/
|
|
116
|
+
async fetchAllData(options) {
|
|
117
|
+
const iterator = new PagedIterator(
|
|
118
|
+
(pageOptions) => this.fetchData({ ...options, ...pageOptions })
|
|
119
|
+
);
|
|
120
|
+
return iterator.fetchAll({ limit: options.limit ?? this.defaultLimit });
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Create an async iterator for paginated data fetching
|
|
124
|
+
*/
|
|
125
|
+
async *fetchDataPages(options) {
|
|
126
|
+
const iterator = new PagedIterator(
|
|
127
|
+
(pageOptions) => this.fetchData({ ...options, ...pageOptions })
|
|
128
|
+
);
|
|
129
|
+
for await (const page of iterator.pages({
|
|
130
|
+
limit: options.limit ?? this.defaultLimit
|
|
131
|
+
})) {
|
|
132
|
+
yield page;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/runtime/exceptions/base.exception.ts
|
|
25
138
|
var KadoaErrorCode = {
|
|
26
139
|
AUTH_ERROR: "AUTH_ERROR",
|
|
27
140
|
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
@@ -204,6 +317,134 @@ var KadoaHttpException = class _KadoaHttpException extends KadoaSdkException {
|
|
|
204
317
|
return "UNKNOWN";
|
|
205
318
|
}
|
|
206
319
|
};
|
|
320
|
+
var createLogger = (namespace) => createDebug__default.default(`kadoa:${namespace}`);
|
|
321
|
+
var logger = {
|
|
322
|
+
client: createLogger("client"),
|
|
323
|
+
wss: createLogger("wss"),
|
|
324
|
+
extraction: createLogger("extraction"),
|
|
325
|
+
http: createLogger("http"),
|
|
326
|
+
workflow: createLogger("workflow"),
|
|
327
|
+
crawl: createLogger("crawl"),
|
|
328
|
+
notifications: createLogger("notifications"),
|
|
329
|
+
schemas: createLogger("schemas"),
|
|
330
|
+
validation: createLogger("validation")
|
|
331
|
+
};
|
|
332
|
+
var _SchemaBuilder = class _SchemaBuilder {
|
|
333
|
+
constructor() {
|
|
334
|
+
this.fields = [];
|
|
335
|
+
}
|
|
336
|
+
hasSchemaFields() {
|
|
337
|
+
return this.fields.some((field) => field.fieldType === "SCHEMA");
|
|
338
|
+
}
|
|
339
|
+
entity(entityName) {
|
|
340
|
+
this.entityName = entityName;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Add a structured field to the schema
|
|
345
|
+
* @param name - Field name (alphanumeric only)
|
|
346
|
+
* @param description - Field description
|
|
347
|
+
* @param dataType - Data type (STRING, NUMBER, BOOLEAN, etc.)
|
|
348
|
+
* @param options - Optional field configuration
|
|
349
|
+
*/
|
|
350
|
+
field(name, description, dataType, options) {
|
|
351
|
+
this.validateFieldName(name);
|
|
352
|
+
const requiresExample = _SchemaBuilder.TYPES_REQUIRING_EXAMPLE.includes(dataType);
|
|
353
|
+
if (requiresExample && !options?.example) {
|
|
354
|
+
throw new KadoaSdkException(
|
|
355
|
+
`Field "${name}" with type ${dataType} requires an example`,
|
|
356
|
+
{ code: "VALIDATION_ERROR", details: { name, dataType } }
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
this.fields.push({
|
|
360
|
+
name,
|
|
361
|
+
description,
|
|
362
|
+
dataType,
|
|
363
|
+
fieldType: "SCHEMA",
|
|
364
|
+
example: options?.example,
|
|
365
|
+
isKey: options?.isKey
|
|
366
|
+
});
|
|
367
|
+
return this;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Add a classification field to categorize content
|
|
371
|
+
* @param name - Field name (alphanumeric only)
|
|
372
|
+
* @param description - Field description
|
|
373
|
+
* @param categories - Array of category definitions
|
|
374
|
+
*/
|
|
375
|
+
classify(name, description, categories) {
|
|
376
|
+
this.validateFieldName(name);
|
|
377
|
+
this.fields.push({
|
|
378
|
+
name,
|
|
379
|
+
description,
|
|
380
|
+
fieldType: "CLASSIFICATION",
|
|
381
|
+
categories
|
|
382
|
+
});
|
|
383
|
+
return this;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Add raw page content to extract
|
|
387
|
+
* @param name - Raw content format(s): "html", "markdown", or "url"
|
|
388
|
+
*/
|
|
389
|
+
raw(name) {
|
|
390
|
+
const names = Array.isArray(name) ? name : [name];
|
|
391
|
+
for (const name2 of names) {
|
|
392
|
+
const fieldName = `raw${esToolkit.upperFirst(esToolkit.camelCase(name2))}`;
|
|
393
|
+
if (this.fields.some((field) => field.name === fieldName)) {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
this.fields.push({
|
|
397
|
+
name: fieldName,
|
|
398
|
+
description: `Raw page content in ${name2.toUpperCase()} format`,
|
|
399
|
+
fieldType: "METADATA",
|
|
400
|
+
metadataKey: name2
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
return this;
|
|
404
|
+
}
|
|
405
|
+
build() {
|
|
406
|
+
if (this.hasSchemaFields() && !this.entityName) {
|
|
407
|
+
throw new KadoaSdkException(
|
|
408
|
+
"Entity name is required when schema fields are present",
|
|
409
|
+
{
|
|
410
|
+
code: "VALIDATION_ERROR",
|
|
411
|
+
details: { entityName: this.entityName }
|
|
412
|
+
}
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
entityName: this.entityName,
|
|
417
|
+
fields: this.fields
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
validateFieldName(name) {
|
|
421
|
+
if (!_SchemaBuilder.FIELD_NAME_PATTERN.test(name)) {
|
|
422
|
+
throw new KadoaSdkException(
|
|
423
|
+
`Field name "${name}" must be alphanumeric only (no underscores or special characters)`,
|
|
424
|
+
{
|
|
425
|
+
code: "VALIDATION_ERROR",
|
|
426
|
+
details: { name, pattern: "^[A-Za-z0-9]+$" }
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
const lowerName = name.toLowerCase();
|
|
431
|
+
if (this.fields.some((f) => f.name.toLowerCase() === lowerName)) {
|
|
432
|
+
throw new KadoaSdkException(`Duplicate field name: "${name}"`, {
|
|
433
|
+
code: "VALIDATION_ERROR",
|
|
434
|
+
details: { name }
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
_SchemaBuilder.FIELD_NAME_PATTERN = /^[A-Za-z0-9]+$/;
|
|
440
|
+
_SchemaBuilder.TYPES_REQUIRING_EXAMPLE = [
|
|
441
|
+
"STRING",
|
|
442
|
+
"IMAGE",
|
|
443
|
+
"LINK",
|
|
444
|
+
"OBJECT",
|
|
445
|
+
"ARRAY"
|
|
446
|
+
];
|
|
447
|
+
var SchemaBuilder = _SchemaBuilder;
|
|
207
448
|
var BASE_PATH = "https://api.kadoa.com".replace(/\/+$/, "");
|
|
208
449
|
var BaseAPI = class {
|
|
209
450
|
constructor(configuration, basePath = BASE_PATH, axios2 = globalAxios5__default.default) {
|
|
@@ -2616,7 +2857,7 @@ var WorkflowsApiAxiosParamCreator = function(configuration) {
|
|
|
2616
2857
|
/**
|
|
2617
2858
|
* Retrieves a list of workflows with pagination and search capabilities
|
|
2618
2859
|
* @summary Get a list of workflows
|
|
2619
|
-
* @param {string} [search] Search term to filter workflows by name or
|
|
2860
|
+
* @param {string} [search] Search term to filter workflows by name, URL, or workflow ID
|
|
2620
2861
|
* @param {number} [skip] Number of items to skip
|
|
2621
2862
|
* @param {number} [limit] Maximum number of items to return
|
|
2622
2863
|
* @param {V4WorkflowsGetStateEnum} [state] Filter workflows by state
|
|
@@ -3450,7 +3691,7 @@ var WorkflowsApiFp = function(configuration) {
|
|
|
3450
3691
|
/**
|
|
3451
3692
|
* Retrieves a list of workflows with pagination and search capabilities
|
|
3452
3693
|
* @summary Get a list of workflows
|
|
3453
|
-
* @param {string} [search] Search term to filter workflows by name or
|
|
3694
|
+
* @param {string} [search] Search term to filter workflows by name, URL, or workflow ID
|
|
3454
3695
|
* @param {number} [skip] Number of items to skip
|
|
3455
3696
|
* @param {number} [limit] Maximum number of items to return
|
|
3456
3697
|
* @param {V4WorkflowsGetStateEnum} [state] Filter workflows by state
|
|
@@ -4058,809 +4299,293 @@ var Configuration = class {
|
|
|
4058
4299
|
}
|
|
4059
4300
|
};
|
|
4060
4301
|
|
|
4061
|
-
// src/
|
|
4062
|
-
var
|
|
4063
|
-
var
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
// src/internal/runtime/config/constants.ts
|
|
4067
|
-
var PUBLIC_API_URI = process.env.KADOA_PUBLIC_API_URI ?? "https://api.kadoa.com";
|
|
4068
|
-
var WSS_API_URI = process.env.KADOA_WSS_API_URI ?? "wss://realtime.kadoa.com";
|
|
4069
|
-
var REALTIME_API_URI = process.env.KADOA_REALTIME_API_URI ?? "https://realtime.kadoa.com";
|
|
4070
|
-
var createLogger = (namespace) => createDebug__default.default(`kadoa:${namespace}`);
|
|
4071
|
-
var logger = {
|
|
4072
|
-
client: createLogger("client"),
|
|
4073
|
-
wss: createLogger("wss"),
|
|
4074
|
-
extraction: createLogger("extraction"),
|
|
4075
|
-
http: createLogger("http"),
|
|
4076
|
-
workflow: createLogger("workflow"),
|
|
4077
|
-
crawl: createLogger("crawl"),
|
|
4078
|
-
notifications: createLogger("notifications"),
|
|
4079
|
-
schemas: createLogger("schemas"),
|
|
4080
|
-
validation: createLogger("validation")
|
|
4081
|
-
};
|
|
4082
|
-
|
|
4083
|
-
// src/internal/domains/realtime/realtime.ts
|
|
4084
|
-
var debug = logger.wss;
|
|
4085
|
-
if (typeof WebSocket === "undefined") {
|
|
4086
|
-
global.WebSocket = __require("ws");
|
|
4087
|
-
}
|
|
4088
|
-
var Realtime = class {
|
|
4089
|
-
constructor(config) {
|
|
4090
|
-
this.lastHeartbeat = Date.now();
|
|
4091
|
-
this.isConnecting = false;
|
|
4092
|
-
this.eventListeners = /* @__PURE__ */ new Set();
|
|
4093
|
-
this.connectionListeners = /* @__PURE__ */ new Set();
|
|
4094
|
-
this.errorListeners = /* @__PURE__ */ new Set();
|
|
4095
|
-
if (!config.teamApiKey.startsWith("tk-")) {
|
|
4096
|
-
throw new KadoaSdkException(
|
|
4097
|
-
"Realtime connection requires a team API key (starting with 'tk-'). Provided key does not appear to be a team API key.",
|
|
4098
|
-
{
|
|
4099
|
-
code: "AUTH_ERROR",
|
|
4100
|
-
details: { providedKeyPrefix: config.teamApiKey.substring(0, 3) }
|
|
4101
|
-
}
|
|
4102
|
-
);
|
|
4103
|
-
}
|
|
4104
|
-
this.teamApiKey = config.teamApiKey;
|
|
4105
|
-
this.heartbeatInterval = config.heartbeatInterval || 1e4;
|
|
4106
|
-
this.reconnectDelay = config.reconnectDelay || 5e3;
|
|
4107
|
-
this.missedHeartbeatsLimit = config.missedHeartbeatsLimit || 3e4;
|
|
4302
|
+
// src/domains/schemas/schemas.service.ts
|
|
4303
|
+
var debug = logger.schemas;
|
|
4304
|
+
var SchemasService = class {
|
|
4305
|
+
constructor(client) {
|
|
4306
|
+
this.schemasApi = new SchemasApi(client.configuration);
|
|
4108
4307
|
}
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
}
|
|
4120
|
-
});
|
|
4121
|
-
const { access_token, team_id } = await response.json();
|
|
4122
|
-
this.socket = new WebSocket(
|
|
4123
|
-
`${WSS_API_URI}?access_token=${access_token}`
|
|
4124
|
-
);
|
|
4125
|
-
this.socket.onopen = () => {
|
|
4126
|
-
this.isConnecting = false;
|
|
4127
|
-
this.lastHeartbeat = Date.now();
|
|
4128
|
-
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
4129
|
-
this.socket.send(
|
|
4130
|
-
JSON.stringify({
|
|
4131
|
-
action: "subscribe",
|
|
4132
|
-
channel: team_id
|
|
4133
|
-
})
|
|
4134
|
-
);
|
|
4135
|
-
debug("Connected to WebSocket");
|
|
4136
|
-
this.notifyConnectionListeners(true);
|
|
4308
|
+
/**
|
|
4309
|
+
* Create a schema builder with fluent API and inline create support.
|
|
4310
|
+
*/
|
|
4311
|
+
builder(entityName) {
|
|
4312
|
+
const service = this;
|
|
4313
|
+
return new class extends SchemaBuilder {
|
|
4314
|
+
constructor() {
|
|
4315
|
+
super();
|
|
4316
|
+
if (entityName) {
|
|
4317
|
+
this.entity(entityName);
|
|
4137
4318
|
}
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
method: "POST",
|
|
4149
|
-
headers: { "Content-Type": "application/json" },
|
|
4150
|
-
body: JSON.stringify({ id: data.id })
|
|
4151
|
-
});
|
|
4319
|
+
}
|
|
4320
|
+
async create(name) {
|
|
4321
|
+
const built = this.build();
|
|
4322
|
+
const schemaName = name ?? built.entityName;
|
|
4323
|
+
if (!schemaName) {
|
|
4324
|
+
throw new KadoaSdkException(
|
|
4325
|
+
"Schema name is required when entity name is not provided",
|
|
4326
|
+
{
|
|
4327
|
+
code: "VALIDATION_ERROR",
|
|
4328
|
+
details: { name }
|
|
4152
4329
|
}
|
|
4153
|
-
|
|
4154
|
-
}
|
|
4155
|
-
} catch (err) {
|
|
4156
|
-
debug("Failed to parse incoming message: %O", err);
|
|
4330
|
+
);
|
|
4157
4331
|
}
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
this.socket.onerror = (error) => {
|
|
4167
|
-
debug("WebSocket error: %O", error);
|
|
4168
|
-
this.isConnecting = false;
|
|
4169
|
-
this.notifyErrorListeners(error);
|
|
4170
|
-
};
|
|
4171
|
-
} catch (err) {
|
|
4172
|
-
debug("Failed to connect: %O", err);
|
|
4173
|
-
this.isConnecting = false;
|
|
4174
|
-
setTimeout(() => this.connect(), this.reconnectDelay);
|
|
4175
|
-
}
|
|
4176
|
-
}
|
|
4177
|
-
handleHeartbeat() {
|
|
4178
|
-
debug("Heartbeat received");
|
|
4179
|
-
this.lastHeartbeat = Date.now();
|
|
4180
|
-
}
|
|
4181
|
-
notifyEventListeners(event) {
|
|
4182
|
-
this.eventListeners.forEach((listener) => {
|
|
4183
|
-
try {
|
|
4184
|
-
listener(event);
|
|
4185
|
-
} catch (error) {
|
|
4186
|
-
debug("Error in event listener: %O", error);
|
|
4187
|
-
}
|
|
4188
|
-
});
|
|
4189
|
-
}
|
|
4190
|
-
notifyConnectionListeners(connected, reason) {
|
|
4191
|
-
this.connectionListeners.forEach((listener) => {
|
|
4192
|
-
try {
|
|
4193
|
-
listener(connected, reason);
|
|
4194
|
-
} catch (error) {
|
|
4195
|
-
debug("Error in connection listener: %O", error);
|
|
4196
|
-
}
|
|
4197
|
-
});
|
|
4198
|
-
}
|
|
4199
|
-
notifyErrorListeners(error) {
|
|
4200
|
-
this.errorListeners.forEach((listener) => {
|
|
4201
|
-
try {
|
|
4202
|
-
listener(error);
|
|
4203
|
-
} catch (error2) {
|
|
4204
|
-
debug("Error in error listener: %O", error2);
|
|
4205
|
-
}
|
|
4206
|
-
});
|
|
4207
|
-
}
|
|
4208
|
-
startHeartbeatCheck() {
|
|
4209
|
-
this.missedHeartbeatCheckTimer = setInterval(() => {
|
|
4210
|
-
if (Date.now() - this.lastHeartbeat > this.missedHeartbeatsLimit) {
|
|
4211
|
-
debug("No heartbeat received in 30 seconds! Closing connection.");
|
|
4212
|
-
this.socket?.close();
|
|
4332
|
+
const createSchemaBody = {
|
|
4333
|
+
name: schemaName,
|
|
4334
|
+
fields: built.fields,
|
|
4335
|
+
...built.entityName ? { entity: built.entityName } : {}
|
|
4336
|
+
};
|
|
4337
|
+
return service.createSchema(
|
|
4338
|
+
createSchemaBody
|
|
4339
|
+
);
|
|
4213
4340
|
}
|
|
4214
|
-
}
|
|
4215
|
-
}
|
|
4216
|
-
stopHeartbeatCheck() {
|
|
4217
|
-
if (this.missedHeartbeatCheckTimer) {
|
|
4218
|
-
clearInterval(this.missedHeartbeatCheckTimer);
|
|
4219
|
-
}
|
|
4341
|
+
}();
|
|
4220
4342
|
}
|
|
4221
4343
|
/**
|
|
4222
|
-
*
|
|
4223
|
-
* @param listener Function to handle incoming events
|
|
4224
|
-
* @returns Function to unsubscribe
|
|
4344
|
+
* Get a schema by ID
|
|
4225
4345
|
*/
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
};
|
|
4346
|
+
async getSchema(schemaId) {
|
|
4347
|
+
debug("Fetching schema with ID: %s", schemaId);
|
|
4348
|
+
const response = await this.schemasApi.v4SchemasSchemaIdGet({
|
|
4349
|
+
schemaId
|
|
4350
|
+
});
|
|
4351
|
+
const schemaData = response.data.data;
|
|
4352
|
+
if (!schemaData) {
|
|
4353
|
+
throw new KadoaSdkException(
|
|
4354
|
+
`${ERROR_MESSAGES.SCHEMA_NOT_FOUND}: ${schemaId}`,
|
|
4355
|
+
{
|
|
4356
|
+
code: KadoaErrorCode.NOT_FOUND,
|
|
4357
|
+
details: { schemaId }
|
|
4358
|
+
}
|
|
4359
|
+
);
|
|
4360
|
+
}
|
|
4361
|
+
return schemaData;
|
|
4231
4362
|
}
|
|
4232
4363
|
/**
|
|
4233
|
-
*
|
|
4234
|
-
* @param listener Function to handle connection state changes
|
|
4235
|
-
* @returns Function to unsubscribe
|
|
4364
|
+
* List all schemas
|
|
4236
4365
|
*/
|
|
4237
|
-
|
|
4238
|
-
this.
|
|
4239
|
-
return
|
|
4240
|
-
this.connectionListeners.delete(listener);
|
|
4241
|
-
};
|
|
4366
|
+
async listSchemas() {
|
|
4367
|
+
const response = await this.schemasApi.v4SchemasGet();
|
|
4368
|
+
return response.data.data;
|
|
4242
4369
|
}
|
|
4243
4370
|
/**
|
|
4244
|
-
*
|
|
4245
|
-
* @param listener Function to handle errors
|
|
4246
|
-
* @returns Function to unsubscribe
|
|
4371
|
+
* Create a new schema
|
|
4247
4372
|
*/
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
};
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
this.socket = void 0;
|
|
4373
|
+
async createSchema(body) {
|
|
4374
|
+
debug("Creating schema with name: %s", body.name);
|
|
4375
|
+
const response = await this.schemasApi.v4SchemasPost({
|
|
4376
|
+
createSchemaBody: body
|
|
4377
|
+
});
|
|
4378
|
+
const schemaId = response.data.schemaId;
|
|
4379
|
+
if (!schemaId) {
|
|
4380
|
+
throw new KadoaSdkException(ERROR_MESSAGES.SCHEMA_CREATE_FAILED, {
|
|
4381
|
+
code: KadoaErrorCode.INTERNAL_ERROR
|
|
4382
|
+
});
|
|
4259
4383
|
}
|
|
4260
|
-
this.
|
|
4261
|
-
this.connectionListeners.clear();
|
|
4262
|
-
this.errorListeners.clear();
|
|
4263
|
-
}
|
|
4264
|
-
isConnected() {
|
|
4265
|
-
return this.socket?.readyState === WebSocket.OPEN;
|
|
4266
|
-
}
|
|
4267
|
-
};
|
|
4268
|
-
|
|
4269
|
-
// src/modules/extraction.module.ts
|
|
4270
|
-
var ExtractionModule = class {
|
|
4271
|
-
constructor(extractionService, dataFetcherService, channelsService, settingsService, workflowsCoreService) {
|
|
4272
|
-
this.extractionService = extractionService;
|
|
4273
|
-
this.dataFetcherService = dataFetcherService;
|
|
4274
|
-
this.channelsService = channelsService;
|
|
4275
|
-
this.settingsService = settingsService;
|
|
4276
|
-
this.workflowsCoreService = workflowsCoreService;
|
|
4384
|
+
return this.getSchema(schemaId);
|
|
4277
4385
|
}
|
|
4278
4386
|
/**
|
|
4279
|
-
*
|
|
4280
|
-
*
|
|
4281
|
-
* @param options Extraction configuration options including optional notification settings
|
|
4282
|
-
* @returns ExtractionResult containing workflow ID, workflow details, and first page of extracted data
|
|
4283
|
-
*
|
|
4284
|
-
* @example Simple extraction with AI detection
|
|
4285
|
-
* ```typescript
|
|
4286
|
-
* const result = await client.extraction.run({
|
|
4287
|
-
* urls: ['https://example.com'],
|
|
4288
|
-
* name: 'My Extraction'
|
|
4289
|
-
* });
|
|
4290
|
-
* ```
|
|
4291
|
-
*
|
|
4292
|
-
* @example With notifications
|
|
4293
|
-
* ```typescript
|
|
4294
|
-
* const result = await client.extraction.run({
|
|
4295
|
-
* urls: ['https://example.com'],
|
|
4296
|
-
* name: 'My Extraction',
|
|
4297
|
-
* notifications: {
|
|
4298
|
-
* events: ['workflow_completed', 'workflow_failed'],
|
|
4299
|
-
* channels: {
|
|
4300
|
-
* email: true,
|
|
4301
|
-
* slack: { channelId: 'slack-channel-id' }
|
|
4302
|
-
* }
|
|
4303
|
-
* }
|
|
4304
|
-
* });
|
|
4305
|
-
* ```
|
|
4306
|
-
*
|
|
4307
|
-
* @see {@link KadoaClient.extract} For more flexible extraction configuration using the builder API
|
|
4387
|
+
* Update an existing schema
|
|
4308
4388
|
*/
|
|
4309
|
-
async
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4389
|
+
async updateSchema(schemaId, body) {
|
|
4390
|
+
debug("Updating schema with ID: %s", schemaId);
|
|
4391
|
+
await this.schemasApi.v4SchemasSchemaIdPut({
|
|
4392
|
+
schemaId,
|
|
4393
|
+
updateSchemaBody: body
|
|
4313
4394
|
});
|
|
4395
|
+
return this.getSchema(schemaId);
|
|
4314
4396
|
}
|
|
4315
4397
|
/**
|
|
4316
|
-
*
|
|
4317
|
-
*
|
|
4318
|
-
* @param options Extraction configuration options including optional notification settings
|
|
4319
|
-
* @returns SubmitExtractionResult containing workflow ID
|
|
4320
|
-
*
|
|
4321
|
-
* @example
|
|
4322
|
-
* ```typescript
|
|
4323
|
-
* const result = await client.extraction.submit({
|
|
4324
|
-
* urls: ['https://example.com'],
|
|
4325
|
-
* name: 'My Extraction',
|
|
4326
|
-
* notifications: {
|
|
4327
|
-
* events: 'all',
|
|
4328
|
-
* channels: {
|
|
4329
|
-
* email: true
|
|
4330
|
-
* }
|
|
4331
|
-
* }
|
|
4332
|
-
* });
|
|
4333
|
-
* ```
|
|
4334
|
-
*
|
|
4335
|
-
* @see {@link KadoaClient.extract} For more flexible extraction configuration using the builder API
|
|
4398
|
+
* Delete a schema
|
|
4336
4399
|
*/
|
|
4337
|
-
async
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4400
|
+
async deleteSchema(schemaId) {
|
|
4401
|
+
debug("Deleting schema with ID: %s", schemaId);
|
|
4402
|
+
await this.schemasApi.v4SchemasSchemaIdDelete({
|
|
4403
|
+
schemaId
|
|
4341
4404
|
});
|
|
4342
4405
|
}
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
*/
|
|
4352
|
-
async runJobAndWait(workflowId, input) {
|
|
4353
|
-
const result = await this.workflowsCoreService.runWorkflow(
|
|
4354
|
-
workflowId,
|
|
4355
|
-
input
|
|
4356
|
-
);
|
|
4357
|
-
return this.workflowsCoreService.waitForJobCompletion(
|
|
4358
|
-
workflowId,
|
|
4359
|
-
result.jobId
|
|
4360
|
-
);
|
|
4406
|
+
};
|
|
4407
|
+
|
|
4408
|
+
// src/domains/extraction/services/entity-resolver.service.ts
|
|
4409
|
+
var ENTITY_API_ENDPOINT = "/v4/entity";
|
|
4410
|
+
var EntityResolverService = class {
|
|
4411
|
+
constructor(client) {
|
|
4412
|
+
this.client = client;
|
|
4413
|
+
this.schemasService = new SchemasService(client);
|
|
4361
4414
|
}
|
|
4362
4415
|
/**
|
|
4363
|
-
*
|
|
4364
|
-
*
|
|
4365
|
-
* @param options Options for fetching data including workflowId and pagination parameters
|
|
4366
|
-
* @returns Paginated workflow data with metadata
|
|
4367
|
-
*
|
|
4368
|
-
* @example
|
|
4369
|
-
* ```typescript
|
|
4370
|
-
* // Fetch first page
|
|
4371
|
-
* const firstPage = await client.extraction.fetchData({
|
|
4372
|
-
* workflowId: 'workflow-id',
|
|
4373
|
-
* page: 1,
|
|
4374
|
-
* limit: 100
|
|
4375
|
-
* });
|
|
4416
|
+
* Resolves entity and fields from the provided entity configuration
|
|
4376
4417
|
*
|
|
4377
|
-
*
|
|
4378
|
-
*
|
|
4379
|
-
*
|
|
4380
|
-
* }
|
|
4381
|
-
* ```
|
|
4418
|
+
* @param entityConfig The entity configuration to resolve
|
|
4419
|
+
* @param options Additional options for AI detection
|
|
4420
|
+
* @returns Resolved entity with fields
|
|
4382
4421
|
*/
|
|
4383
|
-
async
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
* @returns Array of notification channels
|
|
4423
|
-
*
|
|
4424
|
-
* @example
|
|
4425
|
-
* ```typescript
|
|
4426
|
-
* const channels = await client.extraction.getNotificationChannels('workflow-id');
|
|
4427
|
-
* ```
|
|
4428
|
-
*/
|
|
4429
|
-
async getNotificationChannels(workflowId) {
|
|
4430
|
-
return this.channelsService.listChannels({ workflowId });
|
|
4422
|
+
async resolveEntity(entityConfig, options) {
|
|
4423
|
+
if (entityConfig === "ai-detection") {
|
|
4424
|
+
if (!options?.link) {
|
|
4425
|
+
throw new KadoaSdkException(ERROR_MESSAGES.LINK_REQUIRED, {
|
|
4426
|
+
code: "VALIDATION_ERROR",
|
|
4427
|
+
details: { entityConfig, options }
|
|
4428
|
+
});
|
|
4429
|
+
}
|
|
4430
|
+
const entityPrediction = await this.fetchEntityFields({
|
|
4431
|
+
link: options.link,
|
|
4432
|
+
location: options.location,
|
|
4433
|
+
navigationMode: options.navigationMode
|
|
4434
|
+
});
|
|
4435
|
+
const entity = entityPrediction.entity;
|
|
4436
|
+
return {
|
|
4437
|
+
entity,
|
|
4438
|
+
fields: entityPrediction.fields
|
|
4439
|
+
};
|
|
4440
|
+
} else if (entityConfig) {
|
|
4441
|
+
if ("schemaId" in entityConfig) {
|
|
4442
|
+
const schema = await this.schemasService.getSchema(
|
|
4443
|
+
entityConfig.schemaId
|
|
4444
|
+
);
|
|
4445
|
+
return {
|
|
4446
|
+
entity: schema.entity ?? void 0,
|
|
4447
|
+
fields: schema.schema
|
|
4448
|
+
};
|
|
4449
|
+
} else if ("fields" in entityConfig) {
|
|
4450
|
+
return {
|
|
4451
|
+
entity: entityConfig.name,
|
|
4452
|
+
fields: entityConfig.fields
|
|
4453
|
+
};
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
throw new KadoaSdkException(ERROR_MESSAGES.ENTITY_INVARIANT_VIOLATION, {
|
|
4457
|
+
details: {
|
|
4458
|
+
entity: entityConfig
|
|
4459
|
+
}
|
|
4460
|
+
});
|
|
4431
4461
|
}
|
|
4432
4462
|
/**
|
|
4433
|
-
*
|
|
4434
|
-
*
|
|
4435
|
-
*
|
|
4436
|
-
* @returns Array of notification settings
|
|
4463
|
+
* Fetches entity fields dynamically from the /v4/entity endpoint.
|
|
4464
|
+
* This is a workaround implementation using native fetch since the endpoint
|
|
4465
|
+
* is not yet included in the OpenAPI specification.
|
|
4437
4466
|
*
|
|
4438
|
-
* @
|
|
4439
|
-
*
|
|
4440
|
-
* const settings = await client.extraction.getNotificationSettings('workflow-id');
|
|
4441
|
-
* ```
|
|
4467
|
+
* @param options Request options including the link to analyze
|
|
4468
|
+
* @returns EntityPrediction containing the detected entity type and fields
|
|
4442
4469
|
*/
|
|
4443
|
-
async
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
this.channelSetupService = channelSetupService;
|
|
4454
|
-
}
|
|
4455
|
-
async setupForWorkflow(requestData) {
|
|
4456
|
-
const existingSettings = await this.settingsService.listSettings({
|
|
4457
|
-
workflowId: requestData.workflowId
|
|
4470
|
+
async fetchEntityFields(options) {
|
|
4471
|
+
this.validateEntityOptions(options);
|
|
4472
|
+
const url = `${this.client.baseUrl}${ENTITY_API_ENDPOINT}`;
|
|
4473
|
+
const requestBody = options;
|
|
4474
|
+
const response = await this.client.axiosInstance.post(url, requestBody, {
|
|
4475
|
+
headers: {
|
|
4476
|
+
"Content-Type": "application/json",
|
|
4477
|
+
Accept: "application/json",
|
|
4478
|
+
"x-api-key": this.client.apiKey
|
|
4479
|
+
}
|
|
4458
4480
|
});
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4481
|
+
const data = response.data;
|
|
4482
|
+
if (!data.success || !data.entityPrediction || data.entityPrediction.length === 0) {
|
|
4483
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_PREDICTIONS, {
|
|
4484
|
+
code: "NOT_FOUND",
|
|
4462
4485
|
details: {
|
|
4463
|
-
|
|
4486
|
+
success: data.success,
|
|
4487
|
+
hasPredictions: !!data.entityPrediction,
|
|
4488
|
+
predictionCount: data.entityPrediction?.length || 0,
|
|
4489
|
+
link: options.link
|
|
4464
4490
|
}
|
|
4465
4491
|
});
|
|
4466
4492
|
}
|
|
4467
|
-
return
|
|
4468
|
-
workflowId: requestData.workflowId,
|
|
4469
|
-
events: requestData.events,
|
|
4470
|
-
channels: requestData.channels
|
|
4471
|
-
});
|
|
4493
|
+
return data.entityPrediction[0];
|
|
4472
4494
|
}
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4495
|
+
/**
|
|
4496
|
+
* Validates entity request options
|
|
4497
|
+
*/
|
|
4498
|
+
validateEntityOptions(options) {
|
|
4499
|
+
if (!options.link) {
|
|
4500
|
+
throw new KadoaSdkException(ERROR_MESSAGES.LINK_REQUIRED, {
|
|
4501
|
+
code: "VALIDATION_ERROR",
|
|
4502
|
+
details: { options }
|
|
4478
4503
|
});
|
|
4479
4504
|
}
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
var debug2 = logger.extraction;
|
|
4508
|
+
var SUCCESSFUL_RUN_STATES = /* @__PURE__ */ new Set(["FINISHED", "SUCCESS"]);
|
|
4509
|
+
var DEFAULT_OPTIONS = {
|
|
4510
|
+
mode: "run",
|
|
4511
|
+
pollingInterval: 5e3,
|
|
4512
|
+
maxWaitTime: 3e5,
|
|
4513
|
+
navigationMode: "single-page",
|
|
4514
|
+
location: { type: "auto" },
|
|
4515
|
+
name: "Untitled Workflow",
|
|
4516
|
+
bypassPreview: true,
|
|
4517
|
+
autoStart: true
|
|
4518
|
+
};
|
|
4519
|
+
var ExtractionService = class {
|
|
4520
|
+
constructor(workflowsCoreService, dataFetcherService, entityResolverService, notificationSetupService, notificationChannelsService, notificationSettingsService) {
|
|
4521
|
+
this.workflowsCoreService = workflowsCoreService;
|
|
4522
|
+
this.dataFetcherService = dataFetcherService;
|
|
4523
|
+
this.entityResolverService = entityResolverService;
|
|
4524
|
+
this.notificationSetupService = notificationSetupService;
|
|
4525
|
+
this.notificationChannelsService = notificationChannelsService;
|
|
4526
|
+
this.notificationSettingsService = notificationSettingsService;
|
|
4484
4527
|
}
|
|
4485
4528
|
/**
|
|
4486
|
-
*
|
|
4529
|
+
* Run an extraction workflow and wait for completion.
|
|
4487
4530
|
*/
|
|
4488
|
-
|
|
4489
|
-
return this.
|
|
4531
|
+
async run(options) {
|
|
4532
|
+
return await this.executeExtraction({ ...options, mode: "run" });
|
|
4490
4533
|
}
|
|
4491
4534
|
/**
|
|
4492
|
-
*
|
|
4535
|
+
* Submit an extraction workflow for asynchronous processing.
|
|
4493
4536
|
*/
|
|
4494
|
-
|
|
4495
|
-
return this.
|
|
4496
|
-
}
|
|
4497
|
-
};
|
|
4498
|
-
var _SchemaBuilder = class _SchemaBuilder {
|
|
4499
|
-
constructor() {
|
|
4500
|
-
this.fields = [];
|
|
4501
|
-
}
|
|
4502
|
-
entity(entityName) {
|
|
4503
|
-
this.entityName = entityName;
|
|
4504
|
-
return this;
|
|
4537
|
+
async submit(options) {
|
|
4538
|
+
return await this.executeExtraction({ ...options, mode: "submit" });
|
|
4505
4539
|
}
|
|
4506
4540
|
/**
|
|
4507
|
-
*
|
|
4508
|
-
* @param name - Field name (alphanumeric only)
|
|
4509
|
-
* @param description - Field description
|
|
4510
|
-
* @param dataType - Data type (STRING, NUMBER, BOOLEAN, etc.)
|
|
4511
|
-
* @param options - Optional field configuration
|
|
4541
|
+
* Trigger a workflow run without waiting for completion.
|
|
4512
4542
|
*/
|
|
4513
|
-
|
|
4514
|
-
this.
|
|
4515
|
-
const requiresExample = _SchemaBuilder.TYPES_REQUIRING_EXAMPLE.includes(dataType);
|
|
4516
|
-
if (requiresExample && !options?.example) {
|
|
4517
|
-
throw new KadoaSdkException(
|
|
4518
|
-
`Field "${name}" with type ${dataType} requires an example`,
|
|
4519
|
-
{ code: "VALIDATION_ERROR", details: { name, dataType } }
|
|
4520
|
-
);
|
|
4521
|
-
}
|
|
4522
|
-
this.fields.push({
|
|
4523
|
-
name,
|
|
4524
|
-
description,
|
|
4525
|
-
dataType,
|
|
4526
|
-
fieldType: "SCHEMA",
|
|
4527
|
-
example: options?.example,
|
|
4528
|
-
isKey: options?.isKey
|
|
4529
|
-
});
|
|
4530
|
-
return this;
|
|
4543
|
+
async runJob(workflowId, input) {
|
|
4544
|
+
return await this.workflowsCoreService.runWorkflow(workflowId, input);
|
|
4531
4545
|
}
|
|
4532
4546
|
/**
|
|
4533
|
-
*
|
|
4534
|
-
* @param name - Field name (alphanumeric only)
|
|
4535
|
-
* @param description - Field description
|
|
4536
|
-
* @param categories - Array of category definitions
|
|
4547
|
+
* Trigger a workflow run and wait for the job to complete.
|
|
4537
4548
|
*/
|
|
4538
|
-
|
|
4539
|
-
this.
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4549
|
+
async runJobAndWait(workflowId, input) {
|
|
4550
|
+
const result = await this.workflowsCoreService.runWorkflow(
|
|
4551
|
+
workflowId,
|
|
4552
|
+
input
|
|
4553
|
+
);
|
|
4554
|
+
return await this.workflowsCoreService.waitForJobCompletion(
|
|
4555
|
+
workflowId,
|
|
4556
|
+
result.jobId || ""
|
|
4557
|
+
);
|
|
4547
4558
|
}
|
|
4548
4559
|
/**
|
|
4549
|
-
*
|
|
4550
|
-
* @param name - Raw content format(s): "html", "markdown", or "url"
|
|
4560
|
+
* Fetch a single page of extraction data.
|
|
4551
4561
|
*/
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
for (const name2 of names) {
|
|
4555
|
-
const fieldName = `raw${esToolkit.upperFirst(esToolkit.camelCase(name2))}`;
|
|
4556
|
-
if (this.fields.some((field) => field.name === fieldName)) {
|
|
4557
|
-
continue;
|
|
4558
|
-
}
|
|
4559
|
-
this.fields.push({
|
|
4560
|
-
name: fieldName,
|
|
4561
|
-
description: `Raw page content in ${name2.toUpperCase()} format`,
|
|
4562
|
-
fieldType: "METADATA",
|
|
4563
|
-
metadataKey: name2
|
|
4564
|
-
});
|
|
4565
|
-
}
|
|
4566
|
-
return this;
|
|
4567
|
-
}
|
|
4568
|
-
build() {
|
|
4569
|
-
if (!this.entityName) {
|
|
4570
|
-
throw new KadoaSdkException("Entity name is required", {
|
|
4571
|
-
code: "VALIDATION_ERROR",
|
|
4572
|
-
details: { entityName: this.entityName }
|
|
4573
|
-
});
|
|
4574
|
-
}
|
|
4575
|
-
return {
|
|
4576
|
-
entityName: this.entityName,
|
|
4577
|
-
fields: this.fields
|
|
4578
|
-
};
|
|
4579
|
-
}
|
|
4580
|
-
validateFieldName(name) {
|
|
4581
|
-
if (!_SchemaBuilder.FIELD_NAME_PATTERN.test(name)) {
|
|
4582
|
-
throw new KadoaSdkException(
|
|
4583
|
-
`Field name "${name}" must be alphanumeric only (no underscores or special characters)`,
|
|
4584
|
-
{
|
|
4585
|
-
code: "VALIDATION_ERROR",
|
|
4586
|
-
details: { name, pattern: "^[A-Za-z0-9]+$" }
|
|
4587
|
-
}
|
|
4588
|
-
);
|
|
4589
|
-
}
|
|
4590
|
-
const lowerName = name.toLowerCase();
|
|
4591
|
-
if (this.fields.some((f) => f.name.toLowerCase() === lowerName)) {
|
|
4592
|
-
throw new KadoaSdkException(`Duplicate field name: "${name}"`, {
|
|
4593
|
-
code: "VALIDATION_ERROR",
|
|
4594
|
-
details: { name }
|
|
4595
|
-
});
|
|
4596
|
-
}
|
|
4562
|
+
async fetchData(options) {
|
|
4563
|
+
return await this.dataFetcherService.fetchData(options);
|
|
4597
4564
|
}
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
"LINK",
|
|
4604
|
-
"OBJECT",
|
|
4605
|
-
"ARRAY"
|
|
4606
|
-
];
|
|
4607
|
-
var SchemaBuilder = _SchemaBuilder;
|
|
4608
|
-
|
|
4609
|
-
// src/modules/schemas.module.ts
|
|
4610
|
-
var SchemaBuilderWithCreate = class extends SchemaBuilder {
|
|
4611
|
-
constructor(entityName, service) {
|
|
4612
|
-
super();
|
|
4613
|
-
this.service = service;
|
|
4614
|
-
this.entity(entityName);
|
|
4565
|
+
/**
|
|
4566
|
+
* Fetch all extraction data across all pages.
|
|
4567
|
+
*/
|
|
4568
|
+
async fetchAllData(options) {
|
|
4569
|
+
return await this.dataFetcherService.fetchAllData(options);
|
|
4615
4570
|
}
|
|
4616
4571
|
/**
|
|
4617
|
-
*
|
|
4618
|
-
* @param name - Optional schema name (defaults to entity name)
|
|
4619
|
-
* @returns Promise resolving to the created schema
|
|
4572
|
+
* Iterate through extraction data pages.
|
|
4620
4573
|
*/
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
return this.service.createSchema({
|
|
4624
|
-
name: name || built.entityName,
|
|
4625
|
-
entity: built.entityName,
|
|
4626
|
-
fields: built.fields
|
|
4627
|
-
});
|
|
4574
|
+
fetchDataPages(options) {
|
|
4575
|
+
return this.dataFetcherService.fetchDataPages(options);
|
|
4628
4576
|
}
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4577
|
+
/**
|
|
4578
|
+
* List notification channels for a workflow.
|
|
4579
|
+
*/
|
|
4580
|
+
async getNotificationChannels(workflowId) {
|
|
4581
|
+
return await this.notificationChannelsService.listChannels({ workflowId });
|
|
4633
4582
|
}
|
|
4634
4583
|
/**
|
|
4635
|
-
*
|
|
4636
|
-
* @param entityName - The name of the entity this schema represents
|
|
4637
|
-
* @returns A new SchemaBuilder instance with the entity name already set
|
|
4638
|
-
* @example Build then create
|
|
4639
|
-
* ```typescript
|
|
4640
|
-
* const schema = kadoa.schema.builder("Product")
|
|
4641
|
-
* .field("title", "Product name", "STRING", { example: "iPhone 15" })
|
|
4642
|
-
* .field("price", "Product price", "NUMBER")
|
|
4643
|
-
* .build();
|
|
4644
|
-
*
|
|
4645
|
-
* await kadoa.schema.create(schema);
|
|
4646
|
-
* ```
|
|
4647
|
-
*
|
|
4648
|
-
* @example Fluent chain with create
|
|
4649
|
-
* ```typescript
|
|
4650
|
-
* const schema = await kadoa.schema.builder("Product")
|
|
4651
|
-
* .field("title", "Product name", "STRING", { example: "iPhone 15" })
|
|
4652
|
-
* .field("price", "Product price", "NUMBER")
|
|
4653
|
-
* .create("Product Schema");
|
|
4654
|
-
* ```
|
|
4655
|
-
*/
|
|
4656
|
-
builder(entityName) {
|
|
4657
|
-
return new SchemaBuilderWithCreate(entityName, this.service);
|
|
4658
|
-
}
|
|
4659
|
-
/**
|
|
4660
|
-
* Get a schema by ID
|
|
4661
|
-
*/
|
|
4662
|
-
async get(schemaId) {
|
|
4663
|
-
return this.service.getSchema(schemaId);
|
|
4664
|
-
}
|
|
4665
|
-
/**
|
|
4666
|
-
* List all schemas
|
|
4667
|
-
*/
|
|
4668
|
-
async list() {
|
|
4669
|
-
return this.service.listSchemas();
|
|
4670
|
-
}
|
|
4671
|
-
/**
|
|
4672
|
-
* Create a new schema from a body
|
|
4673
|
-
*/
|
|
4674
|
-
async create(body) {
|
|
4675
|
-
return this.service.createSchema(body);
|
|
4676
|
-
}
|
|
4677
|
-
/**
|
|
4678
|
-
* Update an existing schema
|
|
4679
|
-
*/
|
|
4680
|
-
async update(schemaId, body) {
|
|
4681
|
-
return this.service.updateSchema(schemaId, body);
|
|
4682
|
-
}
|
|
4683
|
-
/**
|
|
4684
|
-
* Delete a schema
|
|
4685
|
-
*/
|
|
4686
|
-
async delete(schemaId) {
|
|
4687
|
-
return this.service.deleteSchema(schemaId);
|
|
4688
|
-
}
|
|
4689
|
-
};
|
|
4690
|
-
|
|
4691
|
-
// src/modules/user.module.ts
|
|
4692
|
-
var UserModule = class {
|
|
4693
|
-
constructor(userService) {
|
|
4694
|
-
this.userService = userService;
|
|
4695
|
-
}
|
|
4696
|
-
/**
|
|
4697
|
-
* Get the underlying UserService instance
|
|
4698
|
-
* @returns UserService instance
|
|
4699
|
-
*/
|
|
4700
|
-
get service() {
|
|
4701
|
-
return this.userService;
|
|
4702
|
-
}
|
|
4703
|
-
/**
|
|
4704
|
-
* Get current user details
|
|
4705
|
-
* @returns KadoaUser details
|
|
4706
|
-
*/
|
|
4707
|
-
async getCurrentUser() {
|
|
4708
|
-
return this.userService.getCurrentUser();
|
|
4709
|
-
}
|
|
4710
|
-
};
|
|
4711
|
-
|
|
4712
|
-
// src/modules/validation.module.ts
|
|
4713
|
-
var ValidationModule = class {
|
|
4714
|
-
constructor(coreService, rulesService) {
|
|
4715
|
-
this.coreService = coreService;
|
|
4716
|
-
this.rulesService = rulesService;
|
|
4717
|
-
}
|
|
4718
|
-
listRules(options) {
|
|
4719
|
-
return this.rulesService.listRules(options);
|
|
4720
|
-
}
|
|
4721
|
-
getRuleByName(name) {
|
|
4722
|
-
return this.rulesService.getRuleByName(name);
|
|
4723
|
-
}
|
|
4724
|
-
createRule(data) {
|
|
4725
|
-
return this.rulesService.createRule(data);
|
|
4726
|
-
}
|
|
4727
|
-
generateRule(data) {
|
|
4728
|
-
return this.rulesService.generateRule(data);
|
|
4729
|
-
}
|
|
4730
|
-
generateRules(data) {
|
|
4731
|
-
return this.rulesService.generateRules(data);
|
|
4732
|
-
}
|
|
4733
|
-
bulkApproveRules(data) {
|
|
4734
|
-
return this.rulesService.bulkApproveRules(data);
|
|
4735
|
-
}
|
|
4736
|
-
bulkDeleteRules(data) {
|
|
4737
|
-
return this.rulesService.bulkDeleteRules(data);
|
|
4738
|
-
}
|
|
4739
|
-
deleteAllRules(data) {
|
|
4740
|
-
return this.rulesService.deleteAllRules(data);
|
|
4741
|
-
}
|
|
4742
|
-
listWorkflowValidations(workflowId, jobId) {
|
|
4743
|
-
return this.coreService.listWorkflowValidations({ workflowId, jobId });
|
|
4744
|
-
}
|
|
4745
|
-
scheduleValidation(workflowId, jobId) {
|
|
4746
|
-
return this.coreService.scheduleValidation(workflowId, jobId);
|
|
4747
|
-
}
|
|
4748
|
-
waitUntilCompleted(validationId, options) {
|
|
4749
|
-
return this.coreService.waitUntilCompleted(validationId, options);
|
|
4750
|
-
}
|
|
4751
|
-
getValidationDetails(validationId) {
|
|
4752
|
-
return this.coreService.getValidationDetails(validationId);
|
|
4753
|
-
}
|
|
4754
|
-
getLatestValidation(workflowId, jobId) {
|
|
4755
|
-
return this.coreService.getLatestValidation(workflowId, jobId);
|
|
4756
|
-
}
|
|
4757
|
-
getValidationAnomalies(validationId) {
|
|
4758
|
-
return this.coreService.getValidationAnomalies(validationId);
|
|
4759
|
-
}
|
|
4760
|
-
getValidationAnomaliesByRule(validationId, ruleName) {
|
|
4761
|
-
return this.coreService.getValidationAnomaliesByRule(
|
|
4762
|
-
validationId,
|
|
4763
|
-
ruleName
|
|
4764
|
-
);
|
|
4765
|
-
}
|
|
4766
|
-
toggleValidationEnabled(workflowId) {
|
|
4767
|
-
return this.coreService.toggleValidationEnabled(workflowId);
|
|
4768
|
-
}
|
|
4769
|
-
};
|
|
4770
|
-
|
|
4771
|
-
// src/modules/workflows.module.ts
|
|
4772
|
-
var WorkflowsModule = class {
|
|
4773
|
-
constructor(core) {
|
|
4774
|
-
this.core = core;
|
|
4775
|
-
}
|
|
4776
|
-
async get(workflowId) {
|
|
4777
|
-
return this.core.get(workflowId);
|
|
4778
|
-
}
|
|
4779
|
-
async list(filters) {
|
|
4780
|
-
return this.core.list(filters);
|
|
4781
|
-
}
|
|
4782
|
-
async getByName(name) {
|
|
4783
|
-
return this.core.getByName(name);
|
|
4784
|
-
}
|
|
4785
|
-
async create(input) {
|
|
4786
|
-
return this.core.create(input);
|
|
4787
|
-
}
|
|
4788
|
-
async cancel(workflowId) {
|
|
4789
|
-
return this.core.cancel(workflowId);
|
|
4790
|
-
}
|
|
4791
|
-
async approve(workflowId) {
|
|
4792
|
-
return this.core.resume(workflowId);
|
|
4793
|
-
}
|
|
4794
|
-
async resume(workflowId) {
|
|
4795
|
-
return this.core.resume(workflowId);
|
|
4796
|
-
}
|
|
4797
|
-
async wait(workflowId, options) {
|
|
4798
|
-
return this.core.wait(workflowId, options);
|
|
4799
|
-
}
|
|
4800
|
-
/**
|
|
4801
|
-
* Get job status directly without polling workflow details
|
|
4802
|
-
*/
|
|
4803
|
-
async getJobStatus(workflowId, jobId) {
|
|
4804
|
-
return this.core.getJobStatus(workflowId, jobId);
|
|
4805
|
-
}
|
|
4806
|
-
/**
|
|
4807
|
-
* Wait for a job to complete using the job status endpoint
|
|
4584
|
+
* List notification settings for a workflow.
|
|
4808
4585
|
*/
|
|
4809
|
-
async
|
|
4810
|
-
return this.
|
|
4811
|
-
}
|
|
4812
|
-
};
|
|
4813
|
-
|
|
4814
|
-
// src/internal/domains/user/user.service.ts
|
|
4815
|
-
var UserService = class {
|
|
4816
|
-
constructor(client) {
|
|
4817
|
-
this.client = client;
|
|
4818
|
-
}
|
|
4819
|
-
/**
|
|
4820
|
-
* Get current user details
|
|
4821
|
-
* @returns User details
|
|
4822
|
-
*/
|
|
4823
|
-
async getCurrentUser() {
|
|
4824
|
-
const response = await this.client.axiosInstance.get("/v5/user", {
|
|
4825
|
-
baseURL: this.client.baseUrl,
|
|
4826
|
-
headers: {
|
|
4827
|
-
"x-api-key": this.client.apiKey,
|
|
4828
|
-
"Content-Type": "application/json"
|
|
4829
|
-
}
|
|
4830
|
-
});
|
|
4831
|
-
const userData = response.data;
|
|
4832
|
-
if (!userData || !userData.userId) {
|
|
4833
|
-
throw new KadoaSdkException("Invalid user data received");
|
|
4834
|
-
}
|
|
4835
|
-
return {
|
|
4836
|
-
userId: userData.userId,
|
|
4837
|
-
email: userData.email,
|
|
4838
|
-
featureFlags: userData.featureFlags || []
|
|
4839
|
-
};
|
|
4840
|
-
}
|
|
4841
|
-
};
|
|
4842
|
-
var debug2 = logger.extraction;
|
|
4843
|
-
var SUCCESSFUL_RUN_STATES = /* @__PURE__ */ new Set(["FINISHED", "SUCCESS"]);
|
|
4844
|
-
var DEFAULT_OPTIONS = {
|
|
4845
|
-
mode: "run",
|
|
4846
|
-
pollingInterval: 5e3,
|
|
4847
|
-
maxWaitTime: 3e5,
|
|
4848
|
-
navigationMode: "single-page",
|
|
4849
|
-
location: { type: "auto" },
|
|
4850
|
-
name: "Untitled Workflow",
|
|
4851
|
-
bypassPreview: true,
|
|
4852
|
-
autoStart: true
|
|
4853
|
-
};
|
|
4854
|
-
var ExtractionService = class {
|
|
4855
|
-
constructor(workflowsCoreService, dataFetcherService, entityResolverService, notificationSetupService) {
|
|
4856
|
-
this.workflowsCoreService = workflowsCoreService;
|
|
4857
|
-
this.dataFetcherService = dataFetcherService;
|
|
4858
|
-
this.entityResolverService = entityResolverService;
|
|
4859
|
-
this.notificationSetupService = notificationSetupService;
|
|
4586
|
+
async getNotificationSettings(workflowId) {
|
|
4587
|
+
return await this.notificationSettingsService.listSettings({ workflowId });
|
|
4860
4588
|
}
|
|
4861
|
-
/**
|
|
4862
|
-
* execute extraction workflow
|
|
4863
|
-
*/
|
|
4864
4589
|
async executeExtraction(options) {
|
|
4865
4590
|
this.validateOptions(options);
|
|
4866
4591
|
const config = esToolkit.merge(
|
|
@@ -4877,11 +4602,12 @@ var ExtractionService = class {
|
|
|
4877
4602
|
}
|
|
4878
4603
|
);
|
|
4879
4604
|
const hasNotifications = !!config.notifications;
|
|
4880
|
-
const
|
|
4605
|
+
const workflowRequest = {
|
|
4881
4606
|
...config,
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
}
|
|
4607
|
+
fields: resolvedEntity.fields,
|
|
4608
|
+
...resolvedEntity.entity !== void 0 ? { entity: resolvedEntity.entity } : {}
|
|
4609
|
+
};
|
|
4610
|
+
const result = await this.workflowsCoreService.create(workflowRequest);
|
|
4885
4611
|
workflowId = result.id;
|
|
4886
4612
|
if (hasNotifications) {
|
|
4887
4613
|
const result2 = await this.notificationSetupService.setup({
|
|
@@ -4983,90 +4709,261 @@ var ExtractionService = class {
|
|
|
4983
4709
|
return runState ? SUCCESSFUL_RUN_STATES.has(runState.toUpperCase()) : false;
|
|
4984
4710
|
}
|
|
4985
4711
|
};
|
|
4986
|
-
var
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
recipients: zod.z.array(zod.z.email()).min(1, "Recipients are required for email channel"),
|
|
4994
|
-
from: zod.z.email().refine(
|
|
4995
|
-
(email) => email.endsWith("@kadoa.com"),
|
|
4996
|
-
"From email address must end with @kadoa.com"
|
|
4997
|
-
).optional()
|
|
4998
|
-
});
|
|
4999
|
-
var _NotificationChannelsService = class _NotificationChannelsService {
|
|
5000
|
-
constructor(notificationsApi, userService) {
|
|
5001
|
-
this.api = notificationsApi;
|
|
5002
|
-
this.userService = userService;
|
|
4712
|
+
var debug3 = logger.extraction;
|
|
4713
|
+
var ExtractionBuilderService = class {
|
|
4714
|
+
constructor(workflowsCoreService, entityResolverService, dataFetcherService, notificationSetupService) {
|
|
4715
|
+
this.workflowsCoreService = workflowsCoreService;
|
|
4716
|
+
this.entityResolverService = entityResolverService;
|
|
4717
|
+
this.dataFetcherService = dataFetcherService;
|
|
4718
|
+
this.notificationSetupService = notificationSetupService;
|
|
5003
4719
|
}
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
if (!data) {
|
|
5008
|
-
throw KadoaHttpException.wrap(response, {
|
|
5009
|
-
message: "Failed to list channels"
|
|
5010
|
-
});
|
|
5011
|
-
}
|
|
5012
|
-
return data;
|
|
4720
|
+
get options() {
|
|
4721
|
+
assert__default.default(this._options, "Options are not set");
|
|
4722
|
+
return this._options;
|
|
5013
4723
|
}
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
* This is useful for finding workspace-level channels like WebSocket channels
|
|
5017
|
-
* that might not be associated with a specific workflow
|
|
5018
|
-
*/
|
|
5019
|
-
async listAllChannels(workflowId) {
|
|
5020
|
-
if (!workflowId) {
|
|
5021
|
-
return this.listChannels({});
|
|
5022
|
-
}
|
|
5023
|
-
const [workflowChannels, workspaceChannels] = await Promise.all([
|
|
5024
|
-
this.listChannels({ workflowId }),
|
|
5025
|
-
this.listChannels({})
|
|
5026
|
-
]);
|
|
5027
|
-
const allChannels = [...workflowChannels];
|
|
5028
|
-
workspaceChannels.forEach((channel) => {
|
|
5029
|
-
if (!allChannels.find((c) => c.id === channel.id)) {
|
|
5030
|
-
allChannels.push(channel);
|
|
5031
|
-
}
|
|
5032
|
-
});
|
|
5033
|
-
return allChannels;
|
|
4724
|
+
get notificationOptions() {
|
|
4725
|
+
return this._notificationOptions;
|
|
5034
4726
|
}
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
channelId
|
|
5038
|
-
});
|
|
5039
|
-
if (response.status !== 200) {
|
|
5040
|
-
throw KadoaHttpException.wrap(response, {
|
|
5041
|
-
message: "Failed to delete channel"
|
|
5042
|
-
});
|
|
5043
|
-
}
|
|
4727
|
+
get monitoringOptions() {
|
|
4728
|
+
return this._monitoringOptions;
|
|
5044
4729
|
}
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
4730
|
+
get workflowId() {
|
|
4731
|
+
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
4732
|
+
return this._workflowId;
|
|
4733
|
+
}
|
|
4734
|
+
get jobId() {
|
|
4735
|
+
assert__default.default(this._jobId, "Job ID is not set");
|
|
4736
|
+
return this._jobId;
|
|
4737
|
+
}
|
|
4738
|
+
extract({
|
|
4739
|
+
urls,
|
|
4740
|
+
name,
|
|
4741
|
+
description,
|
|
4742
|
+
navigationMode,
|
|
4743
|
+
extraction
|
|
4744
|
+
}) {
|
|
4745
|
+
let entity = "ai-detection";
|
|
4746
|
+
if (extraction) {
|
|
4747
|
+
const result = extraction(new SchemaBuilder());
|
|
4748
|
+
if ("schemaId" in result) {
|
|
4749
|
+
entity = { schemaId: result.schemaId };
|
|
4750
|
+
} else {
|
|
4751
|
+
const builtSchema = result.build();
|
|
4752
|
+
entity = builtSchema.entityName ? { name: builtSchema.entityName, fields: builtSchema.fields } : { fields: builtSchema.fields };
|
|
5062
4753
|
}
|
|
5063
|
-
return data;
|
|
5064
4754
|
}
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
4755
|
+
this._options = {
|
|
4756
|
+
urls,
|
|
4757
|
+
name,
|
|
4758
|
+
description,
|
|
4759
|
+
navigationMode: navigationMode || "single-page",
|
|
4760
|
+
entity,
|
|
4761
|
+
bypassPreview: false
|
|
4762
|
+
};
|
|
4763
|
+
return this;
|
|
5068
4764
|
}
|
|
5069
|
-
|
|
4765
|
+
withNotifications(options) {
|
|
4766
|
+
this._notificationOptions = options;
|
|
4767
|
+
return this;
|
|
4768
|
+
}
|
|
4769
|
+
withMonitoring(options) {
|
|
4770
|
+
this._monitoringOptions = options;
|
|
4771
|
+
return this;
|
|
4772
|
+
}
|
|
4773
|
+
bypassPreview() {
|
|
4774
|
+
assert__default.default(this._options, "Options are not set");
|
|
4775
|
+
this._options.bypassPreview = true;
|
|
4776
|
+
return this;
|
|
4777
|
+
}
|
|
4778
|
+
setInterval(options) {
|
|
4779
|
+
assert__default.default(this._options, "Options are not set");
|
|
4780
|
+
if ("interval" in options) {
|
|
4781
|
+
this._options.interval = options.interval;
|
|
4782
|
+
} else {
|
|
4783
|
+
this._options.interval = "CUSTOM";
|
|
4784
|
+
this._options.schedules = options.schedules;
|
|
4785
|
+
}
|
|
4786
|
+
return this;
|
|
4787
|
+
}
|
|
4788
|
+
setLocation(options) {
|
|
4789
|
+
assert__default.default(this._options, "Options are not set");
|
|
4790
|
+
this._options.location = options;
|
|
4791
|
+
return this;
|
|
4792
|
+
}
|
|
4793
|
+
async create() {
|
|
4794
|
+
assert__default.default(this._options, "Options are not set");
|
|
4795
|
+
const { urls, name, description, navigationMode, entity } = this.options;
|
|
4796
|
+
const resolvedEntity = await this.entityResolverService.resolveEntity(
|
|
4797
|
+
entity,
|
|
4798
|
+
{
|
|
4799
|
+
link: urls[0],
|
|
4800
|
+
location: this._options.location,
|
|
4801
|
+
navigationMode
|
|
4802
|
+
}
|
|
4803
|
+
);
|
|
4804
|
+
const workflow = await this.workflowsCoreService.create({
|
|
4805
|
+
urls,
|
|
4806
|
+
name,
|
|
4807
|
+
description,
|
|
4808
|
+
navigationMode,
|
|
4809
|
+
monitoring: this._monitoringOptions,
|
|
4810
|
+
schemaId: typeof entity === "object" && "schemaId" in entity ? entity.schemaId : void 0,
|
|
4811
|
+
entity: resolvedEntity.entity,
|
|
4812
|
+
fields: resolvedEntity.fields,
|
|
4813
|
+
autoStart: false,
|
|
4814
|
+
interval: this._options.interval,
|
|
4815
|
+
schedules: this._options.schedules
|
|
4816
|
+
});
|
|
4817
|
+
if (this._notificationOptions) {
|
|
4818
|
+
await this.notificationSetupService.setup({
|
|
4819
|
+
...this._notificationOptions,
|
|
4820
|
+
workflowId: workflow.id
|
|
4821
|
+
});
|
|
4822
|
+
}
|
|
4823
|
+
this._workflowId = workflow.id;
|
|
4824
|
+
return this;
|
|
4825
|
+
}
|
|
4826
|
+
async run(options) {
|
|
4827
|
+
assert__default.default(this._options, "Options are not set");
|
|
4828
|
+
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
4829
|
+
const startedJob = await this.workflowsCoreService.runWorkflow(
|
|
4830
|
+
this._workflowId,
|
|
4831
|
+
{ variables: options?.variables, limit: options?.limit }
|
|
4832
|
+
);
|
|
4833
|
+
assert__default.default(startedJob.jobId, "Job ID is not set");
|
|
4834
|
+
debug3("Job started: %O", startedJob);
|
|
4835
|
+
this._jobId = startedJob.jobId;
|
|
4836
|
+
const finishedJob = await this.workflowsCoreService.waitForJobCompletion(
|
|
4837
|
+
this._workflowId,
|
|
4838
|
+
startedJob.jobId
|
|
4839
|
+
);
|
|
4840
|
+
debug3("Job finished: %O", finishedJob);
|
|
4841
|
+
return this;
|
|
4842
|
+
}
|
|
4843
|
+
async submit(options) {
|
|
4844
|
+
assert__default.default(this._options, "Options are not set");
|
|
4845
|
+
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
4846
|
+
const submittedJob = await this.workflowsCoreService.runWorkflow(
|
|
4847
|
+
this._workflowId,
|
|
4848
|
+
{ variables: options?.variables, limit: options?.limit }
|
|
4849
|
+
);
|
|
4850
|
+
assert__default.default(submittedJob.jobId, "Job ID is not set");
|
|
4851
|
+
debug3("Job submitted: %O", submittedJob);
|
|
4852
|
+
this._jobId = submittedJob.jobId;
|
|
4853
|
+
return {
|
|
4854
|
+
workflowId: this._workflowId,
|
|
4855
|
+
jobId: this._jobId
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
async fetchData(options) {
|
|
4859
|
+
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
4860
|
+
assert__default.default(this._jobId, "Job ID is not set");
|
|
4861
|
+
return this.dataFetcherService.fetchData({
|
|
4862
|
+
workflowId: this._workflowId,
|
|
4863
|
+
runId: this._jobId,
|
|
4864
|
+
page: options.page ?? 1,
|
|
4865
|
+
limit: options.limit ?? 100,
|
|
4866
|
+
...options
|
|
4867
|
+
});
|
|
4868
|
+
}
|
|
4869
|
+
async fetchAllData(options) {
|
|
4870
|
+
assert__default.default(this._jobId, "Job ID is not set");
|
|
4871
|
+
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
4872
|
+
return this.dataFetcherService.fetchAllData({
|
|
4873
|
+
workflowId: this._workflowId,
|
|
4874
|
+
runId: this._jobId,
|
|
4875
|
+
...options
|
|
4876
|
+
});
|
|
4877
|
+
}
|
|
4878
|
+
};
|
|
4879
|
+
|
|
4880
|
+
// src/domains/notifications/notifications.acl.ts
|
|
4881
|
+
var NotificationChannelType = {
|
|
4882
|
+
EMAIL: "EMAIL",
|
|
4883
|
+
SLACK: "SLACK",
|
|
4884
|
+
WEBHOOK: "WEBHOOK",
|
|
4885
|
+
WEBSOCKET: "WEBSOCKET"
|
|
4886
|
+
};
|
|
4887
|
+
|
|
4888
|
+
// src/domains/notifications/notification-channels.service.ts
|
|
4889
|
+
var emailChannelConfigSchema = zod.z.object({
|
|
4890
|
+
recipients: zod.z.array(zod.z.email()).min(1, "Recipients are required for email channel"),
|
|
4891
|
+
from: zod.z.email().refine(
|
|
4892
|
+
(email) => email.endsWith("@kadoa.com"),
|
|
4893
|
+
"From email address must end with @kadoa.com"
|
|
4894
|
+
).optional()
|
|
4895
|
+
});
|
|
4896
|
+
var _NotificationChannelsService = class _NotificationChannelsService {
|
|
4897
|
+
constructor(notificationsApi, userService) {
|
|
4898
|
+
this.api = notificationsApi;
|
|
4899
|
+
this.userService = userService;
|
|
4900
|
+
}
|
|
4901
|
+
async listChannels(filters) {
|
|
4902
|
+
const response = await this.api.v5NotificationsChannelsGet(filters);
|
|
4903
|
+
const data = response.data.data?.channels;
|
|
4904
|
+
if (!data) {
|
|
4905
|
+
throw KadoaHttpException.wrap(response, {
|
|
4906
|
+
message: "Failed to list channels"
|
|
4907
|
+
});
|
|
4908
|
+
}
|
|
4909
|
+
return data;
|
|
4910
|
+
}
|
|
4911
|
+
/**
|
|
4912
|
+
* List all channels (both workflow-specific and workspace-level)
|
|
4913
|
+
* This is useful for finding workspace-level channels like WebSocket channels
|
|
4914
|
+
* that might not be associated with a specific workflow
|
|
4915
|
+
*/
|
|
4916
|
+
async listAllChannels(workflowId) {
|
|
4917
|
+
if (!workflowId) {
|
|
4918
|
+
return this.listChannels({});
|
|
4919
|
+
}
|
|
4920
|
+
const [workflowChannels, workspaceChannels] = await Promise.all([
|
|
4921
|
+
this.listChannels({ workflowId }),
|
|
4922
|
+
this.listChannels({})
|
|
4923
|
+
]);
|
|
4924
|
+
const allChannels = [...workflowChannels];
|
|
4925
|
+
workspaceChannels.forEach((channel) => {
|
|
4926
|
+
if (!allChannels.find((c) => c.id === channel.id)) {
|
|
4927
|
+
allChannels.push(channel);
|
|
4928
|
+
}
|
|
4929
|
+
});
|
|
4930
|
+
return allChannels;
|
|
4931
|
+
}
|
|
4932
|
+
async deleteChannel(channelId) {
|
|
4933
|
+
const response = await this.api.v5NotificationsChannelsChannelIdDelete({
|
|
4934
|
+
channelId
|
|
4935
|
+
});
|
|
4936
|
+
if (response.status !== 200) {
|
|
4937
|
+
throw KadoaHttpException.wrap(response, {
|
|
4938
|
+
message: "Failed to delete channel"
|
|
4939
|
+
});
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
async createChannel(type, config) {
|
|
4943
|
+
const payload = await this.buildPayload(
|
|
4944
|
+
esToolkit.merge(config || {}, {
|
|
4945
|
+
name: _NotificationChannelsService.DEFAULT_CHANNEL_NAME,
|
|
4946
|
+
channelType: type,
|
|
4947
|
+
config: {}
|
|
4948
|
+
})
|
|
4949
|
+
);
|
|
4950
|
+
const response = await this.api.v5NotificationsChannelsPost({
|
|
4951
|
+
v5NotificationsChannelsPostRequest: payload
|
|
4952
|
+
});
|
|
4953
|
+
if (response.status === 201) {
|
|
4954
|
+
const data = response.data.data?.channel;
|
|
4955
|
+
if (!data) {
|
|
4956
|
+
throw KadoaHttpException.wrap(response, {
|
|
4957
|
+
message: "Failed to create default channels"
|
|
4958
|
+
});
|
|
4959
|
+
}
|
|
4960
|
+
return data;
|
|
4961
|
+
}
|
|
4962
|
+
throw KadoaHttpException.wrap(response, {
|
|
4963
|
+
message: "Failed to create default channels"
|
|
4964
|
+
});
|
|
4965
|
+
}
|
|
4966
|
+
async buildPayload(request) {
|
|
5070
4967
|
let config;
|
|
5071
4968
|
switch (request.channelType) {
|
|
5072
4969
|
case NotificationChannelType.EMAIL:
|
|
@@ -5133,7 +5030,7 @@ var _NotificationChannelsService = class _NotificationChannelsService {
|
|
|
5133
5030
|
_NotificationChannelsService.DEFAULT_CHANNEL_NAME = "default";
|
|
5134
5031
|
var NotificationChannelsService = _NotificationChannelsService;
|
|
5135
5032
|
|
|
5136
|
-
// src/
|
|
5033
|
+
// src/domains/notifications/notification-settings.service.ts
|
|
5137
5034
|
var NotificationSettingsService = class {
|
|
5138
5035
|
constructor(notificationsApi) {
|
|
5139
5036
|
this.api = notificationsApi;
|
|
@@ -5154,424 +5051,70 @@ var NotificationSettingsService = class {
|
|
|
5154
5051
|
const response = await this.api.v5NotificationsSettingsGet(filters);
|
|
5155
5052
|
const data = response.data.data?.settings;
|
|
5156
5053
|
if (!data) {
|
|
5157
|
-
throw KadoaHttpException.wrap(response, {
|
|
5158
|
-
message: "Failed to list notification settings"
|
|
5159
|
-
});
|
|
5160
|
-
}
|
|
5161
|
-
return data;
|
|
5162
|
-
}
|
|
5163
|
-
async listAllEvents() {
|
|
5164
|
-
return Object.values(V5NotificationsSettingsGetEventTypeEnum);
|
|
5165
|
-
}
|
|
5166
|
-
async deleteSettings(settingsId) {
|
|
5167
|
-
const response = await this.api.v5NotificationsSettingsSettingsIdDelete({
|
|
5168
|
-
settingsId
|
|
5169
|
-
});
|
|
5170
|
-
if (response.status !== 200) {
|
|
5171
|
-
throw KadoaHttpException.wrap(response, {
|
|
5172
|
-
message: "Failed to delete notification settings"
|
|
5173
|
-
});
|
|
5174
|
-
}
|
|
5175
|
-
}
|
|
5176
|
-
};
|
|
5177
|
-
|
|
5178
|
-
// src/internal/runtime/pagination/paginator.ts
|
|
5179
|
-
var PagedIterator = class {
|
|
5180
|
-
constructor(fetchPage) {
|
|
5181
|
-
this.fetchPage = fetchPage;
|
|
5182
|
-
}
|
|
5183
|
-
/**
|
|
5184
|
-
* Fetch all items across all pages
|
|
5185
|
-
* @param options Base options (page will be overridden)
|
|
5186
|
-
* @returns Array of all items
|
|
5187
|
-
*/
|
|
5188
|
-
async fetchAll(options = {}) {
|
|
5189
|
-
const allItems = [];
|
|
5190
|
-
let currentPage = 1;
|
|
5191
|
-
let hasMore = true;
|
|
5192
|
-
while (hasMore) {
|
|
5193
|
-
const result = await this.fetchPage({ ...options, page: currentPage });
|
|
5194
|
-
allItems.push(...result.data);
|
|
5195
|
-
const pagination = result.pagination;
|
|
5196
|
-
hasMore = pagination.page !== void 0 && pagination.totalPages !== void 0 && pagination.page < pagination.totalPages;
|
|
5197
|
-
currentPage++;
|
|
5198
|
-
}
|
|
5199
|
-
return allItems;
|
|
5200
|
-
}
|
|
5201
|
-
/**
|
|
5202
|
-
* Create an async iterator for pages
|
|
5203
|
-
* @param options Base options (page will be overridden)
|
|
5204
|
-
* @returns Async generator that yields pages
|
|
5205
|
-
*/
|
|
5206
|
-
async *pages(options = {}) {
|
|
5207
|
-
let currentPage = 1;
|
|
5208
|
-
let hasMore = true;
|
|
5209
|
-
while (hasMore) {
|
|
5210
|
-
const result = await this.fetchPage({ ...options, page: currentPage });
|
|
5211
|
-
yield result;
|
|
5212
|
-
const pagination = result.pagination;
|
|
5213
|
-
hasMore = pagination.page !== void 0 && pagination.totalPages !== void 0 && pagination.page < pagination.totalPages;
|
|
5214
|
-
currentPage++;
|
|
5215
|
-
}
|
|
5216
|
-
}
|
|
5217
|
-
/**
|
|
5218
|
-
* Create an async iterator for individual items
|
|
5219
|
-
* @param options Base options (page will be overridden)
|
|
5220
|
-
* @returns Async generator that yields items
|
|
5221
|
-
*/
|
|
5222
|
-
async *items(options = {}) {
|
|
5223
|
-
for await (const page of this.pages(options)) {
|
|
5224
|
-
for (const item of page.data) {
|
|
5225
|
-
yield item;
|
|
5226
|
-
}
|
|
5227
|
-
}
|
|
5228
|
-
}
|
|
5229
|
-
};
|
|
5230
|
-
|
|
5231
|
-
// src/internal/domains/extraction/services/data-fetcher.service.ts
|
|
5232
|
-
var DataFetcherService = class {
|
|
5233
|
-
constructor(workflowsApi) {
|
|
5234
|
-
this.workflowsApi = workflowsApi;
|
|
5235
|
-
this.defaultLimit = 100;
|
|
5236
|
-
}
|
|
5237
|
-
/**
|
|
5238
|
-
* Fetch a page of workflow data
|
|
5239
|
-
*/
|
|
5240
|
-
async fetchData(options) {
|
|
5241
|
-
const response = await this.workflowsApi.v4WorkflowsWorkflowIdDataGet({
|
|
5242
|
-
...options,
|
|
5243
|
-
page: options.page ?? 1,
|
|
5244
|
-
limit: options.limit ?? this.defaultLimit
|
|
5245
|
-
});
|
|
5246
|
-
const result = response.data;
|
|
5247
|
-
return result;
|
|
5248
|
-
}
|
|
5249
|
-
/**
|
|
5250
|
-
* Fetch all pages of workflow data
|
|
5251
|
-
*/
|
|
5252
|
-
async fetchAllData(options) {
|
|
5253
|
-
const iterator = new PagedIterator(
|
|
5254
|
-
(pageOptions) => this.fetchData({ ...options, ...pageOptions })
|
|
5255
|
-
);
|
|
5256
|
-
return iterator.fetchAll({ limit: options.limit ?? this.defaultLimit });
|
|
5257
|
-
}
|
|
5258
|
-
/**
|
|
5259
|
-
* Create an async iterator for paginated data fetching
|
|
5260
|
-
*/
|
|
5261
|
-
async *fetchDataPages(options) {
|
|
5262
|
-
const iterator = new PagedIterator(
|
|
5263
|
-
(pageOptions) => this.fetchData({ ...options, ...pageOptions })
|
|
5264
|
-
);
|
|
5265
|
-
for await (const page of iterator.pages({
|
|
5266
|
-
limit: options.limit ?? this.defaultLimit
|
|
5267
|
-
})) {
|
|
5268
|
-
yield page;
|
|
5269
|
-
}
|
|
5270
|
-
}
|
|
5271
|
-
};
|
|
5272
|
-
|
|
5273
|
-
// src/internal/runtime/utils/polling.ts
|
|
5274
|
-
var DEFAULT_POLLING_OPTIONS = {
|
|
5275
|
-
pollIntervalMs: 1e3,
|
|
5276
|
-
timeoutMs: 5 * 60 * 1e3
|
|
5277
|
-
};
|
|
5278
|
-
var POLLING_ERROR_CODES = {
|
|
5279
|
-
ABORTED: "ABORTED",
|
|
5280
|
-
TIMEOUT: "TIMEOUT"
|
|
5281
|
-
};
|
|
5282
|
-
async function pollUntil(pollFn, isComplete, options = {}) {
|
|
5283
|
-
const internalOptions = {
|
|
5284
|
-
...DEFAULT_POLLING_OPTIONS,
|
|
5285
|
-
...options
|
|
5286
|
-
};
|
|
5287
|
-
const pollInterval = Math.max(250, internalOptions.pollIntervalMs);
|
|
5288
|
-
const timeoutMs = internalOptions.timeoutMs;
|
|
5289
|
-
const start = Date.now();
|
|
5290
|
-
let attempts = 0;
|
|
5291
|
-
while (Date.now() - start < timeoutMs) {
|
|
5292
|
-
if (internalOptions.abortSignal?.aborted) {
|
|
5293
|
-
throw new KadoaSdkException("Polling operation was aborted", {
|
|
5294
|
-
code: POLLING_ERROR_CODES.ABORTED
|
|
5295
|
-
});
|
|
5296
|
-
}
|
|
5297
|
-
attempts++;
|
|
5298
|
-
const current = await pollFn();
|
|
5299
|
-
if (isComplete(current)) {
|
|
5300
|
-
return {
|
|
5301
|
-
result: current,
|
|
5302
|
-
attempts,
|
|
5303
|
-
duration: Date.now() - start
|
|
5304
|
-
};
|
|
5305
|
-
}
|
|
5306
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
5307
|
-
}
|
|
5308
|
-
throw new KadoaSdkException(
|
|
5309
|
-
`Polling operation timed out after ${timeoutMs}ms`,
|
|
5310
|
-
{
|
|
5311
|
-
code: POLLING_ERROR_CODES.TIMEOUT,
|
|
5312
|
-
details: {
|
|
5313
|
-
timeoutMs,
|
|
5314
|
-
attempts,
|
|
5315
|
-
duration: Date.now() - start
|
|
5316
|
-
}
|
|
5317
|
-
}
|
|
5318
|
-
);
|
|
5319
|
-
}
|
|
5320
|
-
|
|
5321
|
-
// src/internal/domains/workflows/types.ts
|
|
5322
|
-
var TERMINAL_JOB_STATES = /* @__PURE__ */ new Set([
|
|
5323
|
-
"FINISHED",
|
|
5324
|
-
"FAILED",
|
|
5325
|
-
"NOT_SUPPORTED",
|
|
5326
|
-
"FAILED_INSUFFICIENT_FUNDS"
|
|
5327
|
-
]);
|
|
5328
|
-
|
|
5329
|
-
// src/internal/domains/workflows/workflows-core.service.ts
|
|
5330
|
-
var TERMINAL_RUN_STATES = /* @__PURE__ */ new Set([
|
|
5331
|
-
"FINISHED",
|
|
5332
|
-
"SUCCESS",
|
|
5333
|
-
"FAILED",
|
|
5334
|
-
"ERROR",
|
|
5335
|
-
"STOPPED",
|
|
5336
|
-
"CANCELLED"
|
|
5337
|
-
]);
|
|
5338
|
-
var debug3 = logger.workflow;
|
|
5339
|
-
var WorkflowsCoreService = class {
|
|
5340
|
-
constructor(workflowsApi) {
|
|
5341
|
-
this.workflowsApi = workflowsApi;
|
|
5342
|
-
}
|
|
5343
|
-
async create(input) {
|
|
5344
|
-
const request = {
|
|
5345
|
-
urls: input.urls,
|
|
5346
|
-
name: input.name,
|
|
5347
|
-
schemaId: input.schemaId,
|
|
5348
|
-
description: input.description,
|
|
5349
|
-
navigationMode: input.navigationMode,
|
|
5350
|
-
entity: input.entity,
|
|
5351
|
-
fields: input.fields,
|
|
5352
|
-
bypassPreview: input.bypassPreview ?? true,
|
|
5353
|
-
tags: input.tags,
|
|
5354
|
-
interval: input.interval,
|
|
5355
|
-
monitoring: input.monitoring,
|
|
5356
|
-
location: input.location,
|
|
5357
|
-
autoStart: input.autoStart,
|
|
5358
|
-
schedules: input.schedules
|
|
5359
|
-
};
|
|
5360
|
-
const response = await this.workflowsApi.v4WorkflowsPost({
|
|
5361
|
-
createWorkflowBody: request
|
|
5362
|
-
});
|
|
5363
|
-
const workflowId = response.data?.workflowId;
|
|
5364
|
-
if (!workflowId) {
|
|
5365
|
-
throw new KadoaSdkException(ERROR_MESSAGES.NO_WORKFLOW_ID, {
|
|
5366
|
-
code: "INTERNAL_ERROR",
|
|
5367
|
-
details: {
|
|
5368
|
-
response: response.data
|
|
5369
|
-
}
|
|
5370
|
-
});
|
|
5371
|
-
}
|
|
5372
|
-
return { id: workflowId };
|
|
5373
|
-
}
|
|
5374
|
-
async get(id) {
|
|
5375
|
-
const response = await this.workflowsApi.v4WorkflowsWorkflowIdGet({
|
|
5376
|
-
workflowId: id
|
|
5377
|
-
});
|
|
5378
|
-
return response.data;
|
|
5379
|
-
}
|
|
5380
|
-
async list(filters) {
|
|
5381
|
-
const response = await this.workflowsApi.v4WorkflowsGet(filters);
|
|
5382
|
-
return response.data?.workflows ?? [];
|
|
5383
|
-
}
|
|
5384
|
-
async getByName(name) {
|
|
5385
|
-
const response = await this.workflowsApi.v4WorkflowsGet({
|
|
5386
|
-
search: name
|
|
5387
|
-
});
|
|
5388
|
-
return response.data?.workflows?.[0];
|
|
5389
|
-
}
|
|
5390
|
-
async cancel(id) {
|
|
5391
|
-
await this.workflowsApi.v4WorkflowsWorkflowIdDelete({
|
|
5392
|
-
workflowId: id
|
|
5393
|
-
});
|
|
5394
|
-
}
|
|
5395
|
-
async resume(id) {
|
|
5396
|
-
await this.workflowsApi.v4WorkflowsWorkflowIdResumePut({
|
|
5397
|
-
workflowId: id
|
|
5398
|
-
});
|
|
5399
|
-
}
|
|
5400
|
-
/**
|
|
5401
|
-
* Wait for a workflow to reach the target state or a terminal state if no target state is provided
|
|
5402
|
-
*/
|
|
5403
|
-
async wait(id, options) {
|
|
5404
|
-
let last;
|
|
5405
|
-
const result = await pollUntil(
|
|
5406
|
-
async () => {
|
|
5407
|
-
const current = await this.get(id);
|
|
5408
|
-
if (last?.state !== current.state || last?.runState !== current.runState) {
|
|
5409
|
-
debug3(
|
|
5410
|
-
"workflow %s state: [workflowState: %s, jobState: %s]",
|
|
5411
|
-
id,
|
|
5412
|
-
current.state,
|
|
5413
|
-
current.runState
|
|
5414
|
-
);
|
|
5415
|
-
}
|
|
5416
|
-
last = current;
|
|
5417
|
-
return current;
|
|
5418
|
-
},
|
|
5419
|
-
(current) => {
|
|
5420
|
-
if (options?.targetState && current.state === options.targetState) {
|
|
5421
|
-
return true;
|
|
5422
|
-
}
|
|
5423
|
-
if (current.runState && TERMINAL_RUN_STATES.has(current.runState.toUpperCase()) && current.state !== "QUEUED") {
|
|
5424
|
-
return true;
|
|
5425
|
-
}
|
|
5426
|
-
return false;
|
|
5427
|
-
},
|
|
5428
|
-
options
|
|
5429
|
-
);
|
|
5430
|
-
return result.result;
|
|
5431
|
-
}
|
|
5432
|
-
/**
|
|
5433
|
-
* Run a workflow with variables and optional limit
|
|
5434
|
-
*/
|
|
5435
|
-
async runWorkflow(workflowId, input) {
|
|
5436
|
-
const response = await this.workflowsApi.v4WorkflowsWorkflowIdRunPut({
|
|
5437
|
-
workflowId,
|
|
5438
|
-
v4WorkflowsWorkflowIdRunPutRequest: {
|
|
5439
|
-
variables: input.variables,
|
|
5440
|
-
limit: input.limit
|
|
5441
|
-
}
|
|
5442
|
-
});
|
|
5443
|
-
const jobId = response.data?.jobId;
|
|
5444
|
-
if (!jobId) {
|
|
5445
|
-
throw new KadoaSdkException(ERROR_MESSAGES.NO_WORKFLOW_ID, {
|
|
5446
|
-
code: "INTERNAL_ERROR",
|
|
5447
|
-
details: {
|
|
5448
|
-
response: response.data
|
|
5449
|
-
}
|
|
5450
|
-
});
|
|
5451
|
-
}
|
|
5452
|
-
return {
|
|
5453
|
-
jobId,
|
|
5454
|
-
message: response.data?.message,
|
|
5455
|
-
status: response.data?.status
|
|
5456
|
-
};
|
|
5457
|
-
}
|
|
5458
|
-
/**
|
|
5459
|
-
* Get job status directly without polling workflow details
|
|
5460
|
-
*/
|
|
5461
|
-
async getJobStatus(workflowId, jobId) {
|
|
5462
|
-
const response = await this.workflowsApi.v4WorkflowsWorkflowIdJobsJobIdGet({
|
|
5463
|
-
workflowId,
|
|
5464
|
-
jobId
|
|
5465
|
-
});
|
|
5466
|
-
return response.data;
|
|
5467
|
-
}
|
|
5468
|
-
/**
|
|
5469
|
-
* Wait for a job to reach the target state or a terminal state
|
|
5470
|
-
*/
|
|
5471
|
-
async waitForJobCompletion(workflowId, jobId, options) {
|
|
5472
|
-
let last;
|
|
5473
|
-
const result = await pollUntil(
|
|
5474
|
-
async () => {
|
|
5475
|
-
const current = await this.getJobStatus(workflowId, jobId);
|
|
5476
|
-
if (last?.state !== current.state) {
|
|
5477
|
-
debug3("job %s state: %s", jobId, current.state);
|
|
5478
|
-
}
|
|
5479
|
-
last = current;
|
|
5480
|
-
return current;
|
|
5481
|
-
},
|
|
5482
|
-
(current) => {
|
|
5483
|
-
if (options?.targetStatus && current.state === options.targetStatus) {
|
|
5484
|
-
return true;
|
|
5485
|
-
}
|
|
5486
|
-
if (current.state && TERMINAL_JOB_STATES.has(current.state)) {
|
|
5487
|
-
return true;
|
|
5488
|
-
}
|
|
5489
|
-
return false;
|
|
5490
|
-
},
|
|
5491
|
-
options
|
|
5492
|
-
);
|
|
5493
|
-
return result.result;
|
|
5494
|
-
}
|
|
5495
|
-
};
|
|
5496
|
-
|
|
5497
|
-
// src/internal/domains/schemas/schemas.service.ts
|
|
5498
|
-
var debug4 = logger.schemas;
|
|
5499
|
-
var SchemasService = class {
|
|
5500
|
-
constructor(client) {
|
|
5501
|
-
this.schemasApi = new SchemasApi(client.configuration);
|
|
5502
|
-
}
|
|
5503
|
-
/**
|
|
5504
|
-
* Get a schema by ID
|
|
5505
|
-
*/
|
|
5506
|
-
async getSchema(schemaId) {
|
|
5507
|
-
debug4("Fetching schema with ID: %s", schemaId);
|
|
5508
|
-
const response = await this.schemasApi.v4SchemasSchemaIdGet({
|
|
5509
|
-
schemaId
|
|
5510
|
-
});
|
|
5511
|
-
const schemaData = response.data.data;
|
|
5512
|
-
if (!schemaData) {
|
|
5513
|
-
throw new KadoaSdkException(
|
|
5514
|
-
`${ERROR_MESSAGES.SCHEMA_NOT_FOUND}: ${schemaId}`,
|
|
5515
|
-
{
|
|
5516
|
-
code: KadoaErrorCode.NOT_FOUND,
|
|
5517
|
-
details: { schemaId }
|
|
5518
|
-
}
|
|
5519
|
-
);
|
|
5520
|
-
}
|
|
5521
|
-
return schemaData;
|
|
5522
|
-
}
|
|
5523
|
-
/**
|
|
5524
|
-
* List all schemas
|
|
5525
|
-
*/
|
|
5526
|
-
async listSchemas() {
|
|
5527
|
-
const response = await this.schemasApi.v4SchemasGet();
|
|
5528
|
-
return response.data.data;
|
|
5529
|
-
}
|
|
5530
|
-
/**
|
|
5531
|
-
* Create a new schema
|
|
5532
|
-
*/
|
|
5533
|
-
async createSchema(body) {
|
|
5534
|
-
debug4("Creating schema with name: %s", body.name);
|
|
5535
|
-
const response = await this.schemasApi.v4SchemasPost({
|
|
5536
|
-
createSchemaBody: body
|
|
5537
|
-
});
|
|
5538
|
-
const schemaId = response.data.schemaId;
|
|
5539
|
-
if (!schemaId) {
|
|
5540
|
-
throw new KadoaSdkException(ERROR_MESSAGES.SCHEMA_CREATE_FAILED, {
|
|
5541
|
-
code: KadoaErrorCode.INTERNAL_ERROR
|
|
5054
|
+
throw KadoaHttpException.wrap(response, {
|
|
5055
|
+
message: "Failed to list notification settings"
|
|
5542
5056
|
});
|
|
5543
5057
|
}
|
|
5544
|
-
return
|
|
5058
|
+
return data;
|
|
5545
5059
|
}
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
*/
|
|
5549
|
-
async updateSchema(schemaId, body) {
|
|
5550
|
-
debug4("Updating schema with ID: %s", schemaId);
|
|
5551
|
-
await this.schemasApi.v4SchemasSchemaIdPut({
|
|
5552
|
-
schemaId,
|
|
5553
|
-
updateSchemaBody: body
|
|
5554
|
-
});
|
|
5555
|
-
return this.getSchema(schemaId);
|
|
5060
|
+
async listAllEvents() {
|
|
5061
|
+
return Object.values(V5NotificationsSettingsGetEventTypeEnum);
|
|
5556
5062
|
}
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
async deleteSchema(schemaId) {
|
|
5561
|
-
debug4("Deleting schema with ID: %s", schemaId);
|
|
5562
|
-
await this.schemasApi.v4SchemasSchemaIdDelete({
|
|
5563
|
-
schemaId
|
|
5063
|
+
async deleteSettings(settingsId) {
|
|
5064
|
+
const response = await this.api.v5NotificationsSettingsSettingsIdDelete({
|
|
5065
|
+
settingsId
|
|
5564
5066
|
});
|
|
5067
|
+
if (response.status !== 200) {
|
|
5068
|
+
throw KadoaHttpException.wrap(response, {
|
|
5069
|
+
message: "Failed to delete notification settings"
|
|
5070
|
+
});
|
|
5071
|
+
}
|
|
5565
5072
|
}
|
|
5566
5073
|
};
|
|
5567
5074
|
|
|
5568
|
-
// src/
|
|
5569
|
-
var
|
|
5075
|
+
// src/domains/notifications/notification-setup.service.ts
|
|
5076
|
+
var debug4 = logger.notifications;
|
|
5570
5077
|
var NotificationSetupService = class {
|
|
5571
5078
|
constructor(channelsService, settingsService) {
|
|
5572
5079
|
this.channelsService = channelsService;
|
|
5573
5080
|
this.settingsService = settingsService;
|
|
5574
5081
|
}
|
|
5082
|
+
/**
|
|
5083
|
+
* Setup notification settings for a specific workflow ensuring no duplicates exist.
|
|
5084
|
+
*/
|
|
5085
|
+
async setupForWorkflow(requestData) {
|
|
5086
|
+
const existingSettings = await this.settingsService.listSettings({
|
|
5087
|
+
workflowId: requestData.workflowId
|
|
5088
|
+
});
|
|
5089
|
+
if (existingSettings.length > 0) {
|
|
5090
|
+
throw new KadoaSdkException("Settings already exist", {
|
|
5091
|
+
code: KadoaErrorCode.BAD_REQUEST,
|
|
5092
|
+
details: {
|
|
5093
|
+
workflowId: requestData.workflowId
|
|
5094
|
+
}
|
|
5095
|
+
});
|
|
5096
|
+
}
|
|
5097
|
+
return this.setup({
|
|
5098
|
+
workflowId: requestData.workflowId,
|
|
5099
|
+
events: requestData.events,
|
|
5100
|
+
channels: requestData.channels
|
|
5101
|
+
});
|
|
5102
|
+
}
|
|
5103
|
+
/**
|
|
5104
|
+
* Setup notification settings at the workspace level ensuring no duplicates exist.
|
|
5105
|
+
*/
|
|
5106
|
+
async setupForWorkspace(requestData) {
|
|
5107
|
+
const existingSettings = await this.settingsService.listSettings({});
|
|
5108
|
+
if (existingSettings.length > 0) {
|
|
5109
|
+
throw new KadoaSdkException("Workspace settings already exist", {
|
|
5110
|
+
code: KadoaErrorCode.BAD_REQUEST
|
|
5111
|
+
});
|
|
5112
|
+
}
|
|
5113
|
+
return this.setup({
|
|
5114
|
+
events: requestData.events,
|
|
5115
|
+
channels: requestData.channels
|
|
5116
|
+
});
|
|
5117
|
+
}
|
|
5575
5118
|
/**
|
|
5576
5119
|
* Complete workflow notification setup including channels and settings
|
|
5577
5120
|
*
|
|
@@ -5579,10 +5122,10 @@ var NotificationSetupService = class {
|
|
|
5579
5122
|
* @returns Array of created notification settings
|
|
5580
5123
|
*/
|
|
5581
5124
|
async setup(requestData) {
|
|
5582
|
-
requestData.workflowId ?
|
|
5125
|
+
requestData.workflowId ? debug4(
|
|
5583
5126
|
"Setting up notifications for workflow %s",
|
|
5584
5127
|
requestData.workflowId
|
|
5585
|
-
) :
|
|
5128
|
+
) : debug4("Setting up notifications for workspace");
|
|
5586
5129
|
const channels = await this.setupChannels({
|
|
5587
5130
|
workflowId: requestData.workflowId,
|
|
5588
5131
|
channels: requestData.channels || {}
|
|
@@ -5590,7 +5133,7 @@ var NotificationSetupService = class {
|
|
|
5590
5133
|
const events = requestData.events || "all";
|
|
5591
5134
|
const eventTypes = events === "all" ? await this.settingsService.listAllEvents() : events;
|
|
5592
5135
|
const channelIds = channels.map((channel) => channel.id).filter(Boolean);
|
|
5593
|
-
|
|
5136
|
+
debug4(
|
|
5594
5137
|
"Creating notification settings for workflow %s: %O",
|
|
5595
5138
|
requestData.workflowId,
|
|
5596
5139
|
{
|
|
@@ -5609,7 +5152,7 @@ var NotificationSetupService = class {
|
|
|
5609
5152
|
});
|
|
5610
5153
|
})
|
|
5611
5154
|
);
|
|
5612
|
-
|
|
5155
|
+
debug4(
|
|
5613
5156
|
requestData.workflowId ? "Successfully setup notifications for workflow %s" : "Successfully setup notifications for workspace",
|
|
5614
5157
|
requestData.workflowId
|
|
5615
5158
|
);
|
|
@@ -5691,7 +5234,7 @@ var NotificationSetupService = class {
|
|
|
5691
5234
|
(channel2) => channel2.channelType === channelType && channel2.name === NotificationChannelsService.DEFAULT_CHANNEL_NAME
|
|
5692
5235
|
);
|
|
5693
5236
|
if (existingChannel) {
|
|
5694
|
-
|
|
5237
|
+
debug4("Using existing default channel: %O", {
|
|
5695
5238
|
workflowId,
|
|
5696
5239
|
channelType,
|
|
5697
5240
|
channelId: existingChannel.id
|
|
@@ -5699,7 +5242,7 @@ var NotificationSetupService = class {
|
|
|
5699
5242
|
return existingChannel;
|
|
5700
5243
|
}
|
|
5701
5244
|
const channel = await this.channelsService.createChannel(channelType);
|
|
5702
|
-
|
|
5245
|
+
debug4("Created default channel %O", {
|
|
5703
5246
|
workflowId,
|
|
5704
5247
|
channelType,
|
|
5705
5248
|
channel
|
|
@@ -5724,7 +5267,7 @@ var NotificationSetupService = class {
|
|
|
5724
5267
|
(channel2) => channel2.channelType === channelType && (channel2.name || NotificationChannelsService.DEFAULT_CHANNEL_NAME) === channelName
|
|
5725
5268
|
);
|
|
5726
5269
|
if (existingChannel) {
|
|
5727
|
-
|
|
5270
|
+
debug4("Using existing channel: %O", {
|
|
5728
5271
|
workflowId,
|
|
5729
5272
|
channelType,
|
|
5730
5273
|
channelName,
|
|
@@ -5736,7 +5279,7 @@ var NotificationSetupService = class {
|
|
|
5736
5279
|
name: channelName,
|
|
5737
5280
|
config
|
|
5738
5281
|
});
|
|
5739
|
-
|
|
5282
|
+
debug4("Created channel with custom config %O", {
|
|
5740
5283
|
workflowId,
|
|
5741
5284
|
channelType,
|
|
5742
5285
|
channelName,
|
|
@@ -5749,7 +5292,280 @@ var NotificationSetupService = class {
|
|
|
5749
5292
|
}
|
|
5750
5293
|
};
|
|
5751
5294
|
|
|
5752
|
-
// src/
|
|
5295
|
+
// src/runtime/config/constants.ts
|
|
5296
|
+
var PUBLIC_API_URI = process.env.KADOA_PUBLIC_API_URI ?? "https://api.kadoa.com";
|
|
5297
|
+
var WSS_API_URI = process.env.KADOA_WSS_API_URI ?? "wss://realtime.kadoa.com";
|
|
5298
|
+
var REALTIME_API_URI = process.env.KADOA_REALTIME_API_URI ?? "https://realtime.kadoa.com";
|
|
5299
|
+
|
|
5300
|
+
// src/version.ts
|
|
5301
|
+
var SDK_VERSION = "0.15.0";
|
|
5302
|
+
var SDK_NAME = "kadoa-node-sdk";
|
|
5303
|
+
var SDK_LANGUAGE = "node";
|
|
5304
|
+
|
|
5305
|
+
// src/domains/realtime/realtime.ts
|
|
5306
|
+
var debug5 = logger.wss;
|
|
5307
|
+
if (typeof WebSocket === "undefined") {
|
|
5308
|
+
global.WebSocket = __require("ws");
|
|
5309
|
+
}
|
|
5310
|
+
var Realtime = class {
|
|
5311
|
+
constructor(config) {
|
|
5312
|
+
this.lastHeartbeat = Date.now();
|
|
5313
|
+
this.isConnecting = false;
|
|
5314
|
+
this.eventListeners = /* @__PURE__ */ new Set();
|
|
5315
|
+
this.connectionListeners = /* @__PURE__ */ new Set();
|
|
5316
|
+
this.errorListeners = /* @__PURE__ */ new Set();
|
|
5317
|
+
if (!config.teamApiKey.startsWith("tk-")) {
|
|
5318
|
+
throw new KadoaSdkException(
|
|
5319
|
+
"Realtime connection requires a team API key (starting with 'tk-'). Provided key does not appear to be a team API key.",
|
|
5320
|
+
{
|
|
5321
|
+
code: "AUTH_ERROR",
|
|
5322
|
+
details: { providedKeyPrefix: config.teamApiKey.substring(0, 3) }
|
|
5323
|
+
}
|
|
5324
|
+
);
|
|
5325
|
+
}
|
|
5326
|
+
this.teamApiKey = config.teamApiKey;
|
|
5327
|
+
this.heartbeatInterval = config.heartbeatInterval || 1e4;
|
|
5328
|
+
this.reconnectDelay = config.reconnectDelay || 5e3;
|
|
5329
|
+
this.missedHeartbeatsLimit = config.missedHeartbeatsLimit || 3e4;
|
|
5330
|
+
}
|
|
5331
|
+
async connect() {
|
|
5332
|
+
if (this.isConnecting) return;
|
|
5333
|
+
this.isConnecting = true;
|
|
5334
|
+
try {
|
|
5335
|
+
const response = await fetch(`${PUBLIC_API_URI}/v4/oauth2/token`, {
|
|
5336
|
+
method: "POST",
|
|
5337
|
+
headers: {
|
|
5338
|
+
"Content-Type": "application/json",
|
|
5339
|
+
"x-api-key": `${this.teamApiKey}`,
|
|
5340
|
+
"x-sdk-version": SDK_VERSION
|
|
5341
|
+
}
|
|
5342
|
+
});
|
|
5343
|
+
const { access_token, team_id } = await response.json();
|
|
5344
|
+
this.socket = new WebSocket(
|
|
5345
|
+
`${WSS_API_URI}?access_token=${access_token}`
|
|
5346
|
+
);
|
|
5347
|
+
this.socket.onopen = () => {
|
|
5348
|
+
this.isConnecting = false;
|
|
5349
|
+
this.lastHeartbeat = Date.now();
|
|
5350
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
5351
|
+
this.socket.send(
|
|
5352
|
+
JSON.stringify({
|
|
5353
|
+
action: "subscribe",
|
|
5354
|
+
channel: team_id
|
|
5355
|
+
})
|
|
5356
|
+
);
|
|
5357
|
+
debug5("Connected to WebSocket");
|
|
5358
|
+
this.notifyConnectionListeners(true);
|
|
5359
|
+
}
|
|
5360
|
+
this.startHeartbeatCheck();
|
|
5361
|
+
};
|
|
5362
|
+
this.socket.onmessage = (event) => {
|
|
5363
|
+
try {
|
|
5364
|
+
const data = JSON.parse(event.data);
|
|
5365
|
+
if (data.type === "heartbeat") {
|
|
5366
|
+
this.handleHeartbeat();
|
|
5367
|
+
} else {
|
|
5368
|
+
if (data?.id) {
|
|
5369
|
+
fetch(`${REALTIME_API_URI}/api/v1/events/ack`, {
|
|
5370
|
+
method: "POST",
|
|
5371
|
+
headers: { "Content-Type": "application/json" },
|
|
5372
|
+
body: JSON.stringify({ id: data.id })
|
|
5373
|
+
});
|
|
5374
|
+
}
|
|
5375
|
+
this.notifyEventListeners(data);
|
|
5376
|
+
}
|
|
5377
|
+
} catch (err) {
|
|
5378
|
+
debug5("Failed to parse incoming message: %O", err);
|
|
5379
|
+
}
|
|
5380
|
+
};
|
|
5381
|
+
this.socket.onclose = () => {
|
|
5382
|
+
debug5("WebSocket disconnected. Attempting to reconnect...");
|
|
5383
|
+
this.isConnecting = false;
|
|
5384
|
+
this.stopHeartbeatCheck();
|
|
5385
|
+
this.notifyConnectionListeners(false, "Connection closed");
|
|
5386
|
+
setTimeout(() => this.connect(), this.reconnectDelay);
|
|
5387
|
+
};
|
|
5388
|
+
this.socket.onerror = (error) => {
|
|
5389
|
+
debug5("WebSocket error: %O", error);
|
|
5390
|
+
this.isConnecting = false;
|
|
5391
|
+
this.notifyErrorListeners(error);
|
|
5392
|
+
};
|
|
5393
|
+
} catch (err) {
|
|
5394
|
+
debug5("Failed to connect: %O", err);
|
|
5395
|
+
this.isConnecting = false;
|
|
5396
|
+
setTimeout(() => this.connect(), this.reconnectDelay);
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
handleHeartbeat() {
|
|
5400
|
+
debug5("Heartbeat received");
|
|
5401
|
+
this.lastHeartbeat = Date.now();
|
|
5402
|
+
}
|
|
5403
|
+
notifyEventListeners(event) {
|
|
5404
|
+
this.eventListeners.forEach((listener) => {
|
|
5405
|
+
try {
|
|
5406
|
+
listener(event);
|
|
5407
|
+
} catch (error) {
|
|
5408
|
+
debug5("Error in event listener: %O", error);
|
|
5409
|
+
}
|
|
5410
|
+
});
|
|
5411
|
+
}
|
|
5412
|
+
notifyConnectionListeners(connected, reason) {
|
|
5413
|
+
this.connectionListeners.forEach((listener) => {
|
|
5414
|
+
try {
|
|
5415
|
+
listener(connected, reason);
|
|
5416
|
+
} catch (error) {
|
|
5417
|
+
debug5("Error in connection listener: %O", error);
|
|
5418
|
+
}
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
notifyErrorListeners(error) {
|
|
5422
|
+
this.errorListeners.forEach((listener) => {
|
|
5423
|
+
try {
|
|
5424
|
+
listener(error);
|
|
5425
|
+
} catch (error2) {
|
|
5426
|
+
debug5("Error in error listener: %O", error2);
|
|
5427
|
+
}
|
|
5428
|
+
});
|
|
5429
|
+
}
|
|
5430
|
+
startHeartbeatCheck() {
|
|
5431
|
+
this.missedHeartbeatCheckTimer = setInterval(() => {
|
|
5432
|
+
if (Date.now() - this.lastHeartbeat > this.missedHeartbeatsLimit) {
|
|
5433
|
+
debug5("No heartbeat received in 30 seconds! Closing connection.");
|
|
5434
|
+
this.socket?.close();
|
|
5435
|
+
}
|
|
5436
|
+
}, this.heartbeatInterval);
|
|
5437
|
+
}
|
|
5438
|
+
stopHeartbeatCheck() {
|
|
5439
|
+
if (this.missedHeartbeatCheckTimer) {
|
|
5440
|
+
clearInterval(this.missedHeartbeatCheckTimer);
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
/**
|
|
5444
|
+
* Subscribe to realtime events
|
|
5445
|
+
* @param listener Function to handle incoming events
|
|
5446
|
+
* @returns Function to unsubscribe
|
|
5447
|
+
*/
|
|
5448
|
+
onEvent(listener) {
|
|
5449
|
+
this.eventListeners.add(listener);
|
|
5450
|
+
return () => {
|
|
5451
|
+
this.eventListeners.delete(listener);
|
|
5452
|
+
};
|
|
5453
|
+
}
|
|
5454
|
+
/**
|
|
5455
|
+
* Subscribe to connection state changes
|
|
5456
|
+
* @param listener Function to handle connection state changes
|
|
5457
|
+
* @returns Function to unsubscribe
|
|
5458
|
+
*/
|
|
5459
|
+
onConnection(listener) {
|
|
5460
|
+
this.connectionListeners.add(listener);
|
|
5461
|
+
return () => {
|
|
5462
|
+
this.connectionListeners.delete(listener);
|
|
5463
|
+
};
|
|
5464
|
+
}
|
|
5465
|
+
/**
|
|
5466
|
+
* Subscribe to errors
|
|
5467
|
+
* @param listener Function to handle errors
|
|
5468
|
+
* @returns Function to unsubscribe
|
|
5469
|
+
*/
|
|
5470
|
+
onError(listener) {
|
|
5471
|
+
this.errorListeners.add(listener);
|
|
5472
|
+
return () => {
|
|
5473
|
+
this.errorListeners.delete(listener);
|
|
5474
|
+
};
|
|
5475
|
+
}
|
|
5476
|
+
close() {
|
|
5477
|
+
if (this.socket) {
|
|
5478
|
+
this.stopHeartbeatCheck();
|
|
5479
|
+
this.socket.close();
|
|
5480
|
+
this.socket = void 0;
|
|
5481
|
+
}
|
|
5482
|
+
this.eventListeners.clear();
|
|
5483
|
+
this.connectionListeners.clear();
|
|
5484
|
+
this.errorListeners.clear();
|
|
5485
|
+
}
|
|
5486
|
+
isConnected() {
|
|
5487
|
+
return this.socket?.readyState === WebSocket.OPEN;
|
|
5488
|
+
}
|
|
5489
|
+
};
|
|
5490
|
+
|
|
5491
|
+
// src/domains/user/user.service.ts
|
|
5492
|
+
var UserService = class {
|
|
5493
|
+
constructor(client) {
|
|
5494
|
+
this.client = client;
|
|
5495
|
+
}
|
|
5496
|
+
/**
|
|
5497
|
+
* Get current user details
|
|
5498
|
+
* @returns User details
|
|
5499
|
+
*/
|
|
5500
|
+
async getCurrentUser() {
|
|
5501
|
+
const response = await this.client.axiosInstance.get("/v5/user", {
|
|
5502
|
+
baseURL: this.client.baseUrl,
|
|
5503
|
+
headers: {
|
|
5504
|
+
"x-api-key": this.client.apiKey,
|
|
5505
|
+
"Content-Type": "application/json"
|
|
5506
|
+
}
|
|
5507
|
+
});
|
|
5508
|
+
const userData = response.data;
|
|
5509
|
+
if (!userData || !userData.userId) {
|
|
5510
|
+
throw new KadoaSdkException("Invalid user data received");
|
|
5511
|
+
}
|
|
5512
|
+
return {
|
|
5513
|
+
userId: userData.userId,
|
|
5514
|
+
email: userData.email,
|
|
5515
|
+
featureFlags: userData.featureFlags || []
|
|
5516
|
+
};
|
|
5517
|
+
}
|
|
5518
|
+
};
|
|
5519
|
+
|
|
5520
|
+
// src/runtime/utils/polling.ts
|
|
5521
|
+
var DEFAULT_POLLING_OPTIONS = {
|
|
5522
|
+
pollIntervalMs: 1e3,
|
|
5523
|
+
timeoutMs: 5 * 60 * 1e3
|
|
5524
|
+
};
|
|
5525
|
+
var POLLING_ERROR_CODES = {
|
|
5526
|
+
ABORTED: "ABORTED",
|
|
5527
|
+
TIMEOUT: "TIMEOUT"
|
|
5528
|
+
};
|
|
5529
|
+
async function pollUntil(pollFn, isComplete, options = {}) {
|
|
5530
|
+
const internalOptions = {
|
|
5531
|
+
...DEFAULT_POLLING_OPTIONS,
|
|
5532
|
+
...options
|
|
5533
|
+
};
|
|
5534
|
+
const pollInterval = Math.max(250, internalOptions.pollIntervalMs);
|
|
5535
|
+
const timeoutMs = internalOptions.timeoutMs;
|
|
5536
|
+
const start = Date.now();
|
|
5537
|
+
let attempts = 0;
|
|
5538
|
+
while (Date.now() - start < timeoutMs) {
|
|
5539
|
+
if (internalOptions.abortSignal?.aborted) {
|
|
5540
|
+
throw new KadoaSdkException("Polling operation was aborted", {
|
|
5541
|
+
code: POLLING_ERROR_CODES.ABORTED
|
|
5542
|
+
});
|
|
5543
|
+
}
|
|
5544
|
+
attempts++;
|
|
5545
|
+
const current = await pollFn();
|
|
5546
|
+
if (isComplete(current)) {
|
|
5547
|
+
return {
|
|
5548
|
+
result: current,
|
|
5549
|
+
attempts,
|
|
5550
|
+
duration: Date.now() - start
|
|
5551
|
+
};
|
|
5552
|
+
}
|
|
5553
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
5554
|
+
}
|
|
5555
|
+
throw new KadoaSdkException(
|
|
5556
|
+
`Polling operation timed out after ${timeoutMs}ms`,
|
|
5557
|
+
{
|
|
5558
|
+
code: POLLING_ERROR_CODES.TIMEOUT,
|
|
5559
|
+
details: {
|
|
5560
|
+
timeoutMs,
|
|
5561
|
+
attempts,
|
|
5562
|
+
duration: Date.now() - start
|
|
5563
|
+
}
|
|
5564
|
+
}
|
|
5565
|
+
);
|
|
5566
|
+
}
|
|
5567
|
+
|
|
5568
|
+
// src/domains/validation/validation-core.service.ts
|
|
5753
5569
|
var ValidationCoreService = class {
|
|
5754
5570
|
constructor(client) {
|
|
5755
5571
|
this.validationApi = new DataValidationApi(
|
|
@@ -5823,7 +5639,7 @@ var ValidationCoreService = class {
|
|
|
5823
5639
|
}
|
|
5824
5640
|
);
|
|
5825
5641
|
}
|
|
5826
|
-
if (response.status !== 200 || response.data
|
|
5642
|
+
if (response.status !== 200 || response.data?.error) {
|
|
5827
5643
|
throw KadoaHttpException.wrap(response.data, {
|
|
5828
5644
|
message: "Failed to get latest validation"
|
|
5829
5645
|
});
|
|
@@ -5973,301 +5789,231 @@ var ValidationRulesService = class {
|
|
|
5973
5789
|
if (response.status !== 200 || response.data.error) {
|
|
5974
5790
|
throw KadoaHttpException.wrap(response.data.data, {
|
|
5975
5791
|
message: response.data.message || "Failed to bulk approve validation rules"
|
|
5976
|
-
});
|
|
5977
|
-
}
|
|
5978
|
-
return response.data.data;
|
|
5979
|
-
}
|
|
5980
|
-
async bulkDeleteRules(data) {
|
|
5981
|
-
const response = await this.validationApi.v4DataValidationRulesActionsBulkDeletePost({
|
|
5982
|
-
bulkDeleteRules: data
|
|
5983
|
-
});
|
|
5984
|
-
if (response.status !== 200 || response.data.error) {
|
|
5985
|
-
throw KadoaHttpException.wrap(response.data.data, {
|
|
5986
|
-
message: response.data.message || "Failed to bulk delete validation rules"
|
|
5987
|
-
});
|
|
5988
|
-
}
|
|
5989
|
-
return response.data.data;
|
|
5990
|
-
}
|
|
5991
|
-
async deleteAllRules(data) {
|
|
5992
|
-
const response = await this.validationApi.v4DataValidationRulesActionsDeleteAllDelete({
|
|
5993
|
-
deleteRuleWithReason: data
|
|
5994
|
-
});
|
|
5995
|
-
if (response.status !== 200 || response.data.error) {
|
|
5996
|
-
throw KadoaHttpException.wrap(response.data.data, {
|
|
5997
|
-
message: response.data.message || "Failed to delete all validation rules"
|
|
5998
|
-
});
|
|
5999
|
-
}
|
|
6000
|
-
return response.data.data;
|
|
6001
|
-
}
|
|
6002
|
-
};
|
|
6003
|
-
|
|
6004
|
-
// src/internal/domains/extraction/services/entity-resolver.service.ts
|
|
6005
|
-
var ENTITY_API_ENDPOINT = "/v4/entity";
|
|
6006
|
-
var EntityResolverService = class {
|
|
6007
|
-
constructor(client) {
|
|
6008
|
-
this.client = client;
|
|
6009
|
-
this.schemasService = new SchemasService(client);
|
|
6010
|
-
}
|
|
6011
|
-
/**
|
|
6012
|
-
* Resolves entity and fields from the provided entity configuration
|
|
6013
|
-
*
|
|
6014
|
-
* @param entityConfig The entity configuration to resolve
|
|
6015
|
-
* @param options Additional options for AI detection
|
|
6016
|
-
* @returns Resolved entity with fields
|
|
6017
|
-
*/
|
|
6018
|
-
async resolveEntity(entityConfig, options) {
|
|
6019
|
-
if (entityConfig === "ai-detection") {
|
|
6020
|
-
if (!options?.link) {
|
|
6021
|
-
throw new KadoaSdkException(ERROR_MESSAGES.LINK_REQUIRED, {
|
|
6022
|
-
code: "VALIDATION_ERROR",
|
|
6023
|
-
details: { entityConfig, options }
|
|
6024
|
-
});
|
|
6025
|
-
}
|
|
6026
|
-
const entityPrediction = await this.fetchEntityFields({
|
|
6027
|
-
link: options.link,
|
|
6028
|
-
location: options.location,
|
|
6029
|
-
navigationMode: options.navigationMode
|
|
6030
|
-
});
|
|
6031
|
-
return {
|
|
6032
|
-
entity: entityPrediction.entity,
|
|
6033
|
-
fields: entityPrediction.fields
|
|
6034
|
-
};
|
|
6035
|
-
} else if (entityConfig) {
|
|
6036
|
-
if ("schemaId" in entityConfig) {
|
|
6037
|
-
const schema = await this.schemasService.getSchema(
|
|
6038
|
-
entityConfig.schemaId
|
|
6039
|
-
);
|
|
6040
|
-
return {
|
|
6041
|
-
entity: schema.entity ?? "",
|
|
6042
|
-
fields: schema.schema
|
|
6043
|
-
};
|
|
6044
|
-
} else if ("name" in entityConfig && "fields" in entityConfig) {
|
|
6045
|
-
return {
|
|
6046
|
-
entity: entityConfig.name,
|
|
6047
|
-
fields: entityConfig.fields
|
|
6048
|
-
};
|
|
6049
|
-
}
|
|
6050
|
-
}
|
|
6051
|
-
throw new KadoaSdkException(ERROR_MESSAGES.ENTITY_INVARIANT_VIOLATION, {
|
|
6052
|
-
details: {
|
|
6053
|
-
entity: entityConfig
|
|
6054
|
-
}
|
|
6055
|
-
});
|
|
6056
|
-
}
|
|
6057
|
-
/**
|
|
6058
|
-
* Fetches entity fields dynamically from the /v4/entity endpoint.
|
|
6059
|
-
* This is a workaround implementation using native fetch since the endpoint
|
|
6060
|
-
* is not yet included in the OpenAPI specification.
|
|
6061
|
-
*
|
|
6062
|
-
* @param options Request options including the link to analyze
|
|
6063
|
-
* @returns EntityPrediction containing the detected entity type and fields
|
|
6064
|
-
*/
|
|
6065
|
-
async fetchEntityFields(options) {
|
|
6066
|
-
this.validateEntityOptions(options);
|
|
6067
|
-
const url = `${this.client.baseUrl}${ENTITY_API_ENDPOINT}`;
|
|
6068
|
-
const requestBody = options;
|
|
6069
|
-
const response = await this.client.axiosInstance.post(url, requestBody, {
|
|
6070
|
-
headers: {
|
|
6071
|
-
"Content-Type": "application/json",
|
|
6072
|
-
Accept: "application/json",
|
|
6073
|
-
"x-api-key": this.client.apiKey
|
|
6074
|
-
}
|
|
6075
|
-
});
|
|
6076
|
-
const data = response.data;
|
|
6077
|
-
if (!data.success || !data.entityPrediction || data.entityPrediction.length === 0) {
|
|
6078
|
-
throw new KadoaSdkException(ERROR_MESSAGES.NO_PREDICTIONS, {
|
|
6079
|
-
code: "NOT_FOUND",
|
|
6080
|
-
details: {
|
|
6081
|
-
success: data.success,
|
|
6082
|
-
hasPredictions: !!data.entityPrediction,
|
|
6083
|
-
predictionCount: data.entityPrediction?.length || 0,
|
|
6084
|
-
link: options.link
|
|
6085
|
-
}
|
|
6086
|
-
});
|
|
6087
|
-
}
|
|
6088
|
-
return data.entityPrediction[0];
|
|
6089
|
-
}
|
|
6090
|
-
/**
|
|
6091
|
-
* Validates entity request options
|
|
6092
|
-
*/
|
|
6093
|
-
validateEntityOptions(options) {
|
|
6094
|
-
if (!options.link) {
|
|
6095
|
-
throw new KadoaSdkException(ERROR_MESSAGES.LINK_REQUIRED, {
|
|
6096
|
-
code: "VALIDATION_ERROR",
|
|
6097
|
-
details: { options }
|
|
6098
|
-
});
|
|
6099
|
-
}
|
|
6100
|
-
}
|
|
6101
|
-
};
|
|
6102
|
-
var debug7 = logger.extraction;
|
|
6103
|
-
var ExtractionBuilderService = class {
|
|
6104
|
-
constructor(workflowsCoreService, entityResolverService, dataFetcherService, notificationSetupService) {
|
|
6105
|
-
this.workflowsCoreService = workflowsCoreService;
|
|
6106
|
-
this.entityResolverService = entityResolverService;
|
|
6107
|
-
this.dataFetcherService = dataFetcherService;
|
|
6108
|
-
this.notificationSetupService = notificationSetupService;
|
|
6109
|
-
}
|
|
6110
|
-
get options() {
|
|
6111
|
-
assert__default.default(this._options, "Options are not set");
|
|
6112
|
-
return this._options;
|
|
6113
|
-
}
|
|
6114
|
-
get notificationOptions() {
|
|
6115
|
-
return this._notificationOptions;
|
|
6116
|
-
}
|
|
6117
|
-
get monitoringOptions() {
|
|
6118
|
-
return this._monitoringOptions;
|
|
6119
|
-
}
|
|
6120
|
-
get workflowId() {
|
|
6121
|
-
assert__default.default(this._workflowId, "Workflow ID is not set");
|
|
6122
|
-
return this._workflowId;
|
|
6123
|
-
}
|
|
6124
|
-
get jobId() {
|
|
6125
|
-
assert__default.default(this._jobId, "Job ID is not set");
|
|
6126
|
-
return this._jobId;
|
|
6127
|
-
}
|
|
6128
|
-
extract({
|
|
6129
|
-
urls,
|
|
6130
|
-
name,
|
|
6131
|
-
description,
|
|
6132
|
-
navigationMode,
|
|
6133
|
-
extraction
|
|
6134
|
-
}) {
|
|
6135
|
-
let entity = "ai-detection";
|
|
6136
|
-
if (extraction) {
|
|
6137
|
-
const result = extraction(new SchemaBuilder());
|
|
6138
|
-
if ("schemaId" in result) {
|
|
6139
|
-
entity = { schemaId: result.schemaId };
|
|
6140
|
-
} else {
|
|
6141
|
-
const builtSchema = result.build();
|
|
6142
|
-
entity = { name: builtSchema.entityName, fields: builtSchema.fields };
|
|
6143
|
-
}
|
|
6144
|
-
}
|
|
6145
|
-
this._options = {
|
|
6146
|
-
urls,
|
|
6147
|
-
name,
|
|
6148
|
-
description,
|
|
6149
|
-
navigationMode: navigationMode || "single-page",
|
|
6150
|
-
entity,
|
|
6151
|
-
bypassPreview: false
|
|
6152
|
-
};
|
|
6153
|
-
return this;
|
|
6154
|
-
}
|
|
6155
|
-
withNotifications(options) {
|
|
6156
|
-
this._notificationOptions = options;
|
|
6157
|
-
return this;
|
|
6158
|
-
}
|
|
6159
|
-
withMonitoring(options) {
|
|
6160
|
-
this._monitoringOptions = options;
|
|
6161
|
-
return this;
|
|
6162
|
-
}
|
|
6163
|
-
bypassPreview() {
|
|
6164
|
-
assert__default.default(this._options, "Options are not set");
|
|
6165
|
-
this._options.bypassPreview = true;
|
|
6166
|
-
return this;
|
|
6167
|
-
}
|
|
6168
|
-
setInterval(options) {
|
|
6169
|
-
assert__default.default(this._options, "Options are not set");
|
|
6170
|
-
if ("interval" in options) {
|
|
6171
|
-
this._options.interval = options.interval;
|
|
6172
|
-
} else {
|
|
6173
|
-
this._options.interval = "CUSTOM";
|
|
6174
|
-
this._options.schedules = options.schedules;
|
|
5792
|
+
});
|
|
6175
5793
|
}
|
|
6176
|
-
return
|
|
5794
|
+
return response.data.data;
|
|
6177
5795
|
}
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
5796
|
+
async bulkDeleteRules(data) {
|
|
5797
|
+
const response = await this.validationApi.v4DataValidationRulesActionsBulkDeletePost({
|
|
5798
|
+
bulkDeleteRules: data
|
|
5799
|
+
});
|
|
5800
|
+
if (response.status !== 200 || response.data.error) {
|
|
5801
|
+
throw KadoaHttpException.wrap(response.data.data, {
|
|
5802
|
+
message: response.data.message || "Failed to bulk delete validation rules"
|
|
5803
|
+
});
|
|
5804
|
+
}
|
|
5805
|
+
return response.data.data;
|
|
6182
5806
|
}
|
|
6183
|
-
async
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
const resolvedEntity = typeof entity === "object" && "schemaId" in entity ? void 0 : await this.entityResolverService.resolveEntity(entity, {
|
|
6187
|
-
link: urls[0],
|
|
6188
|
-
location: this._options.location,
|
|
6189
|
-
navigationMode
|
|
5807
|
+
async deleteAllRules(data) {
|
|
5808
|
+
const response = await this.validationApi.v4DataValidationRulesActionsDeleteAllDelete({
|
|
5809
|
+
deleteRuleWithReason: data
|
|
6190
5810
|
});
|
|
6191
|
-
if (
|
|
6192
|
-
throw
|
|
6193
|
-
|
|
6194
|
-
details: { entity }
|
|
5811
|
+
if (response.status !== 200 || response.data.error) {
|
|
5812
|
+
throw KadoaHttpException.wrap(response.data.data, {
|
|
5813
|
+
message: response.data.message || "Failed to delete all validation rules"
|
|
6195
5814
|
});
|
|
6196
5815
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
5816
|
+
return response.data.data;
|
|
5817
|
+
}
|
|
5818
|
+
};
|
|
5819
|
+
|
|
5820
|
+
// src/domains/workflows/workflows.acl.ts
|
|
5821
|
+
var JobStateEnum = {
|
|
5822
|
+
Finished: "FINISHED",
|
|
5823
|
+
Failed: "FAILED",
|
|
5824
|
+
NotSupported: "NOT_SUPPORTED",
|
|
5825
|
+
FailedInsufficientFunds: "FAILED_INSUFFICIENT_FUNDS"
|
|
5826
|
+
};
|
|
5827
|
+
|
|
5828
|
+
// src/domains/workflows/workflows-core.service.ts
|
|
5829
|
+
var TERMINAL_JOB_STATES = /* @__PURE__ */ new Set([
|
|
5830
|
+
JobStateEnum.Finished,
|
|
5831
|
+
JobStateEnum.Failed,
|
|
5832
|
+
JobStateEnum.NotSupported,
|
|
5833
|
+
JobStateEnum.FailedInsufficientFunds
|
|
5834
|
+
]);
|
|
5835
|
+
var TERMINAL_RUN_STATES = /* @__PURE__ */ new Set([
|
|
5836
|
+
"FINISHED",
|
|
5837
|
+
"SUCCESS",
|
|
5838
|
+
"FAILED",
|
|
5839
|
+
"ERROR",
|
|
5840
|
+
"STOPPED",
|
|
5841
|
+
"CANCELLED"
|
|
5842
|
+
]);
|
|
5843
|
+
var debug6 = logger.workflow;
|
|
5844
|
+
var WorkflowsCoreService = class {
|
|
5845
|
+
constructor(workflowsApi) {
|
|
5846
|
+
this.workflowsApi = workflowsApi;
|
|
5847
|
+
}
|
|
5848
|
+
async create(input) {
|
|
5849
|
+
const request = {
|
|
5850
|
+
urls: input.urls,
|
|
5851
|
+
name: input.name,
|
|
5852
|
+
schemaId: input.schemaId,
|
|
5853
|
+
description: input.description,
|
|
5854
|
+
navigationMode: input.navigationMode,
|
|
5855
|
+
entity: input.entity,
|
|
5856
|
+
fields: input.fields,
|
|
5857
|
+
bypassPreview: input.bypassPreview ?? true,
|
|
5858
|
+
tags: input.tags,
|
|
5859
|
+
interval: input.interval,
|
|
5860
|
+
monitoring: input.monitoring,
|
|
5861
|
+
location: input.location,
|
|
5862
|
+
autoStart: input.autoStart,
|
|
5863
|
+
schedules: input.schedules
|
|
5864
|
+
};
|
|
5865
|
+
const response = await this.workflowsApi.v4WorkflowsPost({
|
|
5866
|
+
createWorkflowBody: request
|
|
6209
5867
|
});
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
5868
|
+
const workflowId = response.data?.workflowId;
|
|
5869
|
+
if (!workflowId) {
|
|
5870
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_WORKFLOW_ID, {
|
|
5871
|
+
code: "INTERNAL_ERROR",
|
|
5872
|
+
details: {
|
|
5873
|
+
response: response.data
|
|
5874
|
+
}
|
|
6214
5875
|
});
|
|
6215
5876
|
}
|
|
6216
|
-
|
|
6217
|
-
return this;
|
|
5877
|
+
return { id: workflowId };
|
|
6218
5878
|
}
|
|
6219
|
-
async
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
{ variables: options?.variables, limit: options?.limit }
|
|
6225
|
-
);
|
|
6226
|
-
debug7("Job started: %O", startedJob);
|
|
6227
|
-
this._jobId = startedJob.jobId;
|
|
6228
|
-
const finishedJob = await this.workflowsCoreService.waitForJobCompletion(
|
|
6229
|
-
this._workflowId,
|
|
6230
|
-
startedJob.jobId
|
|
6231
|
-
);
|
|
6232
|
-
debug7("Job finished: %O", finishedJob);
|
|
6233
|
-
return this;
|
|
5879
|
+
async get(id) {
|
|
5880
|
+
const response = await this.workflowsApi.v4WorkflowsWorkflowIdGet({
|
|
5881
|
+
workflowId: id
|
|
5882
|
+
});
|
|
5883
|
+
return response.data;
|
|
6234
5884
|
}
|
|
6235
|
-
async
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
5885
|
+
async list(filters) {
|
|
5886
|
+
const response = await this.workflowsApi.v4WorkflowsGet(filters);
|
|
5887
|
+
return response.data?.workflows ?? [];
|
|
5888
|
+
}
|
|
5889
|
+
async getByName(name) {
|
|
5890
|
+
const response = await this.workflowsApi.v4WorkflowsGet({
|
|
5891
|
+
search: name
|
|
5892
|
+
});
|
|
5893
|
+
return response.data?.workflows?.[0];
|
|
5894
|
+
}
|
|
5895
|
+
async cancel(id) {
|
|
5896
|
+
await this.workflowsApi.v4WorkflowsWorkflowIdDelete({
|
|
5897
|
+
workflowId: id
|
|
5898
|
+
});
|
|
5899
|
+
}
|
|
5900
|
+
async resume(id) {
|
|
5901
|
+
await this.workflowsApi.v4WorkflowsWorkflowIdResumePut({
|
|
5902
|
+
workflowId: id
|
|
5903
|
+
});
|
|
5904
|
+
}
|
|
5905
|
+
/**
|
|
5906
|
+
* Wait for a workflow to reach the target state or a terminal state if no target state is provided
|
|
5907
|
+
*/
|
|
5908
|
+
async wait(id, options) {
|
|
5909
|
+
let last;
|
|
5910
|
+
const result = await pollUntil(
|
|
5911
|
+
async () => {
|
|
5912
|
+
const current = await this.get(id);
|
|
5913
|
+
if (last?.state !== current.state || last?.runState !== current.runState) {
|
|
5914
|
+
debug6(
|
|
5915
|
+
"workflow %s state: [workflowState: %s, jobState: %s]",
|
|
5916
|
+
id,
|
|
5917
|
+
current.state,
|
|
5918
|
+
current.runState
|
|
5919
|
+
);
|
|
5920
|
+
}
|
|
5921
|
+
last = current;
|
|
5922
|
+
return current;
|
|
5923
|
+
},
|
|
5924
|
+
(current) => {
|
|
5925
|
+
if (options?.targetState && current.state === options.targetState) {
|
|
5926
|
+
return true;
|
|
5927
|
+
}
|
|
5928
|
+
if (current.runState && TERMINAL_RUN_STATES.has(current.runState.toUpperCase()) && current.state !== "QUEUED") {
|
|
5929
|
+
return true;
|
|
5930
|
+
}
|
|
5931
|
+
return false;
|
|
5932
|
+
},
|
|
5933
|
+
options
|
|
6241
5934
|
);
|
|
6242
|
-
|
|
6243
|
-
|
|
5935
|
+
return result.result;
|
|
5936
|
+
}
|
|
5937
|
+
/**
|
|
5938
|
+
* Run a workflow with variables and optional limit
|
|
5939
|
+
*/
|
|
5940
|
+
async runWorkflow(workflowId, input) {
|
|
5941
|
+
const response = await this.workflowsApi.v4WorkflowsWorkflowIdRunPut({
|
|
5942
|
+
workflowId,
|
|
5943
|
+
v4WorkflowsWorkflowIdRunPutRequest: {
|
|
5944
|
+
variables: input.variables,
|
|
5945
|
+
limit: input.limit
|
|
5946
|
+
}
|
|
5947
|
+
});
|
|
5948
|
+
const jobId = response.data?.jobId;
|
|
5949
|
+
if (!jobId) {
|
|
5950
|
+
throw new KadoaSdkException(ERROR_MESSAGES.NO_WORKFLOW_ID, {
|
|
5951
|
+
code: "INTERNAL_ERROR",
|
|
5952
|
+
details: {
|
|
5953
|
+
response: response.data
|
|
5954
|
+
}
|
|
5955
|
+
});
|
|
5956
|
+
}
|
|
6244
5957
|
return {
|
|
6245
|
-
|
|
6246
|
-
|
|
5958
|
+
jobId,
|
|
5959
|
+
message: response.data?.message,
|
|
5960
|
+
status: response.data?.status
|
|
6247
5961
|
};
|
|
6248
5962
|
}
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
limit: options.limit ?? 100,
|
|
6257
|
-
...options
|
|
5963
|
+
/**
|
|
5964
|
+
* Get job status directly without polling workflow details
|
|
5965
|
+
*/
|
|
5966
|
+
async getJobStatus(workflowId, jobId) {
|
|
5967
|
+
const response = await this.workflowsApi.v4WorkflowsWorkflowIdJobsJobIdGet({
|
|
5968
|
+
workflowId,
|
|
5969
|
+
jobId
|
|
6258
5970
|
});
|
|
5971
|
+
return response.data;
|
|
6259
5972
|
}
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
5973
|
+
/**
|
|
5974
|
+
* Wait for a job to reach the target state or a terminal state
|
|
5975
|
+
*/
|
|
5976
|
+
async waitForJobCompletion(workflowId, jobId, options) {
|
|
5977
|
+
let last;
|
|
5978
|
+
const result = await pollUntil(
|
|
5979
|
+
async () => {
|
|
5980
|
+
const current = await this.getJobStatus(workflowId, jobId);
|
|
5981
|
+
if (last?.state !== current.state) {
|
|
5982
|
+
debug6("job %s state: %s", jobId, current.state);
|
|
5983
|
+
}
|
|
5984
|
+
last = current;
|
|
5985
|
+
return current;
|
|
5986
|
+
},
|
|
5987
|
+
(current) => {
|
|
5988
|
+
if (options?.targetStatus && current.state === options.targetStatus) {
|
|
5989
|
+
return true;
|
|
5990
|
+
}
|
|
5991
|
+
if (current.state && TERMINAL_JOB_STATES.has(current.state)) {
|
|
5992
|
+
return true;
|
|
5993
|
+
}
|
|
5994
|
+
return false;
|
|
5995
|
+
},
|
|
5996
|
+
options
|
|
5997
|
+
);
|
|
5998
|
+
return result.result;
|
|
6268
5999
|
}
|
|
6269
6000
|
};
|
|
6270
6001
|
|
|
6002
|
+
// src/domains/validation/validation.facade.ts
|
|
6003
|
+
function createValidationDomain(core, rules) {
|
|
6004
|
+
return {
|
|
6005
|
+
rules,
|
|
6006
|
+
schedule: (workflowId, jobId) => core.scheduleValidation(workflowId, jobId),
|
|
6007
|
+
listWorkflowValidations: (filters) => core.listWorkflowValidations(filters),
|
|
6008
|
+
getValidationDetails: (validationId) => core.getValidationDetails(validationId),
|
|
6009
|
+
toggleEnabled: (workflowId) => core.toggleValidationEnabled(workflowId),
|
|
6010
|
+
getLatest: (workflowId, jobId) => core.getLatestValidation(workflowId, jobId),
|
|
6011
|
+
getAnomalies: (validationId) => core.getValidationAnomalies(validationId),
|
|
6012
|
+
getAnomaliesByRule: (validationId, ruleName) => core.getValidationAnomaliesByRule(validationId, ruleName),
|
|
6013
|
+
waitUntilCompleted: (validationId, options) => core.waitUntilCompleted(validationId, options)
|
|
6014
|
+
};
|
|
6015
|
+
}
|
|
6016
|
+
|
|
6271
6017
|
// src/kadoa-client.ts
|
|
6272
6018
|
var KadoaClient = class {
|
|
6273
6019
|
constructor(config) {
|
|
@@ -6344,7 +6090,9 @@ var KadoaClient = class {
|
|
|
6344
6090
|
workflowsCoreService,
|
|
6345
6091
|
dataFetcherService,
|
|
6346
6092
|
entityResolverService,
|
|
6347
|
-
channelSetupService
|
|
6093
|
+
channelSetupService,
|
|
6094
|
+
channelsService,
|
|
6095
|
+
settingsService
|
|
6348
6096
|
);
|
|
6349
6097
|
this._extractionBuilderService = new ExtractionBuilderService(
|
|
6350
6098
|
workflowsCoreService,
|
|
@@ -6352,22 +6100,19 @@ var KadoaClient = class {
|
|
|
6352
6100
|
dataFetcherService,
|
|
6353
6101
|
channelSetupService
|
|
6354
6102
|
);
|
|
6355
|
-
this.user =
|
|
6356
|
-
this.extraction =
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
channelSetupService
|
|
6369
|
-
);
|
|
6370
|
-
this.validation = new ValidationModule(coreService, rulesService);
|
|
6103
|
+
this.user = userService;
|
|
6104
|
+
this.extraction = extractionService;
|
|
6105
|
+
this.workflow = workflowsCoreService;
|
|
6106
|
+
this.schema = schemasService;
|
|
6107
|
+
this.notification = {
|
|
6108
|
+
channels: channelsService,
|
|
6109
|
+
settings: settingsService,
|
|
6110
|
+
setup: channelSetupService,
|
|
6111
|
+
configure: (options) => channelSetupService.setup(options),
|
|
6112
|
+
setupForWorkflow: (request) => channelSetupService.setupForWorkflow(request),
|
|
6113
|
+
setupForWorkspace: (request) => channelSetupService.setupForWorkspace(request)
|
|
6114
|
+
};
|
|
6115
|
+
this.validation = createValidationDomain(coreService, rulesService);
|
|
6371
6116
|
if (config.enableRealtime && config.realtimeConfig?.autoConnect !== false) {
|
|
6372
6117
|
this.connectRealtime();
|
|
6373
6118
|
}
|
|
@@ -6506,13 +6251,28 @@ var KadoaClient = class {
|
|
|
6506
6251
|
}
|
|
6507
6252
|
};
|
|
6508
6253
|
|
|
6254
|
+
exports.DataFetcherService = DataFetcherService;
|
|
6509
6255
|
exports.ERROR_MESSAGES = ERROR_MESSAGES;
|
|
6256
|
+
exports.EntityResolverService = EntityResolverService;
|
|
6257
|
+
exports.ExtractionBuilderService = ExtractionBuilderService;
|
|
6258
|
+
exports.ExtractionService = ExtractionService;
|
|
6259
|
+
exports.FetchDataOptions = FetchDataOptions;
|
|
6510
6260
|
exports.KadoaClient = KadoaClient;
|
|
6511
6261
|
exports.KadoaHttpException = KadoaHttpException;
|
|
6512
6262
|
exports.KadoaSdkException = KadoaSdkException;
|
|
6263
|
+
exports.NotificationChannelType = NotificationChannelType;
|
|
6264
|
+
exports.NotificationChannelsService = NotificationChannelsService;
|
|
6265
|
+
exports.NotificationSettingsEventTypeEnum = V5NotificationsSettingsGetEventTypeEnum;
|
|
6266
|
+
exports.NotificationSettingsService = NotificationSettingsService;
|
|
6267
|
+
exports.NotificationSetupService = NotificationSetupService;
|
|
6268
|
+
exports.Realtime = Realtime;
|
|
6513
6269
|
exports.SchemaBuilder = SchemaBuilder;
|
|
6514
|
-
exports.
|
|
6515
|
-
exports.
|
|
6270
|
+
exports.SchemaFieldDataType = SchemaFieldDataType;
|
|
6271
|
+
exports.SchemasService = SchemasService;
|
|
6272
|
+
exports.UserService = UserService;
|
|
6273
|
+
exports.ValidationCoreService = ValidationCoreService;
|
|
6274
|
+
exports.ValidationRulesService = ValidationRulesService;
|
|
6275
|
+
exports.WorkflowsCoreService = WorkflowsCoreService;
|
|
6516
6276
|
exports.pollUntil = pollUntil;
|
|
6517
6277
|
//# sourceMappingURL=index.js.map
|
|
6518
6278
|
//# sourceMappingURL=index.js.map
|