fixup! diigo-cache: the caches take their clock as a constructor argument
Past the transitional idiom: the cache logic (DiigoCacheLogic, PublicCacheLogic in cache.ts) requires its Clock, with no default, so cache.ts reaches no ambient time. The worker's entry module is the edge: it makes the live clock and exports the runtime-constructed DiigoCache/PublicCache as (ctx, env) subclasses that supply it (the Cloudflare constraint: the runtime constructs DOs with ctx and env only). Binding class names are unchanged, so stored state is too. The tests' FixedClockCache extends the logic class. Generated-by: Claude Opus 5.5
This commit is contained in:
1 parent
cf901ded5f
commit
961515d8db
6 files changed
+53
-31
No files matched your search
@@ -14,13 +14,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { RpcTarget } from "capnweb";
|
import { RpcTarget } from "capnweb";
|
||||||
import type { DiigoCache, FillStatus, PublicCache } from "./cache.js";
|
import type { DiigoCacheLogic, FillStatus, PublicCacheLogic } from "./cache.js";
|
||||||
import { idFromWebkey, isWebkey, shashKey } from "./webkeys.js";
|
import { idFromWebkey, isWebkey, shashKey } from "./webkeys.js";
|
||||||
|
|
||||||
/** the bindings the API reaches (structural) */
|
/** the bindings the API reaches (structural) */
|
||||||
export type ApiEnv = {
|
export type ApiEnv = {
|
||||||
CACHE_DO: DurableObjectNamespace<DiigoCache>;
|
CACHE_DO: DurableObjectNamespace<DiigoCacheLogic>;
|
||||||
PUBLIC_DO: DurableObjectNamespace<PublicCache>;
|
PUBLIC_DO: DurableObjectNamespace<PublicCacheLogic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** the fill-job surface of one cache (private or public) */
|
/** the fill-job surface of one cache (private or public) */
|
||||||
|
|||||||
+13
-14
@@ -1,6 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @file the cache Durable Objects: `DiigoCache` (public+private items) and
|
* @file the cache Durable Objects' logic: `DiigoCacheLogic` (public+private
|
||||||
* `PublicCache` (public-only items, widely shared). They are independent
|
* items) and `PublicCacheLogic` (public-only items, widely shared). Logic
|
||||||
|
* only: each requires its {@link Clock}; the worker's entry module
|
||||||
|
* (src/index.ts) is the edge that makes the live one and exports the
|
||||||
|
* runtime-constructed `DiigoCache`/`PublicCache`. They are independent
|
||||||
* and work the same way ({@link PagedCache}): pages are the unit of
|
* and work the same way ({@link PagedCache}): pages are the unit of
|
||||||
* caching; a hit is answered from `ctx.storage.sqlite` with no diigo call;
|
* caching; a hit is answered from `ctx.storage.sqlite` with no diigo call;
|
||||||
* a miss asks the webapp instance in the cache's wiring and etches the
|
* a miss asks the webapp instance in the cache's wiring and etches the
|
||||||
@@ -117,14 +120,9 @@ abstract class PagedCache extends DurableObject<CacheEnv> {
|
|||||||
#pause?: Promise<void>;
|
#pause?: Promise<void>;
|
||||||
#clock: Clock;
|
#clock: Clock;
|
||||||
|
|
||||||
/** the runtime constructs DOs with (ctx, env), so the default — the
|
/** `clock` is required: time comes from the edge that constructs us
|
||||||
* live clock, made here at the edge, nowhere in module scope — applies;
|
* (src/index.ts in the worker, tests/test-worker.ts in tests) */
|
||||||
* a subclass (tests) can pass another */
|
constructor(ctx: DurableObjectState, env: CacheEnv, clock: Clock) {
|
||||||
constructor(
|
|
||||||
ctx: DurableObjectState,
|
|
||||||
env: CacheEnv,
|
|
||||||
clock: Clock = { now: () => Date.now(), sleep: (ms) => new Promise((r) => setTimeout(r, ms)) },
|
|
||||||
) {
|
|
||||||
super(ctx, env);
|
super(ctx, env);
|
||||||
this.#clock = clock;
|
this.#clock = clock;
|
||||||
}
|
}
|
||||||
@@ -338,10 +336,11 @@ abstract class PagedCache extends DurableObject<CacheEnv> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the private cache (export name `DiigoCache`): public+private items,
|
* the private cache's logic (exported to the runtime as `DiigoCache` by
|
||||||
* addressed by its cache id (a webkey, held by the user).
|
* src/index.ts): public+private items, addressed by its cache id (a
|
||||||
|
* webkey, held by the user).
|
||||||
*/
|
*/
|
||||||
export class DiigoCache extends PagedCache {
|
export class DiigoCacheLogic extends PagedCache {
|
||||||
protected readonly kind = "private";
|
protected readonly kind = "private";
|
||||||
|
|
||||||
protected keep(rows: ItemRow[]): ItemRow[] {
|
protected keep(rows: ItemRow[]): ItemRow[] {
|
||||||
@@ -375,7 +374,7 @@ export class DiigoCache extends PagedCache {
|
|||||||
* (the idFromName("index") instance holds the kv mapping and is never
|
* (the idFromName("index") instance holds the kv mapping and is never
|
||||||
* wired).
|
* wired).
|
||||||
*/
|
*/
|
||||||
export class PublicCache extends PagedCache {
|
export class PublicCacheLogic extends PagedCache {
|
||||||
protected readonly kind = "public";
|
protected readonly kind = "public";
|
||||||
|
|
||||||
protected keep(rows: ItemRow[]): ItemRow[] {
|
protected keep(rows: ItemRow[]): ItemRow[] {
|
||||||
|
|||||||
@@ -17,16 +17,39 @@ import { newWorkersRpcResponse } from "capnweb";
|
|||||||
import { CacheApi } from "./api.js";
|
import { CacheApi } from "./api.js";
|
||||||
import { CAPNWEB_BROWSER_JS } from "./capnweb-browser.js";
|
import { CAPNWEB_BROWSER_JS } from "./capnweb-browser.js";
|
||||||
import { CACHE_PAGE_HTML } from "./cache-page.js";
|
import { CACHE_PAGE_HTML } from "./cache-page.js";
|
||||||
import { DiigoCache, PublicCache } from "./cache.js";
|
import { DiigoCacheLogic, PublicCacheLogic } from "./cache.js";
|
||||||
import type { FillStatus } from "./cache.js";
|
import type { CacheEnv, Clock, FillStatus } from "./cache.js";
|
||||||
import type { Item } from "./cache.js";
|
import type { Item } from "./cache.js";
|
||||||
import { updatedISO, usernameOf } from "./items.js";
|
import { updatedISO, usernameOf } from "./items.js";
|
||||||
import { toWebkey, idFromWebkey, isWebkey, shashKey } from "./webkeys.js";
|
import { toWebkey, idFromWebkey, isWebkey, shashKey } from "./webkeys.js";
|
||||||
import { pmSave } from "./pm-save.js";
|
import { pmSave } from "./pm-save.js";
|
||||||
|
|
||||||
// the DO classes must be entrypoint exports (the exports/ binding targets
|
/**
|
||||||
// the main module)
|
* the live clock. This module is the worker's edge — the runtime's entry,
|
||||||
export { DiigoCache, PublicCache };
|
* like a program script — so ambient time is reached here and delegated
|
||||||
|
* down; the cache logic only uses the clock it is given.
|
||||||
|
*/
|
||||||
|
function liveClock(): Clock {
|
||||||
|
return { now: () => Date.now(), sleep: (ms) => new Promise((r) => setTimeout(r, ms)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// The DO classes must be exports of the main module, and the runtime
|
||||||
|
// constructs them with (ctx, env) only: a Cloudflare API constraint, met
|
||||||
|
// here at the edge by subclasses that supply the live clock.
|
||||||
|
|
||||||
|
/** the private cache, as the runtime constructs it */
|
||||||
|
export class DiigoCache extends DiigoCacheLogic {
|
||||||
|
constructor(ctx: DurableObjectState, env: CacheEnv) {
|
||||||
|
super(ctx, env, liveClock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** the public cache, as the runtime constructs it */
|
||||||
|
export class PublicCache extends PublicCacheLogic {
|
||||||
|
constructor(ctx: DurableObjectState, env: CacheEnv) {
|
||||||
|
super(ctx, env, liveClock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** worker bindings (structural until wrangler types regenerates) */
|
/** worker bindings (structural until wrangler types regenerates) */
|
||||||
type Env = {
|
type Env = {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { FETCH_BUDGET } from "../src/query.js";
|
|||||||
const WEBAPP_ID = "fake-webapp-id";
|
const WEBAPP_ID = "fake-webapp-id";
|
||||||
|
|
||||||
type TestEnv = {
|
type TestEnv = {
|
||||||
CACHE_DO: DurableObjectNamespace<import("../src/cache.js").DiigoCache>;
|
CACHE_DO: DurableObjectNamespace<import("../src/index.js").DiigoCache>;
|
||||||
PUBLIC_DO: DurableObjectNamespace<import("../src/cache.js").PublicCache>;
|
PUBLIC_DO: DurableObjectNamespace<import("../src/index.js").PublicCache>;
|
||||||
WEBAPP: { calls(): Promise<number> };
|
WEBAPP: { calls(): Promise<number> };
|
||||||
};
|
};
|
||||||
const testEnv = env as unknown as TestEnv;
|
const testEnv = env as unknown as TestEnv;
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import { FIXED_NOW } from "./test-worker.js";
|
|||||||
// of 24, every 3rd private).
|
// of 24, every 3rd private).
|
||||||
|
|
||||||
type TestEnv = {
|
type TestEnv = {
|
||||||
CACHE_DO: DurableObjectNamespace<import("../src/cache.js").DiigoCache>;
|
CACHE_DO: DurableObjectNamespace<import("../src/index.js").DiigoCache>;
|
||||||
CLOCKED_DO: DurableObjectNamespace<import("./test-worker.js").FixedClockCache>;
|
CLOCKED_DO: DurableObjectNamespace<import("./test-worker.js").FixedClockCache>;
|
||||||
PUBLIC_DO: DurableObjectNamespace<import("../src/cache.js").PublicCache>;
|
PUBLIC_DO: DurableObjectNamespace<import("../src/index.js").PublicCache>;
|
||||||
WEBAPP: { calls(): Promise<number> };
|
WEBAPP: { calls(): Promise<number> };
|
||||||
};
|
};
|
||||||
const testEnv = env as unknown as TestEnv;
|
const testEnv = env as unknown as TestEnv;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @file the tests' main module: the real worker, plus a DiigoCache on a
|
* @file the tests' main module — their edge: the real worker (whose own
|
||||||
* fixed clock (bound as CLOCKED_DO in wrangler.tests.jsonc), so tests can
|
* edge supplies the live clock), plus the private cache's logic on a fixed
|
||||||
* interpose time through the constructor.
|
* clock (bound as CLOCKED_DO in wrangler.tests.jsonc).
|
||||||
*/
|
*/
|
||||||
import { DiigoCache } from "../src/cache.js";
|
import { DiigoCacheLogic } from "../src/cache.js";
|
||||||
import type { CacheEnv } from "../src/cache.js";
|
import type { CacheEnv } from "../src/cache.js";
|
||||||
|
|
||||||
export * from "../src/index.js";
|
export * from "../src/index.js";
|
||||||
@@ -12,7 +12,7 @@ export { default } from "../src/index.js";
|
|||||||
/** 2026-10-07T12:00:00Z */
|
/** 2026-10-07T12:00:00Z */
|
||||||
export const FIXED_NOW = Date.UTC(2026, 9, 7, 12, 0, 0);
|
export const FIXED_NOW = Date.UTC(2026, 9, 7, 12, 0, 0);
|
||||||
|
|
||||||
export class FixedClockCache extends DiigoCache {
|
export class FixedClockCache extends DiigoCacheLogic {
|
||||||
constructor(ctx: DurableObjectState, env: CacheEnv) {
|
constructor(ctx: DurableObjectState, env: CacheEnv) {
|
||||||
super(ctx, env, { now: () => FIXED_NOW, sleep: async () => {} });
|
super(ctx, env, { now: () => FIXED_NOW, sleep: async () => {} });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user