@privateaim/server-kit 0.8.16 → 0.8.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/constants.d.ts +6 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/index.cjs +165 -142
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.mjs +156 -135
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/services/entity-event/handlers/index.d.ts +3 -0
  11. package/dist/services/entity-event/handlers/index.d.ts.map +1 -0
  12. package/dist/services/entity-event/handlers/redis/helpers.d.ts +2 -0
  13. package/dist/services/entity-event/handlers/redis/helpers.d.ts.map +1 -0
  14. package/dist/services/entity-event/handlers/redis/index.d.ts.map +1 -0
  15. package/dist/services/entity-event/handlers/redis/module.d.ts +8 -0
  16. package/dist/services/entity-event/handlers/redis/module.d.ts.map +1 -0
  17. package/dist/services/entity-event/handlers/socket/index.d.ts +2 -0
  18. package/dist/services/entity-event/handlers/socket/index.d.ts.map +1 -0
  19. package/dist/services/entity-event/handlers/socket/module.d.ts +10 -0
  20. package/dist/services/entity-event/handlers/socket/module.d.ts.map +1 -0
  21. package/dist/services/entity-event/index.d.ts +5 -0
  22. package/dist/services/entity-event/index.d.ts.map +1 -0
  23. package/dist/services/entity-event/module.d.ts +10 -0
  24. package/dist/services/{domain-event → entity-event}/module.d.ts.map +1 -1
  25. package/dist/services/entity-event/singleton.d.ts +5 -0
  26. package/dist/services/entity-event/singleton.d.ts.map +1 -0
  27. package/dist/services/entity-event/types.d.ts +38 -0
  28. package/dist/services/entity-event/types.d.ts.map +1 -0
  29. package/dist/services/entity-event/utils.d.ts +2 -0
  30. package/dist/services/entity-event/utils.d.ts.map +1 -0
  31. package/dist/services/index.d.ts +1 -1
  32. package/dist/services/logger/index.d.ts +1 -0
  33. package/dist/services/logger/index.d.ts.map +1 -1
  34. package/dist/services/logger/module.d.ts +1 -2
  35. package/dist/services/logger/module.d.ts.map +1 -1
  36. package/dist/services/logger/singleton.d.ts +1 -1
  37. package/dist/services/logger/transports/console.d.ts +8 -0
  38. package/dist/services/logger/transports/console.d.ts.map +1 -0
  39. package/dist/services/logger/transports/index.d.ts +3 -0
  40. package/dist/services/logger/transports/index.d.ts.map +1 -0
  41. package/dist/services/logger/transports/memory.d.ts +6 -0
  42. package/dist/services/logger/transports/memory.d.ts.map +1 -0
  43. package/dist/services/logger/types.d.ts +27 -4
  44. package/dist/services/logger/types.d.ts.map +1 -1
  45. package/package.json +4 -3
  46. package/src/constants.ts +12 -0
  47. package/src/index.ts +1 -0
  48. package/src/services/entity-event/handlers/index.ts +9 -0
  49. package/src/services/{domain-event → entity-event/handlers}/redis/helpers.ts +4 -4
  50. package/src/services/{domain-event → entity-event/handlers}/redis/module.ts +8 -8
  51. package/src/services/{domain-event → entity-event/handlers}/socket/index.ts +0 -1
  52. package/src/services/entity-event/handlers/socket/module.ts +71 -0
  53. package/src/services/{domain-event → entity-event}/index.ts +1 -2
  54. package/src/services/{domain-event → entity-event}/module.ts +24 -20
  55. package/src/services/entity-event/singleton.ts +22 -0
  56. package/src/services/{domain-event → entity-event}/types.ts +18 -16
  57. package/src/services/{domain-event → entity-event}/utils.ts +1 -1
  58. package/src/services/index.ts +1 -1
  59. package/src/services/logger/index.ts +1 -0
  60. package/src/services/logger/module.ts +12 -25
  61. package/src/services/logger/singleton.ts +1 -1
  62. package/src/services/logger/transports/console.ts +27 -0
  63. package/src/services/logger/transports/index.ts +9 -0
  64. package/src/services/logger/transports/memory.ts +18 -0
  65. package/src/services/logger/types.ts +27 -5
  66. package/test/data/error.ts +16 -0
  67. package/test/unit/logger.spec.ts +57 -0
  68. package/dist/services/domain-event/index.d.ts +0 -6
  69. package/dist/services/domain-event/index.d.ts.map +0 -1
  70. package/dist/services/domain-event/module.d.ts +0 -10
  71. package/dist/services/domain-event/redis/helpers.d.ts +0 -2
  72. package/dist/services/domain-event/redis/helpers.d.ts.map +0 -1
  73. package/dist/services/domain-event/redis/index.d.ts.map +0 -1
  74. package/dist/services/domain-event/redis/module.d.ts +0 -8
  75. package/dist/services/domain-event/redis/module.d.ts.map +0 -1
  76. package/dist/services/domain-event/singleton.d.ts +0 -4
  77. package/dist/services/domain-event/singleton.d.ts.map +0 -1
  78. package/dist/services/domain-event/socket/helpers.d.ts +0 -3
  79. package/dist/services/domain-event/socket/helpers.d.ts.map +0 -1
  80. package/dist/services/domain-event/socket/index.d.ts +0 -3
  81. package/dist/services/domain-event/socket/index.d.ts.map +0 -1
  82. package/dist/services/domain-event/socket/module.d.ts +0 -8
  83. package/dist/services/domain-event/socket/module.d.ts.map +0 -1
  84. package/dist/services/domain-event/types.d.ts +0 -37
  85. package/dist/services/domain-event/types.d.ts.map +0 -1
  86. package/dist/services/domain-event/utils.d.ts +0 -2
  87. package/dist/services/domain-event/utils.d.ts.map +0 -1
  88. package/src/services/domain-event/singleton.ts +0 -36
  89. package/src/services/domain-event/socket/helpers.ts +0 -26
  90. package/src/services/domain-event/socket/module.ts +0 -53
  91. /package/dist/services/{domain-event → entity-event/handlers}/redis/index.d.ts +0 -0
  92. /package/src/services/{domain-event → entity-event/handlers}/redis/index.ts +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@privateaim/server-kit",
3
- "version": "0.8.16",
3
+ "version": "0.8.18",
4
4
  "exports": {
5
5
  "./package.json": "./package.json",
6
6
  ".": {
@@ -29,13 +29,14 @@
29
29
  "dependencies": {
30
30
  "@ebec/http": "^2.3.0",
31
31
  "@isaacs/ttlcache": "^1.4.1",
32
- "@privateaim/kit": "^0.8.16",
32
+ "@privateaim/kit": "^0.8.18",
33
33
  "@socket.io/redis-emitter": "^5.1.0",
34
34
  "envix": "^1.5.0",
35
35
  "hapic": "^2.7.0",
36
36
  "singa": "^1.1.0",
37
37
  "triple-beam": "^1.4.1",
38
- "winston": "^3.17.0"
38
+ "winston": "^3.17.0",
39
+ "winston-transport": "^4.9.0"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@authup/core-http-kit": "^1.0.0-beta.27",
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ export enum EnvironmentName {
9
+ TEST = 'test',
10
+ DEVELOPMENT = 'development',
11
+ PRODUCTION = 'production',
12
+ }
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
+ export * from './constants';
8
9
  export * from './core';
9
10
  export * from './services';
10
11
  export * from './type';
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ export * from './redis';
9
+ export * from './socket';
@@ -1,15 +1,15 @@
1
1
  /*
2
2
  * Copyright (c) 2025.
3
- * Author Peter Placzek (tada5hi)
4
- * For the full copyright and license information,
5
- * view the LICENSE file that was distributed with this source code.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
8
  function stringify(input: string | string[]) {
9
9
  return typeof input === 'string' ? input : input.join('/');
10
10
  }
11
11
 
12
- export function buildDomainEventRedisChannel(
12
+ export function buildEntityEventRedisChannel(
13
13
  channel: string | string[],
14
14
  namespace?: string | string[],
15
15
  ) {
@@ -7,22 +7,22 @@
7
7
 
8
8
  import type { Client } from 'redis-extension';
9
9
  import type { DomainEventRecord } from '@privateaim/kit';
10
- import type { DomainEventPublishOptions, IDomainEventConsumer } from '../types';
11
- import { transformEventData } from '../utils';
12
- import { buildDomainEventRedisChannel } from './helpers';
10
+ import type { EntityEventHandleOptions, IEntityEventHandler } from '../../types';
11
+ import { transformEntityEventData } from '../../utils';
12
+ import { buildEntityEventRedisChannel } from './helpers';
13
13
 
14
- export class DomainEventRedisPublisher implements IDomainEventConsumer {
14
+ export class EntityEventRedisHandler implements IEntityEventHandler {
15
15
  protected driver : Client;
16
16
 
17
17
  constructor(client: Client) {
18
18
  this.driver = client;
19
19
  }
20
20
 
21
- async consume(ctx: DomainEventPublishOptions) : Promise<void> {
21
+ async handle(ctx: EntityEventHandleOptions) : Promise<void> {
22
22
  const payload : DomainEventRecord = {
23
- type: ctx.metadata.domain,
23
+ type: ctx.metadata.ref_type,
24
24
  event: ctx.metadata.event,
25
- data: transformEventData(ctx.data),
25
+ data: transformEntityEventData(ctx.data),
26
26
  };
27
27
 
28
28
  const payloadSerialized = JSON.stringify(payload);
@@ -31,7 +31,7 @@ export class DomainEventRedisPublisher implements IDomainEventConsumer {
31
31
  for (let i = 0; i < ctx.destinations.length; i++) {
32
32
  const destination = ctx.destinations[i];
33
33
 
34
- const key = buildDomainEventRedisChannel(
34
+ const key = buildEntityEventRedisChannel(
35
35
  destination.channel,
36
36
  destination.namespace,
37
37
  );
@@ -6,4 +6,3 @@
6
6
  */
7
7
 
8
8
  export * from './module';
9
- export * from './helpers';
@@ -0,0 +1,71 @@
1
+ /*
2
+ * Copyright (c) 2022-2024.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import { buildDomainEventFullName } from '@privateaim/kit';
9
+ import { Emitter } from '@socket.io/redis-emitter';
10
+ import type { Client } from 'redis-extension';
11
+ import type { EntityEventHandleOptions, IEntityEventHandler } from '../../types';
12
+ import { transformEntityEventData } from '../../utils';
13
+
14
+ export class EntityEventSocketHandler implements IEntityEventHandler {
15
+ protected client : Client;
16
+
17
+ constructor(client: Client) {
18
+ this.client = client;
19
+ }
20
+
21
+ async handle(ctx: EntityEventHandleOptions) : Promise<void> {
22
+ ctx.data = transformEntityEventData(ctx.data);
23
+
24
+ for (let i = 0; i < ctx.destinations.length; i++) {
25
+ const destination = ctx.destinations[i];
26
+
27
+ const namespace = this.buildNamespace(destination.namespace);
28
+ const roomName = this.buildChannel(destination.channel);
29
+
30
+ const fullEventName = buildDomainEventFullName(
31
+ ctx.metadata.ref_type,
32
+ ctx.metadata.event,
33
+ );
34
+
35
+ const emitter = new Emitter(this.client, {}, namespace);
36
+
37
+ emitter
38
+ .in(roomName)
39
+ .emit(fullEventName, {
40
+ data: ctx.data,
41
+ meta: {
42
+ refType: ctx.metadata.ref_type,
43
+ refId: ctx.metadata.ref_id,
44
+ event: ctx.metadata.event,
45
+ namespace,
46
+ roomName,
47
+ },
48
+ });
49
+ }
50
+ }
51
+
52
+ protected buildNamespace(namespace?: string | string[]) {
53
+ if (typeof namespace === 'undefined') {
54
+ return '/';
55
+ }
56
+
57
+ if (typeof namespace === 'string') {
58
+ return namespace.startsWith('/') ? namespace : `/${namespace}`;
59
+ }
60
+
61
+ return `/${namespace.join('/')}`;
62
+ }
63
+
64
+ protected buildChannel(channel: string | string[]) {
65
+ if (typeof channel === 'string') {
66
+ return channel;
67
+ }
68
+
69
+ return channel.join('/');
70
+ }
71
+ }
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  export * from './module';
9
- export * from './redis';
9
+ export * from './handlers';
10
10
  export * from './singleton';
11
- export * from './socket';
12
11
  export * from './types';
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2024-2024.
2
+ * Copyright (c) 2024-2025.
3
3
  * Author Peter Placzek (tada5hi)
4
4
  * For the full copyright and license information,
5
5
  * view the LICENSE file that was distributed with this source code.
@@ -9,63 +9,67 @@ import type { ObjectLiteral } from '@privateaim/kit';
9
9
  import { buildDomainEventFullName } from '@privateaim/kit';
10
10
  import { isLoggerUsable, useLogger } from '../logger';
11
11
  import type {
12
- DomainEventConsumeOptions, DomainEventDestination,
13
- DomainEventPublishOptions,
14
- IDomainEventConsumer,
15
- IDomainEventPublisher,
12
+ EntityEventDestination,
13
+ EntityEventHandleOptions,
14
+ EntityEventPublishOptions,
15
+ IEntityEventHandler,
16
+ IEntityEventPublisher,
16
17
  } from './types';
17
18
 
18
- export class DomainEventPublisher implements IDomainEventPublisher {
19
- protected consumers : Set<IDomainEventConsumer>;
19
+ export class EntityEventPublisher implements IEntityEventPublisher {
20
+ protected handlers : Set<IEntityEventHandler>;
20
21
 
21
22
  constructor() {
22
- this.consumers = new Set<IDomainEventConsumer>();
23
+ this.handlers = new Set<IEntityEventHandler>();
23
24
  }
24
25
 
25
- addConsumer(consumer: IDomainEventConsumer) {
26
- this.consumers.add(consumer);
26
+ register(consumer: IEntityEventHandler) {
27
+ this.handlers.add(consumer);
27
28
  }
28
29
 
29
30
  async safePublish<T extends ObjectLiteral = ObjectLiteral>(
30
- ctx: DomainEventPublishOptions<T>,
31
+ ctx: EntityEventPublishOptions<T>,
31
32
  ) : Promise<void> {
32
33
  try {
33
34
  await this.publish(ctx);
34
35
  } catch (e) {
35
36
  if (isLoggerUsable()) {
36
- useLogger().error(`Publishing event ${buildDomainEventFullName(ctx.metadata.domain, ctx.metadata.event)} failed`);
37
+ useLogger().error(`Publishing event ${buildDomainEventFullName(ctx.metadata.ref_type, ctx.metadata.event)} failed`);
37
38
  useLogger().error(e);
38
39
  }
39
40
  }
40
41
  }
41
42
 
42
43
  async publish<T extends ObjectLiteral = ObjectLiteral>(
43
- ctx: DomainEventPublishOptions<T>,
44
+ ctx: EntityEventPublishOptions<T>,
44
45
  ) : Promise<void> {
45
46
  if (isLoggerUsable()) {
46
- useLogger().info(`Publishing event ${buildDomainEventFullName(ctx.metadata.domain, ctx.metadata.event)}`);
47
+ useLogger()
48
+ .debug(
49
+ `Publishing event ${buildDomainEventFullName(ctx.metadata.ref_type, ctx.metadata.event)}`,
50
+ );
47
51
  }
48
52
 
49
- let destinations : DomainEventDestination[] = [];
53
+ let destinations : EntityEventDestination[] = [];
50
54
  if (typeof ctx.destinations === 'function') {
51
55
  destinations = ctx.destinations(ctx.data);
52
56
  } else {
53
57
  destinations = ctx.destinations;
54
58
  }
55
59
 
56
- const consumeContext : DomainEventConsumeOptions = {
60
+ const consumeContext : EntityEventHandleOptions = {
57
61
  ...ctx,
58
62
  destinations,
59
63
  };
60
64
 
61
- const consumers = this.consumers.values();
65
+ const handlers = this.handlers.values();
62
66
  while (true) {
63
- const it = consumers.next();
64
- if (it.done) {
67
+ const handler = handlers.next();
68
+ if (handler.done) {
65
69
  return;
66
70
  }
67
71
 
68
- await it.value.consume(consumeContext);
72
+ await (handler.value as IEntityEventHandler).handle(consumeContext);
69
73
  }
70
74
  }
71
75
  }
@@ -0,0 +1,22 @@
1
+ /*
2
+ * Copyright (c) 2024.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import type { Factory } from 'singa';
9
+ import { singa } from 'singa';
10
+ import type { EntityEventPublisher } from './module';
11
+
12
+ const instance = singa<EntityEventPublisher>({
13
+ name: 'entityEventPublisher',
14
+ });
15
+
16
+ export function setEntityEventPublisherFactory(factory: Factory<EntityEventPublisher>) {
17
+ instance.setFactory(factory);
18
+ }
19
+
20
+ export function useEntityEventPublisher() {
21
+ return instance.use();
22
+ }
@@ -7,19 +7,21 @@
7
7
 
8
8
  import type { ObjectLiteral } from '@privateaim/kit';
9
9
 
10
- export type DomainEventDestination = {
10
+ export type EntityEventDestination = {
11
11
  namespace?: string | string[],
12
12
  channel: string | string[]
13
13
  };
14
14
 
15
- export type DomainEventDestinations = DomainEventDestination[];
15
+ export type EntityEventDestinations = EntityEventDestination[];
16
16
 
17
- export type DomainEventDestinationsFn<
17
+ export type EntityEventDestinationsFn<
18
18
  T extends ObjectLiteral =ObjectLiteral,
19
- > = (data: T) => DomainEventDestination[];
19
+ > = (data: T) => EntityEventDestination[];
20
+
21
+ export type EntityEventMetadata = {
22
+ ref_type: string,
23
+ ref_id?: string,
20
24
 
21
- export type DomainEventMetadata = {
22
- domain: string,
23
25
  event: string,
24
26
 
25
27
  request_path?: string | null,
@@ -32,28 +34,28 @@ export type DomainEventMetadata = {
32
34
  actor_name?: string | null;
33
35
  };
34
36
 
35
- export type DomainEventPublishOptions<
37
+ export type EntityEventPublishOptions<
36
38
  T extends ObjectLiteral = ObjectLiteral,
37
39
  > = {
38
40
  data: T,
39
41
  dataPrevious?: T,
40
- metadata: DomainEventMetadata,
41
- destinations: DomainEventDestinations | DomainEventDestinationsFn<T>
42
+ metadata: EntityEventMetadata,
43
+ destinations: EntityEventDestinations | EntityEventDestinationsFn<T>
42
44
  };
43
45
 
44
- export interface IDomainEventPublisher {
45
- publish(ctx: DomainEventPublishOptions) : Promise<void>;
46
+ export interface IEntityEventPublisher {
47
+ publish(ctx: EntityEventPublishOptions) : Promise<void>;
46
48
  }
47
49
 
48
- export type DomainEventConsumeOptions<
50
+ export type EntityEventHandleOptions<
49
51
  T extends ObjectLiteral = ObjectLiteral,
50
52
  > = {
51
53
  data: T,
52
54
  dataPrevious?: T,
53
- metadata: DomainEventMetadata,
54
- destinations: DomainEventDestinations
55
+ metadata: EntityEventMetadata,
56
+ destinations: EntityEventDestinations
55
57
  };
56
58
 
57
- export interface IDomainEventConsumer {
58
- consume(ctx: DomainEventConsumeOptions) : Promise<void>;
59
+ export interface IEntityEventHandler {
60
+ handle(ctx: EntityEventHandleOptions) : Promise<void>;
59
61
  }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { isObject } from '@privateaim/kit';
9
9
 
10
- export function transformEventData<T>(input: T) : T {
10
+ export function transformEntityEventData<T>(input: T) : T {
11
11
  if (isObject(input)) {
12
12
  const keys = Object.keys(input);
13
13
  for (let i = 0; i < keys.length; i++) {
@@ -9,7 +9,7 @@ export * from './amqp';
9
9
  export * from './authup';
10
10
  export * from './authup-client-authentication-hook';
11
11
  export * from './cache';
12
- export * from './domain-event';
12
+ export * from './entity-event';
13
13
  export * from './logger';
14
14
  export * from './redis';
15
15
  export * from './vault';
@@ -8,3 +8,4 @@
8
8
  export * from './module';
9
9
  export * from './types';
10
10
  export * from './singleton';
11
+ export * from './transports';
@@ -5,32 +5,19 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
- import { read } from 'envix';
9
- import { EnvironmentName } from 'typeorm-extension';
10
- import type { Logger } from 'winston';
11
- import { createLogger as create, format, transports } from 'winston';
12
- import type { LoggerCreateContext, LoggerTransports } from './types';
13
-
14
- function toTransports(input: LoggerTransports) {
15
- return Array.isArray(input) ? input : [input];
16
- }
8
+ import { createLogger as create, format } from 'winston';
9
+ import { createLoggerConsoleTransport } from './transports';
10
+ import type {
11
+ Logger, LoggerCreateContext, LoggerTransport,
12
+ } from './types';
17
13
 
18
14
  export function createLogger(ctx: LoggerCreateContext = {}) : Logger {
19
- let loggerTransports : LoggerTransports;
20
- if (read('env') === EnvironmentName.PRODUCTION) {
21
- loggerTransports = [
22
- new transports.Console({
23
- level: 'info',
24
- }),
25
- ...(ctx.transports ? toTransports(ctx.transports) : []),
26
- ];
27
- } else {
28
- loggerTransports = [
29
- new transports.Console({
30
- level: 'debug',
31
- }),
32
- ...(ctx.transports ? toTransports(ctx.transports) : []),
33
- ];
15
+ const transports : LoggerTransport[] = [
16
+ ...(ctx.transports || []),
17
+ ];
18
+
19
+ if (transports.length === 0) {
20
+ transports.push(createLoggerConsoleTransport());
34
21
  }
35
22
 
36
23
  return create({
@@ -40,7 +27,7 @@ export function createLogger(ctx: LoggerCreateContext = {}) : Logger {
40
27
  format.simple(),
41
28
  ),
42
29
  level: 'debug',
43
- transports: loggerTransports,
30
+ transports,
44
31
  // todo: deeply merge options
45
32
  ...(ctx.options || {}),
46
33
  });
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { type Factory, singa } from 'singa';
9
- import type { Logger } from 'winston';
9
+ import type { Logger } from './types';
10
10
 
11
11
  const instance = singa<Logger>({
12
12
  name: 'logger',
@@ -0,0 +1,27 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import { read } from 'envix';
9
+ import { transports } from 'winston';
10
+ import type { TransportStreamOptions } from 'winston-transport';
11
+ import { EnvironmentName } from '../../../constants';
12
+ import type { LoggerTransport } from '../types';
13
+
14
+ export class LoggerConsoleTransport extends transports.Console {
15
+ constructor(options: TransportStreamOptions = {}) {
16
+ super({
17
+ level: read('env') === EnvironmentName.PRODUCTION ?
18
+ 'info' :
19
+ 'debug',
20
+ ...options,
21
+ });
22
+ }
23
+ }
24
+
25
+ export function createLoggerConsoleTransport(options: TransportStreamOptions = {}) : LoggerTransport {
26
+ return new LoggerConsoleTransport(options);
27
+ }
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ export * from './console';
9
+ export * from './memory';
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import Transport from 'winston-transport';
9
+
10
+ export class LoggerMemoryTransport extends Transport {
11
+ public items : Record<PropertyKey, any>[] = [];
12
+
13
+ log(info: Record<PropertyKey, any>, next: () => void): any {
14
+ this.items.push(info);
15
+
16
+ next();
17
+ }
18
+ }
@@ -5,15 +5,37 @@
5
5
  * view the LICENSE file that was distributed with this source code.
6
6
  */
7
7
 
8
- import type { Logger, LoggerOptions } from 'winston';
8
+ import type Transport from 'winston-transport';
9
+ import type { LoggerOptions } from 'winston';
9
10
 
10
- export type LoggerTransports = LoggerOptions['transports'];
11
+ export type LoggerTransport = Transport;
11
12
 
12
13
  export type LoggerCreateContext = {
13
14
  options?: Partial<LoggerOptions>,
14
- transports?: LoggerTransports
15
+ transports?: LoggerTransport[]
15
16
  };
16
17
 
17
- export type {
18
- Logger,
18
+ type LogEntry = {
19
+ /**
20
+ * Log message.
21
+ */
22
+ message: string | Error,
23
+ [key: string]: any
24
+ };
25
+
26
+ export interface LoggerLevelFn<OUT = any> {
27
+ (message: string, ...meta: Omit<LogEntry, 'message'>[]): OUT,
28
+ (message: LogEntry): OUT,
29
+ (message:string): OUT,
30
+ }
31
+
32
+ export type Logger = {
33
+ emerg: LoggerLevelFn<Logger>,
34
+ alert: LoggerLevelFn<Logger>,
35
+ crit: LoggerLevelFn<Logger>,
36
+ error: LoggerLevelFn<Logger>,
37
+ warn: LoggerLevelFn<Logger>,
38
+ notice: LoggerLevelFn<Logger>,
39
+ info: LoggerLevelFn<Logger>,
40
+ debug: LoggerLevelFn<Logger>,
19
41
  };
@@ -0,0 +1,16 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ export class CustomError extends Error {
9
+ code: string;
10
+
11
+ constructor(message: string, options: ErrorOptions = {}) {
12
+ super(message, options);
13
+
14
+ this.code = 'foo';
15
+ }
16
+ }
@@ -0,0 +1,57 @@
1
+ /*
2
+ * Copyright (c) 2025.
3
+ * Author Peter Placzek (tada5hi)
4
+ * For the full copyright and license information,
5
+ * view the LICENSE file that was distributed with this source code.
6
+ */
7
+
8
+ import { createLogger } from 'winston';
9
+ import { LoggerMemoryTransport } from '../../src';
10
+ import { CustomError } from '../data/error';
11
+
12
+ describe('src/logger', () => {
13
+ it('should log simple message', () => {
14
+ const memoryTransport = new LoggerMemoryTransport();
15
+
16
+ const logger = createLogger({
17
+ transports: [
18
+ memoryTransport,
19
+ ],
20
+ });
21
+
22
+ logger.info('This is a log message', {
23
+ foo: 'bar',
24
+ });
25
+
26
+ const [item] = memoryTransport.items;
27
+ expect(item).toBeDefined();
28
+ expect(item.message).toEqual('This is a log message');
29
+ expect(item.foo).toEqual('bar');
30
+ });
31
+
32
+ it('should log error', () => {
33
+ const memoryTransport = new LoggerMemoryTransport();
34
+
35
+ const logger = createLogger({
36
+ transports: [
37
+ memoryTransport,
38
+ ],
39
+ });
40
+
41
+ const error = new CustomError('This is a log message');
42
+ logger.info({
43
+ message: error,
44
+ foo: 'bar',
45
+ });
46
+
47
+ const [item] = memoryTransport.items;
48
+ expect(item).toBeDefined();
49
+
50
+ expect(item.message?.message).toEqual(error.message);
51
+ expect(item.message?.stack).toEqual(error.stack);
52
+ expect(item.message?.code).toEqual(error.code);
53
+
54
+ expect(item.foo).toEqual('bar');
55
+ expect(item.code).toBeUndefined();
56
+ });
57
+ });
@@ -1,6 +0,0 @@
1
- export * from './module';
2
- export * from './redis';
3
- export * from './singleton';
4
- export * from './socket';
5
- export * from './types';
6
- //# sourceMappingURL=index.d.ts.map