@rytass/wms-module-graphql 0.4.0 → 0.6.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.
Files changed (40) hide show
  1. package/README.md +56 -3
  2. package/adapters/event-emitter.d.ts +29 -0
  3. package/adapters/event-emitter.js +41 -0
  4. package/adapters/member-base.d.ts +11 -0
  5. package/adapters/member-base.js +17 -1
  6. package/docs/README.md +3 -0
  7. package/docs/api-reference.md +60 -0
  8. package/docs/events.md +500 -0
  9. package/docs/integration-guide.md +111 -2
  10. package/index.cjs.js +154 -1
  11. package/index.d.ts +2 -0
  12. package/index.js +3 -0
  13. package/lib/events/index.d.ts +5 -0
  14. package/lib/events/operation-result-map.d.ts +77 -0
  15. package/lib/events/typed-maps.d.ts +73 -0
  16. package/lib/events/wms-mutation-event.constants.d.ts +12 -0
  17. package/lib/events/wms-mutation-event.constants.js +4 -0
  18. package/lib/events/wms-mutation-event.decorator.d.ts +15 -0
  19. package/lib/events/wms-mutation-event.decorator.js +20 -0
  20. package/lib/events/wms-mutation.interceptor.d.ts +21 -0
  21. package/lib/events/wms-mutation.interceptor.js +90 -0
  22. package/lib/graphql.module.d.ts +24 -5
  23. package/lib/graphql.module.js +16 -2
  24. package/lib/mutations/allocate-inventory-order.mutation.js +5 -0
  25. package/lib/mutations/hold-inventory-order.mutation.js +5 -0
  26. package/lib/mutations/loader.mutation.js +7 -0
  27. package/lib/mutations/location.mutation.js +4 -0
  28. package/lib/mutations/material.mutation.js +4 -0
  29. package/lib/mutations/merge-batch.mutation.js +3 -0
  30. package/lib/mutations/quality-inspection-order.mutation.js +3 -0
  31. package/lib/mutations/receive-inventory-order.mutation.js +5 -0
  32. package/lib/mutations/reclassify-inventory-order.mutation.js +3 -0
  33. package/lib/mutations/scrape-order.mutation.js +3 -0
  34. package/lib/mutations/ship-inventory-order.mutation.js +6 -0
  35. package/lib/mutations/split-batch.mutation.js +3 -0
  36. package/lib/mutations/transfer-customer-order.mutation.js +5 -0
  37. package/lib/mutations/transfer-order.mutation.js +6 -0
  38. package/lib/mutations/transfer-vendor-order.mutation.js +5 -0
  39. package/lib/mutations/warehouse-map.mutation.js +3 -0
  40. package/package.json +13 -3
package/index.cjs.js CHANGED
@@ -10,6 +10,7 @@ var typeorm = require('typeorm');
10
10
  var DataLoader = require('dataloader');
11
11
  var graphql = require('@nestjs/graphql');
12
12
  var core = require('@nestjs/core');
13
+ var rxjs = require('rxjs');
13
14
  var wmsBaseNestjsModule = require('@rytass/wms-base-nestjs-module');
14
15
  var warehouseMap_entity = require('@rytass/wms-base-nestjs-module/models/warehouse-map.entity');
15
16
 
@@ -304,6 +305,105 @@ exports.WmsAuthGuard = tslib.__decorate([
304
305
  */
305
306
  const WmsOperation = (requirement) => common.applyDecorators(common.SetMetadata(WMS_OPERATION_METADATA, requirement), common.SetMetadata(HOST_SKIP_METADATA_KEY, true), common.UseGuards(exports.WmsAuthGuard));
306
307
 
308
+ /** Reflector metadata key carrying the {@link WmsMutationEventConfig}. */
309
+ const WMS_MUTATION_EVENT_METADATA = 'wms:mutation-event';
310
+
311
+ const defaultResolveId = (result, args) => {
312
+ if (result &&
313
+ typeof result === 'object' &&
314
+ 'id' in result &&
315
+ typeof result.id === 'string') {
316
+ return result.id;
317
+ }
318
+ const argId = args['id'];
319
+ return typeof argId === 'string' ? argId : null;
320
+ };
321
+ /**
322
+ * Wraps each `@WmsMutationEvent` mutation in a dispatch scope:
323
+ * 1. runs the before-hook (throw -> veto, before any transaction);
324
+ * 2. executes the resolver (services collect stock events into the scope);
325
+ * 3. emits the operation event after the handler resolves (post-commit);
326
+ * 4. flushes the whole buffer to after-listeners + emitter bridge.
327
+ *
328
+ * When no hook/listener/bridge is configured it passes through untouched.
329
+ */
330
+ exports.WmsMutationInterceptor = class WmsMutationInterceptor {
331
+ reflector;
332
+ dispatcher;
333
+ actorExtractor;
334
+ constructor(reflector, dispatcher, actorExtractor = null) {
335
+ this.reflector = reflector;
336
+ this.dispatcher = dispatcher;
337
+ this.actorExtractor = actorExtractor;
338
+ }
339
+ resolveActor(context) {
340
+ if (!this.actorExtractor) {
341
+ return null;
342
+ }
343
+ try {
344
+ return this.actorExtractor(context);
345
+ }
346
+ catch {
347
+ // Fail-open on actor resolution: never break a mutation over audit metadata.
348
+ return null;
349
+ }
350
+ }
351
+ async intercept(context, next) {
352
+ const config = this.reflector.get(WMS_MUTATION_EVENT_METADATA, context.getHandler());
353
+ if (!config || !this.dispatcher.isActive()) {
354
+ return next.handle();
355
+ }
356
+ const args = graphql.GqlExecutionContext.create(context).getArgs() ??
357
+ {};
358
+ const actor = this.resolveActor(context);
359
+ // Before-hook runs before any DB work; a throw vetoes with zero side effects.
360
+ await this.dispatcher.runBeforeHook({
361
+ event: config.event,
362
+ args,
363
+ executionContext: context,
364
+ actor,
365
+ });
366
+ const { result, events } = await wmsModuleCore.runInDispatchScope(async () => {
367
+ const handlerResult = await rxjs.firstValueFrom(next.handle());
368
+ const id = config.resolveId
369
+ ? config.resolveId(handlerResult, args)
370
+ : defaultResolveId(handlerResult, args);
371
+ const operationEvent = {
372
+ name: config.event,
373
+ payload: { id, result: handlerResult, args, actor },
374
+ };
375
+ wmsModuleCore.collectToScope(operationEvent);
376
+ return handlerResult;
377
+ });
378
+ if (events) {
379
+ await this.dispatcher.flush(events);
380
+ }
381
+ return rxjs.of(result);
382
+ }
383
+ };
384
+ exports.WmsMutationInterceptor = tslib.__decorate([
385
+ common.Injectable(),
386
+ tslib.__param(2, common.Optional()),
387
+ tslib.__param(2, common.Inject(wmsModuleCore.WMS_ACTOR_EXTRACTOR)),
388
+ tslib.__metadata("design:paramtypes", [core.Reflector,
389
+ wmsModuleCore.WmsEventDispatcher, Object])
390
+ ], exports.WmsMutationInterceptor);
391
+
392
+ /**
393
+ * Declares the operation event for a WMS root mutation and wires the
394
+ * {@link WmsMutationInterceptor} that runs before-hooks (veto) and flushes
395
+ * collected events post-commit. Apply alongside `@WmsOperation` on each mutation.
396
+ *
397
+ * @example
398
+ * ```ts
399
+ * @Mutation(() => ShipInventoryOrderDto)
400
+ * @WmsOperation({ resource: 'ship-inventory-order', action: 'ship' })
401
+ * @WmsMutationEvent({ event: 'ship-inventory-order.shipped' })
402
+ * ship(@Args() args: ShipArgs): Promise<boolean> { ... }
403
+ * ```
404
+ */
405
+ const WmsMutationEvent = (config) => common.applyDecorators(common.SetMetadata(WMS_MUTATION_EVENT_METADATA, config), common.UseInterceptors(exports.WmsMutationInterceptor));
406
+
307
407
  const IdGenFunction = (input) => {
308
408
  const hash = crypto.createHash('sha256');
309
409
  hash.update(input);
@@ -1633,6 +1733,7 @@ let LoaderMutation = class LoaderMutation {
1633
1733
  tslib.__decorate([
1634
1734
  graphql.Mutation(() => [LoaderDto]),
1635
1735
  WmsOperation({ resource: 'loader', action: 'create' }),
1736
+ WmsMutationEvent({ event: 'loader.created' }),
1636
1737
  tslib.__param(0, graphql.Args()),
1637
1738
  tslib.__metadata("design:type", Function),
1638
1739
  tslib.__metadata("design:paramtypes", [CreateLoaderArgs]),
@@ -1641,6 +1742,7 @@ tslib.__decorate([
1641
1742
  tslib.__decorate([
1642
1743
  graphql.Mutation(() => [LoaderDto]),
1643
1744
  WmsOperation({ resource: 'loader', action: 'create' }),
1745
+ WmsMutationEvent({ event: 'loader.batch-created' }),
1644
1746
  tslib.__param(0, graphql.Args('items', { type: () => [CreateLoadersArgs] })),
1645
1747
  tslib.__metadata("design:type", Function),
1646
1748
  tslib.__metadata("design:paramtypes", [Array]),
@@ -1649,6 +1751,7 @@ tslib.__decorate([
1649
1751
  tslib.__decorate([
1650
1752
  graphql.Mutation(() => LoaderDto),
1651
1753
  WmsOperation({ resource: 'loader', action: 'update' }),
1754
+ WmsMutationEvent({ event: 'loader.updated' }),
1652
1755
  tslib.__param(0, graphql.Args()),
1653
1756
  tslib.__metadata("design:type", Function),
1654
1757
  tslib.__metadata("design:paramtypes", [UpdateLoaderArgs]),
@@ -1657,6 +1760,7 @@ tslib.__decorate([
1657
1760
  tslib.__decorate([
1658
1761
  graphql.Mutation(() => LoaderTypeDto),
1659
1762
  WmsOperation({ resource: 'loader', action: 'create' }),
1763
+ WmsMutationEvent({ event: 'loader.type-created' }),
1660
1764
  tslib.__param(0, graphql.Args()),
1661
1765
  tslib.__metadata("design:type", Function),
1662
1766
  tslib.__metadata("design:paramtypes", [CreateLoaderTypeArgs]),
@@ -1665,6 +1769,7 @@ tslib.__decorate([
1665
1769
  tslib.__decorate([
1666
1770
  graphql.Mutation(() => LoaderTypeDto),
1667
1771
  WmsOperation({ resource: 'loader', action: 'update' }),
1772
+ WmsMutationEvent({ event: 'loader.type-updated' }),
1668
1773
  tslib.__param(0, graphql.Args()),
1669
1774
  tslib.__metadata("design:type", Function),
1670
1775
  tslib.__metadata("design:paramtypes", [UpdateLoaderTypeArgs]),
@@ -2028,6 +2133,7 @@ let MaterialMutation = class MaterialMutation {
2028
2133
  tslib.__decorate([
2029
2134
  graphql.Mutation(() => MaterialDto),
2030
2135
  WmsOperation({ resource: 'material', action: 'create' }),
2136
+ WmsMutationEvent({ event: 'material.created' }),
2031
2137
  tslib.__param(0, graphql.Args()),
2032
2138
  tslib.__metadata("design:type", Function),
2033
2139
  tslib.__metadata("design:paramtypes", [CreateMaterialArgs]),
@@ -2036,6 +2142,7 @@ tslib.__decorate([
2036
2142
  tslib.__decorate([
2037
2143
  graphql.Mutation(() => MaterialDto),
2038
2144
  WmsOperation({ resource: 'material', action: 'update' }),
2145
+ WmsMutationEvent({ event: 'material.updated' }),
2039
2146
  tslib.__param(0, graphql.Args()),
2040
2147
  tslib.__metadata("design:type", Function),
2041
2148
  tslib.__metadata("design:paramtypes", [UpdateMaterialArgs]),
@@ -2431,6 +2538,7 @@ let ReceiveInventoryOrderMutation = class ReceiveInventoryOrderMutation {
2431
2538
  tslib.__decorate([
2432
2539
  graphql.Mutation(() => ReceiveInventoryOrderDto),
2433
2540
  WmsOperation({ resource: 'receive-inventory-order', action: 'create' }),
2541
+ WmsMutationEvent({ event: 'receive-inventory-order.created' }),
2434
2542
  tslib.__param(0, graphql.Args()),
2435
2543
  tslib.__metadata("design:type", Function),
2436
2544
  tslib.__metadata("design:paramtypes", [CreateReceiveInventoryOrderArgs]),
@@ -2439,6 +2547,7 @@ tslib.__decorate([
2439
2547
  tslib.__decorate([
2440
2548
  graphql.Mutation(() => ReceiveInventoryOrderDto),
2441
2549
  WmsOperation({ resource: 'receive-inventory-order', action: 'update' }),
2550
+ WmsMutationEvent({ event: 'receive-inventory-order.updated' }),
2442
2551
  tslib.__param(0, graphql.Args()),
2443
2552
  tslib.__metadata("design:type", Function),
2444
2553
  tslib.__metadata("design:paramtypes", [UpdateReceiveInventoryOrderArgs]),
@@ -2447,6 +2556,7 @@ tslib.__decorate([
2447
2556
  tslib.__decorate([
2448
2557
  graphql.Mutation(() => Boolean),
2449
2558
  WmsOperation({ resource: 'receive-inventory-order', action: 'receive' }),
2559
+ WmsMutationEvent({ event: 'receive-inventory-order.received' }),
2450
2560
  tslib.__param(0, graphql.Args('items', { type: () => [ReceiveOrderArgs] })),
2451
2561
  tslib.__metadata("design:type", Function),
2452
2562
  tslib.__metadata("design:paramtypes", [Array]),
@@ -2790,6 +2900,7 @@ let ShipInventoryOrderMutation = class ShipInventoryOrderMutation {
2790
2900
  tslib.__decorate([
2791
2901
  graphql.Mutation(() => ShipInventoryOrderDto),
2792
2902
  WmsOperation({ resource: 'ship-inventory-order', action: 'create' }),
2903
+ WmsMutationEvent({ event: 'ship-inventory-order.created' }),
2793
2904
  tslib.__param(0, graphql.Args()),
2794
2905
  tslib.__metadata("design:type", Function),
2795
2906
  tslib.__metadata("design:paramtypes", [CreateShipInventoryOrderArgs]),
@@ -2798,6 +2909,7 @@ tslib.__decorate([
2798
2909
  tslib.__decorate([
2799
2910
  graphql.Mutation(() => ShipInventoryOrderDto),
2800
2911
  WmsOperation({ resource: 'ship-inventory-order', action: 'update' }),
2912
+ WmsMutationEvent({ event: 'ship-inventory-order.updated' }),
2801
2913
  tslib.__param(0, graphql.Args()),
2802
2914
  tslib.__metadata("design:type", Function),
2803
2915
  tslib.__metadata("design:paramtypes", [UpdateShipInventoryOrderArgs]),
@@ -2806,6 +2918,7 @@ tslib.__decorate([
2806
2918
  tslib.__decorate([
2807
2919
  graphql.Mutation(() => Boolean),
2808
2920
  WmsOperation({ resource: 'ship-inventory-order', action: 'ship' }),
2921
+ WmsMutationEvent({ event: 'ship-inventory-order.shipped' }),
2809
2922
  tslib.__param(0, graphql.Args('items', { type: () => [ShipOrderArgs] })),
2810
2923
  tslib.__metadata("design:type", Function),
2811
2924
  tslib.__metadata("design:paramtypes", [Array]),
@@ -2814,6 +2927,7 @@ tslib.__decorate([
2814
2927
  tslib.__decorate([
2815
2928
  graphql.Mutation(() => Boolean),
2816
2929
  WmsOperation({ resource: 'ship-inventory-order', action: 'cancel' }),
2930
+ WmsMutationEvent({ event: 'ship-inventory-order.ship-cancelled' }),
2817
2931
  tslib.__param(0, graphql.Args('items', { type: () => [CancelShipOrderArgs] })),
2818
2932
  tslib.__metadata("design:type", Function),
2819
2933
  tslib.__metadata("design:paramtypes", [Array]),
@@ -3469,6 +3583,7 @@ let WarehouseMapMutation = class WarehouseMapMutation {
3469
3583
  tslib.__decorate([
3470
3584
  graphql.Mutation(() => MapDataDto),
3471
3585
  WmsOperation({ resource: 'warehouse-map', action: 'update' }),
3586
+ WmsMutationEvent({ event: 'warehouse-map.updated' }),
3472
3587
  tslib.__param(0, graphql.Args()),
3473
3588
  tslib.__metadata("design:type", Function),
3474
3589
  tslib.__metadata("design:paramtypes", [UpdateWarehouseMapArgs]),
@@ -3650,6 +3765,7 @@ let LocationMutation = class LocationMutation {
3650
3765
  tslib.__decorate([
3651
3766
  graphql.Mutation(() => LocationDto),
3652
3767
  WmsOperation({ resource: 'location', action: 'create' }),
3768
+ WmsMutationEvent({ event: 'location.created' }),
3653
3769
  tslib.__param(0, graphql.Args()),
3654
3770
  tslib.__metadata("design:type", Function),
3655
3771
  tslib.__metadata("design:paramtypes", [CreateLocationArgs]),
@@ -3658,6 +3774,7 @@ tslib.__decorate([
3658
3774
  tslib.__decorate([
3659
3775
  graphql.Mutation(() => LocationDto),
3660
3776
  WmsOperation({ resource: 'location', action: 'update' }),
3777
+ WmsMutationEvent({ event: 'location.updated' }),
3661
3778
  tslib.__param(0, graphql.Args()),
3662
3779
  tslib.__metadata("design:type", Function),
3663
3780
  tslib.__metadata("design:paramtypes", [UpdateLocationArgs]),
@@ -3961,6 +4078,7 @@ let TransferOrderMutation = class TransferOrderMutation {
3961
4078
  tslib.__decorate([
3962
4079
  graphql.Mutation(() => TransferOrderDto),
3963
4080
  WmsOperation({ resource: 'transfer-order', action: 'create' }),
4081
+ WmsMutationEvent({ event: 'transfer-order.created' }),
3964
4082
  tslib.__param(0, graphql.Args()),
3965
4083
  tslib.__metadata("design:type", Function),
3966
4084
  tslib.__metadata("design:paramtypes", [CreateTransferOrderArgs]),
@@ -3969,6 +4087,7 @@ tslib.__decorate([
3969
4087
  tslib.__decorate([
3970
4088
  graphql.Mutation(() => TransferOrderDto),
3971
4089
  WmsOperation({ resource: 'transfer-order', action: 'update' }),
4090
+ WmsMutationEvent({ event: 'transfer-order.updated' }),
3972
4091
  tslib.__param(0, graphql.Args()),
3973
4092
  tslib.__metadata("design:type", Function),
3974
4093
  tslib.__metadata("design:paramtypes", [UpdateTransferOrderArgs]),
@@ -3977,6 +4096,7 @@ tslib.__decorate([
3977
4096
  tslib.__decorate([
3978
4097
  graphql.Mutation(() => Boolean),
3979
4098
  WmsOperation({ resource: 'transfer-order', action: 'transfer' }),
4099
+ WmsMutationEvent({ event: 'transfer-order.transferred' }),
3980
4100
  tslib.__param(0, graphql.Args('items', { type: () => [TransferOrderArgs] })),
3981
4101
  tslib.__metadata("design:type", Function),
3982
4102
  tslib.__metadata("design:paramtypes", [Array]),
@@ -3985,6 +4105,7 @@ tslib.__decorate([
3985
4105
  tslib.__decorate([
3986
4106
  graphql.Mutation(() => Boolean),
3987
4107
  WmsOperation({ resource: 'transfer-order', action: 'cancel' }),
4108
+ WmsMutationEvent({ event: 'transfer-order.transfer-cancelled' }),
3988
4109
  tslib.__param(0, graphql.Args('items', { type: () => [CancelTransferOrderArgs] })),
3989
4110
  tslib.__metadata("design:type", Function),
3990
4111
  tslib.__metadata("design:paramtypes", [Array]),
@@ -4436,6 +4557,7 @@ let HoldInventoryOrderMutation = class HoldInventoryOrderMutation {
4436
4557
  tslib.__decorate([
4437
4558
  graphql.Mutation(() => HoldInventoryOrderDto),
4438
4559
  WmsOperation({ resource: 'hold-inventory-order', action: 'create' }),
4560
+ WmsMutationEvent({ event: 'hold-inventory-order.created' }),
4439
4561
  tslib.__param(0, graphql.Args()),
4440
4562
  tslib.__metadata("design:type", Function),
4441
4563
  tslib.__metadata("design:paramtypes", [CreateHoldInventoryOrderArgs]),
@@ -4444,6 +4566,7 @@ tslib.__decorate([
4444
4566
  tslib.__decorate([
4445
4567
  graphql.Mutation(() => HoldInventoryOrderDto),
4446
4568
  WmsOperation({ resource: 'hold-inventory-order', action: 'update' }),
4569
+ WmsMutationEvent({ event: 'hold-inventory-order.updated' }),
4447
4570
  tslib.__param(0, graphql.Args()),
4448
4571
  tslib.__metadata("design:type", Function),
4449
4572
  tslib.__metadata("design:paramtypes", [UpdateHoldInventoryOrderArgs]),
@@ -4452,6 +4575,7 @@ tslib.__decorate([
4452
4575
  tslib.__decorate([
4453
4576
  graphql.Mutation(() => Boolean),
4454
4577
  WmsOperation({ resource: 'hold-inventory-order', action: 'release' }),
4578
+ WmsMutationEvent({ event: 'hold-inventory-order.released' }),
4455
4579
  tslib.__param(0, graphql.Args('items', { type: () => [ReleaseOrderArgs] })),
4456
4580
  tslib.__metadata("design:type", Function),
4457
4581
  tslib.__metadata("design:paramtypes", [Array]),
@@ -4970,6 +5094,7 @@ let AllocateInventoryOrderMutation = class AllocateInventoryOrderMutation {
4970
5094
  tslib.__decorate([
4971
5095
  graphql.Mutation(() => AllocateInventoryOrderDto),
4972
5096
  WmsOperation({ resource: 'allocate-inventory-order', action: 'create' }),
5097
+ WmsMutationEvent({ event: 'allocate-inventory-order.created' }),
4973
5098
  tslib.__param(0, graphql.Args()),
4974
5099
  tslib.__metadata("design:type", Function),
4975
5100
  tslib.__metadata("design:paramtypes", [CreateAllocateInventoryOrderArgs]),
@@ -4978,6 +5103,7 @@ tslib.__decorate([
4978
5103
  tslib.__decorate([
4979
5104
  graphql.Mutation(() => AllocateInventoryOrderDto),
4980
5105
  WmsOperation({ resource: 'allocate-inventory-order', action: 'update' }),
5106
+ WmsMutationEvent({ event: 'allocate-inventory-order.updated' }),
4981
5107
  tslib.__param(0, graphql.Args()),
4982
5108
  tslib.__metadata("design:type", Function),
4983
5109
  tslib.__metadata("design:paramtypes", [UpdateAllocateInventoryOrderArgs]),
@@ -4986,6 +5112,7 @@ tslib.__decorate([
4986
5112
  tslib.__decorate([
4987
5113
  graphql.Mutation(() => Boolean),
4988
5114
  WmsOperation({ resource: 'allocate-inventory-order', action: 'deallocate' }),
5115
+ WmsMutationEvent({ event: 'allocate-inventory-order.deallocated' }),
4989
5116
  tslib.__param(0, graphql.Args('items', { type: () => [DeallocateOrderArgs] })),
4990
5117
  tslib.__metadata("design:type", Function),
4991
5118
  tslib.__metadata("design:paramtypes", [Array]),
@@ -5442,6 +5569,7 @@ let SplitBatchMutation = class SplitBatchMutation {
5442
5569
  tslib.__decorate([
5443
5570
  graphql.Mutation(() => SplitBatchOrderDto),
5444
5571
  WmsOperation({ resource: 'batch', action: 'split' }),
5572
+ WmsMutationEvent({ event: 'batch.splitted' }),
5445
5573
  tslib.__param(0, graphql.Args()),
5446
5574
  tslib.__metadata("design:type", Function),
5447
5575
  tslib.__metadata("design:paramtypes", [SplitBatchArgs]),
@@ -5561,6 +5689,7 @@ let MergeBatchMutation = class MergeBatchMutation {
5561
5689
  tslib.__decorate([
5562
5690
  graphql.Mutation(() => MergeBatchOrderDto),
5563
5691
  WmsOperation({ resource: 'batch', action: 'merge' }),
5692
+ WmsMutationEvent({ event: 'batch.merged' }),
5564
5693
  tslib.__param(0, graphql.Args()),
5565
5694
  tslib.__metadata("design:type", Function),
5566
5695
  tslib.__metadata("design:paramtypes", [MergeBatchArgs]),
@@ -5686,6 +5815,7 @@ let ReclassifyInventoryOrderMutation = class ReclassifyInventoryOrderMutation {
5686
5815
  tslib.__decorate([
5687
5816
  graphql.Mutation(() => ReclassifyInventoryOrderDto),
5688
5817
  WmsOperation({ resource: 'reclassify-inventory-order', action: 'reclassify' }),
5818
+ WmsMutationEvent({ event: 'reclassify-inventory-order.reclassified' }),
5689
5819
  tslib.__param(0, graphql.Args()),
5690
5820
  tslib.__metadata("design:type", Function),
5691
5821
  tslib.__metadata("design:paramtypes", [ReclassifyInventoryOrderArgs]),
@@ -5859,6 +5989,7 @@ let TransferCustomerOrderMutation = class TransferCustomerOrderMutation {
5859
5989
  tslib.__decorate([
5860
5990
  graphql.Mutation(() => TransferCustomerOrderDto),
5861
5991
  WmsOperation({ resource: 'transfer-customer-order', action: 'create' }),
5992
+ WmsMutationEvent({ event: 'transfer-customer-order.created' }),
5862
5993
  tslib.__param(0, graphql.Args()),
5863
5994
  tslib.__metadata("design:type", Function),
5864
5995
  tslib.__metadata("design:paramtypes", [CreateTransferCustomerOrderArgs]),
@@ -5867,6 +5998,7 @@ tslib.__decorate([
5867
5998
  tslib.__decorate([
5868
5999
  graphql.Mutation(() => TransferCustomerOrderDto),
5869
6000
  WmsOperation({ resource: 'transfer-customer-order', action: 'update' }),
6001
+ WmsMutationEvent({ event: 'transfer-customer-order.updated' }),
5870
6002
  tslib.__param(0, graphql.Args()),
5871
6003
  tslib.__metadata("design:type", Function),
5872
6004
  tslib.__metadata("design:paramtypes", [UpdateTransferCustomerOrderArgs]),
@@ -5875,6 +6007,7 @@ tslib.__decorate([
5875
6007
  tslib.__decorate([
5876
6008
  graphql.Mutation(() => Boolean),
5877
6009
  WmsOperation({ resource: 'transfer-customer-order', action: 'return' }),
6010
+ WmsMutationEvent({ event: 'transfer-customer-order.returned' }),
5878
6011
  tslib.__param(0, graphql.Args('items', { type: () => [ReturnTransferCustomerOrderArgs] })),
5879
6012
  tslib.__metadata("design:type", Function),
5880
6013
  tslib.__metadata("design:paramtypes", [Array]),
@@ -6067,6 +6200,7 @@ let TransferVendorOrderMutation = class TransferVendorOrderMutation {
6067
6200
  tslib.__decorate([
6068
6201
  graphql.Mutation(() => TransferVendorOrderDto),
6069
6202
  WmsOperation({ resource: 'transfer-vendor-order', action: 'create' }),
6203
+ WmsMutationEvent({ event: 'transfer-vendor-order.created' }),
6070
6204
  tslib.__param(0, graphql.Args()),
6071
6205
  tslib.__metadata("design:type", Function),
6072
6206
  tslib.__metadata("design:paramtypes", [CreateTransferVendorOrderArgs]),
@@ -6075,6 +6209,7 @@ tslib.__decorate([
6075
6209
  tslib.__decorate([
6076
6210
  graphql.Mutation(() => TransferVendorOrderDto),
6077
6211
  WmsOperation({ resource: 'transfer-vendor-order', action: 'update' }),
6212
+ WmsMutationEvent({ event: 'transfer-vendor-order.updated' }),
6078
6213
  tslib.__param(0, graphql.Args()),
6079
6214
  tslib.__metadata("design:type", Function),
6080
6215
  tslib.__metadata("design:paramtypes", [UpdateTransferVendorOrderArgs]),
@@ -6083,6 +6218,7 @@ tslib.__decorate([
6083
6218
  tslib.__decorate([
6084
6219
  graphql.Mutation(() => Boolean),
6085
6220
  WmsOperation({ resource: 'transfer-vendor-order', action: 'return' }),
6221
+ WmsMutationEvent({ event: 'transfer-vendor-order.returned' }),
6086
6222
  tslib.__param(0, graphql.Args('items', { type: () => [ReturnTransferVendorOrderArgs] })),
6087
6223
  tslib.__metadata("design:type", Function),
6088
6224
  tslib.__metadata("design:paramtypes", [Array]),
@@ -6205,6 +6341,7 @@ let ScrapeMutation = class ScrapeMutation {
6205
6341
  tslib.__decorate([
6206
6342
  graphql.Mutation(() => ScrapeOrderDto),
6207
6343
  WmsOperation({ resource: 'scrape-order', action: 'scrape' }),
6344
+ WmsMutationEvent({ event: 'scrape-order.scraped' }),
6208
6345
  tslib.__param(0, graphql.Args()),
6209
6346
  tslib.__metadata("design:type", Function),
6210
6347
  tslib.__metadata("design:paramtypes", [ScrapeOrderArgs]),
@@ -6288,6 +6425,7 @@ let QualityInspectionOrderMutation = class QualityInspectionOrderMutation {
6288
6425
  tslib.__decorate([
6289
6426
  graphql.Mutation(() => QualityInspectionOrderDto),
6290
6427
  WmsOperation({ resource: 'quality-inspection-order', action: 'inspect' }),
6428
+ WmsMutationEvent({ event: 'quality-inspection-order.inspected' }),
6291
6429
  tslib.__param(0, graphql.Args()),
6292
6430
  tslib.__metadata("design:type", Function),
6293
6431
  tslib.__metadata("design:paramtypes", [CreateQualityInspectionOrderArgs]),
@@ -6401,13 +6539,26 @@ const exportDependencies = [
6401
6539
  ];
6402
6540
  exports.WmsModuleGraphqlModule = WmsModuleGraphqlModule_1 = class WmsModuleGraphqlModule {
6403
6541
  static forRootAsync(options) {
6404
- const { authChecker, ...coreOptions } = options;
6542
+ const { authChecker, beforeHooks, afterListeners, actorExtractor, eventEmitterBridge, ...coreOptions } = options;
6543
+ // coreOptions still carries `enrichStockEvents`, forwarded to the core module.
6405
6544
  const coreModule = wmsModuleCore.WmsModuleCoreModule.forRootAsync(coreOptions);
6406
6545
  const authOptions = { authChecker };
6546
+ // The typed hook maps are a compile-time refinement of the core maps; at
6547
+ // runtime the dispatched payload IS the concrete result type, so handing the
6548
+ // refined maps to the (looser) core option contract is sound.
6549
+ const eventOptions = {
6550
+ beforeHooks: beforeHooks,
6551
+ afterListeners: afterListeners,
6552
+ };
6407
6553
  const providers = [
6408
6554
  ...exportDependencies,
6409
6555
  exports.WmsAuthGuard,
6410
6556
  { provide: WMS_AUTH_OPTIONS, useValue: authOptions },
6557
+ { provide: wmsModuleCore.WMS_EVENT_OPTIONS, useValue: eventOptions },
6558
+ { provide: wmsModuleCore.WMS_ACTOR_EXTRACTOR, useValue: actorExtractor ?? null },
6559
+ wmsModuleCore.WmsEventDispatcher,
6560
+ exports.WmsMutationInterceptor,
6561
+ ...(eventEmitterBridge ? [eventEmitterBridge] : []),
6411
6562
  ];
6412
6563
  return {
6413
6564
  module: WmsModuleGraphqlModule_1,
@@ -6425,6 +6576,8 @@ exports.WmsModuleGraphqlModule = WmsModuleGraphqlModule_1 = tslib.__decorate([
6425
6576
 
6426
6577
  exports.HOST_SKIP_METADATA_KEY = HOST_SKIP_METADATA_KEY;
6427
6578
  exports.WMS_AUTH_OPTIONS = WMS_AUTH_OPTIONS;
6579
+ exports.WMS_MUTATION_EVENT_METADATA = WMS_MUTATION_EVENT_METADATA;
6428
6580
  exports.WMS_OPERATION_METADATA = WMS_OPERATION_METADATA;
6581
+ exports.WmsMutationEvent = WmsMutationEvent;
6429
6582
  exports.WmsOperation = WmsOperation;
6430
6583
  exports.createWmsLoaders = createWmsLoaders;
package/index.d.ts CHANGED
@@ -5,3 +5,5 @@ export type { LoaderType } from './lib/helpers/dataloader.type';
5
5
  export { createWmsLoaders, type WmsLoaders, } from './lib/helpers/create-wms-loaders';
6
6
  export { HOST_SKIP_METADATA_KEY, WmsAuthGuard, WmsOperation, WMS_AUTH_OPTIONS, WMS_OPERATION_METADATA, type WmsAuthChecker, type WmsAuthModuleOptions, type WmsOperationRequirement, } from './lib/auth';
7
7
  export type { WmsModuleGraphqlModuleAsyncOptions } from './lib/graphql.module';
8
+ export { WmsMutationEvent, WmsMutationInterceptor, WMS_MUTATION_EVENT_METADATA, type WmsMutationEventConfig, type WmsOperationResultMap, type WmsEventPayloadFor, type WmsTypedAfterEventContext, type WmsTypedAfterListenerMap, type WmsTypedBeforeHookContext, type WmsTypedBeforeHookMap, } from './lib/events';
9
+ export type { WmsActor, WmsActorExtractor, WmsAfterEventContext, WmsAfterListener, WmsAfterListenerMap, WmsBeforeHook, WmsBeforeHookContext, WmsBeforeHookMap, WmsDomainEvent, WmsEventModuleOptions, WmsEventName, WmsEventPayloadMap, WmsOperationEventName, WmsOperationEventPayload, WmsStockEventName, WmsStockEventPayload, } from '@rytass/wms-module-core';
package/index.js CHANGED
@@ -5,3 +5,6 @@ export { HOST_SKIP_METADATA_KEY } from './lib/auth/host-skip.constant.js';
5
5
  export { WmsAuthGuard } from './lib/auth/wms-auth.guard.js';
6
6
  export { WmsOperation } from './lib/auth/wms-operation.decorator.js';
7
7
  export { WMS_AUTH_OPTIONS, WMS_OPERATION_METADATA } from './lib/auth/wms-auth.types.js';
8
+ export { WmsMutationEvent } from './lib/events/wms-mutation-event.decorator.js';
9
+ export { WMS_MUTATION_EVENT_METADATA } from './lib/events/wms-mutation-event.constants.js';
10
+ export { WmsMutationInterceptor } from './lib/events/wms-mutation.interceptor.js';
@@ -0,0 +1,5 @@
1
+ export { WmsMutationEvent } from './wms-mutation-event.decorator';
2
+ export { WMS_MUTATION_EVENT_METADATA, type WmsMutationEventConfig, } from './wms-mutation-event.constants';
3
+ export { WmsMutationInterceptor } from './wms-mutation.interceptor';
4
+ export type { WmsOperationResultMap } from './operation-result-map';
5
+ export type { WmsEventPayloadFor, WmsTypedAfterEventContext, WmsTypedAfterListenerMap, WmsTypedBeforeHookContext, WmsTypedBeforeHookMap, } from './typed-maps';
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @file operation-result-map.ts
3
+ * Typed overlay that maps every {@link WmsOperationEventName} to the concrete
4
+ * DTO (or `boolean`) returned by that mutation. Used by {@link WmsEventPayloadFor}
5
+ * and the consumer-facing typed hook/listener maps in `typed-maps.ts`.
6
+ *
7
+ * `WmsOperationResultMap` extends `Record<WmsOperationEventName, unknown>` so
8
+ * the compiler rejects any key that is not a valid operation-event name, and
9
+ * flags missing keys at the interface level — every new mutation must add an
10
+ * entry here.
11
+ */
12
+ import type { WmsOperationEventName } from '@rytass/wms-module-core';
13
+ import type { AllocateInventoryOrderDto, HoldInventoryOrderDto, LoaderDto, LoaderTypeDto, MaterialDto, QualityInspectionOrderDto, ReceiveInventoryOrderDto, ScrapeOrderDto, ShipInventoryOrderDto, TransferCustomerOrderDto, TransferOrderDto, TransferVendorOrderDto } from '../dto';
14
+ import type { LocationDto } from '../dto/location.dto';
15
+ import type { MapDataDto } from '../dto/warehouse-map.dto';
16
+ import type { MergeBatchOrderDto } from '../dto/merge-batch-order.dto';
17
+ import type { ReclassifyInventoryOrderDto } from '../dto/reclassify-inventory-order.dto';
18
+ import type { SplitBatchOrderDto } from '../dto/split-batch-order.dto';
19
+ /**
20
+ * Maps every {@link WmsOperationEventName} to the concrete type returned by
21
+ * the corresponding mutation resolver.
22
+ *
23
+ * - **DTO-returning mutations (29)**: the resolved DTO class.
24
+ * - **Action mutations (9)**: `boolean` (success flag; real intent is in
25
+ * `WmsOperationEventPayload.args` and the accompanying stock events).
26
+ *
27
+ * Maintenance: for every new `@Mutation`, add the matching entry here.
28
+ */
29
+ export interface WmsOperationResultMap extends Record<WmsOperationEventName, unknown> {
30
+ 'material.created': MaterialDto;
31
+ 'material.updated': MaterialDto;
32
+ 'location.created': LocationDto;
33
+ 'location.updated': LocationDto;
34
+ 'warehouse-map.updated': MapDataDto;
35
+ 'loader.created': LoaderDto[];
36
+ 'loader.batch-created': LoaderDto[];
37
+ 'loader.updated': LoaderDto;
38
+ 'loader.type-created': LoaderTypeDto;
39
+ 'loader.type-updated': LoaderTypeDto;
40
+ 'receive-inventory-order.created': ReceiveInventoryOrderDto;
41
+ 'receive-inventory-order.updated': ReceiveInventoryOrderDto;
42
+ /** Action mutation — result is a success flag; use args + stock.received. */
43
+ 'receive-inventory-order.received': boolean;
44
+ 'allocate-inventory-order.created': AllocateInventoryOrderDto;
45
+ 'allocate-inventory-order.updated': AllocateInventoryOrderDto;
46
+ /** Action mutation — result is a success flag; use args + stock.deallocated. */
47
+ 'allocate-inventory-order.deallocated': boolean;
48
+ 'hold-inventory-order.created': HoldInventoryOrderDto;
49
+ 'hold-inventory-order.updated': HoldInventoryOrderDto;
50
+ /** Action mutation — result is a success flag; use args + stock.released. */
51
+ 'hold-inventory-order.released': boolean;
52
+ 'reclassify-inventory-order.reclassified': ReclassifyInventoryOrderDto;
53
+ 'ship-inventory-order.created': ShipInventoryOrderDto;
54
+ 'ship-inventory-order.updated': ShipInventoryOrderDto;
55
+ /** Action mutation — result is a success flag; use args + stock.shipped. */
56
+ 'ship-inventory-order.shipped': boolean;
57
+ /** Action mutation — result is a success flag; use args + stock.shipped (negative). */
58
+ 'ship-inventory-order.ship-cancelled': boolean;
59
+ 'batch.merged': MergeBatchOrderDto;
60
+ 'batch.splitted': SplitBatchOrderDto;
61
+ 'scrape-order.scraped': ScrapeOrderDto;
62
+ 'quality-inspection-order.inspected': QualityInspectionOrderDto;
63
+ 'transfer-order.created': TransferOrderDto;
64
+ 'transfer-order.updated': TransferOrderDto;
65
+ /** Action mutation — result is a success flag; use args + stock.transferred. */
66
+ 'transfer-order.transferred': boolean;
67
+ /** Action mutation — result is a success flag; use args + stock.in-transfer reversal. */
68
+ 'transfer-order.transfer-cancelled': boolean;
69
+ 'transfer-customer-order.created': TransferCustomerOrderDto;
70
+ 'transfer-customer-order.updated': TransferCustomerOrderDto;
71
+ /** Action mutation — result is a success flag; use args + stock.customer-returned. */
72
+ 'transfer-customer-order.returned': boolean;
73
+ 'transfer-vendor-order.created': TransferVendorOrderDto;
74
+ 'transfer-vendor-order.updated': TransferVendorOrderDto;
75
+ /** Action mutation — result is a success flag; use args + stock.vendor-returned. */
76
+ 'transfer-vendor-order.returned': boolean;
77
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @file typed-maps.ts
3
+ * Consumer-facing typed hook/listener maps for the WMS mutation event system.
4
+ *
5
+ * These types give consumers per-event type safety when wiring `beforeHooks`
6
+ * and `afterListeners` in `WmsModuleGraphqlModule.forRootAsync(...)`. They
7
+ * layer on top of the runtime-erased core contracts without introducing any
8
+ * runtime dependency — everything here is `import type` only.
9
+ *
10
+ * Key exports
11
+ * -----------
12
+ * - {@link WmsEventPayloadFor} — resolves the payload type for a given event name
13
+ * - {@link WmsTypedAfterEventContext} — ctx passed to after-listeners
14
+ * - {@link WmsTypedBeforeHookContext} — ctx passed to before-hooks (pre-DB)
15
+ * - {@link WmsTypedAfterListenerMap} — `afterListeners` option with typed callbacks
16
+ * - {@link WmsTypedBeforeHookMap} — `beforeHooks` option with typed callbacks
17
+ */
18
+ import type { WmsActor, WmsEventName, WmsOperationEventName, WmsOperationEventPayload, WmsStockEventPayload } from '@rytass/wms-module-core';
19
+ import type { ExecutionContext } from '@nestjs/common';
20
+ import type { WmsOperationResultMap } from './operation-result-map';
21
+ /**
22
+ * Resolves the full event payload type for a given {@link WmsEventName}.
23
+ *
24
+ * - Operation events (`WmsOperationEventName`): `WmsOperationEventPayload`
25
+ * parameterised with the concrete result type from {@link WmsOperationResultMap}.
26
+ * - Stock events (`WmsStockEventName`): `WmsStockEventPayload` (ids-only by
27
+ * default; enriched when `enrichStockEvents: true`).
28
+ */
29
+ export type WmsEventPayloadFor<N extends WmsEventName> = N extends WmsOperationEventName ? WmsOperationEventPayload<WmsOperationResultMap[N]> : WmsStockEventPayload;
30
+ /**
31
+ * Context passed to an after-listener. Runs post-commit with the full
32
+ * typed event payload.
33
+ */
34
+ export interface WmsTypedAfterEventContext<N extends WmsEventName> {
35
+ readonly event: N;
36
+ readonly payload: WmsEventPayloadFor<N>;
37
+ }
38
+ /**
39
+ * Context passed to a before-hook. Runs *before* any DB work, so
40
+ * `payload` / `result` are not yet available — only the raw GraphQL
41
+ * arguments (`args`) and the resolved actor. Throwing from a before-hook
42
+ * vetoes the mutation with zero side effects.
43
+ */
44
+ export interface WmsTypedBeforeHookContext<N extends WmsEventName> {
45
+ readonly event: N;
46
+ /** Raw GraphQL arguments — the mutation intent (per §3.4 of the design doc). */
47
+ readonly args: Readonly<Record<string, unknown>>;
48
+ /** The NestJS execution context at the time of the mutation call. */
49
+ readonly executionContext: ExecutionContext;
50
+ /** Who performed the mutation; `null` when no `actorExtractor` is configured. */
51
+ readonly actor: WmsActor | null;
52
+ }
53
+ /**
54
+ * Typed `afterListeners` map. Each key is an optional per-event callback
55
+ * that receives a fully typed {@link WmsTypedAfterEventContext}.
56
+ *
57
+ * Pass an instance of this type as `afterListeners` in
58
+ * `WmsModuleGraphqlModule.forRootAsync(...)` to get per-event type safety.
59
+ */
60
+ export type WmsTypedAfterListenerMap = {
61
+ readonly [N in WmsEventName]?: (ctx: WmsTypedAfterEventContext<N>) => void | Promise<void>;
62
+ };
63
+ /**
64
+ * Typed `beforeHooks` map. Each key is an optional per-event callback
65
+ * that receives a fully typed {@link WmsTypedBeforeHookContext}.
66
+ *
67
+ * Throwing inside a before-hook vetoes the mutation before any transaction
68
+ * is opened. Pass an instance of this type as `beforeHooks` in
69
+ * `WmsModuleGraphqlModule.forRootAsync(...)`.
70
+ */
71
+ export type WmsTypedBeforeHookMap = {
72
+ readonly [N in WmsEventName]?: (ctx: WmsTypedBeforeHookContext<N>) => void | Promise<void>;
73
+ };
@@ -0,0 +1,12 @@
1
+ import type { WmsOperationEventName } from '@rytass/wms-module-core';
2
+ /** Reflector metadata key carrying the {@link WmsMutationEventConfig}. */
3
+ export declare const WMS_MUTATION_EVENT_METADATA = "wms:mutation-event";
4
+ export interface WmsMutationEventConfig {
5
+ /** The operation event emitted for this mutation (post-commit). */
6
+ readonly event: WmsOperationEventName;
7
+ /**
8
+ * Optional override for deriving the operation's primary id from the handler
9
+ * result and/or arguments. Defaults to `result.id ?? args.id ?? null`.
10
+ */
11
+ readonly resolveId?: (result: unknown, args: Readonly<Record<string, unknown>>) => string | null;
12
+ }
@@ -0,0 +1,4 @@
1
+ /** Reflector metadata key carrying the {@link WmsMutationEventConfig}. */
2
+ const WMS_MUTATION_EVENT_METADATA = 'wms:mutation-event';
3
+
4
+ export { WMS_MUTATION_EVENT_METADATA };
@@ -0,0 +1,15 @@
1
+ import { type WmsMutationEventConfig } from './wms-mutation-event.constants';
2
+ /**
3
+ * Declares the operation event for a WMS root mutation and wires the
4
+ * {@link WmsMutationInterceptor} that runs before-hooks (veto) and flushes
5
+ * collected events post-commit. Apply alongside `@WmsOperation` on each mutation.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * @Mutation(() => ShipInventoryOrderDto)
10
+ * @WmsOperation({ resource: 'ship-inventory-order', action: 'ship' })
11
+ * @WmsMutationEvent({ event: 'ship-inventory-order.shipped' })
12
+ * ship(@Args() args: ShipArgs): Promise<boolean> { ... }
13
+ * ```
14
+ */
15
+ export declare const WmsMutationEvent: (config: WmsMutationEventConfig) => MethodDecorator;