Skip to content

Commit 45dd1d4

Browse files
nullcoderclaude
andcommitted
feat: add refresh-expired and refresh-timeout attributes to Turnstile
- Add refreshExpired and refreshTimeout props with "auto" | "manual" | "never" options - Add onTimeout callback for handling interactive timeouts - Update Window interface to include timeout-callback and refresh attributes - Remove onExpire handler from create page since refreshExpired="auto" handles it - Fix test to use correct placeholder text for password input - Both refresh attributes default to "auto" for automatic handling 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b34225e commit 45dd1d4

File tree

3 files changed

+17
-10
lines changed

3 files changed

+17
-10
lines changed

app/create/page.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ describe("CreateGistPage", () => {
162162
render(<CreateGistPage />);
163163

164164
const pinInput = screen.getByPlaceholderText(
165-
"Set a PIN to protect edits"
165+
"Leave empty for no protection"
166166
);
167167
expect(pinInput).toBeInTheDocument();
168168

app/create/page.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,6 @@ export default function CreateGistPage() {
7272
setIsTurnstileReady(false);
7373
}, []);
7474

75-
const handleTurnstileExpire = useCallback(() => {
76-
setTurnstileToken(null);
77-
setIsTurnstileReady(false);
78-
setError(
79-
"⏰ Security verification expired. Please refresh the page to continue."
80-
);
81-
}, []);
82-
8375
const handleFilesChange = useCallback((newFiles: FileData[]) => {
8476
setFiles(newFiles);
8577
// Don't clear errors on file change - let them persist
@@ -391,9 +383,9 @@ export default function CreateGistPage() {
391383
<Turnstile
392384
sitekey={turnstileSiteKey}
393385
action="create_gist"
386+
refreshExpired="auto"
394387
onSuccess={handleTurnstileSuccess}
395388
onError={handleTurnstileError}
396-
onExpire={handleTurnstileExpire}
397389
appearance="interaction-only"
398390
/>
399391
)}

components/ui/turnstile.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ interface TurnstileProps {
77
onSuccess?: (token: string) => void;
88
onExpire?: () => void;
99
onError?: () => void;
10+
onTimeout?: () => void;
1011
theme?: "light" | "dark" | "auto";
1112
action?: string;
1213
size?: "normal" | "flexible" | "compact";
1314
appearance?: "always" | "execute" | "interaction-only";
1415
execution?: "render" | "execute";
1516
language?: string;
17+
refreshExpired?: "auto" | "manual" | "never";
18+
refreshTimeout?: "auto" | "manual" | "never";
1619
}
1720

1821
declare global {
@@ -25,12 +28,15 @@ declare global {
2528
callback?: (token: string) => void;
2629
"error-callback"?: () => void;
2730
"expired-callback"?: () => void;
31+
"timeout-callback"?: () => void;
2832
theme?: "light" | "dark" | "auto";
2933
action?: string;
3034
size?: "normal" | "flexible" | "compact";
3135
appearance?: "always" | "execute" | "interaction-only";
3236
execution?: "render" | "execute";
3337
language?: string;
38+
"refresh-expired"?: "auto" | "manual" | "never";
39+
"refresh-timeout"?: "auto" | "manual" | "never";
3440
}
3541
) => string;
3642
reset: (widgetId: string) => void;
@@ -46,12 +52,15 @@ const Turnstile: React.FC<TurnstileProps> = ({
4652
onSuccess,
4753
onExpire,
4854
onError,
55+
onTimeout,
4956
theme = "auto",
5057
action,
5158
size = "normal",
5259
appearance = "interaction-only",
5360
execution = "render",
5461
language = "auto",
62+
refreshExpired = "auto",
63+
refreshTimeout = "auto",
5564
}) => {
5665
const containerRef = useRef<HTMLDivElement>(null);
5766
const widgetIdRef = useRef<string | null>(null);
@@ -67,9 +76,12 @@ const Turnstile: React.FC<TurnstileProps> = ({
6776
appearance,
6877
execution,
6978
language,
79+
"refresh-expired": refreshExpired,
80+
"refresh-timeout": refreshTimeout,
7081
callback: onSuccess,
7182
"error-callback": onError,
7283
"expired-callback": onExpire,
84+
"timeout-callback": onTimeout,
7385
});
7486
}
7587
};
@@ -110,12 +122,15 @@ const Turnstile: React.FC<TurnstileProps> = ({
110122
onSuccess,
111123
onError,
112124
onExpire,
125+
onTimeout,
113126
theme,
114127
action,
115128
size,
116129
appearance,
117130
execution,
118131
language,
132+
refreshExpired,
133+
refreshTimeout,
119134
]);
120135

121136
return <div ref={containerRef} />;

0 commit comments

Comments
 (0)