@bgord/bun 1.23.12 → 1.24.1
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/atomic-file-writer-collecting.adapter.d.ts +8 -0
- package/dist/atomic-file-writer-collecting.adapter.d.ts.map +1 -0
- package/dist/atomic-file-writer-collecting.adapter.js +7 -0
- package/dist/atomic-file-writer-collecting.adapter.js.map +1 -0
- package/dist/atomic-file-writer-noop.adapter.d.ts +7 -0
- package/dist/atomic-file-writer-noop.adapter.d.ts.map +1 -0
- package/dist/atomic-file-writer-noop.adapter.js +4 -0
- package/dist/atomic-file-writer-noop.adapter.js.map +1 -0
- package/dist/atomic-file-writer.adapter.d.ts +19 -0
- package/dist/atomic-file-writer.adapter.d.ts.map +1 -0
- package/dist/atomic-file-writer.adapter.js +18 -0
- package/dist/atomic-file-writer.adapter.js.map +1 -0
- package/dist/atomic-file-writer.port.d.ts +6 -0
- package/dist/atomic-file-writer.port.d.ts.map +1 -0
- package/dist/atomic-file-writer.port.js +2 -0
- package/dist/atomic-file-writer.port.js.map +1 -0
- package/dist/encryption-aes-gcm.adapter.d.ts +2 -2
- package/dist/encryption-aes-gcm.adapter.d.ts.map +1 -1
- package/dist/encryption-aes-gcm.adapter.js +2 -2
- package/dist/encryption-aes-gcm.adapter.js.map +1 -1
- package/dist/event-sourced-repository.adapter.d.ts +27 -0
- package/dist/event-sourced-repository.adapter.d.ts.map +1 -0
- package/dist/event-sourced-repository.adapter.js +16 -0
- package/dist/event-sourced-repository.adapter.js.map +1 -0
- package/dist/event-stream-accept.service.d.ts +4 -0
- package/dist/event-stream-accept.service.d.ts.map +1 -0
- package/dist/event-stream-accept.service.js +11 -0
- package/dist/event-stream-accept.service.js.map +1 -0
- package/dist/gzip.adapter.d.ts +2 -2
- package/dist/gzip.adapter.d.ts.map +1 -1
- package/dist/gzip.adapter.js +1 -1
- package/dist/gzip.adapter.js.map +1 -1
- package/dist/healthcheck.handler.d.ts +4 -2
- package/dist/healthcheck.handler.d.ts.map +1 -1
- package/dist/healthcheck.handler.js +4 -11
- package/dist/healthcheck.handler.js.map +1 -1
- package/dist/http-exception-errors.js +2 -2
- package/dist/http-exception-errors.js.map +1 -1
- package/dist/http-logger-hono.middleware.d.ts +1 -0
- package/dist/http-logger-hono.middleware.d.ts.map +1 -1
- package/dist/http-logger-hono.middleware.js +10 -6
- package/dist/http-logger-hono.middleware.js.map +1 -1
- package/dist/http-logger.middleware.d.ts.map +1 -1
- package/dist/http-logger.middleware.js +4 -6
- package/dist/http-logger.middleware.js.map +1 -1
- package/dist/image-blur.adapter.d.ts +2 -6
- package/dist/image-blur.adapter.d.ts.map +1 -1
- package/dist/image-blur.adapter.js +1 -4
- package/dist/image-blur.adapter.js.map +1 -1
- package/dist/image-compressor.adapter.d.ts +2 -6
- package/dist/image-compressor.adapter.d.ts.map +1 -1
- package/dist/image-compressor.adapter.js +1 -4
- package/dist/image-compressor.adapter.js.map +1 -1
- package/dist/image-exif-clear.adapter.d.ts +2 -6
- package/dist/image-exif-clear.adapter.d.ts.map +1 -1
- package/dist/image-exif-clear.adapter.js +1 -3
- package/dist/image-exif-clear.adapter.js.map +1 -1
- package/dist/image-formatter.adapter.d.ts +2 -6
- package/dist/image-formatter.adapter.d.ts.map +1 -1
- package/dist/image-formatter.adapter.js +1 -3
- package/dist/image-formatter.adapter.js.map +1 -1
- package/dist/image-grayscale.adapter.d.ts +2 -6
- package/dist/image-grayscale.adapter.d.ts.map +1 -1
- package/dist/image-grayscale.adapter.js +1 -4
- package/dist/image-grayscale.adapter.js.map +1 -1
- package/dist/image-processor.adapter.d.ts +2 -6
- package/dist/image-processor.adapter.d.ts.map +1 -1
- package/dist/image-processor.adapter.js +1 -3
- package/dist/image-processor.adapter.js.map +1 -1
- package/dist/image-resizer.adapter.d.ts +2 -6
- package/dist/image-resizer.adapter.d.ts.map +1 -1
- package/dist/image-resizer.adapter.js +1 -4
- package/dist/image-resizer.adapter.js.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/job-pruner-sqlite.adapter.d.ts.map +1 -1
- package/dist/job-pruner-sqlite.adapter.js +2 -1
- package/dist/job-pruner-sqlite.adapter.js.map +1 -1
- package/dist/job-queue-stats-provider-sqlite.adapter.js +4 -4
- package/dist/job-queue-stats-provider-sqlite.adapter.js.map +1 -1
- package/dist/job-recoverer-collecting.adapter.d.ts +7 -0
- package/dist/job-recoverer-collecting.adapter.d.ts.map +1 -0
- package/dist/job-recoverer-collecting.adapter.js +10 -0
- package/dist/job-recoverer-collecting.adapter.js.map +1 -0
- package/dist/job-recoverer-noop.adapter.d.ts +6 -0
- package/dist/job-recoverer-noop.adapter.d.ts.map +1 -0
- package/dist/job-recoverer-noop.adapter.js +7 -0
- package/dist/job-recoverer-noop.adapter.js.map +1 -0
- package/dist/job-recoverer-sqlite.adapter.d.ts +13 -0
- package/dist/job-recoverer-sqlite.adapter.d.ts.map +1 -0
- package/dist/job-recoverer-sqlite.adapter.js +14 -0
- package/dist/job-recoverer-sqlite.adapter.js.map +1 -0
- package/dist/job-recoverer.port.d.ts +5 -0
- package/dist/job-recoverer.port.d.ts.map +1 -0
- package/dist/job-recoverer.port.js +2 -0
- package/dist/job-recoverer.port.js.map +1 -0
- package/dist/memory-consumption.service.d.ts +1 -2
- package/dist/memory-consumption.service.d.ts.map +1 -1
- package/dist/memory-consumption.service.js.map +1 -1
- package/dist/message-bus-strict.adapter.d.ts +19 -0
- package/dist/message-bus-strict.adapter.d.ts.map +1 -0
- package/dist/message-bus-strict.adapter.js +24 -0
- package/dist/message-bus-strict.adapter.js.map +1 -0
- package/dist/path-matcher.service.d.ts +6 -0
- package/dist/path-matcher.service.d.ts.map +1 -0
- package/dist/path-matcher.service.js +13 -0
- package/dist/path-matcher.service.js.map +1 -0
- package/dist/remote-file-storage-disk.adapter.d.ts +2 -6
- package/dist/remote-file-storage-disk.adapter.d.ts.map +1 -1
- package/dist/remote-file-storage-disk.adapter.js +1 -9
- package/dist/remote-file-storage-disk.adapter.js.map +1 -1
- package/dist/request-context-hono.adapter.d.ts +1 -1
- package/dist/request-context-hono.adapter.d.ts.map +1 -1
- package/dist/request-context-hono.adapter.js +3 -3
- package/dist/request-context-hono.adapter.js.map +1 -1
- package/dist/request-context.port.d.ts +4 -0
- package/dist/request-context.port.d.ts.map +1 -1
- package/dist/request-context.port.js +4 -1
- package/dist/request-context.port.js.map +1 -1
- package/dist/runtime-stats-provider-noop.adapter.d.ts +5 -0
- package/dist/runtime-stats-provider-noop.adapter.d.ts.map +1 -0
- package/dist/runtime-stats-provider-noop.adapter.js +14 -0
- package/dist/runtime-stats-provider-noop.adapter.js.map +1 -0
- package/dist/runtime-stats-provider-system.adapter.d.ts +12 -0
- package/dist/runtime-stats-provider-system.adapter.d.ts.map +1 -0
- package/dist/runtime-stats-provider-system.adapter.js +21 -0
- package/dist/runtime-stats-provider-system.adapter.js.map +1 -0
- package/dist/runtime-stats-provider.port.d.ts +18 -0
- package/dist/runtime-stats-provider.port.d.ts.map +1 -0
- package/dist/runtime-stats-provider.port.js +2 -0
- package/dist/runtime-stats-provider.port.js.map +1 -0
- package/dist/security-rule-violation-threshold.strategy.js +1 -1
- package/dist/security-rule-violation-threshold.strategy.js.map +1 -1
- package/dist/setup-hono.service.js +1 -1
- package/dist/setup-hono.service.js.map +1 -1
- package/dist/shield-auth-hono.strategy.d.ts.map +1 -1
- package/dist/shield-auth-hono.strategy.js +4 -3
- package/dist/shield-auth-hono.strategy.js.map +1 -1
- package/dist/shield-auth.strategy.d.ts +1 -5
- package/dist/shield-auth.strategy.d.ts.map +1 -1
- package/dist/shield-auth.strategy.js +3 -6
- package/dist/shield-auth.strategy.js.map +1 -1
- package/dist/shield-maintenance.strategy.d.ts.map +1 -1
- package/dist/shield-maintenance.strategy.js +2 -5
- package/dist/shield-maintenance.strategy.js.map +1 -1
- package/dist/temporary-file-absolute.adapter.d.ts +2 -6
- package/dist/temporary-file-absolute.adapter.d.ts.map +1 -1
- package/dist/temporary-file-absolute.adapter.js +1 -9
- package/dist/temporary-file-absolute.adapter.js.map +1 -1
- package/dist/timing.middleware.d.ts +0 -1
- package/dist/timing.middleware.d.ts.map +1 -1
- package/dist/timing.middleware.js +2 -9
- package/dist/timing.middleware.js.map +1 -1
- package/package.json +5 -5
- package/readme.md +15 -0
- package/src/atomic-file-writer-collecting.adapter.ts +14 -0
- package/src/atomic-file-writer-noop.adapter.ts +10 -0
- package/src/atomic-file-writer.adapter.ts +34 -0
- package/src/atomic-file-writer.port.ts +6 -0
- package/src/encryption-aes-gcm.adapter.ts +4 -4
- package/src/event-sourced-repository.adapter.ts +48 -0
- package/src/event-stream-accept.service.ts +10 -0
- package/src/gzip.adapter.ts +3 -3
- package/src/healthcheck.handler.ts +8 -11
- package/src/http-exception-errors.ts +2 -2
- package/src/http-logger-hono.middleware.ts +12 -6
- package/src/http-logger.middleware.ts +4 -7
- package/src/image-blur.adapter.ts +3 -13
- package/src/image-compressor.adapter.ts +3 -12
- package/src/image-exif-clear.adapter.ts +3 -11
- package/src/image-formatter.adapter.ts +3 -12
- package/src/image-grayscale.adapter.ts +3 -13
- package/src/image-processor.adapter.ts +3 -11
- package/src/image-resizer.adapter.ts +3 -12
- package/src/index.ts +13 -0
- package/src/job-pruner-sqlite.adapter.ts +2 -1
- package/src/job-queue-stats-provider-sqlite.adapter.ts +4 -4
- package/src/job-recoverer-collecting.adapter.ts +14 -0
- package/src/job-recoverer-noop.adapter.ts +8 -0
- package/src/job-recoverer-sqlite.adapter.ts +20 -0
- package/src/job-recoverer.port.ts +5 -0
- package/src/memory-consumption.service.ts +4 -1
- package/src/message-bus-strict.adapter.ts +33 -0
- package/src/path-matcher.service.ts +14 -0
- package/src/remote-file-storage-disk.adapter.ts +3 -17
- package/src/request-context-hono.adapter.ts +3 -4
- package/src/request-context.port.ts +5 -0
- package/src/runtime-stats-provider-noop.adapter.ts +16 -0
- package/src/runtime-stats-provider-system.adapter.ts +24 -0
- package/src/runtime-stats-provider.port.ts +16 -0
- package/src/security-rule-violation-threshold.strategy.ts +2 -2
- package/src/setup-hono.service.ts +1 -1
- package/src/shield-auth-hono.strategy.ts +4 -3
- package/src/shield-auth.strategy.ts +3 -8
- package/src/shield-maintenance.strategy.ts +2 -6
- package/src/temporary-file-absolute.adapter.ts +3 -18
- package/src/timing.middleware.ts +2 -10
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
import type * as tools from "@bgord/tools";
|
|
3
|
-
import type {
|
|
4
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
3
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
5
4
|
import type { ImageBlurPort, ImageBlurStrategy } from "./image-blur.port";
|
|
6
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
7
5
|
|
|
8
6
|
type Dependencies = {
|
|
9
|
-
|
|
10
|
-
FileWriter: FileWriterPort;
|
|
11
|
-
NonceProvider: NonceProviderPort;
|
|
7
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
12
8
|
};
|
|
13
9
|
|
|
14
10
|
export class ImageBlurAdapter implements ImageBlurPort {
|
|
@@ -17,16 +13,10 @@ export class ImageBlurAdapter implements ImageBlurPort {
|
|
|
17
13
|
async blur(recipe: ImageBlurStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
|
|
18
14
|
const final = recipe.output;
|
|
19
15
|
|
|
20
|
-
const filename = final.getFilename();
|
|
21
|
-
const temporary = final.withFilename(
|
|
22
|
-
filename.withSuffix(`-blurred-${this.deps.NonceProvider.generate()}`),
|
|
23
|
-
);
|
|
24
|
-
|
|
25
16
|
const blurred = await Bun.file(recipe.input.get()).image().placeholder();
|
|
26
17
|
const bytes = Buffer.from(blurred.substring(blurred.indexOf(",") + 1), "base64");
|
|
27
18
|
|
|
28
|
-
await this.deps.
|
|
29
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
19
|
+
await this.deps.AtomicFileWriter.write(final, bytes);
|
|
30
20
|
|
|
31
21
|
return final;
|
|
32
22
|
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
import type * as tools from "@bgord/tools";
|
|
3
|
-
import type {
|
|
4
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
3
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
5
4
|
import type { ImageSupportedType } from "./image.types";
|
|
6
5
|
import type { ImageCompressorPort, ImageCompressorStrategy } from "./image-compressor.port";
|
|
7
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
8
6
|
|
|
9
7
|
type Dependencies = {
|
|
10
|
-
|
|
11
|
-
FileWriter: FileWriterPort;
|
|
12
|
-
NonceProvider: NonceProviderPort;
|
|
8
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
13
9
|
};
|
|
14
10
|
|
|
15
11
|
export class ImageCompressorAdapter implements ImageCompressorPort {
|
|
@@ -21,18 +17,13 @@ export class ImageCompressorAdapter implements ImageCompressorPort {
|
|
|
21
17
|
const quality = recipe.quality ?? ImageCompressorAdapter.DEFAULT_QUALITY;
|
|
22
18
|
|
|
23
19
|
const final = recipe.strategy === "output_path" ? recipe.output : recipe.input;
|
|
24
|
-
const filename = final.getFilename();
|
|
25
|
-
const temporary = final.withFilename(
|
|
26
|
-
filename.withSuffix(`-compressed-${this.deps.NonceProvider.generate()}`),
|
|
27
|
-
);
|
|
28
20
|
|
|
29
21
|
const extension = final.getFilename().getExtension();
|
|
30
22
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
31
23
|
|
|
32
24
|
const compressed = await Bun.file(recipe.input.get()).image().rotate(0)[format]({ quality }).bytes();
|
|
33
25
|
|
|
34
|
-
await this.deps.
|
|
35
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
26
|
+
await this.deps.AtomicFileWriter.write(final, compressed);
|
|
36
27
|
|
|
37
28
|
return final;
|
|
38
29
|
}
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
// cspell:ignore Exif
|
|
3
3
|
import type * as tools from "@bgord/tools";
|
|
4
|
-
import type {
|
|
5
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
4
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
6
5
|
import type { ImageSupportedType } from "./image.types";
|
|
7
6
|
import type { ImageExifClearPort, ImageExifClearStrategy } from "./image-exif-clear.port";
|
|
8
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
9
7
|
|
|
10
8
|
type Dependencies = {
|
|
11
|
-
|
|
12
|
-
FileWriter: FileWriterPort;
|
|
13
|
-
NonceProvider: NonceProviderPort;
|
|
9
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
14
10
|
};
|
|
15
11
|
|
|
16
12
|
export class ImageExifClearAdapter implements ImageExifClearPort {
|
|
@@ -18,17 +14,13 @@ export class ImageExifClearAdapter implements ImageExifClearPort {
|
|
|
18
14
|
|
|
19
15
|
async clear(recipe: ImageExifClearStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
|
|
20
16
|
const final = recipe.strategy === "output_path" ? recipe.output : recipe.input;
|
|
21
|
-
const temporary = final.withFilename(
|
|
22
|
-
final.getFilename().withSuffix(`-exif-cleared-${this.deps.NonceProvider.generate()}`),
|
|
23
|
-
);
|
|
24
17
|
|
|
25
18
|
const extension = final.getFilename().getExtension();
|
|
26
19
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
27
20
|
|
|
28
21
|
const cleared = await Bun.file(recipe.input.get()).image().rotate(0)[format]().bytes();
|
|
29
22
|
|
|
30
|
-
await this.deps.
|
|
31
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
23
|
+
await this.deps.AtomicFileWriter.write(final, cleared);
|
|
32
24
|
|
|
33
25
|
return final;
|
|
34
26
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
import type * as tools from "@bgord/tools";
|
|
3
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
3
4
|
import type { FileCleanerPort } from "./file-cleaner.port";
|
|
4
|
-
import type { FileRenamerPort } from "./file-renamer.port";
|
|
5
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
6
5
|
import type { ImageSupportedType } from "./image.types";
|
|
7
6
|
import type { ImageFormatterPort, ImageFormatterStrategy } from "./image-formatter.port";
|
|
8
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
9
7
|
|
|
10
8
|
type Dependencies = {
|
|
9
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
11
10
|
FileCleaner: FileCleanerPort;
|
|
12
|
-
FileRenamer: FileRenamerPort;
|
|
13
|
-
FileWriter: FileWriterPort;
|
|
14
|
-
NonceProvider: NonceProviderPort;
|
|
15
11
|
};
|
|
16
12
|
|
|
17
13
|
export class ImageFormatterAdapter implements ImageFormatterPort {
|
|
@@ -23,17 +19,12 @@ export class ImageFormatterAdapter implements ImageFormatterPort {
|
|
|
23
19
|
? recipe.output
|
|
24
20
|
: recipe.input.withFilename(recipe.input.getFilename().withExtension(recipe.to));
|
|
25
21
|
|
|
26
|
-
const temporary = final.withFilename(
|
|
27
|
-
final.getFilename().withSuffix(`-formatted-${this.deps.NonceProvider.generate()}`),
|
|
28
|
-
);
|
|
29
|
-
|
|
30
22
|
const extension = final.getFilename().getExtension();
|
|
31
23
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
32
24
|
|
|
33
25
|
const bytes = await Bun.file(recipe.input.get()).image().rotate(0)[format]().bytes();
|
|
34
26
|
|
|
35
|
-
await this.deps.
|
|
36
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
27
|
+
await this.deps.AtomicFileWriter.write(final, bytes);
|
|
37
28
|
|
|
38
29
|
if (recipe.strategy === "in_place" && final.get() !== recipe.input.get()) {
|
|
39
30
|
await this.deps.FileCleaner.delete(recipe.input.get());
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
// cspell:ignore grayscaled
|
|
3
3
|
import type * as tools from "@bgord/tools";
|
|
4
|
-
import type {
|
|
5
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
4
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
6
5
|
import type { ImageSupportedType } from "./image.types";
|
|
7
6
|
import type { ImageGrayscalePort, ImageGrayscaleStrategy } from "./image-grayscale.port";
|
|
8
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
9
7
|
|
|
10
8
|
type Dependencies = {
|
|
11
|
-
|
|
12
|
-
FileWriter: FileWriterPort;
|
|
13
|
-
NonceProvider: NonceProviderPort;
|
|
9
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
14
10
|
};
|
|
15
11
|
|
|
16
12
|
export class ImageGrayscaleAdapter implements ImageGrayscalePort {
|
|
@@ -19,11 +15,6 @@ export class ImageGrayscaleAdapter implements ImageGrayscalePort {
|
|
|
19
15
|
async grayscale(recipe: ImageGrayscaleStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
|
|
20
16
|
const final = recipe.strategy === "output_path" ? recipe.output : recipe.input;
|
|
21
17
|
|
|
22
|
-
const filename = final.getFilename();
|
|
23
|
-
const temporary = final.withFilename(
|
|
24
|
-
filename.withSuffix(`-grayscale-${this.deps.NonceProvider.generate()}`),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
18
|
const extension = final.getFilename().getExtension();
|
|
28
19
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
29
20
|
|
|
@@ -34,8 +25,7 @@ export class ImageGrayscaleAdapter implements ImageGrayscalePort {
|
|
|
34
25
|
[format]()
|
|
35
26
|
.bytes();
|
|
36
27
|
|
|
37
|
-
await this.deps.
|
|
38
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
28
|
+
await this.deps.AtomicFileWriter.write(final, grayscaled);
|
|
39
29
|
|
|
40
30
|
return final;
|
|
41
31
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
import type * as tools from "@bgord/tools";
|
|
3
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
3
4
|
import type { FileCleanerPort } from "./file-cleaner.port";
|
|
4
|
-
import type { FileRenamerPort } from "./file-renamer.port";
|
|
5
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
6
5
|
import type { ImageSupportedType } from "./image.types";
|
|
7
6
|
import type { ImageProcessorPort, ImageProcessorStrategy } from "./image-processor.port";
|
|
8
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
9
7
|
|
|
10
8
|
type Dependencies = {
|
|
9
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
11
10
|
FileCleaner: FileCleanerPort;
|
|
12
|
-
FileRenamer: FileRenamerPort;
|
|
13
|
-
FileWriter: FileWriterPort;
|
|
14
|
-
NonceProvider: NonceProviderPort;
|
|
15
11
|
};
|
|
16
12
|
|
|
17
13
|
export class ImageProcessorAdapter implements ImageProcessorPort {
|
|
@@ -25,9 +21,6 @@ export class ImageProcessorAdapter implements ImageProcessorPort {
|
|
|
25
21
|
? recipe.output
|
|
26
22
|
: recipe.input.withFilename(recipe.input.getFilename().withExtension(recipe.to));
|
|
27
23
|
|
|
28
|
-
const temporary = final.withFilename(
|
|
29
|
-
final.getFilename().withSuffix(`-processed-${this.deps.NonceProvider.generate()}`),
|
|
30
|
-
);
|
|
31
24
|
const extension = final.getFilename().getExtension();
|
|
32
25
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
33
26
|
const quality = recipe.quality ?? ImageProcessorAdapter.DEFAULT_QUALITY;
|
|
@@ -39,8 +32,7 @@ export class ImageProcessorAdapter implements ImageProcessorPort {
|
|
|
39
32
|
[format]({ quality })
|
|
40
33
|
.bytes();
|
|
41
34
|
|
|
42
|
-
await this.deps.
|
|
43
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
35
|
+
await this.deps.AtomicFileWriter.write(final, processed);
|
|
44
36
|
|
|
45
37
|
if (recipe.strategy === "in_place" && final.get() !== recipe.input.get()) {
|
|
46
38
|
await this.deps.FileCleaner.delete(recipe.input.get());
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
// cspell:ignore Resizer
|
|
3
3
|
import type * as tools from "@bgord/tools";
|
|
4
|
-
import type {
|
|
5
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
4
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
6
5
|
import type { ImageSupportedType } from "./image.types";
|
|
7
6
|
import type { ImageResizerPort, ImageResizerStrategy } from "./image-resizer.port";
|
|
8
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
9
7
|
|
|
10
8
|
type Dependencies = {
|
|
11
|
-
|
|
12
|
-
FileRenamer: FileRenamerPort;
|
|
13
|
-
NonceProvider: NonceProviderPort;
|
|
9
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
14
10
|
};
|
|
15
11
|
|
|
16
12
|
export class ImageResizerAdapter implements ImageResizerPort {
|
|
@@ -18,10 +14,6 @@ export class ImageResizerAdapter implements ImageResizerPort {
|
|
|
18
14
|
|
|
19
15
|
async resize(recipe: ImageResizerStrategy): Promise<tools.FilePathRelative | tools.FilePathAbsolute> {
|
|
20
16
|
const final = recipe.strategy === "output_path" ? recipe.output : recipe.input;
|
|
21
|
-
const filename = final.getFilename();
|
|
22
|
-
const temporary = final.withFilename(
|
|
23
|
-
filename.withSuffix(`-resized-${this.deps.NonceProvider.generate()}`),
|
|
24
|
-
);
|
|
25
17
|
|
|
26
18
|
const extension = final.getFilename().getExtension();
|
|
27
19
|
const format = (extension === "jpg" ? "jpeg" : extension) as ImageSupportedType;
|
|
@@ -32,8 +24,7 @@ export class ImageResizerAdapter implements ImageResizerPort {
|
|
|
32
24
|
[format]()
|
|
33
25
|
.bytes();
|
|
34
26
|
|
|
35
|
-
await this.deps.
|
|
36
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
27
|
+
await this.deps.AtomicFileWriter.write(final, resized);
|
|
37
28
|
|
|
38
29
|
return final;
|
|
39
30
|
}
|
package/src/index.ts
CHANGED
|
@@ -36,6 +36,10 @@ export * from "./antivirus-with-semaphore.adapter";
|
|
|
36
36
|
export * from "./antivirus-with-timeout.adapter";
|
|
37
37
|
export * from "./api-version.middleware";
|
|
38
38
|
export * from "./api-version-hono.middleware";
|
|
39
|
+
export * from "./atomic-file-writer.adapter";
|
|
40
|
+
export * from "./atomic-file-writer.port";
|
|
41
|
+
export * from "./atomic-file-writer-collecting.adapter";
|
|
42
|
+
export * from "./atomic-file-writer-noop.adapter";
|
|
39
43
|
export * from "./auth-session-reader.port";
|
|
40
44
|
export * from "./auth-session-reader-better-auth.adapter";
|
|
41
45
|
export * from "./auth-session-reader-noop.adapter";
|
|
@@ -148,6 +152,7 @@ export * from "./event-loop-lag.service";
|
|
|
148
152
|
export * from "./event-loop-utilization.service";
|
|
149
153
|
export * from "./event-revision-assigner.adapter";
|
|
150
154
|
export * from "./event-revision-assigner.port";
|
|
155
|
+
export * from "./event-sourced-repository.adapter";
|
|
151
156
|
export * from "./event-store.adapter";
|
|
152
157
|
export * from "./event-store.port";
|
|
153
158
|
export * from "./event-store-collecting.adapter";
|
|
@@ -311,6 +316,10 @@ export * from "./job-queue-stats-provider-noop.adapter";
|
|
|
311
316
|
export * from "./job-queue-stats-provider-sqlite.adapter";
|
|
312
317
|
export * from "./job-queue-with-logger.adapter";
|
|
313
318
|
export * from "./job-queue-worker.service";
|
|
319
|
+
export * from "./job-recoverer.port";
|
|
320
|
+
export * from "./job-recoverer-collecting.adapter";
|
|
321
|
+
export * from "./job-recoverer-noop.adapter";
|
|
322
|
+
export * from "./job-recoverer-sqlite.adapter";
|
|
314
323
|
export * from "./job-registry.adapter";
|
|
315
324
|
export * from "./job-registry.port";
|
|
316
325
|
export * from "./job-requeuer.port";
|
|
@@ -359,6 +368,7 @@ export * from "./message-bus.port";
|
|
|
359
368
|
export * from "./message-bus-collecting.adapter";
|
|
360
369
|
export * from "./message-bus-emittery.adapter";
|
|
361
370
|
export * from "./message-bus-noop.adapter";
|
|
371
|
+
export * from "./message-bus-strict.adapter";
|
|
362
372
|
export * from "./message-bus-with-logger.adapter";
|
|
363
373
|
export * from "./middleware-hono.port";
|
|
364
374
|
export * from "./middleware-hono-noop.adapter";
|
|
@@ -441,6 +451,9 @@ export * from "./retry-backoff-exponential.strategy";
|
|
|
441
451
|
export * from "./retry-backoff-jitter.strategy";
|
|
442
452
|
export * from "./retry-backoff-linear.strategy";
|
|
443
453
|
export * from "./retry-backoff-noop.strategy";
|
|
454
|
+
export * from "./runtime-stats-provider.port";
|
|
455
|
+
export * from "./runtime-stats-provider-noop.adapter";
|
|
456
|
+
export * from "./runtime-stats-provider-system.adapter";
|
|
444
457
|
export * from "./sealer.port";
|
|
445
458
|
export * from "./sealer-aes-gcm.adapter";
|
|
446
459
|
export * from "./sealer-noop.adapter";
|
|
@@ -3,6 +3,7 @@ import type { Database } from "bun:sqlite";
|
|
|
3
3
|
import * as tools from "@bgord/tools";
|
|
4
4
|
import type { ClockPort } from "./clock.port";
|
|
5
5
|
import type { JobPrunerPort } from "./job-pruner.port";
|
|
6
|
+
import { JobStatusEnum } from "./job-status.vo";
|
|
6
7
|
|
|
7
8
|
type Dependencies = { db: Database; Clock: ClockPort };
|
|
8
9
|
|
|
@@ -14,7 +15,7 @@ export class JobPrunerSqliteAdapter implements JobPrunerPort {
|
|
|
14
15
|
|
|
15
16
|
const result = this.deps.db.run<[tools.TimestampValueType]>(
|
|
16
17
|
`DELETE FROM jobs
|
|
17
|
-
WHERE status IN ('completed', 'failed')
|
|
18
|
+
WHERE status IN ('${JobStatusEnum.completed}', '${JobStatusEnum.failed}')
|
|
18
19
|
AND createdAt <= ?`,
|
|
19
20
|
[threshold],
|
|
20
21
|
);
|
|
@@ -25,10 +25,10 @@ export class JobQueueStatsProviderSqliteAdapter implements JobQueueStatsProvider
|
|
|
25
25
|
const counts = Object.fromEntries(snapshot.map((row) => [row.status, row.count]));
|
|
26
26
|
|
|
27
27
|
return {
|
|
28
|
-
pending: tools.Int.nonNegative(counts[
|
|
29
|
-
claimed: tools.Int.nonNegative(counts[
|
|
30
|
-
completed: tools.Int.nonNegative(counts[
|
|
31
|
-
failed: tools.Int.nonNegative(counts[
|
|
28
|
+
pending: tools.Int.nonNegative(counts[JobStatusEnum.pending] ?? 0),
|
|
29
|
+
claimed: tools.Int.nonNegative(counts[JobStatusEnum.claimed] ?? 0),
|
|
30
|
+
completed: tools.Int.nonNegative(counts[JobStatusEnum.completed] ?? 0),
|
|
31
|
+
failed: tools.Int.nonNegative(counts[JobStatusEnum.failed] ?? 0),
|
|
32
32
|
oldestPending: oldestPending?.createdAt ? tools.Timestamp.fromNumber(oldestPending.createdAt).ms : null,
|
|
33
33
|
};
|
|
34
34
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import type { JobRecovererPort } from "./job-recoverer.port";
|
|
3
|
+
|
|
4
|
+
export class JobRecovererCollectingAdapter implements JobRecovererPort {
|
|
5
|
+
readonly recovered: Array<tools.IntegerNonNegativeType> = [];
|
|
6
|
+
|
|
7
|
+
async recover(): Promise<tools.IntegerNonNegativeType> {
|
|
8
|
+
const count = tools.Int.nonNegative(0);
|
|
9
|
+
|
|
10
|
+
this.recovered.push(count);
|
|
11
|
+
|
|
12
|
+
return count;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import type { JobRecovererPort } from "./job-recoverer.port";
|
|
3
|
+
|
|
4
|
+
export class JobRecovererNoopAdapter implements JobRecovererPort {
|
|
5
|
+
async recover(): Promise<tools.IntegerNonNegativeType> {
|
|
6
|
+
return tools.Int.nonNegative(0);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// [BUN DEPENDENCY]
|
|
2
|
+
import type { Database } from "bun:sqlite";
|
|
3
|
+
import * as tools from "@bgord/tools";
|
|
4
|
+
import type { JobRecovererPort } from "./job-recoverer.port";
|
|
5
|
+
import { JobStatusEnum } from "./job-status.vo";
|
|
6
|
+
|
|
7
|
+
type Dependencies = { db: Database };
|
|
8
|
+
|
|
9
|
+
// Single-process only: at boot, every claimed job was left behind by a dead process.
|
|
10
|
+
export class JobRecovererSqliteAdapter implements JobRecovererPort {
|
|
11
|
+
constructor(private readonly deps: Dependencies) {}
|
|
12
|
+
|
|
13
|
+
async recover(): Promise<tools.IntegerNonNegativeType> {
|
|
14
|
+
const result = this.deps.db.run(
|
|
15
|
+
`UPDATE jobs SET status = '${JobStatusEnum.pending}' WHERE status = '${JobStatusEnum.claimed}'`,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return tools.Int.nonNegative(result.changes);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as tools from "@bgord/tools";
|
|
2
2
|
|
|
3
|
-
type MemoryConsumptionSnapshotType = {
|
|
3
|
+
export type MemoryConsumptionSnapshotType = {
|
|
4
|
+
total: tools.Size;
|
|
5
|
+
heap: { used: tools.Size; total: tools.Size };
|
|
6
|
+
};
|
|
4
7
|
|
|
5
8
|
// RSS - resident set size - how much memory this process uses
|
|
6
9
|
// Heap total - how much memory is reserved for the JS heap
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Message, ToMessageMap } from "./message.types";
|
|
2
|
+
import type { MessageBusPort } from "./message-bus.port";
|
|
3
|
+
|
|
4
|
+
export const MessageBusStrictAdapterError = {
|
|
5
|
+
NoHandler: "message.bus.strict.adapter.no.handler",
|
|
6
|
+
DuplicateHandler: "message.bus.strict.adapter.duplicate.handler",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type Dependencies<Messages extends Message> = { inner: MessageBusPort<Messages> };
|
|
10
|
+
|
|
11
|
+
export class MessageBusStrictAdapter<Messages extends Message> implements MessageBusPort<Messages> {
|
|
12
|
+
private readonly registered = new Set<PropertyKey>();
|
|
13
|
+
|
|
14
|
+
constructor(private readonly deps: Dependencies<Messages>) {}
|
|
15
|
+
|
|
16
|
+
async emit<M extends Messages>(message: M): Promise<void> {
|
|
17
|
+
if (!this.registered.has(message.name)) throw new Error(MessageBusStrictAdapterError.NoHandler);
|
|
18
|
+
|
|
19
|
+
await this.deps.inner.emit(message);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
on<MessageName extends keyof ToMessageMap<Messages>>(
|
|
23
|
+
name: MessageName,
|
|
24
|
+
handler: (message: ToMessageMap<Messages>[MessageName]) => void | Promise<void>,
|
|
25
|
+
): void {
|
|
26
|
+
if (this.registered.has(name)) throw new Error(MessageBusStrictAdapterError.DuplicateHandler);
|
|
27
|
+
|
|
28
|
+
this.registered.add(name);
|
|
29
|
+
this.deps.inner.on(name, handler);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const CommandBusStrictAdapter = MessageBusStrictAdapter;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type PathMatcherRule = string | URLPattern;
|
|
2
|
+
|
|
3
|
+
export class PathMatcher {
|
|
4
|
+
static matches(rules: ReadonlyArray<PathMatcherRule> | undefined, path: string): boolean {
|
|
5
|
+
return rules?.some((rule) => PathMatcher.matchesRule(rule, path)) ?? false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
private static matchesRule(rule: PathMatcherRule, path: string): boolean {
|
|
9
|
+
if (rule instanceof URLPattern) return rule.test({ pathname: path });
|
|
10
|
+
if (path === rule) return true;
|
|
11
|
+
|
|
12
|
+
return path.startsWith(rule.endsWith("/") ? rule : `${rule}/`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
// [BUN DEPENDENCY]
|
|
2
2
|
import * as tools from "@bgord/tools";
|
|
3
3
|
import * as v from "valibot";
|
|
4
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
4
5
|
import type { DirectoryEnsurerPort } from "./directory-ensurer.port";
|
|
5
6
|
import type { FileCleanerPort } from "./file-cleaner.port";
|
|
6
|
-
import type { FileCopierPort } from "./file-copier.port";
|
|
7
7
|
import type { FileInspectionPort } from "./file-inspection.port";
|
|
8
|
-
import type { FileRenamerPort } from "./file-renamer.port";
|
|
9
8
|
import type { HashFilePort } from "./hash-file.port";
|
|
10
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
11
9
|
import type {
|
|
12
10
|
RemoteFileStoragePort,
|
|
13
11
|
RemoteHeadResult,
|
|
@@ -16,13 +14,11 @@ import type {
|
|
|
16
14
|
} from "./remote-file-storage.port";
|
|
17
15
|
|
|
18
16
|
type Dependencies = {
|
|
17
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
19
18
|
HashFile: HashFilePort;
|
|
20
19
|
FileInspection: FileInspectionPort;
|
|
21
20
|
FileCleaner: FileCleanerPort;
|
|
22
|
-
FileRenamer: FileRenamerPort;
|
|
23
|
-
FileCopier: FileCopierPort;
|
|
24
21
|
DirectoryEnsurer: DirectoryEnsurerPort;
|
|
25
|
-
NonceProvider: NonceProviderPort;
|
|
26
22
|
};
|
|
27
23
|
|
|
28
24
|
type Config = { root: tools.DirectoryPathAbsoluteType };
|
|
@@ -47,19 +43,9 @@ export class RemoteFileStorageDiskAdapter implements RemoteFileStoragePort {
|
|
|
47
43
|
|
|
48
44
|
async putFromPath(input: RemotePutFromPathInput): Promise<RemotePutFromPathResult> {
|
|
49
45
|
const final = this.resolveKeyToAbsoluteFilePath(input.key);
|
|
50
|
-
const temporary = final.withFilename(
|
|
51
|
-
final.getFilename().withSuffix(`-part-${this.deps.NonceProvider.generate()}`),
|
|
52
|
-
);
|
|
53
46
|
|
|
54
47
|
await this.deps.DirectoryEnsurer.ensure(final.getDirectory());
|
|
55
|
-
await this.deps.
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
59
|
-
} catch (error) {
|
|
60
|
-
await this.deps.FileCleaner.delete(temporary);
|
|
61
|
-
throw error;
|
|
62
|
-
}
|
|
48
|
+
await this.deps.AtomicFileWriter.write(final, Bun.file(input.path.get()));
|
|
63
49
|
|
|
64
50
|
return this.deps.HashFile.hash(final);
|
|
65
51
|
}
|
|
@@ -4,8 +4,7 @@ import type { Context } from "hono";
|
|
|
4
4
|
import { getConnInfo } from "hono/bun";
|
|
5
5
|
import { getCookie } from "hono/cookie";
|
|
6
6
|
import { HTTPException } from "hono/http-exception";
|
|
7
|
-
import type
|
|
8
|
-
import { ShieldAuthStrategyError } from "./shield-auth.strategy";
|
|
7
|
+
import { type RequestContext, RequestIdentityError } from "./request-context.port";
|
|
9
8
|
|
|
10
9
|
export class RequestContextHonoAdapter implements RequestContext {
|
|
11
10
|
readonly request: RequestContext["request"];
|
|
@@ -58,8 +57,8 @@ export class RequestContextHonoAdapter implements RequestContext {
|
|
|
58
57
|
authenticatedUserId: () => {
|
|
59
58
|
const user = context.get("user");
|
|
60
59
|
|
|
61
|
-
if (user === undefined) throw new Error(
|
|
62
|
-
if (user === null) throw new HTTPException(401, { message:
|
|
60
|
+
if (user === undefined) throw new Error(RequestIdentityError.NotAttached);
|
|
61
|
+
if (user === null) throw new HTTPException(401, { message: RequestIdentityError.Rejected });
|
|
63
62
|
return user.id;
|
|
64
63
|
},
|
|
65
64
|
ip: () =>
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type * as tools from "@bgord/tools";
|
|
2
2
|
import type { UUIDType } from "./uuid.vo";
|
|
3
3
|
|
|
4
|
+
export const RequestIdentityError = {
|
|
5
|
+
Rejected: "shield.auth.rejected",
|
|
6
|
+
NotAttached: "shield.auth.not.attached",
|
|
7
|
+
};
|
|
8
|
+
|
|
4
9
|
export interface RequestContext {
|
|
5
10
|
readonly request: {
|
|
6
11
|
readonly path: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import type { RuntimeStatsProviderPort, RuntimeStatsSnapshot } from "./runtime-stats-provider.port";
|
|
3
|
+
|
|
4
|
+
export class RuntimeStatsProviderNoopAdapter implements RuntimeStatsProviderPort {
|
|
5
|
+
getStats(): RuntimeStatsSnapshot {
|
|
6
|
+
const zero = tools.Duration.Ms(0);
|
|
7
|
+
const empty = tools.Size.fromBytes(0);
|
|
8
|
+
|
|
9
|
+
return {
|
|
10
|
+
uptime: { duration: zero, formatted: "0 seconds ago" },
|
|
11
|
+
memory: { total: empty, heap: { used: empty, total: empty } },
|
|
12
|
+
eventLoop: { lag: { p50: zero, p95: zero, p99: zero }, utilization: 0 },
|
|
13
|
+
inFlight: tools.Int.of(0),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ClockPort } from "./clock.port";
|
|
2
|
+
import { EventLoopLag } from "./event-loop-lag.service";
|
|
3
|
+
import { EventLoopUtilization } from "./event-loop-utilization.service";
|
|
4
|
+
import { InFlightRequestsTracker } from "./in-flight-requests-tracker.service";
|
|
5
|
+
import { MemoryConsumption } from "./memory-consumption.service";
|
|
6
|
+
import type { RuntimeStatsProviderPort, RuntimeStatsSnapshot } from "./runtime-stats-provider.port";
|
|
7
|
+
import { Uptime } from "./uptime.service";
|
|
8
|
+
|
|
9
|
+
type Dependencies = { Clock: ClockPort };
|
|
10
|
+
|
|
11
|
+
export class RuntimeStatsProviderSystemAdapter implements RuntimeStatsProviderPort {
|
|
12
|
+
constructor(private readonly deps: Dependencies) {
|
|
13
|
+
EventLoopLag.start();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getStats(): RuntimeStatsSnapshot {
|
|
17
|
+
return {
|
|
18
|
+
uptime: Uptime.get(this.deps.Clock),
|
|
19
|
+
memory: MemoryConsumption.snapshot(),
|
|
20
|
+
eventLoop: { lag: EventLoopLag.snapshot(), utilization: EventLoopUtilization.snapshot() },
|
|
21
|
+
inFlight: InFlightRequestsTracker.get(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { EventLoopLagSnapshotType } from "./event-loop-lag.service";
|
|
3
|
+
import type { EventLoopUtilizationSnapshot } from "./event-loop-utilization.service";
|
|
4
|
+
import type { MemoryConsumptionSnapshotType } from "./memory-consumption.service";
|
|
5
|
+
import type { UptimeResultType } from "./uptime.service";
|
|
6
|
+
|
|
7
|
+
export type RuntimeStatsSnapshot = {
|
|
8
|
+
uptime: UptimeResultType;
|
|
9
|
+
memory: MemoryConsumptionSnapshotType;
|
|
10
|
+
eventLoop: { lag: EventLoopLagSnapshotType; utilization: EventLoopUtilizationSnapshot };
|
|
11
|
+
inFlight: tools.IntegerType;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface RuntimeStatsProviderPort {
|
|
15
|
+
getStats(): RuntimeStatsSnapshot;
|
|
16
|
+
}
|
|
@@ -31,12 +31,12 @@ export class SecurityRuleViolationThresholdStrategy implements SecurityRuleStrat
|
|
|
31
31
|
|
|
32
32
|
// Best-effort increment, occasional lost increments are acceptable for concurrent requests.
|
|
33
33
|
async isViolated(context: RequestContext): Promise<boolean> {
|
|
34
|
-
const subject = await this.resolver.resolve(context);
|
|
35
|
-
|
|
36
34
|
const violated = await this.rule.isViolated(context);
|
|
37
35
|
|
|
38
36
|
if (!violated) return false;
|
|
39
37
|
|
|
38
|
+
const subject = await this.resolver.resolve(context);
|
|
39
|
+
|
|
40
40
|
try {
|
|
41
41
|
const cached = await this.deps.CacheRepository.get(subject.hex);
|
|
42
42
|
const count = typeof cached === "number" ? cached : 0;
|
|
@@ -50,9 +50,9 @@ export class SetupHono {
|
|
|
50
50
|
deps: Dependencies,
|
|
51
51
|
): Array<MiddlewareHandler> {
|
|
52
52
|
return [
|
|
53
|
+
new CorrelationHonoMiddleware(deps).handle(),
|
|
53
54
|
new ShieldMaintenanceHonoStrategy(config.maintenanceMode).handle(),
|
|
54
55
|
new TrailingSlashHonoMiddleware().handle(),
|
|
55
|
-
new CorrelationHonoMiddleware(deps).handle(),
|
|
56
56
|
new TimingHonoMiddleware(deps).handle(),
|
|
57
57
|
new ApiVersionHonoMiddleware(deps).handle(),
|
|
58
58
|
new ShieldCsrfHonoStrategy(config.csrf).handle(),
|