mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 16:55:37 +02:00
✨ feat: Add qwik-react (#103)
This adds the following pages: The landing page (/) The pricing page (/pricing) The contact page (/contact) The changelog page (/changelog) Terms Of Service page (/terms) Privacy Policy (/privacy)
This commit is contained in:
47
packages/cache/caches.ts
vendored
Normal file
47
packages/cache/caches.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const buildCacheKey = (namespace: string) => (key: string) => {
|
||||
return `${namespace}:${key}`;
|
||||
};
|
||||
|
||||
export interface KVResponseCache {
|
||||
match(key: string): Promise<Response | null>;
|
||||
put(key: string, res: Response, options?: KVNamespacePutOptions): Promise<void>;
|
||||
delete(key: string): Promise<void>;
|
||||
}
|
||||
|
||||
export const kvResponseCache =
|
||||
(kv: KVNamespace) =>
|
||||
(cacheName: string): KVResponseCache => {
|
||||
const cacheKey = buildCacheKey(cacheName);
|
||||
|
||||
return {
|
||||
async match(key: string) {
|
||||
const [headers, status, body] = await Promise.all([
|
||||
kv.get(cacheKey(`${key}:headers`)),
|
||||
kv.get(cacheKey(`${key}:status`)),
|
||||
kv.get(cacheKey(`${key}:body`), "stream"),
|
||||
]);
|
||||
|
||||
if (headers === null || body === null || status === null) return null;
|
||||
|
||||
return new Response(body, { headers: JSON.parse(headers), status: parseInt(status, 10) });
|
||||
},
|
||||
async put(key: string, res: Response, options?: KVNamespacePutOptions) {
|
||||
const headers = Array.from(res.headers.entries()).reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
|
||||
const body = res.body;
|
||||
if (body === null) return;
|
||||
|
||||
await Promise.all([
|
||||
kv.put(cacheKey(`${key}:headers`), JSON.stringify(headers), options),
|
||||
kv.put(cacheKey(`${key}:status`), `${res.status}`, options),
|
||||
kv.put(cacheKey(`${key}:body`), body, options),
|
||||
]);
|
||||
},
|
||||
async delete(key: string) {
|
||||
await Promise.all([
|
||||
kv.delete(cacheKey(`${key}:headers`)),
|
||||
kv.delete(cacheKey(`${key}:status`)),
|
||||
kv.delete(cacheKey(`${key}:body`)),
|
||||
]);
|
||||
},
|
||||
};
|
||||
};
|
||||
8
packages/cache/index.ts
vendored
Normal file
8
packages/cache/index.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
//copied from https://github.com/napolab/kv-response-cache with some minor changes
|
||||
import { kvResponseCache } from "./caches";
|
||||
import { kvCaches, defaultGetCacheKey } from "./middleware";
|
||||
|
||||
import type { KVResponseCache } from "./caches";
|
||||
|
||||
export type { KVResponseCache };
|
||||
export { kvResponseCache, kvCaches, defaultGetCacheKey as getCacheKey };
|
||||
47
packages/cache/middleware.ts
vendored
Normal file
47
packages/cache/middleware.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
import { kvResponseCache } from "./caches";
|
||||
|
||||
import type { Filter } from "./types";
|
||||
import type { Context, Env, MiddlewareHandler } from "hono";
|
||||
|
||||
type Namespace<E extends Env> = string | ((c: Context<E>) => string);
|
||||
interface GetCacheKey<E extends Env> {
|
||||
(c: Context<E>): string;
|
||||
}
|
||||
|
||||
type KVCacheOption<E extends Env & { Bindings: Record<string, unknown> }> = {
|
||||
key: keyof E["Bindings"];
|
||||
namespace: Namespace<E>;
|
||||
getCacheKey?: GetCacheKey<E>;
|
||||
options?: KVNamespacePutOptions;
|
||||
};
|
||||
|
||||
export const defaultGetCacheKey = <E extends Env>(c: Context<E>) => c.req.url;
|
||||
|
||||
export const kvCaches =
|
||||
<E extends Env & { Bindings: Record<string, unknown> }>({
|
||||
key: bindingKey,
|
||||
namespace,
|
||||
options,
|
||||
getCacheKey = defaultGetCacheKey,
|
||||
}: KVCacheOption<E>): MiddlewareHandler<E> =>
|
||||
async (c, next) => {
|
||||
const kv: KVNamespace = c.env?.[bindingKey] as KVNamespace;
|
||||
const kvNamespace = typeof namespace === "function" ? namespace(c) : namespace;
|
||||
|
||||
const kvCaches = kvResponseCache(kv);
|
||||
const cache = kvCaches(kvNamespace);
|
||||
|
||||
const key = getCacheKey(c);
|
||||
const response = await cache.match(key);
|
||||
if (response) {
|
||||
response.headers.set("X-KV-CACHE", "hit");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
await next();
|
||||
|
||||
if (c.res.status >= 200 && c.res.status < 300) {
|
||||
c.executionCtx.waitUntil(cache.put(key, c.res.clone(), options));
|
||||
}
|
||||
};
|
||||
13
packages/cache/package.json
vendored
Normal file
13
packages/cache/package.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@nestri/cache",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"exports":{
|
||||
".":"./index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240529.0",
|
||||
"wrangler": "^3.57.2"
|
||||
}
|
||||
}
|
||||
15
packages/cache/tsconfig.json
vendored
Normal file
15
packages/cache/tsconfig.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"types": [
|
||||
"@cloudflare/workers-types/2023-07-01"
|
||||
]
|
||||
},
|
||||
}
|
||||
3
packages/cache/types.ts
vendored
Normal file
3
packages/cache/types.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export type Filter<T extends Record<string, unknown>, V> = {
|
||||
[K in keyof T as T[K] extends V ? K : never]: T[K];
|
||||
};
|
||||
Reference in New Issue
Block a user