@bgord/bun 1.2.4 → 1.2.6

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.
Files changed (86) hide show
  1. package/dist/better-auth-logger.service.d.ts +5 -2
  2. package/dist/better-auth-logger.service.d.ts.map +1 -1
  3. package/dist/better-auth-logger.service.js +6 -6
  4. package/dist/better-auth-logger.service.js.map +1 -1
  5. package/dist/command-logger.service.d.ts +6 -2
  6. package/dist/command-logger.service.d.ts.map +1 -1
  7. package/dist/command-logger.service.js +4 -4
  8. package/dist/command-logger.service.js.map +1 -1
  9. package/dist/encryption-bun.adapter.d.ts +6 -2
  10. package/dist/encryption-bun.adapter.d.ts.map +1 -1
  11. package/dist/encryption-bun.adapter.js +5 -5
  12. package/dist/encryption-bun.adapter.js.map +1 -1
  13. package/dist/event-handler.service.d.ts +6 -2
  14. package/dist/event-handler.service.d.ts.map +1 -1
  15. package/dist/event-handler.service.js +4 -4
  16. package/dist/event-handler.service.js.map +1 -1
  17. package/dist/event-logger.service.d.ts +6 -2
  18. package/dist/event-logger.service.d.ts.map +1 -1
  19. package/dist/event-logger.service.js +4 -4
  20. package/dist/event-logger.service.js.map +1 -1
  21. package/dist/graceful-shutdown.service.d.ts +5 -2
  22. package/dist/graceful-shutdown.service.d.ts.map +1 -1
  23. package/dist/graceful-shutdown.service.js +18 -10
  24. package/dist/graceful-shutdown.service.js.map +1 -1
  25. package/dist/jobs.service.d.ts.map +1 -1
  26. package/dist/jobs.service.js.map +1 -1
  27. package/dist/mailer-smtp-with-logger.adapter.d.ts +5 -5
  28. package/dist/mailer-smtp-with-logger.adapter.d.ts.map +1 -1
  29. package/dist/mailer-smtp-with-logger.adapter.js +8 -8
  30. package/dist/mailer-smtp-with-logger.adapter.js.map +1 -1
  31. package/dist/pdf-generator-noop.adapter.d.ts +6 -2
  32. package/dist/pdf-generator-noop.adapter.d.ts.map +1 -1
  33. package/dist/pdf-generator-noop.adapter.js +8 -4
  34. package/dist/pdf-generator-noop.adapter.js.map +1 -1
  35. package/dist/prerequisites/clock-drift.d.ts +2 -2
  36. package/dist/prerequisites/clock-drift.js +3 -3
  37. package/dist/prerequisites/log-file.d.ts +2 -2
  38. package/dist/prerequisites/log-file.js +3 -3
  39. package/dist/prerequisites/mailer.d.ts +2 -2
  40. package/dist/prerequisites/mailer.js +3 -3
  41. package/dist/prerequisites/space.d.ts +2 -2
  42. package/dist/prerequisites/space.d.ts.map +1 -1
  43. package/dist/prerequisites/space.js +3 -3
  44. package/dist/prerequisites/space.js.map +1 -1
  45. package/dist/prerequisites/ssl-certificate-expiry.d.ts +2 -2
  46. package/dist/prerequisites/ssl-certificate-expiry.d.ts.map +1 -1
  47. package/dist/prerequisites/ssl-certificate-expiry.js +3 -3
  48. package/dist/prerequisites/ssl-certificate-expiry.js.map +1 -1
  49. package/dist/prerequisites/translations.d.ts +4 -4
  50. package/dist/prerequisites/translations.js +5 -5
  51. package/dist/prerequisites.service.d.ts +2 -2
  52. package/dist/prerequisites.service.js +3 -3
  53. package/dist/remote-file-storage-noop.adapter.d.ts +6 -3
  54. package/dist/remote-file-storage-noop.adapter.d.ts.map +1 -1
  55. package/dist/remote-file-storage-noop.adapter.js +10 -8
  56. package/dist/remote-file-storage-noop.adapter.js.map +1 -1
  57. package/dist/shield-rate-limit.middleware.d.ts.map +1 -1
  58. package/dist/shield-rate-limit.middleware.js.map +1 -1
  59. package/dist/timekeeper-noop.adapter.d.ts +6 -2
  60. package/dist/timekeeper-noop.adapter.d.ts.map +1 -1
  61. package/dist/timekeeper-noop.adapter.js +4 -4
  62. package/dist/timekeeper-noop.adapter.js.map +1 -1
  63. package/dist/translations.service.d.ts.map +1 -1
  64. package/dist/translations.service.js.map +1 -1
  65. package/dist/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +16 -18
  67. package/src/better-auth-logger.service.ts +6 -4
  68. package/src/command-logger.service.ts +4 -2
  69. package/src/encryption-bun.adapter.ts +5 -3
  70. package/src/event-handler.service.ts +4 -2
  71. package/src/event-logger.service.ts +4 -2
  72. package/src/graceful-shutdown.service.ts +18 -8
  73. package/src/jobs.service.ts +1 -0
  74. package/src/mailer-smtp-with-logger.adapter.ts +8 -7
  75. package/src/pdf-generator-noop.adapter.ts +8 -2
  76. package/src/prerequisites/clock-drift.ts +4 -4
  77. package/src/prerequisites/log-file.ts +4 -4
  78. package/src/prerequisites/mailer.ts +4 -4
  79. package/src/prerequisites/space.ts +4 -4
  80. package/src/prerequisites/ssl-certificate-expiry.ts +4 -4
  81. package/src/prerequisites/translations.ts +7 -7
  82. package/src/prerequisites.service.ts +4 -4
  83. package/src/remote-file-storage-noop.adapter.ts +13 -9
  84. package/src/shield-rate-limit.middleware.ts +1 -0
  85. package/src/timekeeper-noop.adapter.ts +4 -2
  86. package/src/translations.service.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgord/bun",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "author": "Bartosz Gordon",
@@ -20,40 +20,38 @@
20
20
  "preinstall": "bunx only-allow bun"
21
21
  },
22
22
  "devDependencies": {
23
- "@biomejs/biome": "2.3.5",
23
+ "@biomejs/biome": "2.3.8",
24
24
  "@commitlint/cli": "20.1.0",
25
25
  "@commitlint/config-conventional": "20.0.0",
26
- "@types/bun": "1.3.2",
27
- "@types/lodash": "4.17.20",
28
- "@types/mime-types": "3.0.1",
29
- "@types/nodemailer": "7.0.3",
26
+ "@types/bun": "1.3.3",
27
+ "@types/lodash": "4.17.21",
28
+ "@types/nodemailer": "7.0.4",
30
29
  "@types/yazl": "3.3.0",
31
- "cspell": "9.3.1",
32
- "knip": "5.69.1",
33
- "lefthook": "2.0.4",
34
- "only-allow": "1.2.1",
30
+ "cspell": "9.4.0",
31
+ "knip": "5.71.0",
32
+ "lefthook": "2.0.6",
33
+ "only-allow": "1.2.2",
35
34
  "shellcheck": "4.1.0",
36
35
  "typescript": "5.9.3",
37
- "zod": "4.1.12"
36
+ "zod": "4.1.13"
38
37
  },
39
38
  "dependencies": {
40
39
  "@axiomhq/winston": "1.3.1",
41
- "@bgord/tools": "1.1.7",
42
- "@hono/ua-blocker": "0.1.16",
43
- "better-auth": "1.3.34",
40
+ "@bgord/tools": "1.1.9",
41
+ "@hono/ua-blocker": "0.1.20",
42
+ "better-auth": "1.4.5",
44
43
  "croner": "9.1.0",
45
44
  "csv": "6.4.1",
46
45
  "hcaptcha": "0.2.0",
47
- "hono": "4.10.6",
46
+ "hono": "4.10.7",
48
47
  "lodash": "4.17.21",
49
- "mime-types": "3.0.1",
50
48
  "node-cache": "5.1.2",
51
- "nodemailer": "7.0.10",
49
+ "nodemailer": "7.0.11",
52
50
  "sharp": "0.34.5",
53
51
  "winston": "3.18.3",
54
52
  "yazl": "3.3.1"
55
53
  },
56
54
  "peerDependencies": {
57
- "zod": "4.1.12"
55
+ "zod": "4.1.13"
58
56
  }
59
57
  }
@@ -3,8 +3,10 @@ import { formatError } from "./logger-format-error.service";
3
3
 
4
4
  type LogLevel = "info" | "success" | "warn" | "error" | "debug";
5
5
 
6
+ type Dependencies = { Logger: LoggerPort };
7
+
6
8
  export class BetterAuthLogger {
7
- constructor(private readonly logger: LoggerPort) {}
9
+ constructor(private readonly deps: Dependencies) {}
8
10
 
9
11
  attach() {
10
12
  return {
@@ -16,18 +18,18 @@ export class BetterAuthLogger {
16
18
 
17
19
  switch (level) {
18
20
  case LogLevelEnum.error: {
19
- this.logger.error({
21
+ this.deps.Logger.error({
20
22
  ...base,
21
23
  error: formatError(args.find((a) => a instanceof Error) ?? new Error(message)),
22
24
  });
23
25
  break;
24
26
  }
25
27
  case LogLevelEnum.warn: {
26
- this.logger.warn(base);
28
+ this.deps.Logger.warn(base);
27
29
  break;
28
30
  }
29
31
  default: {
30
- this.logger.info(base);
32
+ this.deps.Logger.info(base);
31
33
  break;
32
34
  }
33
35
  }
@@ -1,9 +1,11 @@
1
1
  import type { LoggerPort } from "./logger.port";
2
2
 
3
+ type Dependencies = { Logger: LoggerPort };
4
+
3
5
  export class CommandLogger {
4
6
  private readonly base = { component: "infra", operation: "command_emitted" };
5
7
 
6
- constructor(private readonly logger: LoggerPort) {}
8
+ constructor(private readonly deps: Dependencies) {}
7
9
 
8
10
  private _handle(
9
11
  type: string,
@@ -14,7 +16,7 @@ export class CommandLogger {
14
16
  if (type === "subscribe") return;
15
17
  if (typeof commandName === "symbol") return;
16
18
 
17
- this.logger.info({ message: `${commandName} emitted`, metadata: commandData, ...this.base });
19
+ this.deps.Logger.info({ message: `${commandName} emitted`, metadata: commandData, ...this.base });
18
20
  }
19
21
 
20
22
  handle = this._handle.bind(this);
@@ -4,11 +4,13 @@ import { EncryptionIV } from "./encryption-iv.vo";
4
4
 
5
5
  export const EncryptionBunAdapterError = { InvalidPayload: "encryption.bun.adapter.invalid.payload" };
6
6
 
7
+ type Dependencies = { CryptoKeyProvider: CryptoKeyProviderPort };
8
+
7
9
  export class EncryptionBunAdapter implements EncryptionPort {
8
- constructor(private readonly cryptoKeyProvider: CryptoKeyProviderPort) {}
10
+ constructor(private readonly deps: Dependencies) {}
9
11
 
10
12
  async encrypt(recipe: EncryptionRecipe) {
11
- const key = await this.cryptoKeyProvider.get();
13
+ const key = await this.deps.CryptoKeyProvider.get();
12
14
  const iv = EncryptionIV.generate();
13
15
 
14
16
  const plaintext = await Bun.file(recipe.input.get()).arrayBuffer();
@@ -30,7 +32,7 @@ export class EncryptionBunAdapter implements EncryptionPort {
30
32
  }
31
33
 
32
34
  async decrypt(recipe: EncryptionRecipe) {
33
- const key = await this.cryptoKeyProvider.get();
35
+ const key = await this.deps.CryptoKeyProvider.get();
34
36
 
35
37
  const bytes = new Uint8Array(await Bun.file(recipe.input.get()).arrayBuffer());
36
38
  if (bytes.length < EncryptionIV.LENGTH + 1) throw new Error(EncryptionBunAdapterError.InvalidPayload);
@@ -3,15 +3,17 @@ import type { GenericEventSchema } from "./event.types";
3
3
  import type { LoggerPort } from "./logger.port";
4
4
  import { formatError } from "./logger-format-error.service";
5
5
 
6
+ type Dependencies = { Logger: LoggerPort };
7
+
6
8
  export class EventHandler {
7
- constructor(private readonly logger: LoggerPort) {}
9
+ constructor(private readonly deps: Dependencies) {}
8
10
 
9
11
  handle<T extends { name: z.infer<GenericEventSchema["shape"]["name"]> }>(fn: (event: T) => Promise<void>) {
10
12
  return async (event: T) => {
11
13
  try {
12
14
  await fn(event);
13
15
  } catch (error) {
14
- this.logger.error({
16
+ this.deps.Logger.error({
15
17
  message: `Unknown ${event.name} event handler error`,
16
18
  component: "infra",
17
19
  operation: "unknown_event_handler_error",
@@ -1,9 +1,11 @@
1
1
  import type { LoggerPort } from "./logger.port";
2
2
 
3
+ type Dependencies = { Logger: LoggerPort };
4
+
3
5
  export class EventLogger {
4
6
  private readonly base = { component: "infra", operation: "event_emitted" };
5
7
 
6
- constructor(private readonly logger: LoggerPort) {}
8
+ constructor(private readonly deps: Dependencies) {}
7
9
 
8
10
  private _handle(
9
11
  type: string,
@@ -14,7 +16,7 @@ export class EventLogger {
14
16
  if (type === "subscribe") return;
15
17
  if (typeof eventName === "symbol") return;
16
18
 
17
- this.logger.info({ message: `${eventName} emitted`, metadata: eventData, ...this.base });
19
+ this.deps.Logger.info({ message: `${eventName} emitted`, metadata: eventData, ...this.base });
18
20
  }
19
21
 
20
22
  handle = this._handle.bind(this);
@@ -4,12 +4,14 @@ import { formatError } from "./logger-format-error.service";
4
4
 
5
5
  type ServerType = ReturnType<typeof Bun.serve>;
6
6
 
7
+ type Dependencies = { Logger: LoggerPort };
8
+
7
9
  export class GracefulShutdown {
8
10
  private readonly base = { operation: "shutdown", component: "infra" } as const;
9
11
  private isShuttingDown = false;
10
12
 
11
13
  constructor(
12
- private readonly logger: LoggerPort,
14
+ private readonly deps: Dependencies,
13
15
  private readonly exitFn: (code: number) => never = ((code: number) => process.exit(code)) as never,
14
16
  ) {}
15
17
 
@@ -20,36 +22,44 @@ export class GracefulShutdown {
20
22
  try {
21
23
  server.stop();
22
24
  } catch (error) {
23
- this.logger.error({ message: "Server stop failed", error: formatError(error), ...this.base });
25
+ this.deps.Logger.error({ message: "Server stop failed", error: formatError(error), ...this.base });
24
26
  }
25
27
 
26
28
  Promise.resolve()
27
29
  .then(() => cleanup())
28
- .then(() => this.logger.info({ message: "HTTP server closed", ...this.base }))
30
+ .then(() => this.deps.Logger.info({ message: "HTTP server closed", ...this.base }))
29
31
  .catch((error) =>
30
- this.logger.error({ message: "Cleanup hook failed", error: formatError(error), ...this.base }),
32
+ this.deps.Logger.error({ message: "Cleanup hook failed", error: formatError(error), ...this.base }),
31
33
  )
32
34
  .finally(() => this.exitFn(exitCode));
33
35
  }
34
36
 
35
37
  applyTo(server: ServerType, cleanup: () => any = tools.noop) {
36
38
  process.once("SIGTERM", () => {
37
- this.logger.info({ message: "SIGTERM received", ...this.base });
39
+ this.deps.Logger.info({ message: "SIGTERM received", ...this.base });
38
40
  this.shutdown(server, cleanup, 0);
39
41
  });
40
42
 
41
43
  process.once("SIGINT", () => {
42
- this.logger.info({ message: "SIGINT received", ...this.base });
44
+ this.deps.Logger.info({ message: "SIGINT received", ...this.base });
43
45
  this.shutdown(server, cleanup, 0);
44
46
  });
45
47
 
46
48
  process.once("unhandledRejection", (reason) => {
47
- this.logger.error({ message: "UnhandledRejection received", error: formatError(reason), ...this.base });
49
+ this.deps.Logger.error({
50
+ message: "UnhandledRejection received",
51
+ error: formatError(reason),
52
+ ...this.base,
53
+ });
48
54
  this.shutdown(server, cleanup, 1);
49
55
  });
50
56
 
51
57
  process.once("uncaughtException", (error) => {
52
- this.logger.error({ message: "UncaughtException received", error: formatError(error), ...this.base });
58
+ this.deps.Logger.error({
59
+ message: "UncaughtException received",
60
+ error: formatError(error),
61
+ ...this.base,
62
+ });
53
63
  this.shutdown(server, cleanup, 1);
54
64
  });
55
65
  }
@@ -9,6 +9,7 @@ import { formatError } from "./logger-format-error.service";
9
9
  export type JobNameType = string;
10
10
  export type MultipleJobsType = Record<JobNameType, Cron>;
11
11
  export type JobProcessorType = { cron: string; label: JobNameType; process: () => Promise<void> };
12
+
12
13
  type Dependencies = { Logger: LoggerPort; IdProvider: IdProviderPort; Clock: ClockPort };
13
14
 
14
15
  export class Jobs {
@@ -5,28 +5,29 @@ import type { MailerPort } from "./mailer.port";
5
5
  import type { MailerSmtpAdapter } from "./mailer-smtp.adapter";
6
6
 
7
7
  type MailerSendOptionsType = SendMailOptions;
8
- type SmtpMailerWithLoggerConfigType = { smtpMailer: MailerSmtpAdapter; logger: LoggerPort };
8
+
9
+ type Dependencies = { MailerSmtp: MailerSmtpAdapter; Logger: LoggerPort };
9
10
 
10
11
  export class MailerSmtpWithLoggerAdapter implements MailerPort {
11
12
  private readonly base = { component: "infra", operation: "mailer" };
12
13
 
13
- constructor(private readonly config: SmtpMailerWithLoggerConfigType) {}
14
+ constructor(private readonly deps: Dependencies) {}
14
15
 
15
16
  async send(message: MailerSendOptionsType): Promise<unknown> {
16
17
  try {
17
- this.config.logger.info({ message: "Mailer attempt", metadata: message, ...this.base });
18
- const result = await this.config.smtpMailer.send(message);
19
- this.config.logger.info({ message: "Mailer success", metadata: { message, result }, ...this.base });
18
+ this.deps.Logger.info({ message: "Mailer attempt", metadata: message, ...this.base });
19
+ const result = await this.deps.MailerSmtp.send(message);
20
+ this.deps.Logger.info({ message: "Mailer success", metadata: { message, result }, ...this.base });
20
21
 
21
22
  return result;
22
23
  } catch (error) {
23
- this.config.logger.error({ message: "Mailer error", error: formatError(error), ...this.base });
24
+ this.deps.Logger.error({ message: "Mailer error", error: formatError(error), ...this.base });
24
25
 
25
26
  throw error;
26
27
  }
27
28
  }
28
29
 
29
30
  async verify() {
30
- return this.config.smtpMailer.verify();
31
+ return this.deps.MailerSmtp.verify();
31
32
  }
32
33
  }
@@ -4,13 +4,19 @@ import type { PdfGeneratorPort, PdfGeneratorTemplateType } from "./pdf-generator
4
4
  export const PLACEHOLDER_PDF_BASE64 =
5
5
  "JVBERi0xLjQKMSAwIG9iago8PC9UeXBlIC9DYXRhbG9nCi9QYWdlcyAyIDAgUgo+PgplbmRvYmoK MiAwIG9iago8PC9UeXBlIC9QYWdlcwovS2lkcyBbMyAwIFJdCi9Db3VudCAxCj4+CmVuZG9iagoz IDAgb2JqCjw8L1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA1OTUgODQy XQovQ29udGVudHMgNSAwIFIKL1Jlc291cmNlcyA8PC9Qcm9jU2V0IFsvUERGIC9UZXh0XQovRm9u dCA8PC9GMSA0IDAgUj4+Cj4+Cj4+CmVuZG9iago0IDAgb2JqCjw8L1R5cGUgL0ZvbnQKL1N1YnR5 cGUgL1R5cGUxCi9OYW1lIC9GMQovQmFzZUZvbnQgL0hlbHZldGljYQovRW5jb2RpbmcgL01hY1Jv bWFuRW5jb2RpbmcKPj4KZW5kb2JqCjUgMCBvYmoKPDwvTGVuZ3RoIDUzCj4+CnN0cmVhbQpCVAov RjEgMjAgVGYKMjIwIDQwMCBUZAooRHVtbXkgUERGKSBUagpFVAplbmRzdHJlYW0KZW5kb2JqCnhy ZWYKMCA2CjAwMDAwMDAwMDAgNjU1MzUgZgowMDAwMDAwMDA5IDAwMDAwIG4KMDAwMDAwMDA2MyAw MDAwMCBuCjAwMDAwMDAxMjQgMDAwMDAgbgowMDAwMDAwMjc3IDAwMDAwIG4KMDAwMDAwMDM5MiAw MDAwMCBuCnRyYWlsZXIKPDwvU2l6ZSA2Ci9Sb290IDEgMCBSCj4+CnN0YXJ0eHJlZgo0OTUKJSVF T0YK";
6
6
 
7
+ type Dependencies = { Logger: LoggerPort };
8
+
7
9
  export class PdfGeneratorNoopAdapter implements PdfGeneratorPort {
8
10
  private readonly base = { component: "infra", operation: "pdf_generator" };
9
11
 
10
- constructor(private readonly logger: LoggerPort) {}
12
+ constructor(private readonly deps: Dependencies) {}
11
13
 
12
14
  async request(template: PdfGeneratorTemplateType, data: Record<string, unknown>) {
13
- this.logger.info({ message: "[NOOP] PDF generator adapter", metadata: { template, data }, ...this.base });
15
+ this.deps.Logger.info({
16
+ message: "[NOOP] PDF generator adapter",
17
+ metadata: { template, data },
18
+ ...this.base,
19
+ });
14
20
 
15
21
  return Buffer.from(PLACEHOLDER_PDF_BASE64, "base64");
16
22
  }
@@ -11,13 +11,13 @@ export class PrerequisiteClockDrift implements prereqs.Prerequisite {
11
11
  readonly enabled?: boolean = true;
12
12
 
13
13
  readonly skew: tools.Duration;
14
- readonly timekeeper: TimekeeperPort;
14
+ readonly Timekeeper: TimekeeperPort;
15
15
  readonly timeout: tools.Duration;
16
16
 
17
17
  constructor(
18
18
  config: prereqs.PrerequisiteConfigType & {
19
19
  skew: tools.Duration;
20
- timekeeper?: TimekeeperPort;
20
+ Timekeeper?: TimekeeperPort;
21
21
  timeout?: tools.Duration;
22
22
  },
23
23
  ) {
@@ -25,7 +25,7 @@ export class PrerequisiteClockDrift implements prereqs.Prerequisite {
25
25
  this.enabled = config.enabled === undefined ? true : config.enabled;
26
26
 
27
27
  this.skew = config.skew;
28
- this.timekeeper = config.timekeeper ?? new TimekeeperGoogleAdapter();
28
+ this.Timekeeper = config.Timekeeper ?? new TimekeeperGoogleAdapter();
29
29
  this.timeout = config.timeout ?? tools.Duration.Seconds(2);
30
30
  }
31
31
 
@@ -36,7 +36,7 @@ export class PrerequisiteClockDrift implements prereqs.Prerequisite {
36
36
 
37
37
  try {
38
38
  const timestamp = await Timeout.cancellable(
39
- (signal: AbortSignal) => this.timekeeper.get(signal),
39
+ (signal: AbortSignal) => this.Timekeeper.get(signal),
40
40
  this.timeout,
41
41
  );
42
42
  if (!timestamp) return prereqs.Verification.undetermined(stopwatch.stop());
@@ -8,13 +8,13 @@ export class PrerequisiteLogFile implements prereqs.Prerequisite {
8
8
  readonly label: prereqs.PrerequisiteLabelType;
9
9
  readonly enabled?: boolean = true;
10
10
 
11
- private readonly logger: LoggerWinstonProductionAdapter;
11
+ private readonly Logger: LoggerWinstonProductionAdapter;
12
12
 
13
- constructor(config: prereqs.PrerequisiteConfigType & { logger: LoggerWinstonProductionAdapter }) {
13
+ constructor(config: prereqs.PrerequisiteConfigType & { Logger: LoggerWinstonProductionAdapter }) {
14
14
  this.label = config.label;
15
15
  this.enabled = config.enabled === undefined ? true : config.enabled;
16
16
 
17
- this.logger = config.logger;
17
+ this.Logger = config.Logger;
18
18
  }
19
19
 
20
20
  async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
@@ -23,7 +23,7 @@ export class PrerequisiteLogFile implements prereqs.Prerequisite {
23
23
  if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
24
24
 
25
25
  try {
26
- const path = this.logger.prodLogFile;
26
+ const path = this.Logger.prodLogFile;
27
27
  const result = await Bun.file(path).exists();
28
28
 
29
29
  if (result) return prereqs.Verification.success(stopwatch.stop());
@@ -9,14 +9,14 @@ export class PrerequisiteMailer implements prereqs.Prerequisite {
9
9
  readonly label: prereqs.PrerequisiteLabelType;
10
10
  readonly enabled?: boolean = true;
11
11
 
12
- private readonly mailer: MailerPort;
12
+ private readonly Mailer: MailerPort;
13
13
  readonly timeout: tools.Duration;
14
14
 
15
- constructor(config: prereqs.PrerequisiteConfigType & { mailer: MailerPort; timeout?: tools.Duration }) {
15
+ constructor(config: prereqs.PrerequisiteConfigType & { Mailer: MailerPort; timeout?: tools.Duration }) {
16
16
  this.label = config.label;
17
17
  this.enabled = config.enabled === undefined ? true : config.enabled;
18
18
 
19
- this.mailer = config.mailer;
19
+ this.Mailer = config.Mailer;
20
20
  this.timeout = config.timeout ?? tools.Duration.Seconds(2);
21
21
  }
22
22
 
@@ -26,7 +26,7 @@ export class PrerequisiteMailer implements prereqs.Prerequisite {
26
26
  if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
27
27
 
28
28
  try {
29
- await Timeout.run(this.mailer.verify(), this.timeout);
29
+ await Timeout.run(this.Mailer.verify(), this.timeout);
30
30
  return prereqs.Verification.success(stopwatch.stop());
31
31
  } catch (error) {
32
32
  return prereqs.Verification.failure(stopwatch.stop(), error as Error);
@@ -11,16 +11,16 @@ export class PrerequisiteSpace implements prereqs.Prerequisite {
11
11
  readonly enabled?: boolean = true;
12
12
 
13
13
  private readonly minimum: tools.Size;
14
- private readonly checker: DiskSpaceCheckerPort;
14
+ private readonly DiskSpaceChecker: DiskSpaceCheckerPort;
15
15
 
16
16
  constructor(
17
- config: prereqs.PrerequisiteConfigType & { minimum: tools.Size; checker?: DiskSpaceCheckerPort },
17
+ config: prereqs.PrerequisiteConfigType & { minimum: tools.Size; DiskSpaceChecker?: DiskSpaceCheckerPort },
18
18
  ) {
19
19
  this.label = config.label;
20
20
  this.enabled = config.enabled === undefined ? true : config.enabled;
21
21
 
22
22
  this.minimum = config.minimum;
23
- this.checker = config.checker ?? new DiskSpaceCheckerBunAdapter();
23
+ this.DiskSpaceChecker = config.DiskSpaceChecker ?? new DiskSpaceCheckerBunAdapter();
24
24
  }
25
25
 
26
26
  async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
@@ -30,7 +30,7 @@ export class PrerequisiteSpace implements prereqs.Prerequisite {
30
30
 
31
31
  try {
32
32
  const root = path.sep;
33
- const freeDiskSpace = await this.checker.get(root);
33
+ const freeDiskSpace = await this.DiskSpaceChecker.get(root);
34
34
 
35
35
  if (freeDiskSpace.isGreaterThan(this.minimum)) return prereqs.Verification.success(stopwatch.stop());
36
36
  return prereqs.Verification.failure(stopwatch.stop(), {
@@ -10,13 +10,13 @@ export class PrerequisiteSSLCertificateExpiry implements prereqs.Prerequisite {
10
10
 
11
11
  private readonly host: string;
12
12
  private readonly days: number;
13
- private readonly inspector: CertificateInspectorPort;
13
+ private readonly CertificateInspector: CertificateInspectorPort;
14
14
 
15
15
  constructor(
16
16
  config: prereqs.PrerequisiteConfigType & {
17
17
  host: string;
18
18
  days: number;
19
- inspector: CertificateInspectorPort;
19
+ CertificateInspector: CertificateInspectorPort;
20
20
  },
21
21
  ) {
22
22
  this.label = config.label;
@@ -24,7 +24,7 @@ export class PrerequisiteSSLCertificateExpiry implements prereqs.Prerequisite {
24
24
 
25
25
  this.host = config.host;
26
26
  this.days = config.days;
27
- this.inspector = config.inspector;
27
+ this.CertificateInspector = config.CertificateInspector;
28
28
  }
29
29
 
30
30
  async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
@@ -32,7 +32,7 @@ export class PrerequisiteSSLCertificateExpiry implements prereqs.Prerequisite {
32
32
 
33
33
  if (!this.enabled) return prereqs.Verification.undetermined(stopwatch.stop());
34
34
 
35
- const result = await this.inspector.inspect(this.host);
35
+ const result = await this.CertificateInspector.inspect(this.host);
36
36
 
37
37
  if (!result.success)
38
38
  return prereqs.Verification.failure(stopwatch.stop(), { message: "Certificate unavailable" });
@@ -23,15 +23,15 @@ export class PrerequisiteTranslations implements prereqs.Prerequisite {
23
23
  private readonly translationsPath?: typeof I18n.DEFAULT_TRANSLATIONS_PATH;
24
24
  private readonly supportedLanguages: types.I18nConfigType["supportedLanguages"];
25
25
 
26
- private readonly logger: LoggerPort;
27
- private readonly jsonFileReader: JsonFileReaderPort;
26
+ private readonly Logger: LoggerPort;
27
+ private readonly JsonFileReader: JsonFileReaderPort;
28
28
 
29
29
  constructor(
30
30
  config: prereqs.PrerequisiteConfigType & {
31
31
  translationsPath?: typeof I18n.DEFAULT_TRANSLATIONS_PATH;
32
32
  supportedLanguages: types.I18nConfigType["supportedLanguages"];
33
- logger: LoggerPort;
34
- jsonFileReader?: JsonFileReaderPort;
33
+ Logger: LoggerPort;
34
+ JsonFileReader?: JsonFileReaderPort;
35
35
  },
36
36
  ) {
37
37
  this.label = config.label;
@@ -40,8 +40,8 @@ export class PrerequisiteTranslations implements prereqs.Prerequisite {
40
40
  this.translationsPath = config.translationsPath;
41
41
  this.supportedLanguages = config.supportedLanguages;
42
42
 
43
- this.logger = config.logger;
44
- this.jsonFileReader = config.jsonFileReader ?? new JsonFileReaderBunForgivingAdapter();
43
+ this.Logger = config.Logger;
44
+ this.JsonFileReader = config.JsonFileReader ?? new JsonFileReaderBunForgivingAdapter();
45
45
  }
46
46
 
47
47
  async verify(clock: ClockPort): Promise<prereqs.VerifyOutcome> {
@@ -52,7 +52,7 @@ export class PrerequisiteTranslations implements prereqs.Prerequisite {
52
52
  const translationsPath = this.translationsPath ?? I18n.DEFAULT_TRANSLATIONS_PATH;
53
53
 
54
54
  const supportedLanguages = Object.keys(this.supportedLanguages);
55
- const i18n = new I18n({ Logger: this.logger, JsonFileReader: this.jsonFileReader });
55
+ const i18n = new I18n({ Logger: this.Logger, JsonFileReader: this.JsonFileReader });
56
56
 
57
57
  try {
58
58
  await fsp.access(translationsPath, constants.R_OK);
@@ -57,7 +57,7 @@ export type PrerequisiteConfigType = { label: string; enabled?: boolean };
57
57
 
58
58
  export const PrerequisitesError = { Failure: "prerequisites.failure" } as const;
59
59
 
60
- type Dependencies = { logger: LoggerPort; clock: ClockPort };
60
+ type Dependencies = { Logger: LoggerPort; Clock: ClockPort };
61
61
 
62
62
  /** @public */
63
63
  export class Prerequisites {
@@ -69,16 +69,16 @@ export class Prerequisites {
69
69
  const results = await Promise.all(
70
70
  prerequisites.map(async (prerequisite) => ({
71
71
  prerequisite,
72
- outcome: await prerequisite.verify(this.deps.clock),
72
+ outcome: await prerequisite.verify(this.deps.Clock),
73
73
  })),
74
74
  );
75
75
 
76
76
  const failed = results.filter((result) => result.outcome.status === PrerequisiteStatusEnum.failure);
77
77
 
78
- if (failed.length === 0) return this.deps.logger.info({ message: "Prerequisites ok", ...this.base });
78
+ if (failed.length === 0) return this.deps.Logger.info({ message: "Prerequisites ok", ...this.base });
79
79
 
80
80
  for (const failure of failed) {
81
- this.deps.logger.error({
81
+ this.deps.Logger.error({
82
82
  message: "Prerequisite failed",
83
83
  metadata: { label: failure.prerequisite.label, kind: failure.prerequisite.kind },
84
84
  // @ts-expect-error
@@ -8,20 +8,24 @@ import type {
8
8
  RemotePutFromPathResult,
9
9
  } from "./remote-file-storage.port";
10
10
 
11
- type RemoteFileStorageNoopConfig = { Logger: LoggerPort; Clock: ClockPort; publicBaseUrl?: string };
11
+ type RemoteFileStorageNoopConfig = { publicBaseUrl?: string };
12
+ type Dependencies = { Logger: LoggerPort; Clock: ClockPort };
12
13
 
13
14
  export class RemoteFileStorageNoopAdapter implements RemoteFileStoragePort {
14
15
  private readonly base = { component: "infra", operation: "RemoteFileStorageNoopAdapter" };
15
16
 
16
- constructor(private readonly config: RemoteFileStorageNoopConfig) {}
17
+ constructor(
18
+ private readonly deps: Dependencies,
19
+ private readonly config?: RemoteFileStorageNoopConfig,
20
+ ) {}
17
21
 
18
22
  publicUrl(key: tools.ObjectKeyType): string {
19
- if (!this.config.publicBaseUrl) return `/${key}`;
20
- return `${this.config.publicBaseUrl}/${key}`;
23
+ if (!this.config?.publicBaseUrl) return `/${key}`;
24
+ return `${this.config?.publicBaseUrl}/${key}`;
21
25
  }
22
26
 
23
27
  async putFromPath(input: RemotePutFromPathInput): Promise<RemotePutFromPathResult> {
24
- this.config.Logger.info({
28
+ this.deps.Logger.info({
25
29
  message: "[NOOP] RemoteFileStorageNoopAdapter putFromPath",
26
30
  metadata: { input },
27
31
  ...this.base,
@@ -30,13 +34,13 @@ export class RemoteFileStorageNoopAdapter implements RemoteFileStoragePort {
30
34
  return {
31
35
  etag: "noop",
32
36
  size: tools.Size.fromBytes(10),
33
- lastModified: this.config.Clock.now(),
37
+ lastModified: this.deps.Clock.now(),
34
38
  mime: new tools.Mime("text/plain"),
35
39
  };
36
40
  }
37
41
 
38
42
  async head(key: tools.ObjectKeyType): Promise<RemoteHeadResult> {
39
- this.config.Logger.info({
43
+ this.deps.Logger.info({
40
44
  message: "[NOOP] RemoteFileStorageNoopAdapter head",
41
45
  metadata: { key },
42
46
  ...this.base,
@@ -46,7 +50,7 @@ export class RemoteFileStorageNoopAdapter implements RemoteFileStoragePort {
46
50
  }
47
51
 
48
52
  async getStream(key: tools.ObjectKeyType): Promise<ReadableStream | null> {
49
- this.config.Logger.info({
53
+ this.deps.Logger.info({
50
54
  message: "[NOOP] RemoteFileStorageNoopAdapter getStream",
51
55
  metadata: { key },
52
56
  ...this.base,
@@ -56,7 +60,7 @@ export class RemoteFileStorageNoopAdapter implements RemoteFileStoragePort {
56
60
  }
57
61
 
58
62
  async delete(key: tools.ObjectKeyType): Promise<void> {
59
- this.config.Logger.info({
63
+ this.deps.Logger.info({
60
64
  message: "[NOOP] RemoteFileStorageNoopAdapter delete",
61
65
  metadata: { key },
62
66
  ...this.base,
@@ -7,6 +7,7 @@ import type { RateLimitStorePort } from "./rate-limit-store.port";
7
7
 
8
8
  type SubjectResolver = (c: Context) => string;
9
9
  type RateLimitShieldOptionsType = { enabled: boolean; store: RateLimitStorePort; subject: SubjectResolver };
10
+
10
11
  type Dependencies = { Clock: ClockPort };
11
12
 
12
13
  export const AnonSubjectResolver: SubjectResolver = () => "anon";
@@ -1,10 +1,12 @@
1
1
  import type { ClockPort } from "./clock.port";
2
2
  import type { TimekeeperPort } from "./timekeeper.port";
3
3
 
4
+ type Dependencies = { Clock: ClockPort };
5
+
4
6
  export class TimekeeperNoopAdapter implements TimekeeperPort {
5
- constructor(private readonly clock: ClockPort) {}
7
+ constructor(private readonly deps: Dependencies) {}
6
8
 
7
9
  async get() {
8
- return this.clock.now();
10
+ return this.deps.Clock.now();
9
11
  }
10
12
  }
@@ -6,6 +6,7 @@ import type { LoggerPort } from "./logger.port";
6
6
  const handler = createFactory();
7
7
 
8
8
  type Config = TranslationsSupportedLanguagesType;
9
+
9
10
  type Dependencies = { JsonFileReader: JsonFileReaderPort; Logger: LoggerPort };
10
11
 
11
12
  export class Translations {