cf-workers-query
Advanced tools
Comparing version 0.3.7 to 0.3.8
@@ -0,1 +1,12 @@ | ||
## 0.3.8 (2024-07-25) | ||
### 🩹 Fixes | ||
- **package:** remove wrangler ([e3e910c](https://github.com/anymaniax/cf-workers-query/commit/e3e910c)) | ||
### ❤️ Thank You | ||
- Victor Bury | ||
## 0.3.7 (2024-07-25) | ||
@@ -2,0 +13,0 @@ |
{ | ||
"name": "cf-workers-query", | ||
"version": "0.3.7", | ||
"version": "0.3.8", | ||
"license": "MIT", | ||
@@ -53,4 +53,3 @@ "description": "Automatically cache and revalidate data in Cloudflare Workers. Using the Cache API and Execution Context", | ||
"vite": "^5.0.0", | ||
"vitest": "^1.3.1", | ||
"wrangler": "^3.65.1" | ||
"vitest": "^1.3.1" | ||
}, | ||
@@ -57,0 +56,0 @@ "nx": { |
@@ -1,67 +0,60 @@ | ||
import { __awaiter } from "tslib"; | ||
export const CACHE_URL = 'INTERNAL_CF_WORKERS_QUERY_CACHE_HOSTNAME.local'; | ||
export class CacheApiAdaptor { | ||
cacheName; | ||
maxAge; | ||
constructor(ctx = {}) { | ||
var _a, _b; | ||
this.cacheName = (_a = ctx.cacheName) !== null && _a !== void 0 ? _a : 'cf-workers-query-cache'; | ||
this.maxAge = (_b = ctx.maxAge) !== null && _b !== void 0 ? _b : 60; | ||
this.cacheName = ctx.cacheName ?? 'cf-workers-query-cache'; | ||
this.maxAge = ctx.maxAge ?? 60; | ||
} | ||
retrieve(key, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
try { | ||
const { raw = false } = options !== null && options !== void 0 ? options : {}; | ||
const cache = yield caches.open(this.cacheName); | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
const response = yield cache.match(cacheKey); | ||
if (!response) { | ||
return null; | ||
} | ||
const data = (raw ? response : yield response.json()); | ||
const cacheControlHeader = response.headers.get('cache-control'); | ||
const dateHeader = response.headers.get('date'); | ||
const lastModified = dateHeader ? new Date(dateHeader).getTime() : 0; | ||
const cacheControl = cacheControlHeader === null || cacheControlHeader === void 0 ? void 0 : cacheControlHeader.split('=')[1]; | ||
const maxAge = Number(cacheControl); | ||
return { | ||
data, | ||
lastModified, | ||
maxAge: !isNaN(maxAge) ? maxAge : 0, | ||
}; | ||
} | ||
catch (_a) { | ||
async retrieve(key, options) { | ||
try { | ||
const { raw = false } = options ?? {}; | ||
const cache = await caches.open(this.cacheName); | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
const response = await cache.match(cacheKey); | ||
if (!response) { | ||
return null; | ||
} | ||
}); | ||
const data = (raw ? response : await response.json()); | ||
const cacheControlHeader = response.headers.get('cache-control'); | ||
const dateHeader = response.headers.get('date'); | ||
const lastModified = dateHeader ? new Date(dateHeader).getTime() : 0; | ||
const cacheControl = cacheControlHeader?.split('=')[1]; | ||
const maxAge = Number(cacheControl); | ||
return { | ||
data, | ||
lastModified, | ||
maxAge: !isNaN(maxAge) ? maxAge : 0, | ||
}; | ||
} | ||
catch { | ||
return null; | ||
} | ||
} | ||
update(key, value, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
var _a; | ||
const cache = yield caches.open(this.cacheName); | ||
const maxAge = (_a = options === null || options === void 0 ? void 0 : options.maxAge) !== null && _a !== void 0 ? _a : this.maxAge; | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
if (value instanceof Response) { | ||
const response = value.clone(); | ||
response.headers.append('cache-control', `max-age=${maxAge}`); | ||
yield cache.put(cacheKey, response); | ||
return; | ||
} | ||
const headers = new Headers(); | ||
headers.append('cache-control', `max-age=${maxAge}`); | ||
const response = new Response(JSON.stringify(value), { | ||
headers, | ||
}); | ||
yield cache.put(cacheKey, response); | ||
async update(key, value, options) { | ||
const cache = await caches.open(this.cacheName); | ||
const maxAge = options?.maxAge ?? this.maxAge; | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
if (value instanceof Response) { | ||
const response = value.clone(); | ||
response.headers.append('cache-control', `max-age=${maxAge}`); | ||
await cache.put(cacheKey, response); | ||
return; | ||
} | ||
const headers = new Headers(); | ||
headers.append('cache-control', `max-age=${maxAge}`); | ||
const response = new Response(JSON.stringify(value), { | ||
headers, | ||
}); | ||
await cache.put(cacheKey, response); | ||
} | ||
delete(key) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cache = yield caches.open(this.cacheName); | ||
const response = new Response(null, { | ||
headers: new Headers({ | ||
'cache-control': `max-age=0`, | ||
}), | ||
}); | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
yield cache.put(cacheKey, response); | ||
async delete(key) { | ||
const cache = await caches.open(this.cacheName); | ||
const response = new Response(null, { | ||
headers: new Headers({ | ||
'cache-control': `max-age=0`, | ||
}), | ||
}); | ||
const cacheKey = key instanceof URL ? key : this.buildCacheKey(key); | ||
await cache.put(cacheKey, response); | ||
} | ||
@@ -68,0 +61,0 @@ /** |
@@ -1,7 +0,6 @@ | ||
import type { PlatformProxy } from 'wrangler'; | ||
export type ExecutionContext = PlatformProxy['ctx']; | ||
export declare const getCFExecutionContext: () => { | ||
export type ExecutionContext = { | ||
waitUntil(promise: Promise<any>): void; | ||
passThroughOnException(): void; | ||
}; | ||
export declare const getCFExecutionContext: () => ExecutionContext; | ||
export declare const defineCFExecutionContext: <T extends ExecutionContext, Func extends (...args: any) => any>(context: T, func: Func) => any; |
@@ -1,9 +0,8 @@ | ||
import { __awaiter } from "tslib"; | ||
import { getCFExecutionContext } from './context'; | ||
import { CacheApiAdaptor } from './cache-api'; | ||
import { nanoid } from 'nanoid'; | ||
export const createQuery = (_a) => __awaiter(void 0, [_a], void 0, function* ({ queryKey, queryFn, gcTime, staleTime, revalidate, retry, retryDelay, executionCtx, cacheName, throwOnError, raw, }) { | ||
export const createQuery = async ({ queryKey, queryFn, gcTime, staleTime, revalidate, retry, retryDelay, executionCtx, cacheName, throwOnError, raw, }) => { | ||
try { | ||
if (!queryKey) { | ||
const data = yield queryFn(); | ||
const data = await queryFn(); | ||
return { data, error: null, invalidate: () => undefined }; | ||
@@ -14,19 +13,18 @@ } | ||
const invalidate = () => cache.delete(cacheKey); | ||
const context = executionCtx !== null && executionCtx !== void 0 ? executionCtx : getCFExecutionContext(); | ||
const context = executionCtx ?? getCFExecutionContext(); | ||
if (!revalidate) { | ||
const cachedData = yield cache.retrieve(cacheKey, { raw }); | ||
if (cachedData === null || cachedData === void 0 ? void 0 : cachedData.data) { | ||
const cachedData = await cache.retrieve(cacheKey, { raw }); | ||
if (cachedData?.data) { | ||
const isStale = staleTime && cachedData.lastModified + staleTime * 1000 < Date.now(); | ||
if (isStale && context) { | ||
const staleId = nanoid(); | ||
yield cache.update([...cacheKey, 'dedupe'], staleId); | ||
const refreshFunc = () => __awaiter(void 0, void 0, void 0, function* () { | ||
var _a; | ||
const { data: cachedStaleId } = (_a = (yield cache.retrieve([...cacheKey, 'dedupe']))) !== null && _a !== void 0 ? _a : {}; | ||
await cache.update([...cacheKey, 'dedupe'], staleId); | ||
const refreshFunc = async () => { | ||
const { data: cachedStaleId } = (await cache.retrieve([...cacheKey, 'dedupe'])) ?? {}; | ||
if (cachedStaleId && cachedStaleId !== staleId) { | ||
return; | ||
} | ||
const newData = yield queryFn(); | ||
yield cache.update(cacheKey, newData); | ||
}); | ||
const newData = await queryFn(); | ||
await cache.update(cacheKey, newData); | ||
}; | ||
context.waitUntil(refreshFunc()); | ||
@@ -39,3 +37,3 @@ } | ||
} | ||
const { data, error } = yield handleQueryFnWithRetry({ | ||
const { data, error } = await handleQueryFnWithRetry({ | ||
queryFn, | ||
@@ -49,3 +47,3 @@ retry, | ||
} | ||
yield cache.update(cacheKey, data); | ||
await cache.update(cacheKey, data); | ||
return { data, error: null, invalidate }; | ||
@@ -59,4 +57,4 @@ } | ||
} | ||
}); | ||
const defaultRetryDelay = (attemptIndex) => Math.min(1000 * Math.pow(2, attemptIndex), 30000); | ||
}; | ||
const defaultRetryDelay = (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000); | ||
function handleRetryDelay(failureCount, error, retryDelay = defaultRetryDelay) { | ||
@@ -70,5 +68,5 @@ const timeMs = typeof retryDelay === 'function' | ||
} | ||
const handleQueryFnWithRetry = (_a) => __awaiter(void 0, [_a], void 0, function* ({ queryFn, retry = 0, failureCount = 0, retryDelay, throwOnError, }) { | ||
const handleQueryFnWithRetry = async ({ queryFn, retry = 0, failureCount = 0, retryDelay, throwOnError, }) => { | ||
try { | ||
const data = yield queryFn(); | ||
const data = await queryFn(); | ||
return { data, error: null }; | ||
@@ -78,3 +76,3 @@ } | ||
if (typeof retry === 'number' && retry > 0) { | ||
yield handleRetryDelay(failureCount, e, retryDelay); | ||
await handleRetryDelay(failureCount, e, retryDelay); | ||
return handleQueryFnWithRetry({ | ||
@@ -87,3 +85,3 @@ queryFn, | ||
if (typeof retry === 'function' && retry(failureCount + 1, e)) { | ||
yield handleRetryDelay(failureCount, e, retryDelay); | ||
await handleRetryDelay(failureCount, e, retryDelay); | ||
return handleQueryFnWithRetry({ | ||
@@ -101,2 +99,2 @@ queryFn, | ||
} | ||
}); | ||
}; |
@@ -1,13 +0,16 @@ | ||
import { __awaiter, __rest } from "tslib"; | ||
import { createQuery } from './create-query'; | ||
import { HTTPException } from 'hono/http-exception'; | ||
export const cache = (_a) => { | ||
var { cacheKey, handler } = _a, options = __rest(_a, ["cacheKey", "handler"]); | ||
return (ctx, next) => __awaiter(void 0, void 0, void 0, function* () { | ||
const { data: response, error } = yield createQuery(Object.assign(Object.assign({}, options), { queryKey: typeof cacheKey === 'function' ? cacheKey(ctx) : cacheKey, queryFn: () => handler(ctx, next), executionCtx: ctx.executionCtx, throwOnError: true, raw: true })); | ||
if (!response || error) { | ||
throw new HTTPException(500); | ||
} | ||
return new Response(response.body, response); | ||
export const cache = ({ cacheKey, handler, ...options }) => async (ctx, next) => { | ||
const { data: response, error } = await createQuery({ | ||
...options, | ||
queryKey: typeof cacheKey === 'function' ? cacheKey(ctx) : cacheKey, | ||
queryFn: () => handler(ctx, next), | ||
executionCtx: ctx.executionCtx, | ||
throwOnError: true, | ||
raw: true, | ||
}); | ||
if (!response || error) { | ||
throw new HTTPException(500); | ||
} | ||
return new Response(response.body, response); | ||
}; |
23
17704
267