참고소스 수정본
This commit is contained in:
8
참고/firecrawl-main/apps/php-sdk/.gitignore
vendored
Normal file
8
참고/firecrawl-main/apps/php-sdk/.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/vendor/
|
||||
/node_modules/
|
||||
composer.lock
|
||||
.phpunit.result.cache
|
||||
.php-cs-fixer.cache
|
||||
.phpstan-cache
|
||||
phpstan.neon
|
||||
.env
|
||||
31
참고/firecrawl-main/apps/php-sdk/CHANGELOG.md
Normal file
31
참고/firecrawl-main/apps/php-sdk/CHANGELOG.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to the Firecrawl PHP SDK will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.1.0] - 2026-04-21
|
||||
|
||||
### Added
|
||||
- Parse: `parse()` with `ParseFile` and `ParseOptions` models for uploading
|
||||
local files (`html`, `pdf`, `docx`, etc.) to the `/v2/parse` endpoint via
|
||||
multipart form data.
|
||||
|
||||
## [1.0.0] - 2026-04-13
|
||||
|
||||
### Added
|
||||
- Initial release with Firecrawl v2 API support
|
||||
- Scrape: `scrape()`, `interact()`, `stopInteractiveBrowser()`
|
||||
- Crawl: `crawl()`, `startCrawl()`, `getCrawlStatus()`, `cancelCrawl()`, `getCrawlErrors()`
|
||||
- Batch Scrape: `batchScrape()`, `startBatchScrape()`, `getBatchScrapeStatus()`, `cancelBatchScrape()`
|
||||
- Map: `map()`
|
||||
- Search: `search()`
|
||||
- Agent: `agent()`, `startAgent()`, `getAgentStatus()`, `cancelAgent()`
|
||||
- Browser: `browser()`, `browserExecute()`, `deleteBrowser()`, `listBrowsers()`
|
||||
- Usage: `getConcurrency()`, `getCreditUsage()`
|
||||
- Automatic polling with pagination for async jobs (crawl, batch scrape, agent)
|
||||
- Retry with exponential backoff for transient failures (408, 409, 502, 5xx)
|
||||
- Typed exception hierarchy: `FirecrawlException`, `AuthenticationException`, `RateLimitException`, `JobTimeoutException`
|
||||
- Laravel integration: auto-discovered service provider, publishable config, `Firecrawl` facade
|
||||
- PHP 8.1+ support with named parameters and readonly properties
|
||||
349
참고/firecrawl-main/apps/php-sdk/README.md
Normal file
349
참고/firecrawl-main/apps/php-sdk/README.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# Firecrawl PHP SDK
|
||||
|
||||
PHP SDK for the [Firecrawl](https://firecrawl.dev) v2 API with first-class Laravel support.
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 8.1.0+
|
||||
- Guzzle 7.9+
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require firecrawl/firecrawl-sdk
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Firecrawl\Client\FirecrawlClient;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
|
||||
$client = FirecrawlClient::create(apiKey: 'fc-your-api-key');
|
||||
|
||||
// Scrape a single page
|
||||
$doc = $client->scrape('https://example.com', ScrapeOptions::with(
|
||||
formats: ['markdown'],
|
||||
onlyMainContent: true,
|
||||
));
|
||||
|
||||
echo $doc->getMarkdown();
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
The SDK reads the following environment variables as fallbacks:
|
||||
|
||||
| Variable | Description |
|
||||
|---|---|
|
||||
| `FIRECRAWL_API_KEY` | API key (required if not passed directly) |
|
||||
| `FIRECRAWL_API_URL` | API base URL (defaults to `https://api.firecrawl.dev`) |
|
||||
|
||||
```php
|
||||
// Uses FIRECRAWL_API_KEY from environment
|
||||
$client = FirecrawlClient::fromEnv();
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Scrape
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
use Firecrawl\Models\JsonFormat;
|
||||
|
||||
// Basic scrape
|
||||
$doc = $client->scrape('https://example.com');
|
||||
echo $doc->getMarkdown();
|
||||
|
||||
// With options
|
||||
$doc = $client->scrape('https://example.com', ScrapeOptions::with(
|
||||
formats: ['markdown', 'html'],
|
||||
onlyMainContent: true,
|
||||
timeout: 30000,
|
||||
waitFor: 5000,
|
||||
));
|
||||
|
||||
// JSON extraction
|
||||
$doc = $client->scrape('https://example.com/product', ScrapeOptions::with(
|
||||
formats: [JsonFormat::with(
|
||||
prompt: 'Extract product name and price',
|
||||
schema: [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'name' => ['type' => 'string'],
|
||||
'price' => ['type' => 'number'],
|
||||
],
|
||||
],
|
||||
)],
|
||||
));
|
||||
|
||||
echo $doc->getJson(); // Structured data
|
||||
```
|
||||
|
||||
### Parse
|
||||
|
||||
Upload a local file (`html`, `pdf`, `docx`, etc.) via multipart form data and
|
||||
parse it synchronously. Parse options intentionally exclude browser-only
|
||||
features such as change tracking, screenshot, branding, actions, waitFor,
|
||||
location, and mobile. The `proxy` option only accepts `"auto"` or `"basic"`.
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\ParseFile;
|
||||
use Firecrawl\Models\ParseOptions;
|
||||
|
||||
// From disk
|
||||
$file = ParseFile::fromPath('./document.pdf');
|
||||
|
||||
// Or from memory
|
||||
$file = ParseFile::fromBytes(
|
||||
filename: 'upload.html',
|
||||
content: '<html>hi</html>',
|
||||
contentType: 'text/html',
|
||||
);
|
||||
|
||||
$doc = $client->parse($file, ParseOptions::with(
|
||||
formats: ['markdown'],
|
||||
));
|
||||
echo $doc->getMarkdown();
|
||||
```
|
||||
|
||||
### Crawl
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\CrawlOptions;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
|
||||
// Crawl with auto-polling (blocks until complete)
|
||||
$job = $client->crawl('https://example.com', CrawlOptions::with(
|
||||
limit: 50,
|
||||
maxDiscoveryDepth: 3,
|
||||
scrapeOptions: ScrapeOptions::with(formats: ['markdown']),
|
||||
));
|
||||
|
||||
foreach ($job->getData() as $doc) {
|
||||
echo $doc->getMetadata()['sourceURL'] . "\n";
|
||||
}
|
||||
|
||||
// Async: start crawl and poll manually
|
||||
$response = $client->startCrawl('https://example.com', CrawlOptions::with(limit: 10));
|
||||
$jobId = $response->getId();
|
||||
|
||||
// Check status later
|
||||
$job = $client->getCrawlStatus($jobId);
|
||||
echo "Completed: {$job->getCompleted()}/{$job->getTotal()}\n";
|
||||
|
||||
// Cancel
|
||||
$client->cancelCrawl($jobId);
|
||||
```
|
||||
|
||||
### Batch Scrape
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\BatchScrapeOptions;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
|
||||
$job = $client->batchScrape(
|
||||
['https://example.com', 'https://example.org'],
|
||||
BatchScrapeOptions::with(
|
||||
options: ScrapeOptions::with(formats: ['markdown']),
|
||||
idempotencyKey: 'my-batch-123',
|
||||
),
|
||||
);
|
||||
|
||||
foreach ($job->getData() as $doc) {
|
||||
echo $doc->getMarkdown() . "\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Map
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\MapOptions;
|
||||
|
||||
$result = $client->map('https://example.com', MapOptions::with(
|
||||
limit: 100,
|
||||
search: 'pricing',
|
||||
));
|
||||
|
||||
foreach ($result->getLinks() as $link) {
|
||||
echo $link['url'] . "\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Search
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\SearchOptions;
|
||||
|
||||
$result = $client->search('firecrawl web scraping', SearchOptions::with(
|
||||
limit: 5,
|
||||
));
|
||||
|
||||
foreach ($result->getWeb() as $item) {
|
||||
echo $item['title'] . ': ' . $item['url'] . "\n";
|
||||
}
|
||||
```
|
||||
|
||||
### Agent
|
||||
|
||||
```php
|
||||
use Firecrawl\Models\AgentOptions;
|
||||
|
||||
// Auto-polling (blocks until complete)
|
||||
$result = $client->agent(AgentOptions::with(
|
||||
prompt: 'Find the pricing plans and compare them',
|
||||
maxCredits: 100,
|
||||
));
|
||||
|
||||
echo $result->getData();
|
||||
```
|
||||
|
||||
### Browser Sessions
|
||||
|
||||
```php
|
||||
// Create a session
|
||||
$session = $client->browser(ttl: 300);
|
||||
$sessionId = $session->getId();
|
||||
|
||||
// Execute code
|
||||
$result = $client->browserExecute($sessionId, 'agent-browser open https://example.com');
|
||||
echo $result->getStdout();
|
||||
|
||||
// Execute JavaScript
|
||||
$result = $client->browserExecute(
|
||||
$sessionId,
|
||||
'console.log(await page.title());',
|
||||
language: 'node',
|
||||
timeout: 30,
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
$client->deleteBrowser($sessionId);
|
||||
|
||||
// List sessions
|
||||
$sessions = $client->listBrowsers(status: 'active');
|
||||
```
|
||||
|
||||
### Scrape-Bound Browser Interaction
|
||||
|
||||
```php
|
||||
$doc = $client->scrape('https://example.com');
|
||||
$scrapeId = $doc->getMetadata()['scrapeId'];
|
||||
|
||||
$result = $client->interact($scrapeId, 'await page.click("button");', language: 'node');
|
||||
echo $result->getStdout();
|
||||
|
||||
$client->stopInteractiveBrowser($scrapeId);
|
||||
```
|
||||
|
||||
### Usage & Metrics
|
||||
|
||||
```php
|
||||
$concurrency = $client->getConcurrency();
|
||||
echo "Current: {$concurrency->getConcurrency()}/{$concurrency->getMaxConcurrency()}\n";
|
||||
|
||||
$credits = $client->getCreditUsage();
|
||||
echo "Remaining: {$credits->getRemainingCredits()}\n";
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
```php
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
use Firecrawl\Exceptions\AuthenticationException;
|
||||
use Firecrawl\Exceptions\RateLimitException;
|
||||
use Firecrawl\Exceptions\JobTimeoutException;
|
||||
|
||||
try {
|
||||
$doc = $client->scrape('https://example.com');
|
||||
} catch (AuthenticationException $e) {
|
||||
echo "Invalid API key\n";
|
||||
} catch (RateLimitException $e) {
|
||||
echo "Rate limited, back off\n";
|
||||
} catch (JobTimeoutException $e) {
|
||||
echo "Job {$e->getJobId()} timed out after {$e->getTimeoutSeconds()}s\n";
|
||||
} catch (FirecrawlException $e) {
|
||||
echo "Error ({$e->getStatusCode()}): {$e->getMessage()}\n";
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
|
||||
$client = FirecrawlClient::create(
|
||||
apiKey: 'fc-your-api-key',
|
||||
apiUrl: 'https://custom-api.example.com',
|
||||
timeoutSeconds: 120,
|
||||
maxRetries: 5,
|
||||
backoffFactor: 1.0,
|
||||
httpClient: new GuzzleClient([
|
||||
'proxy' => 'http://proxy.example.com:8080',
|
||||
]),
|
||||
);
|
||||
```
|
||||
|
||||
## Laravel Integration
|
||||
|
||||
### Setup
|
||||
|
||||
The service provider is auto-discovered. Publish the config file:
|
||||
|
||||
```bash
|
||||
php artisan vendor:publish --tag=firecrawl-config
|
||||
```
|
||||
|
||||
Add your API key to `.env`:
|
||||
|
||||
```
|
||||
FIRECRAWL_API_KEY=fc-your-api-key
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
The published `config/firecrawl.php` supports these environment variables:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|---|---|---|
|
||||
| `FIRECRAWL_API_KEY` | — | API key (required) |
|
||||
| `FIRECRAWL_API_URL` | `https://api.firecrawl.dev` | API base URL |
|
||||
| `FIRECRAWL_TIMEOUT` | `300` | Request timeout in seconds |
|
||||
| `FIRECRAWL_MAX_RETRIES` | `3` | Max retry attempts |
|
||||
| `FIRECRAWL_BACKOFF_FACTOR` | `0.5` | Exponential backoff factor |
|
||||
|
||||
### Using the Facade
|
||||
|
||||
```php
|
||||
use Firecrawl\Laravel\Facades\Firecrawl;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
|
||||
$doc = Firecrawl::scrape('https://example.com', ScrapeOptions::with(
|
||||
formats: ['markdown'],
|
||||
));
|
||||
```
|
||||
|
||||
### Using Dependency Injection
|
||||
|
||||
```php
|
||||
use Firecrawl\Client\FirecrawlClient;
|
||||
|
||||
class MyController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly FirecrawlClient $firecrawl,
|
||||
) {}
|
||||
|
||||
public function scrape(string $url)
|
||||
{
|
||||
return $this->firecrawl->scrape($url);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
64
참고/firecrawl-main/apps/php-sdk/composer.json
Normal file
64
참고/firecrawl-main/apps/php-sdk/composer.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "firecrawl/firecrawl-sdk",
|
||||
"description": "PHP SDK for the Firecrawl v2 API with Laravel support",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"firecrawl",
|
||||
"web-scraping",
|
||||
"crawling",
|
||||
"api",
|
||||
"laravel",
|
||||
"php"
|
||||
],
|
||||
"homepage": "https://firecrawl.dev",
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"psr/http-client": "^1",
|
||||
"psr/http-message": "^1|^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3",
|
||||
"illuminate/contracts": "^10.0|^11.0|^12.0",
|
||||
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||
"orchestra/testbench": "^8|^9|^10",
|
||||
"pestphp/pest": "^2|^3",
|
||||
"phpstan/phpstan": "^1|^2",
|
||||
"phpunit/phpunit": "^10|^11"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/contracts": "Required for Laravel integration (^10.0|^11.0|^12.0)",
|
||||
"illuminate/support": "Required for Laravel integration (^10.0|^11.0|^12.0)"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Firecrawl\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
},
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Firecrawl\\Laravel\\FirecrawlServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Firecrawl": "Firecrawl\\Laravel\\Facades\\Firecrawl"
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
59
참고/firecrawl-main/apps/php-sdk/config/firecrawl.php
Normal file
59
참고/firecrawl-main/apps/php-sdk/config/firecrawl.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Firecrawl API Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Your Firecrawl API key. Get one at https://firecrawl.dev.
|
||||
| Falls back to the FIRECRAWL_API_KEY environment variable.
|
||||
|
|
||||
*/
|
||||
'api_key' => env('FIRECRAWL_API_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Firecrawl API URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The base URL for the Firecrawl API.
|
||||
| Falls back to the FIRECRAWL_API_URL environment variable or the default.
|
||||
|
|
||||
*/
|
||||
'api_url' => env('FIRECRAWL_API_URL', 'https://api.firecrawl.dev'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Request Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The timeout in seconds for HTTP requests to the Firecrawl API.
|
||||
|
|
||||
*/
|
||||
'timeout' => (float) env('FIRECRAWL_TIMEOUT', 300),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Max Retries
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The maximum number of times to retry a failed request.
|
||||
| Retryable errors: 408, 409, 502, 5xx, and connection failures.
|
||||
|
|
||||
*/
|
||||
'max_retries' => (int) env('FIRECRAWL_MAX_RETRIES', 3),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Backoff Factor
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The exponential backoff factor in seconds for retries.
|
||||
| Delay = backoff_factor * 2^(attempt - 1)
|
||||
|
|
||||
*/
|
||||
'backoff_factor' => (float) env('FIRECRAWL_BACKOFF_FACTOR', 0.5),
|
||||
];
|
||||
12
참고/firecrawl-main/apps/php-sdk/phpstan.neon.dist
Normal file
12
참고/firecrawl-main/apps/php-sdk/phpstan.neon.dist
Normal file
@@ -0,0 +1,12 @@
|
||||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- src
|
||||
tmpDir: .phpstan-cache
|
||||
ignoreErrors:
|
||||
# Laravel Facade and ServiceProvider may not be installed
|
||||
-
|
||||
message: '#Class Illuminate\\\\#'
|
||||
paths:
|
||||
- src/Laravel/*
|
||||
reportUnmatched: false
|
||||
18
참고/firecrawl-main/apps/php-sdk/phpunit.xml.dist
Normal file
18
참고/firecrawl-main/apps/php-sdk/phpunit.xml.dist
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
cacheDirectory=".phpunit.cache"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory>tests/Unit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<source>
|
||||
<include>
|
||||
<directory>src</directory>
|
||||
</include>
|
||||
</source>
|
||||
</phpunit>
|
||||
769
참고/firecrawl-main/apps/php-sdk/src/Client/FirecrawlClient.php
Normal file
769
참고/firecrawl-main/apps/php-sdk/src/Client/FirecrawlClient.php
Normal file
@@ -0,0 +1,769 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Client;
|
||||
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
use Firecrawl\Exceptions\JobTimeoutException;
|
||||
use Firecrawl\Models\AgentOptions;
|
||||
use Firecrawl\Models\AgentResponse;
|
||||
use Firecrawl\Models\AgentStatusResponse;
|
||||
use Firecrawl\Models\BatchScrapeJob;
|
||||
use Firecrawl\Models\BatchScrapeOptions;
|
||||
use Firecrawl\Models\BatchScrapeResponse;
|
||||
use Firecrawl\Models\BrowserCreateResponse;
|
||||
use Firecrawl\Models\BrowserDeleteResponse;
|
||||
use Firecrawl\Models\BrowserExecuteResponse;
|
||||
use Firecrawl\Models\BrowserListResponse;
|
||||
use Firecrawl\Models\ConcurrencyCheck;
|
||||
use Firecrawl\Models\CrawlJob;
|
||||
use Firecrawl\Models\CrawlOptions;
|
||||
use Firecrawl\Models\CrawlResponse;
|
||||
use Firecrawl\Models\CreditUsage;
|
||||
use Firecrawl\Models\Document;
|
||||
use Firecrawl\Models\MapData;
|
||||
use Firecrawl\Models\MapOptions;
|
||||
use Firecrawl\Models\Monitor;
|
||||
use Firecrawl\Models\MonitorCheck;
|
||||
use Firecrawl\Models\MonitorCheckDetail;
|
||||
use Firecrawl\Models\ParseFile;
|
||||
use Firecrawl\Models\ParseOptions;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
use Firecrawl\Models\SearchData;
|
||||
use Firecrawl\Models\SearchOptions;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
|
||||
final class FirecrawlClient
|
||||
{
|
||||
private const DEFAULT_API_URL = 'https://api.firecrawl.dev';
|
||||
private const DEFAULT_TIMEOUT_SECONDS = 300;
|
||||
private const DEFAULT_MAX_RETRIES = 3;
|
||||
private const DEFAULT_BACKOFF_FACTOR = 0.5;
|
||||
private const DEFAULT_POLL_INTERVAL = 2;
|
||||
private const DEFAULT_JOB_TIMEOUT = 300;
|
||||
|
||||
private readonly FirecrawlHttpClient $http;
|
||||
|
||||
private function __construct(FirecrawlHttpClient $http)
|
||||
{
|
||||
$this->http = $http;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a client with named parameters.
|
||||
*
|
||||
* Uses FIRECRAWL_API_KEY and FIRECRAWL_API_URL environment variables as fallbacks.
|
||||
*/
|
||||
public static function create(
|
||||
?string $apiKey = null,
|
||||
?string $apiUrl = null,
|
||||
float $timeoutSeconds = self::DEFAULT_TIMEOUT_SECONDS,
|
||||
int $maxRetries = self::DEFAULT_MAX_RETRIES,
|
||||
float $backoffFactor = self::DEFAULT_BACKOFF_FACTOR,
|
||||
?ClientInterface $httpClient = null,
|
||||
): self {
|
||||
$resolvedKey = trim($apiKey ?: (getenv('FIRECRAWL_API_KEY') ?: ''));
|
||||
if ($resolvedKey === '') {
|
||||
throw new FirecrawlException(
|
||||
'API key is required. Pass it directly or set the FIRECRAWL_API_KEY environment variable.',
|
||||
);
|
||||
}
|
||||
|
||||
$resolvedUrl = $apiUrl ?: (getenv('FIRECRAWL_API_URL') ?: self::DEFAULT_API_URL);
|
||||
|
||||
if (!preg_match('#^https?://#i', $resolvedUrl)) {
|
||||
throw new FirecrawlException(
|
||||
'API URL must be a fully qualified URL including scheme (e.g. https://api.firecrawl.dev).',
|
||||
);
|
||||
}
|
||||
|
||||
$http = new FirecrawlHttpClient(
|
||||
$resolvedKey,
|
||||
$resolvedUrl,
|
||||
$timeoutSeconds,
|
||||
$maxRetries,
|
||||
$backoffFactor,
|
||||
$httpClient,
|
||||
);
|
||||
|
||||
return new self($http);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a client from the FIRECRAWL_API_KEY environment variable.
|
||||
*/
|
||||
public static function fromEnv(): self
|
||||
{
|
||||
return self::create();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// SCRAPE
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Scrape a single URL and return the document.
|
||||
*/
|
||||
public function scrape(string $url, ?ScrapeOptions $options = null): Document
|
||||
{
|
||||
$body = ['url' => $url];
|
||||
if ($options !== null) {
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
|
||||
$response = $this->http->post('/v2/scrape', $body);
|
||||
|
||||
return Document::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interact with the scrape-bound browser session for a scrape job.
|
||||
*/
|
||||
public function interact(
|
||||
string $jobId,
|
||||
string $code,
|
||||
string $language = 'node',
|
||||
?int $timeout = null,
|
||||
?string $origin = null,
|
||||
?string $prompt = null,
|
||||
): BrowserExecuteResponse {
|
||||
$body = [
|
||||
'code' => $code,
|
||||
'language' => $language,
|
||||
];
|
||||
if ($timeout !== null) {
|
||||
$body['timeout'] = $timeout;
|
||||
}
|
||||
if ($origin !== null) {
|
||||
$body['origin'] = $origin;
|
||||
}
|
||||
if ($prompt !== null) {
|
||||
$body['prompt'] = $prompt;
|
||||
}
|
||||
|
||||
return BrowserExecuteResponse::fromArray(
|
||||
$this->http->post("/v2/scrape/{$jobId}/interact", $body),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the interactive browser session for a scrape job.
|
||||
*/
|
||||
public function stopInteractiveBrowser(string $jobId): BrowserDeleteResponse
|
||||
{
|
||||
return BrowserDeleteResponse::fromArray(
|
||||
$this->http->delete("/v2/scrape/{$jobId}/interact"),
|
||||
);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// PARSE
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Parse an uploaded file and return the extracted document.
|
||||
*/
|
||||
public function parse(ParseFile $file, ?ParseOptions $options = null): Document
|
||||
{
|
||||
$optionsArray = $options?->toArray() ?? [];
|
||||
$response = $this->http->postMultipart(
|
||||
'/v2/parse',
|
||||
['options' => json_encode($optionsArray, JSON_THROW_ON_ERROR)],
|
||||
'file',
|
||||
$file->getFilename(),
|
||||
$file->getContent(),
|
||||
$file->getContentType(),
|
||||
);
|
||||
|
||||
return Document::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// CRAWL
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Start an async crawl job and return immediately.
|
||||
*/
|
||||
public function startCrawl(string $url, ?CrawlOptions $options = null): CrawlResponse
|
||||
{
|
||||
$body = ['url' => $url];
|
||||
if ($options !== null) {
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
|
||||
return CrawlResponse::fromArray($this->http->post('/v2/crawl', $body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status and results of a crawl job.
|
||||
*/
|
||||
public function getCrawlStatus(string $jobId): CrawlJob
|
||||
{
|
||||
return CrawlJob::fromArray($this->http->get("/v2/crawl/{$jobId}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Crawl a website and wait for completion (auto-polling).
|
||||
*/
|
||||
public function crawl(
|
||||
string $url,
|
||||
?CrawlOptions $options = null,
|
||||
int $pollIntervalSec = self::DEFAULT_POLL_INTERVAL,
|
||||
int $timeoutSec = self::DEFAULT_JOB_TIMEOUT,
|
||||
): CrawlJob {
|
||||
$start = $this->startCrawl($url, $options);
|
||||
|
||||
return $this->pollCrawl($start->getId(), $pollIntervalSec, $timeoutSec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a running crawl job.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function cancelCrawl(string $jobId): array
|
||||
{
|
||||
return $this->http->delete("/v2/crawl/{$jobId}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get errors from a crawl job.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getCrawlErrors(string $jobId): array
|
||||
{
|
||||
return $this->http->get("/v2/crawl/{$jobId}/errors");
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// BATCH SCRAPE
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Start an async batch scrape job.
|
||||
*
|
||||
* @param list<string> $urls
|
||||
*/
|
||||
public function startBatchScrape(array $urls, ?BatchScrapeOptions $options = null): BatchScrapeResponse
|
||||
{
|
||||
$body = ['urls' => $urls];
|
||||
$extraHeaders = [];
|
||||
|
||||
if ($options !== null) {
|
||||
$idempotencyKey = $options->getIdempotencyKey();
|
||||
if ($idempotencyKey !== null && $idempotencyKey !== '') {
|
||||
$extraHeaders['x-idempotency-key'] = $idempotencyKey;
|
||||
}
|
||||
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
|
||||
return BatchScrapeResponse::fromArray(
|
||||
$this->http->post('/v2/batch/scrape', $body, $extraHeaders),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status and results of a batch scrape job.
|
||||
*/
|
||||
public function getBatchScrapeStatus(string $jobId): BatchScrapeJob
|
||||
{
|
||||
return BatchScrapeJob::fromArray($this->http->get("/v2/batch/scrape/{$jobId}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch-scrape URLs and wait for completion (auto-polling).
|
||||
*
|
||||
* @param list<string> $urls
|
||||
*/
|
||||
public function batchScrape(
|
||||
array $urls,
|
||||
?BatchScrapeOptions $options = null,
|
||||
int $pollIntervalSec = self::DEFAULT_POLL_INTERVAL,
|
||||
int $timeoutSec = self::DEFAULT_JOB_TIMEOUT,
|
||||
): BatchScrapeJob {
|
||||
$start = $this->startBatchScrape($urls, $options);
|
||||
|
||||
return $this->pollBatchScrape($start->getId(), $pollIntervalSec, $timeoutSec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a running batch scrape job.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function cancelBatchScrape(string $jobId): array
|
||||
{
|
||||
return $this->http->delete("/v2/batch/scrape/{$jobId}");
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// MAP
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Discover URLs on a website.
|
||||
*/
|
||||
public function map(string $url, ?MapOptions $options = null): MapData
|
||||
{
|
||||
$body = ['url' => $url];
|
||||
if ($options !== null) {
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
|
||||
$response = $this->http->post('/v2/map', $body);
|
||||
|
||||
return MapData::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// MONITOR
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Create a scheduled monitor.
|
||||
*
|
||||
* @param array<string, mixed> $schedule
|
||||
* @param list<array<string, mixed>> $targets
|
||||
* @param array<string, mixed>|null $webhook
|
||||
* @param array<string, mixed>|null $notification
|
||||
*/
|
||||
public function createMonitor(
|
||||
string $name,
|
||||
array $schedule,
|
||||
array $targets,
|
||||
?array $webhook = null,
|
||||
?array $notification = null,
|
||||
?int $retentionDays = null,
|
||||
): Monitor {
|
||||
$body = array_filter([
|
||||
'name' => $name,
|
||||
'schedule' => $schedule,
|
||||
'targets' => $targets,
|
||||
'webhook' => $webhook,
|
||||
'notification' => $notification,
|
||||
'retentionDays' => $retentionDays,
|
||||
], static fn ($value) => $value !== null);
|
||||
|
||||
$response = $this->http->post('/v2/monitor', $body);
|
||||
|
||||
return Monitor::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<Monitor>
|
||||
*/
|
||||
public function listMonitors(?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
$response = $this->http->get('/v2/monitor' . $this->query([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]));
|
||||
|
||||
return array_map(
|
||||
static fn (array $item): Monitor => Monitor::fromArray($item),
|
||||
$response['data'] ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
public function getMonitor(string $monitorId): Monitor
|
||||
{
|
||||
$response = $this->http->get("/v2/monitor/{$monitorId}");
|
||||
|
||||
return Monitor::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $attributes
|
||||
*/
|
||||
public function updateMonitor(string $monitorId, array $attributes): Monitor
|
||||
{
|
||||
$response = $this->http->patch("/v2/monitor/{$monitorId}", $attributes);
|
||||
|
||||
return Monitor::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
public function deleteMonitor(string $monitorId): bool
|
||||
{
|
||||
$response = $this->http->delete("/v2/monitor/{$monitorId}");
|
||||
|
||||
return ($response['success'] ?? false) === true;
|
||||
}
|
||||
|
||||
public function runMonitor(string $monitorId): MonitorCheck
|
||||
{
|
||||
$response = $this->http->post("/v2/monitor/{$monitorId}/run", []);
|
||||
|
||||
return MonitorCheck::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<MonitorCheck>
|
||||
*/
|
||||
public function listMonitorChecks(string $monitorId, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
$response = $this->http->get("/v2/monitor/{$monitorId}/checks" . $this->query([
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]));
|
||||
|
||||
return array_map(
|
||||
static fn (array $item): MonitorCheck => MonitorCheck::fromArray($item),
|
||||
$response['data'] ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
public function getMonitorCheck(
|
||||
string $monitorId,
|
||||
string $checkId,
|
||||
?int $limit = null,
|
||||
?int $skip = null,
|
||||
?string $status = null,
|
||||
bool $autoPaginate = true,
|
||||
): MonitorCheckDetail {
|
||||
$response = $this->http->get("/v2/monitor/{$monitorId}/checks/{$checkId}" . $this->query([
|
||||
'limit' => $limit,
|
||||
'skip' => $skip,
|
||||
'status' => $status,
|
||||
]));
|
||||
|
||||
$data = $response['data'] ?? $response;
|
||||
if (isset($response['next'])) {
|
||||
$data['next'] = $response['next'];
|
||||
}
|
||||
|
||||
if (!$autoPaginate) {
|
||||
return MonitorCheckDetail::fromArray($data);
|
||||
}
|
||||
|
||||
while (isset($data['next']) && is_string($data['next']) && $data['next'] !== '') {
|
||||
$this->assertSameOrigin($data['next']);
|
||||
$nextResponse = $this->http->getAbsolute($data['next']);
|
||||
$nextData = $nextResponse['data'] ?? $nextResponse;
|
||||
if (isset($nextResponse['next'])) {
|
||||
$nextData['next'] = $nextResponse['next'];
|
||||
}
|
||||
|
||||
$data['pages'] = array_merge($data['pages'] ?? [], $nextData['pages'] ?? []);
|
||||
$data['next'] = $nextData['next'] ?? null;
|
||||
}
|
||||
|
||||
$data['next'] = null;
|
||||
return MonitorCheckDetail::fromArray($data);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// SEARCH
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Perform a web search.
|
||||
*/
|
||||
public function search(string $query, ?SearchOptions $options = null): SearchData
|
||||
{
|
||||
$body = ['query' => $query];
|
||||
if ($options !== null) {
|
||||
$body = array_merge($body, $options->toArray());
|
||||
}
|
||||
|
||||
$response = $this->http->post('/v2/search', $body);
|
||||
|
||||
return SearchData::fromArray($response['data'] ?? $response);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// AGENT
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Start an async agent task.
|
||||
*/
|
||||
public function startAgent(AgentOptions $options): AgentResponse
|
||||
{
|
||||
return AgentResponse::fromArray(
|
||||
$this->http->post('/v2/agent', $options->toArray()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of an agent task.
|
||||
*/
|
||||
public function getAgentStatus(string $jobId): AgentStatusResponse
|
||||
{
|
||||
return AgentStatusResponse::fromArray(
|
||||
$this->http->get("/v2/agent/{$jobId}"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an agent task and wait for completion (auto-polling).
|
||||
*/
|
||||
public function agent(
|
||||
AgentOptions $options,
|
||||
int $pollIntervalSec = self::DEFAULT_POLL_INTERVAL,
|
||||
int $timeoutSec = self::DEFAULT_JOB_TIMEOUT,
|
||||
): AgentStatusResponse {
|
||||
$start = $this->startAgent($options);
|
||||
|
||||
if ($start->getId() === null) {
|
||||
throw new FirecrawlException('Agent start did not return a job ID');
|
||||
}
|
||||
|
||||
$this->ensureValidPollInterval($pollIntervalSec);
|
||||
|
||||
$deadline = time() + $timeoutSec;
|
||||
while (time() < $deadline) {
|
||||
$status = $this->getAgentStatus($start->getId());
|
||||
if ($status->isDone()) {
|
||||
return $status;
|
||||
}
|
||||
sleep($pollIntervalSec);
|
||||
}
|
||||
|
||||
throw new JobTimeoutException($start->getId(), $timeoutSec, 'Agent');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a running agent task.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function cancelAgent(string $jobId): array
|
||||
{
|
||||
return $this->http->delete("/v2/agent/{$jobId}");
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// BROWSER
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Create a new browser session.
|
||||
*
|
||||
* @param array<string, string>|null $profile
|
||||
*/
|
||||
public function browser(
|
||||
?int $ttl = null,
|
||||
?int $activityTtl = null,
|
||||
?bool $streamWebView = null,
|
||||
?array $profile = null,
|
||||
): BrowserCreateResponse {
|
||||
$body = [];
|
||||
if ($ttl !== null) {
|
||||
$body['ttl'] = $ttl;
|
||||
}
|
||||
if ($activityTtl !== null) {
|
||||
$body['activityTtl'] = $activityTtl;
|
||||
}
|
||||
if ($streamWebView !== null) {
|
||||
$body['streamWebView'] = $streamWebView;
|
||||
}
|
||||
if ($profile !== null) {
|
||||
$body['profile'] = $profile;
|
||||
}
|
||||
|
||||
return BrowserCreateResponse::fromArray($this->http->post('/v2/browser', $body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute code in a browser session.
|
||||
*/
|
||||
public function browserExecute(
|
||||
string $sessionId,
|
||||
string $code,
|
||||
string $language = 'bash',
|
||||
?int $timeout = null,
|
||||
): BrowserExecuteResponse {
|
||||
$body = [
|
||||
'code' => $code,
|
||||
'language' => $language,
|
||||
];
|
||||
if ($timeout !== null) {
|
||||
$body['timeout'] = $timeout;
|
||||
}
|
||||
|
||||
return BrowserExecuteResponse::fromArray(
|
||||
$this->http->post("/v2/browser/{$sessionId}/execute", $body),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a browser session.
|
||||
*/
|
||||
public function deleteBrowser(string $sessionId): BrowserDeleteResponse
|
||||
{
|
||||
return BrowserDeleteResponse::fromArray(
|
||||
$this->http->delete("/v2/browser/{$sessionId}"),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* List browser sessions.
|
||||
*/
|
||||
public function listBrowsers(?string $status = null): BrowserListResponse
|
||||
{
|
||||
$endpoint = '/v2/browser';
|
||||
if ($status !== null && $status !== '') {
|
||||
$endpoint .= '?status=' . urlencode($status);
|
||||
}
|
||||
|
||||
return BrowserListResponse::fromArray($this->http->get($endpoint));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// USAGE & METRICS
|
||||
// ================================================================
|
||||
|
||||
/**
|
||||
* Get current concurrency usage.
|
||||
*/
|
||||
public function getConcurrency(): ConcurrencyCheck
|
||||
{
|
||||
return ConcurrencyCheck::fromArray($this->http->get('/v2/concurrency-check'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current credit usage.
|
||||
*/
|
||||
public function getCreditUsage(): CreditUsage
|
||||
{
|
||||
return CreditUsage::fromArray($this->http->get('/v2/team/credit-usage'));
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// INTERNAL POLLING HELPERS
|
||||
// ================================================================
|
||||
|
||||
private function ensureValidPollInterval(int $pollIntervalSec): void
|
||||
{
|
||||
if ($pollIntervalSec < 1) {
|
||||
throw new FirecrawlException('Poll interval must be at least 1 second, got ' . $pollIntervalSec);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, scalar|null> $params
|
||||
*/
|
||||
private function query(array $params): string
|
||||
{
|
||||
$params = array_filter($params, static fn ($value) => $value !== null && $value !== '');
|
||||
|
||||
return $params === [] ? '' : '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
private function pollCrawl(
|
||||
?string $jobId,
|
||||
int $pollIntervalSec,
|
||||
int $timeoutSec,
|
||||
): CrawlJob {
|
||||
if ($jobId === null) {
|
||||
throw new FirecrawlException('Crawl start did not return a job ID');
|
||||
}
|
||||
|
||||
$this->ensureValidPollInterval($pollIntervalSec);
|
||||
|
||||
$deadline = time() + $timeoutSec;
|
||||
while (time() < $deadline) {
|
||||
$job = $this->getCrawlStatus($jobId);
|
||||
if ($job->isDone()) {
|
||||
return $this->paginateCrawl($job);
|
||||
}
|
||||
sleep($pollIntervalSec);
|
||||
}
|
||||
|
||||
throw new JobTimeoutException($jobId, $timeoutSec, 'Crawl');
|
||||
}
|
||||
|
||||
private function pollBatchScrape(
|
||||
?string $jobId,
|
||||
int $pollIntervalSec,
|
||||
int $timeoutSec,
|
||||
): BatchScrapeJob {
|
||||
if ($jobId === null) {
|
||||
throw new FirecrawlException('Batch scrape start did not return a job ID');
|
||||
}
|
||||
|
||||
$this->ensureValidPollInterval($pollIntervalSec);
|
||||
|
||||
$deadline = time() + $timeoutSec;
|
||||
while (time() < $deadline) {
|
||||
$job = $this->getBatchScrapeStatus($jobId);
|
||||
if ($job->isDone()) {
|
||||
return $this->paginateBatchScrape($job);
|
||||
}
|
||||
sleep($pollIntervalSec);
|
||||
}
|
||||
|
||||
throw new JobTimeoutException($jobId, $timeoutSec, 'Batch scrape');
|
||||
}
|
||||
|
||||
private function assertSameOrigin(string $url): void
|
||||
{
|
||||
$baseScheme = parse_url($this->http->getBaseUrl(), PHP_URL_SCHEME);
|
||||
$baseHost = parse_url($this->http->getBaseUrl(), PHP_URL_HOST);
|
||||
$basePort = parse_url($this->http->getBaseUrl(), PHP_URL_PORT);
|
||||
$nextScheme = parse_url($url, PHP_URL_SCHEME);
|
||||
$nextHost = parse_url($url, PHP_URL_HOST);
|
||||
$nextPort = parse_url($url, PHP_URL_PORT);
|
||||
|
||||
$basePort ??= is_string($baseScheme) && strcasecmp($baseScheme, 'https') === 0
|
||||
? 443
|
||||
: 80;
|
||||
$nextPort ??= is_string($nextScheme) && strcasecmp($nextScheme, 'https') === 0
|
||||
? 443
|
||||
: 80;
|
||||
|
||||
if (
|
||||
$baseScheme === null ||
|
||||
$nextScheme === null ||
|
||||
$baseHost === null ||
|
||||
$nextHost === null ||
|
||||
strcasecmp($baseScheme, $nextScheme) !== 0 ||
|
||||
strcasecmp($baseHost, $nextHost) !== 0 ||
|
||||
$basePort !== $nextPort
|
||||
) {
|
||||
throw new FirecrawlException(
|
||||
'Pagination URL origin does not match the API base URL. Refusing to follow: ' . $url,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function paginateCrawl(CrawlJob $job): CrawlJob
|
||||
{
|
||||
$current = $job;
|
||||
while ($current->getNext() !== null && $current->getNext() !== '') {
|
||||
$this->assertSameOrigin($current->getNext());
|
||||
$nextRaw = $this->http->getAbsolute($current->getNext());
|
||||
$nextPage = CrawlJob::fromArray($nextRaw);
|
||||
|
||||
foreach ($nextPage->getData() as $doc) {
|
||||
$job->appendData($doc);
|
||||
}
|
||||
|
||||
$current = $nextPage;
|
||||
}
|
||||
|
||||
return $job;
|
||||
}
|
||||
|
||||
private function paginateBatchScrape(BatchScrapeJob $job): BatchScrapeJob
|
||||
{
|
||||
$current = $job;
|
||||
while ($current->getNext() !== null && $current->getNext() !== '') {
|
||||
$this->assertSameOrigin($current->getNext());
|
||||
$nextRaw = $this->http->getAbsolute($current->getNext());
|
||||
$nextPage = BatchScrapeJob::fromArray($nextRaw);
|
||||
|
||||
foreach ($nextPage->getData() as $doc) {
|
||||
$job->appendData($doc);
|
||||
}
|
||||
|
||||
$current = $nextPage;
|
||||
}
|
||||
|
||||
return $job;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Client;
|
||||
|
||||
use Firecrawl\Exceptions\AuthenticationException;
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
use Firecrawl\Exceptions\RateLimitException;
|
||||
use Firecrawl\Version;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class FirecrawlHttpClient
|
||||
{
|
||||
private readonly ClientInterface $httpClient;
|
||||
private readonly string $baseUrl;
|
||||
|
||||
public function __construct(
|
||||
private readonly string $apiKey,
|
||||
string $baseUrl,
|
||||
float $timeoutSeconds,
|
||||
private readonly int $maxRetries,
|
||||
private readonly float $backoffFactor,
|
||||
?ClientInterface $httpClient = null,
|
||||
) {
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
|
||||
$this->httpClient = $httpClient ?? new GuzzleClient([
|
||||
RequestOptions::TIMEOUT => $timeoutSeconds,
|
||||
RequestOptions::CONNECT_TIMEOUT => min($timeoutSeconds, 30),
|
||||
RequestOptions::HTTP_ERRORS => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $body
|
||||
* @param array<string, string> $extraHeaders
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function post(string $path, array $body, array $extraHeaders = []): array
|
||||
{
|
||||
return $this->request('POST', $this->baseUrl . $path, $body, $extraHeaders);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function get(string $path): array
|
||||
{
|
||||
return $this->request('GET', $this->baseUrl . $path);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function getAbsolute(string $absoluteUrl): array
|
||||
{
|
||||
return $this->request('GET', $absoluteUrl);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function delete(string $path): array
|
||||
{
|
||||
return $this->request('DELETE', $this->baseUrl . $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $body
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function patch(string $path, array $body): array
|
||||
{
|
||||
return $this->request('PATCH', $this->baseUrl . $path, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a POST request with a multipart/form-data body.
|
||||
*
|
||||
* @param array<string, string> $fields
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function postMultipart(
|
||||
string $path,
|
||||
array $fields,
|
||||
string $fileField,
|
||||
string $fileName,
|
||||
string $fileContent,
|
||||
?string $fileContentType = null,
|
||||
): array {
|
||||
$multipart = [];
|
||||
foreach ($fields as $name => $value) {
|
||||
$multipart[] = [
|
||||
'name' => $name,
|
||||
'contents' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
$filePart = [
|
||||
'name' => $fileField,
|
||||
'contents' => $fileContent,
|
||||
'filename' => $fileName,
|
||||
];
|
||||
if ($fileContentType !== null && $fileContentType !== '') {
|
||||
$filePart['headers'] = ['Content-Type' => $fileContentType];
|
||||
}
|
||||
$multipart[] = $filePart;
|
||||
|
||||
return $this->request(
|
||||
'POST',
|
||||
$this->baseUrl . $path,
|
||||
body: [],
|
||||
extraHeaders: [],
|
||||
multipart: $multipart,
|
||||
);
|
||||
}
|
||||
|
||||
public function getBaseUrl(): string
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $body
|
||||
* @param array<string, string> $extraHeaders
|
||||
* @param list<array<string, mixed>>|null $multipart
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function request(
|
||||
string $method,
|
||||
string $url,
|
||||
array $body = [],
|
||||
array $extraHeaders = [],
|
||||
?array $multipart = null,
|
||||
): array {
|
||||
$defaultHeaders = [
|
||||
'Authorization' => 'Bearer ' . $this->apiKey,
|
||||
'Accept' => 'application/json',
|
||||
'User-Agent' => 'firecrawl-php/' . Version::SDK_VERSION,
|
||||
];
|
||||
|
||||
if ($multipart === null) {
|
||||
$defaultHeaders['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
$headers = array_merge($defaultHeaders, $extraHeaders);
|
||||
|
||||
$options = [
|
||||
RequestOptions::HEADERS => $headers,
|
||||
RequestOptions::HTTP_ERRORS => false,
|
||||
];
|
||||
|
||||
if ($multipart !== null) {
|
||||
$options[RequestOptions::MULTIPART] = $multipart;
|
||||
} elseif (($method === 'POST' || $method === 'PATCH') && $body !== []) {
|
||||
$options[RequestOptions::JSON] = $body;
|
||||
}
|
||||
|
||||
$attempt = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
$response = $this->httpClient->request($method, $url, $options);
|
||||
$statusCode = $response->getStatusCode();
|
||||
$responseBody = (string) $response->getBody();
|
||||
|
||||
if ($statusCode >= 200 && $statusCode < 300) {
|
||||
if ($responseBody === '' || $responseBody === '{}') {
|
||||
return [];
|
||||
}
|
||||
/** @var array<string, mixed> */
|
||||
return json_decode($responseBody, true, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
$errorMessage = $this->extractErrorMessage($responseBody, $statusCode);
|
||||
$errorCode = $this->extractErrorCode($responseBody);
|
||||
|
||||
// Non-retryable client errors
|
||||
if ($statusCode === 401) {
|
||||
throw new AuthenticationException($errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
if ($statusCode === 429) {
|
||||
throw new RateLimitException($errorMessage, $errorCode);
|
||||
}
|
||||
|
||||
if ($statusCode >= 400 && $statusCode < 500 && $statusCode !== 408 && $statusCode !== 409) {
|
||||
throw new FirecrawlException($errorMessage, $statusCode, $errorCode);
|
||||
}
|
||||
|
||||
// Retryable errors: 408, 409, 502, 5xx
|
||||
if ($attempt < $this->maxRetries) {
|
||||
$attempt++;
|
||||
$this->sleepWithBackoff($attempt);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new FirecrawlException($errorMessage, $statusCode, $errorCode);
|
||||
} catch (FirecrawlException $e) {
|
||||
throw $e;
|
||||
} catch (ConnectException $e) {
|
||||
if ($attempt < $this->maxRetries) {
|
||||
$attempt++;
|
||||
$this->sleepWithBackoff($attempt);
|
||||
continue;
|
||||
}
|
||||
throw new FirecrawlException('Connection failed: ' . $e->getMessage(), previous: $e);
|
||||
} catch (RequestException $e) {
|
||||
if ($attempt < $this->maxRetries) {
|
||||
$attempt++;
|
||||
$this->sleepWithBackoff($attempt);
|
||||
continue;
|
||||
}
|
||||
throw new FirecrawlException('Request failed: ' . $e->getMessage(), previous: $e);
|
||||
} catch (\JsonException $e) {
|
||||
throw new FirecrawlException('Failed to parse API response: ' . $e->getMessage(), previous: $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function extractErrorMessage(string $body, int $statusCode): string
|
||||
{
|
||||
try {
|
||||
/** @var array<string, mixed> $parsed */
|
||||
$parsed = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
if (isset($parsed['error']) && is_string($parsed['error'])) {
|
||||
return $parsed['error'];
|
||||
}
|
||||
|
||||
if (isset($parsed['message']) && is_string($parsed['message'])) {
|
||||
return $parsed['message'];
|
||||
}
|
||||
} catch (\JsonException) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return "HTTP {$statusCode} error";
|
||||
}
|
||||
|
||||
private function extractErrorCode(string $body): ?string
|
||||
{
|
||||
try {
|
||||
/** @var array<string, mixed> $parsed */
|
||||
$parsed = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
if (isset($parsed['code'])) {
|
||||
return (string) $parsed['code'];
|
||||
}
|
||||
} catch (\JsonException) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function sleepWithBackoff(int $attempt): void
|
||||
{
|
||||
$delayMs = (int) ($this->backoffFactor * 1000 * pow(2, $attempt - 1));
|
||||
usleep($delayMs * 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Exceptions;
|
||||
|
||||
class AuthenticationException extends FirecrawlException
|
||||
{
|
||||
public function __construct(
|
||||
string $message = 'Authentication failed. Check your API key.',
|
||||
?string $errorCode = null,
|
||||
mixed $details = null,
|
||||
) {
|
||||
parent::__construct($message, 401, $errorCode, $details);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
class FirecrawlException extends RuntimeException
|
||||
{
|
||||
public function __construct(
|
||||
string $message = '',
|
||||
private readonly int $statusCode = 0,
|
||||
private readonly ?string $errorCode = null,
|
||||
private readonly mixed $details = null,
|
||||
?Throwable $previous = null,
|
||||
) {
|
||||
parent::__construct($message, $statusCode, $previous);
|
||||
}
|
||||
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
public function getErrorCode(): ?string
|
||||
{
|
||||
return $this->errorCode;
|
||||
}
|
||||
|
||||
public function getDetails(): mixed
|
||||
{
|
||||
return $this->details;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Exceptions;
|
||||
|
||||
class JobTimeoutException extends FirecrawlException
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $jobId,
|
||||
private readonly int $timeoutSeconds,
|
||||
string $jobType = 'Job',
|
||||
) {
|
||||
parent::__construct(
|
||||
"{$jobType} {$jobId} timed out after {$timeoutSeconds} seconds",
|
||||
statusCode: 408,
|
||||
);
|
||||
}
|
||||
|
||||
public function getJobId(): string
|
||||
{
|
||||
return $this->jobId;
|
||||
}
|
||||
|
||||
public function getTimeoutSeconds(): int
|
||||
{
|
||||
return $this->timeoutSeconds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Exceptions;
|
||||
|
||||
class RateLimitException extends FirecrawlException
|
||||
{
|
||||
public function __construct(
|
||||
string $message = 'Rate limit exceeded.',
|
||||
?string $errorCode = null,
|
||||
mixed $details = null,
|
||||
) {
|
||||
parent::__construct($message, 429, $errorCode, $details);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Laravel\Facades;
|
||||
|
||||
use Firecrawl\Client\FirecrawlClient;
|
||||
use Firecrawl\Models\AgentOptions;
|
||||
use Firecrawl\Models\AgentStatusResponse;
|
||||
use Firecrawl\Models\BatchScrapeJob;
|
||||
use Firecrawl\Models\BatchScrapeOptions;
|
||||
use Firecrawl\Models\BrowserCreateResponse;
|
||||
use Firecrawl\Models\BrowserDeleteResponse;
|
||||
use Firecrawl\Models\BrowserExecuteResponse;
|
||||
use Firecrawl\Models\BrowserListResponse;
|
||||
use Firecrawl\Models\ConcurrencyCheck;
|
||||
use Firecrawl\Models\CrawlJob;
|
||||
use Firecrawl\Models\CrawlOptions;
|
||||
use Firecrawl\Models\CreditUsage;
|
||||
use Firecrawl\Models\Document;
|
||||
use Firecrawl\Models\MapData;
|
||||
use Firecrawl\Models\MapOptions;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
use Firecrawl\Models\SearchData;
|
||||
use Firecrawl\Models\SearchOptions;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* @method static Document scrape(string $url, ?ScrapeOptions $options = null)
|
||||
* @method static BrowserExecuteResponse interact(string $jobId, string $code, string $language = 'node', ?int $timeout = null, ?string $origin = null)
|
||||
* @method static BrowserDeleteResponse stopInteractiveBrowser(string $jobId)
|
||||
* @method static CrawlJob crawl(string $url, ?CrawlOptions $options = null, int $pollIntervalSec = 2, int $timeoutSec = 300)
|
||||
* @method static CrawlJob getCrawlStatus(string $jobId)
|
||||
* @method static array<string, mixed> cancelCrawl(string $jobId)
|
||||
* @method static BatchScrapeJob batchScrape(list<string> $urls, ?BatchScrapeOptions $options = null, int $pollIntervalSec = 2, int $timeoutSec = 300)
|
||||
* @method static array<string, mixed> cancelBatchScrape(string $jobId)
|
||||
* @method static MapData map(string $url, ?MapOptions $options = null)
|
||||
* @method static SearchData search(string $query, ?SearchOptions $options = null)
|
||||
* @method static AgentStatusResponse agent(AgentOptions $options, int $pollIntervalSec = 2, int $timeoutSec = 300)
|
||||
* @method static array<string, mixed> cancelAgent(string $jobId)
|
||||
* @method static BrowserCreateResponse browser(?int $ttl = null, ?int $activityTtl = null, ?bool $streamWebView = null)
|
||||
* @method static BrowserExecuteResponse browserExecute(string $sessionId, string $code, string $language = 'bash', ?int $timeout = null)
|
||||
* @method static BrowserDeleteResponse deleteBrowser(string $sessionId)
|
||||
* @method static BrowserListResponse listBrowsers(?string $status = null)
|
||||
* @method static ConcurrencyCheck getConcurrency()
|
||||
* @method static CreditUsage getCreditUsage()
|
||||
*
|
||||
* @see FirecrawlClient
|
||||
*/
|
||||
class Firecrawl extends Facade
|
||||
{
|
||||
protected static function getFacadeAccessor(): string
|
||||
{
|
||||
return FirecrawlClient::class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Laravel;
|
||||
|
||||
use Firecrawl\Client\FirecrawlClient;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class FirecrawlServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->mergeConfigFrom(__DIR__ . '/../../config/firecrawl.php', 'firecrawl');
|
||||
|
||||
$this->app->singleton(FirecrawlClient::class, function ($app): FirecrawlClient {
|
||||
/** @var array<string, mixed> $config */
|
||||
$config = $app['config']->get('firecrawl', []);
|
||||
|
||||
$apiKey = isset($config['api_key']) && is_string($config['api_key'])
|
||||
? trim($config['api_key'])
|
||||
: null;
|
||||
|
||||
if ($apiKey === '') {
|
||||
$apiKey = null;
|
||||
}
|
||||
|
||||
return FirecrawlClient::create(
|
||||
apiKey: $apiKey,
|
||||
apiUrl: isset($config['api_url']) && is_string($config['api_url']) ? $config['api_url'] : null,
|
||||
timeoutSeconds: (float) ($config['timeout'] ?? 300),
|
||||
maxRetries: (int) ($config['max_retries'] ?? 3),
|
||||
backoffFactor: (float) ($config['backoff_factor'] ?? 0.5),
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->alias(FirecrawlClient::class, 'firecrawl');
|
||||
}
|
||||
|
||||
public function boot(): void
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->publishes([
|
||||
__DIR__ . '/../../config/firecrawl.php' => $this->app->configPath('firecrawl.php'),
|
||||
], 'firecrawl-config');
|
||||
}
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
public function provides(): array
|
||||
{
|
||||
return [FirecrawlClient::class, 'firecrawl'];
|
||||
}
|
||||
}
|
||||
60
참고/firecrawl-main/apps/php-sdk/src/Models/AgentOptions.php
Normal file
60
참고/firecrawl-main/apps/php-sdk/src/Models/AgentOptions.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class AgentOptions
|
||||
{
|
||||
/**
|
||||
* @param list<string>|null $urls
|
||||
* @param array<string, mixed>|null $schema
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?array $urls = null,
|
||||
private readonly ?string $prompt = null,
|
||||
private readonly ?array $schema = null,
|
||||
private readonly ?string $integration = null,
|
||||
private readonly ?int $maxCredits = null,
|
||||
private readonly ?bool $strictConstrainToURLs = null,
|
||||
private readonly ?string $model = null,
|
||||
private readonly ?WebhookConfig $webhook = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<string>|null $urls
|
||||
* @param array<string, mixed>|null $schema
|
||||
*/
|
||||
public static function with(
|
||||
?array $urls = null,
|
||||
?string $prompt = null,
|
||||
?array $schema = null,
|
||||
?string $integration = null,
|
||||
?int $maxCredits = null,
|
||||
?bool $strictConstrainToURLs = null,
|
||||
?string $model = null,
|
||||
?WebhookConfig $webhook = null,
|
||||
): self {
|
||||
return new self(
|
||||
$urls, $prompt, $schema, $integration,
|
||||
$maxCredits, $strictConstrainToURLs, $model, $webhook,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$fields = [
|
||||
'urls' => $this->urls,
|
||||
'prompt' => $this->prompt,
|
||||
'schema' => $this->schema,
|
||||
'integration' => $this->integration,
|
||||
'maxCredits' => $this->maxCredits,
|
||||
'strictConstrainToURLs' => $this->strictConstrainToURLs,
|
||||
'model' => $this->model,
|
||||
'webhook' => $this->webhook?->toArray(),
|
||||
];
|
||||
|
||||
return array_filter($fields, fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
}
|
||||
39
참고/firecrawl-main/apps/php-sdk/src/Models/AgentResponse.php
Normal file
39
참고/firecrawl-main/apps/php-sdk/src/Models/AgentResponse.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class AgentResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $error = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
success: (bool) ($data['success'] ?? false),
|
||||
id: $data['id'] ?? null,
|
||||
error: $data['error'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class AgentStatusResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly ?string $status = null,
|
||||
private readonly ?string $error = null,
|
||||
private readonly mixed $data = null,
|
||||
private readonly ?string $model = null,
|
||||
private readonly ?string $expiresAt = null,
|
||||
private readonly ?int $creditsUsed = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $raw */
|
||||
public static function fromArray(array $raw): self
|
||||
{
|
||||
return new self(
|
||||
success: (bool) ($raw['success'] ?? false),
|
||||
status: $raw['status'] ?? null,
|
||||
error: $raw['error'] ?? null,
|
||||
data: $raw['data'] ?? null,
|
||||
model: $raw['model'] ?? null,
|
||||
expiresAt: $raw['expiresAt'] ?? null,
|
||||
creditsUsed: isset($raw['creditsUsed']) ? (int) $raw['creditsUsed'] : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isDone(): bool
|
||||
{
|
||||
return in_array($this->status, ['completed', 'failed', 'cancelled'], true);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function getData(): mixed
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getModel(): ?string
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): ?string
|
||||
{
|
||||
return $this->expiresAt;
|
||||
}
|
||||
|
||||
public function getCreditsUsed(): ?int
|
||||
{
|
||||
return $this->creditsUsed;
|
||||
}
|
||||
}
|
||||
109
참고/firecrawl-main/apps/php-sdk/src/Models/BatchScrapeJob.php
Normal file
109
참고/firecrawl-main/apps/php-sdk/src/Models/BatchScrapeJob.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BatchScrapeJob
|
||||
{
|
||||
/** @var list<Document> */
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
* @param list<Document> $data
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $status = null,
|
||||
private readonly int $completed = 0,
|
||||
private readonly int $total = 0,
|
||||
private readonly ?int $creditsUsed = null,
|
||||
private readonly ?string $expiresAt = null,
|
||||
private ?string $next = null,
|
||||
array $data = [],
|
||||
) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $raw */
|
||||
public static function fromArray(array $raw): self
|
||||
{
|
||||
$docs = [];
|
||||
foreach (($raw['data'] ?? []) as $item) {
|
||||
$docs[] = Document::fromArray($item);
|
||||
}
|
||||
|
||||
return new self(
|
||||
id: $raw['id'] ?? null,
|
||||
status: $raw['status'] ?? null,
|
||||
completed: (int) ($raw['completed'] ?? 0),
|
||||
total: (int) ($raw['total'] ?? 0),
|
||||
creditsUsed: isset($raw['creditsUsed']) ? (int) $raw['creditsUsed'] : null,
|
||||
expiresAt: $raw['expiresAt'] ?? null,
|
||||
next: $raw['next'] ?? null,
|
||||
data: $docs,
|
||||
);
|
||||
}
|
||||
|
||||
public function isDone(): bool
|
||||
{
|
||||
return in_array($this->status, ['completed', 'failed', 'cancelled'], true);
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getCompleted(): int
|
||||
{
|
||||
return $this->completed;
|
||||
}
|
||||
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
public function getCreditsUsed(): ?int
|
||||
{
|
||||
return $this->creditsUsed;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): ?string
|
||||
{
|
||||
return $this->expiresAt;
|
||||
}
|
||||
|
||||
public function getNext(): ?string
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
public function setNext(?string $next): void
|
||||
{
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
/** @return list<Document> */
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/** @param list<Document> $data */
|
||||
public function setData(array $data): void
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function appendData(Document $document): void
|
||||
{
|
||||
$this->data[] = $document;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BatchScrapeOptions
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?ScrapeOptions $options = null,
|
||||
private readonly string|WebhookConfig|null $webhook = null,
|
||||
private readonly ?string $appendToId = null,
|
||||
private readonly ?bool $ignoreInvalidURLs = null,
|
||||
private readonly ?int $maxConcurrency = null,
|
||||
private readonly ?bool $zeroDataRetention = null,
|
||||
private readonly ?string $idempotencyKey = null,
|
||||
private readonly ?string $integration = null,
|
||||
) {}
|
||||
|
||||
public static function with(
|
||||
?ScrapeOptions $options = null,
|
||||
string|WebhookConfig|null $webhook = null,
|
||||
?string $appendToId = null,
|
||||
?bool $ignoreInvalidURLs = null,
|
||||
?int $maxConcurrency = null,
|
||||
?bool $zeroDataRetention = null,
|
||||
?string $idempotencyKey = null,
|
||||
?string $integration = null,
|
||||
): self {
|
||||
return new self(
|
||||
$options, $webhook, $appendToId, $ignoreInvalidURLs,
|
||||
$maxConcurrency, $zeroDataRetention, $idempotencyKey, $integration,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$fields = [
|
||||
'webhook' => $this->webhook instanceof WebhookConfig ? $this->webhook->toArray() : $this->webhook,
|
||||
'appendToId' => $this->appendToId,
|
||||
'ignoreInvalidURLs' => $this->ignoreInvalidURLs,
|
||||
'maxConcurrency' => $this->maxConcurrency,
|
||||
'zeroDataRetention' => $this->zeroDataRetention,
|
||||
'integration' => $this->integration,
|
||||
];
|
||||
|
||||
$data = array_filter($fields, fn (mixed $v): bool => $v !== null);
|
||||
|
||||
// Flatten scrape options into body (API expects top-level, not nested)
|
||||
if ($this->options !== null) {
|
||||
$data = array_merge($this->options->toArray(), $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getIdempotencyKey(): ?string
|
||||
{
|
||||
return $this->idempotencyKey;
|
||||
}
|
||||
|
||||
public function getOptions(): ?ScrapeOptions
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BatchScrapeResponse
|
||||
{
|
||||
/**
|
||||
* @param list<string>|null $invalidURLs
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $url = null,
|
||||
private readonly ?array $invalidURLs = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
id: $data['id'] ?? null,
|
||||
url: $data['url'] ?? null,
|
||||
invalidURLs: $data['invalidURLs'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUrl(): ?string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getInvalidURLs(): ?array
|
||||
{
|
||||
return $this->invalidURLs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BrowserCreateResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $cdpUrl = null,
|
||||
private readonly ?string $liveViewUrl = null,
|
||||
private readonly ?string $interactiveLiveViewUrl = null,
|
||||
private readonly ?string $expiresAt = null,
|
||||
private readonly ?string $error = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
success: (bool) ($data['success'] ?? false),
|
||||
id: $data['id'] ?? null,
|
||||
cdpUrl: $data['cdpUrl'] ?? null,
|
||||
liveViewUrl: $data['liveViewUrl'] ?? null,
|
||||
interactiveLiveViewUrl: $data['interactiveLiveViewUrl'] ?? null,
|
||||
expiresAt: $data['expiresAt'] ?? null,
|
||||
error: $data['error'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCdpUrl(): ?string
|
||||
{
|
||||
return $this->cdpUrl;
|
||||
}
|
||||
|
||||
public function getLiveViewUrl(): ?string
|
||||
{
|
||||
return $this->liveViewUrl;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): ?string
|
||||
{
|
||||
return $this->expiresAt;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function getInteractiveLiveViewUrl(): ?string
|
||||
{
|
||||
return $this->interactiveLiveViewUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BrowserDeleteResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly ?int $sessionDurationMs = null,
|
||||
private readonly ?int $creditsBilled = null,
|
||||
private readonly ?string $error = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
success: (bool) ($data['success'] ?? false),
|
||||
sessionDurationMs: isset($data['sessionDurationMs']) ? (int) $data['sessionDurationMs'] : null,
|
||||
creditsBilled: isset($data['creditsBilled']) ? (int) $data['creditsBilled'] : null,
|
||||
error: $data['error'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function getSessionDurationMs(): ?int
|
||||
{
|
||||
return $this->sessionDurationMs;
|
||||
}
|
||||
|
||||
public function getCreditsBilled(): ?int
|
||||
{
|
||||
return $this->creditsBilled;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BrowserExecuteResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly ?string $stdout = null,
|
||||
private readonly ?string $result = null,
|
||||
private readonly ?string $stderr = null,
|
||||
private readonly ?int $exitCode = null,
|
||||
private readonly ?bool $killed = null,
|
||||
private readonly ?string $error = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
success: (bool) ($data['success'] ?? false),
|
||||
stdout: $data['stdout'] ?? null,
|
||||
result: $data['result'] ?? null,
|
||||
stderr: $data['stderr'] ?? null,
|
||||
exitCode: isset($data['exitCode']) ? (int) $data['exitCode'] : null,
|
||||
killed: $data['killed'] ?? null,
|
||||
error: $data['error'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function getStdout(): ?string
|
||||
{
|
||||
return $this->stdout;
|
||||
}
|
||||
|
||||
public function getResult(): ?string
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
public function getStderr(): ?string
|
||||
{
|
||||
return $this->stderr;
|
||||
}
|
||||
|
||||
public function getExitCode(): ?int
|
||||
{
|
||||
return $this->exitCode;
|
||||
}
|
||||
|
||||
public function isKilled(): ?bool
|
||||
{
|
||||
return $this->killed;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BrowserListResponse
|
||||
{
|
||||
/**
|
||||
* @param list<BrowserSession> $sessions
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly bool $success = false,
|
||||
private readonly array $sessions = [],
|
||||
private readonly ?string $error = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$sessions = [];
|
||||
$rawSessions = $data['sessions'] ?? [];
|
||||
if (is_array($rawSessions)) {
|
||||
foreach ($rawSessions as $session) {
|
||||
$sessions[] = BrowserSession::fromArray($session);
|
||||
}
|
||||
}
|
||||
|
||||
return new self(
|
||||
success: (bool) ($data['success'] ?? false),
|
||||
sessions: $sessions,
|
||||
error: $data['error'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function isSuccess(): bool
|
||||
{
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
/** @return list<BrowserSession> */
|
||||
public function getSessions(): array
|
||||
{
|
||||
return $this->sessions;
|
||||
}
|
||||
|
||||
public function getError(): ?string
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
}
|
||||
67
참고/firecrawl-main/apps/php-sdk/src/Models/BrowserSession.php
Normal file
67
참고/firecrawl-main/apps/php-sdk/src/Models/BrowserSession.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class BrowserSession
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $status = null,
|
||||
private readonly ?string $cdpUrl = null,
|
||||
private readonly ?string $liveViewUrl = null,
|
||||
private readonly bool $streamWebView = false,
|
||||
private readonly ?string $createdAt = null,
|
||||
private readonly ?string $lastActivity = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
id: $data['id'] ?? null,
|
||||
status: $data['status'] ?? null,
|
||||
cdpUrl: $data['cdpUrl'] ?? null,
|
||||
liveViewUrl: $data['liveViewUrl'] ?? null,
|
||||
streamWebView: (bool) ($data['streamWebView'] ?? false),
|
||||
createdAt: $data['createdAt'] ?? null,
|
||||
lastActivity: $data['lastActivity'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getCdpUrl(): ?string
|
||||
{
|
||||
return $this->cdpUrl;
|
||||
}
|
||||
|
||||
public function getLiveViewUrl(): ?string
|
||||
{
|
||||
return $this->liveViewUrl;
|
||||
}
|
||||
|
||||
public function isStreamWebView(): bool
|
||||
{
|
||||
return $this->streamWebView;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?string
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function getLastActivity(): ?string
|
||||
{
|
||||
return $this->lastActivity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class ConcurrencyCheck
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $concurrency = 0,
|
||||
private readonly int $maxConcurrency = 0,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
concurrency: (int) ($data['concurrency'] ?? 0),
|
||||
maxConcurrency: (int) ($data['maxConcurrency'] ?? 0),
|
||||
);
|
||||
}
|
||||
|
||||
public function getConcurrency(): int
|
||||
{
|
||||
return $this->concurrency;
|
||||
}
|
||||
|
||||
public function getMaxConcurrency(): int
|
||||
{
|
||||
return $this->maxConcurrency;
|
||||
}
|
||||
}
|
||||
109
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlJob.php
Normal file
109
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlJob.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class CrawlJob
|
||||
{
|
||||
/** @var list<Document> */
|
||||
private array $data;
|
||||
|
||||
/**
|
||||
* @param list<Document> $data
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $status = null,
|
||||
private readonly int $total = 0,
|
||||
private readonly int $completed = 0,
|
||||
private readonly ?int $creditsUsed = null,
|
||||
private readonly ?string $expiresAt = null,
|
||||
private ?string $next = null,
|
||||
array $data = [],
|
||||
) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $raw */
|
||||
public static function fromArray(array $raw): self
|
||||
{
|
||||
$docs = [];
|
||||
foreach (($raw['data'] ?? []) as $item) {
|
||||
$docs[] = Document::fromArray($item);
|
||||
}
|
||||
|
||||
return new self(
|
||||
id: $raw['id'] ?? null,
|
||||
status: $raw['status'] ?? null,
|
||||
total: (int) ($raw['total'] ?? 0),
|
||||
completed: (int) ($raw['completed'] ?? 0),
|
||||
creditsUsed: isset($raw['creditsUsed']) ? (int) $raw['creditsUsed'] : null,
|
||||
expiresAt: $raw['expiresAt'] ?? null,
|
||||
next: $raw['next'] ?? null,
|
||||
data: $docs,
|
||||
);
|
||||
}
|
||||
|
||||
public function isDone(): bool
|
||||
{
|
||||
return in_array($this->status, ['completed', 'failed', 'cancelled'], true);
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function getTotal(): int
|
||||
{
|
||||
return $this->total;
|
||||
}
|
||||
|
||||
public function getCompleted(): int
|
||||
{
|
||||
return $this->completed;
|
||||
}
|
||||
|
||||
public function getCreditsUsed(): ?int
|
||||
{
|
||||
return $this->creditsUsed;
|
||||
}
|
||||
|
||||
public function getExpiresAt(): ?string
|
||||
{
|
||||
return $this->expiresAt;
|
||||
}
|
||||
|
||||
public function getNext(): ?string
|
||||
{
|
||||
return $this->next;
|
||||
}
|
||||
|
||||
public function setNext(?string $next): void
|
||||
{
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
/** @return list<Document> */
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/** @param list<Document> $data */
|
||||
public function setData(array $data): void
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function appendData(Document $document): void
|
||||
{
|
||||
$this->data[] = $document;
|
||||
}
|
||||
}
|
||||
92
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlOptions.php
Normal file
92
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlOptions.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class CrawlOptions
|
||||
{
|
||||
/**
|
||||
* @param list<string>|null $excludePaths
|
||||
* @param list<string>|null $includePaths
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?string $prompt = null,
|
||||
private readonly ?array $excludePaths = null,
|
||||
private readonly ?array $includePaths = null,
|
||||
private readonly ?int $maxDiscoveryDepth = null,
|
||||
private readonly ?string $sitemap = null,
|
||||
private readonly ?bool $ignoreQueryParameters = null,
|
||||
private readonly ?bool $deduplicateSimilarURLs = null,
|
||||
private readonly ?int $limit = null,
|
||||
private readonly ?bool $crawlEntireDomain = null,
|
||||
private readonly ?bool $allowExternalLinks = null,
|
||||
private readonly ?bool $allowSubdomains = null,
|
||||
private readonly ?int $delay = null,
|
||||
private readonly ?int $maxConcurrency = null,
|
||||
private readonly string|WebhookConfig|null $webhook = null,
|
||||
private readonly ?ScrapeOptions $scrapeOptions = null,
|
||||
private readonly ?bool $regexOnFullURL = null,
|
||||
private readonly ?bool $zeroDataRetention = null,
|
||||
private readonly ?string $integration = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<string>|null $excludePaths
|
||||
* @param list<string>|null $includePaths
|
||||
*/
|
||||
public static function with(
|
||||
?string $prompt = null,
|
||||
?array $excludePaths = null,
|
||||
?array $includePaths = null,
|
||||
?int $maxDiscoveryDepth = null,
|
||||
?string $sitemap = null,
|
||||
?bool $ignoreQueryParameters = null,
|
||||
?bool $deduplicateSimilarURLs = null,
|
||||
?int $limit = null,
|
||||
?bool $crawlEntireDomain = null,
|
||||
?bool $allowExternalLinks = null,
|
||||
?bool $allowSubdomains = null,
|
||||
?int $delay = null,
|
||||
?int $maxConcurrency = null,
|
||||
string|WebhookConfig|null $webhook = null,
|
||||
?ScrapeOptions $scrapeOptions = null,
|
||||
?bool $regexOnFullURL = null,
|
||||
?bool $zeroDataRetention = null,
|
||||
?string $integration = null,
|
||||
): self {
|
||||
return new self(
|
||||
$prompt, $excludePaths, $includePaths, $maxDiscoveryDepth, $sitemap,
|
||||
$ignoreQueryParameters, $deduplicateSimilarURLs, $limit, $crawlEntireDomain,
|
||||
$allowExternalLinks, $allowSubdomains, $delay, $maxConcurrency, $webhook,
|
||||
$scrapeOptions, $regexOnFullURL, $zeroDataRetention, $integration,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$fields = [
|
||||
'prompt' => $this->prompt,
|
||||
'excludePaths' => $this->excludePaths,
|
||||
'includePaths' => $this->includePaths,
|
||||
'maxDiscoveryDepth' => $this->maxDiscoveryDepth,
|
||||
'sitemap' => $this->sitemap,
|
||||
'ignoreQueryParameters' => $this->ignoreQueryParameters,
|
||||
'deduplicateSimilarURLs' => $this->deduplicateSimilarURLs,
|
||||
'limit' => $this->limit,
|
||||
'crawlEntireDomain' => $this->crawlEntireDomain,
|
||||
'allowExternalLinks' => $this->allowExternalLinks,
|
||||
'allowSubdomains' => $this->allowSubdomains,
|
||||
'delay' => $this->delay,
|
||||
'maxConcurrency' => $this->maxConcurrency,
|
||||
'webhook' => $this->webhook instanceof WebhookConfig ? $this->webhook->toArray() : $this->webhook,
|
||||
'scrapeOptions' => $this->scrapeOptions?->toArray(),
|
||||
'regexOnFullURL' => $this->regexOnFullURL,
|
||||
'zeroDataRetention' => $this->zeroDataRetention,
|
||||
'integration' => $this->integration,
|
||||
];
|
||||
|
||||
return array_filter($fields, fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
}
|
||||
32
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlResponse.php
Normal file
32
참고/firecrawl-main/apps/php-sdk/src/Models/CrawlResponse.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class CrawlResponse
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $url = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
id: $data['id'] ?? null,
|
||||
url: $data['url'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUrl(): ?string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
}
|
||||
48
참고/firecrawl-main/apps/php-sdk/src/Models/CreditUsage.php
Normal file
48
참고/firecrawl-main/apps/php-sdk/src/Models/CreditUsage.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class CreditUsage
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $remainingCredits = 0,
|
||||
private readonly ?int $planCredits = null,
|
||||
private readonly ?string $billingPeriodStart = null,
|
||||
private readonly ?string $billingPeriodEnd = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$inner = $data['data'] ?? $data;
|
||||
|
||||
return new self(
|
||||
remainingCredits: (int) ($inner['remainingCredits'] ?? 0),
|
||||
planCredits: isset($inner['planCredits']) ? (int) $inner['planCredits'] : null,
|
||||
billingPeriodStart: $inner['billingPeriodStart'] ?? null,
|
||||
billingPeriodEnd: $inner['billingPeriodEnd'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getRemainingCredits(): int
|
||||
{
|
||||
return $this->remainingCredits;
|
||||
}
|
||||
|
||||
public function getPlanCredits(): ?int
|
||||
{
|
||||
return $this->planCredits;
|
||||
}
|
||||
|
||||
public function getBillingPeriodStart(): ?string
|
||||
{
|
||||
return $this->billingPeriodStart;
|
||||
}
|
||||
|
||||
public function getBillingPeriodEnd(): ?string
|
||||
{
|
||||
return $this->billingPeriodEnd;
|
||||
}
|
||||
}
|
||||
153
참고/firecrawl-main/apps/php-sdk/src/Models/Document.php
Normal file
153
참고/firecrawl-main/apps/php-sdk/src/Models/Document.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class Document
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed>|null $metadata
|
||||
* @param list<string>|null $links
|
||||
* @param list<string>|null $images
|
||||
* @param list<array<string, mixed>>|null $attributes
|
||||
* @param array<string, mixed>|null $actions
|
||||
* @param array<string, mixed>|null $changeTracking
|
||||
* @param array<string, mixed>|null $branding
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $markdown = null,
|
||||
private readonly ?string $html = null,
|
||||
private readonly ?string $rawHtml = null,
|
||||
private readonly mixed $json = null,
|
||||
private readonly ?string $summary = null,
|
||||
private readonly ?array $metadata = null,
|
||||
private readonly ?array $links = null,
|
||||
private readonly ?array $images = null,
|
||||
private readonly ?string $screenshot = null,
|
||||
private readonly ?string $audio = null,
|
||||
private readonly ?array $attributes = null,
|
||||
private readonly ?array $actions = null,
|
||||
private readonly ?string $answer = null,
|
||||
private readonly ?string $highlights = null,
|
||||
private readonly ?string $warning = null,
|
||||
private readonly ?array $changeTracking = null,
|
||||
private readonly ?array $branding = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
markdown: $data['markdown'] ?? null,
|
||||
html: $data['html'] ?? null,
|
||||
rawHtml: $data['rawHtml'] ?? null,
|
||||
json: $data['json'] ?? null,
|
||||
summary: $data['summary'] ?? null,
|
||||
metadata: $data['metadata'] ?? null,
|
||||
links: $data['links'] ?? null,
|
||||
images: $data['images'] ?? null,
|
||||
screenshot: $data['screenshot'] ?? null,
|
||||
audio: $data['audio'] ?? null,
|
||||
attributes: $data['attributes'] ?? null,
|
||||
actions: $data['actions'] ?? null,
|
||||
answer: $data['answer'] ?? null,
|
||||
highlights: $data['highlights'] ?? null,
|
||||
warning: $data['warning'] ?? null,
|
||||
changeTracking: $data['changeTracking'] ?? null,
|
||||
branding: $data['branding'] ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getMarkdown(): ?string
|
||||
{
|
||||
return $this->markdown;
|
||||
}
|
||||
|
||||
public function getHtml(): ?string
|
||||
{
|
||||
return $this->html;
|
||||
}
|
||||
|
||||
public function getRawHtml(): ?string
|
||||
{
|
||||
return $this->rawHtml;
|
||||
}
|
||||
|
||||
public function getJson(): mixed
|
||||
{
|
||||
return $this->json;
|
||||
}
|
||||
|
||||
public function getSummary(): ?string
|
||||
{
|
||||
return $this->summary;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getLinks(): ?array
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getImages(): ?array
|
||||
{
|
||||
return $this->images;
|
||||
}
|
||||
|
||||
public function getScreenshot(): ?string
|
||||
{
|
||||
return $this->screenshot;
|
||||
}
|
||||
|
||||
public function getAudio(): ?string
|
||||
{
|
||||
return $this->audio;
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>>|null */
|
||||
public function getAttributes(): ?array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getActions(): ?array
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
public function getWarning(): ?string
|
||||
{
|
||||
return $this->warning;
|
||||
}
|
||||
|
||||
public function getAnswer(): ?string
|
||||
{
|
||||
return $this->answer;
|
||||
}
|
||||
|
||||
public function getHighlights(): ?string
|
||||
{
|
||||
return $this->highlights;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getChangeTracking(): ?array
|
||||
{
|
||||
return $this->changeTracking;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getBranding(): ?array
|
||||
{
|
||||
return $this->branding;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class HighlightsFormat
|
||||
{
|
||||
private function __construct(
|
||||
private readonly string $query,
|
||||
) {}
|
||||
|
||||
public static function with(string $query): self
|
||||
{
|
||||
return new self($query);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'highlights',
|
||||
'query' => $this->query,
|
||||
];
|
||||
}
|
||||
|
||||
public function getQuery(): string
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
}
|
||||
45
참고/firecrawl-main/apps/php-sdk/src/Models/JsonFormat.php
Normal file
45
참고/firecrawl-main/apps/php-sdk/src/Models/JsonFormat.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class JsonFormat
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?string $prompt = null,
|
||||
/** @var array<string, mixed>|null */
|
||||
private readonly ?array $schema = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $schema
|
||||
*/
|
||||
public static function with(
|
||||
?string $prompt = null,
|
||||
?array $schema = null,
|
||||
): self {
|
||||
return new self($prompt, $schema);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'type' => 'json',
|
||||
'prompt' => $this->prompt,
|
||||
'schema' => $this->schema,
|
||||
], fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
|
||||
public function getPrompt(): ?string
|
||||
{
|
||||
return $this->prompt;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getSchema(): ?array
|
||||
{
|
||||
return $this->schema;
|
||||
}
|
||||
}
|
||||
44
참고/firecrawl-main/apps/php-sdk/src/Models/LocationConfig.php
Normal file
44
참고/firecrawl-main/apps/php-sdk/src/Models/LocationConfig.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class LocationConfig
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?string $country = null,
|
||||
/** @var list<string>|null */
|
||||
private readonly ?array $languages = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<string>|null $languages
|
||||
*/
|
||||
public static function with(
|
||||
?string $country = null,
|
||||
?array $languages = null,
|
||||
): self {
|
||||
return new self($country, $languages);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'country' => $this->country,
|
||||
'languages' => $this->languages,
|
||||
], fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
|
||||
public function getCountry(): ?string
|
||||
{
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getLanguages(): ?array
|
||||
{
|
||||
return $this->languages;
|
||||
}
|
||||
}
|
||||
41
참고/firecrawl-main/apps/php-sdk/src/Models/MapData.php
Normal file
41
참고/firecrawl-main/apps/php-sdk/src/Models/MapData.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class MapData
|
||||
{
|
||||
/**
|
||||
* @param list<array<string, mixed>> $links
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $links = [],
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$rawLinks = $data['links'] ?? [];
|
||||
if (!is_array($rawLinks)) {
|
||||
return new self(links: []);
|
||||
}
|
||||
$normalized = [];
|
||||
|
||||
foreach ($rawLinks as $link) {
|
||||
if (is_string($link)) {
|
||||
$normalized[] = ['url' => $link];
|
||||
} elseif (is_array($link)) {
|
||||
$normalized[] = $link;
|
||||
}
|
||||
}
|
||||
|
||||
return new self(links: $normalized);
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getLinks(): array
|
||||
{
|
||||
return $this->links;
|
||||
}
|
||||
}
|
||||
52
참고/firecrawl-main/apps/php-sdk/src/Models/MapOptions.php
Normal file
52
참고/firecrawl-main/apps/php-sdk/src/Models/MapOptions.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class MapOptions
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?string $search = null,
|
||||
private readonly ?string $sitemap = null,
|
||||
private readonly ?bool $includeSubdomains = null,
|
||||
private readonly ?bool $ignoreQueryParameters = null,
|
||||
private readonly ?int $limit = null,
|
||||
private readonly ?int $timeout = null,
|
||||
private readonly ?string $integration = null,
|
||||
private readonly ?LocationConfig $location = null,
|
||||
) {}
|
||||
|
||||
public static function with(
|
||||
?string $search = null,
|
||||
?string $sitemap = null,
|
||||
?bool $includeSubdomains = null,
|
||||
?bool $ignoreQueryParameters = null,
|
||||
?int $limit = null,
|
||||
?int $timeout = null,
|
||||
?string $integration = null,
|
||||
?LocationConfig $location = null,
|
||||
): self {
|
||||
return new self(
|
||||
$search, $sitemap, $includeSubdomains, $ignoreQueryParameters,
|
||||
$limit, $timeout, $integration, $location,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$fields = [
|
||||
'search' => $this->search,
|
||||
'sitemap' => $this->sitemap,
|
||||
'includeSubdomains' => $this->includeSubdomains,
|
||||
'ignoreQueryParameters' => $this->ignoreQueryParameters,
|
||||
'limit' => $this->limit,
|
||||
'timeout' => $this->timeout,
|
||||
'integration' => $this->integration,
|
||||
'location' => $this->location?->toArray(),
|
||||
];
|
||||
|
||||
return array_filter($fields, fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
}
|
||||
76
참고/firecrawl-main/apps/php-sdk/src/Models/Monitor.php
Normal file
76
참고/firecrawl-main/apps/php-sdk/src/Models/Monitor.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class Monitor
|
||||
{
|
||||
/**
|
||||
* @param list<array<string, mixed>> $targets
|
||||
* @param array<string, mixed>|null $schedule
|
||||
* @param array<string, mixed>|null $webhook
|
||||
* @param array<string, mixed>|null $notification
|
||||
* @param array<string, mixed>|null $lastCheckSummary
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $name = null,
|
||||
private readonly ?string $status = null,
|
||||
private readonly ?array $schedule = null,
|
||||
private readonly ?string $nextRunAt = null,
|
||||
private readonly ?string $lastRunAt = null,
|
||||
private readonly ?string $currentCheckId = null,
|
||||
private readonly array $targets = [],
|
||||
private readonly ?array $webhook = null,
|
||||
private readonly ?array $notification = null,
|
||||
private readonly ?int $retentionDays = null,
|
||||
private readonly ?int $estimatedCreditsPerMonth = null,
|
||||
private readonly ?array $lastCheckSummary = null,
|
||||
private readonly ?string $createdAt = null,
|
||||
private readonly ?string $updatedAt = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
id: isset($data['id']) ? (string) $data['id'] : null,
|
||||
name: isset($data['name']) ? (string) $data['name'] : null,
|
||||
status: isset($data['status']) ? (string) $data['status'] : null,
|
||||
schedule: isset($data['schedule']) && is_array($data['schedule']) ? $data['schedule'] : null,
|
||||
nextRunAt: isset($data['nextRunAt']) ? (string) $data['nextRunAt'] : null,
|
||||
lastRunAt: isset($data['lastRunAt']) ? (string) $data['lastRunAt'] : null,
|
||||
currentCheckId: isset($data['currentCheckId']) ? (string) $data['currentCheckId'] : null,
|
||||
targets: isset($data['targets']) && is_array($data['targets']) ? $data['targets'] : [],
|
||||
webhook: isset($data['webhook']) && is_array($data['webhook']) ? $data['webhook'] : null,
|
||||
notification: isset($data['notification']) && is_array($data['notification']) ? $data['notification'] : null,
|
||||
retentionDays: isset($data['retentionDays']) ? (int) $data['retentionDays'] : null,
|
||||
estimatedCreditsPerMonth: isset($data['estimatedCreditsPerMonth']) ? (int) $data['estimatedCreditsPerMonth'] : null,
|
||||
lastCheckSummary: isset($data['lastCheckSummary']) && is_array($data['lastCheckSummary']) ? $data['lastCheckSummary'] : null,
|
||||
createdAt: isset($data['createdAt']) ? (string) $data['createdAt'] : null,
|
||||
updatedAt: isset($data['updatedAt']) ? (string) $data['updatedAt'] : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getId(): ?string { return $this->id; }
|
||||
public function getName(): ?string { return $this->name; }
|
||||
public function getStatus(): ?string { return $this->status; }
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getSchedule(): ?array { return $this->schedule; }
|
||||
public function getNextRunAt(): ?string { return $this->nextRunAt; }
|
||||
public function getLastRunAt(): ?string { return $this->lastRunAt; }
|
||||
public function getCurrentCheckId(): ?string { return $this->currentCheckId; }
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getTargets(): array { return $this->targets; }
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getWebhook(): ?array { return $this->webhook; }
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getNotification(): ?array { return $this->notification; }
|
||||
public function getRetentionDays(): ?int { return $this->retentionDays; }
|
||||
public function getEstimatedCreditsPerMonth(): ?int { return $this->estimatedCreditsPerMonth; }
|
||||
/** @return array<string, mixed>|null */
|
||||
public function getLastCheckSummary(): ?array { return $this->lastCheckSummary; }
|
||||
public function getCreatedAt(): ?string { return $this->createdAt; }
|
||||
public function getUpdatedAt(): ?string { return $this->updatedAt; }
|
||||
}
|
||||
77
참고/firecrawl-main/apps/php-sdk/src/Models/MonitorCheck.php
Normal file
77
참고/firecrawl-main/apps/php-sdk/src/Models/MonitorCheck.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
/** @phpstan-consistent-constructor */
|
||||
class MonitorCheck
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $summary
|
||||
* @param mixed $targetResults
|
||||
* @param mixed $notificationStatus
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ?string $id = null,
|
||||
private readonly ?string $monitorId = null,
|
||||
private readonly ?string $status = null,
|
||||
private readonly ?string $trigger = null,
|
||||
private readonly ?string $scheduledFor = null,
|
||||
private readonly ?string $startedAt = null,
|
||||
private readonly ?string $finishedAt = null,
|
||||
private readonly ?int $estimatedCredits = null,
|
||||
private readonly ?int $reservedCredits = null,
|
||||
private readonly ?int $actualCredits = null,
|
||||
private readonly ?string $billingStatus = null,
|
||||
private readonly array $summary = [],
|
||||
private readonly mixed $targetResults = null,
|
||||
private readonly mixed $notificationStatus = null,
|
||||
private readonly ?string $error = null,
|
||||
private readonly ?string $createdAt = null,
|
||||
private readonly ?string $updatedAt = null,
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): static
|
||||
{
|
||||
return new static(
|
||||
id: isset($data['id']) ? (string) $data['id'] : null,
|
||||
monitorId: isset($data['monitorId']) ? (string) $data['monitorId'] : null,
|
||||
status: isset($data['status']) ? (string) $data['status'] : null,
|
||||
trigger: isset($data['trigger']) ? (string) $data['trigger'] : null,
|
||||
scheduledFor: isset($data['scheduledFor']) ? (string) $data['scheduledFor'] : null,
|
||||
startedAt: isset($data['startedAt']) ? (string) $data['startedAt'] : null,
|
||||
finishedAt: isset($data['finishedAt']) ? (string) $data['finishedAt'] : null,
|
||||
estimatedCredits: isset($data['estimatedCredits']) ? (int) $data['estimatedCredits'] : null,
|
||||
reservedCredits: isset($data['reservedCredits']) ? (int) $data['reservedCredits'] : null,
|
||||
actualCredits: isset($data['actualCredits']) ? (int) $data['actualCredits'] : null,
|
||||
billingStatus: isset($data['billingStatus']) ? (string) $data['billingStatus'] : null,
|
||||
summary: isset($data['summary']) && is_array($data['summary']) ? $data['summary'] : [],
|
||||
targetResults: $data['targetResults'] ?? null,
|
||||
notificationStatus: $data['notificationStatus'] ?? null,
|
||||
error: isset($data['error']) ? (string) $data['error'] : null,
|
||||
createdAt: isset($data['createdAt']) ? (string) $data['createdAt'] : null,
|
||||
updatedAt: isset($data['updatedAt']) ? (string) $data['updatedAt'] : null,
|
||||
);
|
||||
}
|
||||
|
||||
public function getId(): ?string { return $this->id; }
|
||||
public function getMonitorId(): ?string { return $this->monitorId; }
|
||||
public function getStatus(): ?string { return $this->status; }
|
||||
public function getTrigger(): ?string { return $this->trigger; }
|
||||
public function getScheduledFor(): ?string { return $this->scheduledFor; }
|
||||
public function getStartedAt(): ?string { return $this->startedAt; }
|
||||
public function getFinishedAt(): ?string { return $this->finishedAt; }
|
||||
public function getEstimatedCredits(): ?int { return $this->estimatedCredits; }
|
||||
public function getReservedCredits(): ?int { return $this->reservedCredits; }
|
||||
public function getActualCredits(): ?int { return $this->actualCredits; }
|
||||
public function getBillingStatus(): ?string { return $this->billingStatus; }
|
||||
/** @return array<string, mixed> */
|
||||
public function getSummary(): array { return $this->summary; }
|
||||
public function getTargetResults(): mixed { return $this->targetResults; }
|
||||
public function getNotificationStatus(): mixed { return $this->notificationStatus; }
|
||||
public function getError(): ?string { return $this->error; }
|
||||
public function getCreatedAt(): ?string { return $this->createdAt; }
|
||||
public function getUpdatedAt(): ?string { return $this->updatedAt; }
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class MonitorCheckDetail extends MonitorCheck
|
||||
{
|
||||
/**
|
||||
* @param list<array<string, mixed>> $pages
|
||||
*/
|
||||
public function __construct(
|
||||
?string $id = null,
|
||||
?string $monitorId = null,
|
||||
?string $status = null,
|
||||
?string $trigger = null,
|
||||
?string $scheduledFor = null,
|
||||
?string $startedAt = null,
|
||||
?string $finishedAt = null,
|
||||
?int $estimatedCredits = null,
|
||||
?int $reservedCredits = null,
|
||||
?int $actualCredits = null,
|
||||
?string $billingStatus = null,
|
||||
array $summary = [],
|
||||
mixed $targetResults = null,
|
||||
mixed $notificationStatus = null,
|
||||
?string $error = null,
|
||||
?string $createdAt = null,
|
||||
?string $updatedAt = null,
|
||||
private readonly array $pages = [],
|
||||
private readonly ?string $next = null,
|
||||
) {
|
||||
parent::__construct(
|
||||
id: $id,
|
||||
monitorId: $monitorId,
|
||||
status: $status,
|
||||
trigger: $trigger,
|
||||
scheduledFor: $scheduledFor,
|
||||
startedAt: $startedAt,
|
||||
finishedAt: $finishedAt,
|
||||
estimatedCredits: $estimatedCredits,
|
||||
reservedCredits: $reservedCredits,
|
||||
actualCredits: $actualCredits,
|
||||
billingStatus: $billingStatus,
|
||||
summary: $summary,
|
||||
targetResults: $targetResults,
|
||||
notificationStatus: $notificationStatus,
|
||||
error: $error,
|
||||
createdAt: $createdAt,
|
||||
updatedAt: $updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): static
|
||||
{
|
||||
/** @var self $check */
|
||||
$check = new self(
|
||||
id: isset($data['id']) ? (string) $data['id'] : null,
|
||||
monitorId: isset($data['monitorId']) ? (string) $data['monitorId'] : null,
|
||||
status: isset($data['status']) ? (string) $data['status'] : null,
|
||||
trigger: isset($data['trigger']) ? (string) $data['trigger'] : null,
|
||||
scheduledFor: isset($data['scheduledFor']) ? (string) $data['scheduledFor'] : null,
|
||||
startedAt: isset($data['startedAt']) ? (string) $data['startedAt'] : null,
|
||||
finishedAt: isset($data['finishedAt']) ? (string) $data['finishedAt'] : null,
|
||||
estimatedCredits: isset($data['estimatedCredits']) ? (int) $data['estimatedCredits'] : null,
|
||||
reservedCredits: isset($data['reservedCredits']) ? (int) $data['reservedCredits'] : null,
|
||||
actualCredits: isset($data['actualCredits']) ? (int) $data['actualCredits'] : null,
|
||||
billingStatus: isset($data['billingStatus']) ? (string) $data['billingStatus'] : null,
|
||||
summary: isset($data['summary']) && is_array($data['summary']) ? $data['summary'] : [],
|
||||
targetResults: $data['targetResults'] ?? null,
|
||||
notificationStatus: $data['notificationStatus'] ?? null,
|
||||
error: isset($data['error']) ? (string) $data['error'] : null,
|
||||
createdAt: isset($data['createdAt']) ? (string) $data['createdAt'] : null,
|
||||
updatedAt: isset($data['updatedAt']) ? (string) $data['updatedAt'] : null,
|
||||
pages: isset($data['pages']) && is_array($data['pages']) ? $data['pages'] : [],
|
||||
next: isset($data['next']) ? (string) $data['next'] : null,
|
||||
);
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getPages(): array { return $this->pages; }
|
||||
public function getNext(): ?string { return $this->next; }
|
||||
}
|
||||
100
참고/firecrawl-main/apps/php-sdk/src/Models/ParseFile.php
Normal file
100
참고/firecrawl-main/apps/php-sdk/src/Models/ParseFile.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
|
||||
/**
|
||||
* Binary upload payload for the `/v2/parse` endpoint.
|
||||
*
|
||||
* Supported file extensions: .html, .htm, .pdf, .docx, .doc, .odt, .rtf, .xlsx, .xls
|
||||
*/
|
||||
final class ParseFile
|
||||
{
|
||||
private const CONTENT_TYPE_BY_EXTENSION = [
|
||||
'pdf' => 'application/pdf',
|
||||
'html' => 'text/html',
|
||||
'htm' => 'text/html',
|
||||
'xhtml' => 'application/xhtml+xml',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'doc' => 'application/msword',
|
||||
'odt' => 'application/vnd.oasis.opendocument.text',
|
||||
'rtf' => 'application/rtf',
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
];
|
||||
|
||||
private function __construct(
|
||||
private readonly string $filename,
|
||||
private readonly string $content,
|
||||
private readonly ?string $contentType,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Build a ParseFile from raw bytes.
|
||||
*/
|
||||
public static function fromBytes(
|
||||
string $filename,
|
||||
string $content,
|
||||
?string $contentType = null,
|
||||
): self {
|
||||
$trimmed = trim($filename);
|
||||
if ($trimmed === '') {
|
||||
throw new FirecrawlException('filename is required');
|
||||
}
|
||||
if ($content === '') {
|
||||
throw new FirecrawlException('content is required');
|
||||
}
|
||||
|
||||
return new self($trimmed, $content, $contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a ParseFile by reading a file from disk.
|
||||
*/
|
||||
public static function fromPath(
|
||||
string $path,
|
||||
?string $filename = null,
|
||||
?string $contentType = null,
|
||||
): self {
|
||||
if ($path === '') {
|
||||
throw new FirecrawlException('path is required');
|
||||
}
|
||||
if (!is_file($path) || !is_readable($path)) {
|
||||
throw new FirecrawlException('file path does not exist or is not readable: ' . $path);
|
||||
}
|
||||
|
||||
$content = @file_get_contents($path);
|
||||
if ($content === false) {
|
||||
throw new FirecrawlException('failed to read parse file: ' . $path);
|
||||
}
|
||||
|
||||
$resolvedFilename = $filename ?: basename($path);
|
||||
$resolvedContentType = $contentType ?: self::guessContentType($resolvedFilename);
|
||||
|
||||
return self::fromBytes($resolvedFilename, $content, $resolvedContentType);
|
||||
}
|
||||
|
||||
public function getFilename(): string
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function getContentType(): ?string
|
||||
{
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
private static function guessContentType(string $filename): ?string
|
||||
{
|
||||
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
return self::CONTENT_TYPE_BY_EXTENSION[$ext] ?? null;
|
||||
}
|
||||
}
|
||||
229
참고/firecrawl-main/apps/php-sdk/src/Models/ParseOptions.php
Normal file
229
참고/firecrawl-main/apps/php-sdk/src/Models/ParseOptions.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
|
||||
/**
|
||||
* Options for parsing uploaded files via `/v2/parse`.
|
||||
*
|
||||
* Parse does not support browser-rendering features (actions, waitFor,
|
||||
* location, mobile) nor the screenshot, branding, or changeTracking formats.
|
||||
* The proxy field only accepts "auto" or "basic".
|
||||
*/
|
||||
final class ParseOptions
|
||||
{
|
||||
private const UNSUPPORTED_FORMATS = [
|
||||
'changeTracking',
|
||||
'screenshot',
|
||||
'screenshot@fullPage',
|
||||
'branding',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param list<string|JsonFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null $formats
|
||||
* @param array<string, string>|null $headers
|
||||
* @param list<string>|null $includeTags
|
||||
* @param list<string>|null $excludeTags
|
||||
* @param list<mixed>|null $parsers
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?array $formats = null,
|
||||
private readonly ?array $headers = null,
|
||||
private readonly ?array $includeTags = null,
|
||||
private readonly ?array $excludeTags = null,
|
||||
private readonly ?bool $onlyMainContent = null,
|
||||
private readonly ?int $timeout = null,
|
||||
private readonly ?array $parsers = null,
|
||||
private readonly ?bool $skipTlsVerification = null,
|
||||
private readonly ?bool $removeBase64Images = null,
|
||||
private readonly ?bool $blockAds = null,
|
||||
private readonly ?string $proxy = null,
|
||||
private readonly ?string $integration = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<string|JsonFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null $formats
|
||||
* @param array<string, string>|null $headers
|
||||
* @param list<string>|null $includeTags
|
||||
* @param list<string>|null $excludeTags
|
||||
* @param list<mixed>|null $parsers
|
||||
*/
|
||||
public static function with(
|
||||
?array $formats = null,
|
||||
?array $headers = null,
|
||||
?array $includeTags = null,
|
||||
?array $excludeTags = null,
|
||||
?bool $onlyMainContent = null,
|
||||
?int $timeout = null,
|
||||
?array $parsers = null,
|
||||
?bool $skipTlsVerification = null,
|
||||
?bool $removeBase64Images = null,
|
||||
?bool $blockAds = null,
|
||||
?string $proxy = null,
|
||||
?string $integration = null,
|
||||
): self {
|
||||
if ($timeout !== null && $timeout <= 0) {
|
||||
throw new FirecrawlException('timeout must be positive');
|
||||
}
|
||||
|
||||
if ($proxy !== null && $proxy !== '' && !in_array($proxy, ['auto', 'basic'], true)) {
|
||||
throw new FirecrawlException("parse only supports proxy values 'auto' or 'basic'");
|
||||
}
|
||||
|
||||
if ($formats !== null) {
|
||||
foreach ($formats as $fmt) {
|
||||
$type = self::extractFormatType($fmt);
|
||||
if ($type !== null && in_array($type, self::UNSUPPORTED_FORMATS, true)) {
|
||||
throw new FirecrawlException('parse does not support format: ' . $type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new self(
|
||||
$formats,
|
||||
$headers,
|
||||
$includeTags,
|
||||
$excludeTags,
|
||||
$onlyMainContent,
|
||||
$timeout,
|
||||
$parsers,
|
||||
$skipTlsVerification,
|
||||
$removeBase64Images,
|
||||
$blockAds,
|
||||
$proxy,
|
||||
$integration,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
if ($this->formats !== null) {
|
||||
$data['formats'] = array_map(
|
||||
fn (string|JsonFormat|QuestionFormat|HighlightsFormat|QueryFormat $f): string|array =>
|
||||
(
|
||||
$f instanceof JsonFormat
|
||||
|| $f instanceof QuestionFormat
|
||||
|| $f instanceof HighlightsFormat
|
||||
|| $f instanceof QueryFormat
|
||||
) ? $f->toArray() : $f,
|
||||
$this->formats,
|
||||
);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'headers' => $this->headers,
|
||||
'includeTags' => $this->includeTags,
|
||||
'excludeTags' => $this->excludeTags,
|
||||
'onlyMainContent' => $this->onlyMainContent,
|
||||
'timeout' => $this->timeout,
|
||||
'parsers' => $this->parsers,
|
||||
'skipTlsVerification' => $this->skipTlsVerification,
|
||||
'removeBase64Images' => $this->removeBase64Images,
|
||||
'blockAds' => $this->blockAds,
|
||||
'proxy' => $this->proxy,
|
||||
'integration' => $this->integration,
|
||||
];
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
if ($value !== null) {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private static function extractFormatType(mixed $fmt): ?string
|
||||
{
|
||||
if (is_string($fmt)) {
|
||||
return $fmt;
|
||||
}
|
||||
if ($fmt instanceof JsonFormat) {
|
||||
return 'json';
|
||||
}
|
||||
if ($fmt instanceof QuestionFormat) {
|
||||
return 'question';
|
||||
}
|
||||
if ($fmt instanceof HighlightsFormat) {
|
||||
return 'highlights';
|
||||
}
|
||||
if ($fmt instanceof QueryFormat) {
|
||||
return 'query';
|
||||
}
|
||||
if (is_array($fmt) && isset($fmt['type']) && is_string($fmt['type'])) {
|
||||
return $fmt['type'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return list<string|JsonFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null */
|
||||
public function getFormats(): ?array
|
||||
{
|
||||
return $this->formats;
|
||||
}
|
||||
|
||||
/** @return array<string, string>|null */
|
||||
public function getHeaders(): ?array
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getIncludeTags(): ?array
|
||||
{
|
||||
return $this->includeTags;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getExcludeTags(): ?array
|
||||
{
|
||||
return $this->excludeTags;
|
||||
}
|
||||
|
||||
public function getOnlyMainContent(): ?bool
|
||||
{
|
||||
return $this->onlyMainContent;
|
||||
}
|
||||
|
||||
public function getTimeout(): ?int
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
/** @return list<mixed>|null */
|
||||
public function getParsers(): ?array
|
||||
{
|
||||
return $this->parsers;
|
||||
}
|
||||
|
||||
public function getSkipTlsVerification(): ?bool
|
||||
{
|
||||
return $this->skipTlsVerification;
|
||||
}
|
||||
|
||||
public function getRemoveBase64Images(): ?bool
|
||||
{
|
||||
return $this->removeBase64Images;
|
||||
}
|
||||
|
||||
public function getBlockAds(): ?bool
|
||||
{
|
||||
return $this->blockAds;
|
||||
}
|
||||
|
||||
public function getProxy(): ?string
|
||||
{
|
||||
return $this->proxy;
|
||||
}
|
||||
|
||||
public function getIntegration(): ?string
|
||||
{
|
||||
return $this->integration;
|
||||
}
|
||||
}
|
||||
48
참고/firecrawl-main/apps/php-sdk/src/Models/QueryFormat.php
Normal file
48
참고/firecrawl-main/apps/php-sdk/src/Models/QueryFormat.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
/** @deprecated Use QuestionFormat or HighlightsFormat instead. */
|
||||
final class QueryFormat
|
||||
{
|
||||
public const MODE_FREEFORM = 'freeform';
|
||||
public const MODE_DIRECT_QUOTE = 'directQuote';
|
||||
|
||||
private function __construct(
|
||||
private readonly string $prompt,
|
||||
private readonly ?string $mode = null,
|
||||
) {}
|
||||
|
||||
public static function with(
|
||||
string $prompt,
|
||||
?string $mode = null,
|
||||
): self {
|
||||
if ($mode !== null && !in_array($mode, [self::MODE_FREEFORM, self::MODE_DIRECT_QUOTE], true)) {
|
||||
throw new \InvalidArgumentException("query mode must be 'freeform' or 'directQuote'");
|
||||
}
|
||||
|
||||
return new self($prompt, $mode);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'type' => 'query',
|
||||
'prompt' => $this->prompt,
|
||||
'mode' => $this->mode,
|
||||
], fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
|
||||
public function getPrompt(): string
|
||||
{
|
||||
return $this->prompt;
|
||||
}
|
||||
|
||||
public function getMode(): ?string
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
}
|
||||
31
참고/firecrawl-main/apps/php-sdk/src/Models/QuestionFormat.php
Normal file
31
참고/firecrawl-main/apps/php-sdk/src/Models/QuestionFormat.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class QuestionFormat
|
||||
{
|
||||
private function __construct(
|
||||
private readonly string $question,
|
||||
) {}
|
||||
|
||||
public static function with(string $question): self
|
||||
{
|
||||
return new self($question);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'question',
|
||||
'question' => $this->question,
|
||||
];
|
||||
}
|
||||
|
||||
public function getQuestion(): string
|
||||
{
|
||||
return $this->question;
|
||||
}
|
||||
}
|
||||
253
참고/firecrawl-main/apps/php-sdk/src/Models/ScrapeOptions.php
Normal file
253
참고/firecrawl-main/apps/php-sdk/src/Models/ScrapeOptions.php
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class ScrapeOptions
|
||||
{
|
||||
/**
|
||||
* @param list<string|JsonFormat|ScreenshotFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null $formats
|
||||
* @param array<string, string>|null $headers
|
||||
* @param list<string>|null $includeTags
|
||||
* @param list<string>|null $excludeTags
|
||||
* @param list<mixed>|null $parsers
|
||||
* @param list<array<string, mixed>>|null $actions
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?array $formats = null,
|
||||
private readonly ?array $headers = null,
|
||||
private readonly ?array $includeTags = null,
|
||||
private readonly ?array $excludeTags = null,
|
||||
private readonly ?bool $onlyMainContent = null,
|
||||
private readonly ?int $timeout = null,
|
||||
private readonly ?int $waitFor = null,
|
||||
private readonly ?bool $mobile = null,
|
||||
private readonly ?array $parsers = null,
|
||||
private readonly ?array $actions = null,
|
||||
private readonly ?LocationConfig $location = null,
|
||||
private readonly ?bool $skipTlsVerification = null,
|
||||
private readonly ?bool $removeBase64Images = null,
|
||||
private readonly ?bool $blockAds = null,
|
||||
private readonly ?string $proxy = null,
|
||||
private readonly ?int $maxAge = null,
|
||||
private readonly ?int $minAge = null,
|
||||
private readonly ?bool $storeInCache = null,
|
||||
private readonly ?bool $lockdown = null,
|
||||
private readonly ?string $integration = null,
|
||||
/** @var array<string, string>|null */
|
||||
private readonly ?array $profile = null,
|
||||
private readonly ?bool $changeTracking = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<string|JsonFormat|ScreenshotFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null $formats
|
||||
* @param array<string, string>|null $headers
|
||||
* @param list<string>|null $includeTags
|
||||
* @param list<string>|null $excludeTags
|
||||
* @param list<mixed>|null $parsers
|
||||
* @param list<array<string, mixed>>|null $actions
|
||||
* @param array<string, string>|null $profile
|
||||
*/
|
||||
public static function with(
|
||||
?array $formats = null,
|
||||
?array $headers = null,
|
||||
?array $includeTags = null,
|
||||
?array $excludeTags = null,
|
||||
?bool $onlyMainContent = null,
|
||||
?int $timeout = null,
|
||||
?int $waitFor = null,
|
||||
?bool $mobile = null,
|
||||
?array $parsers = null,
|
||||
?array $actions = null,
|
||||
?LocationConfig $location = null,
|
||||
?bool $skipTlsVerification = null,
|
||||
?bool $removeBase64Images = null,
|
||||
?bool $blockAds = null,
|
||||
?string $proxy = null,
|
||||
?int $maxAge = null,
|
||||
?bool $storeInCache = null,
|
||||
?string $integration = null,
|
||||
?bool $lockdown = null,
|
||||
?int $minAge = null,
|
||||
?array $profile = null,
|
||||
?bool $changeTracking = null,
|
||||
): self {
|
||||
return new self(
|
||||
$formats, $headers, $includeTags, $excludeTags, $onlyMainContent,
|
||||
$timeout, $waitFor, $mobile, $parsers, $actions, $location,
|
||||
$skipTlsVerification, $removeBase64Images, $blockAds, $proxy,
|
||||
$maxAge, $minAge, $storeInCache, $lockdown, $integration, $profile,
|
||||
$changeTracking,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
if ($this->formats !== null) {
|
||||
$data['formats'] = array_map(
|
||||
fn (string|JsonFormat|ScreenshotFormat|QuestionFormat|HighlightsFormat|QueryFormat $f): string|array =>
|
||||
(
|
||||
$f instanceof JsonFormat
|
||||
|| $f instanceof ScreenshotFormat
|
||||
|| $f instanceof QuestionFormat
|
||||
|| $f instanceof HighlightsFormat
|
||||
|| $f instanceof QueryFormat
|
||||
) ? $f->toArray() : $f,
|
||||
$this->formats,
|
||||
);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'headers' => $this->headers,
|
||||
'includeTags' => $this->includeTags,
|
||||
'excludeTags' => $this->excludeTags,
|
||||
'onlyMainContent' => $this->onlyMainContent,
|
||||
'timeout' => $this->timeout,
|
||||
'waitFor' => $this->waitFor,
|
||||
'mobile' => $this->mobile,
|
||||
'parsers' => $this->parsers,
|
||||
'actions' => $this->actions,
|
||||
'location' => $this->location?->toArray(),
|
||||
'skipTlsVerification' => $this->skipTlsVerification,
|
||||
'removeBase64Images' => $this->removeBase64Images,
|
||||
'blockAds' => $this->blockAds,
|
||||
'proxy' => $this->proxy,
|
||||
'maxAge' => $this->maxAge,
|
||||
'minAge' => $this->minAge,
|
||||
'storeInCache' => $this->storeInCache,
|
||||
'lockdown' => $this->lockdown,
|
||||
'integration' => $this->integration,
|
||||
'profile' => $this->profile,
|
||||
'changeTracking' => $this->changeTracking,
|
||||
];
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
if ($value !== null) {
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @return list<string|JsonFormat|ScreenshotFormat|QuestionFormat|HighlightsFormat|QueryFormat>|null */
|
||||
public function getFormats(): ?array
|
||||
{
|
||||
return $this->formats;
|
||||
}
|
||||
|
||||
/** @return array<string, string>|null */
|
||||
public function getHeaders(): ?array
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getIncludeTags(): ?array
|
||||
{
|
||||
return $this->includeTags;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getExcludeTags(): ?array
|
||||
{
|
||||
return $this->excludeTags;
|
||||
}
|
||||
|
||||
public function getOnlyMainContent(): ?bool
|
||||
{
|
||||
return $this->onlyMainContent;
|
||||
}
|
||||
|
||||
public function getTimeout(): ?int
|
||||
{
|
||||
return $this->timeout;
|
||||
}
|
||||
|
||||
public function getWaitFor(): ?int
|
||||
{
|
||||
return $this->waitFor;
|
||||
}
|
||||
|
||||
public function getMobile(): ?bool
|
||||
{
|
||||
return $this->mobile;
|
||||
}
|
||||
|
||||
/** @return list<mixed>|null */
|
||||
public function getParsers(): ?array
|
||||
{
|
||||
return $this->parsers;
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>>|null */
|
||||
public function getActions(): ?array
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
public function getLocation(): ?LocationConfig
|
||||
{
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
public function getSkipTlsVerification(): ?bool
|
||||
{
|
||||
return $this->skipTlsVerification;
|
||||
}
|
||||
|
||||
public function getRemoveBase64Images(): ?bool
|
||||
{
|
||||
return $this->removeBase64Images;
|
||||
}
|
||||
|
||||
public function getBlockAds(): ?bool
|
||||
{
|
||||
return $this->blockAds;
|
||||
}
|
||||
|
||||
public function getProxy(): ?string
|
||||
{
|
||||
return $this->proxy;
|
||||
}
|
||||
|
||||
public function getMaxAge(): ?int
|
||||
{
|
||||
return $this->maxAge;
|
||||
}
|
||||
|
||||
public function getStoreInCache(): ?bool
|
||||
{
|
||||
return $this->storeInCache;
|
||||
}
|
||||
|
||||
public function getLockdown(): ?bool
|
||||
{
|
||||
return $this->lockdown;
|
||||
}
|
||||
|
||||
public function getIntegration(): ?string
|
||||
{
|
||||
return $this->integration;
|
||||
}
|
||||
|
||||
public function getMinAge(): ?int
|
||||
{
|
||||
return $this->minAge;
|
||||
}
|
||||
|
||||
/** @return array<string, string>|null */
|
||||
public function getProfile(): ?array
|
||||
{
|
||||
return $this->profile;
|
||||
}
|
||||
|
||||
public function getChangeTracking(): ?bool
|
||||
{
|
||||
return $this->changeTracking;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class ScreenshotFormat
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?bool $fullPage = null,
|
||||
private readonly ?int $quality = null,
|
||||
) {}
|
||||
|
||||
public static function with(
|
||||
?bool $fullPage = null,
|
||||
?int $quality = null,
|
||||
): self {
|
||||
return new self($fullPage, $quality);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'type' => 'screenshot',
|
||||
'fullPage' => $this->fullPage,
|
||||
'quality' => $this->quality,
|
||||
], fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
|
||||
public function getFullPage(): ?bool
|
||||
{
|
||||
return $this->fullPage;
|
||||
}
|
||||
|
||||
public function getQuality(): ?int
|
||||
{
|
||||
return $this->quality;
|
||||
}
|
||||
}
|
||||
51
참고/firecrawl-main/apps/php-sdk/src/Models/SearchData.php
Normal file
51
참고/firecrawl-main/apps/php-sdk/src/Models/SearchData.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class SearchData
|
||||
{
|
||||
/**
|
||||
* @param list<array<string, mixed>> $web
|
||||
* @param list<array<string, mixed>> $news
|
||||
* @param list<array<string, mixed>> $images
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly array $web = [],
|
||||
private readonly array $news = [],
|
||||
private readonly array $images = [],
|
||||
) {}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$web = $data['web'] ?? [];
|
||||
$news = $data['news'] ?? [];
|
||||
$images = $data['images'] ?? [];
|
||||
|
||||
return new self(
|
||||
web: is_array($web) ? $web : [],
|
||||
news: is_array($news) ? $news : [],
|
||||
images: is_array($images) ? $images : [],
|
||||
);
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getWeb(): array
|
||||
{
|
||||
return $this->web;
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getNews(): array
|
||||
{
|
||||
return $this->news;
|
||||
}
|
||||
|
||||
/** @return list<array<string, mixed>> */
|
||||
public function getImages(): array
|
||||
{
|
||||
return $this->images;
|
||||
}
|
||||
}
|
||||
73
참고/firecrawl-main/apps/php-sdk/src/Models/SearchOptions.php
Normal file
73
참고/firecrawl-main/apps/php-sdk/src/Models/SearchOptions.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class SearchOptions
|
||||
{
|
||||
/**
|
||||
* @param list<mixed>|null $sources
|
||||
* @param list<mixed>|null $categories
|
||||
* @param list<string>|null $includeDomains
|
||||
* @param list<string>|null $excludeDomains
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?array $sources = null,
|
||||
private readonly ?array $categories = null,
|
||||
private readonly ?int $limit = null,
|
||||
private readonly ?string $tbs = null,
|
||||
private readonly ?string $location = null,
|
||||
private readonly ?bool $ignoreInvalidURLs = null,
|
||||
private readonly ?int $timeout = null,
|
||||
private readonly ?ScrapeOptions $scrapeOptions = null,
|
||||
private readonly ?string $integration = null,
|
||||
private readonly ?array $includeDomains = null,
|
||||
private readonly ?array $excludeDomains = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param list<mixed>|null $sources
|
||||
* @param list<mixed>|null $categories
|
||||
* @param list<string>|null $includeDomains
|
||||
* @param list<string>|null $excludeDomains
|
||||
*/
|
||||
public static function with(
|
||||
?array $sources = null,
|
||||
?array $categories = null,
|
||||
?int $limit = null,
|
||||
?string $tbs = null,
|
||||
?string $location = null,
|
||||
?bool $ignoreInvalidURLs = null,
|
||||
?int $timeout = null,
|
||||
?ScrapeOptions $scrapeOptions = null,
|
||||
?string $integration = null,
|
||||
?array $includeDomains = null,
|
||||
?array $excludeDomains = null,
|
||||
): self {
|
||||
return new self(
|
||||
$sources, $categories, $limit, $tbs, $location, $ignoreInvalidURLs,
|
||||
$timeout, $scrapeOptions, $integration, $includeDomains, $excludeDomains,
|
||||
);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
$fields = [
|
||||
'sources' => $this->sources,
|
||||
'categories' => $this->categories,
|
||||
'includeDomains' => $this->includeDomains,
|
||||
'excludeDomains' => $this->excludeDomains,
|
||||
'limit' => $this->limit,
|
||||
'tbs' => $this->tbs,
|
||||
'location' => $this->location,
|
||||
'ignoreInvalidURLs' => $this->ignoreInvalidURLs,
|
||||
'timeout' => $this->timeout,
|
||||
'scrapeOptions' => $this->scrapeOptions?->toArray(),
|
||||
'integration' => $this->integration,
|
||||
];
|
||||
|
||||
return array_filter($fields, fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
}
|
||||
66
참고/firecrawl-main/apps/php-sdk/src/Models/WebhookConfig.php
Normal file
66
참고/firecrawl-main/apps/php-sdk/src/Models/WebhookConfig.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl\Models;
|
||||
|
||||
final class WebhookConfig
|
||||
{
|
||||
private function __construct(
|
||||
private readonly string $url,
|
||||
/** @var array<string, string>|null */
|
||||
private readonly ?array $headers = null,
|
||||
/** @var array<string, string>|null */
|
||||
private readonly ?array $metadata = null,
|
||||
/** @var list<string>|null */
|
||||
private readonly ?array $events = null,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<string, string>|null $headers
|
||||
* @param array<string, string>|null $metadata
|
||||
* @param list<string>|null $events
|
||||
*/
|
||||
public static function with(
|
||||
string $url,
|
||||
?array $headers = null,
|
||||
?array $metadata = null,
|
||||
?array $events = null,
|
||||
): self {
|
||||
return new self($url, $headers, $metadata, $events);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'url' => $this->url,
|
||||
'headers' => $this->headers,
|
||||
'metadata' => $this->metadata,
|
||||
'events' => $this->events,
|
||||
], fn (mixed $v): bool => $v !== null);
|
||||
}
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/** @return array<string, string>|null */
|
||||
public function getHeaders(): ?array
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/** @return array<string, string>|null */
|
||||
public function getMetadata(): ?array
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/** @return list<string>|null */
|
||||
public function getEvents(): ?array
|
||||
{
|
||||
return $this->events;
|
||||
}
|
||||
}
|
||||
10
참고/firecrawl-main/apps/php-sdk/src/Version.php
Normal file
10
참고/firecrawl-main/apps/php-sdk/src/Version.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Firecrawl;
|
||||
|
||||
final class Version
|
||||
{
|
||||
public const SDK_VERSION = '1.2.1';
|
||||
}
|
||||
5
참고/firecrawl-main/apps/php-sdk/tests/Pest.php
Normal file
5
참고/firecrawl-main/apps/php-sdk/tests/Pest.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
uses()->group('unit')->in('Unit');
|
||||
174
참고/firecrawl-main/apps/php-sdk/tests/Unit/ModelsTest.php
Normal file
174
참고/firecrawl-main/apps/php-sdk/tests/Unit/ModelsTest.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Firecrawl\Models\CreditUsage;
|
||||
use Firecrawl\Models\MapData;
|
||||
use Firecrawl\Models\BatchScrapeJob;
|
||||
use Firecrawl\Models\CrawlJob;
|
||||
use Firecrawl\Models\HighlightsFormat;
|
||||
use Firecrawl\Models\QueryFormat;
|
||||
use Firecrawl\Models\QuestionFormat;
|
||||
use Firecrawl\Models\ScrapeOptions;
|
||||
|
||||
it('hydrates CreditUsage from nested data key', function (): void {
|
||||
$response = [
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'remainingCredits' => 500,
|
||||
'planCredits' => 1000,
|
||||
'billingPeriodStart' => '2025-01-01',
|
||||
'billingPeriodEnd' => '2025-02-01',
|
||||
],
|
||||
];
|
||||
|
||||
$usage = CreditUsage::fromArray($response);
|
||||
|
||||
expect($usage->getRemainingCredits())->toBe(500);
|
||||
expect($usage->getPlanCredits())->toBe(1000);
|
||||
expect($usage->getBillingPeriodStart())->toBe('2025-01-01');
|
||||
expect($usage->getBillingPeriodEnd())->toBe('2025-02-01');
|
||||
});
|
||||
|
||||
it('hydrates CreditUsage from flat data', function (): void {
|
||||
$response = [
|
||||
'remainingCredits' => 250,
|
||||
'planCredits' => 500,
|
||||
];
|
||||
|
||||
$usage = CreditUsage::fromArray($response);
|
||||
|
||||
expect($usage->getRemainingCredits())->toBe(250);
|
||||
expect($usage->getPlanCredits())->toBe(500);
|
||||
});
|
||||
|
||||
it('guards MapData links against non-array input', function (): void {
|
||||
$data = ['links' => 'not-an-array'];
|
||||
|
||||
$map = MapData::fromArray($data);
|
||||
|
||||
expect($map->getLinks())->toBe([]);
|
||||
});
|
||||
|
||||
it('normalizes MapData string links', function (): void {
|
||||
$data = [
|
||||
'links' => [
|
||||
'https://example.com',
|
||||
['url' => 'https://example.com/about', 'title' => 'About'],
|
||||
],
|
||||
];
|
||||
|
||||
$map = MapData::fromArray($data);
|
||||
|
||||
expect($map->getLinks())->toHaveCount(2);
|
||||
expect($map->getLinks()[0])->toBe(['url' => 'https://example.com']);
|
||||
expect($map->getLinks()[1])->toBe(['url' => 'https://example.com/about', 'title' => 'About']);
|
||||
});
|
||||
|
||||
it('casts creditsUsed to int in BatchScrapeJob', function (): void {
|
||||
$raw = [
|
||||
'id' => 'batch-123',
|
||||
'status' => 'completed',
|
||||
'completed' => 5,
|
||||
'total' => 5,
|
||||
'creditsUsed' => '42',
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
$job = BatchScrapeJob::fromArray($raw);
|
||||
|
||||
expect($job->getCreditsUsed())->toBe(42);
|
||||
expect($job->getCreditsUsed())->toBeInt();
|
||||
});
|
||||
|
||||
it('preserves null creditsUsed in CrawlJob', function (): void {
|
||||
$raw = [
|
||||
'id' => 'crawl-123',
|
||||
'status' => 'scraping',
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
$job = CrawlJob::fromArray($raw);
|
||||
|
||||
expect($job->getCreditsUsed())->toBeNull();
|
||||
});
|
||||
|
||||
it('preserves positional integration in ScrapeOptions::with', function (): void {
|
||||
$options = ScrapeOptions::with(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
'php-sdk',
|
||||
);
|
||||
|
||||
expect($options->getStoreInCache())->toBeFalse();
|
||||
expect($options->getIntegration())->toBe('php-sdk');
|
||||
expect($options->getLockdown())->toBeNull();
|
||||
expect($options->toArray())->toMatchArray([
|
||||
'storeInCache' => false,
|
||||
'integration' => 'php-sdk',
|
||||
]);
|
||||
});
|
||||
|
||||
it('serializes lockdown in ScrapeOptions', function (): void {
|
||||
$options = ScrapeOptions::with(
|
||||
lockdown: true,
|
||||
integration: 'php-sdk',
|
||||
);
|
||||
|
||||
expect($options->getLockdown())->toBeTrue();
|
||||
expect($options->toArray())->toMatchArray([
|
||||
'lockdown' => true,
|
||||
'integration' => 'php-sdk',
|
||||
]);
|
||||
});
|
||||
|
||||
it('serializes query format mode in ScrapeOptions', function (): void {
|
||||
$options = ScrapeOptions::with(
|
||||
formats: [QueryFormat::with('What is Firecrawl?', QueryFormat::MODE_DIRECT_QUOTE)],
|
||||
);
|
||||
|
||||
expect($options->toArray()['formats'][0])->toMatchArray([
|
||||
'type' => 'query',
|
||||
'prompt' => 'What is Firecrawl?',
|
||||
'mode' => 'directQuote',
|
||||
]);
|
||||
});
|
||||
|
||||
it('serializes question and highlights formats in ScrapeOptions', function (): void {
|
||||
$options = ScrapeOptions::with(
|
||||
formats: [
|
||||
QuestionFormat::with('What is Firecrawl?'),
|
||||
HighlightsFormat::with('What is Firecrawl?'),
|
||||
],
|
||||
);
|
||||
|
||||
expect($options->toArray()['formats'])->toMatchArray([
|
||||
[
|
||||
'type' => 'question',
|
||||
'question' => 'What is Firecrawl?',
|
||||
],
|
||||
[
|
||||
'type' => 'highlights',
|
||||
'query' => 'What is Firecrawl?',
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('rejects invalid query format mode', function (): void {
|
||||
QueryFormat::with('What is Firecrawl?', 'quoted');
|
||||
})->throws(InvalidArgumentException::class, "query mode must be 'freeform' or 'directQuote'");
|
||||
48
참고/firecrawl-main/apps/php-sdk/tests/Unit/ParseTest.php
Normal file
48
참고/firecrawl-main/apps/php-sdk/tests/Unit/ParseTest.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Firecrawl\Exceptions\FirecrawlException;
|
||||
use Firecrawl\Models\JsonFormat;
|
||||
use Firecrawl\Models\ParseFile;
|
||||
use Firecrawl\Models\ParseOptions;
|
||||
|
||||
it('builds a ParseFile from bytes', function (): void {
|
||||
$file = ParseFile::fromBytes('doc.pdf', 'hello');
|
||||
|
||||
expect($file->getFilename())->toBe('doc.pdf');
|
||||
expect($file->getContent())->toBe('hello');
|
||||
});
|
||||
|
||||
it('rejects empty filename', function (): void {
|
||||
ParseFile::fromBytes(' ', 'hello');
|
||||
})->throws(FirecrawlException::class);
|
||||
|
||||
it('rejects empty content', function (): void {
|
||||
ParseFile::fromBytes('doc.pdf', '');
|
||||
})->throws(FirecrawlException::class);
|
||||
|
||||
it('serializes ParseOptions with JSON format', function (): void {
|
||||
$options = ParseOptions::with(
|
||||
formats: ['markdown', JsonFormat::with(prompt: 'Extract')],
|
||||
onlyMainContent: true,
|
||||
);
|
||||
|
||||
$array = $options->toArray();
|
||||
|
||||
expect($array['formats'][0])->toBe('markdown');
|
||||
expect($array['formats'][1])->toMatchArray(['type' => 'json', 'prompt' => 'Extract']);
|
||||
expect($array['onlyMainContent'])->toBeTrue();
|
||||
});
|
||||
|
||||
it('rejects unsupported parse formats', function (): void {
|
||||
ParseOptions::with(formats: ['screenshot']);
|
||||
})->throws(FirecrawlException::class);
|
||||
|
||||
it('rejects invalid proxy values', function (): void {
|
||||
ParseOptions::with(proxy: 'stealth');
|
||||
})->throws(FirecrawlException::class);
|
||||
|
||||
it('rejects non-positive timeout', function (): void {
|
||||
ParseOptions::with(timeout: 0);
|
||||
})->throws(FirecrawlException::class);
|
||||
Reference in New Issue
Block a user