@tstdl/base 0.93.1 → 0.93.3

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 (181) hide show
  1. package/api/server/api-request-token.provider.d.ts +5 -3
  2. package/api/server/api-request-token.provider.js +12 -4
  3. package/api/server/gateway.d.ts +1 -9
  4. package/api/server/gateway.js +67 -36
  5. package/api/types.d.ts +5 -1
  6. package/application/application.d.ts +2 -0
  7. package/application/application.js +3 -1
  8. package/application/providers.d.ts +1 -1
  9. package/application/providers.js +1 -1
  10. package/audit/audit.model.d.ts +106 -6
  11. package/audit/audit.model.js +156 -13
  12. package/audit/auditor.d.ts +115 -30
  13. package/audit/auditor.js +160 -19
  14. package/audit/drizzle/0000_bored_stick.sql +26 -0
  15. package/audit/drizzle/meta/0000_snapshot.json +195 -0
  16. package/audit/drizzle/meta/_journal.json +13 -0
  17. package/audit/drizzle.config.d.ts +2 -0
  18. package/audit/drizzle.config.js +11 -0
  19. package/audit/index.d.ts +3 -1
  20. package/audit/index.js +3 -1
  21. package/audit/module.d.ts +22 -0
  22. package/audit/module.js +33 -0
  23. package/audit/schemas.d.ts +6 -0
  24. package/audit/schemas.js +8 -0
  25. package/audit/types.d.ts +2 -1
  26. package/audit/types.js +2 -1
  27. package/authentication/models/authentication-credentials.model.js +1 -2
  28. package/authentication/models/authentication-session.model.d.ts +2 -2
  29. package/authentication/models/authentication-session.model.js +3 -5
  30. package/authentication/models/index.d.ts +0 -1
  31. package/authentication/models/index.js +0 -1
  32. package/authentication/server/authentication-api-request-token.provider.d.ts +2 -2
  33. package/authentication/server/authentication-api-request-token.provider.js +8 -5
  34. package/authentication/server/authentication.api-controller.d.ts +8 -8
  35. package/authentication/server/authentication.api-controller.js +16 -16
  36. package/authentication/server/authentication.audit.d.ts +34 -0
  37. package/authentication/server/authentication.audit.js +1 -0
  38. package/authentication/server/authentication.service.d.ts +19 -10
  39. package/authentication/server/authentication.service.js +158 -43
  40. package/authentication/server/drizzle.config.js +1 -1
  41. package/authentication/server/index.d.ts +1 -0
  42. package/authentication/server/index.js +1 -0
  43. package/authentication/server/module.d.ts +1 -1
  44. package/authentication/{models → server}/schemas.d.ts +2 -3
  45. package/authentication/{models → server}/schemas.js +2 -3
  46. package/constants.d.ts +1 -0
  47. package/constants.js +1 -0
  48. package/document-management/api/document-management.api.d.ts +74 -74
  49. package/document-management/models/document-assignment-scope.model.d.ts +1 -2
  50. package/document-management/models/document-assignment-scope.model.js +4 -6
  51. package/document-management/models/document-assignment-task.model.d.ts +1 -2
  52. package/document-management/models/document-assignment-task.model.js +3 -5
  53. package/document-management/models/document-category.model.d.ts +1 -2
  54. package/document-management/models/document-category.model.js +3 -4
  55. package/document-management/models/document-collection-assignment.model.d.ts +1 -2
  56. package/document-management/models/document-collection-assignment.model.js +5 -7
  57. package/document-management/models/document-collection.model.d.ts +1 -2
  58. package/document-management/models/document-collection.model.js +3 -4
  59. package/document-management/models/document-management-table.d.ts +1 -1
  60. package/document-management/models/document-management-table.js +1 -1
  61. package/document-management/models/document-property-value.model.d.ts +1 -2
  62. package/document-management/models/document-property-value.model.js +5 -8
  63. package/document-management/models/document-property.model.d.ts +1 -2
  64. package/document-management/models/document-property.model.js +2 -3
  65. package/document-management/models/document-request-collection-assignment.model.d.ts +1 -2
  66. package/document-management/models/document-request-collection-assignment.model.js +4 -6
  67. package/document-management/models/document-request-template.d.ts +1 -2
  68. package/document-management/models/document-request-template.js +4 -6
  69. package/document-management/models/document-request.model.d.ts +1 -1
  70. package/document-management/models/document-request.model.js +4 -5
  71. package/document-management/models/document-requests-template.d.ts +1 -1
  72. package/document-management/models/document-requests-template.js +2 -3
  73. package/document-management/models/document-tag-assignment.model.d.ts +1 -2
  74. package/document-management/models/document-tag-assignment.model.js +4 -6
  75. package/document-management/models/document-tag.model.d.ts +1 -1
  76. package/document-management/models/document-tag.model.js +2 -3
  77. package/document-management/models/document-type-property.model.d.ts +1 -2
  78. package/document-management/models/document-type-property.model.js +4 -6
  79. package/document-management/models/document-type-validation.model.d.ts +1 -2
  80. package/document-management/models/document-type-validation.model.js +4 -6
  81. package/document-management/models/document-type.model.d.ts +1 -2
  82. package/document-management/models/document-type.model.js +3 -5
  83. package/document-management/models/document-validation-definition.model.d.ts +1 -2
  84. package/document-management/models/document-validation-definition.model.js +3 -4
  85. package/document-management/models/document-validation-execution-related-document.model.d.ts +1 -2
  86. package/document-management/models/document-validation-execution-related-document.model.js +4 -6
  87. package/document-management/models/document-validation-execution.model.d.ts +1 -2
  88. package/document-management/models/document-validation-execution.model.js +6 -8
  89. package/document-management/models/document-workflow.model.d.ts +1 -2
  90. package/document-management/models/document-workflow.model.js +5 -7
  91. package/document-management/models/document.model.d.ts +1 -2
  92. package/document-management/models/document.model.js +5 -7
  93. package/document-management/server/api/document-management.api.js +1 -1
  94. package/document-management/server/module.d.ts +1 -1
  95. package/document-management/server/module.js +1 -1
  96. package/document-management/server/schemas.d.ts +1 -1
  97. package/document-management/server/schemas.js +1 -1
  98. package/document-management/server/services/document-category-type.service.d.ts +2 -2
  99. package/document-management/server/services/document-category-type.service.js +1 -2
  100. package/document-management/server/services/document-collection.service.d.ts +1 -1
  101. package/document-management/server/services/document-collection.service.js +1 -2
  102. package/document-management/server/services/document-management.service.js +6 -6
  103. package/document-management/server/services/document-property.service.d.ts +1 -1
  104. package/document-management/server/services/document-property.service.js +1 -2
  105. package/document-management/server/services/document-validation.service.js +2 -2
  106. package/document-management/server/services/document-workflow.service.d.ts +2 -2
  107. package/document-management/server/services/document-workflow.service.js +1 -2
  108. package/document-management/server/services/document.service.d.ts +1 -1
  109. package/document-management/server/services/document.service.js +1 -2
  110. package/document-management/server/services/singleton.js +1 -1
  111. package/document-management/service-models/document.service-model.d.ts +62 -62
  112. package/document-management/service-models/document.service-model.js +1 -1
  113. package/document-management/service-models/enriched/enriched-document-management-data.view.js +1 -1
  114. package/document-management/service-models/enriched/enriched-document.view.d.ts +1 -1
  115. package/examples/api/authentication.js +2 -2
  116. package/examples/api/basic-overview.js +2 -2
  117. package/examples/api/custom-authentication.js +2 -2
  118. package/examples/api/streaming.js +2 -2
  119. package/examples/browser/basic.js +2 -2
  120. package/examples/document-management/main.js +2 -2
  121. package/examples/http/client.js +2 -2
  122. package/examples/mail/basic.js +2 -2
  123. package/examples/pdf/basic.js +2 -2
  124. package/examples/template/basic.js +2 -2
  125. package/http/server/http-server-request.d.ts +3 -3
  126. package/key-value-store/postgres/key-value-store.service.js +1 -2
  127. package/key-value-store/postgres/models/key-value.model.d.ts +1 -2
  128. package/key-value-store/postgres/models/key-value.model.js +2 -4
  129. package/key-value-store/postgres/models/schemas.d.ts +1 -1
  130. package/key-value-store/postgres/models/schemas.js +1 -1
  131. package/lock/postgres/lock.js +1 -1
  132. package/lock/postgres/models/lock.model.d.ts +1 -2
  133. package/lock/postgres/models/lock.model.js +3 -5
  134. package/lock/postgres/models/schemas.d.ts +1 -1
  135. package/lock/postgres/models/schemas.js +1 -1
  136. package/lock/postgres/provider.js +1 -2
  137. package/mail/models/mail-log.model.d.ts +1 -1
  138. package/mail/models/mail-log.model.js +4 -5
  139. package/mail/models/schemas.d.ts +1 -1
  140. package/mail/models/schemas.js +1 -1
  141. package/openid-connect/oidc-state.model.d.ts +1 -1
  142. package/openid-connect/oidc-state.model.js +2 -3
  143. package/openid-connect/oidc.service.js +1 -1
  144. package/orm/data-types/bytea.js +1 -1
  145. package/orm/data-types/numeric-date.js +1 -1
  146. package/orm/decorators.d.ts +65 -72
  147. package/orm/decorators.js +42 -40
  148. package/orm/entity.d.ts +7 -1
  149. package/orm/entity.js +25 -11
  150. package/orm/index.d.ts +2 -1
  151. package/orm/index.js +2 -1
  152. package/orm/schemas/json.d.ts +1 -1
  153. package/orm/schemas/json.js +1 -1
  154. package/orm/schemas/numeric-date.d.ts +1 -1
  155. package/orm/schemas/numeric-date.js +1 -1
  156. package/orm/schemas/timestamp.d.ts +1 -1
  157. package/orm/schemas/timestamp.js +1 -1
  158. package/orm/schemas/uuid.d.ts +2 -2
  159. package/orm/schemas/uuid.js +1 -1
  160. package/orm/server/drizzle/schema-converter.ts +408 -0
  161. package/orm/server/repository.d.ts +1 -1
  162. package/orm/server/repository.js +12 -9
  163. package/orm/sqls.d.ts +1 -1
  164. package/orm/sqls.js +1 -1
  165. package/orm/types.d.ts +2 -6
  166. package/orm/types.js +1 -4
  167. package/package.json +15 -24
  168. package/queue/postgres/job.model.d.ts +3 -3
  169. package/queue/postgres/job.model.js +5 -6
  170. package/queue/postgres/queue.js +2 -2
  171. package/queue/postgres/schemas.d.ts +1 -1
  172. package/queue/postgres/schemas.js +1 -1
  173. package/supports.d.ts +1 -0
  174. package/supports.js +2 -1
  175. package/types/types.d.ts +12 -1
  176. package/utils/object/object.d.ts +3 -1
  177. package/utils/object/object.js +7 -1
  178. package/orm/server/drizzle/index.js +0 -1
  179. package/orm/server/drizzle/schema-converter.d.ts +0 -15
  180. package/orm/server/drizzle/schema-converter.js +0 -300
  181. /package/orm/server/drizzle/{index.d.ts → index.ts} +0 -0
@@ -7,29 +7,156 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { EntityWithoutMetadata, Json, Table, Timestamp, Uuid } from '../orm/index.js';
10
+ import { EmbeddedProperty, EntityWithoutMetadata, JsonProperty, Table, TimestampProperty, UuidProperty } from '../orm/index.js';
11
11
  import { Enumeration, StringProperty } from '../schema/index.js';
12
12
  import { ActorType, AuditOutcome, AuditSeverity } from './types.js';
13
+ /**
14
+ * Represents the network details of the request that triggered the audit event.
15
+ */
16
+ export class RequestDetails {
17
+ /**
18
+ * The path of the request.
19
+ * @example '/api/v1/users/xyz'
20
+ */
21
+ path;
22
+ /**
23
+ * The IP address of the client.
24
+ * @example '192.168.1.100'
25
+ */
26
+ ipAddress;
27
+ /**
28
+ * The user agent string of the client.
29
+ * @example 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
30
+ */
31
+ userAgent;
32
+ /**
33
+ * The session ID associated with the request, if any.
34
+ */
35
+ sessionId;
36
+ }
37
+ __decorate([
38
+ StringProperty(),
39
+ __metadata("design:type", Object)
40
+ ], RequestDetails.prototype, "path", void 0);
41
+ __decorate([
42
+ StringProperty({ nullable: true }),
43
+ __metadata("design:type", Object)
44
+ ], RequestDetails.prototype, "ipAddress", void 0);
45
+ __decorate([
46
+ StringProperty({ nullable: true }),
47
+ __metadata("design:type", Object)
48
+ ], RequestDetails.prototype, "userAgent", void 0);
49
+ __decorate([
50
+ UuidProperty({ nullable: true }),
51
+ __metadata("design:type", Object)
52
+ ], RequestDetails.prototype, "sessionId", void 0);
53
+ /**
54
+ * Represents the state of data before and after a change.
55
+ */
56
+ export class ChangeDetails {
57
+ /**
58
+ * The state of the data before the change occurred.
59
+ */
60
+ before;
61
+ /**
62
+ * The state of the data after the change occurred.
63
+ */
64
+ after;
65
+ }
66
+ __decorate([
67
+ JsonProperty({ nullable: true }),
68
+ __metadata("design:type", Object)
69
+ ], ChangeDetails.prototype, "before", void 0);
70
+ __decorate([
71
+ JsonProperty({ nullable: true }),
72
+ __metadata("design:type", Object)
73
+ ], ChangeDetails.prototype, "after", void 0);
74
+ /**
75
+ * Represents a single audit event record in the database.
76
+ * This entity captures who did what, when, and to what, along with other contextual information.
77
+ *
78
+ * @template Details The type of the `details` JSON object, allowing for custom, action-specific data.
79
+ */
13
80
  let AuditEvent = class AuditEvent extends EntityWithoutMetadata {
81
+ /**
82
+ * The timestamp when the event occurred.
83
+ */
14
84
  timestamp;
85
+ /**
86
+ * The ID of the tenant in which the event occurred. Can be null for system-level events.
87
+ */
88
+ tenantId;
89
+ /**
90
+ * A unique identifier to correlate multiple related audit events.
91
+ */
15
92
  correlationId;
93
+ /**
94
+ * The module or feature area where the event originated, in dot-separated format.
95
+ * @example 'user.authentication'
96
+ */
16
97
  module;
98
+ /**
99
+ * The specific action that was performed.
100
+ * @example 'login'
101
+ */
17
102
  action;
103
+ /**
104
+ * The outcome of the action.
105
+ */
18
106
  outcome;
107
+ /**
108
+ * The severity level of the event.
109
+ */
19
110
  severity;
20
- actorId;
111
+ /**
112
+ * The type of the actor.
113
+ */
21
114
  actorType;
22
- targetId;
115
+ /**
116
+ * The (if possible unique) identifier of the actor who performed the action.
117
+ */
118
+ actor;
119
+ /**
120
+ * The type of the impersonator, if applicable.
121
+ */
122
+ impersonatorType;
123
+ /**
124
+ * The (if possible unique) identifier of the user who is impersonating the actor, if applicable.
125
+ */
126
+ impersonator;
127
+ /**
128
+ * The type of the target entity.
129
+ * @example 'User'
130
+ */
23
131
  targetType;
132
+ /**
133
+ * The unique identifier of the primary resource or entity that was the target of the action.
134
+ */
135
+ targetId;
136
+ /**
137
+ * Network-related details for the request that triggered the event.
138
+ */
139
+ network;
140
+ /**
141
+ * Details about data changes.
142
+ */
143
+ changes;
144
+ /**
145
+ * A flexible JSON object for storing additional, action-specific details.
146
+ */
24
147
  details;
25
148
  };
26
149
  __decorate([
27
- Timestamp(),
150
+ TimestampProperty(),
28
151
  __metadata("design:type", Number)
29
152
  ], AuditEvent.prototype, "timestamp", void 0);
30
153
  __decorate([
31
- Uuid({ nullable: true }),
32
- __metadata("design:type", String)
154
+ UuidProperty({ nullable: true }),
155
+ __metadata("design:type", Object)
156
+ ], AuditEvent.prototype, "tenantId", void 0);
157
+ __decorate([
158
+ UuidProperty({ nullable: true }),
159
+ __metadata("design:type", Object)
33
160
  ], AuditEvent.prototype, "correlationId", void 0);
34
161
  __decorate([
35
162
  StringProperty(),
@@ -47,24 +174,40 @@ __decorate([
47
174
  Enumeration(AuditSeverity),
48
175
  __metadata("design:type", String)
49
176
  ], AuditEvent.prototype, "severity", void 0);
50
- __decorate([
51
- StringProperty(),
52
- __metadata("design:type", String)
53
- ], AuditEvent.prototype, "actorId", void 0);
54
177
  __decorate([
55
178
  Enumeration(ActorType),
56
179
  __metadata("design:type", String)
57
180
  ], AuditEvent.prototype, "actorType", void 0);
58
181
  __decorate([
59
182
  StringProperty(),
60
- __metadata("design:type", String)
61
- ], AuditEvent.prototype, "targetId", void 0);
183
+ __metadata("design:type", Object)
184
+ ], AuditEvent.prototype, "actor", void 0);
185
+ __decorate([
186
+ Enumeration(ActorType, { nullable: true }),
187
+ __metadata("design:type", Object)
188
+ ], AuditEvent.prototype, "impersonatorType", void 0);
189
+ __decorate([
190
+ StringProperty({ nullable: true }),
191
+ __metadata("design:type", Object)
192
+ ], AuditEvent.prototype, "impersonator", void 0);
62
193
  __decorate([
63
194
  StringProperty(),
64
195
  __metadata("design:type", String)
65
196
  ], AuditEvent.prototype, "targetType", void 0);
66
197
  __decorate([
67
- Json({ nullable: true }),
198
+ UuidProperty(),
199
+ __metadata("design:type", String)
200
+ ], AuditEvent.prototype, "targetId", void 0);
201
+ __decorate([
202
+ EmbeddedProperty(RequestDetails),
203
+ __metadata("design:type", Object)
204
+ ], AuditEvent.prototype, "network", void 0);
205
+ __decorate([
206
+ EmbeddedProperty(ChangeDetails),
207
+ __metadata("design:type", Object)
208
+ ], AuditEvent.prototype, "changes", void 0);
209
+ __decorate([
210
+ JsonProperty({ nullable: true }),
68
211
  __metadata("design:type", Object)
69
212
  ], AuditEvent.prototype, "details", void 0);
70
213
  AuditEvent = __decorate([
@@ -1,42 +1,127 @@
1
+ import type { IsEqual } from 'type-fest';
1
2
  import { type Resolvable, type resolveArgumentType } from '../injector/index.js';
2
- import type { UndefinableJsonObject } from '../types/index.js';
3
- import type { ActorType } from './types.js';
4
- import { AuditOutcome, AuditSeverity } from './types.js';
5
- export type AuditPayload = Partial<{
6
- correlationId?: string;
7
- outcome?: AuditOutcome;
8
- severity?: AuditSeverity;
9
- actorId?: string;
10
- actorType?: ActorType;
3
+ import type { TypedOmit, UndefinableJsonObject } from '../types/index.js';
4
+ import { AuditEvent } from './audit.model.js';
5
+ export type AuditPayload<Details extends UndefinableJsonObject = never> = Partial<TypedOmit<AuditEvent, 'id' | 'timestamp' | 'module' | 'action' | 'tenantId' | 'correlationId' | 'targetId' | 'network' | 'changes' | 'details'>> & {
6
+ tenantId?: string | null;
7
+ correlationId?: string | null;
11
8
  targetId?: string;
12
- targetType?: string;
9
+ network?: {
10
+ path?: string | null;
11
+ ipAddress?: string | null;
12
+ userAgent?: string | null;
13
+ sessionId?: string | null;
14
+ };
15
+ changes?: {
16
+ before?: unknown;
17
+ after?: unknown;
18
+ };
19
+ } & ([
20
+ Details
21
+ ] extends [never] ? {
13
22
  details?: UndefinableJsonObject;
14
- }>;
23
+ } : IsEqual<Details, {}> extends true ? {
24
+ details?: UndefinableJsonObject;
25
+ } : {
26
+ details: Details;
27
+ });
15
28
  export type AuditorArgument = string | string[] | {
29
+ /**
30
+ * The module or path of modules for the auditor.
31
+ */
16
32
  module?: string | string[];
33
+ /**
34
+ * Default context to apply to all events logged by this auditor instance.
35
+ */
17
36
  context?: Partial<AuditPayload>;
18
37
  };
19
- export declare class Auditor implements Resolvable<AuditorArgument> {
38
+ type AuditEvents = Record<string, UndefinableJsonObject>;
39
+ /**
40
+ * A service for logging audit events.
41
+ * It provides a structured way to record activities within the system.
42
+ * The Auditor can be forked to create sub-auditors for different modules or enriched with contextual data.
43
+ *
44
+ * @template Events A record mapping event action names to their specific `details` payload types.
45
+ */
46
+ export declare class Auditor<Events extends AuditEvents = Record<never, never>> implements Resolvable<AuditorArgument> {
20
47
  #private;
48
+ /**
49
+ * The module path for this auditor instance.
50
+ */
21
51
  readonly module: string[];
22
- readonly context: Partial<Partial<{
23
- correlationId?: string;
24
- outcome?: AuditOutcome;
25
- severity?: AuditSeverity;
26
- actorId?: string;
27
- actorType?: ActorType;
28
- targetId?: string;
29
- targetType?: string;
30
- details?: UndefinableJsonObject;
31
- }>>;
52
+ /**
53
+ * The context that is automatically merged into every event logged by this auditor.
54
+ */
55
+ readonly context: Partial<AuditPayload<never>>;
56
+ /**
57
+ * A dot-separated string representation of the module path.
58
+ * @example ['user', 'authentication'] becomes 'user.authentication'
59
+ */
32
60
  get moduleString(): string;
33
61
  readonly [resolveArgumentType]: AuditorArgument;
34
- fork(subModule: string | string[]): Auditor;
35
- with(context: Partial<AuditPayload>): Auditor;
36
- withCorrelation(): Auditor;
37
- log(action: string, data?: AuditPayload): Promise<void>;
38
- info(action: string, data: AuditPayload): Promise<void>;
39
- warn(action: string, data: AuditPayload): Promise<void>;
40
- error(action: string, data: AuditPayload): Promise<void>;
41
- critical(action: string, data: AuditPayload): Promise<void>;
62
+ /**
63
+ * Creates a new `Auditor` instance for a submodule.
64
+ * The new auditor inherits the context of its parent and appends the submodule to its module path.
65
+ *
66
+ * @param subModule The name of the submodule or a path of submodules.
67
+ * @returns A new `Auditor` instance for the specified submodule.
68
+ * @template T The event map of the new Auditor instance.
69
+ */
70
+ fork<T extends AuditEvents = Record<string, never>>(subModule: string | string[]): Auditor<T>;
71
+ /**
72
+ * Creates a new `Auditor` instance with additional context.
73
+ * The new context is merged with the existing context.
74
+ *
75
+ * @param context The additional context to apply.
76
+ * @returns A new `Auditor` instance with the merged context.
77
+ * @template T The event map of the new Auditor instance.
78
+ */
79
+ with<T extends AuditEvents = Events>(context: Partial<AuditPayload>): Auditor<T>;
80
+ /**
81
+ * Creates a new `Auditor` instance with a correlation ID in its context.
82
+ * If a correlation ID already exists in the context, it is preserved. Otherwise, a new UUID is generated.
83
+ *
84
+ * @returns A new `Auditor` instance with a correlation ID.
85
+ */
86
+ withCorrelation(): Auditor<Events>;
87
+ /**
88
+ * Logs a generic audit event.
89
+ *
90
+ * @param action The name of the action being logged. Must be a key of the `Events` type.
91
+ * @param data The payload containing details about the event.
92
+ */
93
+ log<const E extends Extract<keyof Events, string>>(action: E, data?: AuditPayload<Events[E]>): Promise<void>;
94
+ /**
95
+ * Logs an informational event.
96
+ * Automatically sets severity to `Info` and defaults outcome to `Success`.
97
+ *
98
+ * @param action The name of the action being logged.
99
+ * @param data The payload containing details about the event.
100
+ */
101
+ info<const E extends Extract<keyof Events, string>>(action: E, data: AuditPayload<Events[E]>): Promise<void>;
102
+ /**
103
+ * Logs a warning event.
104
+ * Automatically sets severity to `Warn` and defaults outcome to `Failure`.
105
+ *
106
+ * @param action The name of the action being logged.
107
+ * @param data The payload containing details about the event.
108
+ */
109
+ warn<const E extends Extract<keyof Events, string>>(action: E, data: AuditPayload<Events[E]>): Promise<void>;
110
+ /**
111
+ * Logs an error event.
112
+ * Automatically sets severity to `Error` and defaults outcome to `Failure`.
113
+ *
114
+ * @param action The name of the action being logged.
115
+ * @param data The payload containing details about the event.
116
+ */
117
+ error<const E extends Extract<keyof Events, string>>(action: E, data: AuditPayload<Events[E]>): Promise<void>;
118
+ /**
119
+ * Logs a critical event.
120
+ * Automatically sets severity to `Critical` and defaults outcome to `Failure`.
121
+ *
122
+ * @param action The name of the action being logged.
123
+ * @param data The payload containing details about the event.
124
+ */
125
+ critical<const E extends Extract<keyof Events, string>>(action: E, data: AuditPayload<Events[E]>): Promise<void>;
42
126
  }
127
+ export {};
package/audit/auditor.js CHANGED
@@ -9,56 +9,171 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  var Auditor_1;
11
11
  import { createContextProvider } from '../context/index.js';
12
- import { Injectable, injectArgument } from '../injector/index.js';
13
- import { injectRepository } from '../orm/server/index.js';
14
- import { TRANSACTION_TIMESTAMP } from '../orm/sqls.js';
12
+ import { inject, Injectable, injectArgument, provide } from '../injector/index.js';
13
+ import { Logger, LogLevel } from '../logger/index.js';
14
+ import { TRANSACTION_TIMESTAMP } from '../orm/index.js';
15
+ import { DatabaseConfig, EntityRepositoryConfig, injectRepository, isInTransactionalContext } from '../orm/server/index.js';
15
16
  import { toArray } from '../utils/array/index.js';
16
17
  import { Memoize } from '../utils/function/memoize.js';
17
- import { filterUndefinedFromRecord, objectKeys } from '../utils/object/object.js';
18
+ import { filterNullishFromRecord, filterUndefinedFromRecord, objectKeys } from '../utils/object/object.js';
18
19
  import { assertDefinedPass, isArray, isNotArray, isObject, isString } from '../utils/type-guards.js';
19
20
  import { AuditEvent } from './audit.model.js';
21
+ import { AuditModuleConfig } from './module.js';
20
22
  import { AuditOutcome, AuditSeverity } from './types.js';
21
23
  const { runInAuditorCreationContext, getCurrentAuditorCreationContext, isInAuditorCreationContext } = createContextProvider('AuditorCreation');
24
+ const severityLogLevelMap = {
25
+ [AuditSeverity.Info]: 'info',
26
+ [AuditSeverity.Warn]: 'warn',
27
+ [AuditSeverity.Error]: 'error',
28
+ [AuditSeverity.Critical]: 'error',
29
+ };
30
+ /**
31
+ * A service for logging audit events.
32
+ * It provides a structured way to record activities within the system.
33
+ * The Auditor can be forked to create sub-auditors for different modules or enriched with contextual data.
34
+ *
35
+ * @template Events A record mapping event action names to their specific `details` payload types.
36
+ */
22
37
  let Auditor = Auditor_1 = class Auditor {
23
- #repository = injectRepository(AuditEvent);
24
- #argument = isInAuditorCreationContext() ? injectArgument(this, { optional: true }) : undefined;
25
- #creationContext = getCurrentAuditorCreationContext();
26
- module = this.#creationContext?.module ?? moduleFromArgument(this.#argument);
27
- context = this.#creationContext?.context ?? ((isObject(this.#argument) && isNotArray(this.#argument)) ? (this.#argument.context ?? {}) : {});
38
+ #repository = getCurrentAuditorCreationContext()?.repository ?? injectRepository(AuditEvent);
39
+ #logger = getCurrentAuditorCreationContext()?.logger ?? inject(Logger, 'Audit');
40
+ #argument = (isInAuditorCreationContext() || isInTransactionalContext()) ? undefined : injectArgument(this, { optional: true });
41
+ /**
42
+ * The module path for this auditor instance.
43
+ */
44
+ module = getCurrentAuditorCreationContext()?.module ?? moduleFromArgument(this.#argument);
45
+ /**
46
+ * The context that is automatically merged into every event logged by this auditor.
47
+ */
48
+ context = getCurrentAuditorCreationContext()?.context ?? ((isObject(this.#argument) && isNotArray(this.#argument)) ? (this.#argument.context ?? {}) : {});
49
+ /**
50
+ * A dot-separated string representation of the module path.
51
+ * @example ['user', 'authentication'] becomes 'user.authentication'
52
+ */
28
53
  get moduleString() {
29
54
  return this.module.join('.');
30
55
  }
56
+ /**
57
+ * Creates a new `Auditor` instance for a submodule.
58
+ * The new auditor inherits the context of its parent and appends the submodule to its module path.
59
+ *
60
+ * @param subModule The name of the submodule or a path of submodules.
61
+ * @returns A new `Auditor` instance for the specified submodule.
62
+ * @template T The event map of the new Auditor instance.
63
+ */
31
64
  fork(subModule) {
32
65
  return runInAuditorCreationContext({
66
+ repository: this.#repository,
33
67
  module: [...this.module, ...toArray(subModule)],
34
68
  context: this.context,
69
+ logger: this.#logger,
35
70
  }, () => new Auditor_1());
36
71
  }
72
+ /**
73
+ * Creates a new `Auditor` instance with additional context.
74
+ * The new context is merged with the existing context.
75
+ *
76
+ * @param context The additional context to apply.
77
+ * @returns A new `Auditor` instance with the merged context.
78
+ * @template T The event map of the new Auditor instance.
79
+ */
37
80
  with(context) {
38
81
  return runInAuditorCreationContext({
82
+ repository: this.#repository,
39
83
  module: this.module,
40
- context: { ...this.context, ...context, details: { ...this.context.details, ...context.details } },
84
+ context: {
85
+ ...this.context,
86
+ ...context,
87
+ network: { ...this.context.network, ...context.network },
88
+ changes: { ...this.context.changes, ...context.changes },
89
+ details: { ...this.context.details, ...context.details },
90
+ },
91
+ logger: this.#logger,
41
92
  }, () => new Auditor_1());
42
93
  }
94
+ /**
95
+ * Creates a new `Auditor` instance with a correlation ID in its context.
96
+ * If a correlation ID already exists in the context, it is preserved. Otherwise, a new UUID is generated.
97
+ *
98
+ * @returns A new `Auditor` instance with a correlation ID.
99
+ */
43
100
  withCorrelation() {
44
101
  return this.with({ correlationId: this.context.correlationId ?? crypto.randomUUID() });
45
102
  }
103
+ /**
104
+ * Logs a generic audit event.
105
+ *
106
+ * @param action The name of the action being logged. Must be a key of the `Events` type.
107
+ * @param data The payload containing details about the event.
108
+ */
46
109
  async log(action, data) {
47
- const mergedData = { ...this.context, ...data, details: filterUndefinedFromRecord({ ...this.context.details, ...data?.details }) };
110
+ const mergedData = {
111
+ ...this.context,
112
+ ...data,
113
+ network: { ...this.context.network, ...data?.network },
114
+ changes: { ...this.context.changes, ...data?.changes },
115
+ details: filterUndefinedFromRecord({ ...this.context.details, ...data?.details }),
116
+ };
117
+ const outcome = assertDefinedPass(mergedData.outcome, 'Audit outcome is required');
118
+ const severity = assertDefinedPass(mergedData.severity, 'Audit severity is required');
119
+ const logMessage = `<${this.moduleString}> ${action} - ${outcome}`;
120
+ const details = (objectKeys(mergedData.details).length > 0) ? mergedData.details : undefined;
121
+ const network = filterNullishFromRecord({
122
+ ipAddress: mergedData.network.ipAddress,
123
+ userAgent: mergedData.network.userAgent,
124
+ sessionId: mergedData.network.sessionId,
125
+ });
126
+ const changes = filterUndefinedFromRecord({
127
+ before: mergedData.changes.before,
128
+ after: mergedData.changes.after,
129
+ });
130
+ const logContext = filterNullishFromRecord({
131
+ correlationId: mergedData.correlationId,
132
+ actorType: mergedData.actorType,
133
+ actor: mergedData.actor,
134
+ targetType: mergedData.targetType,
135
+ targetId: mergedData.targetId,
136
+ impersonatorType: mergedData.impersonatorType,
137
+ impersonator: mergedData.impersonator,
138
+ network: (objectKeys(network).length > 0) ? network : undefined,
139
+ changes: (objectKeys(changes).length > 0) ? changes : undefined,
140
+ details,
141
+ });
142
+ this.#logger[severityLogLevelMap[severity]](logMessage, logContext);
48
143
  await this.#repository.insert({
49
144
  timestamp: TRANSACTION_TIMESTAMP,
50
- correlationId: mergedData.correlationId,
145
+ tenantId: mergedData.tenantId ?? null,
146
+ correlationId: mergedData.correlationId ?? null,
51
147
  module: this.moduleString,
52
- action: action,
53
- outcome: assertDefinedPass(mergedData.outcome, 'Audit outcome is required'),
54
- severity: assertDefinedPass(mergedData.severity, 'Audit severity is required'),
55
- actorId: assertDefinedPass(mergedData.actorId, 'Audit actorId is required'),
148
+ action,
149
+ outcome,
150
+ severity,
56
151
  actorType: assertDefinedPass(mergedData.actorType, 'Audit actorType is required'),
57
- targetId: assertDefinedPass(mergedData.targetId, 'Audit targetId is required'),
152
+ actor: assertDefinedPass(mergedData.actor, 'Audit actor is required'),
153
+ impersonatorType: mergedData.impersonatorType ?? null,
154
+ impersonator: mergedData.impersonator ?? null,
58
155
  targetType: assertDefinedPass(mergedData.targetType, 'Audit targetType is required'),
59
- details: (objectKeys(mergedData.details).length > 0) ? mergedData.details : undefined,
156
+ targetId: assertDefinedPass(mergedData.targetId, 'Audit targetId is required'),
157
+ network: {
158
+ path: mergedData.network.path ?? null,
159
+ ipAddress: mergedData.network.ipAddress ?? null,
160
+ userAgent: mergedData.network.userAgent ?? null,
161
+ sessionId: mergedData.network.sessionId ?? null,
162
+ },
163
+ changes: {
164
+ before: mergedData.changes.before ?? null,
165
+ after: mergedData.changes.after ?? null,
166
+ },
167
+ details: details ?? null,
60
168
  });
61
169
  }
170
+ /**
171
+ * Logs an informational event.
172
+ * Automatically sets severity to `Info` and defaults outcome to `Success`.
173
+ *
174
+ * @param action The name of the action being logged.
175
+ * @param data The payload containing details about the event.
176
+ */
62
177
  async info(action, data) {
63
178
  await this.log(action, {
64
179
  ...data,
@@ -66,6 +181,13 @@ let Auditor = Auditor_1 = class Auditor {
66
181
  outcome: data.outcome ?? AuditOutcome.Success,
67
182
  });
68
183
  }
184
+ /**
185
+ * Logs a warning event.
186
+ * Automatically sets severity to `Warn` and defaults outcome to `Failure`.
187
+ *
188
+ * @param action The name of the action being logged.
189
+ * @param data The payload containing details about the event.
190
+ */
69
191
  async warn(action, data) {
70
192
  await this.log(action, {
71
193
  ...data,
@@ -73,6 +195,13 @@ let Auditor = Auditor_1 = class Auditor {
73
195
  outcome: data.outcome ?? AuditOutcome.Failure,
74
196
  });
75
197
  }
198
+ /**
199
+ * Logs an error event.
200
+ * Automatically sets severity to `Error` and defaults outcome to `Failure`.
201
+ *
202
+ * @param action The name of the action being logged.
203
+ * @param data The payload containing details about the event.
204
+ */
76
205
  async error(action, data) {
77
206
  await this.log(action, {
78
207
  ...data,
@@ -80,6 +209,13 @@ let Auditor = Auditor_1 = class Auditor {
80
209
  outcome: data.outcome ?? AuditOutcome.Failure,
81
210
  });
82
211
  }
212
+ /**
213
+ * Logs a critical event.
214
+ * Automatically sets severity to `Critical` and defaults outcome to `Failure`.
215
+ *
216
+ * @param action The name of the action being logged.
217
+ * @param data The payload containing details about the event.
218
+ */
83
219
  async critical(action, data) {
84
220
  await this.log(action, {
85
221
  ...data,
@@ -94,7 +230,12 @@ __decorate([
94
230
  __metadata("design:paramtypes", [])
95
231
  ], Auditor.prototype, "moduleString", null);
96
232
  Auditor = Auditor_1 = __decorate([
97
- Injectable()
233
+ Injectable({
234
+ providers: [
235
+ provide(EntityRepositoryConfig, { useValue: { schema: 'audit' } }),
236
+ { provide: DatabaseConfig, useFactory: (_, context) => context.resolve(AuditModuleConfig).database ?? context.resolve(DatabaseConfig, undefined, { skipSelf: true }) },
237
+ ],
238
+ })
98
239
  ], Auditor);
99
240
  export { Auditor };
100
241
  function moduleFromArgument(argument) {
@@ -0,0 +1,26 @@
1
+ CREATE TYPE "audit"."actor_type" AS ENUM('anonymous', 'system', 'api-key', 'user');--> statement-breakpoint
2
+ CREATE TYPE "audit"."audit_outcome" AS ENUM('pending', 'success', 'cancelled', 'failure', 'denied');--> statement-breakpoint
3
+ CREATE TYPE "audit"."audit_severity" AS ENUM('info', 'warn', 'error', 'critical');--> statement-breakpoint
4
+ CREATE TABLE "audit"."event" (
5
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
6
+ "timestamp" timestamp with time zone NOT NULL,
7
+ "tenant_id" uuid,
8
+ "correlation_id" uuid,
9
+ "module" text NOT NULL,
10
+ "action" text NOT NULL,
11
+ "outcome" "audit"."audit_outcome" NOT NULL,
12
+ "severity" "audit"."audit_severity" NOT NULL,
13
+ "actor_type" "audit"."actor_type" NOT NULL,
14
+ "actor" text NOT NULL,
15
+ "impersonator_type" "audit"."actor_type",
16
+ "impersonator" text,
17
+ "target_type" text NOT NULL,
18
+ "target_id" uuid NOT NULL,
19
+ "network_path" text NOT NULL,
20
+ "network_ip_address" text,
21
+ "network_user_agent" text,
22
+ "network_session_id" uuid,
23
+ "changes_before" jsonb,
24
+ "changes_after" jsonb,
25
+ "details" jsonb
26
+ );