AbstractAbstractgetRetrieves a value from storage by key.
Returns the stored value deserialized to the specified type, or null if the key doesn't exist or the value is null.
Values are automatically deserialized using SuperJSON, which properly restores Date objects, Maps, Sets, and other complex types.
The expected type of the stored value (must be Serializable)
The storage key to retrieve
Promise resolving to the stored value or null
AbstractsetStores a value in persistent storage.
The value will be serialized using SuperJSON and stored persistently. Any existing value at the same key will be overwritten.
SuperJSON automatically handles Date objects, Maps, Sets, undefined values, and other complex types that standard JSON doesn't support.
The type of value being stored (must be Serializable)
The storage key to use
The value to store (must be SuperJSON-serializable)
Promise that resolves when the value is stored
// Date objects are preserved
await this.set('sync_state', {
lastSync: new Date(),
minDate: new Date(2024, 0, 1)
});
// undefined is now supported
await this.set('data', { name: 'test', optional: undefined }); // ✅ Works
// Arrays with undefined are supported
await this.set('items', [1, undefined, 3]); // ✅ Works
await this.set('items', [1, null, 3]); // ✅ Also works
// Maps and Sets are supported
await this.set('mapping', new Map([['key', 'value']])); // ✅ Works
await this.set('tags', new Set(['tag1', 'tag2'])); // ✅ Works
// Functions are NOT supported - use callback tokens instead
const token = await this.callback(this.myFunction);
await this.set('callback_ref', token); // ✅ Use callback token
AbstractsetStores many key/value pairs in one round-trip.
Equivalent to calling set for each entry, but issues a single
storage operation. Always prefer this over looping set() when
writing per-item state in a batch (e.g. an id→channel mapping for every
message in a sync pass): each set() is a network round-trip to the
storage backend, so a loop of hundreds of them dominates the execution's
wall-clock time and request budget, while one setMany() costs a single
request.
All entries are written atomically — either every entry lands or none do.
The type of values being stored (must be Serializable)
Array of [key, value] pairs to store
Promise that resolves when all values are stored
AbstractlistLists all storage keys matching a prefix.
Returns an array of key strings that start with the given prefix. Useful for finding all keys in a namespace (e.g., all sync locks).
Prefer listEntries when you are going to read every value anyway
— list() followed by a get() per key costs one round-trip per key.
The prefix to match keys against
Promise resolving to an array of matching key strings
AbstractlistLists matching keys with their values in one round-trip.
This is the read counterpart of setMany. The common
list(prefix) → get(key) per key shape costs 1 + N round-trips; this
costs one, because the storage backend already reads the values during
the prefix scan and list() simply discards them.
Reach for this whenever you buffer per-item state under a prefix and later drain it (occurrence buffers, pending write-backs, id→id caches). A drain loop of a few hundred keys is enough to dominate an execution's wall-clock time and exhaust its request budget.
The type of the stored values
The prefix to match keys against
Promise resolving to [key, value] pairs, key-ascending
AbstractgetReads many keys in one round-trip.
Equivalent to calling get for each key, but issues a single
storage operation. Always prefer this over looping get() — the same
round-trip arithmetic as setMany. Use listEntries instead
when the keys share a prefix and you don't already know them.
Missing keys come back as null, and the result is positionally aligned
with keys, so a keys[i] ↔ values[i] zip is always safe.
The type of the stored values
The storage keys to read
Promise resolving to one value (or null) per requested key
AbstractclearRemoves a specific key from storage.
After this operation, get() calls for this key will return null. No error is thrown if the key doesn't exist.
The storage key to remove
Promise that resolves when the key is removed
AbstractclearRemoves many keys in one round-trip.
Equivalent to calling clear for each key, but issues a single storage operation — the delete counterpart of setMany. Draining a buffered prefix is the usual case: pair it with listEntries so the whole drain costs two round-trips regardless of how many keys there are, instead of one per key.
Keys that don't exist are ignored. All deletes are applied atomically.
The storage keys to remove
Promise that resolves when all keys are removed
AbstractclearRemoves all keys from this storage instance.
This operation clears all data stored by this twist/tool instance but does not affect storage for other twists or tools.
Promise that resolves when all keys are removed
AbstractacquireAcquire a self-expiring lock. Returns true if the caller now holds the lock, false if another holder has a non-expired lease.
Use this for any operation where you previously hand-rolled a boolean
"in progress" flag with manual cleanup on every error path. The lock
auto-releases after ttlMs, so a crashed/timed-out holder cannot wedge
the system permanently — pick a ttlMs comfortably longer than the
worst-case duration of the protected work.
Acquisition is atomic across concurrent callers (the underlying
Durable Object serializes operations). Lock keys live in a reserved
namespace and never appear in get / list results.
Lock identifier (any string).
Lease duration in milliseconds. After this time the lock
is considered expired and a new caller can acquire it even if
releaseLock was never called.
Promise resolving to true if acquired, false if held.
AbstractreleaseRelease a lock acquired via acquireLock. Safe to call even if the caller never acquired the lock or the lease has already expired.
The same key that was passed to acquireLock.
Built-in tool for persistent key-value storage.
The Store tool provides twists and tools with a simple, persistent storage mechanism that survives worker restarts and invocations. Each twist/tool instance gets its own isolated storage namespace.
Note: Store methods are also available directly on Twist and Tool classes via
this.get(),this.set(),this.clear(), andthis.clearAll(). This is the recommended approach for most use cases.Storage Characteristics:
Supported Data Types (via SuperJSON):
NOT Supported (will throw validation errors):
Use Cases:
Example