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