@bgord/bun 1.5.8 → 1.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache-repository-node-cache.adapter.d.ts +15 -0
- package/dist/cache-repository-node-cache.adapter.d.ts.map +1 -0
- package/dist/cache-repository-node-cache.adapter.js +31 -0
- package/dist/cache-repository-node-cache.adapter.js.map +1 -0
- package/dist/cache-repository-noop.adapter.d.ts +14 -0
- package/dist/cache-repository-noop.adapter.d.ts.map +1 -0
- package/dist/cache-repository-noop.adapter.js +16 -0
- package/dist/cache-repository-noop.adapter.js.map +1 -0
- package/dist/cache-repository.port.d.ts +10 -0
- package/dist/cache-repository.port.d.ts.map +1 -0
- package/dist/cache-repository.port.js +2 -0
- package/dist/cache-repository.port.js.map +1 -0
- package/dist/cache-resolver-simple.adapter.d.ts +18 -0
- package/dist/cache-resolver-simple.adapter.d.ts.map +1 -0
- package/dist/cache-resolver-simple.adapter.js +26 -0
- package/dist/cache-resolver-simple.adapter.js.map +1 -0
- package/dist/cache-resolver.port.d.ts +16 -0
- package/dist/cache-resolver.port.d.ts.map +1 -0
- package/dist/cache-resolver.port.js +6 -0
- package/dist/cache-resolver.port.js.map +1 -0
- package/dist/cache-response.middleware.d.ts +16 -4
- package/dist/cache-response.middleware.d.ts.map +1 -1
- package/dist/cache-response.middleware.js +21 -12
- package/dist/cache-response.middleware.js.map +1 -1
- package/dist/environment-loader-process-safe.adapter.d.ts +13 -6
- package/dist/environment-loader-process-safe.adapter.d.ts.map +1 -1
- package/dist/environment-loader-process-safe.adapter.js +7 -9
- package/dist/environment-loader-process-safe.adapter.js.map +1 -1
- package/dist/http-logger.middleware.js +2 -2
- package/dist/http-logger.middleware.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/job-handler.service.js +1 -1
- package/dist/job-handler.service.js.map +1 -1
- package/dist/shield-rate-limit.adapter.d.ts +4 -4
- package/dist/shield-rate-limit.adapter.d.ts.map +1 -1
- package/dist/shield-rate-limit.adapter.js +5 -10
- package/dist/shield-rate-limit.adapter.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/readme.md +5 -3
- package/src/cache-repository-node-cache.adapter.ts +37 -0
- package/src/cache-repository-noop.adapter.ts +20 -0
- package/src/cache-repository.port.ts +11 -0
- package/src/cache-resolver-simple.adapter.ts +36 -0
- package/src/cache-resolver.port.ts +20 -0
- package/src/cache-response.middleware.ts +37 -11
- package/src/environment-loader-process-safe.adapter.ts +10 -10
- package/src/http-logger.middleware.ts +2 -2
- package/src/index.ts +5 -3
- package/src/job-handler.service.ts +1 -1
- package/src/shield-rate-limit.adapter.ts +11 -15
- package/dist/cache-resolver.service.d.ts +0 -47
- package/dist/cache-resolver.service.d.ts.map +0 -1
- package/dist/cache-resolver.service.js +0 -37
- package/dist/cache-resolver.service.js.map +0 -1
- package/dist/rate-limit-store-node-cache.adapter.d.ts +0 -11
- package/dist/rate-limit-store-node-cache.adapter.d.ts.map +0 -1
- package/dist/rate-limit-store-node-cache.adapter.js +0 -24
- package/dist/rate-limit-store-node-cache.adapter.js.map +0 -1
- package/dist/rate-limit-store.port.d.ts +0 -8
- package/dist/rate-limit-store.port.d.ts.map +0 -1
- package/dist/rate-limit-store.port.js +0 -2
- package/dist/rate-limit-store.port.js.map +0 -1
- package/src/cache-resolver.service.ts +0 -74
- package/src/rate-limit-store-node-cache.adapter.ts +0 -28
- package/src/rate-limit-store.port.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgord/bun",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Bartosz Gordon",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"preinstall": "bunx only-allow bun"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@biomejs/biome": "2.3.
|
|
23
|
+
"@biomejs/biome": "2.3.10",
|
|
24
24
|
"@commitlint/cli": "20.2.0",
|
|
25
25
|
"@commitlint/config-conventional": "20.2.0",
|
|
26
26
|
"@types/bun": "1.3.4",
|
package/readme.md
CHANGED
|
@@ -36,7 +36,11 @@ src/
|
|
|
36
36
|
├── bots.vo.ts
|
|
37
37
|
├── build-info-repository.service.ts
|
|
38
38
|
├── cache-file.service.ts
|
|
39
|
-
├── cache-
|
|
39
|
+
├── cache-repository-node-cache.adapter.ts
|
|
40
|
+
├── cache-repository-noop.adapter.ts
|
|
41
|
+
├── cache-repository.port.ts
|
|
42
|
+
├── cache-resolver-simple.adapter.ts
|
|
43
|
+
├── cache-resolver.port.ts
|
|
40
44
|
├── cache-response.middleware.ts
|
|
41
45
|
├── certificate-inspector-noop.adapter.ts
|
|
42
46
|
├── certificate-inspector-tls.adapter.ts
|
|
@@ -226,8 +230,6 @@ src/
|
|
|
226
230
|
│ ├── timezone-utc.ts
|
|
227
231
|
│ └── translations.ts
|
|
228
232
|
├── prerequisites.service.ts
|
|
229
|
-
├── rate-limit-store-node-cache.adapter.ts
|
|
230
|
-
├── rate-limit-store.port.ts
|
|
231
233
|
├── recaptcha-secret-key.vo.ts
|
|
232
234
|
├── recaptcha-site-key.vo.ts
|
|
233
235
|
├── redactor-compact-array.adapter.ts
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import NodeCache from "node-cache";
|
|
3
|
+
import type { CacheRepositoryKeyType, CacheRepositoryPort } from "./cache-repository.port";
|
|
4
|
+
|
|
5
|
+
export class CacheRepositoryNodeCacheAdapter implements CacheRepositoryPort {
|
|
6
|
+
private readonly store: NodeCache;
|
|
7
|
+
|
|
8
|
+
constructor(private readonly config: { ttl: tools.Duration }) {
|
|
9
|
+
this.store = new NodeCache({
|
|
10
|
+
stdTTL: config.ttl.seconds,
|
|
11
|
+
checkperiod: config.ttl.seconds,
|
|
12
|
+
deleteOnExpire: true,
|
|
13
|
+
maxKeys: 100_000,
|
|
14
|
+
useClones: false,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async get<T>(key: CacheRepositoryKeyType): Promise<T | null> {
|
|
19
|
+
return this.store.get(key) ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async set<T>(key: CacheRepositoryKeyType, value: T) {
|
|
23
|
+
this.store.set(key, value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async delete(key: CacheRepositoryKeyType) {
|
|
27
|
+
this.store.del(key);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async flush() {
|
|
31
|
+
this.store.flushAll();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get ttl() {
|
|
35
|
+
return this.config.ttl;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { CacheRepositoryPort } from "./cache-repository.port";
|
|
3
|
+
|
|
4
|
+
export class CacheRepositoryNoopAdapter implements CacheRepositoryPort {
|
|
5
|
+
constructor(private readonly config: { ttl: tools.Duration }) {}
|
|
6
|
+
|
|
7
|
+
async get<T>(): Promise<T | null> {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async set() {}
|
|
12
|
+
|
|
13
|
+
async delete() {}
|
|
14
|
+
|
|
15
|
+
async flush() {}
|
|
16
|
+
|
|
17
|
+
get ttl() {
|
|
18
|
+
return this.config.ttl;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
|
|
3
|
+
export type CacheRepositoryKeyType = string;
|
|
4
|
+
|
|
5
|
+
export interface CacheRepositoryPort {
|
|
6
|
+
get<T>(key: CacheRepositoryKeyType): Promise<T | null>;
|
|
7
|
+
set<T>(key: CacheRepositoryKeyType, value: T): Promise<void>;
|
|
8
|
+
delete(key: CacheRepositoryKeyType): Promise<void>;
|
|
9
|
+
flush(): Promise<void>;
|
|
10
|
+
get ttl(): tools.Duration;
|
|
11
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CacheRepositoryKeyType, CacheRepositoryPort } from "./cache-repository.port";
|
|
2
|
+
import { type CacheResolverPort, CacheSourceEnum } from "./cache-resolver.port";
|
|
3
|
+
|
|
4
|
+
type Dependencies = { CacheRepository: CacheRepositoryPort };
|
|
5
|
+
|
|
6
|
+
export class CacheResolverSimpleAdapter implements CacheResolverPort {
|
|
7
|
+
constructor(private readonly deps: Dependencies) {}
|
|
8
|
+
|
|
9
|
+
async resolve<T>(key: CacheRepositoryKeyType, producer: () => Promise<T>): Promise<T> {
|
|
10
|
+
const result = await this.resolveWithContext(key, producer);
|
|
11
|
+
|
|
12
|
+
return result.value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async resolveWithContext<T>(
|
|
16
|
+
key: CacheRepositoryKeyType,
|
|
17
|
+
producer: () => Promise<T>,
|
|
18
|
+
): Promise<{ value: T; source: CacheSourceEnum }> {
|
|
19
|
+
const cached = await this.deps.CacheRepository.get<T>(key);
|
|
20
|
+
|
|
21
|
+
if (cached !== null) return { value: cached, source: CacheSourceEnum.hit };
|
|
22
|
+
|
|
23
|
+
const value = await producer();
|
|
24
|
+
await this.deps.CacheRepository.set(key, value);
|
|
25
|
+
|
|
26
|
+
return { value, source: CacheSourceEnum.miss };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async flush() {
|
|
30
|
+
await this.deps.CacheRepository.flush();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get ttl() {
|
|
34
|
+
return this.deps.CacheRepository.ttl;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { CacheRepositoryKeyType } from "./cache-repository.port";
|
|
3
|
+
|
|
4
|
+
export enum CacheSourceEnum {
|
|
5
|
+
hit = "hit",
|
|
6
|
+
miss = "",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface CacheResolverPort {
|
|
10
|
+
resolve<T>(key: CacheRepositoryKeyType, producer: () => Promise<T>): Promise<T>;
|
|
11
|
+
|
|
12
|
+
resolveWithContext<T>(
|
|
13
|
+
key: CacheRepositoryKeyType,
|
|
14
|
+
producer: () => Promise<T>,
|
|
15
|
+
): Promise<{ value: T; source: CacheSourceEnum }>;
|
|
16
|
+
|
|
17
|
+
flush(): Promise<void>;
|
|
18
|
+
|
|
19
|
+
get ttl(): tools.Duration;
|
|
20
|
+
}
|
|
@@ -1,28 +1,54 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
1
2
|
import { createMiddleware } from "hono/factory";
|
|
2
|
-
import type
|
|
3
|
-
import {
|
|
3
|
+
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
4
|
+
import type { CacheResolverPort } from "./cache-resolver.port";
|
|
5
|
+
|
|
6
|
+
type SubjectResolver = (c: Context) => string;
|
|
7
|
+
|
|
8
|
+
type Dependencies = { CacheResolver: CacheResolverPort };
|
|
9
|
+
|
|
10
|
+
type CacheResponseOptions = { enabled: boolean; subject: SubjectResolver };
|
|
11
|
+
|
|
12
|
+
export const CacheResponseSubjectUrl: SubjectResolver = (c: Context) => c.req.url;
|
|
13
|
+
|
|
14
|
+
type CachedResponse = {
|
|
15
|
+
body: string;
|
|
16
|
+
headers: Record<string, string>;
|
|
17
|
+
status: ContentfulStatusCode;
|
|
18
|
+
};
|
|
4
19
|
|
|
5
20
|
export class CacheResponse {
|
|
6
21
|
static readonly CACHE_HIT_HEADER = "Cache-Hit";
|
|
7
22
|
|
|
8
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
private readonly config: CacheResponseOptions,
|
|
25
|
+
private readonly deps: Dependencies,
|
|
26
|
+
) {}
|
|
9
27
|
|
|
10
28
|
handle = createMiddleware(async (c, next) => {
|
|
11
|
-
|
|
29
|
+
if (!this.config.enabled) return next();
|
|
12
30
|
|
|
13
|
-
|
|
14
|
-
c.res.headers.set(CacheResponse.CACHE_HIT_HEADER, CacheHitEnum.hit);
|
|
31
|
+
const subject = this.config.subject(c);
|
|
15
32
|
|
|
16
|
-
|
|
17
|
-
|
|
33
|
+
const result = await this.deps.CacheResolver.resolveWithContext<CachedResponse>(subject, async () => {
|
|
34
|
+
await next();
|
|
18
35
|
|
|
19
|
-
|
|
36
|
+
const response = c.res.clone();
|
|
20
37
|
|
|
21
|
-
|
|
38
|
+
return {
|
|
39
|
+
body: await response.text(),
|
|
40
|
+
headers: response.headers.toJSON(),
|
|
41
|
+
status: response.status as ContentfulStatusCode,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
c.header(CacheResponse.CACHE_HIT_HEADER, result.source);
|
|
46
|
+
|
|
47
|
+
return c.newResponse(result.value.body, result.value.status, result.value.headers);
|
|
22
48
|
});
|
|
23
49
|
|
|
24
50
|
clear = createMiddleware(async (_c, next) => {
|
|
25
|
-
this.
|
|
51
|
+
await this.deps.CacheResolver.flush();
|
|
26
52
|
|
|
27
53
|
return next();
|
|
28
54
|
});
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import type { z } from "zod/v4";
|
|
2
2
|
import type { NodeEnvironmentEnum } from "../src/node-env.vo";
|
|
3
|
-
import type {
|
|
3
|
+
import type { CacheResolverPort } from "./cache-resolver.port";
|
|
4
|
+
import type { EnvironmentLoaderPort } from "./environment-loader.port";
|
|
5
|
+
|
|
6
|
+
type Dependencies = { CacheResolver: CacheResolverPort };
|
|
4
7
|
|
|
5
8
|
export class EnvironmentLoaderProcessSafeAdapter<Schema extends z.ZodObject<any>>
|
|
6
9
|
implements EnvironmentLoaderPort<Schema>
|
|
7
10
|
{
|
|
8
|
-
private cached: Readonly<EnvironmentResultType<Schema>> | null = null;
|
|
9
|
-
|
|
10
11
|
constructor(
|
|
11
|
-
private readonly config: { type: NodeEnvironmentEnum; Schema: Schema },
|
|
12
12
|
private env: NodeJS.ProcessEnv,
|
|
13
|
+
private readonly config: { type: NodeEnvironmentEnum; Schema: Schema },
|
|
14
|
+
private readonly deps: Dependencies,
|
|
13
15
|
) {}
|
|
14
16
|
|
|
15
17
|
async load() {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const result = await this.deps.CacheResolver.resolve("env", async () =>
|
|
19
|
+
this.config.Schema.parse(this.env),
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
for (const key of Object.keys(result)) delete process.env[key];
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return this.cached;
|
|
24
|
+
return Object.freeze({ ...result, type: this.config.type });
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as tools from "@bgord/tools";
|
|
2
2
|
import { createMiddleware } from "hono/factory";
|
|
3
|
-
import {
|
|
3
|
+
import { CacheSourceEnum } from "./cache-resolver.port";
|
|
4
4
|
import { CacheResponse } from "./cache-response.middleware";
|
|
5
5
|
import { ClientFromHonoAdapter } from "./client-from-hono.adapter";
|
|
6
6
|
import type { ClockPort } from "./clock.port";
|
|
@@ -93,7 +93,7 @@ export class HttpLogger {
|
|
|
93
93
|
status: response.status,
|
|
94
94
|
durationMs: duration.ms,
|
|
95
95
|
client,
|
|
96
|
-
cacheHit: response.headers.get(CacheResponse.CACHE_HIT_HEADER) ===
|
|
96
|
+
cacheHit: response.headers.get(CacheResponse.CACHE_HIT_HEADER) === CacheSourceEnum.hit,
|
|
97
97
|
metadata: { response: await HttpLogger.parseJSON(response) },
|
|
98
98
|
});
|
|
99
99
|
});
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,11 @@ export * from "./better-auth-logger.service";
|
|
|
9
9
|
export * from "./binary.vo";
|
|
10
10
|
export * from "./build-info-repository.service";
|
|
11
11
|
export * from "./cache-file.service";
|
|
12
|
-
export * from "./cache-
|
|
12
|
+
export * from "./cache-repository.port";
|
|
13
|
+
export * from "./cache-repository-node-cache.adapter";
|
|
14
|
+
export * from "./cache-repository-noop.adapter";
|
|
15
|
+
export * from "./cache-resolver.port";
|
|
16
|
+
export * from "./cache-resolver-simple.adapter";
|
|
13
17
|
export * from "./cache-response.middleware";
|
|
14
18
|
export * from "./certificate-inspector.port";
|
|
15
19
|
export * from "./certificate-inspector-noop.adapter";
|
|
@@ -146,8 +150,6 @@ export * from "./pdf-generator-noop.adapter";
|
|
|
146
150
|
export * from "./port.vo";
|
|
147
151
|
export * from "./prerequisites/index";
|
|
148
152
|
export * from "./prerequisites.service";
|
|
149
|
-
export * from "./rate-limit-store.port";
|
|
150
|
-
export * from "./rate-limit-store-node-cache.adapter";
|
|
151
153
|
export * from "./recaptcha-secret-key.vo";
|
|
152
154
|
export * from "./recaptcha-site-key.vo";
|
|
153
155
|
export * from "./redactor.port";
|
|
@@ -28,7 +28,7 @@ export class JobHandler {
|
|
|
28
28
|
try {
|
|
29
29
|
this.deps.Logger.info({ message: `${uow.label} start`, correlationId, ...this.base });
|
|
30
30
|
|
|
31
|
-
await CorrelationStorage.run(correlationId, uow.process);
|
|
31
|
+
await CorrelationStorage.run(correlationId, async () => uow.process());
|
|
32
32
|
|
|
33
33
|
this.deps.Logger.info({
|
|
34
34
|
message: `${uow.label} success`,
|
|
@@ -2,17 +2,17 @@ import * as tools from "@bgord/tools";
|
|
|
2
2
|
import type { Context } from "hono";
|
|
3
3
|
import { createMiddleware } from "hono/factory";
|
|
4
4
|
import { HTTPException } from "hono/http-exception";
|
|
5
|
+
import type { CacheResolverPort } from "./cache-resolver.port";
|
|
5
6
|
import type { ClockPort } from "./clock.port";
|
|
6
|
-
import type { RateLimitStorePort } from "./rate-limit-store.port";
|
|
7
7
|
import type { ShieldPort } from "./shield.port";
|
|
8
8
|
|
|
9
9
|
type SubjectResolver = (c: Context) => string;
|
|
10
|
-
type ShieldRateLimitOptionsType = { enabled: boolean;
|
|
10
|
+
type ShieldRateLimitOptionsType = { enabled: boolean; subject: SubjectResolver };
|
|
11
11
|
|
|
12
|
-
type Dependencies = { Clock: ClockPort };
|
|
12
|
+
type Dependencies = { Clock: ClockPort; CacheResolver: CacheResolverPort };
|
|
13
13
|
|
|
14
|
-
export const
|
|
15
|
-
export const
|
|
14
|
+
export const RateLimitSubjectAnon: SubjectResolver = () => "anon";
|
|
15
|
+
export const RateLimitSubjectUser: SubjectResolver = (c) => c.get("user")?.id ?? "anon";
|
|
16
16
|
|
|
17
17
|
export const TooManyRequestsError = new HTTPException(429, { message: "app.too_many_requests" });
|
|
18
18
|
|
|
@@ -27,18 +27,14 @@ export class ShieldRateLimitAdapter implements ShieldPort {
|
|
|
27
27
|
|
|
28
28
|
const subject = this.options.subject(c);
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const limiter = await this.deps.CacheResolver.resolve(
|
|
31
|
+
subject,
|
|
32
|
+
async () => new tools.RateLimiter(this.deps.CacheResolver.ttl),
|
|
33
|
+
);
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
limiter = new tools.RateLimiter(this.options.store.ttl);
|
|
34
|
-
this.options.store.set(subject, limiter);
|
|
35
|
-
}
|
|
35
|
+
const result = limiter.verify(this.deps.Clock.now());
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (!check.allowed) throw TooManyRequestsError;
|
|
40
|
-
|
|
41
|
-
this.options.store.set(subject, limiter);
|
|
37
|
+
if (!result.allowed) throw TooManyRequestsError;
|
|
42
38
|
|
|
43
39
|
return next();
|
|
44
40
|
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { Context } from "hono";
|
|
2
|
-
import type NodeCache from "node-cache";
|
|
3
|
-
import type { Key } from "node-cache";
|
|
4
|
-
type Resolver<T> = () => Promise<T>;
|
|
5
|
-
type BaseOptions<T> = {
|
|
6
|
-
key: Key;
|
|
7
|
-
resolver: Resolver<T>;
|
|
8
|
-
};
|
|
9
|
-
type CacheResolverSimpleResult<T> = {
|
|
10
|
-
data: T;
|
|
11
|
-
};
|
|
12
|
-
type CacheResolverWithMetadataResult<T> = {
|
|
13
|
-
data: T;
|
|
14
|
-
meta: {
|
|
15
|
-
hit: CacheHitEnum;
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
type CacheResolverRequestHeadersResult<T> = {
|
|
19
|
-
data: T;
|
|
20
|
-
header: {
|
|
21
|
-
name: "cache-hit";
|
|
22
|
-
value: CacheHitEnum;
|
|
23
|
-
};
|
|
24
|
-
respond: (c: Context) => Promise<void>;
|
|
25
|
-
};
|
|
26
|
-
export declare enum CacheHitEnum {
|
|
27
|
-
hit = "hit",
|
|
28
|
-
miss = "miss"
|
|
29
|
-
}
|
|
30
|
-
export declare enum CacheResolverStrategy {
|
|
31
|
-
simple = "simple",
|
|
32
|
-
with_metadata = "with_metadata",
|
|
33
|
-
request_headers = "request_headers"
|
|
34
|
-
}
|
|
35
|
-
export declare class CacheResolver {
|
|
36
|
-
static resolve<T>(cache: NodeCache, options: BaseOptions<T> & {
|
|
37
|
-
strategy?: CacheResolverStrategy.simple;
|
|
38
|
-
}): Promise<CacheResolverSimpleResult<T>>;
|
|
39
|
-
static resolve<T>(cache: NodeCache, options: BaseOptions<T> & {
|
|
40
|
-
strategy: CacheResolverStrategy.with_metadata;
|
|
41
|
-
}): Promise<CacheResolverWithMetadataResult<T>>;
|
|
42
|
-
static resolve<T>(cache: NodeCache, options: BaseOptions<T> & {
|
|
43
|
-
strategy: CacheResolverStrategy.request_headers;
|
|
44
|
-
}): Promise<CacheResolverRequestHeadersResult<T>>;
|
|
45
|
-
}
|
|
46
|
-
export {};
|
|
47
|
-
//# sourceMappingURL=cache-resolver.service.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache-resolver.service.d.ts","sourceRoot":"","sources":["../src/cache-resolver.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,SAAS,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,QAAQ,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;AACpC,KAAK,WAAW,CAAC,CAAC,IAAI;IAAE,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC;AAC1D,KAAK,yBAAyB,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,CAAC;AAChD,KAAK,+BAA+B,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE;QAAE,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;CAAE,CAAC;AACnF,KAAK,iCAAiC,CAAC,CAAC,IAAI;IAC1C,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAC;IACnD,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAEF,oBAAY,YAAY;IACtB,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,oBAAY,qBAAqB;IAC/B,MAAM,WAAW;IACjB,aAAa,kBAAkB;IAC/B,eAAe,oBAAoB;CACpC;AAED,qBAAa,aAAa;WACX,OAAO,CAAC,CAAC,EACpB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,qBAAqB,CAAC,MAAM,CAAA;KAAE,GACpE,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC;WAE3B,OAAO,CAAC,CAAC,EACpB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;QAAE,QAAQ,EAAE,qBAAqB,CAAC,aAAa,CAAA;KAAE,GAC1E,OAAO,CAAC,+BAA+B,CAAC,CAAC,CAAC,CAAC;WAEjC,OAAO,CAAC,CAAC,EACpB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;QAAE,QAAQ,EAAE,qBAAqB,CAAC,eAAe,CAAA;KAAE,GAC5E,OAAO,CAAC,iCAAiC,CAAC,CAAC,CAAC,CAAC;CAkCjD"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export var CacheHitEnum;
|
|
2
|
-
(function (CacheHitEnum) {
|
|
3
|
-
CacheHitEnum["hit"] = "hit";
|
|
4
|
-
CacheHitEnum["miss"] = "miss";
|
|
5
|
-
})(CacheHitEnum || (CacheHitEnum = {}));
|
|
6
|
-
export var CacheResolverStrategy;
|
|
7
|
-
(function (CacheResolverStrategy) {
|
|
8
|
-
CacheResolverStrategy["simple"] = "simple";
|
|
9
|
-
CacheResolverStrategy["with_metadata"] = "with_metadata";
|
|
10
|
-
CacheResolverStrategy["request_headers"] = "request_headers";
|
|
11
|
-
})(CacheResolverStrategy || (CacheResolverStrategy = {}));
|
|
12
|
-
export class CacheResolver {
|
|
13
|
-
static async resolve(cache, options) {
|
|
14
|
-
const strategy = options.strategy ?? CacheResolverStrategy.simple;
|
|
15
|
-
const cached = cache.get(options.key);
|
|
16
|
-
const hit = cached !== undefined;
|
|
17
|
-
const data = hit ? cached : await options.resolver();
|
|
18
|
-
if (!hit)
|
|
19
|
-
cache.set(options.key, data);
|
|
20
|
-
switch (strategy) {
|
|
21
|
-
case CacheResolverStrategy.with_metadata:
|
|
22
|
-
return { data, meta: { hit: hit ? CacheHitEnum.hit : CacheHitEnum.miss } };
|
|
23
|
-
case CacheResolverStrategy.request_headers:
|
|
24
|
-
return {
|
|
25
|
-
data,
|
|
26
|
-
respond: (c) => {
|
|
27
|
-
c.header("cache-hit", hit ? CacheHitEnum.hit : CacheHitEnum.miss);
|
|
28
|
-
return c.json(data);
|
|
29
|
-
},
|
|
30
|
-
header: { name: "cache-hit", value: hit ? CacheHitEnum.hit : CacheHitEnum.miss },
|
|
31
|
-
};
|
|
32
|
-
default:
|
|
33
|
-
return { data };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=cache-resolver.service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cache-resolver.service.js","sourceRoot":"","sources":["../src/cache-resolver.service.ts"],"names":[],"mappings":"AAcA,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,2BAAW,CAAA;IACX,6BAAa,CAAA;AACf,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AAED,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,0CAAiB,CAAA;IACjB,wDAA+B,CAAA;IAC/B,4DAAmC,CAAA;AACrC,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC;AAED,MAAM,OAAO,aAAa;IAgBxB,MAAM,CAAC,KAAK,CAAC,OAAO,CAClB,KAAgB,EAChB,OAA8D;QAE9D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,qBAAqB,CAAC,MAAM,CAAC;QAElE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAI,OAAO,CAAC,GAAG,CAAC,CAAC;QAEzC,MAAM,GAAG,GAAG,MAAM,KAAK,SAAS,CAAC;QAEjC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAErD,IAAI,CAAC,GAAG;YAAE,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAEvC,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,qBAAqB,CAAC,aAAa;gBACtC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;YAE7E,KAAK,qBAAqB,CAAC,eAAe;gBACxC,OAAO;oBACL,IAAI;oBACJ,OAAO,EAAE,CAAC,CAAU,EAAE,EAAE;wBACtB,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;wBAClE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACtB,CAAC;oBACD,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE;iBACjF,CAAC;YAEJ;gBACE,OAAO,EAAE,IAAI,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type * as tools from "@bgord/tools";
|
|
2
|
-
import type { RateLimitStorePort, RateLimitStoreSubjectType } from "./rate-limit-store.port";
|
|
3
|
-
export declare class RateLimitStoreNodeCacheAdapter implements RateLimitStorePort {
|
|
4
|
-
readonly ttl: tools.Duration;
|
|
5
|
-
private readonly store;
|
|
6
|
-
constructor(ttl: tools.Duration);
|
|
7
|
-
get(subject: RateLimitStoreSubjectType): Promise<tools.RateLimiter | undefined>;
|
|
8
|
-
set(subject: RateLimitStoreSubjectType, limiter: tools.RateLimiter): Promise<void>;
|
|
9
|
-
flushAll(): void;
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=rate-limit-store-node-cache.adapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-store-node-cache.adapter.d.ts","sourceRoot":"","sources":["../src/rate-limit-store-node-cache.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAE7F,qBAAa,8BAA+B,YAAW,kBAAkB;IAG3D,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ;IAFxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;gBAEb,GAAG,EAAE,KAAK,CAAC,QAAQ;IASlC,GAAG,CAAC,OAAO,EAAE,yBAAyB;IAItC,GAAG,CAAC,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW;IAIxE,QAAQ;CAGT"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import NodeCache from "node-cache";
|
|
2
|
-
export class RateLimitStoreNodeCacheAdapter {
|
|
3
|
-
ttl;
|
|
4
|
-
store;
|
|
5
|
-
constructor(ttl) {
|
|
6
|
-
this.ttl = ttl;
|
|
7
|
-
this.store = new NodeCache({
|
|
8
|
-
stdTTL: this.ttl.seconds,
|
|
9
|
-
checkperiod: this.ttl.seconds,
|
|
10
|
-
deleteOnExpire: true,
|
|
11
|
-
maxKeys: 100_000,
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
async get(subject) {
|
|
15
|
-
return this.store.get(subject);
|
|
16
|
-
}
|
|
17
|
-
async set(subject, limiter) {
|
|
18
|
-
this.store.set(subject, limiter);
|
|
19
|
-
}
|
|
20
|
-
flushAll() {
|
|
21
|
-
this.store.flushAll();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
//# sourceMappingURL=rate-limit-store-node-cache.adapter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-store-node-cache.adapter.js","sourceRoot":"","sources":["../src/rate-limit-store-node-cache.adapter.ts"],"names":[],"mappings":"AACA,OAAO,SAAS,MAAM,YAAY,CAAC;AAGnC,MAAM,OAAO,8BAA8B;IAGpB;IAFJ,KAAK,CAAY;IAElC,YAAqB,GAAmB;QAAnB,QAAG,GAAH,GAAG,CAAgB;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,SAAS,CAAC;YACzB,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO;YACxB,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO;YAC7B,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAAkC;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,OAAkC,EAAE,OAA0B;QACtE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type * as tools from "@bgord/tools";
|
|
2
|
-
export type RateLimitStoreSubjectType = string;
|
|
3
|
-
export interface RateLimitStorePort {
|
|
4
|
-
readonly ttl: tools.Duration;
|
|
5
|
-
get(subject: RateLimitStoreSubjectType): Promise<tools.RateLimiter | undefined>;
|
|
6
|
-
set(subject: RateLimitStoreSubjectType, limiter: tools.RateLimiter): Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=rate-limit-store.port.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-store.port.d.ts","sourceRoot":"","sources":["../src/rate-limit-store.port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAE3C,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC;IAC7B,GAAG,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAChF,GAAG,CAAC,OAAO,EAAE,yBAAyB,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-store.port.js","sourceRoot":"","sources":["../src/rate-limit-store.port.ts"],"names":[],"mappings":""}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import type { Context } from "hono";
|
|
2
|
-
import type NodeCache from "node-cache";
|
|
3
|
-
import type { Key } from "node-cache";
|
|
4
|
-
|
|
5
|
-
type Resolver<T> = () => Promise<T>;
|
|
6
|
-
type BaseOptions<T> = { key: Key; resolver: Resolver<T> };
|
|
7
|
-
type CacheResolverSimpleResult<T> = { data: T };
|
|
8
|
-
type CacheResolverWithMetadataResult<T> = { data: T; meta: { hit: CacheHitEnum } };
|
|
9
|
-
type CacheResolverRequestHeadersResult<T> = {
|
|
10
|
-
data: T;
|
|
11
|
-
header: { name: "cache-hit"; value: CacheHitEnum };
|
|
12
|
-
respond: (c: Context) => Promise<void>;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export enum CacheHitEnum {
|
|
16
|
-
hit = "hit",
|
|
17
|
-
miss = "miss",
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export enum CacheResolverStrategy {
|
|
21
|
-
simple = "simple",
|
|
22
|
-
with_metadata = "with_metadata",
|
|
23
|
-
request_headers = "request_headers",
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export class CacheResolver {
|
|
27
|
-
static async resolve<T>(
|
|
28
|
-
cache: NodeCache,
|
|
29
|
-
options: BaseOptions<T> & { strategy?: CacheResolverStrategy.simple },
|
|
30
|
-
): Promise<CacheResolverSimpleResult<T>>;
|
|
31
|
-
|
|
32
|
-
static async resolve<T>(
|
|
33
|
-
cache: NodeCache,
|
|
34
|
-
options: BaseOptions<T> & { strategy: CacheResolverStrategy.with_metadata },
|
|
35
|
-
): Promise<CacheResolverWithMetadataResult<T>>;
|
|
36
|
-
|
|
37
|
-
static async resolve<T>(
|
|
38
|
-
cache: NodeCache,
|
|
39
|
-
options: BaseOptions<T> & { strategy: CacheResolverStrategy.request_headers },
|
|
40
|
-
): Promise<CacheResolverRequestHeadersResult<T>>;
|
|
41
|
-
|
|
42
|
-
static async resolve<T>(
|
|
43
|
-
cache: NodeCache,
|
|
44
|
-
options: BaseOptions<T> & { strategy?: CacheResolverStrategy },
|
|
45
|
-
): Promise<any> {
|
|
46
|
-
const strategy = options.strategy ?? CacheResolverStrategy.simple;
|
|
47
|
-
|
|
48
|
-
const cached = cache.get<T>(options.key);
|
|
49
|
-
|
|
50
|
-
const hit = cached !== undefined;
|
|
51
|
-
|
|
52
|
-
const data = hit ? cached : await options.resolver();
|
|
53
|
-
|
|
54
|
-
if (!hit) cache.set(options.key, data);
|
|
55
|
-
|
|
56
|
-
switch (strategy) {
|
|
57
|
-
case CacheResolverStrategy.with_metadata:
|
|
58
|
-
return { data, meta: { hit: hit ? CacheHitEnum.hit : CacheHitEnum.miss } };
|
|
59
|
-
|
|
60
|
-
case CacheResolverStrategy.request_headers:
|
|
61
|
-
return {
|
|
62
|
-
data,
|
|
63
|
-
respond: (c: Context) => {
|
|
64
|
-
c.header("cache-hit", hit ? CacheHitEnum.hit : CacheHitEnum.miss);
|
|
65
|
-
return c.json(data);
|
|
66
|
-
},
|
|
67
|
-
header: { name: "cache-hit", value: hit ? CacheHitEnum.hit : CacheHitEnum.miss },
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
default:
|
|
71
|
-
return { data };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type * as tools from "@bgord/tools";
|
|
2
|
-
import NodeCache from "node-cache";
|
|
3
|
-
import type { RateLimitStorePort, RateLimitStoreSubjectType } from "./rate-limit-store.port";
|
|
4
|
-
|
|
5
|
-
export class RateLimitStoreNodeCacheAdapter implements RateLimitStorePort {
|
|
6
|
-
private readonly store: NodeCache;
|
|
7
|
-
|
|
8
|
-
constructor(readonly ttl: tools.Duration) {
|
|
9
|
-
this.store = new NodeCache({
|
|
10
|
-
stdTTL: this.ttl.seconds,
|
|
11
|
-
checkperiod: this.ttl.seconds,
|
|
12
|
-
deleteOnExpire: true,
|
|
13
|
-
maxKeys: 100_000,
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async get(subject: RateLimitStoreSubjectType) {
|
|
18
|
-
return this.store.get<tools.RateLimiter>(subject);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async set(subject: RateLimitStoreSubjectType, limiter: tools.RateLimiter) {
|
|
22
|
-
this.store.set(subject, limiter);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
flushAll() {
|
|
26
|
-
this.store.flushAll();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type * as tools from "@bgord/tools";
|
|
2
|
-
|
|
3
|
-
export type RateLimitStoreSubjectType = string;
|
|
4
|
-
|
|
5
|
-
export interface RateLimitStorePort {
|
|
6
|
-
readonly ttl: tools.Duration;
|
|
7
|
-
get(subject: RateLimitStoreSubjectType): Promise<tools.RateLimiter | undefined>;
|
|
8
|
-
set(subject: RateLimitStoreSubjectType, limiter: tools.RateLimiter): Promise<void>;
|
|
9
|
-
}
|