@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/src/i18n.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import * as
|
|
3
|
-
|
|
4
|
-
import {
|
|
2
|
+
import * as tools from "@bgord/tools";
|
|
3
|
+
|
|
4
|
+
import { Path, PathType } from "./path";
|
|
5
5
|
|
|
6
6
|
export type TranslationsKeyType = string;
|
|
7
7
|
export type TranslationsValueType = string;
|
|
@@ -12,50 +12,19 @@ export type TranslationPlaceholderValueType = string | number;
|
|
|
12
12
|
export type TranslationVariableType = Record<TranslationPlaceholderType, TranslationPlaceholderValueType>;
|
|
13
13
|
|
|
14
14
|
export type I18nConfigType = {
|
|
15
|
-
translationsPath?:
|
|
16
|
-
defaultLanguage?:
|
|
17
|
-
supportedLanguages: Record<string,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type I18nVariablesType = {
|
|
21
|
-
language: bgn.Schema.LanguageType;
|
|
22
|
-
supportedLanguages: bgn.Schema.LanguageType[];
|
|
23
|
-
translationsPath: bgn.Schema.PathType;
|
|
15
|
+
translationsPath?: PathType;
|
|
16
|
+
defaultLanguage?: tools.LanguageType;
|
|
17
|
+
supportedLanguages: Record<string, tools.LanguageType>;
|
|
24
18
|
};
|
|
25
19
|
|
|
26
20
|
export class I18n {
|
|
27
|
-
static
|
|
28
|
-
|
|
29
|
-
static DEFAULT_TRANSLATIONS_PATH = bgn.Schema.Path.parse("infra/translations");
|
|
30
|
-
|
|
31
|
-
static FALLBACK_LANGUAGE = "en";
|
|
32
|
-
|
|
33
|
-
static applyTo(config: I18nConfigType) {
|
|
34
|
-
return createMiddleware(async (c, next) => {
|
|
35
|
-
const translationsPath = config?.translationsPath ?? I18n.DEFAULT_TRANSLATIONS_PATH;
|
|
21
|
+
static DEFAULT_TRANSLATIONS_PATH = Path.parse("infra/translations");
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const chosenLanguage = getCookie(c, I18n.LANGUAGE_COOKIE_NAME) ?? defaultLanguage;
|
|
40
|
-
|
|
41
|
-
const language = Object.keys(config.supportedLanguages).find((language) => language === chosenLanguage)
|
|
42
|
-
? chosenLanguage
|
|
43
|
-
: I18n.FALLBACK_LANGUAGE;
|
|
44
|
-
|
|
45
|
-
c.set("supportedLanguages", Object.keys(config.supportedLanguages));
|
|
46
|
-
c.set("language", language);
|
|
47
|
-
c.set("translationsPath", translationsPath);
|
|
48
|
-
|
|
49
|
-
return next();
|
|
50
|
-
});
|
|
51
|
-
}
|
|
23
|
+
constructor(private translationsPath: PathType = I18n.DEFAULT_TRANSLATIONS_PATH) {}
|
|
52
24
|
|
|
53
|
-
|
|
54
|
-
language: bgn.Schema.LanguageType,
|
|
55
|
-
translationsPath: bgn.Schema.PathType,
|
|
56
|
-
): Promise<TranslationsType> {
|
|
25
|
+
async getTranslations(language: tools.LanguageType): Promise<TranslationsType> {
|
|
57
26
|
try {
|
|
58
|
-
return Bun.file(
|
|
27
|
+
return Bun.file(this.getTranslationPathForLanguage(language)).json();
|
|
59
28
|
} catch (error) {
|
|
60
29
|
// biome-ignore lint: lint/suspicious/noConsoleLog
|
|
61
30
|
console.log("I18n#getTranslations", error);
|
|
@@ -64,7 +33,7 @@ export class I18n {
|
|
|
64
33
|
}
|
|
65
34
|
}
|
|
66
35
|
|
|
67
|
-
|
|
36
|
+
useTranslations(translations: TranslationsType) {
|
|
68
37
|
return function translate(key: TranslationsKeyType, variables?: TranslationVariableType) {
|
|
69
38
|
const translation = translations[key];
|
|
70
39
|
|
|
@@ -82,10 +51,7 @@ export class I18n {
|
|
|
82
51
|
};
|
|
83
52
|
}
|
|
84
53
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
translationsPath = I18n.DEFAULT_TRANSLATIONS_PATH,
|
|
88
|
-
): bgn.Schema.PathType {
|
|
89
|
-
return bgn.Schema.Path.parse(path.join(translationsPath, `${language}.json`));
|
|
54
|
+
getTranslationPathForLanguage(language: tools.LanguageType): PathType {
|
|
55
|
+
return Path.parse(path.join(this.translationsPath, `${language}.json`));
|
|
90
56
|
}
|
|
91
57
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
export * from "./api-key-shield";
|
|
2
2
|
export * from "./api-version";
|
|
3
3
|
export * from "./auth-shield";
|
|
4
|
+
export * from "./build-info-repository";
|
|
5
|
+
export * from "./cache-resolver";
|
|
6
|
+
export * from "./cache-response";
|
|
7
|
+
export * from "./cache-static-files";
|
|
4
8
|
export * from "./context";
|
|
9
|
+
export * from "./correlation-id";
|
|
10
|
+
export * from "./download-file";
|
|
5
11
|
export * from "./etag-extractor";
|
|
12
|
+
export * from "./file-uploader";
|
|
6
13
|
export * from "./graceful-shutdown";
|
|
7
14
|
export * from "./healthcheck";
|
|
8
15
|
export * from "./http-logger";
|
|
9
|
-
export * from "./rate-limit-shield";
|
|
10
|
-
export * from "./time-zone-offset";
|
|
11
|
-
export * from "./cache-static-files";
|
|
12
|
-
export * from "./cache-response";
|
|
13
|
-
export * from "./download-file";
|
|
14
16
|
export * from "./i18n";
|
|
15
|
-
export * from "./
|
|
16
|
-
export * from "./
|
|
17
|
+
export * from "./jobs";
|
|
18
|
+
export * from "./logger";
|
|
19
|
+
export * from "./mailer";
|
|
20
|
+
export * from "./memory-consumption";
|
|
21
|
+
export * from "./new-uuid";
|
|
22
|
+
export * from "./node-env.vo";
|
|
23
|
+
export * from "./passwords";
|
|
24
|
+
export * from "./path";
|
|
25
|
+
export * from "./port";
|
|
26
|
+
export * from "./prerequisites";
|
|
27
|
+
export * from "./prerequisites/index";
|
|
28
|
+
export * from "./rate-limit-shield";
|
|
29
|
+
export * from "./session-id";
|
|
17
30
|
export * from "./setup";
|
|
31
|
+
export * from "./time-zone-offset";
|
|
32
|
+
export * from "./uptime";
|
|
33
|
+
export * from "./username";
|
|
34
|
+
export * from "./uuid";
|
|
35
|
+
export * from "./weak-etag-extractor";
|
|
36
|
+
export { default as sharp } from "sharp";
|
package/src/jobs.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import { Cron } from "croner";
|
|
3
|
+
|
|
4
|
+
import { CorrelationId } from "./correlation-id";
|
|
5
|
+
import { Logger } from "./logger";
|
|
6
|
+
import { NewUUID } from "./new-uuid";
|
|
7
|
+
|
|
8
|
+
export type JobNameType = string;
|
|
9
|
+
export type MultipleJobsType = Record<JobNameType, Cron>;
|
|
10
|
+
|
|
11
|
+
export enum UTC_DAY_OF_THE_WEEK {
|
|
12
|
+
Monday = 1,
|
|
13
|
+
Tuesday = 2,
|
|
14
|
+
Wednesday = 3,
|
|
15
|
+
Thursday = 4,
|
|
16
|
+
Friday = 5,
|
|
17
|
+
Saturday = 6,
|
|
18
|
+
Sunday = 0,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Jobs {
|
|
22
|
+
static SCHEDULES = { EVERY_MINUTE: "* * * * *", EVERY_HOUR: "0 * * * *" };
|
|
23
|
+
|
|
24
|
+
static stopAll(jobs: MultipleJobsType) {
|
|
25
|
+
Object.values(jobs).forEach((job) => job.stop());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static areAllRunning(jobs: MultipleJobsType): boolean {
|
|
29
|
+
return Object.values(jobs).every((job) => job.isRunning());
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type JobProcessorType = {
|
|
34
|
+
cron: string;
|
|
35
|
+
label: JobNameType;
|
|
36
|
+
process: () => Promise<void>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export class JobHandler {
|
|
40
|
+
constructor(private readonly logger: Logger) {}
|
|
41
|
+
|
|
42
|
+
handle(jobProcessor: JobProcessorType) {
|
|
43
|
+
const correlationId = CorrelationId.parse(NewUUID.generate());
|
|
44
|
+
|
|
45
|
+
// biome-ignore lint: lint/complexity/noUselessThisAlias
|
|
46
|
+
const that = this;
|
|
47
|
+
|
|
48
|
+
return async () => {
|
|
49
|
+
const stopwatch = new tools.Stopwatch();
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
that.logger.info({
|
|
53
|
+
message: `${jobProcessor.label} start`,
|
|
54
|
+
operation: "job_start",
|
|
55
|
+
correlationId,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await jobProcessor.process();
|
|
59
|
+
|
|
60
|
+
that.logger.info({
|
|
61
|
+
message: `${jobProcessor.label} success`,
|
|
62
|
+
operation: "job_success",
|
|
63
|
+
correlationId,
|
|
64
|
+
metadata: stopwatch.stop(),
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
that.logger.error({
|
|
68
|
+
message: `${jobProcessor.label} error`,
|
|
69
|
+
operation: "job_error",
|
|
70
|
+
correlationId,
|
|
71
|
+
metadata: {
|
|
72
|
+
...that.logger.formatError(error),
|
|
73
|
+
...stopwatch.stop(),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protect(cron: Cron) {
|
|
81
|
+
// biome-ignore lint: lint/complexity/noUselessThisAlias
|
|
82
|
+
const that = this;
|
|
83
|
+
|
|
84
|
+
return async () => {
|
|
85
|
+
that.logger.info({
|
|
86
|
+
message: `${cron.name} overrun`,
|
|
87
|
+
operation: "job_overrun",
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import * as winston from "winston";
|
|
3
|
+
import { z } from "zod/v4";
|
|
4
|
+
|
|
5
|
+
import { CorrelationIdType } from "./correlation-id";
|
|
6
|
+
import { NodeEnvironmentEnum } from "./node-env.vo";
|
|
7
|
+
import { PathType } from "./path";
|
|
8
|
+
|
|
9
|
+
export enum LogLevelEnum {
|
|
10
|
+
/** @public */
|
|
11
|
+
silent = "silent",
|
|
12
|
+
error = "error",
|
|
13
|
+
warn = "warn",
|
|
14
|
+
info = "info",
|
|
15
|
+
http = "http",
|
|
16
|
+
verbose = "verbose",
|
|
17
|
+
}
|
|
18
|
+
export const LogLevel = z.enum(LogLevelEnum);
|
|
19
|
+
|
|
20
|
+
type LogTimestampType = number;
|
|
21
|
+
type LogAppType = string;
|
|
22
|
+
type LogEnvironmentType = NodeEnvironmentEnum;
|
|
23
|
+
type LogMessageType = string;
|
|
24
|
+
type LogOperationType = string;
|
|
25
|
+
type LogMetadataType = Record<string, any>;
|
|
26
|
+
type LogCorrelationIdType = CorrelationIdType;
|
|
27
|
+
|
|
28
|
+
const levels: Record<LogLevelEnum, number> = {
|
|
29
|
+
silent: 0,
|
|
30
|
+
error: 0,
|
|
31
|
+
warn: 1,
|
|
32
|
+
info: 2,
|
|
33
|
+
http: 3,
|
|
34
|
+
verbose: 4,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type LogFullType = {
|
|
38
|
+
timestamp: LogTimestampType;
|
|
39
|
+
app: LogAppType;
|
|
40
|
+
environment: LogEnvironmentType;
|
|
41
|
+
level: LogLevelEnum;
|
|
42
|
+
message: LogMessageType;
|
|
43
|
+
operation: LogOperationType;
|
|
44
|
+
method: string;
|
|
45
|
+
url: string;
|
|
46
|
+
client: { ip?: string; userAgent?: string };
|
|
47
|
+
correlationId?: LogCorrelationIdType;
|
|
48
|
+
responseCode?: number;
|
|
49
|
+
durationMs?: tools.TimestampType;
|
|
50
|
+
metadata?: LogMetadataType;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
type LogErrorType = Omit<
|
|
54
|
+
LogFullType,
|
|
55
|
+
"app" | "client" | "environment" | "duration" | "level" | "method" | "responseCode" | "timestamp" | "url"
|
|
56
|
+
>;
|
|
57
|
+
|
|
58
|
+
type LogWarnType = Omit<
|
|
59
|
+
LogFullType,
|
|
60
|
+
"app" | "client" | "environment" | "duration" | "level" | "method" | "responseCode" | "timestamp" | "url"
|
|
61
|
+
>;
|
|
62
|
+
|
|
63
|
+
type LogInfoType = Omit<
|
|
64
|
+
LogFullType,
|
|
65
|
+
"app" | "client" | "environment" | "duration" | "level" | "method" | "responseCode" | "timestamp" | "url"
|
|
66
|
+
>;
|
|
67
|
+
|
|
68
|
+
type LogHttpType = Omit<LogFullType, "app" | "environment" | "timestamp" | "level">;
|
|
69
|
+
|
|
70
|
+
type LoggerOptionsType = {
|
|
71
|
+
app: LogAppType;
|
|
72
|
+
environment: NodeEnvironmentEnum;
|
|
73
|
+
level?: LogLevelEnum;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export class Logger {
|
|
77
|
+
private readonly instance: winston.Logger;
|
|
78
|
+
|
|
79
|
+
private readonly app: LoggerOptionsType["app"];
|
|
80
|
+
|
|
81
|
+
private readonly environment: LoggerOptionsType["environment"];
|
|
82
|
+
|
|
83
|
+
private readonly level: LoggerOptionsType["level"] = LogLevelEnum.verbose;
|
|
84
|
+
|
|
85
|
+
constructor(options: LoggerOptionsType) {
|
|
86
|
+
this.app = options.app;
|
|
87
|
+
this.environment = options.environment;
|
|
88
|
+
this.level = options.level ?? LogLevelEnum.verbose;
|
|
89
|
+
|
|
90
|
+
const formats = [
|
|
91
|
+
winston.format.json(),
|
|
92
|
+
|
|
93
|
+
this.environment !== NodeEnvironmentEnum.production ? winston.format.prettyPrint() : undefined,
|
|
94
|
+
].filter(Boolean);
|
|
95
|
+
|
|
96
|
+
this.instance = winston.createLogger({
|
|
97
|
+
level: this.level,
|
|
98
|
+
levels,
|
|
99
|
+
handleExceptions: true,
|
|
100
|
+
handleRejections: true,
|
|
101
|
+
format: winston.format.combine(...(formats as NonNullable<winston.LoggerOptions["format"]>[])),
|
|
102
|
+
transports: [new winston.transports.Console()],
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (this.environment === NodeEnvironmentEnum.production) {
|
|
106
|
+
this.instance.add(
|
|
107
|
+
new winston.transports.File({
|
|
108
|
+
filename: this.getProductionLogFilePath(),
|
|
109
|
+
maxsize: tools.Size.toBytes({ unit: tools.SizeUnit.MB, value: 100 }),
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private getBase() {
|
|
116
|
+
return {
|
|
117
|
+
app: this.app,
|
|
118
|
+
environment: this.environment,
|
|
119
|
+
timestamp: Date.now(),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
info(log: LogInfoType) {
|
|
124
|
+
this.instance.info({ level: LogLevelEnum.info, ...this.getBase(), ...log });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
error(log: LogErrorType) {
|
|
128
|
+
this.instance.error({
|
|
129
|
+
level: LogLevelEnum.error,
|
|
130
|
+
...this.getBase(),
|
|
131
|
+
...log,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
warn(log: LogWarnType) {
|
|
136
|
+
this.instance.warn({ level: LogLevelEnum.warn, ...this.getBase(), ...log });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
http(log: LogHttpType) {
|
|
140
|
+
this.instance.http({ level: LogLevelEnum.http, ...this.getBase(), ...log });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
getProductionLogFilePath(): PathType {
|
|
144
|
+
return `/var/log/${this.app}-${this.environment}.log`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
formatError(_error: unknown) {
|
|
148
|
+
const error = _error as Error;
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
message: error?.message,
|
|
152
|
+
name: error?.name,
|
|
153
|
+
stack: error?.stack,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
package/src/mailer.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import nodemailer, { SendMailOptions } from "nodemailer";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
|
|
4
|
+
import { Port } from "./port";
|
|
5
|
+
|
|
6
|
+
export const SmtpHost = z.string().trim().min(1);
|
|
7
|
+
export type SmtpHostType = z.infer<typeof SmtpHost>;
|
|
8
|
+
|
|
9
|
+
export const SmtpPort = Port;
|
|
10
|
+
export type SmtpPortType = z.infer<typeof SmtpPort>;
|
|
11
|
+
|
|
12
|
+
export const SmtpUser = z.string().trim().min(1);
|
|
13
|
+
export type SmtpUserType = z.infer<typeof SmtpUser>;
|
|
14
|
+
|
|
15
|
+
export const SmtpPass = z.string().trim().min(1);
|
|
16
|
+
export type SmtpPassType = z.infer<typeof SmtpPass>;
|
|
17
|
+
|
|
18
|
+
type MailerConfigType = {
|
|
19
|
+
SMTP_HOST: SmtpHostType;
|
|
20
|
+
SMTP_PORT: SmtpPortType;
|
|
21
|
+
SMTP_USER: SmtpUserType;
|
|
22
|
+
SMTP_PASS: SmtpPassType;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type MailerSendOptionsType = SendMailOptions;
|
|
26
|
+
|
|
27
|
+
export class Mailer {
|
|
28
|
+
private readonly transport: nodemailer.Transporter;
|
|
29
|
+
|
|
30
|
+
constructor(config: MailerConfigType) {
|
|
31
|
+
this.transport = nodemailer.createTransport({
|
|
32
|
+
host: config.SMTP_HOST,
|
|
33
|
+
port: config.SMTP_PORT,
|
|
34
|
+
auth: {
|
|
35
|
+
user: config.SMTP_USER,
|
|
36
|
+
pass: config.SMTP_PASS,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async send(options: MailerSendOptionsType): Promise<unknown> {
|
|
42
|
+
return this.transport.sendMail(options);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async verify() {
|
|
46
|
+
return this.transport.verify();
|
|
47
|
+
}
|
|
48
|
+
}
|
package/src/new-uuid.ts
ADDED
package/src/passwords.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
|
|
3
|
+
export type PasswordType = string;
|
|
4
|
+
type HashedPasswordType = string;
|
|
5
|
+
|
|
6
|
+
export class Password {
|
|
7
|
+
private schema: z.ZodSchema = z.string().min(1).max(256);
|
|
8
|
+
|
|
9
|
+
private value: PasswordType;
|
|
10
|
+
|
|
11
|
+
constructor(value: PasswordType, schema?: z.ZodSchema) {
|
|
12
|
+
this.schema = schema ?? this.schema;
|
|
13
|
+
this.value = this.schema.parse(value) as PasswordType;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async hash(): Promise<HashedPassword> {
|
|
17
|
+
return HashedPassword.fromPassword(this);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
read(): PasswordType {
|
|
21
|
+
return this.value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class HashedPassword {
|
|
26
|
+
private constructor(private value: HashedPasswordType) {}
|
|
27
|
+
|
|
28
|
+
static async fromPassword(password: Password) {
|
|
29
|
+
const hash = await Bun.password.hash(password.read());
|
|
30
|
+
|
|
31
|
+
return new HashedPassword(hash);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static async fromHash(value: HashedPasswordType) {
|
|
35
|
+
return new HashedPassword(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
read(): HashedPasswordType {
|
|
39
|
+
return this.value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async matches(password: Password): Promise<boolean> {
|
|
43
|
+
return Bun.password.verify(password.read(), this.read());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async matchesOrThrow(password: Password): Promise<true> {
|
|
47
|
+
const matches = await Bun.password.verify(password.read(), this.read());
|
|
48
|
+
|
|
49
|
+
if (!matches) {
|
|
50
|
+
throw new Error("HashedPassword does not match the provided password");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/path.ts
ADDED
package/src/port.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import bun from "bun";
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AbstractPrerequisite,
|
|
6
|
+
PrerequisiteLabelType,
|
|
7
|
+
PrerequisiteStatusEnum,
|
|
8
|
+
PrerequisiteStrategyEnum,
|
|
9
|
+
} from "../prerequisites";
|
|
10
|
+
|
|
11
|
+
const PrerequisiteBinaryValue = z
|
|
12
|
+
.string()
|
|
13
|
+
.min(1)
|
|
14
|
+
.max(64)
|
|
15
|
+
.refine((value) => !value.includes(" "));
|
|
16
|
+
type PrerequisiteBinaryValueType = z.infer<typeof PrerequisiteBinaryValue>;
|
|
17
|
+
|
|
18
|
+
type PrerequisiteBinaryConfigType = {
|
|
19
|
+
binary: PrerequisiteBinaryValueType;
|
|
20
|
+
label: PrerequisiteLabelType;
|
|
21
|
+
enabled?: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class PrerequisiteBinary extends AbstractPrerequisite<PrerequisiteBinaryConfigType> {
|
|
25
|
+
readonly strategy = PrerequisiteStrategyEnum.binary;
|
|
26
|
+
|
|
27
|
+
constructor(readonly config: PrerequisiteBinaryConfigType) {
|
|
28
|
+
super(config);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async verify() {
|
|
32
|
+
if (!this.enabled) return PrerequisiteStatusEnum.undetermined;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const binary = PrerequisiteBinaryValue.parse(this.config.binary);
|
|
36
|
+
|
|
37
|
+
const result = await bun.$`which ${binary}`;
|
|
38
|
+
|
|
39
|
+
return result.exitCode === 0 ? this.pass() : this.reject();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return this.reject();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AbstractPrerequisite,
|
|
5
|
+
PrerequisiteLabelType,
|
|
6
|
+
PrerequisiteStatusEnum,
|
|
7
|
+
PrerequisiteStrategyEnum,
|
|
8
|
+
} from "../prerequisites";
|
|
9
|
+
|
|
10
|
+
type PrerequisiteBunConfigType = {
|
|
11
|
+
version: tools.PackageVersion;
|
|
12
|
+
label: PrerequisiteLabelType;
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
current: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class PrerequisiteBun extends AbstractPrerequisite<PrerequisiteBunConfigType> {
|
|
18
|
+
readonly strategy = PrerequisiteStrategyEnum.bun;
|
|
19
|
+
|
|
20
|
+
constructor(readonly config: PrerequisiteBunConfigType) {
|
|
21
|
+
super(config);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async verify(): Promise<PrerequisiteStatusEnum> {
|
|
25
|
+
const current = tools.PackageVersion.fromString(this.config.current);
|
|
26
|
+
|
|
27
|
+
if (current.isGreaterThanOrEqual(this.config.version)) {
|
|
28
|
+
return this.pass();
|
|
29
|
+
}
|
|
30
|
+
return this.reject();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./binary";
|
|
2
|
+
export * from "./bun";
|
|
3
|
+
export * from "./jobs";
|
|
4
|
+
export * from "./log-file";
|
|
5
|
+
export * from "./mailer";
|
|
6
|
+
export * from "./memory";
|
|
7
|
+
export * from "./node";
|
|
8
|
+
export * from "./outside-connectivity";
|
|
9
|
+
export * from "./path";
|
|
10
|
+
export * from "./port";
|
|
11
|
+
export * from "./ram";
|
|
12
|
+
export * from "./self";
|
|
13
|
+
export * from "./space";
|
|
14
|
+
export * from "./ssl-certificate-expiry";
|
|
15
|
+
export * from "./timezone-utc";
|
|
16
|
+
export * from "./translations";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Jobs, MultipleJobsType } from "../jobs";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AbstractPrerequisite,
|
|
5
|
+
PrerequisiteLabelType,
|
|
6
|
+
PrerequisiteStatusEnum,
|
|
7
|
+
PrerequisiteStrategyEnum,
|
|
8
|
+
} from "../prerequisites";
|
|
9
|
+
|
|
10
|
+
type PrerequisiteJobsConfigType = {
|
|
11
|
+
jobs: MultipleJobsType;
|
|
12
|
+
label: PrerequisiteLabelType;
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class PrerequisiteJobs extends AbstractPrerequisite<PrerequisiteJobsConfigType> {
|
|
17
|
+
readonly strategy = PrerequisiteStrategyEnum.jobs;
|
|
18
|
+
|
|
19
|
+
constructor(readonly config: PrerequisiteJobsConfigType) {
|
|
20
|
+
super(config);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async verify(): Promise<PrerequisiteStatusEnum> {
|
|
24
|
+
if (!this.enabled) return PrerequisiteStatusEnum.undetermined;
|
|
25
|
+
|
|
26
|
+
return Jobs.areAllRunning(this.config.jobs) ? this.pass() : this.reject();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Logger } from "../logger";
|
|
2
|
+
import {
|
|
3
|
+
AbstractPrerequisite,
|
|
4
|
+
PrerequisiteLabelType,
|
|
5
|
+
PrerequisiteStatusEnum,
|
|
6
|
+
PrerequisiteStrategyEnum,
|
|
7
|
+
} from "../prerequisites";
|
|
8
|
+
|
|
9
|
+
type PrerequisiteLogFileConfigType = {
|
|
10
|
+
logger: Logger;
|
|
11
|
+
label: PrerequisiteLabelType;
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class PrerequisiteLogFile extends AbstractPrerequisite<PrerequisiteLogFileConfigType> {
|
|
16
|
+
readonly strategy = PrerequisiteStrategyEnum.logFile;
|
|
17
|
+
|
|
18
|
+
constructor(readonly config: PrerequisiteLogFileConfigType) {
|
|
19
|
+
super(config);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async verify(): Promise<PrerequisiteStatusEnum> {
|
|
23
|
+
if (!this.enabled) return PrerequisiteStatusEnum.undetermined;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const path = this.config.logger.getProductionLogFilePath();
|
|
27
|
+
|
|
28
|
+
const result = await Bun.file(path).exists();
|
|
29
|
+
|
|
30
|
+
return result ? this.pass() : this.reject();
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return this.reject();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|