Cloudflare Turnstile plugin for Deno Fresh.
First of all, create your fresh app.
Add Turnstile to your import_map.json
.
{
"imports": {
"$turnstile/": "https://deno.land/x/fresh_turnstile@1.0.1-0/"
}
}
Consume the Turnstile plugin in your app's main.ts
.
import { TurnstilePlugin } from "$turnstile/index.ts";
await start(manifest, {
plugins: [
// ...
TurnstilePlugin(),
// ...
],
});
Add <CfTurnstile sitekey="..." />
inside your form. A hidden input named cf-turnstile-response
will be added to your form with the token value once a
response is received from Turnstile. See the instructions in the server-side validation section further below for easy server-side
handling.
Please note that if you use AJAX / fetch to submit the form, you will need to call getTurnstileAsync()
to get access to the turnstile
object and then
invokes turnstile.reset(widgetId)
to get a fresh token. See the section on explicit rendering below for more instructions on how to get
access to the turnstile
object. The id
attribute you provide to <CfTurnstile />
gets passthrough directly to the widget, so you can use that ID as
widgetId
in turnstile.getResponse(widgetId)
and turnstile.reset(widgetId)
.
You can add the callback
, errorCallback
, and expiredCallback
props on <CfTurnstile />
and dynamically handle these events.
The following code sample displays the response token on the page when it's received from Turnstile.
import { useSignal } from "@preact/signals";
// ...
const response = useSignal("Waiting for validation...");
// ...
<CfTurnstile sitekey={sitekey} {...props} callback={(token) => response.value = token} />
<pre>{response}</pre>
Note: for implicit rendering, the official docs describe
data-callback
, data-error-callback
, and data-expired-callback
as strings (function names) that get invoked later. However, this plugin makes uses of
useId
and useEffect
hooks to allow you to provide the callable props directly to callback
, errorCallback
, and expiredCallback
.
Add the disableImplicitRendering
option to your plugin declaration. (See the installation section above again for more information.)
await start(manifest, {
plugins: [
// ...
TurnstilePlugin({ disableImplicitRendering: true }),
// ...
],
});
Once you have disabled implicit rendering, see the next section to explicitly render your Turnstile widgets.
You can get the turnstile
global object from inside a useEffect
hook like this:
import { useEffect } from "preact/hooks";
import { getTurnstileAsync } from "$turnstile/plugin.ts";
//...
useEffect(() => {
getTurnstileAsync().then((turnstile) => {
// console.log(turnstile);
});
});
Or you can directly use the useTurnstileEffect
hook:
import { useTurnstileEffect } from "$turnstile/plugin.ts";
// ...
useTurnstileEffect((turnstile) => {
// console.log(turnstile);
});
Once you have got ahold of the turnstile
object within an effect hook, you can now call turnstile.render(...)
similar to how it is shown in
official docs.
fresh-turnstile
provides a default POST handler for easy server-side form validations.
You may use it like this in your route:
import { CfTurnstileValidationResult, generatePostHandler } from "$turnstile/handlers/CfTurnstileValidation.ts";
import Page from "$flowbite/components/Page.tsx";
export const handler = { POST: generatePostHandler(cf_turnstile_secret_key) };
export default function CfTurnstileValidation({ data }: PageProps<CfTurnstileValidationResult | null>) {
/* 3 scenarios can occur here:
* 1. data is null => the form was not submitted correctly, or the secret key was not provided.
* 2. data.success is false => the form was submitted correctly, but validation failed. data["error-codes"] should be a list of error codes (as strings).
* 3. data.success is true => the form was submitted correctly and validated successfully. data.challenge_ts and data.hostname should be available for inspection.
*/
}
For now, the versions are a.b.c-x.y.z
where a.b.c
is the plugin version and x.y.z
is the supported Turnstile API version. For example, 0.0.1-0
is the
initial release of plugin, which supports Turnstile API v0.
All tags starting with 0.0.
are mutable. Expect breaking changes! Starting from 0.1.
, tags will be immutable. However, still expect breaking
changes. Starting from 1.
, semver will kick in and there will be no breaking changes until 2.
.