weshipyou-sdk 1.0.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/LICENSE +33 -0
- package/README.md +49 -0
- package/dist/chunk-KT3VLIZI.mjs +18 -0
- package/dist/chunk-KT3VLIZI.mjs.map +1 -0
- package/dist/chunk-RM3JFTCX.cjs +18 -0
- package/dist/chunk-RM3JFTCX.cjs.map +1 -0
- package/dist/cli.js +20 -0
- package/dist/cli.js.map +1 -0
- package/dist/enterprise.cjs +73 -0
- package/dist/enterprise.cjs.map +1 -0
- package/dist/enterprise.d.mts +398 -0
- package/dist/enterprise.d.ts +398 -0
- package/dist/enterprise.mjs +73 -0
- package/dist/enterprise.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +221 -0
- package/dist/index.d.ts +221 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/update-shipment.use-case-BsHiVqQV.d.mts +504 -0
- package/dist/update-shipment.use-case-BsHiVqQV.d.ts +504 -0
- package/package.json +106 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { D as DomainEvent, I as IHttpClient, a as IShipmentRequest, A as AcceptLanguage, C as CreateShipmentUseCase, b as IEventStore, E as ExecuteRechargeUseCase, U as UpdateShipmentUseCase, S as SqliteEventStore, c as Services } from './update-shipment.use-case-BsHiVqQV.js';
|
|
2
|
+
import { Request, RequestHandler } from 'express';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
interface TenantContext {
|
|
6
|
+
tenantId: string;
|
|
7
|
+
accountId: string;
|
|
8
|
+
permissions: string[];
|
|
9
|
+
metadata?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
interface ITenantContextProvider {
|
|
12
|
+
getCurrent(): TenantContext | null;
|
|
13
|
+
set(context: TenantContext): void;
|
|
14
|
+
clear(): void;
|
|
15
|
+
isolate<T>(context: TenantContext, fn: () => Promise<T>): Promise<T>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface SchemaIsolationConfig {
|
|
19
|
+
tenantId: string;
|
|
20
|
+
schemaName: string;
|
|
21
|
+
migrationStatements: string[];
|
|
22
|
+
}
|
|
23
|
+
declare class SchemaIsolationManager {
|
|
24
|
+
private tenantProvider;
|
|
25
|
+
private schemas;
|
|
26
|
+
constructor(tenantProvider: ITenantContextProvider);
|
|
27
|
+
register(tenantId: string, config: SchemaIsolationConfig): void;
|
|
28
|
+
getCurrentSchema(): string | null;
|
|
29
|
+
getSchemaFor(tenantId: string): string | null;
|
|
30
|
+
deregister(tenantId: string): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ShipmentReadModel {
|
|
34
|
+
id: string;
|
|
35
|
+
tenantId: string;
|
|
36
|
+
accountId: string;
|
|
37
|
+
status: string;
|
|
38
|
+
trackingNumber?: string;
|
|
39
|
+
totalValue: number;
|
|
40
|
+
incoterms: 'DDU' | 'DDP';
|
|
41
|
+
senderName: string;
|
|
42
|
+
recipientName: string;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
updatedAt: string;
|
|
45
|
+
metadata?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
interface IReadModel {
|
|
48
|
+
init(): Promise<void>;
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
upsert(shipment: ShipmentReadModel): Promise<void>;
|
|
51
|
+
getById(id: string, tenantId: string): Promise<ShipmentReadModel | null>;
|
|
52
|
+
query(filters: {
|
|
53
|
+
tenantId: string;
|
|
54
|
+
accountId?: string;
|
|
55
|
+
status?: string;
|
|
56
|
+
limit?: number;
|
|
57
|
+
offset?: number;
|
|
58
|
+
}): Promise<ShipmentReadModel[]>;
|
|
59
|
+
}
|
|
60
|
+
interface IProjectionHandler {
|
|
61
|
+
handle(event: DomainEvent): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
declare class RedisStreamsProjection {
|
|
65
|
+
private client;
|
|
66
|
+
private streamName;
|
|
67
|
+
private groupName;
|
|
68
|
+
private consumerName;
|
|
69
|
+
constructor(redisUrl: string, streamName?: string, groupName?: string, consumerName?: string);
|
|
70
|
+
init(): Promise<void>;
|
|
71
|
+
publish(event: DomainEvent): Promise<void>;
|
|
72
|
+
consume(handler: IProjectionHandler, timeout?: number): Promise<void>;
|
|
73
|
+
close(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
declare class ShipmentProjection implements IProjectionHandler {
|
|
77
|
+
private readonly readModel;
|
|
78
|
+
constructor(readModel: IReadModel);
|
|
79
|
+
handle(event: DomainEvent): Promise<void>;
|
|
80
|
+
private onShipmentCreated;
|
|
81
|
+
private onStatusChanged;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
interface AuditLogEntry extends DomainEvent {
|
|
85
|
+
tenantId: string;
|
|
86
|
+
actorId: string;
|
|
87
|
+
actorType: 'user' | 'system' | 'api_key';
|
|
88
|
+
action: string;
|
|
89
|
+
resourceType: string;
|
|
90
|
+
resourceId: string;
|
|
91
|
+
ipAddress?: string;
|
|
92
|
+
userAgent?: string;
|
|
93
|
+
signature: string;
|
|
94
|
+
}
|
|
95
|
+
interface IAuditLogService {
|
|
96
|
+
log(entry: Omit<AuditLogEntry, 'signature'>, privateKey: string): Promise<void>;
|
|
97
|
+
verify(entry: AuditLogEntry, publicKey: string): boolean;
|
|
98
|
+
query(filters: {
|
|
99
|
+
tenantId: string;
|
|
100
|
+
resourceType?: string;
|
|
101
|
+
resourceId?: string;
|
|
102
|
+
since?: string;
|
|
103
|
+
until?: string;
|
|
104
|
+
}): Promise<AuditLogEntry[]>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
type SiemFormat = 'json' | 'cef' | 'leef';
|
|
108
|
+
declare class SiemExporter {
|
|
109
|
+
export(entries: AuditLogEntry[], format: SiemFormat): string;
|
|
110
|
+
private toCEF;
|
|
111
|
+
private toLEEF;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
declare class AuditLogService {
|
|
115
|
+
private readonly auditLog;
|
|
116
|
+
private readonly tenantProvider;
|
|
117
|
+
private readonly privateKey;
|
|
118
|
+
constructor(auditLog: IAuditLogService, tenantProvider: ITenantContextProvider, privateKey: string);
|
|
119
|
+
record(partial: {
|
|
120
|
+
action: string;
|
|
121
|
+
resourceType: string;
|
|
122
|
+
resourceId: string;
|
|
123
|
+
payload: Record<string, unknown>;
|
|
124
|
+
}): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type ChaosAttack = 'latency' | 'error' | 'timeout' | 'crash';
|
|
128
|
+
interface IChaosTester {
|
|
129
|
+
inject(attack: ChaosAttack, durationMs?: number): Promise<void>;
|
|
130
|
+
recover(): Promise<void>;
|
|
131
|
+
isActive(): boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare class HttpChaosTester implements IChaosTester {
|
|
135
|
+
private readonly httpClient;
|
|
136
|
+
private active;
|
|
137
|
+
constructor(httpClient: IHttpClient);
|
|
138
|
+
inject(attack: ChaosAttack, durationMs?: number): Promise<void>;
|
|
139
|
+
recover(): Promise<void>;
|
|
140
|
+
isActive(): boolean;
|
|
141
|
+
private injectLatency;
|
|
142
|
+
private injectErrors;
|
|
143
|
+
private injectTimeout;
|
|
144
|
+
private injectCrash;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface TenantExtractor {
|
|
148
|
+
(req: Request): Promise<{
|
|
149
|
+
tenantId: string;
|
|
150
|
+
accountId: string;
|
|
151
|
+
}>;
|
|
152
|
+
}
|
|
153
|
+
declare function createTenantMiddleware(tenantProvider: ITenantContextProvider, extractTenant: TenantExtractor): RequestHandler;
|
|
154
|
+
|
|
155
|
+
interface EnterpriseConfig {
|
|
156
|
+
postgresUrl: string;
|
|
157
|
+
redisUrl: string;
|
|
158
|
+
auditPrivateKey: string;
|
|
159
|
+
streamName?: string;
|
|
160
|
+
consumerName?: string;
|
|
161
|
+
chaosBaseUrl?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface ICommand<TResult = void> {
|
|
165
|
+
readonly type: string;
|
|
166
|
+
}
|
|
167
|
+
interface ICommandHandler<TCommand extends ICommand<TResult>, TResult = void> {
|
|
168
|
+
execute(command: TCommand): Promise<TResult>;
|
|
169
|
+
}
|
|
170
|
+
interface IQuery<TResult = unknown> {
|
|
171
|
+
readonly type: string;
|
|
172
|
+
}
|
|
173
|
+
interface IQueryHandler<TQuery extends IQuery<TResult>, TResult = unknown> {
|
|
174
|
+
execute(query: TQuery): Promise<TResult>;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
interface CreateShipmentResult {
|
|
178
|
+
shipmentId: string;
|
|
179
|
+
trackingNumber?: string;
|
|
180
|
+
}
|
|
181
|
+
declare class CreateShipmentCommand implements ICommand<CreateShipmentResult> {
|
|
182
|
+
readonly username: string;
|
|
183
|
+
readonly password: string;
|
|
184
|
+
readonly payload: IShipmentRequest;
|
|
185
|
+
readonly lang: AcceptLanguage;
|
|
186
|
+
readonly type = "CreateShipment";
|
|
187
|
+
constructor(username: string, password: string, payload: IShipmentRequest, lang?: AcceptLanguage);
|
|
188
|
+
}
|
|
189
|
+
declare class CreateShipmentHandler implements ICommandHandler<CreateShipmentCommand, CreateShipmentResult> {
|
|
190
|
+
private readonly createShipmentUseCase;
|
|
191
|
+
private readonly eventStore;
|
|
192
|
+
private readonly tenantId?;
|
|
193
|
+
constructor(createShipmentUseCase: CreateShipmentUseCase, eventStore: IEventStore, tenantId?: string | undefined);
|
|
194
|
+
execute(command: CreateShipmentCommand): Promise<CreateShipmentResult>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface CancelShipmentResult {
|
|
198
|
+
success: boolean;
|
|
199
|
+
shipmentId: string;
|
|
200
|
+
}
|
|
201
|
+
declare class CancelShipmentCommand implements ICommand<CancelShipmentResult> {
|
|
202
|
+
readonly shipmentId: string;
|
|
203
|
+
readonly tenantId: string;
|
|
204
|
+
readonly accountId: string;
|
|
205
|
+
readonly type = "CancelShipment";
|
|
206
|
+
constructor(shipmentId: string, tenantId: string, accountId: string);
|
|
207
|
+
}
|
|
208
|
+
declare class CancelShipmentHandler implements ICommandHandler<CancelShipmentCommand, CancelShipmentResult> {
|
|
209
|
+
private readonly httpClient;
|
|
210
|
+
private readonly eventStore;
|
|
211
|
+
constructor(httpClient: IHttpClient, eventStore: IEventStore);
|
|
212
|
+
execute(command: CancelShipmentCommand): Promise<CancelShipmentResult>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface RechargeableProduct {
|
|
216
|
+
id: number;
|
|
217
|
+
}
|
|
218
|
+
interface AccountRechargeableContact {
|
|
219
|
+
name: string;
|
|
220
|
+
accountNumber: string;
|
|
221
|
+
}
|
|
222
|
+
interface CreateRechargeRequest {
|
|
223
|
+
paymentMethod: 'zelle' | 'credit_card' | 'balance';
|
|
224
|
+
accountUid?: string;
|
|
225
|
+
rechargeable_product: RechargeableProduct;
|
|
226
|
+
scheduleDate?: string | null;
|
|
227
|
+
amount: number;
|
|
228
|
+
account_rechargeable_contact: AccountRechargeableContact;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
interface ExecuteRechargeResult {
|
|
232
|
+
transactionId: string;
|
|
233
|
+
status: string;
|
|
234
|
+
}
|
|
235
|
+
declare class ExecuteRechargeCommand implements ICommand<ExecuteRechargeResult> {
|
|
236
|
+
readonly username: string;
|
|
237
|
+
readonly password: string;
|
|
238
|
+
readonly payload: CreateRechargeRequest;
|
|
239
|
+
readonly lang: AcceptLanguage;
|
|
240
|
+
readonly type = "ExecuteRecharge";
|
|
241
|
+
constructor(username: string, password: string, payload: CreateRechargeRequest, lang?: AcceptLanguage);
|
|
242
|
+
}
|
|
243
|
+
declare class ExecuteRechargeHandler implements ICommandHandler<ExecuteRechargeCommand, ExecuteRechargeResult> {
|
|
244
|
+
private readonly executeRechargeUseCase;
|
|
245
|
+
private readonly eventStore;
|
|
246
|
+
constructor(executeRechargeUseCase: ExecuteRechargeUseCase, eventStore: IEventStore);
|
|
247
|
+
execute(command: ExecuteRechargeCommand): Promise<ExecuteRechargeResult>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface UpdateShipmentResult {
|
|
251
|
+
shipmentId: string;
|
|
252
|
+
}
|
|
253
|
+
declare class UpdateShipmentCommand implements ICommand<UpdateShipmentResult> {
|
|
254
|
+
readonly username: string;
|
|
255
|
+
readonly password: string;
|
|
256
|
+
readonly shipmentId: string;
|
|
257
|
+
readonly payload: Partial<IShipmentRequest>;
|
|
258
|
+
readonly lang: AcceptLanguage;
|
|
259
|
+
readonly type = "UpdateShipment";
|
|
260
|
+
constructor(username: string, password: string, shipmentId: string, payload: Partial<IShipmentRequest>, lang?: AcceptLanguage);
|
|
261
|
+
}
|
|
262
|
+
declare class UpdateShipmentHandler implements ICommandHandler<UpdateShipmentCommand, UpdateShipmentResult> {
|
|
263
|
+
private readonly updateShipmentUseCase;
|
|
264
|
+
private readonly eventStore;
|
|
265
|
+
private readonly tenantId?;
|
|
266
|
+
constructor(updateShipmentUseCase: UpdateShipmentUseCase, eventStore: IEventStore, tenantId?: string | undefined);
|
|
267
|
+
execute(command: UpdateShipmentCommand): Promise<UpdateShipmentResult>;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
declare class GetShipmentQuery implements IQuery<ShipmentReadModel | null> {
|
|
271
|
+
readonly shipmentId: string;
|
|
272
|
+
readonly tenantId: string;
|
|
273
|
+
readonly type = "GetShipment";
|
|
274
|
+
constructor(shipmentId: string, tenantId: string);
|
|
275
|
+
}
|
|
276
|
+
declare class GetShipmentHandler implements IQueryHandler<GetShipmentQuery, ShipmentReadModel | null> {
|
|
277
|
+
private readonly readModel;
|
|
278
|
+
constructor(readModel: IReadModel);
|
|
279
|
+
execute(query: GetShipmentQuery): Promise<ShipmentReadModel | null>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
interface ListShipmentsFilter {
|
|
283
|
+
tenantId: string;
|
|
284
|
+
accountId?: string;
|
|
285
|
+
status?: string;
|
|
286
|
+
limit?: number;
|
|
287
|
+
offset?: number;
|
|
288
|
+
}
|
|
289
|
+
declare class ListShipmentsQuery implements IQuery<ShipmentReadModel[]> {
|
|
290
|
+
readonly filter: ListShipmentsFilter;
|
|
291
|
+
readonly type = "ListShipments";
|
|
292
|
+
constructor(filter: ListShipmentsFilter);
|
|
293
|
+
}
|
|
294
|
+
declare class ListShipmentsHandler implements IQueryHandler<ListShipmentsQuery, ShipmentReadModel[]> {
|
|
295
|
+
private readonly readModel;
|
|
296
|
+
constructor(readModel: IReadModel);
|
|
297
|
+
execute(query: ListShipmentsQuery): Promise<ShipmentReadModel[]>;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
declare class GetShipmentHistoryQuery implements IQuery<DomainEvent[]> {
|
|
301
|
+
readonly shipmentId: string;
|
|
302
|
+
readonly sinceVersion?: number | undefined;
|
|
303
|
+
readonly type = "GetShipmentHistory";
|
|
304
|
+
constructor(shipmentId: string, sinceVersion?: number | undefined);
|
|
305
|
+
}
|
|
306
|
+
declare class GetShipmentHistoryHandler implements IQueryHandler<GetShipmentHistoryQuery, DomainEvent[]> {
|
|
307
|
+
private readonly eventStore;
|
|
308
|
+
constructor(eventStore: IEventStore);
|
|
309
|
+
execute(query: GetShipmentHistoryQuery): Promise<DomainEvent[]>;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
declare class AsyncLocalStorageTenantContext implements ITenantContextProvider {
|
|
313
|
+
private storage;
|
|
314
|
+
getCurrent(): TenantContext | null;
|
|
315
|
+
set(context: TenantContext): void;
|
|
316
|
+
clear(): void;
|
|
317
|
+
isolate<T>(context: TenantContext, fn: () => Promise<T>): Promise<T>;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
declare class PostgresReadModel implements IReadModel {
|
|
321
|
+
private pool;
|
|
322
|
+
constructor(connectionString: string, poolConfig?: {
|
|
323
|
+
max?: number;
|
|
324
|
+
idleTimeoutMillis?: number;
|
|
325
|
+
connectionTimeoutMillis?: number;
|
|
326
|
+
});
|
|
327
|
+
init(): Promise<void>;
|
|
328
|
+
upsert(shipment: ShipmentReadModel): Promise<void>;
|
|
329
|
+
getById(id: string, tenantId: string): Promise<ShipmentReadModel | null>;
|
|
330
|
+
query(filters: {
|
|
331
|
+
tenantId: string;
|
|
332
|
+
accountId?: string;
|
|
333
|
+
status?: string;
|
|
334
|
+
limit?: number;
|
|
335
|
+
offset?: number;
|
|
336
|
+
}): Promise<ShipmentReadModel[]>;
|
|
337
|
+
close(): Promise<void>;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
declare class ImmutableAuditLog implements IAuditLogService {
|
|
341
|
+
private db;
|
|
342
|
+
private readonly algorithm;
|
|
343
|
+
constructor(dbPath?: string);
|
|
344
|
+
log(entry: Omit<AuditLogEntry, 'signature'>, privateKey: string): Promise<void>;
|
|
345
|
+
verify(entry: AuditLogEntry, key: string): boolean;
|
|
346
|
+
query(filters: {
|
|
347
|
+
tenantId: string;
|
|
348
|
+
resourceType?: string;
|
|
349
|
+
resourceId?: string;
|
|
350
|
+
since?: string;
|
|
351
|
+
until?: string;
|
|
352
|
+
}): Promise<AuditLogEntry[]>;
|
|
353
|
+
exportToSIEM(format: 'json' | 'cef' | 'leef'): Promise<string>;
|
|
354
|
+
close(): void;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface TenantConfig {
|
|
358
|
+
tenantId: string;
|
|
359
|
+
accountId: string;
|
|
360
|
+
dbSchema?: string;
|
|
361
|
+
features: {
|
|
362
|
+
auditLog: boolean;
|
|
363
|
+
readModel: boolean;
|
|
364
|
+
webhookReplay: boolean;
|
|
365
|
+
};
|
|
366
|
+
rateLimits: {
|
|
367
|
+
requestsPerMinute: number;
|
|
368
|
+
concurrentShipments: number;
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
interface EnterpriseServices {
|
|
373
|
+
tenantProvider: ITenantContextProvider;
|
|
374
|
+
schemaIsolation: SchemaIsolationManager;
|
|
375
|
+
readModel: IReadModel;
|
|
376
|
+
projection: RedisStreamsProjection;
|
|
377
|
+
shipmentProjection: ShipmentProjection;
|
|
378
|
+
eventStore: SqliteEventStore;
|
|
379
|
+
auditLog: IAuditLogService;
|
|
380
|
+
siemExporter: SiemExporter;
|
|
381
|
+
auditService: AuditLogService;
|
|
382
|
+
chaosTester: HttpChaosTester;
|
|
383
|
+
tenantMiddleware: ReturnType<typeof createTenantMiddleware>;
|
|
384
|
+
commands: {
|
|
385
|
+
createShipment: CreateShipmentHandler;
|
|
386
|
+
cancelShipment: CancelShipmentHandler;
|
|
387
|
+
executeRecharge: ExecuteRechargeHandler;
|
|
388
|
+
updateShipment: UpdateShipmentHandler;
|
|
389
|
+
};
|
|
390
|
+
queries: {
|
|
391
|
+
getShipment: GetShipmentHandler;
|
|
392
|
+
listShipments: ListShipmentsHandler;
|
|
393
|
+
getShipmentHistory: GetShipmentHistoryHandler;
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
declare function bootstrapEnterprise(base: Services, config: EnterpriseConfig): EnterpriseServices;
|
|
397
|
+
|
|
398
|
+
export { AsyncLocalStorageTenantContext, type AuditLogEntry, AuditLogService, CancelShipmentCommand, CancelShipmentHandler, type CancelShipmentResult, type ChaosAttack, CreateShipmentCommand, CreateShipmentHandler, type CreateShipmentResult, type EnterpriseConfig, type EnterpriseServices, ExecuteRechargeCommand, ExecuteRechargeHandler, type ExecuteRechargeResult, GetShipmentHandler, GetShipmentHistoryHandler, GetShipmentHistoryQuery, GetShipmentQuery, HttpChaosTester, type IAuditLogService, type IChaosTester, type ICommand, type ICommandHandler, type IProjectionHandler, type IQuery, type IQueryHandler, type IReadModel, type ITenantContextProvider, ImmutableAuditLog, ListShipmentsHandler, ListShipmentsQuery, PostgresReadModel, RedisStreamsProjection, SchemaIsolationManager, ShipmentProjection, type ShipmentReadModel, SiemExporter, type TenantConfig, type TenantContext, type TenantExtractor, UpdateShipmentCommand, UpdateShipmentHandler, type UpdateShipmentResult, bootstrapEnterprise, createTenantMiddleware };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import{a as k,b as $,c as X,d as j,f as F}from"./chunk-KT3VLIZI.mjs";import{AsyncLocalStorage as V}from"async_hooks";var s=class{constructor(){this.storage=new V}getCurrent(){return this.storage.getStore()||null}set(e){this.storage.enterWith(e)}clear(){this.storage.disable()}async isolate(e,t){return this.storage.run(e,t)}};var d=class{constructor(e){this.schemas=new Map;this.tenantProvider=e}register(e,t){this.schemas.set(e,t)}getCurrentSchema(){let e=this.tenantProvider.getCurrent();return e&&this.schemas.get(e.tenantId)?.schemaName||null}getSchemaFor(e){return this.schemas.get(e)?.schemaName||null}deregister(e){this.schemas.delete(e)}};import{Pool as Z}from"pg";var m=class{constructor(e,t){this.pool=new Z({connectionString:e,max:10,idleTimeoutMillis:3e4,connectionTimeoutMillis:1e4,...t})}async init(){await this.pool.query(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS shipment_read_model (
|
|
3
|
+
id TEXT PRIMARY KEY,
|
|
4
|
+
tenant_id TEXT NOT NULL,
|
|
5
|
+
account_id TEXT NOT NULL,
|
|
6
|
+
status TEXT NOT NULL,
|
|
7
|
+
tracking_number TEXT,
|
|
8
|
+
total_value NUMERIC(10,2) NOT NULL,
|
|
9
|
+
incoterms TEXT CHECK (incoterms IN ('DDU', 'DDP')),
|
|
10
|
+
sender_name TEXT NOT NULL,
|
|
11
|
+
recipient_name TEXT NOT NULL,
|
|
12
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
13
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
14
|
+
metadata JSONB
|
|
15
|
+
)
|
|
16
|
+
`),await this.pool.query(`
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_shipment_tenant_account
|
|
18
|
+
ON shipment_read_model (tenant_id, account_id)
|
|
19
|
+
`),await this.pool.query(`
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_shipment_status
|
|
21
|
+
ON shipment_read_model (status)
|
|
22
|
+
`),await this.pool.query(`
|
|
23
|
+
CREATE INDEX IF NOT EXISTS idx_shipment_created
|
|
24
|
+
ON shipment_read_model (created_at)
|
|
25
|
+
`)}async upsert(e){await this.pool.query(`
|
|
26
|
+
INSERT INTO shipment_read_model (
|
|
27
|
+
id, tenant_id, account_id, status, tracking_number,
|
|
28
|
+
total_value, incoterms, sender_name, recipient_name,
|
|
29
|
+
created_at, updated_at, metadata
|
|
30
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
31
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
32
|
+
status = EXCLUDED.status,
|
|
33
|
+
tracking_number = EXCLUDED.tracking_number,
|
|
34
|
+
total_value = EXCLUDED.total_value,
|
|
35
|
+
incoterms = EXCLUDED.incoterms,
|
|
36
|
+
sender_name = EXCLUDED.sender_name,
|
|
37
|
+
recipient_name = EXCLUDED.recipient_name,
|
|
38
|
+
updated_at = NOW(),
|
|
39
|
+
metadata = EXCLUDED.metadata
|
|
40
|
+
`,[e.id,e.tenantId,e.accountId,e.status,e.trackingNumber,e.totalValue,e.incoterms,e.senderName,e.recipientName,e.createdAt,e.updatedAt,e.metadata?JSON.stringify(e.metadata):null])}async getById(e,t){let r=(await this.pool.query("SELECT * FROM shipment_read_model WHERE id = $1 AND tenant_id = $2",[e,t])).rows[0];return r?{...r,metadata:r.metadata||void 0}:null}async query(e){let t="SELECT * FROM shipment_read_model WHERE tenant_id = $1",a=[e.tenantId],r=2;return e.accountId&&(t+=` AND account_id = $${r++}`,a.push(e.accountId)),e.status&&(t+=` AND status = $${r++}`,a.push(e.status)),t+=" ORDER BY created_at DESC",e.limit&&(t+=` LIMIT $${r++}`,a.push(e.limit)),e.offset&&(t+=` OFFSET $${r++}`,a.push(e.offset)),(await this.pool.query(t,a)).rows.map(o=>({...o,metadata:o.metadata||void 0}))}async close(){await this.pool.end()}};import{createClient as z}from"redis";var p=class{constructor(e,t="weshipyou:events",a="projections",r="shipment-projection"){this.client=z({url:e}),this.streamName=t,this.groupName=a,this.consumerName=r}async init(){await this.client.connect();try{await this.client.xGroupCreate(this.streamName,this.groupName,"$",{MKSTREAM:!0})}catch(e){if(!(e?.message||"").includes("BUSYGROUP"))throw e}}async publish(e){await this.client.xAdd(this.streamName,"*",{eventId:e.eventId,aggregateId:e.aggregateId,type:e.type,payload:JSON.stringify(e.payload),timestamp:e.timestamp,version:e.version.toString()})}async consume(e,t=5e3){let a=await this.client.xReadGroup(this.groupName,this.consumerName,{key:this.streamName,id:">"},{COUNT:10,BLOCK:t});if(!(!a||!a[0]?.messages))for(let r of a[0].messages)try{let n={eventId:r.message.eventId,aggregateId:r.message.aggregateId,type:r.message.type,payload:JSON.parse(r.message.payload),timestamp:r.message.timestamp,version:parseInt(r.message.version,10)};await e.handle(n),await this.client.xAck(this.streamName,this.groupName,r.id)}catch(n){await this.client.xAdd(`${this.streamName}:dead`,"*",r.message),await this.client.xAck(this.streamName,this.groupName,r.id),console.error("Projection consumer error \u2014 moved to dead-letter:",n)}}async close(){await this.client.quit()}};var c=class{constructor(e){this.readModel=e}async handle(e){switch(e.type){case"shipment.created":await this.onShipmentCreated(e);break;case"shipment.status_changed":await this.onStatusChanged(e);break}}async onShipmentCreated(e){let t=e.payload,a=e,r={id:e.aggregateId,tenantId:a.tenantId||"default",accountId:t.accountId,status:"created",trackingNumber:t.trackingNumber,totalValue:Number(t.totalValue)||0,incoterms:t.incoterms||"DDU",senderName:t.sender?.name||"",recipientName:t.recipient?.name||"",createdAt:e.timestamp,updatedAt:e.timestamp,metadata:{sourceEvent:e.eventId}};await this.readModel.upsert(r)}async onStatusChanged(e){let t=e.payload,a=e,r=await this.readModel.getById(e.aggregateId,a.tenantId||"default");r&&await this.readModel.upsert({...r,status:t.status||r.status,updatedAt:t.updatedAt||e.timestamp,metadata:{...r.metadata,previousStatus:t.previousStatus,lastEventId:e.eventId}})}};import{createHmac as q}from"crypto";import ee from"better-sqlite3";var u=class{constructor(e=":memory:"){this.algorithm="sha256";this.db=new ee(e),this.db.exec(`
|
|
41
|
+
CREATE TABLE IF NOT EXISTS audit_logs (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
tenant_id TEXT NOT NULL,
|
|
44
|
+
aggregate_id TEXT NOT NULL DEFAULT '',
|
|
45
|
+
type TEXT NOT NULL DEFAULT '',
|
|
46
|
+
actor_id TEXT NOT NULL,
|
|
47
|
+
actor_type TEXT NOT NULL,
|
|
48
|
+
action TEXT NOT NULL,
|
|
49
|
+
resource_type TEXT NOT NULL,
|
|
50
|
+
resource_id TEXT NOT NULL,
|
|
51
|
+
payload TEXT NOT NULL,
|
|
52
|
+
signature TEXT NOT NULL,
|
|
53
|
+
timestamp TEXT NOT NULL,
|
|
54
|
+
ip_address TEXT,
|
|
55
|
+
user_agent TEXT,
|
|
56
|
+
version INTEGER DEFAULT 1
|
|
57
|
+
)
|
|
58
|
+
`),this.db.exec("CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id, resource_type, resource_id)"),this.db.exec("CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_logs(timestamp)")}async log(e,t){let a=JSON.stringify({eventId:e.eventId,aggregateId:e.aggregateId,type:e.type,payload:e.payload,timestamp:e.timestamp,actorId:e.actorId,action:e.action,resourceType:e.resourceType,resourceId:e.resourceId}),r=q(this.algorithm,t).update(a).digest("hex");this.db.prepare(`
|
|
59
|
+
INSERT INTO audit_logs (
|
|
60
|
+
id, tenant_id, aggregate_id, type, actor_id, actor_type, action,
|
|
61
|
+
resource_type, resource_id, payload, signature,
|
|
62
|
+
timestamp, ip_address, user_agent, version
|
|
63
|
+
) VALUES (
|
|
64
|
+
@id, @tenantId, @aggregateId, @type, @actorId, @actorType, @action,
|
|
65
|
+
@resourceType, @resourceId, @payloadText, @signature,
|
|
66
|
+
@timestamp, @ipAddress, @userAgent, @version
|
|
67
|
+
)
|
|
68
|
+
`).run({id:e.eventId,tenantId:e.tenantId,aggregateId:e.aggregateId,type:e.type,actorId:e.actorId,actorType:e.actorType,action:e.action,resourceType:e.resourceType,resourceId:e.resourceId,payloadText:JSON.stringify(e.payload),version:e.version,signature:r,timestamp:e.timestamp,ipAddress:e.ipAddress||null,userAgent:e.userAgent||null})}verify(e,t){let a=JSON.stringify({eventId:e.eventId,aggregateId:e.aggregateId,type:e.type,payload:e.payload,timestamp:e.timestamp,actorId:e.actorId,action:e.action,resourceType:e.resourceType,resourceId:e.resourceId});return q(this.algorithm,t).update(a).digest("hex")===e.signature}async query(e){let t="SELECT * FROM audit_logs WHERE tenant_id = ?",a=[e.tenantId];return e.resourceType&&(t+=" AND resource_type = ?",a.push(e.resourceType)),e.resourceId&&(t+=" AND resource_id = ?",a.push(e.resourceId)),e.since&&(t+=" AND timestamp >= ?",a.push(e.since)),e.until&&(t+=" AND timestamp <= ?",a.push(e.until)),t+=" ORDER BY timestamp DESC",this.db.prepare(t).all(...a).map(n=>({eventId:n.id,aggregateId:n.aggregate_id,type:n.type,payload:JSON.parse(n.payload),timestamp:n.timestamp,version:Number(n.version)||1,tenantId:n.tenant_id,actorId:n.actor_id,actorType:n.actor_type,action:n.action,resourceType:n.resource_type,resourceId:n.resource_id,signature:n.signature,ipAddress:n.ip_address,userAgent:n.user_agent}))}async exportToSIEM(e){let a=this.db.prepare("SELECT * FROM audit_logs ORDER BY timestamp ASC").all().map(r=>{let n=JSON.parse(r.payload);return{...r,payload:n}});switch(e){case"cef":return a.map(r=>`CEF:0|WeShipYou|SDK|1.0|${r.action}|${r.resource_type} operation|5|src=${r.ip_address||"unknown"} rt=${new Date(r.timestamp).getTime()} externalId=${r.id} msg=${JSON.stringify(r.payload)}`).join(`
|
|
69
|
+
`);case"leef":return a.map(r=>`LEEF:2.0|WeShipYou|SDK|1.0|${r.action}|sev=5 cat=${r.resource_type} src=${r.ip_address||"unknown"} rt=${new Date(r.timestamp).toISOString()} msg=${JSON.stringify(r.payload)}`).join(`
|
|
70
|
+
`);default:return JSON.stringify(a,null,2)}}close(){this.db.close()}};var l=class{export(e,t){switch(t){case"cef":return this.toCEF(e);case"leef":return this.toLEEF(e);default:return JSON.stringify(e,null,2)}}toCEF(e){return e.map(t=>`CEF:0|WeShipYou|SDK|1.0|${t.action}|${t.resourceType} operation|5|src=${t.ipAddress||"unknown"} rt=${new Date(t.timestamp).getTime()} externalId=${t.eventId} msg=${JSON.stringify(t.payload)}`).join(`
|
|
71
|
+
`)}toLEEF(e){return e.map(t=>`LEEF:2.0|WeShipYou|SDK|1.0|${t.action}|sev=5 cat=${t.resourceType} src=${t.ipAddress||"unknown"} rt=${new Date(t.timestamp).toISOString()} msg=${JSON.stringify(t.payload)}`).join(`
|
|
72
|
+
`)}};import{randomUUID as te}from"crypto";var g=class{constructor(e,t,a){this.auditLog=e;this.tenantProvider=t;this.privateKey=a}async record(e){let t=this.tenantProvider.getCurrent(),a=new Date().toISOString(),r={eventId:te(),aggregateId:e.resourceId,type:`audit.${e.action}`,payload:e.payload,timestamp:a,version:1,tenantId:t?.tenantId||"default",actorId:t?.accountId||"system",actorType:"system",action:e.action,resourceType:e.resourceType,resourceId:e.resourceId,ipAddress:t?.metadata?.ipAddress,userAgent:t?.metadata?.userAgent};await this.auditLog.log(r,this.privateKey)}};var h=class{constructor(e){this.httpClient=e;this.active=!1}async inject(e,t=5e3){switch(this.active=!0,e){case"latency":await this.injectLatency(t);break;case"error":await this.injectErrors(t);break;case"timeout":await this.injectTimeout(t);break;case"crash":await this.injectCrash();break}this.active=!1}async recover(){this.active=!1}isActive(){return this.active}async injectLatency(e){let t=Date.now();for(;Date.now()-t<e&&this.active;)await new Promise(a=>setTimeout(a,100))}async injectErrors(e){throw new Error("Simulated chaos error")}async injectTimeout(e){await new Promise(()=>{})}async injectCrash(){process.exit(1)}};function R(i,e){return async(t,a,r)=>{try{let{tenantId:n,accountId:o}=await e(t),x={tenantId:n,accountId:o,permissions:t.user?.permissions||[],metadata:{ipAddress:t.ip,userAgent:t.get("User-Agent")}};await i.isolate(x,async()=>{r()})}catch(n){r(n)}}}import{randomUUID as re}from"crypto";var w=class{constructor(e,t,a,r="en-US"){this.username=e;this.password=t;this.payload=a;this.lang=r;this.type="CreateShipment"}},I=class{constructor(e,t,a){this.createShipmentUseCase=e;this.eventStore=t;this.tenantId=a}async execute(e){let a=await this.createShipmentUseCase.execute(e.username,e.password,e.payload,e.lang),r=a.id||a.shipmentId||a.uid,n=new j(re(),r,{accountId:e.payload.accountId,trackingNumber:a.trackingNumber});return await this.eventStore.append(r,[n]),{shipmentId:r,trackingNumber:a.trackingNumber}}};import{randomUUID as ae}from"crypto";var L=class{constructor(e,t,a){this.shipmentId=e;this.tenantId=t;this.accountId=a;this.type="CancelShipment"}},y=class{constructor(e,t){this.httpClient=e;this.eventStore=t}async execute(e){await this.httpClient.request({method:"POST",url:"/api/v1/shipments/cancel",body:{accountId:e.accountId,ids:[e.shipmentId]}});let t={eventId:ae(),aggregateId:e.shipmentId,type:"shipment.cancelled",payload:{accountId:e.accountId,tenantId:e.tenantId},timestamp:new Date().toISOString(),version:1};return await this.eventStore.append(e.shipmentId,[t]),{success:!0,shipmentId:e.shipmentId}}};import{randomUUID as J}from"crypto";var _=class{constructor(e,t,a,r="en-US"){this.username=e;this.password=t;this.payload=a;this.lang=r;this.type="ExecuteRecharge"}},S=class{constructor(e,t){this.executeRechargeUseCase=e;this.eventStore=t}async execute(e){let a=await this.executeRechargeUseCase.execute(e.username,e.password,e.payload,e.lang),r=J();return await this.eventStore.append(r,[{eventId:J(),aggregateId:r,type:"recharge.executed",payload:{accountUid:e.payload.accountUid,amount:e.payload.amount,provider:a.provider,status:a.status||"completed"},timestamp:new Date().toISOString(),version:1}]),{transactionId:r,status:a.status||"completed"}}};import{randomUUID as ne}from"crypto";var A=class{constructor(e,t,a,r,n="en-US"){this.username=e;this.password=t;this.shipmentId=a;this.payload=r;this.lang=n;this.type="UpdateShipment"}},f=class{constructor(e,t,a){this.updateShipmentUseCase=e;this.eventStore=t;this.tenantId=a}async execute(e){await this.updateShipmentUseCase.execute(e.username,e.password,e.shipmentId,e.payload,e.lang);let t=Object.keys(e.payload),a=new F(ne(),e.shipmentId,{accountId:e.payload.accountId||"",fields:t});return await this.eventStore.append(e.shipmentId,[a]),{shipmentId:e.shipmentId}}};var U=class{constructor(e,t){this.shipmentId=e;this.tenantId=t;this.type="GetShipment"}},E=class{constructor(e){this.readModel=e}async execute(e){return this.readModel.getById(e.shipmentId,e.tenantId)}};var D=class{constructor(e){this.filter=e;this.type="ListShipments"}},T=class{constructor(e){this.readModel=e}async execute(e){return this.readModel.query(e.filter)}};var P=class{constructor(e,t){this.shipmentId=e;this.sinceVersion=t;this.type="GetShipmentHistory"}},v=class{constructor(e){this.eventStore=e}async execute(e){return this.eventStore.getByAggregate(e.shipmentId,e.sinceVersion)}};function nt(i,e){let t=new s,a=new d(t),r=new m(e.postgresUrl),n=new X,o=new p(e.redisUrl,e.streamName,"projections",e.consumerName||"shipment-projection"),x=new c(r),O=new u,B=new l,G=new g(O,t,e.auditPrivateKey),W=new h(i.httpClient),K=R(t,async Y=>{let N=Y.headers?.authorization||"",b=N.startsWith("Bearer ")?N.slice(7):N,M="default",H="default";if(b)try{let C=JSON.parse(Buffer.from(b.split(".")[1],"base64url").toString());M=C.tenant_id||C.sub||"default",H=C.account_id||C.client_id||"default"}catch{}return{tenantId:M,accountId:H}});return{tenantProvider:t,schemaIsolation:a,readModel:r,projection:o,shipmentProjection:x,eventStore:n,auditLog:O,siemExporter:B,auditService:G,chaosTester:W,tenantMiddleware:K,commands:{createShipment:new I(i.createShipment,n),cancelShipment:new y(i.httpClient,n),executeRecharge:new S(i.executeRecharge,n),updateShipment:new f(new $(i.auth,new k(i.httpClient)),n)},queries:{getShipment:new E(r),listShipments:new T(r),getShipmentHistory:new v(n)}}}export{s as AsyncLocalStorageTenantContext,g as AuditLogService,L as CancelShipmentCommand,y as CancelShipmentHandler,w as CreateShipmentCommand,I as CreateShipmentHandler,_ as ExecuteRechargeCommand,S as ExecuteRechargeHandler,E as GetShipmentHandler,v as GetShipmentHistoryHandler,P as GetShipmentHistoryQuery,U as GetShipmentQuery,h as HttpChaosTester,u as ImmutableAuditLog,T as ListShipmentsHandler,D as ListShipmentsQuery,m as PostgresReadModel,p as RedisStreamsProjection,d as SchemaIsolationManager,c as ShipmentProjection,l as SiemExporter,A as UpdateShipmentCommand,f as UpdateShipmentHandler,nt as bootstrapEnterprise,R as createTenantMiddleware};
|
|
73
|
+
//# sourceMappingURL=enterprise.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/infrastructure/multi-tenant/tenant-context.impl.ts","../src/infrastructure/multi-tenant/schema-isolation.impl.ts","../src/infrastructure/cqrs/postgres-read-model.impl.ts","../src/infrastructure/cqrs/redis-streams-projection.impl.ts","../src/application/cqrs/projections/shipment-projection.ts","../src/infrastructure/audit/immutable-log.impl.ts","../src/infrastructure/audit/siem-exporter.impl.ts","../src/application/services/audit-log.service.ts","../src/infrastructure/chaos/litmus-chaos.impl.ts","../src/application/middlewares/tenant-context.middleware.ts","../src/application/cqrs/commands/create-shipment.command.ts","../src/application/cqrs/commands/cancel-shipment.command.ts","../src/application/cqrs/commands/execute-recharge.command.ts","../src/application/cqrs/commands/update-shipment.command.ts","../src/application/cqrs/queries/get-shipment.query.ts","../src/application/cqrs/queries/list-shipments.query.ts","../src/application/cqrs/queries/get-shipment-history.query.ts","../src/sdk/enterprise.ts"],"sourcesContent":["import { AsyncLocalStorage } from 'async_hooks';\nimport { ITenantContextProvider, TenantContext } from '../../domain/interfaces/tenant-context.interface';\n\nexport class AsyncLocalStorageTenantContext implements ITenantContextProvider {\n private storage = new AsyncLocalStorage<TenantContext>();\n\n getCurrent(): TenantContext | null {\n return this.storage.getStore() || null;\n }\n\n set(context: TenantContext): void {\n this.storage.enterWith(context);\n }\n\n clear(): void {\n this.storage.disable();\n }\n\n async isolate<T>(context: TenantContext, fn: () => Promise<T>): Promise<T> {\n return this.storage.run(context, fn);\n }\n}\n","import { ITenantContextProvider } from '../../domain/interfaces/tenant-context.interface';\n\nexport interface SchemaIsolationConfig {\n tenantId: string;\n schemaName: string;\n migrationStatements: string[];\n}\n\nexport class SchemaIsolationManager {\n private tenantProvider: ITenantContextProvider;\n private schemas: Map<string, SchemaIsolationConfig> = new Map();\n\n constructor(tenantProvider: ITenantContextProvider) {\n this.tenantProvider = tenantProvider;\n }\n\n register(tenantId: string, config: SchemaIsolationConfig): void {\n this.schemas.set(tenantId, config);\n }\n\n getCurrentSchema(): string | null {\n const context = this.tenantProvider.getCurrent();\n if (!context) return null;\n const config = this.schemas.get(context.tenantId);\n return config?.schemaName || null;\n }\n\n getSchemaFor(tenantId: string): string | null {\n return this.schemas.get(tenantId)?.schemaName || null;\n }\n\n deregister(tenantId: string): void {\n this.schemas.delete(tenantId);\n }\n}\n","import { Pool } from 'pg';\nimport { IReadModel, ShipmentReadModel } from '../../domain/interfaces/read-model.interface';\n\nexport class PostgresReadModel implements IReadModel {\n private pool: Pool;\n\n constructor(connectionString: string, poolConfig?: { max?: number; idleTimeoutMillis?: number; connectionTimeoutMillis?: number }) {\n this.pool = new Pool({ connectionString, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 10000, ...poolConfig });\n }\n\n async init(): Promise<void> {\n await this.pool.query(`\n CREATE TABLE IF NOT EXISTS shipment_read_model (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n account_id TEXT NOT NULL,\n status TEXT NOT NULL,\n tracking_number TEXT,\n total_value NUMERIC(10,2) NOT NULL,\n incoterms TEXT CHECK (incoterms IN ('DDU', 'DDP')),\n sender_name TEXT NOT NULL,\n recipient_name TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n metadata JSONB\n )\n `);\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS idx_shipment_tenant_account\n ON shipment_read_model (tenant_id, account_id)\n `);\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS idx_shipment_status\n ON shipment_read_model (status)\n `);\n await this.pool.query(`\n CREATE INDEX IF NOT EXISTS idx_shipment_created\n ON shipment_read_model (created_at)\n `);\n }\n\n async upsert(shipment: ShipmentReadModel): Promise<void> {\n await this.pool.query(`\n INSERT INTO shipment_read_model (\n id, tenant_id, account_id, status, tracking_number,\n total_value, incoterms, sender_name, recipient_name,\n created_at, updated_at, metadata\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)\n ON CONFLICT (id) DO UPDATE SET\n status = EXCLUDED.status,\n tracking_number = EXCLUDED.tracking_number,\n total_value = EXCLUDED.total_value,\n incoterms = EXCLUDED.incoterms,\n sender_name = EXCLUDED.sender_name,\n recipient_name = EXCLUDED.recipient_name,\n updated_at = NOW(),\n metadata = EXCLUDED.metadata\n `, [\n shipment.id, shipment.tenantId, shipment.accountId,\n shipment.status, shipment.trackingNumber,\n shipment.totalValue, shipment.incoterms,\n shipment.senderName, shipment.recipientName,\n shipment.createdAt, shipment.updatedAt,\n shipment.metadata ? JSON.stringify(shipment.metadata) : null\n ]);\n }\n\n async getById(id: string, tenantId: string): Promise<ShipmentReadModel | null> {\n const result = await this.pool.query(\n 'SELECT * FROM shipment_read_model WHERE id = $1 AND tenant_id = $2',\n [id, tenantId]\n );\n const row = result.rows[0];\n if (!row) return null;\n return {\n ...row,\n metadata: row.metadata || undefined\n };\n }\n\n async query(filters: {\n tenantId: string;\n accountId?: string;\n status?: string;\n limit?: number;\n offset?: number;\n }): Promise<ShipmentReadModel[]> {\n let query = 'SELECT * FROM shipment_read_model WHERE tenant_id = $1';\n const params: unknown[] = [filters.tenantId];\n let paramIndex = 2;\n\n if (filters.accountId) {\n query += ` AND account_id = $${paramIndex++}`;\n params.push(filters.accountId);\n }\n if (filters.status) {\n query += ` AND status = $${paramIndex++}`;\n params.push(filters.status);\n }\n\n query += ' ORDER BY created_at DESC';\n\n if (filters.limit) {\n query += ` LIMIT $${paramIndex++}`;\n params.push(filters.limit);\n }\n if (filters.offset) {\n query += ` OFFSET $${paramIndex++}`;\n params.push(filters.offset);\n }\n\n const result = await this.pool.query(query, params);\n return result.rows.map((row: Record<string, unknown>) => ({\n ...row,\n metadata: row.metadata || undefined\n })) as ShipmentReadModel[];\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n}\n","import { DomainEvent } from '../../domain/interfaces/event-store.interface';\nimport { IProjectionHandler } from '../../domain/interfaces/read-model.interface';\nimport { createClient, RedisClientType } from 'redis';\n\nexport class RedisStreamsProjection {\n private client: RedisClientType;\n private streamName: string;\n private groupName: string;\n private consumerName: string;\n\n constructor(\n redisUrl: string,\n streamName = 'weshipyou:events',\n groupName = 'projections',\n consumerName = 'shipment-projection'\n ) {\n this.client = createClient({ url: redisUrl }) as RedisClientType;\n this.streamName = streamName;\n this.groupName = groupName;\n this.consumerName = consumerName;\n }\n\n async init(): Promise<void> {\n await this.client.connect();\n try {\n await this.client.xGroupCreate(this.streamName, this.groupName, '$', { MKSTREAM: true });\n } catch (err: unknown) {\n const msg = (err as Error)?.message || '';\n if (!msg.includes('BUSYGROUP')) throw err;\n }\n }\n\n async publish(event: DomainEvent): Promise<void> {\n await this.client.xAdd(this.streamName, '*', {\n eventId: event.eventId,\n aggregateId: event.aggregateId,\n type: event.type,\n payload: JSON.stringify(event.payload),\n timestamp: event.timestamp,\n version: event.version.toString()\n });\n }\n\n async consume(handler: IProjectionHandler, timeout = 5000): Promise<void> {\n const result = await this.client.xReadGroup(\n this.groupName,\n this.consumerName,\n { key: this.streamName, id: '>' },\n { COUNT: 10, BLOCK: timeout }\n );\n\n if (!result || !result[0]?.messages) return;\n\n for (const msg of result[0].messages) {\n try {\n const event: DomainEvent = {\n eventId: msg.message.eventId as string,\n aggregateId: msg.message.aggregateId as string,\n type: msg.message.type as string,\n payload: JSON.parse(msg.message.payload as string),\n timestamp: msg.message.timestamp as string,\n version: parseInt(msg.message.version as string, 10)\n };\n await handler.handle(event);\n await this.client.xAck(this.streamName, this.groupName, msg.id);\n } catch (err) {\n await this.client.xAdd(`${this.streamName}:dead`, '*', msg.message);\n await this.client.xAck(this.streamName, this.groupName, msg.id);\n console.error('Projection consumer error — moved to dead-letter:', err);\n }\n }\n }\n\n async close(): Promise<void> {\n await this.client.quit();\n }\n}\n","import { DomainEvent } from '../../../domain/interfaces/event-store.interface';\nimport { IProjectionHandler, ShipmentReadModel, IReadModel } from '../../../domain/interfaces/read-model.interface';\n\nexport class ShipmentProjection implements IProjectionHandler {\n constructor(private readonly readModel: IReadModel) {}\n\n async handle(event: DomainEvent): Promise<void> {\n switch (event.type) {\n case 'shipment.created':\n await this.onShipmentCreated(event);\n break;\n case 'shipment.status_changed':\n await this.onStatusChanged(event);\n break;\n }\n }\n\n private async onShipmentCreated(event: DomainEvent): Promise<void> {\n const p = event.payload as Record<string, unknown>;\n const meta = event as unknown as Record<string, unknown>;\n\n const readModel: ShipmentReadModel = {\n id: event.aggregateId,\n tenantId: meta.tenantId as string || 'default',\n accountId: p.accountId as string,\n status: 'created',\n trackingNumber: p.trackingNumber as string | undefined,\n totalValue: Number(p.totalValue) || 0,\n incoterms: (p.incoterms as 'DDU' | 'DDP') || 'DDU',\n senderName: ((p.sender as Record<string, unknown>)?.name as string) || '',\n recipientName: ((p.recipient as Record<string, unknown>)?.name as string) || '',\n createdAt: event.timestamp,\n updatedAt: event.timestamp,\n metadata: { sourceEvent: event.eventId }\n };\n\n await this.readModel.upsert(readModel);\n }\n\n private async onStatusChanged(event: DomainEvent): Promise<void> {\n const p = event.payload as Record<string, unknown>;\n const meta = event as unknown as Record<string, unknown>;\n\n const existing = await this.readModel.getById(\n event.aggregateId,\n meta.tenantId as string || 'default'\n );\n\n if (!existing) return;\n\n await this.readModel.upsert({\n ...existing,\n status: p.status as string || existing.status,\n updatedAt: p.updatedAt as string || event.timestamp,\n metadata: {\n ...existing.metadata,\n previousStatus: p.previousStatus,\n lastEventId: event.eventId\n }\n });\n }\n}\n","import { createHmac } from 'crypto';\nimport Database from 'better-sqlite3';\nimport { IAuditLogService, AuditLogEntry } from '../../domain/interfaces/audit-log.interface';\n\nexport class ImmutableAuditLog implements IAuditLogService {\n private db: Database.Database;\n private readonly algorithm = 'sha256';\n\n constructor(dbPath = ':memory:') {\n this.db = new Database(dbPath);\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS audit_logs (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n aggregate_id TEXT NOT NULL DEFAULT '',\n type TEXT NOT NULL DEFAULT '',\n actor_id TEXT NOT NULL,\n actor_type TEXT NOT NULL,\n action TEXT NOT NULL,\n resource_type TEXT NOT NULL,\n resource_id TEXT NOT NULL,\n payload TEXT NOT NULL,\n signature TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n ip_address TEXT,\n user_agent TEXT,\n version INTEGER DEFAULT 1\n )\n `);\n this.db.exec('CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id, resource_type, resource_id)');\n this.db.exec('CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_logs(timestamp)');\n }\n\n async log(entry: Omit<AuditLogEntry, 'signature'>, privateKey: string): Promise<void> {\n const canonical = JSON.stringify({\n eventId: entry.eventId,\n aggregateId: entry.aggregateId,\n type: entry.type,\n payload: entry.payload,\n timestamp: entry.timestamp,\n actorId: entry.actorId,\n action: entry.action,\n resourceType: entry.resourceType,\n resourceId: entry.resourceId\n });\n\n const signature = createHmac(this.algorithm, privateKey)\n .update(canonical)\n .digest('hex');\n\n const insert = this.db.prepare(`\n INSERT INTO audit_logs (\n id, tenant_id, aggregate_id, type, actor_id, actor_type, action,\n resource_type, resource_id, payload, signature,\n timestamp, ip_address, user_agent, version\n ) VALUES (\n @id, @tenantId, @aggregateId, @type, @actorId, @actorType, @action,\n @resourceType, @resourceId, @payloadText, @signature,\n @timestamp, @ipAddress, @userAgent, @version\n )\n `);\n\n insert.run({\n id: entry.eventId,\n tenantId: entry.tenantId,\n aggregateId: entry.aggregateId,\n type: entry.type,\n actorId: entry.actorId,\n actorType: entry.actorType,\n action: entry.action,\n resourceType: entry.resourceType,\n resourceId: entry.resourceId,\n payloadText: JSON.stringify(entry.payload),\n version: entry.version,\n signature,\n timestamp: entry.timestamp,\n ipAddress: entry.ipAddress || null,\n userAgent: entry.userAgent || null\n });\n }\n\n verify(entry: AuditLogEntry, key: string): boolean {\n const canonical = JSON.stringify({\n eventId: entry.eventId,\n aggregateId: entry.aggregateId,\n type: entry.type,\n payload: entry.payload,\n timestamp: entry.timestamp,\n actorId: entry.actorId,\n action: entry.action,\n resourceType: entry.resourceType,\n resourceId: entry.resourceId\n });\n\n const expected = createHmac(this.algorithm, key)\n .update(canonical)\n .digest('hex');\n return expected === entry.signature;\n }\n\n async query(filters: {\n tenantId: string;\n resourceType?: string;\n resourceId?: string;\n since?: string;\n until?: string;\n }): Promise<AuditLogEntry[]> {\n let query = 'SELECT * FROM audit_logs WHERE tenant_id = ?';\n const params: unknown[] = [filters.tenantId];\n\n if (filters.resourceType) {\n query += ' AND resource_type = ?';\n params.push(filters.resourceType);\n }\n if (filters.resourceId) {\n query += ' AND resource_id = ?';\n params.push(filters.resourceId);\n }\n if (filters.since) {\n query += ' AND timestamp >= ?';\n params.push(filters.since);\n }\n if (filters.until) {\n query += ' AND timestamp <= ?';\n params.push(filters.until);\n }\n\n query += ' ORDER BY timestamp DESC';\n\n const rows = this.db.prepare(query).all(...params) as Array<Record<string, unknown>>;\n return rows.map(row => ({\n eventId: row.id as string,\n aggregateId: row.aggregate_id as string,\n type: row.type as string,\n payload: JSON.parse(row.payload as string),\n timestamp: row.timestamp as string,\n version: Number(row.version) || 1,\n tenantId: row.tenant_id as string,\n actorId: row.actor_id as string,\n actorType: row.actor_type as 'user' | 'system' | 'api_key',\n action: row.action as string,\n resourceType: row.resource_type as string,\n resourceId: row.resource_id as string,\n signature: row.signature as string,\n ipAddress: row.ip_address as string | undefined,\n userAgent: row.user_agent as string | undefined\n })) as AuditLogEntry[];\n }\n\n async exportToSIEM(format: 'json' | 'cef' | 'leef'): Promise<string> {\n const allLogs = this.db.prepare('SELECT * FROM audit_logs ORDER BY timestamp ASC')\n .all() as Array<Record<string, unknown>>;\n\n const parsed = allLogs.map(log => {\n const p = JSON.parse(log.payload as string);\n return { ...log, payload: p } as Record<string, unknown>;\n });\n\n switch (format) {\n case 'cef':\n return parsed.map(log =>\n `CEF:0|WeShipYou|SDK|1.0|${log.action}|${log.resource_type} operation|5|` +\n `src=${log.ip_address || 'unknown'} ` +\n `rt=${new Date(log.timestamp as string).getTime()} ` +\n `externalId=${log.id} ` +\n `msg=${JSON.stringify(log.payload)}`\n ).join('\\n');\n\n case 'leef':\n return parsed.map(log =>\n `LEEF:2.0|WeShipYou|SDK|1.0|${log.action}|` +\n `sev=5 cat=${log.resource_type} src=${log.ip_address || 'unknown'} ` +\n `rt=${new Date(log.timestamp as string).toISOString()} ` +\n `msg=${JSON.stringify(log.payload)}`\n ).join('\\n');\n\n default:\n return JSON.stringify(parsed, null, 2);\n }\n }\n\n close(): void {\n this.db.close();\n }\n}\n","import { AuditLogEntry } from '../../domain/interfaces/audit-log.interface';\n\nexport type SiemFormat = 'json' | 'cef' | 'leef';\n\nexport class SiemExporter {\n export(entries: AuditLogEntry[], format: SiemFormat): string {\n switch (format) {\n case 'cef':\n return this.toCEF(entries);\n case 'leef':\n return this.toLEEF(entries);\n default:\n return JSON.stringify(entries, null, 2);\n }\n }\n\n private toCEF(entries: AuditLogEntry[]): string {\n return entries.map(e =>\n `CEF:0|WeShipYou|SDK|1.0|${e.action}|${e.resourceType} operation|5|` +\n `src=${e.ipAddress || 'unknown'} ` +\n `rt=${new Date(e.timestamp).getTime()} ` +\n `externalId=${e.eventId} ` +\n `msg=${JSON.stringify(e.payload)}`\n ).join('\\n');\n }\n\n private toLEEF(entries: AuditLogEntry[]): string {\n return entries.map(e =>\n `LEEF:2.0|WeShipYou|SDK|1.0|${e.action}|` +\n `sev=5 cat=${e.resourceType} src=${e.ipAddress || 'unknown'} ` +\n `rt=${new Date(e.timestamp).toISOString()} ` +\n `msg=${JSON.stringify(e.payload)}`\n ).join('\\n');\n }\n}\n","import { randomUUID } from 'crypto';\nimport { IAuditLogService, AuditLogEntry } from '../../domain/interfaces/audit-log.interface';\nimport { ITenantContextProvider } from '../../domain/interfaces/tenant-context.interface';\n\nexport class AuditLogService {\n constructor(\n private readonly auditLog: IAuditLogService,\n private readonly tenantProvider: ITenantContextProvider,\n private readonly privateKey: string\n ) {}\n\n async record(partial: {\n action: string;\n resourceType: string;\n resourceId: string;\n payload: Record<string, unknown>;\n }): Promise<void> {\n const context = this.tenantProvider.getCurrent();\n const timestamp = new Date().toISOString();\n\n const entry: Omit<AuditLogEntry, 'signature'> = {\n eventId: randomUUID(),\n aggregateId: partial.resourceId,\n type: `audit.${partial.action}`,\n payload: partial.payload,\n timestamp,\n version: 1,\n tenantId: context?.tenantId || 'default',\n actorId: context?.accountId || 'system',\n actorType: 'system',\n action: partial.action,\n resourceType: partial.resourceType,\n resourceId: partial.resourceId,\n ipAddress: context?.metadata?.ipAddress as string | undefined,\n userAgent: context?.metadata?.userAgent as string | undefined\n };\n\n await this.auditLog.log(entry, this.privateKey);\n }\n}\n","import { IChaosTester, ChaosAttack } from '../../domain/interfaces/chaos-tester.interface';\nimport { IHttpClient } from '../../domain/interfaces/http-client.interface';\n\nexport class HttpChaosTester implements IChaosTester {\n private active = false;\n\n constructor(private readonly httpClient: IHttpClient) {}\n\n async inject(attack: ChaosAttack, durationMs = 5000): Promise<void> {\n this.active = true;\n\n switch (attack) {\n case 'latency':\n await this.injectLatency(durationMs);\n break;\n case 'error':\n await this.injectErrors(durationMs);\n break;\n case 'timeout':\n await this.injectTimeout(durationMs);\n break;\n case 'crash':\n await this.injectCrash();\n break;\n }\n\n this.active = false;\n }\n\n async recover(): Promise<void> {\n this.active = false;\n }\n\n isActive(): boolean {\n return this.active;\n }\n\n private async injectLatency(durationMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < durationMs && this.active) {\n await new Promise(res => setTimeout(res, 100));\n }\n }\n\n private async injectErrors(_durationMs: number): Promise<void> {\n throw new Error('Simulated chaos error');\n }\n\n private async injectTimeout(_durationMs: number): Promise<void> {\n await new Promise(() => {}); // Never resolves\n }\n\n private async injectCrash(): Promise<void> {\n process.exit(1);\n }\n}\n","import { Request, RequestHandler } from 'express';\nimport { ITenantContextProvider } from '../../domain/interfaces/tenant-context.interface';\n\ninterface RequestWithUser extends Request {\n user?: { permissions?: string[] };\n}\n\nexport interface TenantExtractor {\n (req: Request): Promise<{ tenantId: string; accountId: string }>;\n}\n\nexport function createTenantMiddleware(\n tenantProvider: ITenantContextProvider,\n extractTenant: TenantExtractor\n): RequestHandler {\n return async (req, res, next) => {\n try {\n const { tenantId, accountId } = await extractTenant(req);\n\n const context = {\n tenantId,\n accountId,\n permissions: (req as RequestWithUser).user?.permissions || [],\n metadata: {\n ipAddress: req.ip,\n userAgent: req.get('User-Agent')\n }\n };\n\n await tenantProvider.isolate(context, async () => {\n next();\n });\n } catch (err) {\n next(err);\n }\n };\n}\n","import { randomUUID } from 'crypto';\nimport { ICommand, ICommandHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IShipmentRequest } from '../../../domain/interfaces/shipment.interface';\nimport { IEventStore } from '../../../domain/interfaces/event-store.interface';\nimport { ShipmentCreatedEvent } from '../../../domain/events/shipment.events';\nimport { CreateShipmentUseCase } from '../../use-cases/create-shipment.use-case';\nimport { AcceptLanguage } from '../../../domain/interfaces/language.enum';\nimport { ShipmentService } from '../../services/shipment.service';\n\nexport interface CreateShipmentResult {\n shipmentId: string;\n trackingNumber?: string;\n}\n\nexport class CreateShipmentCommand implements ICommand<CreateShipmentResult> {\n readonly type = 'CreateShipment';\n\n constructor(\n public readonly username: string,\n public readonly password: string,\n public readonly payload: IShipmentRequest,\n public readonly lang: AcceptLanguage = AcceptLanguage.EN_US\n ) {}\n}\n\nexport class CreateShipmentHandler implements ICommandHandler<CreateShipmentCommand, CreateShipmentResult> {\n constructor(\n private readonly createShipmentUseCase: CreateShipmentUseCase,\n private readonly eventStore: IEventStore,\n private readonly tenantId?: string\n ) {}\n\n async execute(command: CreateShipmentCommand): Promise<CreateShipmentResult> {\n const result = await this.createShipmentUseCase.execute(\n command.username,\n command.password,\n command.payload,\n command.lang\n );\n\n const data = result as Record<string, unknown>;\n const shipmentId = (data.id || data.shipmentId || data.uid) as string;\n\n const event = new ShipmentCreatedEvent(\n randomUUID(),\n shipmentId,\n {\n accountId: command.payload.accountId,\n trackingNumber: data.trackingNumber as string | undefined\n }\n );\n\n await this.eventStore.append(shipmentId, [event]);\n\n return {\n shipmentId,\n trackingNumber: data.trackingNumber as string | undefined\n };\n }\n}\n","import { randomUUID } from 'crypto';\nimport { ICommand, ICommandHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IEventStore, DomainEvent } from '../../../domain/interfaces/event-store.interface';\nimport { IHttpClient } from '../../../domain/interfaces/http-client.interface';\n\nexport interface CancelShipmentResult {\n success: boolean;\n shipmentId: string;\n}\n\nexport class CancelShipmentCommand implements ICommand<CancelShipmentResult> {\n readonly type = 'CancelShipment';\n\n constructor(\n public readonly shipmentId: string,\n public readonly tenantId: string,\n public readonly accountId: string\n ) {}\n}\n\nexport class CancelShipmentHandler implements ICommandHandler<CancelShipmentCommand, CancelShipmentResult> {\n constructor(\n private readonly httpClient: IHttpClient,\n private readonly eventStore: IEventStore\n ) {}\n\n async execute(command: CancelShipmentCommand): Promise<CancelShipmentResult> {\n await this.httpClient.request({\n method: 'POST',\n url: `/api/v1/shipments/cancel`,\n body: { accountId: command.accountId, ids: [command.shipmentId] }\n });\n\n const cancelEvent: DomainEvent = {\n eventId: randomUUID(),\n aggregateId: command.shipmentId,\n type: 'shipment.cancelled',\n payload: { accountId: command.accountId, tenantId: command.tenantId },\n timestamp: new Date().toISOString(),\n version: 1\n };\n\n await this.eventStore.append(command.shipmentId, [cancelEvent]);\n\n return { success: true, shipmentId: command.shipmentId };\n }\n}\n","import { randomUUID } from 'crypto';\nimport { ICommand, ICommandHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IEventStore } from '../../../domain/interfaces/event-store.interface';\nimport { ExecuteRechargeUseCase } from '../../use-cases/execute-recharge.use-case';\nimport { AcceptLanguage } from '../../../domain/interfaces/language.enum';\nimport { CreateRechargeRequest } from '../../../domain/interfaces/mobile-recharge.interface';\n\nexport interface ExecuteRechargeResult {\n transactionId: string;\n status: string;\n}\n\nexport class ExecuteRechargeCommand implements ICommand<ExecuteRechargeResult> {\n readonly type = 'ExecuteRecharge';\n\n constructor(\n public readonly username: string,\n public readonly password: string,\n public readonly payload: CreateRechargeRequest,\n public readonly lang: AcceptLanguage = AcceptLanguage.EN_US\n ) {}\n}\n\nexport class ExecuteRechargeHandler implements ICommandHandler<ExecuteRechargeCommand, ExecuteRechargeResult> {\n constructor(\n private readonly executeRechargeUseCase: ExecuteRechargeUseCase,\n private readonly eventStore: IEventStore\n ) {}\n\n async execute(command: ExecuteRechargeCommand): Promise<ExecuteRechargeResult> {\n const result = await this.executeRechargeUseCase.execute(\n command.username,\n command.password,\n command.payload,\n command.lang\n );\n\n const data = result as Record<string, unknown>;\n const transactionId = randomUUID();\n\n await this.eventStore.append(transactionId, [{\n eventId: randomUUID(),\n aggregateId: transactionId,\n type: 'recharge.executed',\n payload: {\n accountUid: command.payload.accountUid,\n amount: command.payload.amount,\n provider: data.provider,\n status: data.status || 'completed'\n },\n timestamp: new Date().toISOString(),\n version: 1\n }]);\n\n return {\n transactionId,\n status: (data.status as string) || 'completed'\n };\n }\n}\n","import { randomUUID } from 'crypto';\nimport { ICommand, ICommandHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IShipmentRequest } from '../../../domain/interfaces/shipment.interface';\nimport { IEventStore } from '../../../domain/interfaces/event-store.interface';\nimport { ShipmentUpdatedEvent } from '../../../domain/events/shipment.events';\nimport { UpdateShipmentUseCase } from '../../use-cases/update-shipment.use-case';\nimport { AcceptLanguage } from '../../../domain/interfaces/language.enum';\n\nexport interface UpdateShipmentResult {\n shipmentId: string;\n}\n\nexport class UpdateShipmentCommand implements ICommand<UpdateShipmentResult> {\n readonly type = 'UpdateShipment';\n\n constructor(\n public readonly username: string,\n public readonly password: string,\n public readonly shipmentId: string,\n public readonly payload: Partial<IShipmentRequest>,\n public readonly lang: AcceptLanguage = AcceptLanguage.EN_US\n ) {}\n}\n\nexport class UpdateShipmentHandler implements ICommandHandler<UpdateShipmentCommand, UpdateShipmentResult> {\n constructor(\n private readonly updateShipmentUseCase: UpdateShipmentUseCase,\n private readonly eventStore: IEventStore,\n private readonly tenantId?: string\n ) {}\n\n async execute(command: UpdateShipmentCommand): Promise<UpdateShipmentResult> {\n await this.updateShipmentUseCase.execute(\n command.username,\n command.password,\n command.shipmentId,\n command.payload,\n command.lang\n );\n\n const updatedFields = Object.keys(command.payload);\n\n const event = new ShipmentUpdatedEvent(\n randomUUID(),\n command.shipmentId,\n {\n accountId: command.payload.accountId || '',\n fields: updatedFields\n }\n );\n\n await this.eventStore.append(command.shipmentId, [event]);\n\n return {\n shipmentId: command.shipmentId\n };\n }\n}\n","import { IQuery, IQueryHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IReadModel, ShipmentReadModel } from '../../../domain/interfaces/read-model.interface';\n\nexport class GetShipmentQuery implements IQuery<ShipmentReadModel | null> {\n readonly type = 'GetShipment';\n\n constructor(\n public readonly shipmentId: string,\n public readonly tenantId: string\n ) {}\n}\n\nexport class GetShipmentHandler implements IQueryHandler<GetShipmentQuery, ShipmentReadModel | null> {\n constructor(private readonly readModel: IReadModel) {}\n\n async execute(query: GetShipmentQuery): Promise<ShipmentReadModel | null> {\n return this.readModel.getById(query.shipmentId, query.tenantId);\n }\n}\n","import { IQuery, IQueryHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IReadModel, ShipmentReadModel } from '../../../domain/interfaces/read-model.interface';\n\nexport interface ListShipmentsFilter {\n tenantId: string;\n accountId?: string;\n status?: string;\n limit?: number;\n offset?: number;\n}\n\nexport class ListShipmentsQuery implements IQuery<ShipmentReadModel[]> {\n readonly type = 'ListShipments';\n\n constructor(public readonly filter: ListShipmentsFilter) {}\n}\n\nexport class ListShipmentsHandler implements IQueryHandler<ListShipmentsQuery, ShipmentReadModel[]> {\n constructor(private readonly readModel: IReadModel) {}\n\n async execute(query: ListShipmentsQuery): Promise<ShipmentReadModel[]> {\n return this.readModel.query(query.filter);\n }\n}\n","import { IQuery, IQueryHandler } from '../../../domain/interfaces/cqrs.interface';\nimport { IEventStore, DomainEvent } from '../../../domain/interfaces/event-store.interface';\n\nexport class GetShipmentHistoryQuery implements IQuery<DomainEvent[]> {\n readonly type = 'GetShipmentHistory';\n\n constructor(\n public readonly shipmentId: string,\n public readonly sinceVersion?: number\n ) {}\n}\n\nexport class GetShipmentHistoryHandler implements IQueryHandler<GetShipmentHistoryQuery, DomainEvent[]> {\n constructor(private readonly eventStore: IEventStore) {}\n\n async execute(query: GetShipmentHistoryQuery): Promise<DomainEvent[]> {\n return this.eventStore.getByAggregate(query.shipmentId, query.sinceVersion);\n }\n}\n","import { Services } from '../infrastructure/di/bootstrap';\nimport { AsyncLocalStorageTenantContext } from '../infrastructure/multi-tenant/tenant-context.impl';\nimport { SchemaIsolationManager } from '../infrastructure/multi-tenant/schema-isolation.impl';\nimport { PostgresReadModel } from '../infrastructure/cqrs/postgres-read-model.impl';\nimport { RedisStreamsProjection } from '../infrastructure/cqrs/redis-streams-projection.impl';\nimport { ShipmentProjection } from '../application/cqrs/projections/shipment-projection';\nimport { ImmutableAuditLog } from '../infrastructure/audit/immutable-log.impl';\nimport { SiemExporter } from '../infrastructure/audit/siem-exporter.impl';\nimport { AuditLogService } from '../application/services/audit-log.service';\nimport { HttpChaosTester } from '../infrastructure/chaos/litmus-chaos.impl';\nimport { createTenantMiddleware } from '../application/middlewares/tenant-context.middleware';\nimport { SqliteEventStore } from '../infrastructure/event-store/sqlite-event-store.impl';\nimport { EnterpriseConfig } from '../domain/types/enterprise-config.types';\nimport { CreateShipmentHandler } from '../application/cqrs/commands/create-shipment.command';\nimport { CancelShipmentHandler } from '../application/cqrs/commands/cancel-shipment.command';\nimport { ExecuteRechargeHandler } from '../application/cqrs/commands/execute-recharge.command';\nimport { UpdateShipmentHandler } from '../application/cqrs/commands/update-shipment.command';\nimport { UpdateShipmentUseCase } from '../application/use-cases/update-shipment.use-case';\nimport { ShipmentService } from '../application/services/shipment.service';\nimport { GetShipmentHandler } from '../application/cqrs/queries/get-shipment.query';\nimport { ListShipmentsHandler } from '../application/cqrs/queries/list-shipments.query';\nimport { GetShipmentHistoryHandler } from '../application/cqrs/queries/get-shipment-history.query';\n\nimport type { ITenantContextProvider } from '../domain/interfaces/tenant-context.interface';\nimport type { IReadModel } from '../domain/interfaces/read-model.interface';\nimport type { IAuditLogService } from '../domain/interfaces/audit-log.interface';\n\nexport interface EnterpriseServices {\n tenantProvider: ITenantContextProvider;\n schemaIsolation: SchemaIsolationManager;\n readModel: IReadModel;\n projection: RedisStreamsProjection;\n shipmentProjection: ShipmentProjection;\n eventStore: SqliteEventStore;\n auditLog: IAuditLogService;\n siemExporter: SiemExporter;\n auditService: AuditLogService;\n chaosTester: HttpChaosTester;\n tenantMiddleware: ReturnType<typeof createTenantMiddleware>;\n commands: {\n createShipment: CreateShipmentHandler;\n cancelShipment: CancelShipmentHandler;\n executeRecharge: ExecuteRechargeHandler;\n updateShipment: UpdateShipmentHandler;\n };\n queries: {\n getShipment: GetShipmentHandler;\n listShipments: ListShipmentsHandler;\n getShipmentHistory: GetShipmentHistoryHandler;\n };\n}\n\nexport function bootstrapEnterprise(\n base: Services,\n config: EnterpriseConfig\n): EnterpriseServices {\n const tenantProvider = new AsyncLocalStorageTenantContext();\n const schemaIsolation = new SchemaIsolationManager(tenantProvider);\n const readModel = new PostgresReadModel(config.postgresUrl);\n const eventStore = new SqliteEventStore();\n const projection = new RedisStreamsProjection(\n config.redisUrl,\n config.streamName,\n 'projections',\n config.consumerName || 'shipment-projection'\n );\n const shipmentProjection = new ShipmentProjection(readModel);\n const auditLog = new ImmutableAuditLog();\n const siemExporter = new SiemExporter();\n const auditService = new AuditLogService(auditLog, tenantProvider, config.auditPrivateKey);\n const chaosTester = new HttpChaosTester(base.httpClient);\n\n const tenantMiddleware = createTenantMiddleware(tenantProvider, async (req) => {\n const authHeader = (req.headers?.['authorization'] as string) || '';\n const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : authHeader;\n let tenantId = 'default';\n let accountId = 'default';\n if (token) {\n try {\n const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString());\n tenantId = payload.tenant_id || payload.sub || 'default';\n accountId = payload.account_id || payload.client_id || 'default';\n } catch {}\n }\n return { tenantId, accountId };\n });\n\n return {\n tenantProvider,\n schemaIsolation,\n readModel,\n projection,\n shipmentProjection,\n eventStore,\n auditLog,\n siemExporter,\n auditService,\n chaosTester,\n tenantMiddleware,\n commands: {\n createShipment: new CreateShipmentHandler(base.createShipment, eventStore),\n cancelShipment: new CancelShipmentHandler(base.httpClient, eventStore),\n executeRecharge: new ExecuteRechargeHandler(base.executeRecharge, eventStore),\n updateShipment: new UpdateShipmentHandler(\n new UpdateShipmentUseCase(base.auth, new ShipmentService(base.httpClient)),\n eventStore\n )\n },\n queries: {\n getShipment: new GetShipmentHandler(readModel),\n listShipments: new ListShipmentsHandler(readModel),\n getShipmentHistory: new GetShipmentHistoryHandler(eventStore)\n }\n };\n}\n\nexport { AsyncLocalStorageTenantContext } from '../infrastructure/multi-tenant/tenant-context.impl';\nexport { SchemaIsolationManager } from '../infrastructure/multi-tenant/schema-isolation.impl';\nexport { PostgresReadModel } from '../infrastructure/cqrs/postgres-read-model.impl';\nexport type { ShipmentReadModel } from '../domain/interfaces/read-model.interface';\nexport { RedisStreamsProjection } from '../infrastructure/cqrs/redis-streams-projection.impl';\nexport { ShipmentProjection } from '../application/cqrs/projections/shipment-projection';\nexport { ImmutableAuditLog } from '../infrastructure/audit/immutable-log.impl';\nexport { SiemExporter } from '../infrastructure/audit/siem-exporter.impl';\nexport { AuditLogService } from '../application/services/audit-log.service';\nexport { HttpChaosTester } from '../infrastructure/chaos/litmus-chaos.impl';\nexport { createTenantMiddleware } from '../application/middlewares/tenant-context.middleware';\nexport type { TenantExtractor } from '../application/middlewares/tenant-context.middleware';\nexport type { TenantContext, ITenantContextProvider } from '../domain/interfaces/tenant-context.interface';\nexport type { AuditLogEntry, IAuditLogService } from '../domain/interfaces/audit-log.interface';\nexport type { IChaosTester, ChaosAttack } from '../domain/interfaces/chaos-tester.interface';\nexport type { IReadModel, IProjectionHandler } from '../domain/interfaces/read-model.interface';\nexport type { TenantConfig } from '../domain/types/tenant.types';\nexport type { EnterpriseConfig } from '../domain/types/enterprise-config.types';\nexport type { ICommand, ICommandHandler, IQuery, IQueryHandler } from '../domain/interfaces/cqrs.interface';\nexport { CreateShipmentCommand, CreateShipmentHandler } from '../application/cqrs/commands/create-shipment.command';\nexport type { CreateShipmentResult } from '../application/cqrs/commands/create-shipment.command';\nexport { CancelShipmentCommand, CancelShipmentHandler } from '../application/cqrs/commands/cancel-shipment.command';\nexport type { CancelShipmentResult } from '../application/cqrs/commands/cancel-shipment.command';\nexport { UpdateShipmentCommand, UpdateShipmentHandler } from '../application/cqrs/commands/update-shipment.command';\nexport type { UpdateShipmentResult } from '../application/cqrs/commands/update-shipment.command';\nexport { ExecuteRechargeCommand, ExecuteRechargeHandler } from '../application/cqrs/commands/execute-recharge.command';\nexport type { ExecuteRechargeResult } from '../application/cqrs/commands/execute-recharge.command';\nexport { GetShipmentQuery, GetShipmentHandler } from '../application/cqrs/queries/get-shipment.query';\nexport { ListShipmentsQuery, ListShipmentsHandler } from '../application/cqrs/queries/list-shipments.query';\nexport { GetShipmentHistoryQuery, GetShipmentHistoryHandler } from '../application/cqrs/queries/get-shipment-history.query';\n"],"mappings":"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","names":["AsyncLocalStorage","AsyncLocalStorageTenantContext","context","fn","SchemaIsolationManager","tenantProvider","tenantId","config","context","Pool","PostgresReadModel","connectionString","poolConfig","shipment","id","tenantId","row","filters","query","params","paramIndex","createClient","RedisStreamsProjection","redisUrl","streamName","groupName","consumerName","err","event","handler","timeout","result","msg","ShipmentProjection","readModel","event","p","meta","existing","createHmac","Database","ImmutableAuditLog","dbPath","entry","privateKey","canonical","signature","key","filters","query","params","row","format","parsed","log","p","SiemExporter","entries","format","e","randomUUID","AuditLogService","auditLog","tenantProvider","privateKey","partial","context","timestamp","entry","HttpChaosTester","httpClient","attack","durationMs","start","res","_durationMs","createTenantMiddleware","tenantProvider","extractTenant","req","res","next","tenantId","accountId","context","err","randomUUID","CreateShipmentCommand","username","password","payload","lang","CreateShipmentHandler","createShipmentUseCase","eventStore","tenantId","command","data","shipmentId","event","ShipmentCreatedEvent","randomUUID","randomUUID","CancelShipmentCommand","shipmentId","tenantId","accountId","CancelShipmentHandler","httpClient","eventStore","command","cancelEvent","randomUUID","ExecuteRechargeCommand","username","password","payload","lang","ExecuteRechargeHandler","executeRechargeUseCase","eventStore","command","data","transactionId","randomUUID","randomUUID","UpdateShipmentCommand","username","password","shipmentId","payload","lang","UpdateShipmentHandler","updateShipmentUseCase","eventStore","tenantId","command","updatedFields","event","ShipmentUpdatedEvent","randomUUID","GetShipmentQuery","shipmentId","tenantId","GetShipmentHandler","readModel","query","ListShipmentsQuery","filter","ListShipmentsHandler","readModel","query","GetShipmentHistoryQuery","shipmentId","sinceVersion","GetShipmentHistoryHandler","eventStore","query","bootstrapEnterprise","base","config","tenantProvider","AsyncLocalStorageTenantContext","schemaIsolation","SchemaIsolationManager","readModel","PostgresReadModel","eventStore","SqliteEventStore","projection","RedisStreamsProjection","shipmentProjection","ShipmentProjection","auditLog","ImmutableAuditLog","siemExporter","SiemExporter","auditService","AuditLogService","chaosTester","HttpChaosTester","tenantMiddleware","createTenantMiddleware","req","authHeader","token","tenantId","accountId","payload","CreateShipmentHandler","CancelShipmentHandler","ExecuteRechargeHandler","UpdateShipmentHandler","UpdateShipmentUseCase","ShipmentService","GetShipmentHandler","ListShipmentsHandler","GetShipmentHistoryHandler"]}
|