onUpdateConfig("actorInput", value)}
+ value={(config?.actorInput as string) || ""}
/>
JSON input for the Actor. Check the Actor's documentation for required
diff --git a/plugins/apify/steps/run-actor/step.ts b/plugins/apify/steps/run-actor/step.ts
index 89c404bf..610261d0 100644
--- a/plugins/apify/steps/run-actor/step.ts
+++ b/plugins/apify/steps/run-actor/step.ts
@@ -3,6 +3,7 @@ import "server-only";
import { ApifyClient } from "apify-client";
import { fetchCredentials } from "@/lib/credential-fetcher";
import { getErrorMessage } from "@/lib/utils";
+import { type StepInput, withStepLogging } from "@/lib/steps/step-handler";
type ApifyRunActorResult =
| {
@@ -18,56 +19,69 @@ type ApifyRunActorResult =
* Run Apify Actor Step
* Runs an Apify Actor and optionally waits for results
*/
-export async function apifyRunActorStep(input: {
- integrationId?: string;
- actorId: string;
- actorInput?: Record;
-}): Promise {
+export async function apifyRunActorStep(
+ input: {
+ integrationId?: string;
+ actorId: string;
+ actorInput?: string;
+ } & StepInput
+): Promise {
"use step";
- const credentials = input.integrationId
- ? await fetchCredentials(input.integrationId)
- : {};
+ return withStepLogging(input, async () => {
+ const credentials = input.integrationId
+ ? await fetchCredentials(input.integrationId)
+ : {};
- const apiKey = credentials.APIFY_API_KEY;
+ const apiKey = credentials.APIFY_API_KEY;
- if (!apiKey) {
- return {
- success: false,
- error: "Apify API Token is not configured.",
- };
- }
+ if (!apiKey) {
+ return {
+ success: false,
+ error: "Apify API Token is not configured.",
+ };
+ }
+
+ let parsedActorInput = {};
+ if (input?.actorInput) {
+ try {
+ parsedActorInput = JSON.parse(input?.actorInput);
+ } catch (err) {
+ return {
+ success: false,
+ error: `Cannot parse Actor input: ${getErrorMessage(err)}`,
+ };
+ }
+ }
- try {
- const client = new ApifyClient({ token: apiKey });
- const actorClient = client.actor(input.actorId);
- const maxWaitSecs = 120;
+ try {
+ const client = new ApifyClient({ token: apiKey });
+ const actorClient = client.actor(input.actorId);
// Run synchronously and wait for completion
- const runData = await actorClient.call(input.actorInput || {}, {
- waitSecs: maxWaitSecs,
- });
+ const runData = await actorClient.call(parsedActorInput);
// Get dataset items
- let data: unknown[] = [];
+ let datasetItems: unknown[] = [];
if (runData.defaultDatasetId) {
- const datasetItems = await client
- .dataset(runData.defaultDatasetId)
- .listItems();
- data = datasetItems.items;
+ const dataset = await client
+ .dataset(runData.defaultDatasetId)
+ .listItems();
+ datasetItems = dataset.items;
}
return {
- success: true,
- runId: runData.id || "unknown",
- status: runData.status || "SUCCEEDED",
- datasetId: runData.defaultDatasetId,
- data,
+ success: true,
+ runId: runData.id || "unknown",
+ status: runData.status || "SUCCEEDED",
+ datasetId: runData.defaultDatasetId,
+ datasetItems,
+ };
+ } catch (error) {
+ return {
+ success: false,
+ error: `Failed to run Actor: ${getErrorMessage(error)}`,
};
- } catch (error) {
- return {
- success: false,
- error: `Failed to run Actor: ${getErrorMessage(error)}`,
- };
- }
+ }
+ });
}
diff --git a/plugins/apify/steps/scrape-single-url/config.tsx b/plugins/apify/steps/scrape-single-url/config.tsx
deleted file mode 100644
index e3c0db30..00000000
--- a/plugins/apify/steps/scrape-single-url/config.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { Label } from "@/components/ui/label";
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { TemplateBadgeInput } from "@/components/ui/template-badge-input";
-
-/**
- * Scrape Single URL Config Fields Component
- * UI for configuring the scrape single URL action
- */
-export function ScrapeSingleUrlConfigFields({
- config,
- onUpdateConfig,
- disabled,
-}: {
- config: Record;
- onUpdateConfig: (key: string, value: unknown) => void;
- disabled?: boolean;
-}) {
- return (
-
-
-
-
onUpdateConfig("url", value)}
- placeholder="https://example.com or {{NodeName.url}}"
- value={(config?.url as string) || ""}
- />
-
- Enter the URL to scrape or use a template reference.
-
-
-
-
-
-
-
- Select the crawler type to use for scraping.
-
-
-
- );
-}
diff --git a/plugins/apify/steps/scrape-single-url/step.ts b/plugins/apify/steps/scrape-single-url/step.ts
index 5adf2945..3b0bb7b7 100644
--- a/plugins/apify/steps/scrape-single-url/step.ts
+++ b/plugins/apify/steps/scrape-single-url/step.ts
@@ -3,6 +3,7 @@ import "server-only";
import { ApifyClient } from "apify-client";
import { fetchCredentials } from "@/lib/credential-fetcher";
import { getErrorMessage } from "@/lib/utils";
+import { type StepInput, withStepLogging } from "@/lib/steps/step-handler";
type ScrapeSingleUrlResult =
| {
@@ -17,83 +18,90 @@ type ScrapeSingleUrlResult =
* Scrape Single URL Step
* Scrapes a single URL using apify/website-content-crawler and returns markdown
*/
-export async function scrapeSingleUrlStep(input: {
- integrationId?: string;
- url: string;
- crawlerType?: string;
-}): Promise {
+export async function scrapeSingleUrlStep(
+ input: {
+ integrationId?: string;
+ url: string;
+ crawlerType?: string;
+ } & StepInput
+): Promise {
"use step";
- const credentials = input.integrationId
- ? await fetchCredentials(input.integrationId)
- : {};
+ return withStepLogging(input, async () => {
+ const credentials = input.integrationId
+ ? await fetchCredentials(input.integrationId)
+ : {};
- const apiKey = credentials.APIFY_API_KEY;
+ const apiKey = credentials.APIFY_API_KEY;
- if (!apiKey) {
- return {
- success: false,
- error: "Apify API Token is not configured.",
- };
- }
+ if (!apiKey) {
+ return {
+ success: false,
+ error: "Apify API Token is not configured.",
+ };
+ }
- if (!input.url) {
- return {
- success: false,
- error: "URL is required.",
- };
- }
+ if (!input.url) {
+ return {
+ success: false,
+ error: "URL is required.",
+ };
+ }
- try {
- const client = new ApifyClient({ token: apiKey });
- const actorClient = client.actor("apify/website-content-crawler");
- const crawlerType = input.crawlerType || "playwright";
+ try {
+ const client = new ApifyClient({ token: apiKey });
+ const actorClient = client.actor("apify/website-content-crawler");
+ const crawlerType = input.crawlerType || "playwright:adaptive";
- // Prepare actor input
- const actorInput = {
- startUrls: [{ url: input.url }],
- crawlerType,
+ // Prepare actor input
+ const actorInput = {
+ startUrls: [{ url: input.url }],
+ crawlerType,
maxCrawlDepth: 0,
maxCrawlPages: 1,
maxResults: 1,
proxyConfiguration: {
- useApifyProxy: true,
+ useApifyProxy: true,
},
removeCookieWarnings: true,
- saveHtml: true,
saveMarkdown: true,
- };
+ };
- // Run synchronously and wait for completion
- const maxWaitSecs = 120;
- const runData = await actorClient.call(actorInput, {
- waitSecs: maxWaitSecs,
- });
+ // Run synchronously and wait for completion (waits indefinitely if waitSecs not specified)
+ const runData = await actorClient.call(actorInput);
+ console.log("[Scrape Single URL] Actor call completed:", {
+ runId: runData.id,
+ status: runData.status,
+ hasDataset: !!runData.defaultDatasetId,
+ });
- // Get dataset items
- let markdown: string | undefined;
- if (runData.defaultDatasetId) {
- const datasetItems = await client
- .dataset(runData.defaultDatasetId)
- .listItems();
+ // Get dataset items
+ let markdown: string | undefined;
+ if (runData.defaultDatasetId) {
+ const datasetItems = await client
+ .dataset(runData.defaultDatasetId)
+ .listItems();
- // Extract markdown from the first item
- if (datasetItems.items && datasetItems.items.length > 0) {
- const firstItem = datasetItems.items[0] as Record;
- markdown = (firstItem.markdown as string) || (firstItem.text as string) || undefined;
+ // Extract markdown from the first item
+ if (datasetItems.items && datasetItems.items.length > 0) {
+ const firstItem = datasetItems.items[0] as Record;
+ markdown = (firstItem.markdown as string);
+ }
}
- }
- return {
- success: true,
- runId: runData.id || "unknown",
- status: runData.status || "SUCCEEDED",
- markdown,
- };
- } catch (error) {
- return {
- success: false,
- error: `Failed to scrape URL: ${getErrorMessage(error)}`,
- };
- }
+ const result: ScrapeSingleUrlResult = {
+ success: true,
+ runId: runData.id || "unknown",
+ status: runData.status || "SUCCEEDED",
+ markdown,
+ };
+
+ return result;
+ } catch (error) {
+ return {
+ success: false,
+ error: `Failed to scrape URL: ${getErrorMessage(error)}`,
+ };
+ }
+ });
}
From fce3519e32354acd73617ca245a74495e7efcea6 Mon Sep 17 00:00:00 2001
From: drobnikj
Date: Wed, 3 Dec 2025 11:29:07 +0100
Subject: [PATCH 14/18] fix: review comments fix
---
README.md | 2 +-
.../[integrationId]/test/route.ts | 2 +-
components/ui/template-badge-json.tsx | 6 +++
lib/step-registry.ts | 2 +-
lib/steps/index.ts | 2 +-
plugins/apify/codegen/run-actor.ts | 8 ++--
plugins/apify/codegen/scrape-single-url.ts | 4 +-
plugins/apify/icon.tsx | 2 +-
plugins/apify/index.tsx | 14 +++---
plugins/apify/settings.tsx | 47 -------------------
plugins/apify/steps/run-actor/config.tsx | 2 +-
plugins/apify/steps/run-actor/step.ts | 6 +--
plugins/apify/steps/scrape-single-url/step.ts | 7 +--
plugins/apify/test.ts | 2 +-
14 files changed, 30 insertions(+), 76 deletions(-)
delete mode 100644 plugins/apify/settings.tsx
diff --git a/README.md b/README.md
index c8d580e2..d0bb35ec 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,7 @@ Visit [http://localhost:3000](http://localhost:3000) to get started.
- **AI Gateway**: Generate Text, Generate Image
-- **Apify**: Run Apify Actor, Scrape Single URL
+- **Apify**: Run Actor, Scrape Single URL
- **Firecrawl**: Scrape URL, Search Web
- **Linear**: Create Ticket, Find Issues
- **Resend**: Send Email
diff --git a/app/api/integrations/[integrationId]/test/route.ts b/app/api/integrations/[integrationId]/test/route.ts
index 1af52776..3085f617 100644
--- a/app/api/integrations/[integrationId]/test/route.ts
+++ b/app/api/integrations/[integrationId]/test/route.ts
@@ -70,7 +70,7 @@ export async function POST(
);
break;
case "apify":
- result = await testApifyConnection(integration.config.apifyApiKey);
+ result = await testApifyConnection(integration.config.apifyApiToken);
break;
default:
return NextResponse.json(
diff --git a/components/ui/template-badge-json.tsx b/components/ui/template-badge-json.tsx
index b67492fd..223a88a2 100644
--- a/components/ui/template-badge-json.tsx
+++ b/components/ui/template-badge-json.tsx
@@ -45,6 +45,12 @@ export function TemplateBadgeJson({
return;
}
+ // Ensure that parsable values (not object) throws
+ if (!/^\s*\{[\s\S]*\}\s*$/.test(value)) {
+ setJsonError("Value must be a JSON object");
+ return;
+ }
+
// Parse JSON directly - template variables will be treated as normal strings
try {
JSON.parse(value);
diff --git a/lib/step-registry.ts b/lib/step-registry.ts
index 6e51f4a2..48876bc9 100644
--- a/lib/step-registry.ts
+++ b/lib/step-registry.ts
@@ -122,7 +122,7 @@ export const PLUGIN_STEP_IMPORTERS: Record = {
export const ACTION_LABELS: Record = {
"ai-gateway/generate-text": "Generate Text",
"ai-gateway/generate-image": "Generate Image",
- "apify/run-actor": "Run Apify Actor",
+ "apify/run-actor": "Run Actor",
"apify/scrape-single-url": "Scrape Single URL",
"firecrawl/scrape": "Scrape URL",
"firecrawl/search": "Search Web",
diff --git a/lib/steps/index.ts b/lib/steps/index.ts
index 14269795..32959688 100644
--- a/lib/steps/index.ts
+++ b/lib/steps/index.ts
@@ -66,7 +66,7 @@ export const stepRegistry: Record = {
(await import("../../plugins/firecrawl/steps/search")).firecrawlSearchStep(
input as Parameters[0]
),
- "Run Apify Actor": async (input) =>
+ "Run Actor": async (input) =>
(
await import("../../plugins/apify/steps/run-actor/step")
).apifyRunActorStep(input as Parameters[0]),
diff --git a/plugins/apify/codegen/run-actor.ts b/plugins/apify/codegen/run-actor.ts
index 826c0aea..aa43bb55 100644
--- a/plugins/apify/codegen/run-actor.ts
+++ b/plugins/apify/codegen/run-actor.ts
@@ -1,5 +1,5 @@
/**
- * Code generation template for Run Apify Actor action
+ * Code generation template for Run Actor action
* This template is used when exporting workflows to standalone Next.js projects
* It uses environment variables instead of integrationId
*/
@@ -11,10 +11,10 @@ export async function apifyRunActorStep(input: {
}) {
"use step";
- const apiKey = process.env.APIFY_API_KEY;
+ const apiKey = process.env.APIFY_API_TOKEN;
if (!apiKey) {
- throw new Error("Apify API Token is not configured. Set APIFY_API_KEY environment variable.");
+ throw new Error("Apify API Token is not configured. Set APIFY_API_TOKEN environment variable.");
}
let parsedActorInput: Record = {};
@@ -46,7 +46,7 @@ export async function apifyRunActorStep(input: {
runId: runData.id || "unknown",
status: runData.status || "SUCCEEDED",
datasetId: runData.defaultDatasetId,
- datasetItems,
+ data: datasetItems,
};
} catch (error) {
throw new Error(\`Failed to run Actor: \${error instanceof Error ? error.message : String(error)}\`);
diff --git a/plugins/apify/codegen/scrape-single-url.ts b/plugins/apify/codegen/scrape-single-url.ts
index ec35c6c8..cc4d5d82 100644
--- a/plugins/apify/codegen/scrape-single-url.ts
+++ b/plugins/apify/codegen/scrape-single-url.ts
@@ -11,10 +11,10 @@ export async function scrapeSingleUrlStep(input: {
}) {
"use step";
- const apiKey = process.env.APIFY_API_KEY;
+ const apiKey = process.env.APIFY_API_TOKEN;
if (!apiKey) {
- throw new Error("Apify API Token is not configured. Set APIFY_API_KEY environment variable.");
+ throw new Error("Apify API Token is not configured. Set APIFY_API_TOKEN environment variable.");
}
if (!input.url) {
diff --git a/plugins/apify/icon.tsx b/plugins/apify/icon.tsx
index 26358944..6329437e 100644
--- a/plugins/apify/icon.tsx
+++ b/plugins/apify/icon.tsx
@@ -2,7 +2,7 @@ import Image from "next/image";
/**
* Apify Icon Component
- * Used as the icon for Run Apify Actor action
+ * Used as the icon for Run Actor action
*/
export function ApifyIcon({ className }: { className?: string }) {
return (
diff --git a/plugins/apify/index.tsx b/plugins/apify/index.tsx
index bd2b8935..faab5338 100644
--- a/plugins/apify/index.tsx
+++ b/plugins/apify/index.tsx
@@ -13,12 +13,12 @@ const apifyPlugin: IntegrationPlugin = {
formFields: [
{
- id: "apifyApiKey",
- label: "API Token",
+ id: "apifyApiToken",
+ label: "Apify API Token",
type: "password",
placeholder: "apify_api_...",
- configKey: "apifyApiKey",
- envVar: "APIFY_API_KEY",
+ configKey: "apifyApiToken",
+ envVar: "APIFY_API_TOKEN",
helpText: "Get your API token from ",
helpLink: {
text: "Apify Console",
@@ -37,7 +37,7 @@ const apifyPlugin: IntegrationPlugin = {
actions: [
{
slug: "run-actor",
- label: "Run Apify Actor",
+ label: "Run Actor",
description: "Run an Apify Actor and get results",
category: "Apify",
stepFunction: "apifyRunActorStep",
@@ -47,8 +47,8 @@ const apifyPlugin: IntegrationPlugin = {
key: "actorId",
label: "Actor (ID or name)",
type: "template-input",
- placeholder: "apify/web-scraper or {{NodeName.actorId}}",
- example: "apify/web-scraper",
+ placeholder: "apify/website-content-crawler or {{NodeName.actorId}}",
+ example: "apify/website-content-crawler",
required: true,
},
{
diff --git a/plugins/apify/settings.tsx b/plugins/apify/settings.tsx
deleted file mode 100644
index 932f9a56..00000000
--- a/plugins/apify/settings.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Input } from "@/components/ui/input";
-import { Label } from "@/components/ui/label";
-
-export function ApifySettings({
- apiKey,
- hasKey,
- onApiKeyChange,
-}: {
- apiKey: string;
- hasKey?: boolean;
- onApiKeyChange: (key: string) => void;
- showCard?: boolean;
- config?: Record;
- onConfigChange?: (key: string, value: string) => void;
-}) {
- return (
-
-
-
-
onApiKeyChange(e.target.value)}
- placeholder={
- hasKey ? "API token is configured" : "Enter your Apify API token"
- }
- type="password"
- value={apiKey}
- />
-
- Get your API token from{" "}
-
- Apify Console
-
- .
-
-
-
- );
-}
diff --git a/plugins/apify/steps/run-actor/config.tsx b/plugins/apify/steps/run-actor/config.tsx
index b34ad89b..e085da9e 100644
--- a/plugins/apify/steps/run-actor/config.tsx
+++ b/plugins/apify/steps/run-actor/config.tsx
@@ -3,7 +3,7 @@ import { TemplateBadgeInput } from "@/components/ui/template-badge-input";
import { TemplateBadgeJson } from "@/components/ui/template-badge-json";
/**
- * Run Apify Actor Config Fields Component
+ * Run Actor Config Fields Component
* UI for configuring the run actor action
*/
export function RunActorConfigFields({
diff --git a/plugins/apify/steps/run-actor/step.ts b/plugins/apify/steps/run-actor/step.ts
index 610261d0..3541a6f3 100644
--- a/plugins/apify/steps/run-actor/step.ts
+++ b/plugins/apify/steps/run-actor/step.ts
@@ -16,7 +16,7 @@ type ApifyRunActorResult =
| { success: false; error: string };
/**
- * Run Apify Actor Step
+ * Run Actor Step
* Runs an Apify Actor and optionally waits for results
*/
export async function apifyRunActorStep(
@@ -33,7 +33,7 @@ export async function apifyRunActorStep(
? await fetchCredentials(input.integrationId)
: {};
- const apiKey = credentials.APIFY_API_KEY;
+ const apiKey = credentials.APIFY_API_TOKEN;
if (!apiKey) {
return {
@@ -75,7 +75,7 @@ export async function apifyRunActorStep(
runId: runData.id || "unknown",
status: runData.status || "SUCCEEDED",
datasetId: runData.defaultDatasetId,
- datasetItems,
+ data: datasetItems,
};
} catch (error) {
return {
diff --git a/plugins/apify/steps/scrape-single-url/step.ts b/plugins/apify/steps/scrape-single-url/step.ts
index 3b0bb7b7..09c9f966 100644
--- a/plugins/apify/steps/scrape-single-url/step.ts
+++ b/plugins/apify/steps/scrape-single-url/step.ts
@@ -32,7 +32,7 @@ export async function scrapeSingleUrlStep(
? await fetchCredentials(input.integrationId)
: {};
- const apiKey = credentials.APIFY_API_KEY;
+ const apiKey = credentials.APIFY_API_TOKEN;
if (!apiKey) {
return {
@@ -69,11 +69,6 @@ export async function scrapeSingleUrlStep(
// Run synchronously and wait for completion (waits indefinitely if waitSecs not specified)
const runData = await actorClient.call(actorInput);
- console.log("[Scrape Single URL] Actor call completed:", {
- runId: runData.id,
- status: runData.status,
- hasDataset: !!runData.defaultDatasetId,
- });
// Get dataset items
let markdown: string | undefined;
diff --git a/plugins/apify/test.ts b/plugins/apify/test.ts
index 8382720f..729bf786 100644
--- a/plugins/apify/test.ts
+++ b/plugins/apify/test.ts
@@ -2,7 +2,7 @@ import { ApifyClient } from "apify-client";
export async function testApify(credentials: Record) {
try {
- const client = new ApifyClient({ token: credentials.APIFY_API_KEY });
+ const client = new ApifyClient({ token: credentials.APIFY_API_TOKEN });
await client.user("me").get();
return { success: true };
} catch (error) {
From 3885666fb27c64f4ce1fe3e766e23ffd34b7185d Mon Sep 17 00:00:00 2001
From: drobnikj
Date: Wed, 3 Dec 2025 11:49:07 +0100
Subject: [PATCH 15/18] fix: update readme
---
README.md | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/README.md b/README.md
index d0bb35ec..2c99c9ba 100644
--- a/README.md
+++ b/README.md
@@ -263,6 +263,30 @@ const searchResult = await firecrawlSearchStep({
});
```
+### Apify (Web Scraping)
+
+```typescript
+import {
+ scrapeSingleUrlStep,
+ apifyRunActorStep,
+} from "@/lib/steps/apify";
+
+// Scrape a URL
+const scrapeResult = await scrapeSingleUrlStep({
+ url: "https://example.com",
+ crawlerType: "playwright:adaptive",
+});
+
+// Run an Actor from Apify Store
+const searchMapsResults = await apifyRunActorStep({
+ actorId: "compass/crawler-google-places",
+ actorInput: {
+ searchStringsArray: [ "restaurants in San Francisco" ]
+ },
+});
+```
+
+
## Tech Stack
- **Framework**: Next.js 16 with React 19
From d391d21ac35f74d168c2db41fc11b2ba815f0850 Mon Sep 17 00:00:00 2001
From: drobnikj
Date: Wed, 3 Dec 2025 12:00:41 +0100
Subject: [PATCH 16/18] fix: update apifyRunActorStep to accept object same as
string
---
plugins/apify/codegen/run-actor.ts | 16 +++++++++++-----
plugins/apify/steps/run-actor/step.ts | 20 +++++++++++++-------
2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/plugins/apify/codegen/run-actor.ts b/plugins/apify/codegen/run-actor.ts
index aa43bb55..9306ef3f 100644
--- a/plugins/apify/codegen/run-actor.ts
+++ b/plugins/apify/codegen/run-actor.ts
@@ -7,7 +7,7 @@ export const runActorCodegenTemplate = `import { ApifyClient } from "apify-clien
export async function apifyRunActorStep(input: {
actorId: string;
- actorInput?: string;
+ actorInput?: string | Record | null;
}) {
"use step";
@@ -19,10 +19,16 @@ export async function apifyRunActorStep(input: {
let parsedActorInput: Record = {};
if (input.actorInput) {
- try {
- parsedActorInput = JSON.parse(input.actorInput);
- } catch (err) {
- throw new Error(\`Cannot parse Actor input: \${err instanceof Error ? err.message : String(err)}\`);
+ // If it's already an object, use it directly
+ if (typeof input.actorInput === "object" && !Array.isArray(input.actorInput)) {
+ parsedActorInput = input.actorInput;
+ } else if (typeof input.actorInput === "string") {
+ // If it's a string, parse it
+ try {
+ parsedActorInput = JSON.parse(input.actorInput);
+ } catch (err) {
+ throw new Error(\`Cannot parse Actor input: \${err instanceof Error ? err.message : String(err)}\`);
+ }
}
}
diff --git a/plugins/apify/steps/run-actor/step.ts b/plugins/apify/steps/run-actor/step.ts
index 3541a6f3..44a586f6 100644
--- a/plugins/apify/steps/run-actor/step.ts
+++ b/plugins/apify/steps/run-actor/step.ts
@@ -23,7 +23,7 @@ export async function apifyRunActorStep(
input: {
integrationId?: string;
actorId: string;
- actorInput?: string;
+ actorInput?: string | Record | null;
} & StepInput
): Promise {
"use step";
@@ -42,16 +42,22 @@ export async function apifyRunActorStep(
};
}
- let parsedActorInput = {};
+ let parsedActorInput: Record = {};
if (input?.actorInput) {
+ // If it's already an object, use it directly
+ if (typeof input.actorInput === "object" && !Array.isArray(input.actorInput)) {
+ parsedActorInput = input.actorInput;
+ } else if (typeof input.actorInput === "string") {
+ // If it's a string, parse it
try {
- parsedActorInput = JSON.parse(input?.actorInput);
+ parsedActorInput = JSON.parse(input.actorInput);
} catch (err) {
- return {
- success: false,
- error: `Cannot parse Actor input: ${getErrorMessage(err)}`,
- };
+ return {
+ success: false,
+ error: `Cannot parse Actor input: ${getErrorMessage(err)}`,
+ };
}
+ }
}
try {
From eb901028b0781f3004f01a8a4f3344635399599e Mon Sep 17 00:00:00 2001
From: drobnikj
Date: Thu, 4 Dec 2025 11:52:02 +0100
Subject: [PATCH 17/18] fix: resolving merge conflicts
---
pnpm-lock.yaml | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0c7d892f..b3574029 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -50,6 +50,9 @@ importers:
ai:
specifier: ^5.0.102
version: 5.0.102(zod@4.1.12)
+ apify-client:
+ specifier: ^2.20.0
+ version: 2.20.0
better-auth:
specifier: ^1.3.34
version: 1.3.34(next@16.0.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
@@ -194,6 +197,15 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
+ '@apify/consts@2.48.0':
+ resolution: {integrity: sha512-a0HeYDxAbbkRxc9z2N6beMFAmAJSgBw8WuKUwV+KmCuPyGUVLp54fYzjQ63p9Gv5IVFC88/HMXpAzI29ARgO5w==}
+
+ '@apify/log@2.5.28':
+ resolution: {integrity: sha512-jU8qIvU+Crek8glBjFl3INjJQWWDR9n2z9Dr0WvUI8KJi0LG9fMdTvV+Aprf9z1b37CbHXgiZkA1iPlNYxKOEQ==}
+
+ '@apify/utilities@2.24.0':
+ resolution: {integrity: sha512-tc1lH0T4C0KOrCFKy4+pP/bj0VkAKUOqG1Unyyz0ddKv2b8R1PKxboEx2sGDZSHxCLA+nbk/kC2jgIvGqen2KA==}
+
'@aws-crypto/sha256-browser@5.2.0':
resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==}
@@ -413,6 +425,10 @@ packages:
'@clack/prompts@0.11.0':
resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==}
+ '@crawlee/types@3.15.3':
+ resolution: {integrity: sha512-RvgVPXrsQw4GQIUXrC1z1aNOedUPJnZ/U/8n+jZ0fu1Iw9moJVMuiuIxSI8q1P6BA84aWZdalyfDWBZ3FMjsiw==}
+ engines: {node: '>=16.0.0'}
+
'@drizzle-team/brocli@0.10.2':
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
@@ -2039,6 +2055,10 @@ packages:
resolution: {integrity: sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==}
engines: {node: '>=20.0.0'}
+ '@sindresorhus/is@4.6.0':
+ resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
+ engines: {node: '>=10'}
+
'@sindresorhus/merge-streams@4.0.0':
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
engines: {node: '>=18'}
@@ -2626,6 +2646,10 @@ packages:
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+ ansi-colors@4.1.3:
+ resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+ engines: {node: '>=6'}
+
ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
@@ -2654,6 +2678,9 @@ packages:
resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==}
engines: {node: '>=14'}
+ apify-client@2.20.0:
+ resolution: {integrity: sha512-oEMTImVVRZ5n8JkFV6dgbBFL3Xqz+GTwjUCjn/hwSNkow31Q8VNGk4qYDfRjkoqNQJ3ZirhtCwTnhkSXn1Tf+g==}
+
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -2672,6 +2699,9 @@ packages:
resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==}
engines: {node: '>=12.0.0'}
+ async-retry@1.3.3:
+ resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
+
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
@@ -2860,6 +2890,10 @@ packages:
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
engines: {node: ^14.18.0 || >=16.10.0}
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@@ -2995,6 +3029,10 @@ packages:
dompurify@3.1.7:
resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==}
+ dot-prop@6.0.1:
+ resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
+ engines: {node: '>=10'}
+
dotenv@17.2.3:
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
engines: {node: '>=12'}
@@ -3479,6 +3517,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-obj@2.0.0:
+ resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
+ engines: {node: '>=8'}
+
is-plain-obj@4.1.0:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
@@ -3684,6 +3726,10 @@ packages:
resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ lodash.isequal@4.5.0:
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
+
log-symbols@6.0.0:
resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==}
engines: {node: '>=18'}
@@ -3909,6 +3955,10 @@ packages:
resolution: {integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==}
engines: {node: '>= 6.0'}
+ ow@0.28.2:
+ resolution: {integrity: sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q==}
+ engines: {node: '>=12'}
+
oxc-resolver@11.13.2:
resolution: {integrity: sha512-1SXVyYQ9bqMX3uZo8Px81EG7jhZkO9PvvR5X9roY5TLYVm4ZA7pbPDNlYaDBBeF9U+YO3OeMNoHde52hrcCu8w==}
@@ -4522,6 +4572,10 @@ packages:
resolution: {integrity: sha512-4MYBu2UuYq6wwNtqlOTUobeUYjXH+RzpSFRQKWOlRw18T47mjGq5Tp4odGS0GK7OGnUwxKG2Cm6JkLx6RLWmBA==}
engines: {node: '>=22', pnpm: '>=9'}
+ vali-date@1.0.0:
+ resolution: {integrity: sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg==}
+ engines: {node: '>=0.10.0'}
+
vaul@1.1.2:
resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==}
peerDependencies:
@@ -4674,6 +4728,18 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
+ '@apify/consts@2.48.0': {}
+
+ '@apify/log@2.5.28':
+ dependencies:
+ '@apify/consts': 2.48.0
+ ansi-colors: 4.1.3
+
+ '@apify/utilities@2.24.0':
+ dependencies:
+ '@apify/consts': 2.48.0
+ '@apify/log': 2.5.28
+
'@aws-crypto/sha256-browser@5.2.0':
dependencies:
'@aws-crypto/sha256-js': 5.2.0
@@ -5204,6 +5270,10 @@ snapshots:
picocolors: 1.1.1
sisteransi: 1.0.5
+ '@crawlee/types@3.15.3':
+ dependencies:
+ tslib: 2.8.1
+
'@drizzle-team/brocli@0.10.2': {}
'@emnapi/core@1.7.1':
@@ -6732,6 +6802,8 @@ snapshots:
'@peculiar/asn1-x509': 2.5.0
'@peculiar/x509': 1.14.0
+ '@sindresorhus/is@4.6.0': {}
+
'@sindresorhus/merge-streams@4.0.0': {}
'@slack/logger@4.0.0':
@@ -7487,6 +7559,8 @@ snapshots:
dependencies:
string-width: 4.2.3
+ ansi-colors@4.1.3: {}
+
ansi-escapes@4.3.2:
dependencies:
type-fest: 0.21.3
@@ -7507,6 +7581,22 @@ snapshots:
ansis@3.17.0: {}
+ apify-client@2.20.0:
+ dependencies:
+ '@apify/consts': 2.48.0
+ '@apify/log': 2.5.28
+ '@apify/utilities': 2.24.0
+ '@crawlee/types': 3.15.3
+ ansi-colors: 4.1.3
+ async-retry: 1.3.3
+ axios: 1.13.1
+ content-type: 1.0.5
+ ow: 0.28.2
+ tslib: 2.8.1
+ type-fest: 4.41.0
+ transitivePeerDependencies:
+ - debug
+
argparse@2.0.1: {}
aria-hidden@1.2.6:
@@ -7523,6 +7613,10 @@ snapshots:
pvutils: 1.1.5
tslib: 2.8.1
+ async-retry@1.3.3:
+ dependencies:
+ retry: 0.13.1
+
async@3.2.6: {}
asynckit@0.4.0: {}
@@ -7702,6 +7796,8 @@ snapshots:
consola@3.4.2: {}
+ content-type@1.0.5: {}
+
convert-source-map@2.0.0:
optional: true
@@ -7816,6 +7912,10 @@ snapshots:
dompurify@3.1.7: {}
+ dot-prop@6.0.1:
+ dependencies:
+ is-obj: 2.0.0
+
dotenv@17.2.3: {}
drizzle-kit@0.31.6:
@@ -8224,6 +8324,8 @@ snapshots:
is-number@7.0.0: {}
+ is-obj@2.0.0: {}
+
is-plain-obj@4.1.0: {}
is-stream@2.0.1: {}
@@ -8392,6 +8494,8 @@ snapshots:
dependencies:
p-locate: 6.0.0
+ lodash.isequal@4.5.0: {}
+
log-symbols@6.0.0:
dependencies:
chalk: 5.6.2
@@ -8596,6 +8700,14 @@ snapshots:
os-paths@4.4.0: {}
+ ow@0.28.2:
+ dependencies:
+ '@sindresorhus/is': 4.6.0
+ callsites: 3.1.0
+ dot-prop: 6.0.1
+ lodash.isequal: 4.5.0
+ vali-date: 1.0.0
+
oxc-resolver@11.13.2:
optionalDependencies:
'@oxc-resolver/binding-android-arm-eabi': 11.13.2
@@ -9225,6 +9337,8 @@ snapshots:
v0-sdk@0.15.1: {}
+ vali-date@1.0.0: {}
+
vaul@1.1.2(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies:
'@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
From 83a1f46f006248708dc325d57dbf894a1a3a631a Mon Sep 17 00:00:00 2001
From: drobnikj
Date: Fri, 5 Dec 2025 15:17:09 +0100
Subject: [PATCH 18/18] fix: fix readme imports
---
README.md | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index f28eda04..16a3d93d 100644
--- a/README.md
+++ b/README.md
@@ -272,10 +272,8 @@ const searchResult = await firecrawlSearchStep({
### Apify (Web Scraping)
```typescript
-import {
- scrapeSingleUrlStep,
- apifyRunActorStep,
-} from "@/lib/steps/apify";
+import { apifyRunActorStep } from "@/lib/apify/steps/run-actor/step";
+import { scrapeSingleUrlStep } from "@/lib/apify/steps/scrape-single-url/step";
// Scrape a URL
const scrapeResult = await scrapeSingleUrlStep({