@pipedream/strale 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ import strale from "../../strale.app.mjs";
2
+
3
+ export default {
4
+ name: "Execute Capability",
5
+ version: "0.0.1",
6
+ key: "strale-execute-capability",
7
+ description: "Execute a specific Strale capability by slug with the provided inputs. Returns structured data with quality score and audit trail. [See the documentation](https://strale.dev/docs)",
8
+ type: "action",
9
+ annotations: {
10
+ readOnlyHint: false,
11
+ destructiveHint: false,
12
+ openWorldHint: true,
13
+ },
14
+ props: {
15
+ strale,
16
+ capabilitySlug: {
17
+ propDefinition: [
18
+ strale,
19
+ "capabilitySlug",
20
+ ],
21
+ },
22
+ inputs: {
23
+ propDefinition: [
24
+ strale,
25
+ "inputs",
26
+ ],
27
+ },
28
+ maxPriceCents: {
29
+ propDefinition: [
30
+ strale,
31
+ "maxPriceCents",
32
+ ],
33
+ },
34
+ dryRun: {
35
+ propDefinition: [
36
+ strale,
37
+ "dryRun",
38
+ ],
39
+ },
40
+ },
41
+ async run({ $ }) {
42
+ // Pipedream's object-type prop is usually parsed to a JS object, but
43
+ // can arrive as a string if the user pasted raw JSON in the UI. Coerce
44
+ // defensively so `/v1/do` receives an object as the API expects.
45
+ let parsedInputs = this.inputs;
46
+ if (typeof parsedInputs === "string") {
47
+ try {
48
+ parsedInputs = JSON.parse(parsedInputs);
49
+ } catch {
50
+ throw new Error(
51
+ "The \"Inputs\" field must be a valid JSON object (e.g. {\"email\": \"ops@example.com\"}).",
52
+ );
53
+ }
54
+ }
55
+
56
+ const data = {
57
+ capability_slug: this.capabilitySlug,
58
+ inputs: parsedInputs ?? {},
59
+ max_price_cents: this.maxPriceCents,
60
+ };
61
+
62
+ if (this.dryRun) {
63
+ data.dry_run = true;
64
+ }
65
+
66
+ const response = await this.strale.execute({
67
+ $,
68
+ data,
69
+ });
70
+
71
+ if (this.dryRun) {
72
+ $.export("$summary", `Dry run matched capability "${response.capability?.slug ?? this.capabilitySlug}"`);
73
+ } else {
74
+ $.export("$summary", `Successfully executed "${this.capabilitySlug}" (transaction: ${response?.result?.transaction_id ?? "n/a"})`);
75
+ }
76
+
77
+ return response;
78
+ },
79
+ };
@@ -0,0 +1,82 @@
1
+ import strale from "../../strale.app.mjs";
2
+
3
+ export default {
4
+ name: "Search and Execute",
5
+ version: "0.0.1",
6
+ key: "strale-search-and-execute",
7
+ description: "Describe what you need in plain language \u2014 Strale picks the best capability and executes it in one step. Use this when you don't know the exact capability slug. If you already know the slug, use **Execute Capability** instead; if you only want to discover matches without running anything, use **Search Capabilities**. [See the documentation](https://strale.dev/docs)",
8
+ type: "action",
9
+ annotations: {
10
+ readOnlyHint: false,
11
+ destructiveHint: false,
12
+ openWorldHint: true,
13
+ },
14
+ props: {
15
+ strale,
16
+ task: {
17
+ propDefinition: [
18
+ strale,
19
+ "task",
20
+ ],
21
+ },
22
+ inputs: {
23
+ propDefinition: [
24
+ strale,
25
+ "inputs",
26
+ ],
27
+ optional: true,
28
+ },
29
+ maxPriceCents: {
30
+ propDefinition: [
31
+ strale,
32
+ "maxPriceCents",
33
+ ],
34
+ },
35
+ dryRun: {
36
+ propDefinition: [
37
+ strale,
38
+ "dryRun",
39
+ ],
40
+ },
41
+ },
42
+ async run({ $ }) {
43
+ // Pipedream's object-type prop is usually parsed to a JS object, but
44
+ // can arrive as a string if the user pasted raw JSON in the UI. Coerce
45
+ // defensively so `/v1/do` receives an object as the API expects.
46
+ let parsedInputs = this.inputs;
47
+ if (typeof parsedInputs === "string") {
48
+ try {
49
+ parsedInputs = JSON.parse(parsedInputs);
50
+ } catch {
51
+ throw new Error(
52
+ "The \"Inputs\" field must be a valid JSON object (e.g. {\"email\": \"ops@example.com\"}).",
53
+ );
54
+ }
55
+ }
56
+
57
+ const data = {
58
+ task: this.task,
59
+ inputs: parsedInputs ?? {},
60
+ max_price_cents: this.maxPriceCents,
61
+ };
62
+
63
+ if (this.dryRun) {
64
+ data.dry_run = true;
65
+ const response = await this.strale.execute({
66
+ $,
67
+ data,
68
+ });
69
+ $.export("$summary", `Dry run completed for "${this.task}"`);
70
+ return response;
71
+ }
72
+
73
+ const response = await this.strale.execute({
74
+ $,
75
+ data,
76
+ });
77
+
78
+ $.export("$summary", `Executed "${this.task}" (transaction: ${response?.result?.transaction_id ?? "n/a"})`);
79
+
80
+ return response;
81
+ },
82
+ };
@@ -0,0 +1,42 @@
1
+ import strale from "../../strale.app.mjs";
2
+
3
+ export default {
4
+ name: "Search Capabilities",
5
+ version: "0.0.1",
6
+ key: "strale-search-capabilities",
7
+ description: "Search Strale's catalog of 290+ data capabilities using natural language. Returns matching capabilities with prices and quality scores. [See the documentation](https://strale.dev/docs)",
8
+ type: "action",
9
+ annotations: {
10
+ readOnlyHint: true,
11
+ destructiveHint: false,
12
+ openWorldHint: true,
13
+ },
14
+ props: {
15
+ strale,
16
+ task: {
17
+ propDefinition: [
18
+ strale,
19
+ "task",
20
+ ],
21
+ },
22
+ limit: {
23
+ propDefinition: [
24
+ strale,
25
+ "limit",
26
+ ],
27
+ },
28
+ },
29
+ async run({ $ }) {
30
+ const response = await this.strale.suggest({
31
+ $,
32
+ data: {
33
+ query: this.task,
34
+ limit: this.limit ?? 5,
35
+ },
36
+ });
37
+
38
+ $.export("$summary", `Successfully searched for matching capabilities for "${this.task}"`);
39
+
40
+ return response;
41
+ },
42
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/strale",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Pipedream Strale Components",
5
5
  "main": "strale.app.mjs",
6
6
  "keywords": [
@@ -11,5 +11,8 @@
11
11
  "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
12
12
  "publishConfig": {
13
13
  "access": "public"
14
+ },
15
+ "dependencies": {
16
+ "@pipedream/platform": "^3.1.1"
14
17
  }
15
18
  }
package/strale.app.mjs CHANGED
@@ -1,11 +1,121 @@
1
+ import { axios } from "@pipedream/platform";
2
+
1
3
  export default {
2
4
  type: "app",
3
5
  app: "strale",
4
- propDefinitions: {},
6
+ description: "Strale is the data layer for AI agents — 290+ quality-tested data capabilities including company verification, sanctions screening, VAT validation, invoice extraction, and more. [See the documentation](https://strale.dev/docs)",
7
+ propDefinitions: {
8
+ task: {
9
+ type: "string",
10
+ label: "Task",
11
+ description: "A natural-language description of what you need (e.g. \"verify a Swedish company\", \"validate this VAT number\").",
12
+ },
13
+ capabilitySlug: {
14
+ type: "string",
15
+ label: "Capability Slug",
16
+ description: "The slug of the capability to execute (e.g. `swedish-company-data`, `vat-validate`, `email-validate`). [See the catalog](https://strale.dev).",
17
+ },
18
+ inputs: {
19
+ type: "object",
20
+ label: "Inputs",
21
+ description: "Input parameters for the capability as a JSON object (e.g. `{ \"vat_number\": \"SE556677889901\" }` or `{ \"email\": \"ops@example.com\" }`). The required fields depend on the capability being called.",
22
+ },
23
+ limit: {
24
+ type: "integer",
25
+ label: "Limit",
26
+ description: "Maximum number of results to return.",
27
+ optional: true,
28
+ default: 5,
29
+ },
30
+ maxPriceCents: {
31
+ type: "integer",
32
+ label: "Max Price (cents)",
33
+ description: "Maximum price in euro cents you are willing to pay per execution.",
34
+ optional: true,
35
+ },
36
+ dryRun: {
37
+ type: "boolean",
38
+ label: "Dry Run",
39
+ description: "If `true`, validates the request and returns the matched capability without executing or charging.",
40
+ optional: true,
41
+ default: false,
42
+ },
43
+ },
5
44
  methods: {
6
- // this.$auth contains connected account data
7
- authKeys() {
8
- console.log(Object.keys(this.$auth));
45
+ _apiKey() {
46
+ return this.$auth.api_key;
47
+ },
48
+ _baseUrl() {
49
+ return "https://api.strale.io";
50
+ },
51
+ _headers() {
52
+ const headers = {
53
+ "Content-Type": "application/json",
54
+ };
55
+ const apiKey = this._apiKey();
56
+ if (apiKey) {
57
+ headers["Authorization"] = `Bearer ${apiKey}`;
58
+ }
59
+ return headers;
60
+ },
61
+ async _makeRequest({
62
+ $ = this, path, headers = {}, ...args
63
+ }) {
64
+ try {
65
+ return await axios($, {
66
+ url: `${this._baseUrl()}${path}`,
67
+ ...args,
68
+ headers: {
69
+ ...this._headers(),
70
+ ...headers,
71
+ },
72
+ });
73
+ } catch (err) {
74
+ // The Strale API returns HTTP 500 with a structured body for
75
+ // execution-level failures (missing input fields, capability
76
+ // timeouts, etc.). axios throws on non-2xx — without this catch,
77
+ // Pipedream surfaces it as a generic "Internal server error".
78
+ // Re-throw with the actual message + error_code so the workflow
79
+ // UI shows something actionable.
80
+ const data = err.response?.data;
81
+ const message = data?.message ?? data?.error_code ?? err.message;
82
+ const code = data?.error_code
83
+ ? ` (${data.error_code})`
84
+ : "";
85
+ const status = err.response?.status ?? "";
86
+ const statusLabel = status
87
+ ? ` [HTTP ${status}]`
88
+ : "";
89
+ throw new Error(`Strale API error${statusLabel}${code}: ${message}`);
90
+ }
91
+ },
92
+ suggest(args = {}) {
93
+ return this._makeRequest({
94
+ path: "/v1/suggest",
95
+ method: "post",
96
+ ...args,
97
+ });
98
+ },
99
+ execute(args = {}) {
100
+ return this._makeRequest({
101
+ path: "/v1/do",
102
+ method: "post",
103
+ ...args,
104
+ });
105
+ },
106
+ listCapabilities(args = {}) {
107
+ return this._makeRequest({
108
+ path: "/v1/capabilities",
109
+ ...args,
110
+ });
111
+ },
112
+ getQuality({
113
+ slug, ...args
114
+ } = {}) {
115
+ return this._makeRequest({
116
+ path: `/v1/quality/${slug}`,
117
+ ...args,
118
+ });
9
119
  },
10
120
  },
11
- };
121
+ };