docs(executors): add Unsandbox and Vercel deployment guides
Restructure executor documentation to support multiple platforms: - Main /docs/executors page now serves as overview with platform selector - Add dedicated /docs/executors/unsandbox guide with CLI deployment - Add dedicated /docs/executors/vercel guide with one-click deploy - Include platform comparison table and shared API specification
This commit is contained in:
parent
ee066a20ca
commit
3f62228c56
3 changed files with 1096 additions and 109 deletions
|
|
@ -1,4 +1,3 @@
|
|||
import { Button } from '@tpmjs/ui/Button/Button';
|
||||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import type { Metadata } from 'next';
|
||||
|
|
@ -10,7 +9,7 @@ import { AppHeader } from '~/components/AppHeader';
|
|||
export const metadata: Metadata = {
|
||||
title: 'Custom Executors - TPMJS',
|
||||
description:
|
||||
'Learn how to deploy and configure custom executors for running TPMJS tools on your own infrastructure.',
|
||||
'Deploy your own executor to run TPMJS tools on your own infrastructure with full control and privacy.',
|
||||
};
|
||||
|
||||
const executeToolExample = `// POST /execute-tool
|
||||
|
|
@ -46,69 +45,39 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
<div className="mb-12">
|
||||
<h1 className="text-3xl font-bold text-foreground mb-4">Custom Executors</h1>
|
||||
<p className="text-lg text-foreground-secondary">
|
||||
Deploy your own executor to run TPMJS tools on your own infrastructure.
|
||||
Deploy your own executor to run TPMJS tools on your infrastructure with full control
|
||||
over environment, secrets, and data.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Quick Start Banner */}
|
||||
<section className="mb-12">
|
||||
<Link
|
||||
href="/docs/tutorials/custom-executor"
|
||||
className="block p-4 bg-gradient-to-r from-primary/10 via-primary/5 to-transparent border border-primary/30 rounded-lg hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="text-3xl">🚀</div>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-foreground">
|
||||
New to custom executors? Start with the tutorial
|
||||
</p>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Deploy your own executor in 10 minutes with our step-by-step guide
|
||||
</p>
|
||||
</div>
|
||||
<Icon icon="chevronRight" className="w-5 h-5 text-primary" />
|
||||
</div>
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
{/* Overview Section */}
|
||||
{/* What is an Executor */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">What is an Executor?</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
An executor is a service that runs TPMJS tools. When you use a collection or agent,
|
||||
TPMJS sends tool execution requests to an executor, which dynamically loads and runs
|
||||
the tool code.
|
||||
TPMJS sends tool execution requests to an executor, which dynamically loads the npm
|
||||
package and calls the tool's{' '}
|
||||
<code className="px-1 bg-surface rounded">execute()</code> function.
|
||||
</p>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
By default, TPMJS uses a shared executor. You can deploy your own for:
|
||||
<p className="text-foreground-secondary">
|
||||
By default, TPMJS uses a shared executor. Deploying your own gives you complete
|
||||
control over the execution environment.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Benefits Grid */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">
|
||||
Why Deploy Your Own Executor?
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon icon="folder" className="w-5 h-5 text-primary" />
|
||||
<h3 className="font-medium text-foreground">Full Control</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Run tools on your own infrastructure with complete control over the execution
|
||||
environment.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon icon="globe" className="w-5 h-5 text-primary" />
|
||||
<Icon icon="key" className="w-5 h-5 text-primary" />
|
||||
<h3 className="font-medium text-foreground">Privacy</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Keep tool execution data on your own servers. No data leaves your infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon icon="clock" className="w-5 h-5 text-primary" />
|
||||
<h3 className="font-medium text-foreground">Performance</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Deploy in regions closest to your users for lower latency tool execution.
|
||||
Keep tool execution data on your own servers. No data passes through TPMJS.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
|
|
@ -117,68 +86,206 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
<h3 className="font-medium text-foreground">Custom Environment</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Inject your own environment variables, secrets, and configuration into tool
|
||||
execution.
|
||||
Inject your own API keys, database connections, and secrets into tool execution.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon icon="folder" className="w-5 h-5 text-primary" />
|
||||
<h3 className="font-medium text-foreground">Full Control</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Choose your infrastructure, scale resources, and customize the execution
|
||||
environment.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<Icon icon="clock" className="w-5 h-5 text-primary" />
|
||||
<h3 className="font-medium text-foreground">No Timeouts</h3>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
Run long-running tools without hitting shared executor time limits.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Deploy Section */}
|
||||
{/* Choose Your Platform */}
|
||||
<section id="deploy" className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">
|
||||
Deploy Your Own Executor
|
||||
</h2>
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Choose Your Platform</h2>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
The fastest way to get started is to deploy our template to Vercel with one click:
|
||||
We provide deployment templates for multiple platforms. Choose the one that fits your
|
||||
needs:
|
||||
</p>
|
||||
<div className="mb-6">
|
||||
<a
|
||||
href="https://vercel.com/new/clone?repository-url=https://github.com/tpmjs/tpmjs/tree/main/templates/vercel-executor&project-name=tpmjs-executor&repository-name=tpmjs-executor"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* Unsandbox Card */}
|
||||
<Link
|
||||
href="/docs/executors/unsandbox"
|
||||
className="group p-6 bg-surface border border-border rounded-lg hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<Button size="lg">
|
||||
<Icon icon="externalLink" className="w-4 h-4 mr-2" />
|
||||
Deploy to Vercel
|
||||
</Button>
|
||||
</a>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-orange-500 to-red-600 rounded-lg flex items-center justify-center text-white font-bold text-lg">
|
||||
un
|
||||
</div>
|
||||
<p className="text-sm text-foreground-tertiary">
|
||||
After deployment, you'll get a URL like{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded text-foreground-secondary">
|
||||
https://tpmjs-executor.vercel.app
|
||||
</code>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-foreground group-hover:text-primary transition-colors">
|
||||
Unsandbox
|
||||
</h3>
|
||||
<p className="text-sm text-foreground-secondary mt-1">
|
||||
Always-on container execution with automatic HTTPS. Deploy with one CLI
|
||||
command.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
<span className="px-2 py-0.5 text-xs bg-success/10 text-success rounded">
|
||||
Recommended
|
||||
</span>
|
||||
<span className="px-2 py-0.5 text-xs bg-surface-secondary rounded text-foreground-tertiary">
|
||||
No cold starts
|
||||
</span>
|
||||
<span className="px-2 py-0.5 text-xs bg-surface-secondary rounded text-foreground-tertiary">
|
||||
Unlimited runtime
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Icon
|
||||
icon="chevronRight"
|
||||
className="w-5 h-5 text-foreground-tertiary group-hover:text-primary transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
{/* Vercel Card */}
|
||||
<Link
|
||||
href="/docs/executors/vercel"
|
||||
className="group p-6 bg-surface border border-border rounded-lg hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-12 h-12 bg-black rounded-lg flex items-center justify-center">
|
||||
<svg
|
||||
className="w-6 h-6 text-white"
|
||||
viewBox="0 0 76 65"
|
||||
fill="currentColor"
|
||||
aria-label="Vercel logo"
|
||||
>
|
||||
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-foreground group-hover:text-primary transition-colors">
|
||||
Vercel
|
||||
</h3>
|
||||
<p className="text-sm text-foreground-secondary mt-1">
|
||||
Serverless execution with VM-level isolation using Vercel Sandbox. One-click
|
||||
deploy.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2 mt-3">
|
||||
<span className="px-2 py-0.5 text-xs bg-surface-secondary rounded text-foreground-tertiary">
|
||||
One-click deploy
|
||||
</span>
|
||||
<span className="px-2 py-0.5 text-xs bg-surface-secondary rounded text-foreground-tertiary">
|
||||
Free tier available
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Icon
|
||||
icon="chevronRight"
|
||||
className="w-5 h-5 text-foreground-tertiary group-hover:text-primary transition-colors"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<p className="text-sm text-foreground-tertiary mt-4">
|
||||
You can also build your own executor on any platform that runs Node.js. Just implement
|
||||
the API specification below.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Comparison Table */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Platform Comparison</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-border">
|
||||
<th className="text-left py-3 pr-4 font-medium text-foreground">Feature</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-foreground">Unsandbox</th>
|
||||
<th className="text-left py-3 pl-4 font-medium text-foreground">Vercel</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-foreground-secondary">
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Deploy method</td>
|
||||
<td className="py-3 px-4">CLI command</td>
|
||||
<td className="py-3 pl-4">One-click button</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Isolation</td>
|
||||
<td className="py-3 px-4">Container-level</td>
|
||||
<td className="py-3 pl-4">VM-level (Sandbox)</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Cold starts</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-success">None (always-on)</span>
|
||||
</td>
|
||||
<td className="py-3 pl-4">Yes (serverless)</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Max runtime</td>
|
||||
<td className="py-3 px-4">
|
||||
<span className="text-success">Unlimited</span>
|
||||
</td>
|
||||
<td className="py-3 pl-4">45min (Hobby) / 5hr (Pro)</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Pricing</td>
|
||||
<td className="py-3 px-4">Per uptime</td>
|
||||
<td className="py-3 pl-4">Per compute time</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Custom domains</td>
|
||||
<td className="py-3 px-4">Yes</td>
|
||||
<td className="py-3 pl-4">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 pr-4">Freeze/unfreeze</td>
|
||||
<td className="py-3 px-4">Yes (save costs)</td>
|
||||
<td className="py-3 pl-4">N/A (serverless)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Configuration Section */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Configuration</h2>
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">
|
||||
Connecting to Your Executor
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Once you have your executor deployed, configure your collections or agents to use it:
|
||||
Once deployed, configure your collections or agents to use your executor:
|
||||
</p>
|
||||
<ol className="list-decimal list-inside text-foreground-secondary space-y-3 mb-6">
|
||||
<li>Go to your collection or agent settings</li>
|
||||
<li>
|
||||
In the "Executor Configuration" section, select "Custom
|
||||
Executor"
|
||||
</li>
|
||||
<li>In "Executor Configuration", select "Custom Executor"</li>
|
||||
<li>
|
||||
Enter your executor URL (e.g.,{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded">
|
||||
https://tpmjs-executor.vercel.app
|
||||
https://my-executor.on.unsandbox.com
|
||||
</code>
|
||||
)
|
||||
</li>
|
||||
<li>Optionally add an API key if your executor requires authentication</li>
|
||||
<li>Click "Verify Connection" to test the configuration</li>
|
||||
<li>Add your API key if authentication is enabled</li>
|
||||
<li>Click "Verify Connection" to test</li>
|
||||
</ol>
|
||||
<div className="p-4 bg-warning/10 border border-warning/30 rounded-lg">
|
||||
<p className="text-sm text-warning">
|
||||
<strong>Security tip:</strong> Set the{' '}
|
||||
<code className="px-1 bg-warning/20 rounded">EXECUTOR_API_KEY</code> environment
|
||||
variable in your Vercel project to require authentication for all requests.
|
||||
<strong>Security:</strong> Always set{' '}
|
||||
<code className="px-1 bg-warning/20 rounded">EXECUTOR_API_KEY</code> to require
|
||||
authentication. Without it, anyone can execute tools on your executor.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -188,7 +295,10 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
<h2 className="text-2xl font-semibold text-foreground mb-4">
|
||||
Executor API Specification
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-6">All executors must implement this API:</p>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
All executors must implement these endpoints. Use this spec if building a custom
|
||||
executor.
|
||||
</p>
|
||||
|
||||
{/* POST /execute-tool */}
|
||||
<div className="mb-8">
|
||||
|
|
@ -197,7 +307,9 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
/execute-tool
|
||||
</h3>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Execute a TPMJS tool with the provided parameters.
|
||||
Execute a TPMJS tool. The executor should install the npm package, find the named
|
||||
export, and call its{' '}
|
||||
<code className="px-1 bg-surface rounded">execute(params)</code> function.
|
||||
</p>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
|
|
@ -217,22 +329,33 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
<code className="px-2 py-1 bg-success/10 text-success rounded">GET</code> /health
|
||||
</h3>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Check executor health status. Used by TPMJS to verify the executor is reachable.
|
||||
Health check endpoint. TPMJS uses this to verify the executor is reachable and
|
||||
working.
|
||||
</p>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-foreground mb-2">Response:</p>
|
||||
<CodeBlock language="json" code={healthExample} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
<strong>Note:</strong> Both{' '}
|
||||
<code className="px-1 bg-surface-secondary rounded">/api/health</code> and{' '}
|
||||
<code className="px-1 bg-surface-secondary rounded">/health</code> paths should work
|
||||
(same for <code className="px-1 bg-surface-secondary rounded">/execute-tool</code>).
|
||||
Our templates support both.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Cascade Section */}
|
||||
{/* Executor Cascade */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Executor Cascade</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Executor configuration follows a cascade resolution order:
|
||||
When a tool is executed, TPMJS resolves which executor to use in this order:
|
||||
</p>
|
||||
<div className="flex items-center gap-2 text-foreground-secondary mb-4">
|
||||
<div className="flex items-center gap-2 text-foreground-secondary mb-4 flex-wrap">
|
||||
<span className="px-3 py-1 bg-primary/10 text-primary rounded-full text-sm font-medium">
|
||||
Agent Config
|
||||
</span>
|
||||
|
|
@ -255,35 +378,47 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
</ul>
|
||||
</section>
|
||||
|
||||
{/* FAQ Section */}
|
||||
{/* FAQ */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">FAQ</h2>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground mb-2">Can I use any cloud provider?</h3>
|
||||
<h3 className="font-medium text-foreground mb-2">
|
||||
Which platform should I choose?
|
||||
</h3>
|
||||
<p className="text-foreground-secondary text-sm">
|
||||
Yes! While we provide a Vercel template, you can deploy an executor anywhere that
|
||||
can run Node.js and expose an HTTP endpoint. The executor just needs to implement
|
||||
the API specification above.
|
||||
<strong>Unsandbox</strong> is recommended for most use cases. It has no cold
|
||||
starts, unlimited runtime, and simple CLI deployment. Use <strong>Vercel</strong>{' '}
|
||||
if you're already on Vercel or prefer one-click deployment and pay-per-use
|
||||
pricing.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground mb-2">What about timeouts?</h3>
|
||||
<h3 className="font-medium text-foreground mb-2">Can I use other platforms?</h3>
|
||||
<p className="text-foreground-secondary text-sm">
|
||||
The default timeout for tool execution is 30 seconds. On Vercel's free tier,
|
||||
you get up to 10 seconds per request. For longer-running tools, consider deploying
|
||||
to a platform with higher timeout limits.
|
||||
Yes! Any platform that runs Node.js and exposes HTTP endpoints works. AWS Lambda,
|
||||
Google Cloud Run, Railway, Render, Fly.io—just implement the API specification
|
||||
above.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground mb-2">How do tools get loaded?</h3>
|
||||
<p className="text-foreground-secondary text-sm">
|
||||
Tools are dynamically imported from{' '}
|
||||
<Link href="https://esm.sh" className="text-primary hover:underline">
|
||||
esm.sh
|
||||
</Link>
|
||||
, a CDN for npm packages. The executor fetches the package, finds the tool export,
|
||||
and calls its <code className="px-1 bg-surface rounded">execute()</code> function.
|
||||
The executor runs <code className="px-1 bg-surface rounded">npm install</code> for
|
||||
the requested package, then dynamically imports it and calls the tool's{' '}
|
||||
<code className="px-1 bg-surface rounded">execute()</code> function. Each
|
||||
execution uses a fresh temporary directory.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium text-foreground mb-2">
|
||||
Are environment variables secure?
|
||||
</h3>
|
||||
<p className="text-foreground-secondary text-sm">
|
||||
Yes. Environment variables are stored encrypted by the platform (Vercel/Unsandbox)
|
||||
and only available during execution. You can also pass per-request environment
|
||||
variables in the <code className="px-1 bg-surface rounded">env</code> field of the
|
||||
execute-tool request.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -302,16 +437,22 @@ export default function ExecutorsDocsPage(): React.ReactElement {
|
|||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Button variant="secondary" size="sm">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md bg-surface-secondary hover:bg-surface-tertiary text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="github" className="w-4 h-4 mr-2" />
|
||||
Open an Issue
|
||||
</Button>
|
||||
</button>
|
||||
</a>
|
||||
<a href="https://discord.gg/tpmjs" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="ghost" size="sm">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md hover:bg-surface text-foreground-secondary transition-colors"
|
||||
>
|
||||
<Icon icon="discord" className="w-4 h-4 mr-2" />
|
||||
Join Discord
|
||||
</Button>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
420
apps/web/src/app/docs/executors/unsandbox/page.tsx
Normal file
420
apps/web/src/app/docs/executors/unsandbox/page.tsx
Normal file
|
|
@ -0,0 +1,420 @@
|
|||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { AppFooter } from '~/components/AppFooter';
|
||||
import { AppHeader } from '~/components/AppHeader';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Deploy to Unsandbox - Custom Executors - TPMJS',
|
||||
description:
|
||||
'Deploy a TPMJS executor to Unsandbox with one CLI command. Always-on, no cold starts, unlimited runtime.',
|
||||
};
|
||||
|
||||
const deployCommand = `# Install the Unsandbox CLI
|
||||
curl -fsSL https://unsandbox.com/install.sh | bash
|
||||
|
||||
# Deploy the TPMJS executor
|
||||
un service --name tpmjs-executor --ports 80 -n semitrusted \\
|
||||
--bootstrap "curl -fsSL https://raw.githubusercontent.com/tpmjs/tpmjs/main/templates/unsandbox-executor/bootstrap.sh | bash"`;
|
||||
|
||||
const deployWithApiKey = `un service --name tpmjs-executor --ports 80 -n semitrusted \\
|
||||
-e EXECUTOR_API_KEY=your-secure-random-key \\
|
||||
--bootstrap "curl -fsSL https://raw.githubusercontent.com/tpmjs/tpmjs/main/templates/unsandbox-executor/bootstrap.sh | bash"`;
|
||||
|
||||
const deployWithEnvVars = `un service --name tpmjs-executor --ports 80 -n semitrusted \\
|
||||
-e EXECUTOR_API_KEY=your-key \\
|
||||
-e OPENAI_API_KEY=sk-xxx \\
|
||||
-e DATABASE_URL=postgres://... \\
|
||||
--bootstrap "curl -fsSL https://raw.githubusercontent.com/tpmjs/tpmjs/main/templates/unsandbox-executor/bootstrap.sh | bash"`;
|
||||
|
||||
const deployWithEnvFile = `# Create .env file with your secrets
|
||||
cat > .env << EOF
|
||||
EXECUTOR_API_KEY=your-key
|
||||
OPENAI_API_KEY=sk-xxx
|
||||
DATABASE_URL=postgres://...
|
||||
EOF
|
||||
|
||||
# Deploy with env file
|
||||
un service --name tpmjs-executor --ports 80 -n semitrusted \\
|
||||
--env-file .env \\
|
||||
--bootstrap "curl -fsSL https://raw.githubusercontent.com/tpmjs/tpmjs/main/templates/unsandbox-executor/bootstrap.sh | bash"`;
|
||||
|
||||
const healthCheck = `curl https://tpmjs-executor.on.unsandbox.com/api/health`;
|
||||
|
||||
const healthResponse = `{
|
||||
"status": "ok",
|
||||
"version": "1.0.0",
|
||||
"info": {
|
||||
"runtime": "unsandbox",
|
||||
"timestamp": "2024-01-01T00:00:00.000Z"
|
||||
}
|
||||
}`;
|
||||
|
||||
const executeExample = `curl -X POST https://tpmjs-executor.on.unsandbox.com/api/execute-tool \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "Authorization: Bearer your-api-key" \\
|
||||
-d '{
|
||||
"packageName": "@tpmjs/hello",
|
||||
"name": "helloWorldTool",
|
||||
"version": "latest",
|
||||
"params": { "includeTimestamp": true }
|
||||
}'`;
|
||||
|
||||
const localDev = `# Clone the repository
|
||||
git clone https://github.com/tpmjs/tpmjs.git
|
||||
cd tpmjs/templates/unsandbox-executor
|
||||
|
||||
# Run locally
|
||||
PORT=3000 node executor.js
|
||||
|
||||
# Test health endpoint
|
||||
curl http://localhost:3000/api/health`;
|
||||
|
||||
const managementCommands = `# View logs
|
||||
un service --logs tpmjs-executor
|
||||
|
||||
# Redeploy (after updating)
|
||||
un service --redeploy tpmjs-executor
|
||||
|
||||
# Freeze when not in use (save costs)
|
||||
un service --freeze tpmjs-executor
|
||||
|
||||
# Unfreeze when needed
|
||||
un service --unfreeze tpmjs-executor
|
||||
|
||||
# Scale resources (4 vCPU, 8GB RAM)
|
||||
un service --resize tpmjs-executor --vcpu 4
|
||||
|
||||
# Destroy service
|
||||
un service --destroy tpmjs-executor`;
|
||||
|
||||
const customDomain = `un service --name tpmjs-executor --ports 80 -n semitrusted \\
|
||||
--domains executor.yourdomain.com \\
|
||||
--bootstrap "curl -fsSL https://raw.githubusercontent.com/tpmjs/tpmjs/main/templates/unsandbox-executor/bootstrap.sh | bash"`;
|
||||
|
||||
export default function UnsandboxExecutorPage(): React.ReactElement {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<AppHeader />
|
||||
|
||||
<main className="flex-1">
|
||||
<div className="max-w-4xl mx-auto px-4 py-12">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-sm text-foreground-secondary mb-8">
|
||||
<Link href="/docs/executors" className="hover:text-foreground transition-colors">
|
||||
Executors
|
||||
</Link>
|
||||
<Icon icon="chevronRight" className="w-4 h-4" />
|
||||
<span className="text-foreground">Unsandbox</span>
|
||||
</nav>
|
||||
|
||||
{/* Header */}
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center gap-4 mb-4">
|
||||
<div className="w-12 h-12 bg-gradient-to-br from-orange-500 to-red-600 rounded-lg flex items-center justify-center text-white font-bold text-lg">
|
||||
un
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-foreground">Deploy to Unsandbox</h1>
|
||||
<p className="text-foreground-secondary">
|
||||
Always-on execution with one CLI command
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Why Unsandbox */}
|
||||
<section className="mb-12">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">0ms</div>
|
||||
<div className="text-sm text-foreground-secondary">No cold starts</div>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">∞</div>
|
||||
<div className="text-sm text-foreground-secondary">Unlimited runtime</div>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">1 cmd</div>
|
||||
<div className="text-sm text-foreground-secondary">Deploy in seconds</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Quick Deploy */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Quick Deploy</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Deploy a TPMJS executor with a single command. Your executor will be live at{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded">
|
||||
https://tpmjs-executor.on.unsandbox.com
|
||||
</code>
|
||||
</p>
|
||||
<CodeBlock language="bash" code={deployCommand} />
|
||||
<p className="text-sm text-foreground-tertiary mt-4">
|
||||
This creates an always-on service that runs the executor. HTTPS is automatically
|
||||
configured.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Test Your Deployment */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Test Your Deployment</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Verify your executor is running with a health check:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={healthCheck} />
|
||||
<p className="text-sm text-foreground-secondary mt-4 mb-2">Expected response:</p>
|
||||
<CodeBlock language="json" code={healthResponse} />
|
||||
</section>
|
||||
|
||||
{/* Authentication */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Add Authentication</h2>
|
||||
<div className="p-4 bg-warning/10 border border-warning/30 rounded-lg mb-4">
|
||||
<p className="text-sm text-warning">
|
||||
<strong>Important:</strong> Without an API key, anyone can execute tools on your
|
||||
executor. Always set{' '}
|
||||
<code className="px-1 bg-warning/20 rounded">EXECUTOR_API_KEY</code> in production.
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Deploy with an API key to require authentication:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={deployWithApiKey} />
|
||||
<p className="text-sm text-foreground-tertiary mt-4">
|
||||
When configured, requests must include{' '}
|
||||
<code className="px-1 bg-surface rounded">Authorization: Bearer your-api-key</code>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Environment Variables */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Environment Variables</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Pass environment variables that your tools need. These are available during tool
|
||||
execution.
|
||||
</p>
|
||||
|
||||
<h3 className="text-lg font-medium text-foreground mb-3">Inline Variables</h3>
|
||||
<CodeBlock language="bash" code={deployWithEnvVars} />
|
||||
|
||||
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">Using an Env File</h3>
|
||||
<CodeBlock language="bash" code={deployWithEnvFile} />
|
||||
|
||||
<div className="p-4 bg-surface border border-border rounded-lg mt-4">
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
All environment variables are stored encrypted and only available to your executor.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Execute a Tool */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Execute a Tool</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Test tool execution with a curl request:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={executeExample} />
|
||||
</section>
|
||||
|
||||
{/* Local Development */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Local Development</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Run the executor locally for testing and development:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={localDev} />
|
||||
</section>
|
||||
|
||||
{/* Management Commands */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Managing Your Service</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Unsandbox provides commands to manage your executor:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={managementCommands} />
|
||||
|
||||
<h3 className="text-lg font-medium text-foreground mt-6 mb-3">Cost Optimization</h3>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Freeze your executor when not in use to stop billing:
|
||||
</p>
|
||||
<ul className="text-foreground-secondary text-sm space-y-2">
|
||||
<li>
|
||||
• <code className="px-1 bg-surface rounded">un service --freeze</code> stops the
|
||||
service and billing
|
||||
</li>
|
||||
<li>
|
||||
• <code className="px-1 bg-surface rounded">un service --unfreeze</code> restarts it
|
||||
when needed
|
||||
</li>
|
||||
<li>• Configure auto-unfreeze to wake on HTTP request (incurs cold start)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Custom Domains */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Custom Domains</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Use your own domain instead of the default{' '}
|
||||
<code className="px-1 bg-surface rounded">*.on.unsandbox.com</code>:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={customDomain} />
|
||||
<p className="text-foreground-secondary text-sm mt-4">
|
||||
After deploying, add a CNAME record pointing{' '}
|
||||
<code className="px-1 bg-surface rounded">executor.yourdomain.com</code> to your
|
||||
Unsandbox service domain.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* How It Works */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">How It Works</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
The Unsandbox executor runs as an always-on HTTP server:
|
||||
</p>
|
||||
<ol className="text-foreground-secondary space-y-3">
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
1
|
||||
</span>
|
||||
<span>
|
||||
Receives tool execution request via HTTP POST to{' '}
|
||||
<code className="px-1 bg-surface rounded">/api/execute-tool</code>
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
2
|
||||
</span>
|
||||
<span>Creates an isolated temporary directory for the execution</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
3
|
||||
</span>
|
||||
<span>
|
||||
Installs the npm package using{' '}
|
||||
<code className="px-1 bg-surface rounded">npm install</code>
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
4
|
||||
</span>
|
||||
<span>
|
||||
Loads the tool and calls its{' '}
|
||||
<code className="px-1 bg-surface rounded">execute()</code> function
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
5
|
||||
</span>
|
||||
<span>Returns the result and cleans up the temporary directory</span>
|
||||
</li>
|
||||
</ol>
|
||||
<p className="text-foreground-secondary text-sm mt-4">
|
||||
Since Unsandbox containers are already isolated, no additional sandbox layer is
|
||||
needed. Network access is controlled by Unsandbox's semitrusted mode.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Security */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Security</h2>
|
||||
<ul className="text-foreground-secondary space-y-2">
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>
|
||||
Set <code className="px-1 bg-surface rounded">EXECUTOR_API_KEY</code> to require
|
||||
authentication
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Tools run in isolated Unsandbox containers</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Each execution uses a fresh temporary directory</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Network controlled by semitrusted mode</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Environment variables stored encrypted</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Pricing */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Pricing</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Unsandbox services are billed based on uptime. See{' '}
|
||||
<a
|
||||
href="https://unsandbox.com/pricing"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
Unsandbox Pricing
|
||||
</a>{' '}
|
||||
for current rates.
|
||||
</p>
|
||||
<ul className="text-foreground-secondary text-sm space-y-2">
|
||||
<li>
|
||||
• HTTPS included via{' '}
|
||||
<code className="px-1 bg-surface rounded">*.on.unsandbox.com</code>
|
||||
</li>
|
||||
<li>• Freeze when not in use to pause billing</li>
|
||||
<li>• Scale vCPU and RAM as needed</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Connect to TPMJS */}
|
||||
<section className="mb-12 p-6 bg-primary/5 border border-primary/20 rounded-lg">
|
||||
<h2 className="text-lg font-semibold text-foreground mb-4">Connect to TPMJS</h2>
|
||||
<ol className="text-foreground-secondary space-y-2">
|
||||
<li>1. Go to your collection or agent settings on TPMJS</li>
|
||||
<li>2. Select "Custom Executor" in Executor Configuration</li>
|
||||
<li>
|
||||
3. Enter URL:{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded">
|
||||
https://tpmjs-executor.on.unsandbox.com
|
||||
</code>
|
||||
</li>
|
||||
<li>4. Enter your API key (if configured)</li>
|
||||
<li>5. Click "Verify Connection"</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex items-center justify-between pt-8 border-t border-border">
|
||||
<Link
|
||||
href="/docs/executors"
|
||||
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="chevronLeft" className="w-4 h-4" />
|
||||
<span>Back to Executors</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs/executors/vercel"
|
||||
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
>
|
||||
<span>Vercel Guide</span>
|
||||
<Icon icon="chevronRight" className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<AppFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
426
apps/web/src/app/docs/executors/vercel/page.tsx
Normal file
426
apps/web/src/app/docs/executors/vercel/page.tsx
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
import { Button } from '@tpmjs/ui/Button/Button';
|
||||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import type { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
|
||||
import { AppFooter } from '~/components/AppFooter';
|
||||
import { AppHeader } from '~/components/AppHeader';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Deploy to Vercel - Custom Executors - TPMJS',
|
||||
description:
|
||||
'Deploy a TPMJS executor to Vercel with one click. VM-level isolation using Vercel Sandbox.',
|
||||
};
|
||||
|
||||
const healthCheck = `curl https://your-executor.vercel.app/api/health`;
|
||||
|
||||
const healthResponse = `{
|
||||
"status": "ok",
|
||||
"version": "1.0.0",
|
||||
"info": {
|
||||
"runtime": "vercel-sandbox",
|
||||
"region": "iad1",
|
||||
"timestamp": "2024-01-01T00:00:00.000Z"
|
||||
}
|
||||
}`;
|
||||
|
||||
const executeExample = `curl -X POST https://your-executor.vercel.app/api/execute-tool \\
|
||||
-H "Content-Type: application/json" \\
|
||||
-H "Authorization: Bearer your-api-key" \\
|
||||
-d '{
|
||||
"packageName": "@tpmjs/hello",
|
||||
"name": "helloWorld",
|
||||
"version": "latest",
|
||||
"params": { "name": "World" }
|
||||
}'`;
|
||||
|
||||
const localDev = `# Clone and install
|
||||
git clone https://github.com/tpmjs/tpmjs.git
|
||||
cd tpmjs/templates/vercel-executor
|
||||
npm install
|
||||
|
||||
# Login to Vercel (required for sandbox)
|
||||
vercel login
|
||||
vercel link
|
||||
|
||||
# Pull environment variables
|
||||
vercel env pull
|
||||
|
||||
# Run development server
|
||||
npm run dev
|
||||
|
||||
# Test health endpoint
|
||||
curl http://localhost:3000/api/health`;
|
||||
|
||||
export default function VercelExecutorPage(): React.ReactElement {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<AppHeader />
|
||||
|
||||
<main className="flex-1">
|
||||
<div className="max-w-4xl mx-auto px-4 py-12">
|
||||
{/* Breadcrumb */}
|
||||
<nav className="flex items-center gap-2 text-sm text-foreground-secondary mb-8">
|
||||
<Link href="/docs/executors" className="hover:text-foreground transition-colors">
|
||||
Executors
|
||||
</Link>
|
||||
<Icon icon="chevronRight" className="w-4 h-4" />
|
||||
<span className="text-foreground">Vercel</span>
|
||||
</nav>
|
||||
|
||||
{/* Header */}
|
||||
<div className="mb-12">
|
||||
<div className="flex items-center gap-4 mb-4">
|
||||
<div className="w-12 h-12 bg-black rounded-lg flex items-center justify-center">
|
||||
<svg
|
||||
className="w-6 h-6 text-white"
|
||||
viewBox="0 0 76 65"
|
||||
fill="currentColor"
|
||||
aria-label="Vercel logo"
|
||||
>
|
||||
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-foreground">Deploy to Vercel</h1>
|
||||
<p className="text-foreground-secondary">
|
||||
One-click deploy with VM-level isolation
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Why Vercel */}
|
||||
<section className="mb-12">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">1-click</div>
|
||||
<div className="text-sm text-foreground-secondary">Deploy instantly</div>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">VM</div>
|
||||
<div className="text-sm text-foreground-secondary">Sandbox isolation</div>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg">
|
||||
<div className="text-2xl mb-2">Free</div>
|
||||
<div className="text-sm text-foreground-secondary">Hobby tier available</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* One-Click Deploy */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">One-Click Deploy</h2>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
Deploy the TPMJS executor template to your Vercel account:
|
||||
</p>
|
||||
<a
|
||||
href="https://vercel.com/new/clone?repository-url=https://github.com/tpmjs/tpmjs/tree/main/templates/vercel-executor&project-name=tpmjs-executor&repository-name=tpmjs-executor"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Button size="lg">
|
||||
<svg
|
||||
className="w-4 h-4 mr-2"
|
||||
viewBox="0 0 76 65"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M37.5274 0L75.0548 65H0L37.5274 0Z" />
|
||||
</svg>
|
||||
Deploy with Vercel
|
||||
</Button>
|
||||
</a>
|
||||
<p className="text-sm text-foreground-tertiary mt-4">
|
||||
After deployment, your executor will be available at{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded">
|
||||
https://tpmjs-executor.vercel.app
|
||||
</code>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Test Your Deployment */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Test Your Deployment</h2>
|
||||
<p className="text-foreground-secondary mb-4">Verify your executor is running:</p>
|
||||
<CodeBlock language="bash" code={healthCheck} />
|
||||
<p className="text-sm text-foreground-secondary mt-4 mb-2">Expected response:</p>
|
||||
<CodeBlock language="json" code={healthResponse} />
|
||||
</section>
|
||||
|
||||
{/* Authentication */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Add Authentication</h2>
|
||||
<div className="p-4 bg-warning/10 border border-warning/30 rounded-lg mb-4">
|
||||
<p className="text-sm text-warning">
|
||||
<strong>Important:</strong> Without an API key, anyone can execute tools on your
|
||||
executor. Always set{' '}
|
||||
<code className="px-1 bg-warning/20 rounded">EXECUTOR_API_KEY</code> in production.
|
||||
</p>
|
||||
</div>
|
||||
<ol className="text-foreground-secondary space-y-3">
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-surface-secondary text-foreground-secondary text-sm flex items-center justify-center">
|
||||
1
|
||||
</span>
|
||||
<span>Go to your Vercel project settings</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-surface-secondary text-foreground-secondary text-sm flex items-center justify-center">
|
||||
2
|
||||
</span>
|
||||
<span>Navigate to Environment Variables</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-surface-secondary text-foreground-secondary text-sm flex items-center justify-center">
|
||||
3
|
||||
</span>
|
||||
<span>
|
||||
Add <code className="px-1 bg-surface rounded">EXECUTOR_API_KEY</code> with a
|
||||
secure random value
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-surface-secondary text-foreground-secondary text-sm flex items-center justify-center">
|
||||
4
|
||||
</span>
|
||||
<span>Redeploy your project to apply the changes</span>
|
||||
</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
{/* Environment Variables */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Environment Variables</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Add custom environment variables for your tools in Vercel project settings:
|
||||
</p>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-border">
|
||||
<th className="text-left py-3 pr-4 font-medium text-foreground">Variable</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-foreground">Required</th>
|
||||
<th className="text-left py-3 pl-4 font-medium text-foreground">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-foreground-secondary">
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">
|
||||
<code className="px-1 bg-surface rounded">EXECUTOR_API_KEY</code>
|
||||
</td>
|
||||
<td className="py-3 px-4">No*</td>
|
||||
<td className="py-3 pl-4">
|
||||
API key for authentication. Required for production.
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">
|
||||
<code className="px-1 bg-surface rounded">OPENAI_API_KEY</code>
|
||||
</td>
|
||||
<td className="py-3 px-4">No</td>
|
||||
<td className="py-3 pl-4">Example: Pass through to tools that need OpenAI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 pr-4">
|
||||
<code className="px-1 bg-surface rounded">DATABASE_URL</code>
|
||||
</td>
|
||||
<td className="py-3 px-4">No</td>
|
||||
<td className="py-3 pl-4">Example: Pass through to tools that need database</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-tertiary mt-4">
|
||||
* Strongly recommended for production deployments
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Execute a Tool */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Execute a Tool</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Test tool execution with a curl request:
|
||||
</p>
|
||||
<CodeBlock language="bash" code={executeExample} />
|
||||
</section>
|
||||
|
||||
{/* Local Development */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Local Development</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Run the executor locally for testing. Note: Vercel Sandbox requires authentication
|
||||
even in development.
|
||||
</p>
|
||||
<CodeBlock language="bash" code={localDev} />
|
||||
<div className="p-4 bg-surface border border-border rounded-lg mt-4">
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
<strong>Note:</strong> You must run{' '}
|
||||
<code className="px-1 bg-surface-secondary rounded">vercel login</code> and{' '}
|
||||
<code className="px-1 bg-surface-secondary rounded">vercel link</code> before local
|
||||
development. Vercel Sandbox requires authentication to create VMs.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* How It Works */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">How It Works</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
The Vercel executor uses{' '}
|
||||
<a
|
||||
href="https://vercel.com/docs/vercel-sandbox"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
Vercel Sandbox
|
||||
</a>{' '}
|
||||
for isolated execution:
|
||||
</p>
|
||||
<ol className="text-foreground-secondary space-y-3">
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
1
|
||||
</span>
|
||||
<span>Creates an isolated VM for each tool execution</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
2
|
||||
</span>
|
||||
<span>Installs the npm package in the sandbox</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
3
|
||||
</span>
|
||||
<span>Executes the tool with your parameters</span>
|
||||
</li>
|
||||
<li className="flex gap-3">
|
||||
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-primary/10 text-primary text-sm flex items-center justify-center">
|
||||
4
|
||||
</span>
|
||||
<span>Returns the result and destroys the sandbox</span>
|
||||
</li>
|
||||
</ol>
|
||||
<p className="text-foreground-secondary text-sm mt-4">
|
||||
This provides VM-level isolation without the limitations of Node.js serverless
|
||||
functions.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Security */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Security</h2>
|
||||
<ul className="text-foreground-secondary space-y-2">
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>
|
||||
Set <code className="px-1 bg-surface rounded">EXECUTOR_API_KEY</code> to require
|
||||
authentication
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Tools run in isolated VMs with no access to your Vercel project</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Each execution gets a fresh sandbox instance</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-2">
|
||||
<Icon icon="check" className="w-5 h-5 text-success flex-shrink-0 mt-0.5" />
|
||||
<span>Sandboxes are destroyed after execution completes</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Pricing & Limits */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-2xl font-semibold text-foreground mb-4">Pricing & Limits</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
Vercel Sandbox usage is billed based on compute time. See{' '}
|
||||
<a
|
||||
href="https://vercel.com/docs/vercel-sandbox/pricing"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
>
|
||||
Vercel Sandbox Pricing
|
||||
</a>{' '}
|
||||
for current rates.
|
||||
</p>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-border">
|
||||
<th className="text-left py-3 pr-4 font-medium text-foreground">Plan</th>
|
||||
<th className="text-left py-3 px-4 font-medium text-foreground">Max Runtime</th>
|
||||
<th className="text-left py-3 pl-4 font-medium text-foreground">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-foreground-secondary">
|
||||
<tr className="border-b border-border/50">
|
||||
<td className="py-3 pr-4">Hobby</td>
|
||||
<td className="py-3 px-4">45 minutes</td>
|
||||
<td className="py-3 pl-4">Free tier</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="py-3 pr-4">Pro</td>
|
||||
<td className="py-3 px-4">5 hours</td>
|
||||
<td className="py-3 pl-4">For longer-running tools</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 bg-surface border border-border rounded-lg mt-4">
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
<strong>Region:</strong> Vercel Sandbox is currently only available in{' '}
|
||||
<code className="px-1 bg-surface-secondary rounded">iad1</code> (US East).
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Connect to TPMJS */}
|
||||
<section className="mb-12 p-6 bg-primary/5 border border-primary/20 rounded-lg">
|
||||
<h2 className="text-lg font-semibold text-foreground mb-4">Connect to TPMJS</h2>
|
||||
<ol className="text-foreground-secondary space-y-2">
|
||||
<li>1. Go to your collection or agent settings on TPMJS</li>
|
||||
<li>2. Select "Custom Executor" in Executor Configuration</li>
|
||||
<li>
|
||||
3. Enter URL:{' '}
|
||||
<code className="px-1.5 py-0.5 bg-surface rounded">
|
||||
https://tpmjs-executor.vercel.app
|
||||
</code>
|
||||
</li>
|
||||
<li>4. Enter your API key (if configured)</li>
|
||||
<li>5. Click "Verify Connection"</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
{/* Navigation */}
|
||||
<div className="flex items-center justify-between pt-8 border-t border-border">
|
||||
<Link
|
||||
href="/docs/executors/unsandbox"
|
||||
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="chevronLeft" className="w-4 h-4" />
|
||||
<span>Unsandbox Guide</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/docs/executors"
|
||||
className="flex items-center gap-2 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
>
|
||||
<span>Back to Executors</span>
|
||||
<Icon icon="chevronRight" className="w-4 h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<AppFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue