@bgord/bun 0.4.0 → 0.6.0
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/api-key-shield.d.ts +14 -13
- package/dist/api-key-shield.d.ts.map +1 -0
- package/dist/api-key-shield.js +19 -0
- package/dist/api-key-shield.js.map +1 -0
- package/dist/api-version.d.ts +6 -5
- package/dist/api-version.d.ts.map +1 -0
- package/dist/api-version.js +12 -0
- package/dist/api-version.js.map +1 -0
- package/dist/auth-shield.d.ts +31 -29
- package/dist/auth-shield.d.ts.map +1 -0
- package/dist/auth-shield.js +83 -0
- package/dist/auth-shield.js.map +1 -0
- package/dist/build-info-repository.d.ts +5 -3
- package/dist/build-info-repository.d.ts.map +1 -0
- package/dist/build-info-repository.js +18 -0
- package/dist/build-info-repository.js.map +1 -0
- package/dist/cache-resolver.d.ts +46 -0
- package/dist/cache-resolver.d.ts.map +1 -0
- package/dist/cache-resolver.js +44 -0
- package/dist/cache-resolver.js.map +1 -0
- package/dist/cache-response.d.ts +9 -12
- package/dist/cache-response.d.ts.map +1 -0
- package/dist/cache-response.js +25 -0
- package/dist/cache-response.js.map +1 -0
- package/dist/cache-static-files.d.ts +9 -8
- package/dist/cache-static-files.d.ts.map +1 -0
- package/dist/cache-static-files.js +25 -0
- package/dist/cache-static-files.js.map +1 -0
- package/dist/context.d.ts +14 -9
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +11 -0
- package/dist/context.js.map +1 -0
- package/dist/correlation-id.d.ts +4 -0
- package/dist/correlation-id.d.ts.map +1 -0
- package/dist/correlation-id.js +3 -0
- package/dist/correlation-id.js.map +1 -0
- package/dist/download-file.d.ts +13 -12
- package/dist/download-file.d.ts.map +1 -0
- package/dist/download-file.js +11 -0
- package/dist/download-file.js.map +1 -0
- package/dist/etag-extractor.d.ts +11 -15
- package/dist/etag-extractor.d.ts.map +1 -0
- package/dist/etag-extractor.js +18 -0
- package/dist/etag-extractor.js.map +1 -0
- package/dist/file-uploader.d.ts +13 -12
- package/dist/file-uploader.d.ts.map +1 -0
- package/dist/file-uploader.js +35 -0
- package/dist/file-uploader.js.map +1 -0
- package/dist/graceful-shutdown.d.ts +7 -6
- package/dist/graceful-shutdown.d.ts.map +1 -0
- package/dist/graceful-shutdown.js +32 -0
- package/dist/graceful-shutdown.js.map +1 -0
- package/dist/healthcheck.d.ts +22 -20
- package/dist/healthcheck.d.ts.map +1 -0
- package/dist/healthcheck.js +35 -0
- package/dist/healthcheck.js.map +1 -0
- package/dist/http-logger.d.ts +7 -7
- package/dist/http-logger.d.ts.map +1 -0
- package/dist/http-logger.js +89 -0
- package/dist/http-logger.js.map +1 -0
- package/dist/i18n.d.ts +22 -26
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +35 -0
- package/dist/i18n.js.map +1 -0
- package/dist/image-processor.d.ts +5 -4
- package/dist/image-processor.d.ts.map +1 -0
- package/dist/image-processor.js +5 -0
- package/dist/image-processor.js.map +1 -0
- package/dist/index.d.ts +37 -17
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs.d.ts +1 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +72 -0
- package/dist/jobs.js.map +1 -0
- package/dist/logger.d.ts +23 -7
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +87 -0
- package/dist/logger.js.map +1 -0
- package/dist/mailer.d.ts +10 -1
- package/dist/mailer.d.ts.map +1 -0
- package/dist/mailer.js +27 -0
- package/dist/mailer.js.map +1 -0
- package/dist/memory-consumption.d.ts +3 -2
- package/dist/memory-consumption.d.ts.map +1 -0
- package/dist/memory-consumption.js +8 -0
- package/dist/memory-consumption.js.map +1 -0
- package/dist/new-uuid.d.ts +4 -0
- package/dist/new-uuid.d.ts.map +1 -0
- package/dist/new-uuid.js +6 -0
- package/dist/new-uuid.js.map +1 -0
- package/dist/node-env.vo.d.ts +9 -0
- package/dist/node-env.vo.d.ts.map +1 -0
- package/dist/node-env.vo.js +10 -0
- package/dist/node-env.vo.js.map +1 -0
- package/dist/passwords.d.ts +21 -0
- package/dist/passwords.d.ts.map +1 -0
- package/dist/passwords.js +42 -0
- package/dist/passwords.js.map +1 -0
- package/dist/path.d.ts +4 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +3 -0
- package/dist/path.js.map +1 -0
- package/dist/port.d.ts +4 -0
- package/dist/port.d.ts.map +1 -0
- package/dist/port.js +3 -0
- package/dist/port.js.map +1 -0
- package/dist/prerequisites/binary.d.ts +4 -3
- package/dist/prerequisites/binary.d.ts.map +1 -0
- package/dist/prerequisites/binary.js +29 -0
- package/dist/prerequisites/binary.js.map +1 -0
- package/dist/prerequisites/bun.d.ts +7 -4
- package/dist/prerequisites/bun.d.ts.map +1 -0
- package/dist/prerequisites/bun.js +18 -0
- package/dist/prerequisites/bun.js.map +1 -0
- package/dist/prerequisites/index.d.ts +17 -0
- package/dist/prerequisites/index.d.ts.map +1 -0
- package/dist/prerequisites/index.js +17 -0
- package/dist/prerequisites/index.js.map +1 -0
- package/dist/prerequisites/jobs.d.ts +4 -2
- package/dist/prerequisites/jobs.d.ts.map +1 -0
- package/dist/prerequisites/jobs.js +16 -0
- package/dist/prerequisites/jobs.js.map +1 -0
- package/dist/prerequisites/log-file.d.ts +15 -0
- package/dist/prerequisites/log-file.d.ts.map +1 -0
- package/dist/prerequisites/log-file.js +22 -0
- package/dist/prerequisites/log-file.js.map +1 -0
- package/dist/prerequisites/mailer.d.ts +4 -2
- package/dist/prerequisites/mailer.d.ts.map +1 -0
- package/dist/prerequisites/mailer.js +21 -0
- package/dist/prerequisites/mailer.js.map +1 -0
- package/dist/prerequisites/memory.d.ts +6 -4
- package/dist/prerequisites/memory.d.ts.map +1 -0
- package/dist/prerequisites/memory.js +20 -0
- package/dist/prerequisites/memory.js.map +1 -0
- package/dist/prerequisites/node.d.ts +6 -4
- package/dist/prerequisites/node.d.ts.map +1 -0
- package/dist/prerequisites/node.js +23 -0
- package/dist/prerequisites/node.js.map +1 -0
- package/dist/prerequisites/outside-connectivity.d.ts +4 -2
- package/dist/prerequisites/outside-connectivity.d.ts.map +1 -0
- package/dist/prerequisites/outside-connectivity.js +21 -0
- package/dist/prerequisites/outside-connectivity.js.map +1 -0
- package/dist/prerequisites/path.d.ts +4 -2
- package/dist/prerequisites/path.d.ts.map +1 -0
- package/dist/prerequisites/path.js +26 -0
- package/dist/prerequisites/path.js.map +1 -0
- package/dist/prerequisites/port.d.ts +6 -4
- package/dist/prerequisites/port.d.ts.map +1 -0
- package/dist/prerequisites/port.js +26 -0
- package/dist/prerequisites/port.js.map +1 -0
- package/dist/prerequisites/ram.d.ts +6 -4
- package/dist/prerequisites/ram.d.ts.map +1 -0
- package/dist/prerequisites/ram.js +23 -0
- package/dist/prerequisites/ram.js.map +1 -0
- package/dist/prerequisites/self.d.ts +4 -2
- package/dist/prerequisites/self.d.ts.map +1 -0
- package/dist/prerequisites/self.js +15 -0
- package/dist/prerequisites/self.js.map +1 -0
- package/dist/prerequisites/space.d.ts +6 -4
- package/dist/prerequisites/space.d.ts.map +1 -0
- package/dist/prerequisites/space.js +26 -0
- package/dist/prerequisites/space.js.map +1 -0
- package/dist/prerequisites/ssl-certificate-expiry.d.ts +4 -2
- package/dist/prerequisites/ssl-certificate-expiry.d.ts.map +1 -0
- package/dist/prerequisites/ssl-certificate-expiry.js +24 -0
- package/dist/prerequisites/ssl-certificate-expiry.js.map +1 -0
- package/dist/prerequisites/timezone-utc.d.ts +6 -4
- package/dist/prerequisites/timezone-utc.d.ts.map +1 -0
- package/dist/prerequisites/timezone-utc.js +22 -0
- package/dist/prerequisites/timezone-utc.js.map +1 -0
- package/dist/prerequisites/translations.d.ts +4 -2
- package/dist/prerequisites/translations.d.ts.map +1 -0
- package/dist/prerequisites/translations.js +59 -0
- package/dist/prerequisites/translations.js.map +1 -0
- package/dist/prerequisites.d.ts +2 -0
- package/dist/prerequisites.d.ts.map +1 -0
- package/dist/prerequisites.js +83 -0
- package/dist/prerequisites.js.map +1 -0
- package/dist/rate-limit-shield.d.ts +9 -8
- package/dist/rate-limit-shield.d.ts.map +1 -0
- package/dist/rate-limit-shield.js +18 -0
- package/dist/rate-limit-shield.js.map +1 -0
- package/dist/session-id.d.ts +7 -0
- package/dist/session-id.d.ts.map +1 -0
- package/dist/session-id.js +10 -0
- package/dist/session-id.js.map +1 -0
- package/dist/setup.d.ts +9 -7
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +39 -0
- package/dist/setup.js.map +1 -0
- package/dist/time-zone-offset.d.ts +15 -14
- package/dist/time-zone-offset.d.ts.map +1 -0
- package/dist/time-zone-offset.js +22 -0
- package/dist/time-zone-offset.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/uptime.d.ts +4 -4
- package/dist/uptime.d.ts.map +1 -0
- package/dist/uptime.js +10 -0
- package/dist/uptime.js.map +1 -0
- package/dist/username.d.ts +11 -0
- package/dist/username.d.ts.map +1 -0
- package/dist/username.js +13 -0
- package/dist/username.js.map +1 -0
- package/dist/uuid.d.ts +4 -3
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +4 -0
- package/dist/uuid.js.map +1 -0
- package/dist/weak-etag-extractor.d.ts +7 -0
- package/dist/weak-etag-extractor.d.ts.map +1 -0
- package/dist/weak-etag-extractor.js +18 -0
- package/dist/weak-etag-extractor.js.map +1 -0
- package/package.json +29 -28
- package/src/api-key-shield.ts +2 -2
- package/src/api-version.ts +3 -2
- package/src/auth-shield.ts +14 -23
- package/src/build-info-repository.ts +26 -0
- package/src/cache-resolver.ts +93 -0
- package/src/cache-response.ts +2 -5
- package/src/cache-static-files.ts +3 -3
- package/src/context.ts +9 -4
- package/src/correlation-id.ts +6 -0
- package/src/download-file.ts +2 -2
- package/src/etag-extractor.ts +5 -20
- package/src/file-uploader.ts +4 -4
- package/src/graceful-shutdown.ts +3 -3
- package/src/healthcheck.ts +30 -20
- package/src/http-logger.ts +10 -6
- package/src/i18n.ts +13 -47
- package/src/index.ts +26 -7
- package/src/jobs.ts +91 -0
- package/src/logger.ts +156 -0
- package/src/mailer.ts +48 -0
- package/src/memory-consumption.ts +9 -0
- package/src/new-uuid.ts +5 -0
- package/src/node-env.vo.ts +9 -0
- package/src/passwords.ts +55 -0
- package/src/path.ts +4 -0
- package/src/port.ts +4 -0
- package/src/prerequisites/binary.ts +44 -0
- package/src/prerequisites/bun.ts +32 -0
- package/src/prerequisites/index.ts +16 -0
- package/src/prerequisites/jobs.ts +28 -0
- package/src/prerequisites/log-file.ts +35 -0
- package/src/prerequisites/mailer.ts +32 -0
- package/src/prerequisites/memory.ts +34 -0
- package/src/prerequisites/node.ts +36 -0
- package/src/prerequisites/outside-connectivity.ts +31 -0
- package/src/prerequisites/path.ts +41 -0
- package/src/prerequisites/port.ts +44 -0
- package/src/prerequisites/ram.ts +35 -0
- package/src/prerequisites/self.ts +24 -0
- package/src/prerequisites/space.ts +39 -0
- package/src/prerequisites/ssl-certificate-expiry.ts +37 -0
- package/src/prerequisites/timezone-utc.ts +34 -0
- package/src/prerequisites/translations.ts +92 -0
- package/src/prerequisites.ts +105 -0
- package/src/rate-limit-shield.ts +3 -3
- package/src/session-id.ts +13 -0
- package/src/setup.ts +13 -5
- package/src/time-zone-offset.ts +11 -14
- package/src/uptime.ts +16 -0
- package/src/username.ts +20 -0
- package/src/uuid.ts +6 -0
- package/src/weak-etag-extractor.ts +19 -0
- package/src/image-processor.ts +0 -5
package/package.json
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.4.0",
|
|
3
|
-
"license": "MIT",
|
|
4
2
|
"name": "@bgord/bun",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Bartosz Gordon",
|
|
7
|
-
"
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
8
10
|
"exports": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
11
13
|
},
|
|
12
|
-
"
|
|
13
|
-
"module": "./dist/bgord-bun.module.js",
|
|
14
|
-
"unpkg": "./dist/bgord-bun.umd.js",
|
|
15
|
-
"typings": "./dist/index.d.ts",
|
|
14
|
+
"files": ["dist", "src"],
|
|
16
15
|
"scripts": {
|
|
17
|
-
"build": "
|
|
16
|
+
"build": "tsc --build",
|
|
18
17
|
"preinstall": "bunx only-allow bun"
|
|
19
18
|
},
|
|
20
|
-
"files": ["dist", "src"],
|
|
21
19
|
"devDependencies": {
|
|
22
20
|
"@biomejs/biome": "1.9.4",
|
|
23
|
-
"@commitlint/cli": "19.
|
|
24
|
-
"@commitlint/config-conventional": "19.
|
|
25
|
-
"@types/bun": "1.
|
|
26
|
-
"@types/lodash": "4.17.
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
21
|
+
"@commitlint/cli": "19.8.1",
|
|
22
|
+
"@commitlint/config-conventional": "19.8.1",
|
|
23
|
+
"@types/bun": "1.2.15",
|
|
24
|
+
"@types/lodash": "4.17.17",
|
|
25
|
+
"@types/nodemailer": "6.4.17",
|
|
26
|
+
"cspell": "9.0.2",
|
|
27
|
+
"knip": "5.60.2",
|
|
28
|
+
"lefthook": "1.11.13",
|
|
31
29
|
"only-allow": "1.2.1",
|
|
32
|
-
"shellcheck": "3.
|
|
33
|
-
"
|
|
34
|
-
"typescript": "5.6.3"
|
|
30
|
+
"shellcheck": "3.1.0",
|
|
31
|
+
"typescript": "5.8.3"
|
|
35
32
|
},
|
|
36
33
|
"dependencies": {
|
|
37
|
-
"@bgord/
|
|
38
|
-
"
|
|
34
|
+
"@bgord/tools": "0.6.0",
|
|
35
|
+
"check-disk-space": "3.4.0",
|
|
36
|
+
"croner": "9.0.0",
|
|
37
|
+
"hono": "4.7.11",
|
|
39
38
|
"lodash": "4.17.21",
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
39
|
+
"lucia": "3.2.2",
|
|
40
|
+
"node-cache": "5.1.2",
|
|
41
|
+
"nodemailer": "7.0.3",
|
|
42
|
+
"sharp": "0.34.2",
|
|
43
|
+
"ssl-checker": "2.0.10",
|
|
44
|
+
"winston": "3.17.0"
|
|
44
45
|
}
|
|
45
46
|
}
|
package/src/api-key-shield.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
import { createMiddleware } from "hono/factory";
|
|
3
3
|
import { HTTPException } from "hono/http-exception";
|
|
4
4
|
|
|
5
|
-
type ApiKeyShieldConfigType = { API_KEY:
|
|
5
|
+
type ApiKeyShieldConfigType = { API_KEY: tools.ApiKeyType };
|
|
6
6
|
|
|
7
7
|
export const AccessDeniedApiKeyError = new HTTPException(403, {
|
|
8
8
|
message: "access_denied_api_key",
|
package/src/api-version.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import * as bg from "@bgord/node";
|
|
2
1
|
import { createMiddleware } from "hono/factory";
|
|
3
2
|
|
|
3
|
+
import { BuildInfoRepository } from "./build-info-repository";
|
|
4
|
+
|
|
4
5
|
export class ApiVersion {
|
|
5
6
|
static HEADER_NAME = "api-version";
|
|
6
7
|
|
|
7
8
|
static DEFAULT_API_VERSION = "unknown";
|
|
8
9
|
|
|
9
10
|
static attach = createMiddleware(async (c, next) => {
|
|
10
|
-
const build = await
|
|
11
|
+
const build = await BuildInfoRepository.extract();
|
|
11
12
|
|
|
12
13
|
c.res.headers.set(ApiVersion.HEADER_NAME, build.BUILD_VERSION ?? ApiVersion.DEFAULT_API_VERSION);
|
|
13
14
|
|
package/src/auth-shield.ts
CHANGED
|
@@ -1,47 +1,38 @@
|
|
|
1
|
-
import * as bgn from "@bgord/node";
|
|
2
1
|
import hono from "hono";
|
|
3
2
|
import { createMiddleware } from "hono/factory";
|
|
4
3
|
import { HTTPException } from "hono/http-exception";
|
|
5
4
|
import { Lucia } from "lucia";
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
constructor(cookie: string | undefined, lucia: Lucia) {
|
|
11
|
-
this.value = lucia.readSessionCookie(cookie ?? "");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get(): SessionId["value"] {
|
|
15
|
-
return this.value;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
6
|
+
import { HashedPassword, Password, PasswordType } from "./passwords";
|
|
7
|
+
import { SessionId } from "./session-id";
|
|
8
|
+
import { IdType, Username } from "./username";
|
|
18
9
|
|
|
19
10
|
type AuthShieldConfigType<T> = {
|
|
20
|
-
Username: typeof
|
|
21
|
-
Password: typeof
|
|
22
|
-
HashedPassword: typeof
|
|
11
|
+
Username: typeof Username;
|
|
12
|
+
Password: typeof Password;
|
|
13
|
+
HashedPassword: typeof HashedPassword;
|
|
23
14
|
lucia: Lucia;
|
|
24
|
-
findUniqueUserOrThrow: (username:
|
|
15
|
+
findUniqueUserOrThrow: (username: Username) => Promise<T>;
|
|
25
16
|
};
|
|
26
17
|
|
|
27
18
|
export const AccessDeniedAuthShieldError = new HTTPException(403, {
|
|
28
19
|
message: "access_denied_auth_shield",
|
|
29
20
|
});
|
|
30
21
|
|
|
31
|
-
export class AuthShield<T extends { password:
|
|
22
|
+
export class AuthShield<T extends { password: PasswordType; id: IdType }> {
|
|
32
23
|
private readonly config: AuthShieldConfigType<T>;
|
|
33
24
|
|
|
34
25
|
constructor(
|
|
35
26
|
overrides: Omit<AuthShieldConfigType<T>, "Username" | "Password" | "HashedPassword"> & {
|
|
36
|
-
Username?: typeof
|
|
37
|
-
Password?: typeof
|
|
38
|
-
HashedPassword?: typeof
|
|
27
|
+
Username?: typeof Username;
|
|
28
|
+
Password?: typeof Password;
|
|
29
|
+
HashedPassword?: typeof HashedPassword;
|
|
39
30
|
},
|
|
40
31
|
) {
|
|
41
32
|
const config = {
|
|
42
|
-
Username: overrides.Username ??
|
|
43
|
-
Password: overrides.Password ??
|
|
44
|
-
HashedPassword: overrides.HashedPassword ??
|
|
33
|
+
Username: overrides.Username ?? Username,
|
|
34
|
+
Password: overrides.Password ?? Password,
|
|
35
|
+
HashedPassword: overrides.HashedPassword ?? HashedPassword,
|
|
45
36
|
lucia: overrides.lucia,
|
|
46
37
|
findUniqueUserOrThrow: overrides.findUniqueUserOrThrow,
|
|
47
38
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
|
|
3
|
+
export type BuildInfoType = {
|
|
4
|
+
BUILD_DATE: tools.TimestampType;
|
|
5
|
+
BUILD_VERSION?: tools.BuildVersionType;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export class BuildInfoRepository {
|
|
9
|
+
static async extract(): Promise<BuildInfoType> {
|
|
10
|
+
const BUILD_DATE = Date.now();
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const packageJson = await BuildInfoRepository.getPackageJson();
|
|
14
|
+
|
|
15
|
+
const BUILD_VERSION = tools.BuildVersion.parse(packageJson.version);
|
|
16
|
+
|
|
17
|
+
return { BUILD_DATE, BUILD_VERSION };
|
|
18
|
+
} catch (error) {
|
|
19
|
+
return { BUILD_DATE };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static async getPackageJson() {
|
|
24
|
+
return Bun.file("package.json").json();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Context } from "hono";
|
|
2
|
+
import NodeCache, { Key } from "node-cache";
|
|
3
|
+
|
|
4
|
+
export enum CacheHitEnum {
|
|
5
|
+
hit = "hit",
|
|
6
|
+
miss = "miss",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export enum CacheResolverStrategy {
|
|
10
|
+
simple = "simple",
|
|
11
|
+
with_metadata = "with_metadata",
|
|
12
|
+
request_headers = "request_headers",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type Resolver<T> = () => Promise<T>;
|
|
16
|
+
|
|
17
|
+
type BaseOptions<T> = { key: Key; resolver: Resolver<T> };
|
|
18
|
+
|
|
19
|
+
type CacheResolverSimpleResult<T> = { data: T };
|
|
20
|
+
|
|
21
|
+
type CacheResolverWithMetadataResult<T> = {
|
|
22
|
+
data: T;
|
|
23
|
+
meta: { hit: CacheHitEnum };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type CacheResolverRequestHeadersResult<T> = {
|
|
27
|
+
data: T;
|
|
28
|
+
header: {
|
|
29
|
+
name: "cache-hit";
|
|
30
|
+
value: CacheHitEnum;
|
|
31
|
+
};
|
|
32
|
+
respond: (c: Context) => Promise<void>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export class CacheResolver {
|
|
36
|
+
static async resolve<T>(
|
|
37
|
+
cache: NodeCache,
|
|
38
|
+
options: BaseOptions<T> & { strategy?: CacheResolverStrategy.simple },
|
|
39
|
+
): Promise<CacheResolverSimpleResult<T>>;
|
|
40
|
+
|
|
41
|
+
static async resolve<T>(
|
|
42
|
+
cache: NodeCache,
|
|
43
|
+
options: BaseOptions<T> & { strategy: CacheResolverStrategy.with_metadata },
|
|
44
|
+
): Promise<CacheResolverWithMetadataResult<T>>;
|
|
45
|
+
|
|
46
|
+
static async resolve<T>(
|
|
47
|
+
cache: NodeCache,
|
|
48
|
+
options: BaseOptions<T> & {
|
|
49
|
+
strategy: CacheResolverStrategy.request_headers;
|
|
50
|
+
},
|
|
51
|
+
): Promise<CacheResolverRequestHeadersResult<T>>;
|
|
52
|
+
|
|
53
|
+
static async resolve<T>(
|
|
54
|
+
cache: NodeCache,
|
|
55
|
+
options: BaseOptions<T> & { strategy?: CacheResolverStrategy },
|
|
56
|
+
): Promise<any> {
|
|
57
|
+
const strategy = options.strategy ?? CacheResolverStrategy.simple;
|
|
58
|
+
|
|
59
|
+
const cached = cache.get<T>(options.key);
|
|
60
|
+
|
|
61
|
+
const hit = cached !== undefined;
|
|
62
|
+
|
|
63
|
+
const data = hit ? cached : await options.resolver();
|
|
64
|
+
|
|
65
|
+
if (!hit) cache.set(options.key, data);
|
|
66
|
+
|
|
67
|
+
switch (strategy) {
|
|
68
|
+
case CacheResolverStrategy.with_metadata:
|
|
69
|
+
return {
|
|
70
|
+
data,
|
|
71
|
+
meta: { hit: hit ? CacheHitEnum.hit : CacheHitEnum.miss },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
case CacheResolverStrategy.request_headers:
|
|
75
|
+
return {
|
|
76
|
+
data,
|
|
77
|
+
respond: (c: Context) => {
|
|
78
|
+
c.header("cache-hit", hit ? CacheHitEnum.hit : CacheHitEnum.miss);
|
|
79
|
+
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
return c.json(data);
|
|
82
|
+
},
|
|
83
|
+
header: {
|
|
84
|
+
name: "cache-hit",
|
|
85
|
+
value: hit ? CacheHitEnum.hit : CacheHitEnum.miss,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
default:
|
|
90
|
+
return { data };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/cache-response.ts
CHANGED
|
@@ -2,10 +2,7 @@ import { createMiddleware } from "hono/factory";
|
|
|
2
2
|
import _ from "lodash";
|
|
3
3
|
import NodeCache from "node-cache";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
hit = "hit",
|
|
7
|
-
miss = "miss",
|
|
8
|
-
}
|
|
5
|
+
import { CacheHitEnum } from "./cache-resolver";
|
|
9
6
|
|
|
10
7
|
export class CacheResponse {
|
|
11
8
|
static readonly CACHE_HIT_HEADER = "Cache-Hit";
|
|
@@ -18,7 +15,7 @@ export class CacheResponse {
|
|
|
18
15
|
if (this.cache.has(url)) {
|
|
19
16
|
c.res.headers.set(CacheResponse.CACHE_HIT_HEADER, CacheHitEnum.hit);
|
|
20
17
|
|
|
21
|
-
// @ts-
|
|
18
|
+
// @ts-expect-error
|
|
22
19
|
return c.json(this.cache.get(url));
|
|
23
20
|
}
|
|
24
21
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
import { createMiddleware } from "hono/factory";
|
|
3
3
|
|
|
4
4
|
export enum CacheStaticFilesStrategy {
|
|
@@ -14,10 +14,10 @@ export class CacheStaticFiles {
|
|
|
14
14
|
c.res.headers.set("cache-control", "private, no-cache, no-store, must-revalidate");
|
|
15
15
|
}
|
|
16
16
|
if (strategy === CacheStaticFilesStrategy.always) {
|
|
17
|
-
c.res.headers.set("cache-control", `public, max-age=${
|
|
17
|
+
c.res.headers.set("cache-control", `public, max-age=${tools.Time.Days(365).seconds}, immutable`);
|
|
18
18
|
}
|
|
19
19
|
if (strategy === CacheStaticFilesStrategy.five_minutes) {
|
|
20
|
-
c.res.headers.set("cache-control", `public, max-age=${
|
|
20
|
+
c.res.headers.set("cache-control", `public, max-age=${tools.Time.Minutes(5).seconds}`);
|
|
21
21
|
}
|
|
22
22
|
return next();
|
|
23
23
|
});
|
package/src/context.ts
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import * as bg from "@bgord/node";
|
|
2
1
|
import { createMiddleware } from "hono/factory";
|
|
3
2
|
|
|
3
|
+
import { CorrelationIdType } from "./correlation-id";
|
|
4
4
|
import { TimeZoneOffsetVariables } from "./time-zone-offset";
|
|
5
5
|
|
|
6
|
+
export type ContextType = {
|
|
7
|
+
requestId: CorrelationIdType;
|
|
8
|
+
timeZoneOffset: TimeZoneOffsetVariables["timeZoneOffset"];
|
|
9
|
+
};
|
|
10
|
+
|
|
6
11
|
export type ContextVariables = {
|
|
7
|
-
context:
|
|
8
|
-
requestId:
|
|
12
|
+
context: ContextType;
|
|
13
|
+
requestId: CorrelationIdType;
|
|
9
14
|
} & TimeZoneOffsetVariables;
|
|
10
15
|
|
|
11
16
|
export class Context {
|
|
12
17
|
static attach = createMiddleware(async (c, next) => {
|
|
13
18
|
c.set("context", {
|
|
14
|
-
requestId: c.get("requestId") as
|
|
19
|
+
requestId: c.get("requestId") as CorrelationIdType,
|
|
15
20
|
timeZoneOffset: c.get("timeZoneOffset"),
|
|
16
21
|
});
|
|
17
22
|
|
package/src/download-file.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PathLike } from "node:fs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as tools from "@bgord/tools";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
type DownloadFileConfigType = { filename: PathLike; mime: tools.Mime };
|
|
5
5
|
|
|
6
6
|
export class DownloadFile {
|
|
7
7
|
static attach(config: DownloadFileConfigType) {
|
package/src/etag-extractor.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
import { createMiddleware } from "hono/factory";
|
|
3
3
|
|
|
4
4
|
export type EtagVariables = {
|
|
5
|
-
ETag:
|
|
6
|
-
WeakETag:
|
|
5
|
+
ETag: tools.ETag | null;
|
|
6
|
+
WeakETag: tools.WeakETag | null;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export class ETagExtractor {
|
|
10
10
|
static attach = createMiddleware<{ Variables: EtagVariables }>(async (c, next) => {
|
|
11
11
|
try {
|
|
12
|
-
const header = String(c.req.header(
|
|
12
|
+
const header = String(c.req.header(tools.ETag.IF_MATCH_HEADER_NAME));
|
|
13
13
|
|
|
14
14
|
if (!header || header === "undefined") c.set("ETag", null);
|
|
15
|
-
else c.set("ETag",
|
|
15
|
+
else c.set("ETag", tools.ETag.fromHeader(header));
|
|
16
16
|
} catch (error) {
|
|
17
17
|
c.set("ETag", null);
|
|
18
18
|
}
|
|
@@ -20,18 +20,3 @@ export class ETagExtractor {
|
|
|
20
20
|
await next();
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
export class WeakETagExtractor {
|
|
25
|
-
static attach = createMiddleware<{ Variables: EtagVariables }>(async (c, next) => {
|
|
26
|
-
try {
|
|
27
|
-
const header = String(c.req.header(bg.WeakETag.IF_MATCH_HEADER_NAME));
|
|
28
|
-
|
|
29
|
-
if (!header || header === "undefined") c.set("WeakETag", null);
|
|
30
|
-
else c.set("WeakETag", bg.WeakETag.fromHeader(header));
|
|
31
|
-
} catch (error) {
|
|
32
|
-
c.set("WeakETag", null);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
await next();
|
|
36
|
-
});
|
|
37
|
-
}
|
package/src/file-uploader.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
import { bodyLimit } from "hono/body-limit";
|
|
3
3
|
import { createMiddleware } from "hono/factory";
|
|
4
4
|
import { HTTPException } from "hono/http-exception";
|
|
@@ -13,7 +13,7 @@ export const FileTooBigError = new HTTPException(400, {
|
|
|
13
13
|
|
|
14
14
|
type FileUploaderConfigType = {
|
|
15
15
|
mimeTypes: string[];
|
|
16
|
-
maxFilesSize:
|
|
16
|
+
maxFilesSize: tools.SizeValueType;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export class FileUploader {
|
|
@@ -35,9 +35,9 @@ export class FileUploader {
|
|
|
35
35
|
throw InvalidFileMimeTypeError;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const contentType = new
|
|
38
|
+
const contentType = new tools.Mime(file.type);
|
|
39
39
|
const accepted = config.mimeTypes.some((acceptedMimeType) =>
|
|
40
|
-
new
|
|
40
|
+
new tools.Mime(acceptedMimeType).isSatisfiedBy(contentType),
|
|
41
41
|
);
|
|
42
42
|
|
|
43
43
|
if (!accepted) throw InvalidFileMimeTypeError;
|
package/src/graceful-shutdown.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
|
|
3
3
|
type ServerType = ReturnType<typeof Bun.serve>;
|
|
4
4
|
|
|
5
5
|
export class GracefulShutdown {
|
|
6
|
-
private static async shutdown(server: ServerType, callback: () => any =
|
|
6
|
+
private static async shutdown(server: ServerType, callback: () => any = tools.noop) {
|
|
7
7
|
server.stop();
|
|
8
8
|
await callback();
|
|
9
9
|
// biome-ignore lint: lint/suspicious/noConsoleLog
|
|
10
10
|
console.log("HTTP server closed");
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
static applyTo(server: ServerType, callback: () => any =
|
|
13
|
+
static applyTo(server: ServerType, callback: () => any = tools.noop) {
|
|
14
14
|
process.on("SIGTERM", async () => {
|
|
15
15
|
// biome-ignore lint: lint/suspicious/noConsoleLog
|
|
16
16
|
console.log("SIGTERM signal received: closing HTTP server");
|
package/src/healthcheck.ts
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
2
|
import { createFactory } from "hono/factory";
|
|
3
3
|
|
|
4
|
+
import { BuildInfoRepository } from "./build-info-repository";
|
|
5
|
+
import { MemoryConsumption } from "./memory-consumption";
|
|
6
|
+
import {
|
|
7
|
+
AbstractPrerequisite,
|
|
8
|
+
BasePrerequisiteConfig,
|
|
9
|
+
PrerequisiteLabelType,
|
|
10
|
+
PrerequisiteStatusEnum,
|
|
11
|
+
} from "./prerequisites";
|
|
12
|
+
import { Uptime, UptimeResultType } from "./uptime";
|
|
13
|
+
|
|
4
14
|
const handler = createFactory();
|
|
5
15
|
|
|
6
16
|
type HealthcheckResultType = {
|
|
7
|
-
ok:
|
|
8
|
-
version:
|
|
17
|
+
ok: PrerequisiteStatusEnum;
|
|
18
|
+
version: tools.BuildVersionType;
|
|
9
19
|
details: {
|
|
10
|
-
label:
|
|
11
|
-
status:
|
|
20
|
+
label: PrerequisiteLabelType;
|
|
21
|
+
status: PrerequisiteStatusEnum;
|
|
12
22
|
}[];
|
|
13
|
-
uptime:
|
|
23
|
+
uptime: UptimeResultType;
|
|
14
24
|
memory: {
|
|
15
|
-
bytes:
|
|
16
|
-
formatted: ReturnType<
|
|
25
|
+
bytes: tools.Size["bytes"];
|
|
26
|
+
formatted: ReturnType<tools.Size["format"]>;
|
|
17
27
|
};
|
|
18
|
-
} &
|
|
28
|
+
} & tools.StopwatchResultType;
|
|
19
29
|
|
|
20
30
|
export class Healthcheck {
|
|
21
|
-
static build = (prerequisites:
|
|
31
|
+
static build = (prerequisites: AbstractPrerequisite<BasePrerequisiteConfig>[]) =>
|
|
22
32
|
handler.createHandlers(async (c) => {
|
|
23
|
-
const stopwatch = new
|
|
33
|
+
const stopwatch = new tools.Stopwatch();
|
|
24
34
|
|
|
25
|
-
const build = await
|
|
35
|
+
const build = await BuildInfoRepository.extract();
|
|
26
36
|
|
|
27
37
|
const details: HealthcheckResultType["details"][number][] = [];
|
|
28
38
|
|
|
@@ -31,20 +41,20 @@ export class Healthcheck {
|
|
|
31
41
|
details.push({ label: prerequisite.label, status });
|
|
32
42
|
}
|
|
33
43
|
|
|
34
|
-
const ok = details.every((result) => result.status !==
|
|
35
|
-
?
|
|
36
|
-
:
|
|
44
|
+
const ok = details.every((result) => result.status !== PrerequisiteStatusEnum.failure)
|
|
45
|
+
? PrerequisiteStatusEnum.success
|
|
46
|
+
: PrerequisiteStatusEnum.failure;
|
|
37
47
|
|
|
38
|
-
const code = ok ===
|
|
48
|
+
const code = ok === PrerequisiteStatusEnum.success ? 200 : 424;
|
|
39
49
|
|
|
40
50
|
const result: HealthcheckResultType = {
|
|
41
51
|
ok,
|
|
42
52
|
details,
|
|
43
|
-
version: build.BUILD_VERSION ??
|
|
44
|
-
uptime:
|
|
53
|
+
version: build.BUILD_VERSION ?? tools.BuildVersion.parse("unknown"),
|
|
54
|
+
uptime: Uptime.get(),
|
|
45
55
|
memory: {
|
|
46
|
-
bytes:
|
|
47
|
-
formatted:
|
|
56
|
+
bytes: MemoryConsumption.get().toBytes(),
|
|
57
|
+
formatted: MemoryConsumption.get().format(tools.SizeUnit.MB),
|
|
48
58
|
},
|
|
49
59
|
...stopwatch.stop(),
|
|
50
60
|
};
|
package/src/http-logger.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import * as bg from "@bgord/node";
|
|
2
1
|
import { getConnInfo } from "hono/bun";
|
|
3
2
|
import { createMiddleware } from "hono/factory";
|
|
4
3
|
import _ from "lodash";
|
|
5
4
|
|
|
5
|
+
import { CacheHitEnum } from "./cache-resolver";
|
|
6
|
+
import { CacheResponse } from "./cache-response";
|
|
7
|
+
import { CorrelationIdType } from "./correlation-id";
|
|
8
|
+
import { Logger } from "./logger";
|
|
9
|
+
|
|
6
10
|
export class HttpLogger {
|
|
7
11
|
private static simplify(response: unknown) {
|
|
8
12
|
const result = JSON.stringify(response, (_key, value) =>
|
|
@@ -34,9 +38,9 @@ export class HttpLogger {
|
|
|
34
38
|
"if-none-match",
|
|
35
39
|
];
|
|
36
40
|
|
|
37
|
-
static build = (logger:
|
|
41
|
+
static build = (logger: Logger) =>
|
|
38
42
|
createMiddleware(async (c, next) => {
|
|
39
|
-
const correlationId = c.get("requestId") as
|
|
43
|
+
const correlationId = c.get("requestId") as CorrelationIdType;
|
|
40
44
|
const info = getConnInfo(c);
|
|
41
45
|
const url = c.req.url;
|
|
42
46
|
const method = c.req.method;
|
|
@@ -54,7 +58,7 @@ export class HttpLogger {
|
|
|
54
58
|
|
|
55
59
|
const httpRequestBeforeMetadata = {
|
|
56
60
|
params: c.req.param(),
|
|
57
|
-
headers: _.omit(c.req.raw.clone().headers
|
|
61
|
+
headers: _.omit(Object.fromEntries(c.req.raw.clone().headers), HttpLogger.uninformativeHeaders),
|
|
58
62
|
body,
|
|
59
63
|
query: c.req.queries(),
|
|
60
64
|
};
|
|
@@ -71,9 +75,9 @@ export class HttpLogger {
|
|
|
71
75
|
|
|
72
76
|
await next();
|
|
73
77
|
|
|
74
|
-
const cacheHitHeader = c.res.clone().headers.get(
|
|
78
|
+
const cacheHitHeader = c.res.clone().headers.get(CacheResponse.CACHE_HIT_HEADER);
|
|
75
79
|
|
|
76
|
-
const cacheHit = cacheHitHeader ===
|
|
80
|
+
const cacheHit = cacheHitHeader === CacheHitEnum.hit ? CacheHitEnum.hit : undefined;
|
|
77
81
|
|
|
78
82
|
let response: any;
|
|
79
83
|
try {
|