mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-20 18:11:27 -07:00
update skills
This commit is contained in:
240
.agents/skills/cloudflare-deploy/references/turnstile/api.md
Normal file
240
.agents/skills/cloudflare-deploy/references/turnstile/api.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# API Reference
|
||||
|
||||
## Client-Side JavaScript API
|
||||
|
||||
The Turnstile JavaScript API is available at `window.turnstile` after loading the script.
|
||||
|
||||
### `turnstile.render(container, options)`
|
||||
|
||||
Renders a Turnstile widget into a container element.
|
||||
|
||||
**Parameters:**
|
||||
- `container` (string | HTMLElement): CSS selector or DOM element
|
||||
- `options` (TurnstileOptions): Configuration object (see [configuration.md](configuration.md))
|
||||
|
||||
**Returns:** `string` - Widget ID for use with other API methods
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
const widgetId = window.turnstile.render('#my-container', {
|
||||
sitekey: 'YOUR_SITE_KEY',
|
||||
callback: (token) => console.log('Success:', token),
|
||||
'error-callback': (code) => console.error('Error:', code)
|
||||
});
|
||||
```
|
||||
|
||||
### `turnstile.reset(widgetId)`
|
||||
|
||||
Resets a widget (clears token, resets challenge state). Useful when form validation fails.
|
||||
|
||||
**Parameters:**
|
||||
- `widgetId` (string): Widget ID from `render()`, or container element
|
||||
|
||||
**Returns:** `void`
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Reset on form error
|
||||
if (!validateForm()) {
|
||||
window.turnstile.reset(widgetId);
|
||||
}
|
||||
```
|
||||
|
||||
### `turnstile.remove(widgetId)`
|
||||
|
||||
Removes a widget from the DOM completely.
|
||||
|
||||
**Parameters:**
|
||||
- `widgetId` (string): Widget ID from `render()`
|
||||
|
||||
**Returns:** `void`
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Cleanup on navigation
|
||||
window.turnstile.remove(widgetId);
|
||||
```
|
||||
|
||||
### `turnstile.getResponse(widgetId)`
|
||||
|
||||
Gets the current token from a widget (if challenge completed).
|
||||
|
||||
**Parameters:**
|
||||
- `widgetId` (string): Widget ID from `render()`, or container element
|
||||
|
||||
**Returns:** `string | undefined` - Token string, or undefined if not ready
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
const token = window.turnstile.getResponse(widgetId);
|
||||
if (token) {
|
||||
submitForm(token);
|
||||
}
|
||||
```
|
||||
|
||||
### `turnstile.isExpired(widgetId)`
|
||||
|
||||
Checks if a widget's token has expired (>5 minutes old).
|
||||
|
||||
**Parameters:**
|
||||
- `widgetId` (string): Widget ID from `render()`
|
||||
|
||||
**Returns:** `boolean` - True if expired
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
if (window.turnstile.isExpired(widgetId)) {
|
||||
window.turnstile.reset(widgetId);
|
||||
}
|
||||
```
|
||||
|
||||
## Callback Signatures
|
||||
|
||||
```typescript
|
||||
type TurnstileCallback = (token: string) => void;
|
||||
type ErrorCallback = (errorCode: string) => void;
|
||||
type TimeoutCallback = () => void;
|
||||
type ExpiredCallback = () => void;
|
||||
type BeforeInteractiveCallback = () => void;
|
||||
type AfterInteractiveCallback = () => void;
|
||||
type UnsupportedCallback = () => void;
|
||||
```
|
||||
|
||||
## Siteverify API (Server-Side)
|
||||
|
||||
**Endpoint:** `https://challenges.cloudflare.com/turnstile/v0/siteverify`
|
||||
|
||||
### Request
|
||||
|
||||
**Method:** POST
|
||||
**Content-Type:** `application/json` or `application/x-www-form-urlencoded`
|
||||
|
||||
```typescript
|
||||
interface SiteverifyRequest {
|
||||
secret: string; // Your secret key (never expose client-side)
|
||||
response: string; // Token from cf-turnstile-response
|
||||
remoteip?: string; // User's IP (optional but recommended)
|
||||
idempotency_key?: string; // Unique key for idempotent validation
|
||||
}
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```javascript
|
||||
// Cloudflare Workers
|
||||
const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
secret: env.TURNSTILE_SECRET,
|
||||
response: token,
|
||||
remoteip: request.headers.get('CF-Connecting-IP')
|
||||
})
|
||||
});
|
||||
const data = await result.json();
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```typescript
|
||||
interface SiteverifyResponse {
|
||||
success: boolean; // Validation result
|
||||
challenge_ts?: string; // ISO timestamp of challenge
|
||||
hostname?: string; // Hostname where widget was solved
|
||||
'error-codes'?: string[]; // Error codes if success=false
|
||||
action?: string; // Action name from widget config
|
||||
cdata?: string; // Custom data from widget config
|
||||
}
|
||||
```
|
||||
|
||||
**Example Success:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"challenge_ts": "2024-01-15T10:30:00Z",
|
||||
"hostname": "example.com",
|
||||
"action": "login",
|
||||
"cdata": "user123"
|
||||
}
|
||||
```
|
||||
|
||||
**Example Failure:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error-codes": ["timeout-or-duplicate"]
|
||||
}
|
||||
```
|
||||
|
||||
## Error Codes
|
||||
|
||||
| Code | Cause | Solution |
|
||||
|------|-------|----------|
|
||||
| `missing-input-secret` | Secret key not provided | Include `secret` in request |
|
||||
| `invalid-input-secret` | Secret key is wrong | Check secret key in dashboard |
|
||||
| `missing-input-response` | Token not provided | Include `response` token |
|
||||
| `invalid-input-response` | Token is invalid/malformed | Verify token from widget |
|
||||
| `timeout-or-duplicate` | Token expired (>5min) or reused | Generate new token, validate once |
|
||||
| `internal-error` | Cloudflare server error | Retry with exponential backoff |
|
||||
| `bad-request` | Malformed request | Check JSON/form encoding |
|
||||
|
||||
## TypeScript Types
|
||||
|
||||
```typescript
|
||||
interface TurnstileOptions {
|
||||
sitekey: string;
|
||||
action?: string;
|
||||
cData?: string;
|
||||
callback?: (token: string) => void;
|
||||
'error-callback'?: (errorCode: string) => void;
|
||||
'expired-callback'?: () => void;
|
||||
'timeout-callback'?: () => void;
|
||||
'before-interactive-callback'?: () => void;
|
||||
'after-interactive-callback'?: () => void;
|
||||
'unsupported-callback'?: () => void;
|
||||
theme?: 'light' | 'dark' | 'auto';
|
||||
size?: 'normal' | 'compact' | 'flexible';
|
||||
tabindex?: number;
|
||||
'response-field'?: boolean;
|
||||
'response-field-name'?: string;
|
||||
retry?: 'auto' | 'never';
|
||||
'retry-interval'?: number;
|
||||
language?: string;
|
||||
execution?: 'render' | 'execute';
|
||||
appearance?: 'always' | 'execute' | 'interaction-only';
|
||||
'refresh-expired'?: 'auto' | 'manual' | 'never';
|
||||
}
|
||||
|
||||
interface Turnstile {
|
||||
render(container: string | HTMLElement, options: TurnstileOptions): string;
|
||||
reset(widgetId: string): void;
|
||||
remove(widgetId: string): void;
|
||||
getResponse(widgetId: string): string | undefined;
|
||||
isExpired(widgetId: string): boolean;
|
||||
execute(container?: string | HTMLElement, options?: TurnstileOptions): void;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
turnstile: Turnstile;
|
||||
onloadTurnstileCallback?: () => void;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Script Loading
|
||||
|
||||
```html
|
||||
<!-- Standard -->
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||
|
||||
<!-- Explicit render mode -->
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>
|
||||
|
||||
<!-- With load callback -->
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback"></script>
|
||||
<script>
|
||||
window.onloadTurnstileCallback = () => {
|
||||
window.turnstile.render('#container', { sitekey: 'YOUR_SITE_KEY' });
|
||||
};
|
||||
</script>
|
||||
```
|
||||
Reference in New Issue
Block a user