What malicious actor is causing the problem @Avi?
What malicious actor is causing the problem @Avi?

Currently, DO to DO RPC requires at least 2 requests per RPC callWhat do you mean 2 requests per RPC call? There should only be one round trip for a normal RPC call.
getCurrentBookmark() and getBookmarkForTime() return a Promise<string>, but the example right below it shows it being used without a promise:Configures the Durable Object so that the next time it restarts, it should restore its storage to exactly match what the storage contained at the given bookmark. After calling this, the application should typically invoke ctx.abort() to restart the Durable Object, thus completing the point-in-time recovery.
onNextSessionRestoreBookmark works on the next restart, so you need to kill the DO for the restore to happen.await explicitly any async operation. The example there probably depends on implicit transactions, but just await in your code to be able to reason about things.ctx.waitUntil(doSomething())doSomething() as a result of the alarmctx.storage.get() returns a Promise.
ctx.storage.kv.get() is the sync API (in SQLite DOs)ctx.storage.get() is the old async API.kvenvironment and keep the script_name with the correct worker name does it work? The error says there isn't any worker with the name api which is correct, since you say the worker is api-staging.
getCurrentBookmark()getBookmarkForTime()Promise<string>onNextSessionRestoreBookmarkctx.waitUntil(doSomething())doSomething()ctx.storage.get()ctx.storage.get()ctx.storage.kv.get().kvscript_nameapi-stagingimport { DurableObject } from 'cloudflare:workers';
let LOCK_TIMEOUT = 5000; // 5 seconds
let RATE_LIMIT_WINDOW = 200; // 200 milliseconds, now using stamina in cast system
// UserLock.js
export default class RateLimitkDurableObject extends DurableObject {
constructor(state, env) {
super(state, env);
this.state = state;
this.env = env;
}
async acquireLock() {
// Check if user is locked
const isLocked = await this.state.storage.get("isLocked");
if (isLocked) {
// check lastInteraction
const lastInteraction = (await this.state.storage.get("lastInteraction")) || 0;
if (Date.now() - lastInteraction < LOCK_TIMEOUT) {
throw new Error("User is currently locked");
}
}
// Check rate limit (e.g., 1 request per 15 seconds)
const lastInteraction = (await this.state.storage.get("lastInteraction")) || 0;
const now = Date.now();
const rateLimitWindow = RATE_LIMIT_WINDOW;
if (now - lastInteraction < rateLimitWindow) {
let timeLeft = Math.ceil((rateLimitWindow - (now - lastInteraction)) / 1000);
throw new Error(`Please try again in ${timeLeft} seconds.`);
}
// Acquire lock and update last interaction time
await this.state.storage.put("isLocked", true);
await this.state.storage.put("lastInteraction", now);
return { status: "Lock acquired" };
}
async releaseLock() {
// Release lock
console.log("Releasing lock for user");
await this.state.storage.put("isLocked", false);
return { status: "Lock released" };
}
}let now = new Date();
// restore to 2 days ago
let bookmark = ctx.storage.getBookmarkForTime(now - 2);
ctx.storage.onNextSessionRestoreBookmark(bookmark);let bookmark = await getCurrentBookmark();
// stuff may happen here while it is awaiting
this.sql.exec(/* omitted */);let bookmark = await getCurrentBookmark();
// stuff may happen here while it is awaiting
this.sql.exec(/* omitted */);// Get a bookmark for the current state of the database. Note that since this is async, the
// bookmark will include any writes in the current atomic batch, including writes that are
// performed after this call begins. It could also include concurrent writes that haven't happened
// yet, unless blockConcurrencyWhile() is used to prevent them.
kj::Promise<kj::String> getCurrentBookmark();