@bgord/bun 1.15.5 → 1.16.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/antivirus-clamav.adapter.js +1 -1
- package/dist/antivirus-clamav.adapter.js.map +1 -1
- package/dist/api-version-hono.middleware.d.ts +3 -2
- package/dist/api-version-hono.middleware.d.ts.map +1 -1
- package/dist/api-version-hono.middleware.js.map +1 -1
- package/dist/api-version.middleware.d.ts +4 -3
- package/dist/api-version.middleware.d.ts.map +1 -1
- package/dist/api-version.middleware.js +1 -1
- package/dist/api-version.middleware.js.map +1 -1
- package/dist/build-info.vo.d.ts +11 -0
- package/dist/build-info.vo.d.ts.map +1 -0
- package/dist/build-info.vo.js +11 -0
- package/dist/build-info.vo.js.map +1 -0
- package/dist/error-normalizer.service.js +1 -1
- package/dist/error-normalizer.service.js.map +1 -1
- package/dist/event-envelope.d.ts +0 -7
- package/dist/event-envelope.d.ts.map +1 -1
- package/dist/event-envelope.js +2 -2
- package/dist/event-envelope.js.map +1 -1
- package/dist/event-serializer-collecting.adapter.d.ts +5 -4
- package/dist/event-serializer-collecting.adapter.d.ts.map +1 -1
- package/dist/event-serializer-collecting.adapter.js.map +1 -1
- package/dist/event-serializer-json.adapter.d.ts +3 -2
- package/dist/event-serializer-json.adapter.d.ts.map +1 -1
- package/dist/event-serializer-json.adapter.js.map +1 -1
- package/dist/event-serializer.port.d.ts +3 -2
- package/dist/event-serializer.port.d.ts.map +1 -1
- package/dist/event-store.adapter.d.ts +2 -0
- package/dist/event-store.adapter.d.ts.map +1 -1
- package/dist/event-store.adapter.js +1 -0
- package/dist/event-store.adapter.js.map +1 -1
- package/dist/event-upcaster-chain.adapter.d.ts +11 -0
- package/dist/event-upcaster-chain.adapter.d.ts.map +1 -0
- package/dist/event-upcaster-chain.adapter.js +31 -0
- package/dist/event-upcaster-chain.adapter.js.map +1 -0
- package/dist/event-upcaster-noop.adapter.d.ts +6 -0
- package/dist/event-upcaster-noop.adapter.d.ts.map +1 -0
- package/dist/event-upcaster-noop.adapter.js +6 -0
- package/dist/event-upcaster-noop.adapter.js.map +1 -0
- package/dist/event-upcaster-step.vo.d.ts +11 -0
- package/dist/event-upcaster-step.vo.d.ts.map +1 -0
- package/dist/event-upcaster-step.vo.js +10 -0
- package/dist/event-upcaster-step.vo.js.map +1 -0
- package/dist/event-upcaster.port.d.ts +5 -0
- package/dist/event-upcaster.port.d.ts.map +1 -0
- package/dist/event-upcaster.port.js +2 -0
- package/dist/event-upcaster.port.js.map +1 -0
- package/dist/event.types.d.ts +1 -1
- package/dist/event.types.d.ts.map +1 -1
- package/dist/healthcheck-hono.handler.d.ts +3 -2
- package/dist/healthcheck-hono.handler.d.ts.map +1 -1
- package/dist/healthcheck-hono.handler.js.map +1 -1
- package/dist/healthcheck.handler.d.ts +3 -2
- package/dist/healthcheck.handler.d.ts.map +1 -1
- package/dist/healthcheck.handler.js +6 -6
- package/dist/healthcheck.handler.js.map +1 -1
- package/dist/image-alpha-sharp.adapter.js +76 -14
- package/dist/image-alpha-sharp.adapter.js.map +1 -1
- package/dist/image-blur-sharp.adapter.js +72 -10
- package/dist/image-blur-sharp.adapter.js.map +1 -1
- package/dist/image-compressor-sharp.adapter.js +73 -11
- package/dist/image-compressor-sharp.adapter.js.map +1 -1
- package/dist/image-exif-clear-sharp.adapter.js +70 -8
- package/dist/image-exif-clear-sharp.adapter.js.map +1 -1
- package/dist/image-formatter-sharp.adapter.js +75 -13
- package/dist/image-formatter-sharp.adapter.js.map +1 -1
- package/dist/image-grayscale-sharp.adapter.js +70 -8
- package/dist/image-grayscale-sharp.adapter.js.map +1 -1
- package/dist/image-info-sharp.adapter.js +73 -11
- package/dist/image-info-sharp.adapter.js.map +1 -1
- package/dist/image-processor-sharp.adapter.js +86 -24
- package/dist/image-processor-sharp.adapter.js.map +1 -1
- package/dist/image-resizer-sharp.adapter.js +81 -19
- package/dist/image-resizer-sharp.adapter.js.map +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/modules/preferences/command-handlers/handleSetUserLanguageCommand.d.ts.map +1 -1
- package/dist/modules/preferences/command-handlers/handleSetUserLanguageCommand.js +4 -8
- package/dist/modules/preferences/command-handlers/handleSetUserLanguageCommand.js.map +1 -1
- package/dist/modules/system/services/passage-of-time-hourly.service.d.ts.map +1 -1
- package/dist/modules/system/services/passage-of-time-hourly.service.js +5 -9
- package/dist/modules/system/services/passage-of-time-hourly.service.js.map +1 -1
- package/dist/modules/system/services/passage-of-time-minute.service.d.ts.map +1 -1
- package/dist/modules/system/services/passage-of-time-minute.service.js +5 -9
- package/dist/modules/system/services/passage-of-time-minute.service.js.map +1 -1
- package/dist/reactive-config-file-json.adapter.d.ts +15 -0
- package/dist/reactive-config-file-json.adapter.d.ts.map +1 -0
- package/dist/reactive-config-file-json.adapter.js +21 -0
- package/dist/reactive-config-file-json.adapter.js.map +1 -0
- package/dist/reactive-config-noop.adapter.d.ts +8 -0
- package/dist/reactive-config-noop.adapter.d.ts.map +1 -0
- package/dist/reactive-config-noop.adapter.js +18 -0
- package/dist/reactive-config-noop.adapter.js.map +1 -0
- package/dist/reactive-config-with-cache.adapter.d.ts +16 -0
- package/dist/reactive-config-with-cache.adapter.d.ts.map +1 -0
- package/dist/reactive-config-with-cache.adapter.js +15 -0
- package/dist/reactive-config-with-cache.adapter.js.map +1 -0
- package/dist/reactive-config-with-fallback.adapter.d.ts +9 -0
- package/dist/reactive-config-with-fallback.adapter.d.ts.map +1 -0
- package/dist/reactive-config-with-fallback.adapter.js +25 -0
- package/dist/reactive-config-with-fallback.adapter.js.map +1 -0
- package/dist/reactive-config.port.d.ts +9 -0
- package/dist/reactive-config.port.d.ts.map +1 -0
- package/dist/reactive-config.port.js +2 -0
- package/dist/reactive-config.port.js.map +1 -0
- package/dist/redactor-error-cause-depth-limit.strategy.d.ts.map +1 -1
- package/dist/redactor-error-cause-depth-limit.strategy.js +2 -2
- package/dist/redactor-error-cause-depth-limit.strategy.js.map +1 -1
- package/dist/redactor-error-stack-hide.strategy.d.ts.map +1 -1
- package/dist/redactor-error-stack-hide.strategy.js +2 -2
- package/dist/redactor-error-stack-hide.strategy.js.map +1 -1
- package/dist/redactor-metadata-compact-array.strategy.js +1 -1
- package/dist/redactor-metadata-compact-array.strategy.js.map +1 -1
- package/dist/redactor-metadata-compact-object.strategy.js +1 -1
- package/dist/redactor-metadata-compact-object.strategy.js.map +1 -1
- package/dist/security-countermeasure-ban.strategy.d.ts.map +1 -1
- package/dist/security-countermeasure-ban.strategy.js +5 -8
- package/dist/security-countermeasure-ban.strategy.js.map +1 -1
- package/dist/setup-hono.service.d.ts +3 -2
- package/dist/setup-hono.service.d.ts.map +1 -1
- package/dist/setup-hono.service.js.map +1 -1
- package/dist/shield-ip-whitelist.strategy.d.ts.map +1 -1
- package/dist/shield-ip-whitelist.strategy.js +2 -0
- package/dist/shield-ip-whitelist.strategy.js.map +1 -1
- package/dist/shield-recaptcha.strategy.js +1 -1
- package/dist/shield-recaptcha.strategy.js.map +1 -1
- package/package.json +13 -12
- package/readme.md +10 -4
- package/src/antivirus-clamav.adapter.ts +1 -1
- package/src/api-version-hono.middleware.ts +3 -2
- package/src/api-version.middleware.ts +5 -4
- package/src/build-info.vo.ts +14 -0
- package/src/error-normalizer.service.ts +1 -1
- package/src/event-envelope.ts +2 -2
- package/src/event-serializer-collecting.adapter.ts +5 -4
- package/src/event-serializer-json.adapter.ts +3 -2
- package/src/event-serializer.port.ts +4 -2
- package/src/event-store.adapter.ts +3 -0
- package/src/event-upcaster-chain.adapter.ts +49 -0
- package/src/event-upcaster-noop.adapter.ts +8 -0
- package/src/event-upcaster-step.vo.ts +21 -0
- package/src/event-upcaster.port.ts +5 -0
- package/src/event.types.ts +1 -1
- package/src/healthcheck-hono.handler.ts +3 -2
- package/src/healthcheck.handler.ts +9 -8
- package/src/index.ts +10 -4
- package/src/modules/preferences/command-handlers/handleSetUserLanguageCommand.ts +9 -9
- package/src/modules/system/services/passage-of-time-hourly.service.ts +5 -14
- package/src/modules/system/services/passage-of-time-minute.service.ts +5 -14
- package/src/reactive-config-file-json.adapter.ts +26 -0
- package/src/reactive-config-noop.adapter.ts +19 -0
- package/src/reactive-config-with-cache.adapter.ts +19 -0
- package/src/reactive-config-with-fallback.adapter.ts +24 -0
- package/src/reactive-config.port.ts +9 -0
- package/src/redactor-error-cause-depth-limit.strategy.ts +2 -3
- package/src/redactor-error-stack-hide.strategy.ts +2 -3
- package/src/redactor-metadata-compact-array.strategy.ts +1 -1
- package/src/redactor-metadata-compact-object.strategy.ts +1 -1
- package/src/security-countermeasure-ban.strategy.ts +4 -9
- package/src/setup-hono.service.ts +3 -2
- package/src/shield-ip-whitelist.strategy.ts +2 -0
- package/src/shield-recaptcha.strategy.ts +1 -1
- package/dist/build-info-repository-file.strategy.d.ts +0 -14
- package/dist/build-info-repository-file.strategy.d.ts.map +0 -1
- package/dist/build-info-repository-file.strategy.js +0 -18
- package/dist/build-info-repository-file.strategy.js.map +0 -1
- package/dist/build-info-repository-noop.strategy.d.ts +0 -12
- package/dist/build-info-repository-noop.strategy.d.ts.map +0 -1
- package/dist/build-info-repository-noop.strategy.js +0 -16
- package/dist/build-info-repository-noop.strategy.js.map +0 -1
- package/dist/build-info-repository-package-json.strategy.d.ts +0 -14
- package/dist/build-info-repository-package-json.strategy.d.ts.map +0 -1
- package/dist/build-info-repository-package-json.strategy.js +0 -21
- package/dist/build-info-repository-package-json.strategy.js.map +0 -1
- package/dist/build-info-repository.strategy.d.ts +0 -12
- package/dist/build-info-repository.strategy.d.ts.map +0 -1
- package/dist/build-info-repository.strategy.js +0 -2
- package/dist/build-info-repository.strategy.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/build-info-repository-file.strategy.ts +0 -23
- package/src/build-info-repository-noop.strategy.ts +0 -16
- package/src/build-info-repository-package-json.strategy.ts +0 -25
- package/src/build-info-repository.strategy.ts +0 -13
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { MiddlewareHandler } from "hono";
|
|
2
2
|
import { ApiVersionMiddleware } from "./api-version.middleware";
|
|
3
|
-
import type {
|
|
3
|
+
import type { BuildInfoType } from "./build-info.vo";
|
|
4
4
|
import type { CacheResolverStrategy } from "./cache-resolver.strategy";
|
|
5
5
|
import type { HashContentStrategy } from "./hash-content.strategy";
|
|
6
6
|
import type { MiddlewareHonoPort } from "./middleware-hono.port";
|
|
7
|
+
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
7
8
|
|
|
8
9
|
type Dependencies = {
|
|
9
10
|
CacheResolver: CacheResolverStrategy;
|
|
10
11
|
HashContent: HashContentStrategy;
|
|
11
|
-
|
|
12
|
+
BuildInfoConfig: ReactiveConfigPort<BuildInfoType>;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export class ApiVersionHonoMiddleware implements MiddlewareHonoPort {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type * as tools from "@bgord/tools";
|
|
2
|
-
import type {
|
|
2
|
+
import type { BuildInfoType } from "./build-info.vo";
|
|
3
3
|
import type { CacheResolverStrategy } from "./cache-resolver.strategy";
|
|
4
4
|
import type { HashContentStrategy } from "./hash-content.strategy";
|
|
5
|
+
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
5
6
|
import { SubjectApplicationResolver } from "./subject-application-resolver.vo";
|
|
6
7
|
import { SubjectSegmentFixedStrategy } from "./subject-segment-fixed.strategy";
|
|
7
8
|
|
|
8
9
|
type Dependencies = {
|
|
9
10
|
CacheResolver: CacheResolverStrategy;
|
|
10
11
|
HashContent: HashContentStrategy;
|
|
11
|
-
|
|
12
|
+
BuildInfoConfig: ReactiveConfigPort<BuildInfoType>;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export class ApiVersionMiddleware {
|
|
@@ -16,7 +17,7 @@ export class ApiVersionMiddleware {
|
|
|
16
17
|
|
|
17
18
|
constructor(private readonly deps: Dependencies) {}
|
|
18
19
|
|
|
19
|
-
async evaluate(): Promise<tools.
|
|
20
|
+
async evaluate(): Promise<tools.PackageVersionSchemaType> {
|
|
20
21
|
const resolver = new SubjectApplicationResolver(
|
|
21
22
|
[new SubjectSegmentFixedStrategy("api-version")],
|
|
22
23
|
this.deps,
|
|
@@ -24,7 +25,7 @@ export class ApiVersionMiddleware {
|
|
|
24
25
|
const subject = await resolver.resolve();
|
|
25
26
|
|
|
26
27
|
const build = await this.deps.CacheResolver.resolve(subject.hex, async () =>
|
|
27
|
-
this.deps.
|
|
28
|
+
this.deps.BuildInfoConfig.get(),
|
|
28
29
|
);
|
|
29
30
|
|
|
30
31
|
return build.version;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as tools from "@bgord/tools";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
import { CommitShaValue } from "./commit-sha-value.vo";
|
|
4
|
+
|
|
5
|
+
export const BuildInfo = v.object({
|
|
6
|
+
timestamp: tools.TimestampValue,
|
|
7
|
+
version: tools.PackageVersionSchema,
|
|
8
|
+
sha: CommitShaValue,
|
|
9
|
+
size: tools.SizeBytes,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type BuildInfoType = v.InferOutput<typeof BuildInfo>;
|
|
13
|
+
|
|
14
|
+
export const BUILD_INFO_FILE_PATH = tools.FilePathRelative.fromString("infra/build-info.json");
|
|
@@ -8,7 +8,7 @@ export class ErrorNormalizer {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
static isNormalizedError(value: unknown): value is NormalizedError {
|
|
11
|
-
return isPlainObject(value) && "message" in value && typeof value
|
|
11
|
+
return isPlainObject(value) && "message" in value && typeof value["message"] === "string";
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
private static normalizeWithGuard(error: unknown, seen: WeakSet<object>): NormalizedError {
|
package/src/event-envelope.ts
CHANGED
|
@@ -17,13 +17,12 @@ export const EventEnvelopeSchema = {
|
|
|
17
17
|
revision: v.optional(tools.RevisionValue),
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
const createEventEnvelope = (stream: EventStreamType, deps: Dependencies) =>
|
|
21
21
|
({
|
|
22
22
|
id: deps.IdProvider.generate(),
|
|
23
23
|
correlationId: CorrelationStorage.get(),
|
|
24
24
|
createdAt: deps.Clock.now().ms,
|
|
25
25
|
stream,
|
|
26
|
-
version: 1,
|
|
27
26
|
}) as const;
|
|
28
27
|
|
|
29
28
|
export function event<Schema extends v.ObjectSchema<any, any>>(
|
|
@@ -35,6 +34,7 @@ export function event<Schema extends v.ObjectSchema<any, any>>(
|
|
|
35
34
|
return v.parse(schema, {
|
|
36
35
|
...createEventEnvelope(stream, deps),
|
|
37
36
|
name: schema.entries.name.literal,
|
|
37
|
+
version: schema.entries.version.literal,
|
|
38
38
|
payload,
|
|
39
39
|
});
|
|
40
40
|
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import type { GenericEvent, GenericEventSerialized } from "./event.types";
|
|
1
2
|
import type { EventSerializerPort } from "./event-serializer.port";
|
|
2
3
|
|
|
3
4
|
export class EventSerializerCollectingAdapter implements EventSerializerPort {
|
|
4
|
-
readonly serialized: Array<
|
|
5
|
+
readonly serialized: Array<GenericEvent["payload"]> = [];
|
|
5
6
|
|
|
6
|
-
readonly deserialized: Array<
|
|
7
|
+
readonly deserialized: Array<GenericEventSerialized["payload"]> = [];
|
|
7
8
|
|
|
8
|
-
serialize(payload:
|
|
9
|
+
serialize(payload: GenericEvent["payload"]): GenericEventSerialized["payload"] {
|
|
9
10
|
this.serialized.push(payload);
|
|
10
11
|
|
|
11
12
|
return JSON.stringify(payload);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
deserialize(raw:
|
|
15
|
+
deserialize(raw: GenericEventSerialized["payload"]): GenericEvent["payload"] {
|
|
15
16
|
this.deserialized.push(raw);
|
|
16
17
|
|
|
17
18
|
return JSON.parse(raw);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import type { GenericEvent, GenericEventSerialized } from "./event.types";
|
|
1
2
|
import type { EventSerializerPort } from "./event-serializer.port";
|
|
2
3
|
|
|
3
4
|
export class EventSerializerJsonAdapter implements EventSerializerPort {
|
|
4
|
-
serialize(payload:
|
|
5
|
+
serialize(payload: GenericEvent["payload"]): GenericEventSerialized["payload"] {
|
|
5
6
|
return JSON.stringify(payload);
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
deserialize(raw:
|
|
9
|
+
deserialize(raw: GenericEventSerialized["payload"]): GenericEvent["payload"] {
|
|
9
10
|
return JSON.parse(raw);
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { GenericEvent, GenericEventSerialized } from "./event.types";
|
|
2
|
+
|
|
1
3
|
export interface EventSerializerPort {
|
|
2
|
-
serialize(payload:
|
|
3
|
-
deserialize(raw:
|
|
4
|
+
serialize(payload: GenericEvent["payload"]): GenericEventSerialized["payload"];
|
|
5
|
+
deserialize(raw: GenericEventSerialized["payload"]): GenericEvent["payload"];
|
|
4
6
|
}
|
|
@@ -4,12 +4,14 @@ import type { EventInserterPort } from "./event-inserter.port";
|
|
|
4
4
|
import type { EventSerializerPort } from "./event-serializer.port";
|
|
5
5
|
import type { EventStorePort } from "./event-store.port";
|
|
6
6
|
import type { EventStreamType } from "./event-stream.vo";
|
|
7
|
+
import type { EventUpcasterPort } from "./event-upcaster.port";
|
|
7
8
|
import type { EventValidatorRegistryPort } from "./event-validator-registry.port";
|
|
8
9
|
|
|
9
10
|
type Config = {
|
|
10
11
|
finder: EventFinderPort;
|
|
11
12
|
inserter: EventInserterPort;
|
|
12
13
|
serializer: EventSerializerPort;
|
|
14
|
+
upcaster?: EventUpcasterPort;
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
const EventStoreAdapterError = { UniqueStream: "event.store.adapter.error.unique.stream" };
|
|
@@ -25,6 +27,7 @@ export class EventStoreAdapter<Event extends GenericEvent> implements EventStore
|
|
|
25
27
|
|
|
26
28
|
return events
|
|
27
29
|
.map((event) => ({ ...event, payload: this.config.serializer.deserialize(event.payload) }))
|
|
30
|
+
.map((event) => (this.config.upcaster ? this.config.upcaster.upcast(event) : event))
|
|
28
31
|
.map((event) => registry.validate(event));
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { GenericEvent } from "./event.types";
|
|
2
|
+
import type { EventUpcasterPort } from "./event-upcaster.port";
|
|
3
|
+
import type { EventUpcasterStep } from "./event-upcaster-step.vo";
|
|
4
|
+
|
|
5
|
+
const EventUpcasterChainAdapterError = {
|
|
6
|
+
DuplicateStep: "event.upcaster.chain.duplicate.step",
|
|
7
|
+
GapInChain: "event.upcaster.chain.gap",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type EventUpcasterChainConfig = Record<GenericEvent["name"], ReadonlyArray<EventUpcasterStep<any, any>>>;
|
|
11
|
+
|
|
12
|
+
export class EventUpcasterChainAdapter implements EventUpcasterPort {
|
|
13
|
+
private readonly upcasters: Record<GenericEvent["name"], ReadonlyArray<EventUpcasterStep<any, any>>>;
|
|
14
|
+
|
|
15
|
+
constructor(config: EventUpcasterChainConfig) {
|
|
16
|
+
this.upcasters = Object.fromEntries(
|
|
17
|
+
Object.entries(config).map(([name, chain]) => [
|
|
18
|
+
name,
|
|
19
|
+
[...chain].sort((a, b) => a.config.fromVersion - b.config.fromVersion),
|
|
20
|
+
]),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
for (const chain of Object.values(this.upcasters)) {
|
|
24
|
+
const versions = chain.map((step) => step.config.fromVersion);
|
|
25
|
+
|
|
26
|
+
if (new Set(versions).size !== versions.length) {
|
|
27
|
+
throw new Error(EventUpcasterChainAdapterError.DuplicateStep);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (chain.some((step, i) => i > 0 && step.config.fromVersion !== chain[i - 1]!.config.toVersion)) {
|
|
31
|
+
throw new Error(EventUpcasterChainAdapterError.GapInChain);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
upcast(event: GenericEvent): GenericEvent {
|
|
37
|
+
const chain = this.upcasters[event.name];
|
|
38
|
+
|
|
39
|
+
if (!chain) return event;
|
|
40
|
+
|
|
41
|
+
return chain.reduce(
|
|
42
|
+
(result, step) =>
|
|
43
|
+
result.version === step.config.fromVersion
|
|
44
|
+
? { ...result, version: step.config.toVersion, payload: step.config.upcast(result.payload) }
|
|
45
|
+
: result,
|
|
46
|
+
event,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { GenericEvent } from "./event.types";
|
|
2
|
+
|
|
3
|
+
export type EventUpcasterStepConfig<
|
|
4
|
+
From extends GenericEvent = GenericEvent,
|
|
5
|
+
To extends GenericEvent = GenericEvent,
|
|
6
|
+
> = {
|
|
7
|
+
fromVersion: GenericEvent["version"];
|
|
8
|
+
toVersion: GenericEvent["version"];
|
|
9
|
+
upcast: (payload: From["payload"]) => To["payload"];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const EventUpcasterStepError = { VersionIncrement: "event.upcaster.step.version.increment" };
|
|
13
|
+
|
|
14
|
+
export class EventUpcasterStep<
|
|
15
|
+
From extends GenericEvent = GenericEvent,
|
|
16
|
+
To extends GenericEvent = GenericEvent,
|
|
17
|
+
> {
|
|
18
|
+
constructor(readonly config: EventUpcasterStepConfig<From, To>) {
|
|
19
|
+
if (config.toVersion !== config.fromVersion + 1) throw new Error(EventUpcasterStepError.VersionIncrement);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/event.types.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type GenericEvent = {
|
|
|
10
10
|
revision?: tools.RevisionValueType;
|
|
11
11
|
name: string;
|
|
12
12
|
version: number;
|
|
13
|
-
payload: unknown
|
|
13
|
+
payload: Record<string, unknown>;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export type GenericEventSerialized = Omit<GenericEvent, "payload"> & { payload: string };
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { createFactory } from "hono/factory";
|
|
2
|
-
import type {
|
|
2
|
+
import type { BuildInfoType } from "./build-info.vo";
|
|
3
3
|
import type { ClockPort } from "./clock.port";
|
|
4
4
|
import type { HandlerHonoPort } from "./handler-hono.port";
|
|
5
5
|
import { type HealthcheckConfig, HealthcheckHandler } from "./healthcheck.handler";
|
|
6
6
|
import type { LoggerStatsProviderPort } from "./logger-stats-provider.port";
|
|
7
|
+
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
7
8
|
|
|
8
9
|
type Dependencies = {
|
|
9
10
|
Clock: ClockPort;
|
|
10
|
-
|
|
11
|
+
BuildInfoConfig: ReactiveConfigPort<BuildInfoType>;
|
|
11
12
|
LoggerStatsProvider?: LoggerStatsProviderPort;
|
|
12
13
|
};
|
|
13
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import * as tools from "@bgord/tools";
|
|
3
|
-
import type {
|
|
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
6
|
import { EventLoopLag } from "./event-loop-lag.service";
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
type PrerequisiteVerificationResult,
|
|
16
16
|
} from "./prerequisite-verifier.port";
|
|
17
17
|
import { PrerequisiteVerifierSelfAdapter } from "./prerequisite-verifier-self.adapter";
|
|
18
|
+
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
18
19
|
import type { RedactorStrategy } from "./redactor.strategy";
|
|
19
20
|
import { Stopwatch } from "./stopwatch.service";
|
|
20
21
|
import { Uptime, type UptimeResultType } from "./uptime.service";
|
|
@@ -27,7 +28,7 @@ export enum HealthcheckStatusEnum {
|
|
|
27
28
|
|
|
28
29
|
type Dependencies = {
|
|
29
30
|
Clock: ClockPort;
|
|
30
|
-
|
|
31
|
+
BuildInfoConfig: ReactiveConfigPort<BuildInfoType>;
|
|
31
32
|
LoggerStatsProvider?: LoggerStatsProviderPort;
|
|
32
33
|
};
|
|
33
34
|
|
|
@@ -125,7 +126,7 @@ export class HealthcheckHandler {
|
|
|
125
126
|
? HealthcheckStatusEnum.degraded
|
|
126
127
|
: HealthcheckStatusEnum.healthy;
|
|
127
128
|
|
|
128
|
-
const build = await this.deps.
|
|
129
|
+
const build = await this.deps.BuildInfoConfig.get();
|
|
129
130
|
const uptime = Uptime.get(this.deps.Clock);
|
|
130
131
|
const histogram = EventLoopLag.snapshot();
|
|
131
132
|
const memory = MemoryConsumption.snapshot();
|
|
@@ -135,11 +136,11 @@ export class HealthcheckHandler {
|
|
|
135
136
|
code: HealthcheckStatusCode[status],
|
|
136
137
|
details,
|
|
137
138
|
deployment: {
|
|
138
|
-
version: build.version
|
|
139
|
-
timestamp: build.timestamp
|
|
140
|
-
date: new Date(build.timestamp
|
|
141
|
-
sha: build.sha
|
|
142
|
-
size: build.size.format(tools.Size.unit.MB),
|
|
139
|
+
version: build.version,
|
|
140
|
+
timestamp: build.timestamp,
|
|
141
|
+
date: new Date(build.timestamp).toISOString(),
|
|
142
|
+
sha: build.sha,
|
|
143
|
+
size: tools.Size.fromBytes(build.size).format(tools.Size.unit.MB),
|
|
143
144
|
environment: this.config.Env,
|
|
144
145
|
},
|
|
145
146
|
server: {
|
package/src/index.ts
CHANGED
|
@@ -35,10 +35,7 @@ export * from "./basic-auth-username.vo";
|
|
|
35
35
|
export * from "./better-auth-logger.service";
|
|
36
36
|
export * from "./binary.vo";
|
|
37
37
|
export * from "./bots.vo";
|
|
38
|
-
export * from "./build-info
|
|
39
|
-
export * from "./build-info-repository-file.strategy";
|
|
40
|
-
export * from "./build-info-repository-noop.strategy";
|
|
41
|
-
export * from "./build-info-repository-package-json.strategy";
|
|
38
|
+
export * from "./build-info.vo";
|
|
42
39
|
export * from "./cache-file.service";
|
|
43
40
|
export * from "./cache-repository.port";
|
|
44
41
|
export * from "./cache-repository-node-cache.adapter";
|
|
@@ -114,6 +111,10 @@ export * from "./event-store-dispatching.adapter";
|
|
|
114
111
|
export * from "./event-store-noop.adapter";
|
|
115
112
|
export * from "./event-store-with-logger.adapter";
|
|
116
113
|
export * from "./event-stream.vo";
|
|
114
|
+
export * from "./event-upcaster.port";
|
|
115
|
+
export * from "./event-upcaster-chain.adapter";
|
|
116
|
+
export * from "./event-upcaster-noop.adapter";
|
|
117
|
+
export * from "./event-upcaster-step.vo";
|
|
117
118
|
export * from "./event-validator-registry.adapter";
|
|
118
119
|
export * from "./event-validator-registry.port";
|
|
119
120
|
export * from "./file-cleaner.adapter";
|
|
@@ -303,6 +304,11 @@ export * from "./randomness.strategy";
|
|
|
303
304
|
export * from "./randomness-crypto.strategy";
|
|
304
305
|
export * from "./randomness-math.strategy";
|
|
305
306
|
export * from "./randomness-noop.strategy";
|
|
307
|
+
export * from "./reactive-config.port";
|
|
308
|
+
export * from "./reactive-config-file-json.adapter";
|
|
309
|
+
export * from "./reactive-config-noop.adapter";
|
|
310
|
+
export * from "./reactive-config-with-cache.adapter";
|
|
311
|
+
export * from "./reactive-config-with-fallback.adapter";
|
|
306
312
|
export * from "./readiness.handler";
|
|
307
313
|
export * from "./readiness-hono.handler";
|
|
308
314
|
export * from "./recaptcha-secret-key.vo";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type * as tools from "@bgord/tools";
|
|
2
|
-
import * as v from "valibot";
|
|
3
2
|
import type { ClockPort } from "../../../clock.port";
|
|
4
|
-
import {
|
|
3
|
+
import { event } from "../../../event-envelope";
|
|
5
4
|
import type { EventStorePort } from "../../../event-store.port";
|
|
6
5
|
import type { IdProviderPort } from "../../../id-provider.port";
|
|
7
6
|
import type { Languages } from "../../../languages.vo";
|
|
@@ -34,11 +33,12 @@ export const handleSetUserLanguageCommand =
|
|
|
34
33
|
|
|
35
34
|
if (!Invariants.UserLanguageHasChanged.passes({ current, candidate })) return;
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
await deps.EventStore.save([
|
|
37
|
+
event(
|
|
38
|
+
Events.UserLanguageSetEvent,
|
|
39
|
+
`preferences_${command.payload.userId}`,
|
|
40
|
+
{ userId: command.payload.userId, language: candidate },
|
|
41
|
+
deps,
|
|
42
|
+
),
|
|
43
|
+
]);
|
|
44
44
|
};
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import * as v from "valibot";
|
|
2
1
|
import type { ClockPort } from "../../../clock.port";
|
|
3
|
-
import {
|
|
2
|
+
import { event } from "../../../event-envelope";
|
|
4
3
|
import type { EventStorePort } from "../../../event-store.port";
|
|
5
4
|
import type { IdProviderPort } from "../../../id-provider.port";
|
|
6
5
|
import type { UnitOfWork } from "../../../job-handler.strategy";
|
|
7
6
|
import { Jobs } from "../../../jobs.service";
|
|
8
|
-
import {
|
|
9
|
-
HOUR_HAS_PASSED_EVENT,
|
|
10
|
-
HourHasPassedEvent,
|
|
11
|
-
type HourHasPassedEventType,
|
|
12
|
-
} from "../events/HOUR_HAS_PASSED_EVENT";
|
|
7
|
+
import { HourHasPassedEvent, type HourHasPassedEventType } from "../events/HOUR_HAS_PASSED_EVENT";
|
|
13
8
|
|
|
14
9
|
type Dependencies = {
|
|
15
10
|
EventStore: EventStorePort<HourHasPassedEventType>;
|
|
@@ -25,12 +20,8 @@ export class PassageOfTimeHourly implements UnitOfWork {
|
|
|
25
20
|
label = "PassageOfTime";
|
|
26
21
|
|
|
27
22
|
async process() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
payload: { timestamp: this.deps.Clock.now().ms },
|
|
32
|
-
} satisfies HourHasPassedEventType);
|
|
33
|
-
|
|
34
|
-
await this.deps.EventStore.save([event]);
|
|
23
|
+
await this.deps.EventStore.save([
|
|
24
|
+
event(HourHasPassedEvent, "passage_of_time", { timestamp: this.deps.Clock.now().ms }, this.deps),
|
|
25
|
+
]);
|
|
35
26
|
}
|
|
36
27
|
}
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import * as v from "valibot";
|
|
2
1
|
import type { ClockPort } from "../../../clock.port";
|
|
3
|
-
import {
|
|
2
|
+
import { event } from "../../../event-envelope";
|
|
4
3
|
import type { EventStorePort } from "../../../event-store.port";
|
|
5
4
|
import type { IdProviderPort } from "../../../id-provider.port";
|
|
6
5
|
import type { UnitOfWork } from "../../../job-handler.strategy";
|
|
7
6
|
import { Jobs } from "../../../jobs.service";
|
|
8
|
-
import {
|
|
9
|
-
MINUTE_HAS_PASSED_EVENT,
|
|
10
|
-
MinuteHasPassedEvent,
|
|
11
|
-
type MinuteHasPassedEventType,
|
|
12
|
-
} from "../events/MINUTE_HAS_PASSED_EVENT";
|
|
7
|
+
import { MinuteHasPassedEvent, type MinuteHasPassedEventType } from "../events/MINUTE_HAS_PASSED_EVENT";
|
|
13
8
|
|
|
14
9
|
type Dependencies = {
|
|
15
10
|
EventStore: EventStorePort<MinuteHasPassedEventType>;
|
|
@@ -25,12 +20,8 @@ export class PassageOfTimeMinute implements UnitOfWork {
|
|
|
25
20
|
label = "PassageOfTime";
|
|
26
21
|
|
|
27
22
|
async process() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
payload: { timestamp: this.deps.Clock.now().ms },
|
|
32
|
-
} satisfies MinuteHasPassedEventType);
|
|
33
|
-
|
|
34
|
-
await this.deps.EventStore.save([event]);
|
|
23
|
+
await this.deps.EventStore.save([
|
|
24
|
+
event(MinuteHasPassedEvent, "passage_of_time", { timestamp: this.deps.Clock.now().ms }, this.deps),
|
|
25
|
+
]);
|
|
35
26
|
}
|
|
36
27
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type * as tools from "@bgord/tools";
|
|
2
|
+
import type { FileReaderJsonPort } from "./file-reader-json.port";
|
|
3
|
+
import {
|
|
4
|
+
ReactiveConfigError,
|
|
5
|
+
type ReactiveConfigPort,
|
|
6
|
+
type ReactiveConfigSchema,
|
|
7
|
+
} from "./reactive-config.port";
|
|
8
|
+
|
|
9
|
+
type Dependencies = { FileReaderJson: FileReaderJsonPort };
|
|
10
|
+
|
|
11
|
+
export class ReactiveConfigFileJsonAdapter<T extends object> implements ReactiveConfigPort<T> {
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly path: tools.FilePathAbsolute | tools.FilePathRelative,
|
|
14
|
+
private readonly schema: ReactiveConfigSchema<T>,
|
|
15
|
+
private readonly deps: Dependencies,
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
async get(): Promise<Readonly<T>> {
|
|
19
|
+
const raw = await this.deps.FileReaderJson.read(this.path);
|
|
20
|
+
|
|
21
|
+
const result = this.schema["~standard"].validate(raw);
|
|
22
|
+
if (result instanceof Promise) throw new Error(ReactiveConfigError.NoAsyncSchema);
|
|
23
|
+
if (result.issues) throw new Error(result.issues[0]?.message);
|
|
24
|
+
return Object.freeze(result.value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ReactiveConfigError,
|
|
3
|
+
type ReactiveConfigPort,
|
|
4
|
+
type ReactiveConfigSchema,
|
|
5
|
+
} from "./reactive-config.port";
|
|
6
|
+
|
|
7
|
+
export class ReactiveConfigNoopAdapter<T extends object> implements ReactiveConfigPort<T> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly schema: ReactiveConfigSchema<T>,
|
|
10
|
+
private readonly value: T,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
async get(): Promise<Readonly<T>> {
|
|
14
|
+
const result = this.schema["~standard"].validate(this.value);
|
|
15
|
+
if (result instanceof Promise) throw new Error(ReactiveConfigError.NoAsyncSchema);
|
|
16
|
+
if (result.issues) throw new Error(result.issues[0]?.message);
|
|
17
|
+
return Object.freeze(result.value);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CacheResolverStrategy } from "./cache-resolver.strategy";
|
|
2
|
+
import type { HashContentStrategy } from "./hash-content.strategy";
|
|
3
|
+
import type { ReactiveConfigPort } from "./reactive-config.port";
|
|
4
|
+
|
|
5
|
+
type Dependencies = { CacheResolver: CacheResolverStrategy; HashContent: HashContentStrategy };
|
|
6
|
+
|
|
7
|
+
export class ReactiveConfigWithCacheAdapter<T extends object> implements ReactiveConfigPort<T> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly inner: ReactiveConfigPort<T>,
|
|
10
|
+
private readonly subject: string,
|
|
11
|
+
private readonly deps: Dependencies,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async get(): Promise<Readonly<T>> {
|
|
15
|
+
const key = await this.deps.HashContent.hash(this.subject);
|
|
16
|
+
|
|
17
|
+
return this.deps.CacheResolver.resolve(key, () => this.inner.get());
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ReactiveConfigError,
|
|
3
|
+
type ReactiveConfigPort,
|
|
4
|
+
type ReactiveConfigSchema,
|
|
5
|
+
} from "./reactive-config.port";
|
|
6
|
+
|
|
7
|
+
export class ReactiveConfigWithFallbackAdapter<T extends object> implements ReactiveConfigPort<T> {
|
|
8
|
+
constructor(
|
|
9
|
+
private readonly inner: ReactiveConfigPort<T>,
|
|
10
|
+
private readonly schema: ReactiveConfigSchema<T>,
|
|
11
|
+
private readonly fallback: T,
|
|
12
|
+
) {}
|
|
13
|
+
|
|
14
|
+
async get(): Promise<Readonly<T>> {
|
|
15
|
+
try {
|
|
16
|
+
return await this.inner.get();
|
|
17
|
+
} catch {
|
|
18
|
+
const result = this.schema["~standard"].validate(this.fallback);
|
|
19
|
+
if (result instanceof Promise) throw new Error(ReactiveConfigError.NoAsyncSchema);
|
|
20
|
+
if (result.issues) throw new Error(result.issues[0]?.message);
|
|
21
|
+
return Object.freeze(result.value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
|
|
3
|
+
export const ReactiveConfigError = { NoAsyncSchema: "reactive.config.no.async.schema" };
|
|
4
|
+
|
|
5
|
+
export type ReactiveConfigSchema<T extends object> = StandardSchemaV1<unknown, T>;
|
|
6
|
+
|
|
7
|
+
export interface ReactiveConfigPort<T extends object> {
|
|
8
|
+
get(): Promise<Readonly<T>>;
|
|
9
|
+
}
|
|
@@ -10,9 +10,8 @@ export class RedactorErrorCauseDepthLimit implements RedactorStrategy {
|
|
|
10
10
|
// Stryker disable all
|
|
11
11
|
if (!isPlainObject(input)) return input;
|
|
12
12
|
// Stryker restore all
|
|
13
|
-
if (!ErrorNormalizer.isNormalizedError(input
|
|
14
|
-
|
|
15
|
-
return { ...input, error: this.limit(input.error, tools.Int.nonNegative(0)) };
|
|
13
|
+
if (!ErrorNormalizer.isNormalizedError(input["error"])) return input;
|
|
14
|
+
return { ...input, error: this.limit(input["error"], tools.Int.nonNegative(0)) };
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
private limit(error: NormalizedError, depth: tools.IntegerNonNegativeType): NormalizedError {
|
|
@@ -7,9 +7,8 @@ export class RedactorErrorStackHide implements RedactorStrategy {
|
|
|
7
7
|
// Stryker disable all
|
|
8
8
|
if (!isPlainObject(input)) return input;
|
|
9
9
|
// Stryker restore all
|
|
10
|
-
if (!ErrorNormalizer.isNormalizedError(input
|
|
11
|
-
|
|
12
|
-
return { ...input, error: this.hide(input.error) };
|
|
10
|
+
if (!ErrorNormalizer.isNormalizedError(input["error"])) return input;
|
|
11
|
+
return { ...input, error: this.hide(input["error"]) };
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
private hide(error: NormalizedError): NormalizedError {
|
|
@@ -20,7 +20,7 @@ export class RedactorMetadataCompactArray implements RedactorStrategy {
|
|
|
20
20
|
return {
|
|
21
21
|
...input,
|
|
22
22
|
metadata: deepCloneWith(
|
|
23
|
-
input
|
|
23
|
+
input["metadata"],
|
|
24
24
|
(value) => {
|
|
25
25
|
if (!Array.isArray(value)) return undefined;
|
|
26
26
|
if (value.length <= this.maxItems) return undefined;
|