@maykonpaulo/maestro-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # @maykonpaulo/maestro-core
2
+
3
+ Pacote central da plataforma Maestro. Fornece capacidades administrativas genéricas e reutilizáveis para sistemas internos.
4
+
5
+ ## Módulos disponíveis
6
+
7
+ | Módulo | Classes / Interfaces principais |
8
+ |-----------------|----------------------------------------------------------------------|
9
+ | `audit` | `AuditRecorder`, `InMemoryAuditRepository`, `AuditRepository` |
10
+ | `rbac` | `RbacEngine`, `RbacPolicy`, `Role` |
11
+ | `logging` | `ConsoleLogger`, `Logger` |
12
+ | `feature-flags` | `InMemoryFeatureFlagProvider`, `FeatureFlagProvider` |
13
+ | `config` | `InMemoryConfigProvider`, `ConfigProvider` |
14
+ | `events` | `InMemoryEventBus`, `EventBus`, `DomainEvent` |
15
+ | `errors` | `MaestroError`, `ErrorCode` |
16
+ | `types` | `Actor`, `ResourceRef`, `Metadata` |
17
+
18
+ ## Instalação
19
+
20
+ ```bash
21
+ pnpm add @maykonpaulo/maestro-core
22
+ ```
23
+
24
+ ## Uso básico
25
+
26
+ ```typescript
27
+ import {
28
+ AuditRecorder,
29
+ InMemoryAuditRepository,
30
+ RbacEngine,
31
+ ConsoleLogger,
32
+ InMemoryFeatureFlagProvider,
33
+ InMemoryConfigProvider,
34
+ InMemoryEventBus,
35
+ } from '@maykonpaulo/maestro-core';
36
+ import type { Actor, RbacPolicy } from '@maykonpaulo/maestro-core';
37
+
38
+ // Actor
39
+ const actor: Actor = { id: 'user-1', type: 'user', roles: ['editor'] };
40
+
41
+ // Auditoria
42
+ const audit = new AuditRecorder(new InMemoryAuditRepository());
43
+ await audit.record({ action: 'contract.updated', actor });
44
+
45
+ // RBAC
46
+ const policy: RbacPolicy = {
47
+ roles: {
48
+ editor: { id: 'editor', name: 'editor', permissions: ['contracts.*'] },
49
+ },
50
+ };
51
+ const rbac = new RbacEngine(policy);
52
+ rbac.can(actor, 'contracts.update'); // true
53
+
54
+ // Logging
55
+ const logger = new ConsoleLogger('info');
56
+ logger.info({ message: 'Operação concluída', correlationId: 'req-123' });
57
+
58
+ // Feature flags
59
+ const flags = new InMemoryFeatureFlagProvider([{ key: 'new-ui', enabled: true }]);
60
+ await flags.isEnabled('new-ui', actor); // true
61
+
62
+ // Config
63
+ const config = new InMemoryConfigProvider({ 'app.name': 'meu-sistema' });
64
+ config.get('app.name'); // 'meu-sistema'
65
+
66
+ // Eventos
67
+ const bus = new InMemoryEventBus();
68
+ bus.subscribe('contract.updated', (event) => console.log(event));
69
+ await bus.publish({ id: 'evt-1', type: 'contract.updated', payload: {}, occurredAt: new Date() });
70
+ ```
71
+
72
+ ## API pública
73
+
74
+ Todas as exportações estão documentadas em `src/index.ts`. Importe apenas pelo nome do pacote:
75
+
76
+ ```typescript
77
+ import { ... } from '@maykonpaulo/maestro-core';
78
+ ```
79
+
80
+ ## Limitações da Fase 1
81
+
82
+ - **Sem persistência real** — todas as implementações são in-memory. Dados são perdidos ao reiniciar o processo.
83
+ - **Sem provider remoto de feature flags** — `InMemoryFeatureFlagProvider` não suporta avaliação por actor com regras complexas.
84
+ - **Sem adapter de logging externo** — `ConsoleLogger` escreve em `console.*`. Para produção, implementar um adapter que envie para seu stack de observabilidade.
85
+ - **Sem autenticação** — o `RbacEngine` avalia autorização com base no `Actor` recebido. Autenticação é responsabilidade do consumer.
86
+
87
+ As interfaces (`AuditRepository`, `FeatureFlagProvider`, `ConfigProvider`, `EventBus`, `Logger`) foram projetadas para serem substituídas por implementações concretas em produção.
@@ -0,0 +1,209 @@
1
+ type MetadataValue = string | number | boolean | null | MetadataValue[] | {
2
+ [key: string]: MetadataValue;
3
+ };
4
+ type Metadata = Record<string, MetadataValue>;
5
+
6
+ type ActorType = 'user' | 'system' | 'job' | 'integration' | 'ai-agent';
7
+ interface Actor {
8
+ id: string;
9
+ type: ActorType;
10
+ name?: string;
11
+ email?: string;
12
+ roles?: string[];
13
+ permissions?: string[];
14
+ metadata?: Metadata;
15
+ }
16
+
17
+ interface ResourceRef {
18
+ type: string;
19
+ id: string;
20
+ label?: string;
21
+ metadata?: Metadata;
22
+ }
23
+
24
+ declare enum ErrorCode {
25
+ VALIDATION_ERROR = "VALIDATION_ERROR",
26
+ PERMISSION_DENIED = "PERMISSION_DENIED",
27
+ NOT_FOUND = "NOT_FOUND",
28
+ CONFLICT = "CONFLICT",
29
+ INTERNAL_ERROR = "INTERNAL_ERROR",
30
+ CONFIGURATION_ERROR = "CONFIGURATION_ERROR"
31
+ }
32
+
33
+ declare class MaestroError extends Error {
34
+ readonly code: ErrorCode;
35
+ readonly details?: Metadata;
36
+ readonly cause?: unknown;
37
+ constructor(code: ErrorCode, message: string, options?: {
38
+ details?: Metadata;
39
+ cause?: unknown;
40
+ });
41
+ }
42
+
43
+ interface LogEntry {
44
+ message: string;
45
+ metadata?: Metadata;
46
+ error?: unknown;
47
+ correlationId?: string;
48
+ }
49
+ interface Logger {
50
+ debug(entry: LogEntry): void;
51
+ info(entry: LogEntry): void;
52
+ warn(entry: LogEntry): void;
53
+ error(entry: LogEntry): void;
54
+ }
55
+
56
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
57
+
58
+ declare class ConsoleLogger implements Logger {
59
+ private readonly minLevel;
60
+ constructor(minLevel?: LogLevel);
61
+ debug(entry: LogEntry): void;
62
+ info(entry: LogEntry): void;
63
+ warn(entry: LogEntry): void;
64
+ error(entry: LogEntry): void;
65
+ private log;
66
+ private serializeError;
67
+ }
68
+
69
+ type AuditLevel = 'debug' | 'info' | 'warn' | 'error' | 'critical';
70
+
71
+ interface AuditEvent {
72
+ id: string;
73
+ timestamp: Date;
74
+ action: string;
75
+ actor: Actor;
76
+ resource?: ResourceRef;
77
+ level: AuditLevel;
78
+ before?: Metadata;
79
+ after?: Metadata;
80
+ metadata?: Metadata;
81
+ correlationId?: string;
82
+ requestId?: string;
83
+ ip?: string;
84
+ userAgent?: string;
85
+ }
86
+
87
+ interface AuditFilter {
88
+ actorId?: string;
89
+ action?: string;
90
+ resourceType?: string;
91
+ resourceId?: string;
92
+ level?: AuditLevel;
93
+ from?: Date;
94
+ to?: Date;
95
+ correlationId?: string;
96
+ }
97
+ interface AuditRepository {
98
+ record(event: AuditEvent): Promise<void>;
99
+ list(filter?: AuditFilter): Promise<AuditEvent[]>;
100
+ }
101
+
102
+ interface RecordAuditInput {
103
+ action: string;
104
+ actor: Actor;
105
+ level?: AuditLevel;
106
+ resource?: ResourceRef;
107
+ before?: Metadata;
108
+ after?: Metadata;
109
+ metadata?: Metadata;
110
+ correlationId?: string;
111
+ requestId?: string;
112
+ ip?: string;
113
+ userAgent?: string;
114
+ }
115
+ declare class AuditRecorder {
116
+ private readonly repository;
117
+ constructor(repository: AuditRepository);
118
+ record(input: RecordAuditInput): Promise<AuditEvent>;
119
+ }
120
+
121
+ declare class InMemoryAuditRepository implements AuditRepository {
122
+ private readonly store;
123
+ record(event: AuditEvent): Promise<void>;
124
+ list(filter?: AuditFilter): Promise<AuditEvent[]>;
125
+ }
126
+
127
+ type Permission = string;
128
+
129
+ interface Role {
130
+ id: string;
131
+ name: string;
132
+ permissions: Permission[];
133
+ }
134
+
135
+ interface RbacPolicy {
136
+ roles: Record<string, Role>;
137
+ }
138
+
139
+ declare class RbacEngine {
140
+ private readonly policy;
141
+ constructor(policy: RbacPolicy);
142
+ can(actor: Actor, permission: string): boolean;
143
+ private resolvePermissions;
144
+ private matchesPattern;
145
+ }
146
+
147
+ interface FeatureFlag {
148
+ key: string;
149
+ enabled: boolean;
150
+ description?: string;
151
+ metadata?: Metadata;
152
+ }
153
+
154
+ interface FeatureFlagProvider {
155
+ isEnabled(key: string, actor?: Actor): Promise<boolean>;
156
+ get(key: string): FeatureFlag | undefined;
157
+ set(flag: FeatureFlag): void;
158
+ list(): FeatureFlag[];
159
+ }
160
+
161
+ declare class InMemoryFeatureFlagProvider implements FeatureFlagProvider {
162
+ private readonly flags;
163
+ constructor(flags?: FeatureFlag[]);
164
+ isEnabled(key: string, _actor?: Actor): Promise<boolean>;
165
+ get(key: string): FeatureFlag | undefined;
166
+ set(flag: FeatureFlag): void;
167
+ list(): FeatureFlag[];
168
+ }
169
+
170
+ interface ConfigProvider {
171
+ get<T extends MetadataValue>(key: string): T | undefined;
172
+ set<T extends MetadataValue>(key: string, value: T): void;
173
+ has(key: string): boolean;
174
+ getOrDefault<T extends MetadataValue>(key: string, defaultValue: T): T;
175
+ }
176
+
177
+ declare class InMemoryConfigProvider implements ConfigProvider {
178
+ private readonly store;
179
+ constructor(initial?: Record<string, MetadataValue>);
180
+ get<T extends MetadataValue>(key: string): T | undefined;
181
+ set<T extends MetadataValue>(key: string, value: T): void;
182
+ has(key: string): boolean;
183
+ getOrDefault<T extends MetadataValue>(key: string, defaultValue: T): T;
184
+ }
185
+
186
+ interface DomainEvent<TPayload = Metadata> {
187
+ id: string;
188
+ type: string;
189
+ occurredAt: Date;
190
+ payload?: TPayload;
191
+ metadata?: Metadata;
192
+ correlationId?: string;
193
+ }
194
+
195
+ type EventHandler<TPayload = unknown> = (event: DomainEvent<TPayload>) => void | Promise<void>;
196
+ interface EventBus {
197
+ publish<TPayload>(event: DomainEvent<TPayload>): Promise<void>;
198
+ subscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void;
199
+ unsubscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void;
200
+ }
201
+
202
+ declare class InMemoryEventBus implements EventBus {
203
+ private readonly handlers;
204
+ publish<TPayload>(event: DomainEvent<TPayload>): Promise<void>;
205
+ subscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void;
206
+ unsubscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void;
207
+ }
208
+
209
+ export { type Actor, type ActorType, type AuditEvent, type AuditFilter, type AuditLevel, AuditRecorder, type AuditRepository, type ConfigProvider, ConsoleLogger, type DomainEvent, ErrorCode, type EventBus, type EventHandler, type FeatureFlag, type FeatureFlagProvider, InMemoryAuditRepository, InMemoryConfigProvider, InMemoryEventBus, InMemoryFeatureFlagProvider, type LogEntry, type LogLevel, type Logger, MaestroError, type Metadata, type MetadataValue, type Permission, RbacEngine, type RbacPolicy, type RecordAuditInput, type ResourceRef, type Role };
package/dist/index.js ADDED
@@ -0,0 +1,245 @@
1
+ // src/errors/ErrorCode.ts
2
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
3
+ ErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
4
+ ErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED";
5
+ ErrorCode2["NOT_FOUND"] = "NOT_FOUND";
6
+ ErrorCode2["CONFLICT"] = "CONFLICT";
7
+ ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
8
+ ErrorCode2["CONFIGURATION_ERROR"] = "CONFIGURATION_ERROR";
9
+ return ErrorCode2;
10
+ })(ErrorCode || {});
11
+
12
+ // src/errors/MaestroError.ts
13
+ var MaestroError = class extends Error {
14
+ code;
15
+ details;
16
+ cause;
17
+ constructor(code, message, options) {
18
+ super(message, { cause: options?.cause });
19
+ this.code = code;
20
+ this.details = options?.details;
21
+ this.cause = options?.cause;
22
+ this.name = "MaestroError";
23
+ }
24
+ };
25
+
26
+ // src/logging/LogLevel.ts
27
+ var LOG_LEVEL_PRIORITY = {
28
+ debug: 0,
29
+ info: 1,
30
+ warn: 2,
31
+ error: 3
32
+ };
33
+
34
+ // src/logging/ConsoleLogger.ts
35
+ var ConsoleLogger = class {
36
+ constructor(minLevel = "info") {
37
+ this.minLevel = minLevel;
38
+ }
39
+ minLevel;
40
+ debug(entry) {
41
+ this.log("debug", entry);
42
+ }
43
+ info(entry) {
44
+ this.log("info", entry);
45
+ }
46
+ warn(entry) {
47
+ this.log("warn", entry);
48
+ }
49
+ error(entry) {
50
+ this.log("error", entry);
51
+ }
52
+ log(level, entry) {
53
+ if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.minLevel]) return;
54
+ const output = {
55
+ level,
56
+ message: entry.message,
57
+ ...entry.correlationId && { correlationId: entry.correlationId },
58
+ ...entry.metadata && { metadata: entry.metadata },
59
+ ...entry.error !== void 0 && { error: this.serializeError(entry.error) }
60
+ };
61
+ const consoleFn = level === "error" ? console.error : level === "warn" ? console.warn : level === "debug" ? console.debug : console.info;
62
+ consoleFn(JSON.stringify(output));
63
+ }
64
+ serializeError(error) {
65
+ if (error instanceof Error) {
66
+ return { name: error.name, message: error.message };
67
+ }
68
+ return error;
69
+ }
70
+ };
71
+
72
+ // src/audit/InMemoryAuditRepository.ts
73
+ var InMemoryAuditRepository = class {
74
+ store = /* @__PURE__ */ new Map();
75
+ async record(event) {
76
+ this.store.set(event.id, event);
77
+ }
78
+ async list(filter) {
79
+ let events = Array.from(this.store.values());
80
+ if (!filter) return events;
81
+ if (filter.actorId !== void 0) {
82
+ events = events.filter((e) => e.actor.id === filter.actorId);
83
+ }
84
+ if (filter.action !== void 0) {
85
+ events = events.filter((e) => e.action === filter.action);
86
+ }
87
+ if (filter.resourceType !== void 0) {
88
+ events = events.filter((e) => e.resource?.type === filter.resourceType);
89
+ }
90
+ if (filter.resourceId !== void 0) {
91
+ events = events.filter((e) => e.resource?.id === filter.resourceId);
92
+ }
93
+ if (filter.level !== void 0) {
94
+ events = events.filter((e) => e.level === filter.level);
95
+ }
96
+ if (filter.from !== void 0) {
97
+ const from = filter.from;
98
+ events = events.filter((e) => e.timestamp >= from);
99
+ }
100
+ if (filter.to !== void 0) {
101
+ const to = filter.to;
102
+ events = events.filter((e) => e.timestamp <= to);
103
+ }
104
+ if (filter.correlationId !== void 0) {
105
+ events = events.filter((e) => e.correlationId === filter.correlationId);
106
+ }
107
+ return events;
108
+ }
109
+ };
110
+
111
+ // src/audit/AuditRecorder.ts
112
+ import { randomUUID } from "crypto";
113
+ var AuditRecorder = class {
114
+ constructor(repository) {
115
+ this.repository = repository;
116
+ }
117
+ repository;
118
+ async record(input) {
119
+ const event = {
120
+ id: randomUUID(),
121
+ timestamp: /* @__PURE__ */ new Date(),
122
+ action: input.action,
123
+ actor: input.actor,
124
+ level: input.level ?? "info",
125
+ resource: input.resource,
126
+ before: input.before,
127
+ after: input.after,
128
+ metadata: input.metadata,
129
+ correlationId: input.correlationId,
130
+ requestId: input.requestId,
131
+ ip: input.ip,
132
+ userAgent: input.userAgent
133
+ };
134
+ await this.repository.record(event);
135
+ return event;
136
+ }
137
+ };
138
+
139
+ // src/rbac/RbacEngine.ts
140
+ var RbacEngine = class {
141
+ constructor(policy) {
142
+ this.policy = policy;
143
+ }
144
+ policy;
145
+ can(actor, permission) {
146
+ const permissions = this.resolvePermissions(actor);
147
+ return permissions.some((p) => this.matchesPattern(p, permission));
148
+ }
149
+ resolvePermissions(actor) {
150
+ const direct = actor.permissions ?? [];
151
+ const fromRoles = (actor.roles ?? []).flatMap((roleName) => {
152
+ const role = this.policy.roles[roleName];
153
+ return role?.permissions ?? [];
154
+ });
155
+ return [...direct, ...fromRoles];
156
+ }
157
+ matchesPattern(pattern, target) {
158
+ if (pattern === "*") return true;
159
+ if (pattern === target) return true;
160
+ if (pattern.endsWith(".*")) {
161
+ const prefix = pattern.slice(0, -2);
162
+ return target === prefix || target.startsWith(`${prefix}.`);
163
+ }
164
+ return false;
165
+ }
166
+ };
167
+
168
+ // src/feature-flags/InMemoryFeatureFlagProvider.ts
169
+ var InMemoryFeatureFlagProvider = class {
170
+ flags = /* @__PURE__ */ new Map();
171
+ constructor(flags = []) {
172
+ for (const flag of flags) {
173
+ this.flags.set(flag.key, flag);
174
+ }
175
+ }
176
+ async isEnabled(key, _actor) {
177
+ return this.flags.get(key)?.enabled ?? false;
178
+ }
179
+ get(key) {
180
+ return this.flags.get(key);
181
+ }
182
+ set(flag) {
183
+ this.flags.set(flag.key, flag);
184
+ }
185
+ list() {
186
+ return Array.from(this.flags.values());
187
+ }
188
+ };
189
+
190
+ // src/config/InMemoryConfigProvider.ts
191
+ var InMemoryConfigProvider = class {
192
+ store = /* @__PURE__ */ new Map();
193
+ constructor(initial = {}) {
194
+ for (const [key, value] of Object.entries(initial)) {
195
+ this.store.set(key, value);
196
+ }
197
+ }
198
+ get(key) {
199
+ return this.store.get(key);
200
+ }
201
+ set(key, value) {
202
+ this.store.set(key, value);
203
+ }
204
+ has(key) {
205
+ return this.store.has(key);
206
+ }
207
+ getOrDefault(key, defaultValue) {
208
+ const value = this.store.get(key);
209
+ return value !== void 0 ? value : defaultValue;
210
+ }
211
+ };
212
+
213
+ // src/events/InMemoryEventBus.ts
214
+ var InMemoryEventBus = class {
215
+ handlers = /* @__PURE__ */ new Map();
216
+ async publish(event) {
217
+ const set = this.handlers.get(event.type);
218
+ if (!set) return;
219
+ const promises = Array.from(set).map(
220
+ (handler) => Promise.resolve(handler(event))
221
+ );
222
+ await Promise.all(promises);
223
+ }
224
+ subscribe(eventType, handler) {
225
+ if (!this.handlers.has(eventType)) {
226
+ this.handlers.set(eventType, /* @__PURE__ */ new Set());
227
+ }
228
+ this.handlers.get(eventType).add(handler);
229
+ }
230
+ unsubscribe(eventType, handler) {
231
+ this.handlers.get(eventType)?.delete(handler);
232
+ }
233
+ };
234
+ export {
235
+ AuditRecorder,
236
+ ConsoleLogger,
237
+ ErrorCode,
238
+ InMemoryAuditRepository,
239
+ InMemoryConfigProvider,
240
+ InMemoryEventBus,
241
+ InMemoryFeatureFlagProvider,
242
+ MaestroError,
243
+ RbacEngine
244
+ };
245
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/ErrorCode.ts","../src/errors/MaestroError.ts","../src/logging/LogLevel.ts","../src/logging/ConsoleLogger.ts","../src/audit/InMemoryAuditRepository.ts","../src/audit/AuditRecorder.ts","../src/rbac/RbacEngine.ts","../src/feature-flags/InMemoryFeatureFlagProvider.ts","../src/config/InMemoryConfigProvider.ts","../src/events/InMemoryEventBus.ts"],"sourcesContent":["export enum ErrorCode {\n VALIDATION_ERROR = 'VALIDATION_ERROR',\n PERMISSION_DENIED = 'PERMISSION_DENIED',\n NOT_FOUND = 'NOT_FOUND',\n CONFLICT = 'CONFLICT',\n INTERNAL_ERROR = 'INTERNAL_ERROR',\n CONFIGURATION_ERROR = 'CONFIGURATION_ERROR',\n}\n","import type { Metadata } from '../types/index.js';\nimport type { ErrorCode } from './ErrorCode.js';\n\nexport class MaestroError extends Error {\n readonly code: ErrorCode;\n readonly details?: Metadata;\n override readonly cause?: unknown;\n\n constructor(\n code: ErrorCode,\n message: string,\n options?: { details?: Metadata; cause?: unknown },\n ) {\n super(message, { cause: options?.cause });\n this.code = code;\n this.details = options?.details;\n this.cause = options?.cause;\n this.name = 'MaestroError';\n }\n}\n","export type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n","import type { Logger, LogEntry } from './Logger.js';\nimport type { LogLevel } from './LogLevel.js';\nimport { LOG_LEVEL_PRIORITY } from './LogLevel.js';\n\nexport class ConsoleLogger implements Logger {\n constructor(private readonly minLevel: LogLevel = 'info') {}\n\n debug(entry: LogEntry): void {\n this.log('debug', entry);\n }\n\n info(entry: LogEntry): void {\n this.log('info', entry);\n }\n\n warn(entry: LogEntry): void {\n this.log('warn', entry);\n }\n\n error(entry: LogEntry): void {\n this.log('error', entry);\n }\n\n private log(level: LogLevel, entry: LogEntry): void {\n if (LOG_LEVEL_PRIORITY[level] < LOG_LEVEL_PRIORITY[this.minLevel]) return;\n\n const output = {\n level,\n message: entry.message,\n ...(entry.correlationId && { correlationId: entry.correlationId }),\n ...(entry.metadata && { metadata: entry.metadata }),\n ...(entry.error !== undefined && { error: this.serializeError(entry.error) }),\n };\n\n const consoleFn = level === 'error' ? console.error\n : level === 'warn' ? console.warn\n : level === 'debug' ? console.debug\n : console.info;\n\n consoleFn(JSON.stringify(output));\n }\n\n private serializeError(error: unknown): unknown {\n if (error instanceof Error) {\n return { name: error.name, message: error.message };\n }\n return error;\n }\n}\n","import type { AuditRepository, AuditFilter } from './AuditRepository.js';\nimport type { AuditEvent } from './AuditEvent.js';\n\nexport class InMemoryAuditRepository implements AuditRepository {\n private readonly store = new Map<string, AuditEvent>();\n\n async record(event: AuditEvent): Promise<void> {\n this.store.set(event.id, event);\n }\n\n async list(filter?: AuditFilter): Promise<AuditEvent[]> {\n let events = Array.from(this.store.values());\n\n if (!filter) return events;\n\n if (filter.actorId !== undefined) {\n events = events.filter((e) => e.actor.id === filter.actorId);\n }\n if (filter.action !== undefined) {\n events = events.filter((e) => e.action === filter.action);\n }\n if (filter.resourceType !== undefined) {\n events = events.filter((e) => e.resource?.type === filter.resourceType);\n }\n if (filter.resourceId !== undefined) {\n events = events.filter((e) => e.resource?.id === filter.resourceId);\n }\n if (filter.level !== undefined) {\n events = events.filter((e) => e.level === filter.level);\n }\n if (filter.from !== undefined) {\n const from = filter.from;\n events = events.filter((e) => e.timestamp >= from);\n }\n if (filter.to !== undefined) {\n const to = filter.to;\n events = events.filter((e) => e.timestamp <= to);\n }\n if (filter.correlationId !== undefined) {\n events = events.filter((e) => e.correlationId === filter.correlationId);\n }\n\n return events;\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport type { AuditRepository } from './AuditRepository.js';\nimport type { AuditEvent } from './AuditEvent.js';\nimport type { AuditLevel } from './AuditLevel.js';\nimport type { Actor, ResourceRef, Metadata } from '../types/index.js';\n\nexport interface RecordAuditInput {\n action: string;\n actor: Actor;\n level?: AuditLevel;\n resource?: ResourceRef;\n before?: Metadata;\n after?: Metadata;\n metadata?: Metadata;\n correlationId?: string;\n requestId?: string;\n ip?: string;\n userAgent?: string;\n}\n\nexport class AuditRecorder {\n constructor(private readonly repository: AuditRepository) {}\n\n async record(input: RecordAuditInput): Promise<AuditEvent> {\n const event: AuditEvent = {\n id: randomUUID(),\n timestamp: new Date(),\n action: input.action,\n actor: input.actor,\n level: input.level ?? 'info',\n resource: input.resource,\n before: input.before,\n after: input.after,\n metadata: input.metadata,\n correlationId: input.correlationId,\n requestId: input.requestId,\n ip: input.ip,\n userAgent: input.userAgent,\n };\n\n await this.repository.record(event);\n return event;\n }\n}\n","import type { Actor } from '../types/index.js';\nimport type { RbacPolicy } from './RbacPolicy.js';\n\nexport class RbacEngine {\n constructor(private readonly policy: RbacPolicy) {}\n\n can(actor: Actor, permission: string): boolean {\n const permissions = this.resolvePermissions(actor);\n return permissions.some((p) => this.matchesPattern(p, permission));\n }\n\n private resolvePermissions(actor: Actor): string[] {\n const direct = actor.permissions ?? [];\n const fromRoles = (actor.roles ?? []).flatMap((roleName) => {\n const role = this.policy.roles[roleName];\n return role?.permissions ?? [];\n });\n return [...direct, ...fromRoles];\n }\n\n private matchesPattern(pattern: string, target: string): boolean {\n if (pattern === '*') return true;\n if (pattern === target) return true;\n if (pattern.endsWith('.*')) {\n const prefix = pattern.slice(0, -2);\n return target === prefix || target.startsWith(`${prefix}.`);\n }\n return false;\n }\n}\n","import type { FeatureFlagProvider } from './FeatureFlagProvider.js';\nimport type { FeatureFlag } from './FeatureFlag.js';\nimport type { Actor } from '../types/index.js';\n\nexport class InMemoryFeatureFlagProvider implements FeatureFlagProvider {\n private readonly flags = new Map<string, FeatureFlag>();\n\n constructor(flags: FeatureFlag[] = []) {\n for (const flag of flags) {\n this.flags.set(flag.key, flag);\n }\n }\n\n async isEnabled(key: string, _actor?: Actor): Promise<boolean> {\n return this.flags.get(key)?.enabled ?? false;\n }\n\n get(key: string): FeatureFlag | undefined {\n return this.flags.get(key);\n }\n\n set(flag: FeatureFlag): void {\n this.flags.set(flag.key, flag);\n }\n\n list(): FeatureFlag[] {\n return Array.from(this.flags.values());\n }\n}\n","import type { ConfigProvider } from './ConfigProvider.js';\nimport type { MetadataValue } from '../types/index.js';\n\nexport class InMemoryConfigProvider implements ConfigProvider {\n private readonly store = new Map<string, MetadataValue>();\n\n constructor(initial: Record<string, MetadataValue> = {}) {\n for (const [key, value] of Object.entries(initial)) {\n this.store.set(key, value);\n }\n }\n\n get<T extends MetadataValue>(key: string): T | undefined {\n return this.store.get(key) as T | undefined;\n }\n\n set<T extends MetadataValue>(key: string, value: T): void {\n this.store.set(key, value);\n }\n\n has(key: string): boolean {\n return this.store.has(key);\n }\n\n getOrDefault<T extends MetadataValue>(key: string, defaultValue: T): T {\n const value = this.store.get(key);\n return value !== undefined ? (value as T) : defaultValue;\n }\n}\n","import type { EventBus, EventHandler } from './EventBus.js';\nimport type { DomainEvent } from './DomainEvent.js';\n\nexport class InMemoryEventBus implements EventBus {\n private readonly handlers = new Map<string, Set<EventHandler>>();\n\n async publish<TPayload>(event: DomainEvent<TPayload>): Promise<void> {\n const set = this.handlers.get(event.type);\n if (!set) return;\n\n const promises = Array.from(set).map((handler) =>\n Promise.resolve(handler(event as DomainEvent<unknown>)),\n );\n await Promise.all(promises);\n }\n\n subscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void {\n if (!this.handlers.has(eventType)) {\n this.handlers.set(eventType, new Set());\n }\n this.handlers.get(eventType)!.add(handler as EventHandler);\n }\n\n unsubscribe<TPayload>(eventType: string, handler: EventHandler<TPayload>): void {\n this.handlers.get(eventType)?.delete(handler as EventHandler);\n }\n}\n"],"mappings":";AAAO,IAAK,YAAL,kBAAKA,eAAL;AACL,EAAAA,WAAA,sBAAmB;AACnB,EAAAA,WAAA,uBAAoB;AACpB,EAAAA,WAAA,eAAY;AACZ,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,oBAAiB;AACjB,EAAAA,WAAA,yBAAsB;AANZ,SAAAA;AAAA,GAAA;;;ACGL,IAAM,eAAN,cAA2B,MAAM;AAAA,EAC7B;AAAA,EACA;AAAA,EACS;AAAA,EAElB,YACE,MACA,SACA,SACA;AACA,UAAM,SAAS,EAAE,OAAO,SAAS,MAAM,CAAC;AACxC,SAAK,OAAO;AACZ,SAAK,UAAU,SAAS;AACxB,SAAK,QAAQ,SAAS;AACtB,SAAK,OAAO;AAAA,EACd;AACF;;;ACjBO,IAAM,qBAA+C;AAAA,EAC1D,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;;;ACHO,IAAM,gBAAN,MAAsC;AAAA,EAC3C,YAA6B,WAAqB,QAAQ;AAA7B;AAAA,EAA8B;AAAA,EAA9B;AAAA,EAE7B,MAAM,OAAuB;AAC3B,SAAK,IAAI,SAAS,KAAK;AAAA,EACzB;AAAA,EAEA,KAAK,OAAuB;AAC1B,SAAK,IAAI,QAAQ,KAAK;AAAA,EACxB;AAAA,EAEA,KAAK,OAAuB;AAC1B,SAAK,IAAI,QAAQ,KAAK;AAAA,EACxB;AAAA,EAEA,MAAM,OAAuB;AAC3B,SAAK,IAAI,SAAS,KAAK;AAAA,EACzB;AAAA,EAEQ,IAAI,OAAiB,OAAuB;AAClD,QAAI,mBAAmB,KAAK,IAAI,mBAAmB,KAAK,QAAQ,EAAG;AAEnE,UAAM,SAAS;AAAA,MACb;AAAA,MACA,SAAS,MAAM;AAAA,MACf,GAAI,MAAM,iBAAiB,EAAE,eAAe,MAAM,cAAc;AAAA,MAChE,GAAI,MAAM,YAAY,EAAE,UAAU,MAAM,SAAS;AAAA,MACjD,GAAI,MAAM,UAAU,UAAa,EAAE,OAAO,KAAK,eAAe,MAAM,KAAK,EAAE;AAAA,IAC7E;AAEA,UAAM,YAAY,UAAU,UAAU,QAAQ,QAC1C,UAAU,SAAS,QAAQ,OAC3B,UAAU,UAAU,QAAQ,QAC5B,QAAQ;AAEZ,cAAU,KAAK,UAAU,MAAM,CAAC;AAAA,EAClC;AAAA,EAEQ,eAAe,OAAyB;AAC9C,QAAI,iBAAiB,OAAO;AAC1B,aAAO,EAAE,MAAM,MAAM,MAAM,SAAS,MAAM,QAAQ;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AACF;;;AC7CO,IAAM,0BAAN,MAAyD;AAAA,EAC7C,QAAQ,oBAAI,IAAwB;AAAA,EAErD,MAAM,OAAO,OAAkC;AAC7C,SAAK,MAAM,IAAI,MAAM,IAAI,KAAK;AAAA,EAChC;AAAA,EAEA,MAAM,KAAK,QAA6C;AACtD,QAAI,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAE3C,QAAI,CAAC,OAAQ,QAAO;AAEpB,QAAI,OAAO,YAAY,QAAW;AAChC,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,OAAO,OAAO,OAAO;AAAA,IAC7D;AACA,QAAI,OAAO,WAAW,QAAW;AAC/B,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,MAAM;AAAA,IAC1D;AACA,QAAI,OAAO,iBAAiB,QAAW;AACrC,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,OAAO,YAAY;AAAA,IACxE;AACA,QAAI,OAAO,eAAe,QAAW;AACnC,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,OAAO,UAAU;AAAA,IACpE;AACA,QAAI,OAAO,UAAU,QAAW;AAC9B,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,KAAK;AAAA,IACxD;AACA,QAAI,OAAO,SAAS,QAAW;AAC7B,YAAM,OAAO,OAAO;AACpB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,IAAI;AAAA,IACnD;AACA,QAAI,OAAO,OAAO,QAAW;AAC3B,YAAM,KAAK,OAAO;AAClB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE;AAAA,IACjD;AACA,QAAI,OAAO,kBAAkB,QAAW;AACtC,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,kBAAkB,OAAO,aAAa;AAAA,IACxE;AAEA,WAAO;AAAA,EACT;AACF;;;AC5CA,SAAS,kBAAkB;AAoBpB,IAAM,gBAAN,MAAoB;AAAA,EACzB,YAA6B,YAA6B;AAA7B;AAAA,EAA8B;AAAA,EAA9B;AAAA,EAE7B,MAAM,OAAO,OAA8C;AACzD,UAAM,QAAoB;AAAA,MACxB,IAAI,WAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM;AAAA,MACb,OAAO,MAAM,SAAS;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,eAAe,MAAM;AAAA,MACrB,WAAW,MAAM;AAAA,MACjB,IAAI,MAAM;AAAA,MACV,WAAW,MAAM;AAAA,IACnB;AAEA,UAAM,KAAK,WAAW,OAAO,KAAK;AAClC,WAAO;AAAA,EACT;AACF;;;ACxCO,IAAM,aAAN,MAAiB;AAAA,EACtB,YAA6B,QAAoB;AAApB;AAAA,EAAqB;AAAA,EAArB;AAAA,EAE7B,IAAI,OAAc,YAA6B;AAC7C,UAAM,cAAc,KAAK,mBAAmB,KAAK;AACjD,WAAO,YAAY,KAAK,CAAC,MAAM,KAAK,eAAe,GAAG,UAAU,CAAC;AAAA,EACnE;AAAA,EAEQ,mBAAmB,OAAwB;AACjD,UAAM,SAAS,MAAM,eAAe,CAAC;AACrC,UAAM,aAAa,MAAM,SAAS,CAAC,GAAG,QAAQ,CAAC,aAAa;AAC1D,YAAM,OAAO,KAAK,OAAO,MAAM,QAAQ;AACvC,aAAO,MAAM,eAAe,CAAC;AAAA,IAC/B,CAAC;AACD,WAAO,CAAC,GAAG,QAAQ,GAAG,SAAS;AAAA,EACjC;AAAA,EAEQ,eAAe,SAAiB,QAAyB;AAC/D,QAAI,YAAY,IAAK,QAAO;AAC5B,QAAI,YAAY,OAAQ,QAAO;AAC/B,QAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,YAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,aAAO,WAAW,UAAU,OAAO,WAAW,GAAG,MAAM,GAAG;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AACF;;;ACzBO,IAAM,8BAAN,MAAiE;AAAA,EACrD,QAAQ,oBAAI,IAAyB;AAAA,EAEtD,YAAY,QAAuB,CAAC,GAAG;AACrC,eAAW,QAAQ,OAAO;AACxB,WAAK,MAAM,IAAI,KAAK,KAAK,IAAI;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,KAAa,QAAkC;AAC7D,WAAO,KAAK,MAAM,IAAI,GAAG,GAAG,WAAW;AAAA,EACzC;AAAA,EAEA,IAAI,KAAsC;AACxC,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA,EAEA,IAAI,MAAyB;AAC3B,SAAK,MAAM,IAAI,KAAK,KAAK,IAAI;AAAA,EAC/B;AAAA,EAEA,OAAsB;AACpB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,EACvC;AACF;;;ACzBO,IAAM,yBAAN,MAAuD;AAAA,EAC3C,QAAQ,oBAAI,IAA2B;AAAA,EAExD,YAAY,UAAyC,CAAC,GAAG;AACvD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,WAAK,MAAM,IAAI,KAAK,KAAK;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,IAA6B,KAA4B;AACvD,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA,EAEA,IAA6B,KAAa,OAAgB;AACxD,SAAK,MAAM,IAAI,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,IAAI,KAAsB;AACxB,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAC3B;AAAA,EAEA,aAAsC,KAAa,cAAoB;AACrE,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,WAAO,UAAU,SAAa,QAAc;AAAA,EAC9C;AACF;;;ACzBO,IAAM,mBAAN,MAA2C;AAAA,EAC/B,WAAW,oBAAI,IAA+B;AAAA,EAE/D,MAAM,QAAkB,OAA6C;AACnE,UAAM,MAAM,KAAK,SAAS,IAAI,MAAM,IAAI;AACxC,QAAI,CAAC,IAAK;AAEV,UAAM,WAAW,MAAM,KAAK,GAAG,EAAE;AAAA,MAAI,CAAC,YACpC,QAAQ,QAAQ,QAAQ,KAA6B,CAAC;AAAA,IACxD;AACA,UAAM,QAAQ,IAAI,QAAQ;AAAA,EAC5B;AAAA,EAEA,UAAoB,WAAmB,SAAuC;AAC5E,QAAI,CAAC,KAAK,SAAS,IAAI,SAAS,GAAG;AACjC,WAAK,SAAS,IAAI,WAAW,oBAAI,IAAI,CAAC;AAAA,IACxC;AACA,SAAK,SAAS,IAAI,SAAS,EAAG,IAAI,OAAuB;AAAA,EAC3D;AAAA,EAEA,YAAsB,WAAmB,SAAuC;AAC9E,SAAK,SAAS,IAAI,SAAS,GAAG,OAAO,OAAuB;AAAA,EAC9D;AACF;","names":["ErrorCode"]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@maykonpaulo/maestro-core",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^22.0.0",
23
+ "rimraf": "^6.0.0",
24
+ "tsup": "^8.0.0",
25
+ "typescript": "^5.6.0",
26
+ "vitest": "^2.0.0"
27
+ },
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "test": "vitest run",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "eslint src tests",
33
+ "clean": "rimraf dist"
34
+ }
35
+ }