@bgord/bun 1.23.11 → 1.24.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/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/build-info.vo.d.ts +7 -1
- package/dist/build-info.vo.d.ts.map +1 -1
- package/dist/build-info.vo.js +4 -1
- package/dist/build-info.vo.js.map +1 -1
- 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-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 +11 -3
- package/dist/healthcheck.handler.d.ts.map +1 -1
- package/dist/healthcheck.handler.js +11 -12
- 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 +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -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/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 +2 -2
- package/readme.md +13 -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/build-info.vo.ts +4 -1
- package/src/encryption-aes-gcm.adapter.ts +4 -4
- package/src/event-stream-accept.service.ts +10 -0
- package/src/gzip.adapter.ts +3 -3
- package/src/healthcheck.handler.ts +16 -13
- 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 +11 -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/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,5 +1,6 @@
|
|
|
1
1
|
import * as tools from "@bgord/tools";
|
|
2
2
|
import * as v from "valibot";
|
|
3
|
+
import { PathMatcher } from "./path-matcher.service";
|
|
3
4
|
export const Maintenance = v.object({ enabled: tools.FeatureFlagValue });
|
|
4
5
|
export class ShieldMaintenanceStrategy {
|
|
5
6
|
config;
|
|
@@ -12,11 +13,7 @@ export class ShieldMaintenanceStrategy {
|
|
|
12
13
|
this.RetryAfter = config?.RetryAfter ?? tools.Duration.Hours(1);
|
|
13
14
|
}
|
|
14
15
|
shouldSkip(context) {
|
|
15
|
-
return (this.config?.skip
|
|
16
|
-
if (rule instanceof URLPattern)
|
|
17
|
-
return rule.test({ pathname: context.request.path });
|
|
18
|
-
return context.request.path.startsWith(rule);
|
|
19
|
-
}) ?? false);
|
|
16
|
+
return PathMatcher.matches(this.config?.skip, context.request.path);
|
|
20
17
|
}
|
|
21
18
|
async evaluate() {
|
|
22
19
|
const maintenance = await this.MaintenanceConfig?.get();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shield-maintenance.strategy.js","sourceRoot":"","sources":["../src/shield-maintenance.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"shield-maintenance.strategy.js","sourceRoot":"","sources":["../src/shield-maintenance.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIrD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAiBzE,MAAM,OAAO,yBAAyB;IAKP,MAAM;IAJlB,QAAQ,GAAG,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;IAC1C,iBAAiB,CAAuC;IACxD,UAAU,CAAiB;IAE5C,YAA6B,MAAgC;sBAAhC,MAAM;QACjC,IAAI,CAAC,iBAAiB,GAAG,MAAM,EAAE,iBAAiB,CAAC;QACnD,IAAI,CAAC,UAAU,GAAG,MAAM,EAAE,UAAU,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,UAAU,CAAC,OAAuB;QAChC,OAAO,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC;QACxD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAE9F,OAAO;YACL,OAAO;YACP,IAAI,EAAE,GAAG;YACT,IAAI,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE;YAC/B,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;SACpF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as tools from "@bgord/tools";
|
|
2
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
2
3
|
import type { FileCleanerPort } from "./file-cleaner.port";
|
|
3
|
-
import type { FileRenamerPort } from "./file-renamer.port";
|
|
4
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
5
|
-
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
6
4
|
import type { TemporaryFilePort } from "./temporary-file.port";
|
|
7
5
|
type Dependencies = {
|
|
6
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
8
7
|
FileCleaner: FileCleanerPort;
|
|
9
|
-
FileRenamer: FileRenamerPort;
|
|
10
|
-
FileWriter: FileWriterPort;
|
|
11
|
-
NonceProvider: NonceProviderPort;
|
|
12
8
|
};
|
|
13
9
|
export declare class TemporaryFileAbsoluteAdapter implements TemporaryFilePort {
|
|
14
10
|
private readonly directory;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temporary-file-absolute.adapter.d.ts","sourceRoot":"","sources":["../src/temporary-file-absolute.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"temporary-file-absolute.adapter.d.ts","sourceRoot":"","sources":["../src/temporary-file-absolute.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,KAAK,YAAY,GAAG;IAClB,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF,qBAAa,4BAA6B,YAAW,iBAAiB;IAElE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFvB,YACmB,SAAS,EAAE,KAAK,CAAC,yBAAyB,EAC1C,IAAI,EAAE,YAAY,EACjC;IAEE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAMpF;IAEK,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;IAED,IAAI,IAAI,IAAI,KAAK,CAAC,yBAAyB,CAE1C;CACF"}
|
|
@@ -7,16 +7,8 @@ export class TemporaryFileAbsoluteAdapter {
|
|
|
7
7
|
this.deps = deps;
|
|
8
8
|
}
|
|
9
9
|
async write(filename, content) {
|
|
10
|
-
const temporary = tools.FilePathAbsolute.fromPartsSafe(this.directory, filename.withSuffix(`-part-${this.deps.NonceProvider.generate()}`));
|
|
11
10
|
const final = tools.FilePathAbsolute.fromPartsSafe(this.directory, filename);
|
|
12
|
-
await this.deps.
|
|
13
|
-
try {
|
|
14
|
-
await this.deps.FileRenamer.rename(temporary, final);
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
await this.deps.FileCleaner.delete(temporary);
|
|
18
|
-
throw error;
|
|
19
|
-
}
|
|
11
|
+
await this.deps.AtomicFileWriter.write(final, content);
|
|
20
12
|
return final;
|
|
21
13
|
}
|
|
22
14
|
async cleanup(filename) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"temporary-file-absolute.adapter.js","sourceRoot":"","sources":["../src/temporary-file-absolute.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"temporary-file-absolute.adapter.js","sourceRoot":"","sources":["../src/temporary-file-absolute.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAUtC,MAAM,OAAO,4BAA4B;IAEpB,SAAS;IACT,IAAI;IAFvB,YACmB,SAA0C,EAC1C,IAAkB;yBADlB,SAAS;oBACT,IAAI;IACpB,CAAC;IAEJ,KAAK,CAAC,KAAK,CAAC,QAAwB,EAAE,OAAa;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE7E,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAEvD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAwB;QACpC,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrG,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -8,6 +8,5 @@ export declare class TimingMiddleware {
|
|
|
8
8
|
static readonly HEADER_NAME = "Server-Timing";
|
|
9
9
|
constructor(deps: TimingMiddlewareDependencies);
|
|
10
10
|
measure(context: HasRequestHeader, action: () => void | Promise<void>): Promise<string | null>;
|
|
11
|
-
private static isEventStream;
|
|
12
11
|
}
|
|
13
12
|
//# sourceMappingURL=timing.middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.middleware.d.ts","sourceRoot":"","sources":["../src/timing.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"timing.middleware.d.ts","sourceRoot":"","sources":["../src/timing.middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG/D,MAAM,MAAM,4BAA4B,GAAG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhE,qBAAa,gBAAgB;IAGf,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,MAAM,CAAC,QAAQ,CAAC,WAAW,mBAAmB;IAE9C,YAA6B,IAAI,EAAE,4BAA4B,EAAI;IAE7D,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQnG;CACF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EventStreamAccept } from "./event-stream-accept.service";
|
|
1
2
|
import { Stopwatch } from "./stopwatch.service";
|
|
2
3
|
export class TimingMiddleware {
|
|
3
4
|
deps;
|
|
@@ -6,19 +7,11 @@ export class TimingMiddleware {
|
|
|
6
7
|
this.deps = deps;
|
|
7
8
|
}
|
|
8
9
|
async measure(context, action) {
|
|
9
|
-
if (
|
|
10
|
+
if (EventStreamAccept.matches(context.request.header("accept")))
|
|
10
11
|
return null;
|
|
11
12
|
const stopwatch = new Stopwatch(this.deps);
|
|
12
13
|
await action();
|
|
13
14
|
return `total;dur=${Math.max(0, stopwatch.stop().ms)}`;
|
|
14
15
|
}
|
|
15
|
-
static isEventStream(accept) {
|
|
16
|
-
if (!accept)
|
|
17
|
-
return false;
|
|
18
|
-
return accept
|
|
19
|
-
.toLowerCase()
|
|
20
|
-
.split(",")
|
|
21
|
-
.some((type) => type.split(";")[0]?.trim() === "text/event-stream");
|
|
22
|
-
}
|
|
23
16
|
}
|
|
24
17
|
//# sourceMappingURL=timing.middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.middleware.js","sourceRoot":"","sources":["../src/timing.middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"timing.middleware.js","sourceRoot":"","sources":["../src/timing.middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAIhD,MAAM,OAAO,gBAAgB;IAGE,IAAI;IAFjC,MAAM,CAAU,WAAW,GAAG,eAAe,CAAC;IAE9C,YAA6B,IAAkC;oBAAlC,IAAI;IAAiC,CAAC;IAEnE,KAAK,CAAC,OAAO,CAAC,OAAyB,EAAE,MAAkC;QACzE,IAAI,iBAAiB,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAE7E,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,MAAM,EAAE,CAAC;QAEf,OAAO,aAAa,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bgord/bun",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Bartosz Gordon",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@types/bun": "1.4.2",
|
|
28
28
|
"@types/nodemailer": "8.0.2",
|
|
29
29
|
"better-auth": "1.7.6",
|
|
30
|
-
"cspell": "10.3.
|
|
30
|
+
"cspell": "10.3.6",
|
|
31
31
|
"fallow": "3.30.0",
|
|
32
32
|
"lefthook": "2.1.14",
|
|
33
33
|
"lockfile-lint": "5.0.1",
|
package/readme.md
CHANGED
|
@@ -61,6 +61,10 @@ src/
|
|
|
61
61
|
├── antivirus.port.ts
|
|
62
62
|
├── api-version-hono.middleware.ts
|
|
63
63
|
├── api-version.middleware.ts
|
|
64
|
+
├── atomic-file-writer-collecting.adapter.ts
|
|
65
|
+
├── atomic-file-writer-noop.adapter.ts
|
|
66
|
+
├── atomic-file-writer.adapter.ts
|
|
67
|
+
├── atomic-file-writer.port.ts
|
|
64
68
|
├── auth-session-reader-better-auth.adapter.ts
|
|
65
69
|
├── auth-session-reader-noop.adapter.ts
|
|
66
70
|
├── auth-session-reader.port.ts
|
|
@@ -180,6 +184,7 @@ src/
|
|
|
180
184
|
├── event-store-with-logger.adapter.ts
|
|
181
185
|
├── event-store.adapter.ts
|
|
182
186
|
├── event-store.port.ts
|
|
187
|
+
├── event-stream-accept.service.ts
|
|
183
188
|
├── event-stream.vo.ts
|
|
184
189
|
├── event-upcaster-chain.adapter.ts
|
|
185
190
|
├── event-upcaster-noop.adapter.ts
|
|
@@ -338,6 +343,10 @@ src/
|
|
|
338
343
|
├── job-queue-worker.service.ts
|
|
339
344
|
├── job-queue.adapter.ts
|
|
340
345
|
├── job-queue.port.ts
|
|
346
|
+
├── job-recoverer-collecting.adapter.ts
|
|
347
|
+
├── job-recoverer-noop.adapter.ts
|
|
348
|
+
├── job-recoverer-sqlite.adapter.ts
|
|
349
|
+
├── job-recoverer.port.ts
|
|
341
350
|
├── job-registry.adapter.ts
|
|
342
351
|
├── job-registry.port.ts
|
|
343
352
|
├── job-requeuer-collecting.adapter.ts
|
|
@@ -443,6 +452,7 @@ src/
|
|
|
443
452
|
├── nonce-provider-noop.adapter.ts
|
|
444
453
|
├── nonce-provider.port.ts
|
|
445
454
|
├── nonce-value.vo.ts
|
|
455
|
+
├── path-matcher.service.ts
|
|
446
456
|
├── payload-serializer-collecting.adapter.ts
|
|
447
457
|
├── payload-serializer-json.adapter.ts
|
|
448
458
|
├── payload-serializer.port.ts
|
|
@@ -519,6 +529,9 @@ src/
|
|
|
519
529
|
├── retry-backoff-noop.strategy.ts
|
|
520
530
|
├── retry-backoff.strategy.ts
|
|
521
531
|
├── retry.service.ts
|
|
532
|
+
├── runtime-stats-provider-noop.adapter.ts
|
|
533
|
+
├── runtime-stats-provider-system.adapter.ts
|
|
534
|
+
├── runtime-stats-provider.port.ts
|
|
522
535
|
├── sealer-aes-gcm.adapter.ts
|
|
523
536
|
├── sealer-noop.adapter.ts
|
|
524
537
|
├── sealer.port.ts
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
3
|
+
import type { FileWriterContent } from "./file-writer.port";
|
|
4
|
+
|
|
5
|
+
export class AtomicFileWriterCollectingAdapter implements AtomicFileWriterPort {
|
|
6
|
+
readonly written: Array<[tools.FilePathRelative | tools.FilePathAbsolute, FileWriterContent]> = [];
|
|
7
|
+
|
|
8
|
+
async write(
|
|
9
|
+
path: tools.FilePathRelative | tools.FilePathAbsolute,
|
|
10
|
+
content: FileWriterContent,
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
this.written.push([path, content]);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
3
|
+
import type { FileWriterContent } from "./file-writer.port";
|
|
4
|
+
|
|
5
|
+
export class AtomicFileWriterNoopAdapter implements AtomicFileWriterPort {
|
|
6
|
+
async write(
|
|
7
|
+
_path: tools.FilePathRelative | tools.FilePathAbsolute,
|
|
8
|
+
_content: FileWriterContent,
|
|
9
|
+
): Promise<void> {}
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
3
|
+
import type { FileCleanerPort } from "./file-cleaner.port";
|
|
4
|
+
import type { FileRenamerPort } from "./file-renamer.port";
|
|
5
|
+
import type { FileWriterContent, FileWriterPort } from "./file-writer.port";
|
|
6
|
+
import type { NonceProviderPort } from "./nonce-provider.port";
|
|
7
|
+
|
|
8
|
+
type Dependencies = {
|
|
9
|
+
FileCleaner: FileCleanerPort;
|
|
10
|
+
FileRenamer: FileRenamerPort;
|
|
11
|
+
FileWriter: FileWriterPort;
|
|
12
|
+
NonceProvider: NonceProviderPort;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class AtomicFileWriterAdapter implements AtomicFileWriterPort {
|
|
16
|
+
constructor(private readonly deps: Dependencies) {}
|
|
17
|
+
|
|
18
|
+
async write(
|
|
19
|
+
path: tools.FilePathRelative | tools.FilePathAbsolute,
|
|
20
|
+
content: FileWriterContent,
|
|
21
|
+
): Promise<void> {
|
|
22
|
+
const temporary = path.withFilename(
|
|
23
|
+
path.getFilename().withSuffix(`-part-${this.deps.NonceProvider.generate()}`),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
await this.deps.FileWriter.write(temporary.get(), content);
|
|
28
|
+
await this.deps.FileRenamer.rename(temporary, path);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
await this.deps.FileCleaner.delete(temporary).catch(() => {});
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/build-info.vo.ts
CHANGED
|
@@ -6,7 +6,10 @@ export const BuildInfo = v.object({
|
|
|
6
6
|
timestamp: tools.TimestampValue,
|
|
7
7
|
version: tools.PackageVersionSchema,
|
|
8
8
|
sha: CommitShaValue,
|
|
9
|
-
|
|
9
|
+
sizes: v.object({
|
|
10
|
+
server: tools.SizeBytes,
|
|
11
|
+
web: v.object({ js: tools.SizeBytes, css: tools.SizeBytes }),
|
|
12
|
+
}),
|
|
10
13
|
});
|
|
11
14
|
|
|
12
15
|
export type BuildInfoType = v.InferOutput<typeof BuildInfo>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { AtomicFileWriterPort } from "./atomic-file-writer.port";
|
|
2
3
|
import { CryptoAesGcm } from "./crypto-aes-gcm.service";
|
|
3
4
|
import type { CryptoKeyProviderPort } from "./crypto-key-provider.port";
|
|
4
5
|
import type { EncryptionPort, EncryptionRecipe } from "./encryption.port";
|
|
5
6
|
import { EncryptionIV } from "./encryption-iv.vo";
|
|
6
7
|
import type { FileInspectionPort } from "./file-inspection.port";
|
|
7
8
|
import type { FileReaderRawPort } from "./file-reader-raw.port";
|
|
8
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
9
9
|
|
|
10
10
|
type Dependencies = {
|
|
11
11
|
FileReaderRaw: FileReaderRawPort;
|
|
12
|
-
|
|
12
|
+
AtomicFileWriter: AtomicFileWriterPort;
|
|
13
13
|
CryptoKeyProvider: CryptoKeyProviderPort;
|
|
14
14
|
FileInspection: FileInspectionPort;
|
|
15
15
|
};
|
|
@@ -29,7 +29,7 @@ export class EncryptionAesGcmAdapter implements EncryptionPort {
|
|
|
29
29
|
const plaintext = await this.deps.FileReaderRaw.read(recipe.input);
|
|
30
30
|
const encrypted = await CryptoAesGcm.encrypt(key, plaintext, iv);
|
|
31
31
|
|
|
32
|
-
await this.deps.
|
|
32
|
+
await this.deps.AtomicFileWriter.write(recipe.output, encrypted);
|
|
33
33
|
|
|
34
34
|
return recipe.output;
|
|
35
35
|
}
|
|
@@ -43,7 +43,7 @@ export class EncryptionAesGcmAdapter implements EncryptionPort {
|
|
|
43
43
|
const encrypted = new Uint8Array(await this.deps.FileReaderRaw.read(recipe.input));
|
|
44
44
|
const plaintext = await CryptoAesGcm.decrypt(key, encrypted);
|
|
45
45
|
|
|
46
|
-
await this.deps.
|
|
46
|
+
await this.deps.AtomicFileWriter.write(recipe.output, plaintext);
|
|
47
47
|
|
|
48
48
|
return recipe.output;
|
|
49
49
|
}
|
package/src/gzip.adapter.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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 { FileReaderRawPort } from "./file-reader-raw.port";
|
|
4
|
-
import type { FileWriterPort } from "./file-writer.port";
|
|
5
5
|
import type { GzipPort, GzipRecipe } from "./gzip.port";
|
|
6
6
|
|
|
7
|
-
type Dependencies = { FileReaderRaw: FileReaderRawPort;
|
|
7
|
+
type Dependencies = { FileReaderRaw: FileReaderRawPort; AtomicFileWriter: AtomicFileWriterPort };
|
|
8
8
|
|
|
9
9
|
export class GzipAdapter implements GzipPort {
|
|
10
10
|
constructor(private readonly deps: Dependencies) {}
|
|
@@ -13,7 +13,7 @@ export class GzipAdapter implements GzipPort {
|
|
|
13
13
|
const file = await this.deps.FileReaderRaw.read(recipe.input);
|
|
14
14
|
const archive = Bun.gzipSync(file);
|
|
15
15
|
|
|
16
|
-
await this.deps.
|
|
16
|
+
await this.deps.AtomicFileWriter.write(recipe.output, archive);
|
|
17
17
|
|
|
18
18
|
return recipe.output;
|
|
19
19
|
}
|
|
@@ -3,12 +3,9 @@ import * as tools from "@bgord/tools";
|
|
|
3
3
|
import type { BuildInfoType } from "./build-info.vo";
|
|
4
4
|
import type { ClockPort } from "./clock.port";
|
|
5
5
|
import type { CommitShaValueType } from "./commit-sha-value.vo";
|
|
6
|
-
import {
|
|
7
|
-
import { EventLoopUtilization, type EventLoopUtilizationSnapshot } from "./event-loop-utilization.service";
|
|
8
|
-
import { InFlightRequestsTracker } from "./in-flight-requests-tracker.service";
|
|
6
|
+
import type { EventLoopUtilizationSnapshot } from "./event-loop-utilization.service";
|
|
9
7
|
import type { JobQueueStatsProviderPort, JobQueueStatsSnapshot } from "./job-queue-stats-provider.port";
|
|
10
8
|
import type { LoggerStatsProviderPort, LoggerStatsSnapshot } from "./logger-stats-provider.port";
|
|
11
|
-
import { MemoryConsumption } from "./memory-consumption.service";
|
|
12
9
|
import type { NodeEnvironmentEnum } from "./node-env.vo";
|
|
13
10
|
import { Prerequisite, type PrerequisiteLabelType } from "./prerequisite.vo";
|
|
14
11
|
import {
|
|
@@ -18,8 +15,9 @@ import {
|
|
|
18
15
|
import { PrerequisiteVerifierSelfAdapter } from "./prerequisite-verifier-self.adapter";
|
|
19
16
|
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
20
17
|
import type { RedactorStrategy } from "./redactor.strategy";
|
|
18
|
+
import type { RuntimeStatsProviderPort } from "./runtime-stats-provider.port";
|
|
21
19
|
import { Stopwatch } from "./stopwatch.service";
|
|
22
|
-
import {
|
|
20
|
+
import type { UptimeResultType } from "./uptime.service";
|
|
23
21
|
|
|
24
22
|
export enum HealthcheckStatusEnum {
|
|
25
23
|
healthy = "healthy",
|
|
@@ -30,6 +28,7 @@ export enum HealthcheckStatusEnum {
|
|
|
30
28
|
export type HealthcheckDependencies = {
|
|
31
29
|
Clock: ClockPort;
|
|
32
30
|
BuildInfoConfig: ReactiveConfigPort<BuildInfoType>;
|
|
31
|
+
RuntimeStatsProvider: RuntimeStatsProviderPort;
|
|
33
32
|
LoggerStatsProvider?: LoggerStatsProviderPort;
|
|
34
33
|
JobQueueStatsProvider?: JobQueueStatsProviderPort;
|
|
35
34
|
};
|
|
@@ -56,7 +55,7 @@ export type HealthcheckResult = {
|
|
|
56
55
|
timestamp: tools.TimestampValueType;
|
|
57
56
|
date: string;
|
|
58
57
|
sha: CommitShaValueType;
|
|
59
|
-
|
|
58
|
+
sizes: { server: string; web: { js: string; css: string } };
|
|
60
59
|
environment: NodeEnvironmentEnum;
|
|
61
60
|
};
|
|
62
61
|
server: {
|
|
@@ -131,9 +130,7 @@ export class HealthcheckHandler {
|
|
|
131
130
|
: HealthcheckStatusEnum.healthy;
|
|
132
131
|
|
|
133
132
|
const build = await this.deps.BuildInfoConfig.get();
|
|
134
|
-
const uptime =
|
|
135
|
-
const histogram = EventLoopLag.snapshot();
|
|
136
|
-
const memory = MemoryConsumption.snapshot();
|
|
133
|
+
const { uptime, memory, eventLoop, inFlight } = this.deps.RuntimeStatsProvider.getStats();
|
|
137
134
|
|
|
138
135
|
return {
|
|
139
136
|
status,
|
|
@@ -144,7 +141,13 @@ export class HealthcheckHandler {
|
|
|
144
141
|
timestamp: build.timestamp,
|
|
145
142
|
date: tools.Timestamp.fromNumber(build.timestamp).toInstant().toString(),
|
|
146
143
|
sha: build.sha,
|
|
147
|
-
|
|
144
|
+
sizes: {
|
|
145
|
+
server: tools.Size.fromBytes(build.sizes.server).format(tools.Size.unit.MB),
|
|
146
|
+
web: {
|
|
147
|
+
js: tools.Size.fromBytes(build.sizes.web.js).format(tools.Size.unit.kB),
|
|
148
|
+
css: tools.Size.fromBytes(build.sizes.web.css).format(tools.Size.unit.kB),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
148
151
|
environment: this.config.Env,
|
|
149
152
|
},
|
|
150
153
|
server: {
|
|
@@ -167,10 +170,10 @@ export class HealthcheckHandler {
|
|
|
167
170
|
},
|
|
168
171
|
},
|
|
169
172
|
eventLoop: {
|
|
170
|
-
lag: { p50:
|
|
171
|
-
utilization:
|
|
173
|
+
lag: { p50: eventLoop.lag.p50.ms, p95: eventLoop.lag.p95.ms, p99: eventLoop.lag.p99.ms },
|
|
174
|
+
utilization: eventLoop.utilization,
|
|
172
175
|
},
|
|
173
|
-
inFlight
|
|
176
|
+
inFlight,
|
|
174
177
|
},
|
|
175
178
|
logger: this.deps.LoggerStatsProvider?.getStats(),
|
|
176
179
|
queue: await this.deps.JobQueueStatsProvider?.getStats(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FileUploaderError } from "./file-uploader.middleware";
|
|
2
|
+
import { RequestIdentityError } from "./request-context.port";
|
|
2
3
|
import { ShieldApiKeyStrategyError } from "./shield-api-key.strategy";
|
|
3
|
-
import { ShieldAuthStrategyError } from "./shield-auth.strategy";
|
|
4
4
|
import { ShieldBasicAuthStrategyError } from "./shield-basic-auth.strategy";
|
|
5
5
|
import { ShieldBodyLimitError } from "./shield-body-limit.strategy";
|
|
6
6
|
import { ShieldCsrfStrategyError } from "./shield-csrf.strategy";
|
|
@@ -15,7 +15,7 @@ import { ShieldWebhookStrategyError } from "./shield-webhook.strategy";
|
|
|
15
15
|
|
|
16
16
|
export const HttpExceptionErrors = {
|
|
17
17
|
ShieldApiKeyRejected: ShieldApiKeyStrategyError.Rejected,
|
|
18
|
-
ShieldAuthRejected:
|
|
18
|
+
ShieldAuthRejected: RequestIdentityError.Rejected,
|
|
19
19
|
ShieldBasicAuthRejected: ShieldBasicAuthStrategyError.Rejected,
|
|
20
20
|
ShieldBodyLimitTooBig: ShieldBodyLimitError.TooBig,
|
|
21
21
|
ShieldCsrfRejected: ShieldCsrfStrategyError.Rejected,
|
|
@@ -20,28 +20,34 @@ export class HttpLoggerHonoMiddleware implements MiddlewareHonoPort {
|
|
|
20
20
|
|
|
21
21
|
if (this.middleware.shouldSkip(context)) return await next();
|
|
22
22
|
|
|
23
|
-
const request = c.req.raw.clone();
|
|
24
23
|
const correlationId = c.get("correlationId");
|
|
25
|
-
const body = await HttpLoggerHonoMiddleware.parseJSON(
|
|
24
|
+
const body = await HttpLoggerHonoMiddleware.parseJSON(c.req.raw);
|
|
26
25
|
|
|
27
26
|
const { stopwatch } = this.middleware.before(context, correlationId, body);
|
|
28
27
|
|
|
29
28
|
await next();
|
|
30
29
|
|
|
31
|
-
const
|
|
32
|
-
const responseBody = await HttpLoggerHonoMiddleware.parseJSON(response);
|
|
30
|
+
const responseBody = await HttpLoggerHonoMiddleware.parseJSON(c.res);
|
|
33
31
|
|
|
34
32
|
this.middleware.after(context, correlationId, {
|
|
35
33
|
stopwatch,
|
|
36
|
-
status:
|
|
34
|
+
status: c.res.status,
|
|
37
35
|
responseBody,
|
|
38
36
|
});
|
|
39
37
|
};
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
private static async parseJSON(resource: Request | Response): Promise<any> {
|
|
41
|
+
if (!HttpLoggerHonoMiddleware.isJSON(resource.headers.get("content-type"))) return undefined;
|
|
42
|
+
|
|
43
43
|
try {
|
|
44
|
-
return await resource.json();
|
|
44
|
+
return await resource.clone().json();
|
|
45
45
|
} catch {}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
private static isJSON(contentType: string | null): boolean {
|
|
49
|
+
const type = contentType?.split(";")[0]?.trim().toLowerCase();
|
|
50
|
+
|
|
51
|
+
return type === "application/json" || Boolean(type?.endsWith("+json"));
|
|
52
|
+
}
|
|
47
53
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ClockPort } from "./clock.port";
|
|
2
2
|
import type { CorrelationIdType } from "./correlation-id.vo";
|
|
3
|
+
import { EventStreamAccept } from "./event-stream-accept.service";
|
|
3
4
|
import { type LoggerPort, LogLevelEnum } from "./logger.port";
|
|
5
|
+
import { PathMatcher } from "./path-matcher.service";
|
|
4
6
|
import type { HasRequestHeader, HasRequestPath, RequestContext } from "./request-context.port";
|
|
5
7
|
import { Stopwatch } from "./stopwatch.service";
|
|
6
8
|
|
|
@@ -44,14 +46,9 @@ export class HttpLoggerMiddleware {
|
|
|
44
46
|
) {}
|
|
45
47
|
|
|
46
48
|
shouldSkip(context: HasRequestPath & HasRequestHeader): boolean {
|
|
47
|
-
if (context.request.header("accept")
|
|
49
|
+
if (EventStreamAccept.matches(context.request.header("accept"))) return true;
|
|
48
50
|
|
|
49
|
-
return (
|
|
50
|
-
this.config?.skip?.some((rule) => {
|
|
51
|
-
if (rule instanceof URLPattern) return rule.test({ pathname: context.request.path });
|
|
52
|
-
return context.request.path.startsWith(rule);
|
|
53
|
-
}) ?? false
|
|
54
|
-
);
|
|
51
|
+
return PathMatcher.matches(this.config?.skip, context.request.path);
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
before(context: RequestContext, correlationId: CorrelationIdType, body: any = {}): HttpLoggerBeforeResult {
|
|
@@ -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
|
}
|