@agnocon/piece-browse-ai 0.1.7

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.
Files changed (47) hide show
  1. package/LICENSE.MIT-AP +24 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +42 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/actions/get-task-details.d.ts +5 -0
  7. package/dist/lib/actions/get-task-details.d.ts.map +1 -0
  8. package/dist/lib/actions/get-task-details.js +50 -0
  9. package/dist/lib/actions/get-task-details.js.map +1 -0
  10. package/dist/lib/actions/list-robots.d.ts +2 -0
  11. package/dist/lib/actions/list-robots.d.ts.map +1 -0
  12. package/dist/lib/actions/list-robots.js +45 -0
  13. package/dist/lib/actions/list-robots.js.map +1 -0
  14. package/dist/lib/actions/run-robot.d.ts +6 -0
  15. package/dist/lib/actions/run-robot.d.ts.map +1 -0
  16. package/dist/lib/actions/run-robot.js +64 -0
  17. package/dist/lib/actions/run-robot.js.map +1 -0
  18. package/dist/lib/common/auth.d.ts +2 -0
  19. package/dist/lib/common/auth.d.ts.map +1 -0
  20. package/dist/lib/common/auth.js +31 -0
  21. package/dist/lib/common/auth.js.map +1 -0
  22. package/dist/lib/common/client.d.ts +13 -0
  23. package/dist/lib/common/client.d.ts.map +1 -0
  24. package/dist/lib/common/client.js +63 -0
  25. package/dist/lib/common/client.js.map +1 -0
  26. package/dist/lib/common/props.d.ts +4 -0
  27. package/dist/lib/common/props.d.ts.map +1 -0
  28. package/dist/lib/common/props.js +168 -0
  29. package/dist/lib/common/props.js.map +1 -0
  30. package/dist/lib/triggers/task-finished-successfully.d.ts +11 -0
  31. package/dist/lib/triggers/task-finished-successfully.d.ts.map +1 -0
  32. package/dist/lib/triggers/task-finished-successfully.js +110 -0
  33. package/dist/lib/triggers/task-finished-successfully.js.map +1 -0
  34. package/dist/lib/triggers/task-finished-with-error.d.ts +11 -0
  35. package/dist/lib/triggers/task-finished-with-error.d.ts.map +1 -0
  36. package/dist/lib/triggers/task-finished-with-error.js +110 -0
  37. package/dist/lib/triggers/task-finished-with-error.js.map +1 -0
  38. package/package.json +46 -0
  39. package/src/index.ts +34 -0
  40. package/src/lib/actions/get-task-details.ts +52 -0
  41. package/src/lib/actions/list-robots.ts +41 -0
  42. package/src/lib/actions/run-robot.ts +65 -0
  43. package/src/lib/common/auth.ts +24 -0
  44. package/src/lib/common/client.ts +85 -0
  45. package/src/lib/common/props.ts +213 -0
  46. package/src/lib/triggers/task-finished-successfully.ts +139 -0
  47. package/src/lib/triggers/task-finished-with-error.ts +138 -0
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.taskFinishedSuccessfullyTrigger = void 0;
4
+ const tslib_1 = require("tslib");
5
+ // Vendored from Activepieces packages/pieces/community/browse-ai/src/lib/triggers/task-finished-successfully.ts (MIT).
6
+ // Generated by packages/scripts/vendor-ap.mjs - do not edit by hand.
7
+ const pieces_common_1 = require("@agnocon/pieces-common");
8
+ const pieces_framework_1 = require("@agnocon/pieces-framework");
9
+ const pieces_framework_2 = require("@agnocon/pieces-framework");
10
+ const auth_1 = require("../common/auth");
11
+ const client_1 = require("../common/client");
12
+ const props_1 = require("../common/props");
13
+ const TRIGGER_KEY = 'browse-ai-task_finished_successfully';
14
+ exports.taskFinishedSuccessfullyTrigger = (0, pieces_framework_1.createTrigger)({
15
+ auth: auth_1.browseAiAuth,
16
+ name: 'task_finished_successfully',
17
+ displayName: 'Task Finished Successfully',
18
+ description: 'Triggers when a robot finishes a task successfully.',
19
+ aiMetadata: {
20
+ description: 'Fires when a task run for the selected Browse AI robot completes successfully, delivering the finished task record with its captured/extracted data. Use to process scrape results as soon as they are ready.',
21
+ },
22
+ type: pieces_framework_1.TriggerStrategy.WEBHOOK,
23
+ props: {
24
+ robotId: props_1.robotIdDropdown,
25
+ },
26
+ onEnable(context) {
27
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
28
+ var _a, _b, _c, _d, _e, _f;
29
+ const { robotId } = context.propsValue;
30
+ const apiKey = context.auth.secret_text;
31
+ try {
32
+ // Verify robot exists and we have access
33
+ yield (0, client_1.browseAiApiCall)({
34
+ method: pieces_common_1.HttpMethod.GET,
35
+ auth: { apiKey },
36
+ resourceUri: `/robots/${robotId}`,
37
+ });
38
+ const response = yield (0, client_1.browseAiApiCall)({
39
+ method: pieces_common_1.HttpMethod.POST,
40
+ auth: { apiKey },
41
+ resourceUri: `/robots/${robotId}/webhooks`,
42
+ body: {
43
+ hookUrl: context.webhookUrl,
44
+ eventType: 'taskFinishedSuccessfully',
45
+ },
46
+ });
47
+ yield context.store.put(TRIGGER_KEY, response.webhook.id);
48
+ }
49
+ catch (error) {
50
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
51
+ throw new Error(`Robot not found: The robot with ID "${robotId}" does not exist or you do not have access to it. Please verify the robot ID and your permissions.`);
52
+ }
53
+ if (((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 403) {
54
+ throw new Error('Access denied: You do not have permission to set up webhooks for this robot. Please check your Browse AI account permissions and ensure you have webhook access.');
55
+ }
56
+ if (((_c = error.response) === null || _c === void 0 ? void 0 : _c.status) === 400) {
57
+ throw new Error(`Invalid webhook configuration: ${((_e = (_d = error.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.message) || error.message}. Please check your webhook URL and robot ID.`);
58
+ }
59
+ if (((_f = error.response) === null || _f === void 0 ? void 0 : _f.status) === 429) {
60
+ throw new Error('Rate limit exceeded: Too many webhook requests. Please wait a moment and try again.');
61
+ }
62
+ throw new Error(`Failed to set up webhook: ${error.message || 'Unknown error occurred'}. Please check your robot ID and try again.`);
63
+ }
64
+ });
65
+ },
66
+ onDisable(context) {
67
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
68
+ const { robotId } = context.propsValue;
69
+ const webhookId = yield context.store.get(TRIGGER_KEY);
70
+ const apiKey = context.auth.secret_text;
71
+ if (!(0, pieces_framework_2.isNil)(webhookId)) {
72
+ try {
73
+ yield (0, client_1.browseAiApiCall)({
74
+ method: pieces_common_1.HttpMethod.DELETE,
75
+ auth: { apiKey },
76
+ resourceUri: `/robots/${robotId}/webhooks/${webhookId}`,
77
+ });
78
+ }
79
+ catch (error) {
80
+ console.warn(`Warning: Failed to clean up webhook ${webhookId}:`, error.message);
81
+ // Clean up the stored webhook ID even if deletion failed
82
+ yield context.store.delete(TRIGGER_KEY);
83
+ }
84
+ }
85
+ });
86
+ },
87
+ run(context) {
88
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
89
+ const payload = context.payload.body;
90
+ if (payload.event !== 'task.finishedSuccessfully')
91
+ return [];
92
+ return [payload.task];
93
+ });
94
+ },
95
+ test(context) {
96
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
97
+ const { robotId } = context.propsValue;
98
+ const apiKey = context.auth.secret_text;
99
+ const response = yield (0, client_1.browseAiApiCall)({
100
+ method: pieces_common_1.HttpMethod.GET,
101
+ auth: { apiKey },
102
+ resourceUri: `/robots/${robotId}/tasks`,
103
+ query: { status: 'successful', sort: '-createdAt' },
104
+ });
105
+ return response.result.robotTasks.items;
106
+ });
107
+ },
108
+ sampleData: {},
109
+ });
110
+ //# sourceMappingURL=task-finished-successfully.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-finished-successfully.js","sourceRoot":"","sources":["../../../src/lib/triggers/task-finished-successfully.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { TriggerStrategy } from '@agnocon/pieces-framework';
2
+ export declare const taskFinishedWithErrorTrigger: import("@agnocon/pieces-framework").ITrigger<TriggerStrategy.WEBHOOK, import("@agnocon/pieces-framework").SecretTextProperty<true>, {
3
+ robotId: import("@agnocon/pieces-framework").DropdownProperty<string, true, import("@agnocon/pieces-framework").SecretTextProperty<true>>;
4
+ }> | import("@agnocon/pieces-framework").ITrigger<TriggerStrategy.POLLING, import("@agnocon/pieces-framework").SecretTextProperty<true>, {
5
+ robotId: import("@agnocon/pieces-framework").DropdownProperty<string, true, import("@agnocon/pieces-framework").SecretTextProperty<true>>;
6
+ }> | import("@agnocon/pieces-framework").ITrigger<TriggerStrategy.MANUAL, import("@agnocon/pieces-framework").SecretTextProperty<true>, {
7
+ robotId: import("@agnocon/pieces-framework").DropdownProperty<string, true, import("@agnocon/pieces-framework").SecretTextProperty<true>>;
8
+ }> | import("@agnocon/pieces-framework").ITrigger<TriggerStrategy.APP_WEBHOOK, import("@agnocon/pieces-framework").SecretTextProperty<true>, {
9
+ robotId: import("@agnocon/pieces-framework").DropdownProperty<string, true, import("@agnocon/pieces-framework").SecretTextProperty<true>>;
10
+ }>;
11
+ //# sourceMappingURL=task-finished-with-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-finished-with-error.d.ts","sourceRoot":"","sources":["../../../src/lib/triggers/task-finished-with-error.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAQ3E,eAAO,MAAM,4BAA4B;;;;;;;;EAgIvC,CAAC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.taskFinishedWithErrorTrigger = void 0;
4
+ const tslib_1 = require("tslib");
5
+ // Vendored from Activepieces packages/pieces/community/browse-ai/src/lib/triggers/task-finished-with-error.ts (MIT).
6
+ // Generated by packages/scripts/vendor-ap.mjs - do not edit by hand.
7
+ const pieces_common_1 = require("@agnocon/pieces-common");
8
+ const pieces_framework_1 = require("@agnocon/pieces-framework");
9
+ const pieces_framework_2 = require("@agnocon/pieces-framework");
10
+ const auth_1 = require("../common/auth");
11
+ const client_1 = require("../common/client");
12
+ const props_1 = require("../common/props");
13
+ const TRIGGER_KEY = 'browse-ai-task_finished_with_error';
14
+ exports.taskFinishedWithErrorTrigger = (0, pieces_framework_1.createTrigger)({
15
+ auth: auth_1.browseAiAuth,
16
+ name: 'task_finished_with_error',
17
+ displayName: 'Task Finished with Error',
18
+ description: 'Triggers when a robot task run fails with an error.',
19
+ aiMetadata: {
20
+ description: 'Fires when a task run for the selected Browse AI robot finishes in a failed/error state, delivering the failed task record. Use to detect and react to scrapes that did not complete successfully.',
21
+ },
22
+ type: pieces_framework_1.TriggerStrategy.WEBHOOK,
23
+ props: {
24
+ robotId: props_1.robotIdDropdown,
25
+ },
26
+ onEnable(context) {
27
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
28
+ var _a, _b, _c, _d, _e, _f;
29
+ const { robotId } = context.propsValue;
30
+ const apiKey = context.auth.secret_text;
31
+ try {
32
+ // Verify robot exists and we have access
33
+ yield (0, client_1.browseAiApiCall)({
34
+ method: pieces_common_1.HttpMethod.GET,
35
+ auth: { apiKey },
36
+ resourceUri: `/robots/${robotId}`,
37
+ });
38
+ const response = yield (0, client_1.browseAiApiCall)({
39
+ method: pieces_common_1.HttpMethod.POST,
40
+ auth: { apiKey },
41
+ resourceUri: `/robots/${robotId}/webhooks`,
42
+ body: {
43
+ hookUrl: context.webhookUrl,
44
+ eventType: 'taskFinishedWithError',
45
+ },
46
+ });
47
+ yield context.store.put(TRIGGER_KEY, response.webhook.id);
48
+ }
49
+ catch (error) {
50
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
51
+ throw new Error(`Robot not found: The robot with ID "${robotId}" does not exist or you do not have access to it. Please verify the robot ID and your permissions.`);
52
+ }
53
+ if (((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 403) {
54
+ throw new Error('Access denied: You do not have permission to set up webhooks for this robot. Please check your Browse AI account permissions and ensure you have webhook access.');
55
+ }
56
+ if (((_c = error.response) === null || _c === void 0 ? void 0 : _c.status) === 400) {
57
+ throw new Error(`Invalid webhook configuration: ${((_e = (_d = error.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.message) || error.message}. Please check your webhook URL and robot ID.`);
58
+ }
59
+ if (((_f = error.response) === null || _f === void 0 ? void 0 : _f.status) === 429) {
60
+ throw new Error('Rate limit exceeded: Too many webhook requests. Please wait a moment and try again.');
61
+ }
62
+ throw new Error(`Failed to set up webhook: ${error.message || 'Unknown error occurred'}. Please check your robot ID and try again.`);
63
+ }
64
+ });
65
+ },
66
+ onDisable(context) {
67
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
68
+ const { robotId } = context.propsValue;
69
+ const webhookId = yield context.store.get(TRIGGER_KEY);
70
+ const apiKey = context.auth.secret_text;
71
+ if (!(0, pieces_framework_2.isNil)(webhookId)) {
72
+ try {
73
+ yield (0, client_1.browseAiApiCall)({
74
+ method: pieces_common_1.HttpMethod.DELETE,
75
+ auth: { apiKey },
76
+ resourceUri: `/robots/${robotId}/webhooks/${webhookId}`,
77
+ });
78
+ }
79
+ catch (error) {
80
+ console.warn(`Warning: Failed to clean up webhook ${webhookId}:`, error.message);
81
+ // Clean up the stored webhook ID even if deletion failed
82
+ yield context.store.delete(TRIGGER_KEY);
83
+ }
84
+ }
85
+ });
86
+ },
87
+ run(context) {
88
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
89
+ const payload = context.payload.body;
90
+ if (payload.event !== 'task.finishedWithError')
91
+ return [];
92
+ return [payload.task];
93
+ });
94
+ },
95
+ test(context) {
96
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
97
+ const { robotId } = context.propsValue;
98
+ const apiKey = context.auth.secret_text;
99
+ const response = yield (0, client_1.browseAiApiCall)({
100
+ method: pieces_common_1.HttpMethod.GET,
101
+ auth: { apiKey },
102
+ resourceUri: `/robots/${robotId}/tasks`,
103
+ query: { status: 'failed', sort: '-createdAt' },
104
+ });
105
+ return response.result.robotTasks.items;
106
+ });
107
+ },
108
+ sampleData: {},
109
+ });
110
+ //# sourceMappingURL=task-finished-with-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-finished-with-error.js","sourceRoot":"","sources":["../../../src/lib/triggers/task-finished-with-error.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@agnocon/piece-browse-ai",
3
+ "version": "0.1.7",
4
+ "description": "AgnoCon browse ai connector",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "require": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "src",
17
+ "LICENSE.MIT-AP"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "vendor": "node ../scripts/vendor-ap.mjs piece-browse-ai"
22
+ },
23
+ "dependencies": {
24
+ "@agnocon/core-utils": "0.2.0",
25
+ "@agnocon/piece-types": "0.3.1",
26
+ "@agnocon/pieces-common": "0.12.8",
27
+ "@agnocon/pieces-framework": "0.36.0",
28
+ "tslib": "2.6.2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "20.17.6",
32
+ "typescript": "5.5.4"
33
+ },
34
+ "license": "MIT",
35
+ "agnocon": {
36
+ "originVersion": "0.1.7"
37
+ },
38
+ "publishConfig": {
39
+ "access": "restricted",
40
+ "tag": "latest"
41
+ },
42
+ "keywords": [
43
+ "agnocon",
44
+ "connector"
45
+ ]
46
+ }
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { createCustomApiCallAction } from '@agnocon/pieces-common';
2
+ import { createPiece } from '@agnocon/pieces-framework';
3
+ import { browseAiAuth } from './lib/common/auth';
4
+ import { getTaskDetailsAction } from './lib/actions/get-task-details';
5
+ import { listRobotsAction } from './lib/actions/list-robots';
6
+ import { runRobotAction } from './lib/actions/run-robot';
7
+ import { taskFinishedWithErrorTrigger } from './lib/triggers/task-finished-with-error';
8
+ import { taskFinishedSuccessfullyTrigger } from './lib/triggers/task-finished-successfully';
9
+ import { PieceCategory } from '@agnocon/pieces-framework';
10
+
11
+ export const browseAi = createPiece({
12
+ displayName: 'Browse AI',
13
+ auth: browseAiAuth,
14
+ minimumSupportedRelease: '0.36.1',
15
+ logoUrl: 'https://cdn.activepieces.com/pieces/browse-ai.png',
16
+ categories:[PieceCategory.PRODUCTIVITY],
17
+ authors: ['aryel780'],
18
+ actions: [
19
+ getTaskDetailsAction,
20
+ listRobotsAction,
21
+ runRobotAction,
22
+ createCustomApiCallAction({
23
+ auth: browseAiAuth,
24
+ baseUrl: () => 'https://api.browse.ai/v2',
25
+ authMapping: async (auth) => ({
26
+ Authorization: `Bearer ${auth.secret_text}`,
27
+ }),
28
+ }),
29
+ ],
30
+ triggers: [
31
+ taskFinishedWithErrorTrigger,
32
+ taskFinishedSuccessfullyTrigger,
33
+ ],
34
+ });
@@ -0,0 +1,52 @@
1
+ import { createAction } from '@agnocon/pieces-framework';
2
+ import { HttpMethod } from '@agnocon/pieces-common';
3
+ import { browseAiApiCall } from '../common/client';
4
+ import { browseAiAuth } from '../common/auth';
5
+ import { robotIdDropdown, taskIdDropdown } from '../common/props';
6
+
7
+ export const getTaskDetailsAction = createAction({
8
+ name: 'get-task-details',
9
+ auth: browseAiAuth,
10
+ displayName: 'Get Task Details',
11
+ description:
12
+ 'Retrieves the details of a specific task executed by a Browse AI robot.',
13
+ audience: 'both',
14
+ aiMetadata: {
15
+ description:
16
+ 'Fetches the full record of one previously-run Browse AI scraping task by robot ID and task ID, including its status and any captured/extracted data. Use to check the outcome or pull results of a known task. Requires both the robot ID and the task ID; read-only and idempotent.',
17
+ idempotent: true,
18
+ },
19
+ props: {
20
+ robotId: robotIdDropdown,
21
+ taskId: taskIdDropdown,
22
+ },
23
+ async run(context) {
24
+ const { robotId, taskId } = context.propsValue;
25
+
26
+ try {
27
+ const response = await browseAiApiCall({
28
+ auth: { apiKey: context.auth.secret_text },
29
+ method: HttpMethod.GET,
30
+ resourceUri: `/robots/${robotId}/tasks/${taskId}`,
31
+ });
32
+
33
+ return response;
34
+ } catch (error: any) {
35
+ if (error.response?.status === 404) {
36
+ throw new Error(
37
+ 'Task not found. Please verify the Robot ID and Task ID.'
38
+ );
39
+ }
40
+
41
+ if (error.response?.status === 401) {
42
+ throw new Error('Authentication failed. Please check your API key.');
43
+ }
44
+
45
+ throw new Error(
46
+ `Failed to fetch task details: ${
47
+ error.message || 'Unknown error occurred'
48
+ }`
49
+ );
50
+ }
51
+ },
52
+ });
@@ -0,0 +1,41 @@
1
+ import { createAction } from '@agnocon/pieces-framework';
2
+ import { HttpMethod } from '@agnocon/pieces-common';
3
+ import { browseAiApiCall } from '../common/client';
4
+ import { browseAiAuth } from '../common/auth';
5
+
6
+ export const listRobotsAction = createAction({
7
+ name: 'list-robots',
8
+ auth: browseAiAuth,
9
+ displayName: 'List Robots',
10
+ description: 'Retrieves all robots available in your account.',
11
+ audience: 'both',
12
+ aiMetadata: {
13
+ description:
14
+ 'Lists all Browse AI robots in the connected account, returning each robot and its ID. Use to discover the available robots or resolve a robot name to the ID needed by other Browse AI actions. Takes no input; read-only and idempotent.',
15
+ idempotent: true,
16
+ },
17
+ props: {},
18
+ async run(context) {
19
+ try {
20
+ const response = await browseAiApiCall({
21
+ auth: { apiKey: context.auth.secret_text },
22
+ method: HttpMethod.GET,
23
+ resourceUri: '/robots',
24
+ });
25
+
26
+ return response;
27
+ } catch (error: any) {
28
+ if (error.response?.status === 401) {
29
+ throw new Error('Authentication failed. Please check your API key.');
30
+ }
31
+
32
+ if (error.response?.status === 429) {
33
+ throw new Error('Rate limit exceeded. Please wait before retrying.');
34
+ }
35
+
36
+ throw new Error(
37
+ `Failed to fetch robots: ${error.message || 'Unknown error occurred'}`
38
+ );
39
+ }
40
+ },
41
+ });
@@ -0,0 +1,65 @@
1
+ import { HttpMethod } from '@agnocon/pieces-common';
2
+ import { createAction, Property } from '@agnocon/pieces-framework';
3
+ import { browseAiApiCall } from '../common/client';
4
+ import { browseAiAuth } from '../common/auth';
5
+ import { robotIdDropdown, robotParameters } from '../common/props';
6
+
7
+ export const runRobotAction = createAction({
8
+ name: 'run-robot',
9
+ auth: browseAiAuth,
10
+ displayName: 'Run a Robot',
11
+ description:
12
+ 'Runs a robot on-demand with custom input parameters.',
13
+ audience: 'both',
14
+ aiMetadata: {
15
+ description:
16
+ 'Starts a new on-demand run of a Browse AI robot, creating a fresh scraping task with the robot-specific input parameters (the required inputs vary per robot and are pulled from its definition). Use to trigger a scrape/extraction; results arrive asynchronously, so poll Get Task Details or use a task-finished trigger for the outcome. Not idempotent: each call queues another task run.',
17
+ idempotent: false,
18
+ },
19
+ props: {
20
+ robotId: robotIdDropdown,
21
+ recordVideo: Property.Checkbox({
22
+ displayName: 'Record Video',
23
+ description:
24
+ 'Try to record a video while running the task.',
25
+ required: false,
26
+ defaultValue: false,
27
+ }),
28
+ robotParams: robotParameters,
29
+ },
30
+ async run(context) {
31
+ const { robotId, recordVideo } = context.propsValue;
32
+
33
+ const inputParameters = context.propsValue.robotParams ?? {};
34
+
35
+ try {
36
+ const response = await browseAiApiCall({
37
+ method: HttpMethod.POST,
38
+ resourceUri: `/robots/${robotId}/tasks`,
39
+ auth: { apiKey: context.auth.secret_text },
40
+ body: {
41
+ recordVideo: recordVideo || false,
42
+ inputParameters,
43
+ },
44
+ });
45
+
46
+ return response;
47
+ } catch (error: any) {
48
+ if (error.response?.status === 401) {
49
+ throw new Error('Authentication failed. Please check your API key.');
50
+ }
51
+
52
+ if (error.response?.status === 404) {
53
+ throw new Error('Robot not found. Please verify the robot ID.');
54
+ }
55
+
56
+ if (error.response?.status === 429) {
57
+ throw new Error('Rate limit exceeded. Please wait before retrying.');
58
+ }
59
+
60
+ throw new Error(
61
+ `Failed to run robot: ${error.message || 'Unknown error occurred'}`
62
+ );
63
+ }
64
+ },
65
+ });
@@ -0,0 +1,24 @@
1
+ import { PieceAuth } from '@agnocon/pieces-framework';
2
+ import { HttpMethod } from '@agnocon/pieces-common';
3
+ import { browseAiApiCall } from './client';
4
+
5
+ export const browseAiAuth = PieceAuth.SecretText({
6
+ displayName: 'API Key',
7
+ description: 'You can find your Browse AI API key on the dashboard under Settings → API Key.',
8
+ required: true,
9
+ validate: async ({ auth }) => {
10
+ try {
11
+ await browseAiApiCall({
12
+ method: HttpMethod.GET,
13
+ resourceUri: '/status',
14
+ auth: { apiKey: auth },
15
+ });
16
+ return { valid: true };
17
+ } catch {
18
+ return {
19
+ valid: false,
20
+ error: 'Invalid API Key. Please check your Browse AI credentials.',
21
+ };
22
+ }
23
+ },
24
+ });
@@ -0,0 +1,85 @@
1
+ import {
2
+ httpClient,
3
+ HttpMethod,
4
+ HttpRequest,
5
+ HttpMessageBody,
6
+ QueryParams,
7
+ } from '@agnocon/pieces-common';
8
+
9
+ export type BrowseAiAuthProps = {
10
+ apiKey: string;
11
+ };
12
+
13
+ export type BrowseAiApiCallParams = {
14
+ method: HttpMethod;
15
+ resourceUri: string;
16
+ query?: Record<string, string | number | string[] | undefined>;
17
+ body?: unknown;
18
+ auth: BrowseAiAuthProps;
19
+ };
20
+
21
+ export async function browseAiApiCall<T extends HttpMessageBody>({
22
+ method,
23
+ resourceUri,
24
+ query,
25
+ body,
26
+ auth,
27
+ }: BrowseAiApiCallParams): Promise<T> {
28
+ const { apiKey } = auth;
29
+
30
+ if (!apiKey) {
31
+ throw new Error('Browse AI API key is required for authentication');
32
+ }
33
+
34
+ const queryParams: QueryParams = {};
35
+
36
+ if (query) {
37
+ for (const [key, value] of Object.entries(query)) {
38
+ if (value !== null && value !== undefined) {
39
+ queryParams[key] = String(value);
40
+ }
41
+ }
42
+ }
43
+
44
+ const baseUrl = `https://api.browse.ai/v2`;
45
+
46
+ const request: HttpRequest = {
47
+ method,
48
+ url: `${baseUrl}${resourceUri}`,
49
+ headers: {
50
+ Authorization: `Bearer ${apiKey}`,
51
+ 'Content-Type': 'application/json',
52
+ },
53
+ queryParams,
54
+ body,
55
+ };
56
+
57
+ try {
58
+ const response = await httpClient.sendRequest<T>(request);
59
+ return response.body;
60
+ } catch (error: any) {
61
+ const statusCode = error.response?.status;
62
+ const errorData = error.response?.data;
63
+
64
+ switch (statusCode) {
65
+ case 400:
66
+ throw new Error(`Bad Request: ${errorData?.message || 'Invalid parameters'}`);
67
+ case 401:
68
+ throw new Error('Unauthorized: Invalid API key. Please check your credentials.');
69
+ case 403:
70
+ throw new Error('Forbidden: You do not have permission to access this resource.');
71
+ case 404:
72
+ throw new Error('Not Found: The requested resource does not exist.');
73
+ case 429:
74
+ throw new Error('Rate Limit Exceeded: Please slow down your requests.');
75
+ case 500:
76
+ throw new Error('Internal Server Error: Something went wrong on Browse AI’s side.');
77
+ default:
78
+ {
79
+ const message = errorData?.message || error.message || 'Unknown error';
80
+ throw new Error(`Browse AI API Error (${statusCode || 'Unknown'}): ${message}`);
81
+ }
82
+
83
+ }
84
+ }
85
+ }