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