PSAPify.psm1

#Region '.\Private\Get-ApifyDatasetItems.ps1' -1

<#
.SYNOPSIS
    Retrieves items from an Apify dataset.
.DESCRIPTION
    Fetches the items from the specified Apify dataset using the dataset ID.
.PARAMETER DefaultDatasetId
    The dataset ID returned from a completed actor run.
.EXAMPLE
    Get-ApifyDatasetItems -DefaultDatasetId 'xyz789'
.NOTES
    Requires the environment variable 'ApifyToken' to be set with your Apify API token.
#>

function Get-ApifyDatasetItems {
    param(
        [string]$DefaultDatasetId # The dataset ID returned from the previous step
    )

    $url = "https://api.apify.com/v2/datasets/$DefaultDatasetId/items"
    $headers = @{
        "Authorization" = "Bearer $env:ApifyToken"
    }

    $response = Invoke-RestMethod -Method GET -Uri $url -Headers $headers
    return $response
}
#EndRegion '.\Private\Get-ApifyDatasetItems.ps1' 26
#Region '.\Private\Invoke-ApifyRunActor.ps1' -1

<#
.SYNOPSIS
    Starts an Apify actor run via the Apify API.
.DESCRIPTION
    Sends a POST request to the Apify API to start an actor run with the specified input.
.PARAMETER Url
    The URL to the Apify actor run endpoint.
.PARAMETER RunInput
    The input object (hashtable or PSObject) to pass to the actor.
.EXAMPLE
    $input = @{ foo = 'bar' }
    Invoke-ApifyRunActor -Url 'https://api.apify.com/v2/acts/apify~hello-world/runs' -RunInput $input
.NOTES
    Requires the environment variable 'ApifyToken' to be set with your Apify API token.
#>

function Invoke-ApifyRunActor {
    param(
        [string]$Url,
        [Parameter(Mandatory = $true)]
        [object]$RunInput # Accepts a hashtable or PSObject
    )

    $headers = @{
        "Content-Type"  = "application/json"
        "Authorization" = "Bearer $env:ApifyToken"
    }
    $body = $RunInput | ConvertTo-Json -Depth 10

    $response = Invoke-RestMethod -Method POST -Uri $Url -Headers $headers -Body $body
    return $response
}
#EndRegion '.\Private\Invoke-ApifyRunActor.ps1' 32
#Region '.\Private\Wait-ApifyActorRunSucceeded.ps1' -1

<#
.SYNOPSIS
    Waits for an Apify actor run to reach the SUCCEEDED state.
.DESCRIPTION
    Polls the Apify API for the status of a given actor run until it succeeds, fails, or times out.
.PARAMETER RunId
    The run ID returned from Invoke-ApifyRunActor.
.PARAMETER PollIntervalSec
    How often to poll the actor run status, in seconds. Default is 10.
.PARAMETER TimeoutSec
    Maximum time to wait for the actor run to finish, in seconds. Default is 600.
.EXAMPLE
    Wait-ApifyActorRunSucceeded -RunId 'abc123' -PollIntervalSec 5 -TimeoutSec 300
.NOTES
    Throws if the run fails, is aborted, or times out. Requires 'ApifyToken' environment variable.
#>

function Wait-ApifyActorRunSucceeded {
    param(
        [string]$RunId, # The run ID from Invoke-ApifyRunActor
        [int]$PollIntervalSec = 10, # How often to poll (seconds)
        [int]$TimeoutSec = 600      # Max time to wait (seconds)
    )

    $url = "https://api.apify.com/v2/actor-runs/$RunId"
    $headers = @{
        "Authorization" = "Bearer $env:ApifyToken"
    }

    $elapsed = 0
    while ($true) {
        $response = Invoke-RestMethod -Method GET -Uri $url -Headers $headers
        $status = $response.data.status
        Write-Host "Current status: $status"
        if ($status -eq "SUCCEEDED") {
            return $response
        }
        elseif ($status -eq "FAILED" -or $status -eq "ABORTED" -or $status -eq "TIMED-OUT") {
            throw "Actor run ended with status: $status"
        }
        Start-Sleep -Seconds $PollIntervalSec
        $elapsed += $PollIntervalSec
        if ($elapsed -ge $TimeoutSec) {
            throw "Timeout waiting for actor run to succeed."
        }
    }
}
#EndRegion '.\Private\Wait-ApifyActorRunSucceeded.ps1' 47
#Region '.\Public\Export-toN8NWorkflow.ps1' -1

<#
.SYNOPSIS
    Exports JSON data to an n8n workflow via HTTP POST.
.DESCRIPTION
    Sends JSON data (either as a raw string or as an object/array to be converted) to a specified n8n webhook URL. Useful for integrating PowerShell data with n8n workflows.
.PARAMETER WebhookUrl
    The n8n webhook URL to which the data will be posted.
.PARAMETER Json
    The data to send. If -RawJson is specified, this should be a JSON string. Otherwise, it can be any object or array.
.PARAMETER RawJson
    If specified, treats the -Json parameter as a raw JSON string and uploads it as-is. Otherwise, the object is converted to JSON.
.EXAMPLE
    # Send an array of objects (converted to JSON automatically)
    $data = @(
        @{ name = 'User 1'; email = 'user1@example.com' },
        @{ name = 'User 2'; email = 'user2@example.com' }
    )
    Export-toN8NWorkflow -WebhookUrl 'https://example.com/webhook' -Json $data
.EXAMPLE
    # Send a raw JSON string
    $json = '[{"name":"User 1","email":"user1@example.com"}]'
    Export-toN8NWorkflow -WebhookUrl 'https://example.com/webhook' -Json $json -RawJson
.NOTES
    The n8n workflow should expect an array or object in the request body.
#>

function Export-toN8NWorkflow {
    param(
        [Parameter(Mandatory = $true)]
        [string]$WebhookUrl,
        [Parameter(Mandatory = $true)]
        $Json,
        [switch]$RawJson
    )
    if ($RawJson) {
        $bodyJson = $Json
    }
    else {
        $bodyJson = $Json | ConvertTo-Json -Depth 10 -Compress
    }
    Invoke-RestMethod -Uri $WebhookUrl -Method Post -Body $bodyJson -ContentType "application/json"
}
#EndRegion '.\Public\Export-toN8NWorkflow.ps1' 42
#Region '.\Public\Invoke-Apify.ps1' -1

<#
.SYNOPSIS
    Runs an Apify actor and retrieves its output dataset items.
.DESCRIPTION
    Starts an Apify actor run, waits for it to complete, and fetches the resulting dataset items. Handles polling and timeout.
.PARAMETER Id
    The Apify actor ID to run (e.g., 'apify/hello-world').
.PARAMETER RunInput
    The input object (hashtable or PSObject) to pass to the actor.
.PARAMETER PollIntervalSec
    How often to poll the actor run status, in seconds. Default is 10.
.PARAMETER TimeoutSec
    Maximum time to wait for the actor run to finish, in seconds. Default is 600.
.EXAMPLE
$RunInput = @"
{
    "location": "United States",
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    },
    "publishedAt": "r2592000",
    "rows": 5,
    "title": "SEO"
}
"@ | ConvertFrom-Json
 
Invoke-Apify -Id 'BHzefUZlZRKWxkTck' -RunInput $input
.NOTES
    Requires the environment variable 'ApifyToken' to be set with your Apify API token.
#>

function Invoke-Apify {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Id, # Apify actor ID
        [Parameter(Mandatory = $true)]
        [object]$RunInput, # Accepts a hashtable or PSObject
        [int]$PollIntervalSec = 10,
        [int]$TimeoutSec = 600
    )

    $url = "https://api.apify.com/v2/acts/$Id/runs"

    # Step 1: Start the actor run
    $runResult = Invoke-ApifyRunActor -Url $url -RunInput $RunInput
    $runId = $runResult.data.id

    # Step 2: Wait for the actor run to succeed
    $finalRun = Wait-ApifyActorRunSucceeded -RunId $runId -PollIntervalSec $PollIntervalSec -TimeoutSec $TimeoutSec
    $datasetId = $finalRun.data.defaultDatasetId

    # Step 3: Get the dataset items
    $items = Get-ApifyDatasetItems -DefaultDatasetId $datasetId

    return $items
}
#EndRegion '.\Public\Invoke-Apify.ps1' 59