The next generation web framework for Cloudflare Workers
MIT License
until
exit condition: 20e663617035932393bd5ba631c12a3240902a890.6.0
changes to read
empty condition (a2edaa4449393d0ad30008d6e6844c98b4057432)
"ws"
example for new worktop/ws
moduletypes/check.ts
test passing: 1bed24e2610425ded40e258b58e333cc0c7b972a(kv) The read
export now returns Promise<T | null>
instead of Promise<T | false>
: a2edaa4
This is only breaking if your data integrity checks did strict comparison against false
values.
Note: This also affects the Database.get
method.
import { read } from 'worktop/kv';
import type { Item } from 'lib/example';
let item = await read<Item>(binding, 'my:key');
// ^ BEFORE: Item | false
// ^ AFTER: Item | null
(kv): Move the toJSON
parameter for write
and Database.put
into a new options
argument: 861a4e9
Note: The default behavior is unchanged.
import { write, Database } from 'worktop/kv';
let DB = new Database(binding);
// BEFORE:
await write(binding, 'my:key', 'value', false);
await DB.put('my:key', 'value', false);
// AFTER:
await write(binding, 'my:key', 'value', { toJSON: false });
await DB.put('my:key', 'value', { toJSON: false });
Add worktop/ws
module (#48): 8beefdf
Check out #48 for examples and documentation
import { Router, compose } from 'worktop';
import * as ws from 'worktop/ws';
// userland code
import * as Token from 'lib/token';
import * as Chat from 'lib/chat';
const API = new Router;
API.add('GET', '/chat/:lobby', compose(
Token.isValid, // verify token exists & is valid
Chat.isAuthorized, // verify user can access this room
ws.listen(Chat.handler) // the SocketHandler for WS events
));
(kv) Add list
method for keys generator (#47): e97bb57
Returns an AsyncGenerator
you can use to manually apply your own stop-until-X logic.
(kv) Add paginate
method for keys paging (#47): abbdf7f, e14e1bd
Applies the 90% use case for consuming the list()
iterator:
let keys = await database.paginate(BINDING, {
prefix: 'users::1234::projects',
limit: 25,
page: 3
});
// ^ This will skip the first 50 keys (2 x 25) and
// then return the 0-25 keys that constitute a "page 3".
// If you supply a `limit` x `page` combination that exceeds
// the total keys, then an empty array is returned early.
(kv) Add options.metadata
support to all read
and write
methods (#46): 73e8160
Metadata allows you to assign additional information/context to a key. This is particularly useful when list
ing or paginate
ing keys.
(crypto) Add timingSafeEqual
method (#34, #45): 200999a
A constant-time TypedArray comparison utility.
paginate
utility within the kv-todos
example: e14e1bdKV.Namespace[getWithMetadata]
types: d381808read
type overloads: e609be2null
return type from KV.Namespace[get]
: 58beaecoptions
variants to KV.Namespace[get]
method: 7c9ab8b(cache): Attempt a GET
match in Cache.lookup
method with incoming HEAD
request (#44): 1a27c9c
When the incoming request is a HEAD method, try to look for its GET counterpart in the Cache.
API.add('GET', '/articles', async (req, res) => {
// heavy DB query processing, etc
const items = await expensive('task');
res.send(200, items);
});
// BEFORE
// ---
// request -> "GET /articles" -> Cache MISS -> execute -> Cache PUT -> Response
// request -> "GET /articles" -> Cache HIT -> Response
// request -> "HEAD /articles" -> Cache HIT -> execute -> Cache PUT -> Response
// AFTER
// ---
// request -> "GET /articles" -> Cache MISS -> execute -> Cache PUT -> Response
// request -> "GET /articles" -> Cache HIT -> Response
// request -> "HEAD /articles" -> Cache HIT -> Response
(router): Prevent early exit via compose
in prepare
hook (#43): a1ab931
When using compose()
to create a $.prepare
handler, a Response was always returned from $.prepare
, preventing any/all route handlers from running. This has been fixed.
(cache): Do not try to Cache.put
for HEAD
requests (#44): e69859c
This technically was throwing at runtime error, which didn't affect the Response – thanks to event.waitUntil
.
(kv) Pass-through KV.WriteOptions
value via write
and Database.put
methods: 93df321
This enables the ability to set expiration
and/or expirationTtl
values, which was previously missing.
(types) Add Method
definition for request and router (#39): 9757ed6
Thank you @cometkim!
(types) Add scheduled
event & listener definitions: 108e463, d110d60
worktop/cors
and worktop/crypto
modules in README (#36): 84dd7b1/.vsconfig
override for tsc
location: 9178737Add conditional exports
support for CommonJS (#27, #31, #32): cacf3e2
See #32 for details. TLDR: This is meant for testing purposes only.
(crypto) Add additional export methods (#15, #30): f3322ac
keyload
– generate a CryptoKey
with a raw secret valuekeygen
– generate a CryptoKey
without a base valuesign
– generate a digital signature for a payload
using the specified algorithm and CryptoKey
verify
– verify the digital signature of a payload
using the specified algorithm and CryptoKey
PBKDF2
– apply the PBKDF2 function to an input using a salt and derivation function(utils): Add ulid
export (#25, #28): b854b00
A lexicographically sortable random identifier; see ulid/spec
(utils): Add randomize
export: f3322ac
Wrapper for crypto.getRandomValues
utility.
req.cf
properties: 3f74f6bbanner
approach for require hook: 7862deeviaHEX
helper: 34e65a2Uint8Array
toHEX
helper.
(cache): Clone Response
before Set-Cookie
guard: ac19ee9
This fixes a bug with worktop that only occurred when a handler returned a fetch() call directly and the subrequest was to a resource that was cacheable & had a "Set-Cookie" header.
In code, this may have looked like:
API.add('GET', '/example', (req, res) => {
return fetch('https://other.com/foobar');
});
And where the response from 'https://other.com/foobar'
was both cacheable and had a "Set-Cookie" header.
Any/All other cache usage was (and remains) unaffected.
find()
to return void
: f6cadf3Add worktop/cors
module (#1, #22): c2e83e7, 9482d6a, 9eee191
Add compose
utility to main worktop
module (#23): b7103b7, c5d49c1
Note: Updated #7 to add explicit type-safety at later date.
Add named UID
and UUID
types from worktop/utils
module (#21): dc600c3, 35c2a1b
More explicit type interfaces by default, while still satisfying string
types.
Allow Router.prepare
function to return Response
instance directly: 50383e8
This makes it a true Handler
signature.
(response): Make res.send
stringify non-obj/str data to String: dd597db
Otherwise TextEncoder
throws when determining byteLength
Add __PURE__
directives for better tree-shaking: ed4159a, 1fa1b5f
"cors"
example: 13c27bf/bin
devDependencies into root package.json
file: 54663a1worktop/cookie
module (#20): b148f46req.params
type safety! (#16, #17): b048388, fbf6e48read
values: (#19): a024283/examples
builder: 21a6af9, 4d90405Important: For a complete rundown of all breaking changes, including points not mentioned in this section, please see #10
The base Router
class no longer has an implicit dependency on the worktop/cache
module. By disassociating, developers can now choose whether or not their application(s) should interact with the Cache, allowing worktop
to now be used as a framework for authoring Service Workers – yes, for the browser!
Note: There will eventually be a
worktop/sw
module that provides Service Worker utilities. Other modules must come first, though.
In [email protected]
, the default behavior was to pass all incoming FetchEvent
s through worktop/cache
in search of a matching cache entry. To regain this behavior, please make the following changes after upgrading to [email protected]
:
import { Router } from 'worktop';
++ import { reply } from 'worktop/cache';
const API = new Router();
// ... routes
-- addEventListener('fetch', API.listen);
++ addEventListener('fetch', reply(API.run));
Or, you may choose to involve the new listen
utility, which invokes the addEventListener
call for you:
import { Router } from 'worktop';
++ import * as Cache from 'worktop/cache';
const API = new Router();
// ... routes
-- addEventListener('fetch', API.listen);
++ Cache.listen(API.run);
worktop/utils
module (#8): a0123be
..4e0a0b2
worktop/crypto
module (#11): d8ee779worktop/base64
module (#12, #14): 6695b54req.body
method assignments (#9): 693c15a, aacb152build
table summary (#13): 87bcf51