@kadoa/node-sdk 0.12.1 → 0.14.1

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