WebDyne::Cloudflare

Use Cloudflare services from WebDyne PSP pages or native PAGI applications under ZeroPerl. The npm package @webdyne/webdyne-cloudflare includes both the Perl modules and JavaScript adapters. No separate CPAN installation is required in the Worker.

GitHub Attestations

The release workflows generate GitHub artifact attestations for release archives. Install the GitHub CLI with gh attestation support and authenticate with gh auth login.

Download the npm package with npm pack, replace VERSION, and verify the resulting archive with:

npm pack @webdyne/webdyne-cloudflare@VERSION
gh attestation verify webdyne-webdyne-cloudflare-VERSION.tgz --repo aspeer/pm-WebDyne-Cloudflare

For a CPAN distribution archive, use:

gh attestation verify WebDyne-Cloudflare-VERSION.tar.gz --repo aspeer/pm-WebDyne-Cloudflare

A successful verification confirms that the archive's checksum matches an attestation from this repository. Attestations cover archives produced by the attestation-enabled release workflows. Older releases and GitHub's automatically generated source-code archives are not covered.

| Service | Perl API | WebDyne example | | --- | --- | --- | | D1 queries and atomic batches | D1 | Storage | | D1 sessions and bookmarks | Sessions | Bookmark continuation | | Workers KV | KV | Storage | | R2 buffered objects | R2 | Storage | | PostgreSQL through Hyperdrive | Hyperdrive | Inventory | | MySQL through Hyperdrive | MySQL | Inventory | | Secrets Store retrieval | Secrets Store | Safe retrieval | | Durable Object RPC and Perl SQLite handlers | Durable Objects | Counter |

Quick start

Start with the examples guide. Each service directory is a standalone application with WebDyne as its default entry and, where useful, a native PAGI alternative.

For a new application:

npm init -y
npm install @webdyne/webdyne-zeroperl@^1.0.14 @webdyne/webdyne-cloudflare@^1.7.1
npx webdyne-cloudflare init

Install the released packages from npm. See the examples guide for complete local development instructions. Create app/app.psp, enable the extension and configure the required bindings in package.json using the configuration guide, then run npm run check and npm run dev. Initialization creates scaffolding; it does not create your application page or provision Cloudflare resources.

Request lifetime and Futures

Construct facades inside the request. In WebDyne, the scope is $self->r()->{'scope'}; native PAGI receives $scope_hr directly. Cloudflare bindings and database credentials remain in JavaScript. Perl receives an opaque capability that expires when the request or invocation finishes. Do not retain facades, statements, or unfinished operations in package globals.

Service I/O returns Futures. The WebDyne examples retrieve results with ->get() through ZeroPerl's host bridge. Native async handlers use Future::AsyncAwait and await. Complete all work within the request; dropping a Future does not schedule background work. Hyperdrive uses familiar DBI-style method names and argument positions, but is asynchronous and is not DBI-compatible.

use WebDyne::Cloudflare::D1;

sub customer {
    my ($self, $match_hr)=@_;
    my $db_or=WebDyne::Cloudflare::D1->new(
        scope => $self->r()->{'scope'}, binding => 'DB',
    );
    return $db_or->prepare('SELECT name FROM customers WHERE id=?1')
        ->bind($match_hr->{'id'})->first()->get();
}

Use bound SQL parameters and the service's explicit byte/blob wrapper for binary data. Escape values inserted into HTML. See the individual API references for result types, errors, limits, and transaction behavior. A timeout or failed commit does not prove a database write was cancelled; ambiguous writes are never retried automatically. Runtime teardown awaits resource cleanup.

Text, binary data and errors

Perl character strings cross as text. Unflagged non-ASCII strings are decoded strictly as UTF-8, including SQL, keys, column names and nested metadata/JSON keys and values. Invalid UTF-8 fails before the host call. Normalization copies containers without changing caller data; cycles and keys which become identical after UTF-8 decoding are rejected.

Use the service's blob($bytes) wrapper for binary values. Returned binary data becomes ordinary Perl byte strings. D1 preserves numbers, zero, empty strings, JSON booleans and SQL NULL (undef). KV/R2 put treats a plain numeric body as text; use KV put_json to retain JSON numeric/boolean types.

Missing capabilities or invalid constructor arguments throw immediately. Service operations fail their Future on errors. Host errors use WebDyne::Cloudflare::D1::Error, KV::Error or R2::Error, with name(), message(), code() and cause() accessors and stringification. Local input validation errors can be plain exceptions. Catch failures around await or ->get(); don't assume every exception is a service Error object.

KV values and R2 bodies are buffered, with a default bridge limit of 16 MiB. KV provider reads are buffered before the limit check; it is not a streaming memory guarantee. R2 rejects oversized reads and cancels unread bodies. Increasing the limits increases interpreter/Worker memory pressure and does not lift Cloudflare's own service limits.

R2 streaming, multipart uploads, conditional requests, signed URL generation and automatic retries are not implemented for the storage APIs. Use the documented methods rather than assuming the complete JavaScript binding API is available in Perl.

Development and documentation

Perl 5.20+ with Future and Future::AsyncAwait is declared; current native tests use Perl 5.44. Use Node.js 24+ for the full suite, including SQLite tests.

npm ci --ignore-scripts
perl Makefile.PL
make test
make distcheck
npm run pack:check

Generated consumers, npm archives and local Wrangler state are ignored build outputs. Keep them out of source distributions. Historical implementation reports and superseded prototypes are available in Git history before the 1.7.1 cleanup.