@weave-js/core 0.15.3 → 0.16.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 (64) hide show
  1. package/index.mjs +0 -0
  2. package/lib/broker/context.js +4 -11
  3. package/lib/broker/defaultOptions.js +3 -2
  4. package/lib/broker/index.js +80 -26
  5. package/lib/broker/public.d.ts +2 -1
  6. package/lib/buildRuntime.js +30 -13
  7. package/lib/cache/adapters/index.js +14 -0
  8. package/lib/cache/lock.js +17 -0
  9. package/lib/errorHandler.js +27 -2
  10. package/lib/errors.js +11 -1
  11. package/lib/helper/defineAction.js +22 -7
  12. package/lib/helper/defineBrokerOptions.js +26 -8
  13. package/lib/helper/defineService.js +29 -5
  14. package/lib/index.js +69 -19
  15. package/lib/logger/format/asHumanReadable.js +4 -4
  16. package/lib/metrics/common.js +1 -1
  17. package/lib/metrics/exporter/base.js +2 -2
  18. package/lib/metrics/exporter/event.js +15 -13
  19. package/lib/metrics/exporter/index.js +1 -1
  20. package/lib/metrics/index.js +28 -0
  21. package/lib/middlewares/bulkhead/index.js +3 -3
  22. package/lib/middlewares/cache/index.js +6 -5
  23. package/lib/middlewares/context-tracker/index.js +12 -5
  24. package/lib/middlewares/index.js +18 -0
  25. package/lib/middlewares/tracing/tags.js +2 -2
  26. package/lib/middlewares/validator/index.js +2 -2
  27. package/lib/registry/actionEndpoint.js +5 -5
  28. package/lib/registry/collections/actionCollection.js +2 -2
  29. package/lib/registry/collections/endpointCollection.js +5 -5
  30. package/lib/registry/collections/eventCollection.js +5 -5
  31. package/lib/registry/collections/nodeCollection.js +2 -2
  32. package/lib/registry/collections/serviceCollection.js +2 -2
  33. package/lib/registry/node.js +1 -1
  34. package/lib/registry/registry.js +24 -15
  35. package/lib/registry/service/parseAction.js +11 -2
  36. package/lib/registry/service/parseEvent.js +2 -1
  37. package/lib/registry/service/service.js +29 -8
  38. package/lib/registry/serviceItem.js +2 -2
  39. package/lib/runtime/initActionInvoker.js +5 -1
  40. package/lib/runtime/initCache.js +4 -0
  41. package/lib/runtime/initContextFactory.js +6 -15
  42. package/lib/runtime/initEventbus.js +25 -4
  43. package/lib/runtime/initLogger.js +30 -10
  44. package/lib/runtime/initMetrics.js +18 -8
  45. package/lib/runtime/initRegistry.js +1 -1
  46. package/lib/runtime/initServiceManager.js +4 -0
  47. package/lib/runtime/initTracing.js +5 -1
  48. package/lib/runtime/initTransport.js +1 -1
  49. package/lib/runtime/initUuidFactory.js +1 -5
  50. package/lib/runtime/initValidator.js +1 -6
  51. package/lib/tracing/collectors/base.js +21 -3
  52. package/lib/tracing/collectors/event.js +10 -0
  53. package/lib/tracing/collectors/index.js +34 -1
  54. package/lib/transport/adapters/adapterBase.js +14 -4
  55. package/lib/transport/adapters/fromURI.js +31 -23
  56. package/lib/transport/createTransport.js +30 -13
  57. package/lib/transport/messageHandlers.js +3 -3
  58. package/lib/utils/index.js +17 -1
  59. package/lib/utils/options.js +70 -2
  60. package/lib/utils/restoreError.js +25 -0
  61. package/lib/utils/wrap-handler.js +22 -0
  62. package/package.json +2 -1
  63. package/types/index.d.ts +958 -0
  64. /package/lib/{types.js → types.__js} +0 -0
@@ -1,19 +1,29 @@
1
- /**
2
- * @typedef {import('../types.js').Runtime} Runtime
3
- * @typedef {import('../types.js').Broker} Broker
4
- * @typedef {import('../types.js').Transport} Transport
5
- */
6
1
 
7
2
  const { defaultsDeep } = require('@weave-js/utils');
8
3
  const { createLogger: createDefaultLogger } = require('../logger/index');
9
4
 
10
5
  /**
11
- * Init logger
12
- * @param {Runtime} runtime - Runtime reference
6
+ * Initializes the logging subsystem for the runtime
7
+ *
8
+ * Creates a logger factory that can generate module-specific loggers with consistent formatting
9
+ * and configuration. Supports both custom logger functions and built-in logger with configurable
10
+ * levels, formatting, and output destinations.
11
+ *
12
+ * @param {import("../../types").Runtime} runtime - Runtime instance to initialize logger for
13
13
  * @returns {void}
14
+ * @example
15
+ * initLogger(runtime);
16
+ * const moduleLogger = runtime.createLogger('SERVICE-MANAGER');
17
+ * moduleLogger.info('Service initialized');
14
18
  */
15
19
  exports.initLogger = (runtime) => {
16
- const loggerFactory = (runtime, moduleName, additional = {}) => {
20
+ /**
21
+ * Factory function to create module-specific loggers
22
+ * @param {string} moduleName - Name of the module requesting a logger
23
+ * @param {object} [additional={}] - Additional metadata to include in log entries
24
+ * @returns {import("../../types").Logger} Configured logger instance
25
+ */
26
+ const loggerFactory = (moduleName, additional = {}) => {
17
27
  const bindings = {
18
28
  nodeId: runtime.options.nodeId,
19
29
  moduleName,
@@ -21,7 +31,7 @@ exports.initLogger = (runtime) => {
21
31
  };
22
32
 
23
33
  if (typeof runtime.options.logger === 'function') {
24
- return runtime.options.logger(bindings, runtime.options.logger.level);
34
+ return runtime.options.logger(bindings, runtime.options.logger);
25
35
  }
26
36
 
27
37
  const loggerOptions = defaultsDeep({
@@ -33,8 +43,18 @@ exports.initLogger = (runtime) => {
33
43
  return createDefaultLogger(loggerOptions);
34
44
  };
35
45
 
36
- const createLogger = (moduleName, service) => loggerFactory(runtime, moduleName, service);
46
+ /**
47
+ * Public API for creating loggers
48
+ * @param {string} moduleName - Name of the module requesting a logger
49
+ * @param {object} [service] - Service context for additional metadata
50
+ * @returns {import("../../types").Logger} Configured logger instance
51
+ */
52
+ const createLogger = (moduleName, service) => loggerFactory(moduleName, service);
37
53
 
54
+ /**
55
+ * Main runtime logger instance
56
+ * @type {import("../../types").Logger}
57
+ */
38
58
  const log = createLogger('WEAVE');
39
59
 
40
60
  Object.assign(runtime, {
@@ -3,19 +3,15 @@ const { WeaveError } = require('../errors');
3
3
  const { registerCommonMetrics, updateCommonMetrics } = require('../metrics/common');
4
4
  const MetricTypes = require('../metrics/types');
5
5
 
6
- /**
7
- * @typedef {import('../types.js').Runtime} Runtime
8
- */
9
-
10
6
  /**
11
7
  * Init metrics module
12
- * @param {Runtime} runtime - Runtime reference
8
+ * @param {import('../../types').Runtime} runtime - Runtime reference
13
9
  * @returns {void}
14
10
  */
15
11
  exports.initMetrics = (runtime) => {
16
12
  const metricOptions = runtime.options.metrics;
17
13
 
18
- if (metricOptions.enabled) {
14
+ if (metricOptions?.enabled) {
19
15
  const storage = new Map();
20
16
 
21
17
  const log = runtime.createLogger('METRICS');
@@ -41,12 +37,26 @@ exports.initMetrics = (runtime) => {
41
37
  });
42
38
  }
43
39
  },
44
- stop () {
40
+ async stop () {
45
41
  if (commonUpdateTimer) {
46
42
  clearInterval(commonUpdateTimer);
47
43
  }
48
44
 
49
- return Promise.all(this.adapters.map(adapter => adapter.stop()));
45
+ if (!this.adapters || this.adapters.length === 0) {
46
+ return;
47
+ }
48
+
49
+ const results = await Promise.allSettled(this.adapters.map(adapter => adapter.stop()));
50
+ const failures = results.filter(result => result.status === 'rejected');
51
+
52
+ if (failures.length > 0) {
53
+ failures.forEach(failure => {
54
+ log.warn(failure.reason, 'Failed to stop metrics adapter');
55
+ });
56
+ log.warn(`Failed to stop ${failures.length} of ${this.adapters.length} metrics adapters`);
57
+ }
58
+
59
+ return results;
50
60
  },
51
61
  register (obj) {
52
62
  if (!isPlainObject(obj)) {
@@ -5,7 +5,7 @@
5
5
  * Copyright 2021 Fachwerk
6
6
  */
7
7
  /**
8
- * @typedef {import('../types').Runtime} Runtime
8
+ * @typedef {import('../types.__js').Runtime} Runtime
9
9
  */
10
10
  const { createRegistry } = require('../registry/registry.js');
11
11
 
@@ -1,6 +1,10 @@
1
1
  const { createServiceFromSchema } = require('../registry/service/service.js');
2
2
  const { WeaveError } = require('../errors');
3
3
 
4
+ /**
5
+ *
6
+ * @param {import('../../types/index.js').Runtime} runtime
7
+ */
4
8
  exports.initServiceManager = (runtime) => {
5
9
  const { options, log, eventBus, transport, state, registry, handleError } = runtime;
6
10
 
@@ -1,6 +1,10 @@
1
1
  const { resolveCollector } = require('../tracing/collectors');
2
2
  const { Span } = require('../tracing/span');
3
3
 
4
+ /**
5
+ * Init tracer
6
+ * @param {import('../../types').Runtime} runtime Runtime
7
+ */
4
8
  exports.initTracer = (runtime) => {
5
9
  const options = runtime.options.tracing;
6
10
  const log = runtime.createLogger('TRACER');
@@ -37,7 +41,7 @@ exports.initTracer = (runtime) => {
37
41
  invokeCollectorMethod (method, args) {
38
42
  collectors.map(collector => collector[method].apply(collector, args));
39
43
  },
40
- startSpan (name, spanOptions) {
44
+ startSpan (name, spanOptions = {}) {
41
45
  const parentOptions = {};
42
46
 
43
47
  if (spanOptions.parentSpan) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {import('../types').TransportAdapter} TransportAdapter
2
+ * @typedef {import('../types.__js').TransportAdapter} TransportAdapter
3
3
  **/
4
4
 
5
5
  const { createTransport } = require('../transport/createTransport');
@@ -1,12 +1,8 @@
1
- /**
2
- * @typedef {import('../types.js').Runtime} Runtime
3
- */
4
-
5
1
  const { isFunction, uuid } = require('@weave-js/utils');
6
2
 
7
3
  /**
8
4
  * Init uuid Generator and attach it to our runtime object.
9
- * @param {Runtime} runtime Runtime object.
5
+ * @param {import('../../types').Runtime} runtime Runtime object.
10
6
  * @returns {void}
11
7
  */
12
8
  exports.initUUIDFactory = (runtime) => {
@@ -4,16 +4,11 @@
4
4
  * Copyright 2021 Fachwerk
5
5
  */
6
6
 
7
- /**
8
- * @typedef {import('../types.js').Runtime} Runtime
9
- */
10
-
11
7
  const ObjectValidator = require('@weave-js/validator');
12
8
 
13
9
  /**
14
10
  * Init validator and attach it to our runtime object.
15
- * @param {Runtime} runtime Runtime object.
16
- * @returns {void}
11
+ * @param {import('../../types').Runtime} runtime Runtime object.
17
12
  */
18
13
  exports.initValidator = (runtime) => {
19
14
  const validator = ObjectValidator();
@@ -1,5 +1,10 @@
1
1
  const { isObject, pick } = require('@weave-js/utils');
2
2
 
3
+ /**
4
+ * Create a base tracing collector
5
+ * @param {import('../../../types').Runtime} runtime
6
+ * @returns {import('../../../types').TracingCollector}
7
+ */
3
8
  exports.createBaseTracingCollector = (runtime) => {
4
9
  const baseTracingCollector = Object.create(null);
5
10
 
@@ -22,6 +27,13 @@ exports.createBaseTracingCollector = (runtime) => {
22
27
  // throw new WeaveError('not implemented.')
23
28
  };
24
29
 
30
+ /**
31
+ * Flatten an object.
32
+ * @param {object} obj Object
33
+ * @param {boolean?} convertToString
34
+ * @param {string?} path
35
+ * @returns {object}
36
+ */
25
37
  baseTracingCollector.flattenTags = (obj, convertToString = false, path = '') => {
26
38
  if (!obj) {
27
39
  return null;
@@ -41,11 +53,17 @@ exports.createBaseTracingCollector = (runtime) => {
41
53
  }, {});
42
54
  };
43
55
 
44
- baseTracingCollector.getErrorFields = (err, fields) => {
45
- if (!err) {
56
+ /**
57
+ * Get fields of an error object.
58
+ * @param {Error} error Error
59
+ * @param {string[]} fields
60
+ * @returns
61
+ */
62
+ baseTracingCollector.getErrorFields = (error, fields) => {
63
+ if (!error) {
46
64
  return null;
47
65
  }
48
- return pick(err, fields);
66
+ return pick(error, fields);
49
67
  };
50
68
 
51
69
  return baseTracingCollector;
@@ -1,5 +1,10 @@
1
1
  const { createBaseTracingCollector } = require('./base');
2
2
 
3
+ /**
4
+ * Merge options wirh default options.
5
+ * @param {import('../../../types').TracingOptions} options
6
+ * @returns {import('../../../types').TracingOptions}
7
+ */
3
8
  const mergeDefaultOptions = (options) => {
4
9
  return Object.assign({
5
10
  interval: 5000,
@@ -10,6 +15,11 @@ const mergeDefaultOptions = (options) => {
10
15
  }, options);
11
16
  };
12
17
 
18
+ /**
19
+ * Create event collector for tracing
20
+ * @param {import('../../../types').TracingOptions} options
21
+ * @returns {(runtime: import('../../broker').Runtime, tracer: any) => import('../../../types').TracingCollector}
22
+ */
13
23
  module.exports = (options) => (runtime, tracer) => {
14
24
  options = mergeDefaultOptions(options);
15
25
 
@@ -1,3 +1,17 @@
1
+ /**
2
+ * Tracing collectors for distributed tracing and observability
3
+ *
4
+ * Provides pluggable collectors that capture and export trace data:
5
+ * - Event: Event-based collector that emits trace spans as events
6
+ * - BaseCollector: Abstract base class for custom collector implementations
7
+ *
8
+ * Collectors can be resolved by name (string) or provided as constructor functions/instances.
9
+ * They handle span lifecycle management, trace context propagation, and data export
10
+ * to various observability backends like Jaeger, Zipkin, or custom systems.
11
+ *
12
+ * @namespace TracingCollectors
13
+ */
14
+
1
15
  const { isFunction } = require('@weave-js/utils');
2
16
 
3
17
  const collectors = {
@@ -5,11 +19,30 @@ const collectors = {
5
19
  BaseCollector: require('./base')
6
20
  };
7
21
 
8
- const getByName = name => {
22
+ /**
23
+ * Get a tracing collector by name (case-insensitive lookup)
24
+ * @param {string} name Tracing collector name (e.g., 'Event', 'BaseCollector')
25
+ * @returns {import('../../../types').TracingCollector} The collector constructor or undefined if not found
26
+ */
27
+ const getByName = (name) => {
9
28
  const n = Object.keys(collectors).find(collectorName => collectorName.toLowerCase() === name.toLowerCase());
10
29
  return collectors[n];
11
30
  };
12
31
 
32
+ /**
33
+ * Resolve a tracing collector by name, function, or object
34
+ *
35
+ * Supports multiple collector resolution patterns:
36
+ * - String: Looks up collector by name ('Event', 'BaseCollector')
37
+ * - Function: Calls function with runtime to get collector instance
38
+ * - Object: Returns object directly as collector instance
39
+ * - Constructor: Instantiates with new operator
40
+ *
41
+ * @param {import('../../../types').Runtime} runtime Runtime instance for collector initialization
42
+ * @param {string | Function | Object | import('../../../types').TracingCollector} collector Tracing collector specification
43
+ * @returns {import('../../../types').TracingCollector} Resolved collector instance
44
+ * @throws {Error} When collector cannot be resolved or is not found
45
+ */
13
46
  exports.resolveCollector = (runtime, collector) => {
14
47
  let CollectorClass;
15
48
  if (typeof collector === 'string') {
@@ -4,6 +4,8 @@
4
4
  * Copyright 2021 Fachwerk
5
5
  */
6
6
 
7
+ const { WeavePacketSizeLimitExceeded } = require('../../errors');
8
+
7
9
  const EventEmitter = require('events').EventEmitter;
8
10
 
9
11
  /**
@@ -15,12 +17,12 @@ const EventEmitter = require('events').EventEmitter;
15
17
  * @property {number} interruptCounter Interruption counter.
16
18
  * @property {number} repeatAttemptCounter Repeat attempt counter
17
19
  * @property {function(Object, Object, Object):Promise<any>} init Repeat attempt counter
18
- */
20
+ */
19
21
 
20
22
  /**
21
23
  * Create a adapter base object.
22
24
  * @returns {AdapterBase} Adapter base object
23
- */
25
+ */
24
26
  const createTransportBase = () => {
25
27
  let prefix = 'weave';
26
28
 
@@ -57,7 +59,7 @@ const createTransportBase = () => {
57
59
  * @param {*} connectionEventParams Connection event
58
60
  * @param {boolean} [startHeartbeatTimers=true] Start timers for this adapter
59
61
  * @returns {void}
60
- */
62
+ */
61
63
  connected (connectionEventParams = {}) {
62
64
  this.bus.emit('$adapter.connected', connectionEventParams);
63
65
  },
@@ -82,7 +84,15 @@ const createTransportBase = () => {
82
84
  serialize (packet) {
83
85
  try {
84
86
  packet.payload.sender = this.broker.nodeId;
85
- return Buffer.from(JSON.stringify(packet));
87
+ const payloadBuffer = Buffer.from(JSON.stringify(packet));
88
+ const maxPayloadSize = this.broker.options.transport.maxPayloadSize
89
+ if (maxPayloadSize && payloadBuffer.byteLength > maxPayloadSize) {
90
+ this.log.warn({ type: packet.payload.type, })
91
+ if (this.broker.options.transport.rejectLargePayloadSize) {
92
+ throw new WeavePacketSizeLimitExceeded(packet.payload.type, payloadBuffer.byteLength, maxPayloadSize);
93
+ }
94
+ }
95
+ return payloadBuffer;
86
96
  } catch (error) {
87
97
  this.broker.handleError(error);
88
98
  }
@@ -6,30 +6,38 @@
6
6
  const { parse } = require('url');
7
7
  const getAdapterByName = require('./getAdapterByName');
8
8
 
9
- function fromURI (uri) {
10
- if (typeof uri !== 'string') {
11
- throw new Error('URI needs to be a string.');
9
+ function fromURI (uri, handleError) {
10
+ try {
11
+ if (typeof uri !== 'string') {
12
+ throw new Error('URI needs to be a string.');
13
+ }
14
+
15
+ const urlObject = parse(uri);
16
+
17
+ if (!urlObject.protocol) {
18
+ throw new Error('Protocol is missing.');
19
+ }
20
+
21
+ const name = urlObject.protocol.slice(0, -1).toLowerCase();
22
+
23
+ const AdapterFactory = getAdapterByName(name);
24
+
25
+ if (!AdapterFactory) {
26
+ throw new Error('No adapter found.');
27
+ }
28
+
29
+ let config = null;
30
+ if (AdapterFactory.uriToConfig) {
31
+ config = AdapterFactory.uriToConfig(urlObject);
32
+ }
33
+ return AdapterFactory(config);
34
+ } catch (error) {
35
+ if (typeof handleError === 'function') {
36
+ handleError(error);
37
+ return null;
38
+ }
39
+ throw error;
12
40
  }
13
-
14
- const urlObject = parse(uri);
15
-
16
- if (!urlObject.protocol) {
17
- throw new Error('Protocol is missing.');
18
- }
19
-
20
- const name = urlObject.protocol.slice(0, -1).toLowerCase();
21
-
22
- const AdapterFactory = getAdapterByName(name);
23
-
24
- if (!AdapterFactory) {
25
- throw new Error('No adapter found.');
26
- }
27
-
28
- let config = null;
29
- if (AdapterFactory.uriToConfig) {
30
- config = AdapterFactory.uriToConfig(urlObject);
31
- }
32
- return AdapterFactory(config);
33
41
  }
34
42
 
35
43
  module.exports = fromURI;
@@ -5,12 +5,13 @@
5
5
  */
6
6
 
7
7
  /**
8
- * @typedef {import('../types').Runtime} Runtime
9
- * @typedef {import('../types.js').TransportAdapter} TransportAdapter
10
- * @typedef {import('../types.js').Transport} Transport
11
- * @typedef {import('../types').TransportMessage} TransportMessage
12
- * @typedef {import('../types').Context} Context
13
- */
8
+ * @typedef {import('../../types').Runtime} Runtime
9
+ * @typedef {import('../../types').Transport} Transport
10
+ * @typedef {import('../../types').TransportMessage} TransportMessage
11
+ * @typedef {import('../../types').Context} Context
12
+ * @typedef {import('../../types').Node} Node
13
+ * @typedef {import('../../types').PendingStore} PendingStore
14
+ */
14
15
 
15
16
  // Own packages
16
17
  const { WeaveError, WeaveQueueSizeExceededError } = require('../errors');
@@ -21,11 +22,25 @@ const createMessageHandler = require('./messageHandlers');
21
22
  const { errorPayloadFactory } = require('./errorPayloadFactory');
22
23
 
23
24
  /**
24
- * Create a Transport adapter
25
- * @param {Runtime} runtime Broker instance
26
- * @param {TransportAdapter} adapter Adapter wrapper
27
- * @returns {Transport} transport
28
- */
25
+ * Creates a transport layer for network communication between Weave nodes
26
+ *
27
+ * The transport handles:
28
+ * - Network connections between nodes
29
+ * - Message serialization and deserialization
30
+ * - Request/response lifecycle management
31
+ * - Stream handling for large payloads
32
+ * - Heartbeat and node discovery
33
+ * - Connection reconnection and error recovery
34
+ * - Load balancing and routing
35
+ *
36
+ * @param {Runtime} runtime - Weave runtime instance
37
+ * @param {any} adapter - Transport adapter implementation (TCP, NATS, Redis, etc.)
38
+ * @returns {Transport} Configured transport instance with messaging capabilities
39
+ * @example
40
+ * const tcpAdapter = require('./adapters/tcp');
41
+ * const transport = createTransport(runtime, tcpAdapter);
42
+ * await transport.connect();
43
+ */
29
44
  exports.createTransport = (runtime, adapter) => {
30
45
  const transport = Object.create(null);
31
46
  const { nodeId, middlewareHandler, createLogger } = runtime;
@@ -54,10 +69,12 @@ exports.createTransport = (runtime, adapter) => {
54
69
  transport.adapterName = adapter.name;
55
70
  transport.statistics = {
56
71
  received: {
57
- packages: 0
72
+ packages: 0,
73
+ bytes: 0
58
74
  },
59
75
  sent: {
60
- packages: 0
76
+ packages: 0,
77
+ bytes: 0
61
78
  }
62
79
  };
63
80
 
@@ -12,9 +12,9 @@ const MessageTypes = require('./messageTypes');
12
12
  const { restoreError } = require('../utils/restoreError');
13
13
 
14
14
  /**
15
- * @typedef {import('../types').Transport} Transport
16
- * @typedef {import('../types').Runtime} Runtime
17
- * @typedef {import('../types').TransportMessageHandler} TransportMessageHandler
15
+ * @typedef {import('../types.__js').Transport} Transport
16
+ * @typedef {import('../types.__js').Runtime} Runtime
17
+ * @typedef {import('../types.__js').TransportMessageHandler} TransportMessageHandler
18
18
  */
19
19
 
20
20
  /**
@@ -1,5 +1,21 @@
1
1
 
2
+ /**
3
+ * Utility functions for Weave framework internal operations
4
+ *
5
+ * Provides common utilities for:
6
+ * - Options processing and default merging
7
+ * - Error restoration from serialized format
8
+ * - Handler wrapping for middleware integration
9
+ *
10
+ * These utilities are used internally by the framework and are not part
11
+ * of the public API. They handle low-level operations like configuration
12
+ * processing, error handling, and function composition.
13
+ *
14
+ * @namespace Utils
15
+ */
16
+
2
17
  exports = {
3
18
  ...require('./options'),
4
- ...require('./restoreError')
19
+ ...require('./restoreError'),
20
+ ...require('./wrap-handler')
5
21
  };
@@ -1,25 +1,54 @@
1
+ /**
2
+ * @typedef {import('../../types').ServiceSchema} ServiceSchema
3
+ */
4
+
1
5
  const {
2
6
  clone,
3
7
  compact,
4
8
  deepMerge,
5
9
  defaultsDeep,
6
10
  flatten,
7
- wrapHandler,
8
11
  wrapInArray
9
12
  } = require('@weave-js/utils');
10
13
 
14
+ const { wrapHandler } = require('../utils/wrap-handler');
15
+
16
+ /**
17
+ * Merge service settings with deep default merging
18
+ * @param {Object} source Source settings object
19
+ * @param {Object} targetSchema Target schema settings
20
+ * @returns {Object} Merged settings object
21
+ */
11
22
  function mergeSettings (source, targetSchema) {
12
23
  return defaultsDeep(source, targetSchema);
13
24
  }
14
25
 
26
+ /**
27
+ * Merge service metadata with deep default merging
28
+ * @param {Object} source Source metadata object
29
+ * @param {Object} targetSchema Target schema metadata
30
+ * @returns {Object} Merged metadata object
31
+ */
15
32
  function mergeMeta (source, targetSchema) {
16
33
  return defaultsDeep(source, targetSchema);
17
34
  }
18
35
 
36
+ /**
37
+ * Merge arrays ensuring unique values
38
+ * @param {Array} source Source array
39
+ * @param {Array} targetSchema Target schema array
40
+ * @returns {Array} Flattened and compacted unique array
41
+ */
19
42
  function mergeUniqueArrays (source, targetSchema) {
20
43
  return compact(flatten([targetSchema, source]));
21
44
  }
22
45
 
46
+ /**
47
+ * Merge service actions with handler wrapping and conflict resolution
48
+ * @param {Object} source Source actions object
49
+ * @param {Object} targetSchema Target schema actions
50
+ * @returns {Object} Merged actions object with wrapped handlers
51
+ */
23
52
  function mergeActions (source, targetSchema) {
24
53
  Object.keys(source).map(key => {
25
54
  // prevent action merge
@@ -37,7 +66,12 @@ function mergeActions (source, targetSchema) {
37
66
  return targetSchema;
38
67
  }
39
68
 
40
- // Merge events
69
+ /**
70
+ * Merge service events with handler composition
71
+ * @param {Object} source Source events object
72
+ * @param {Object} targetSchema Target schema events
73
+ * @returns {Object} Merged events object with composed handlers
74
+ */
41
75
  function mergeEvents (source, targetSchema) {
42
76
  Object.keys(source).map(key => {
43
77
  const sourceEvent = wrapHandler(source[key]);
@@ -54,10 +88,22 @@ function mergeEvents (source, targetSchema) {
54
88
  return targetSchema;
55
89
  }
56
90
 
91
+ /**
92
+ * Merge service methods by object assignment
93
+ * @param {Object} source Source methods object
94
+ * @param {Object} targetSchema Target schema methods
95
+ * @returns {Object} Merged methods object
96
+ */
57
97
  function mergeMethods (source, targetSchema) {
58
98
  return Object.assign(source, targetSchema);
59
99
  }
60
100
 
101
+ /**
102
+ * Merge action hooks by combining hook arrays
103
+ * @param {Object} source Source action hooks object
104
+ * @param {Object} target Target action hooks object
105
+ * @returns {Object} Merged action hooks with combined arrays
106
+ */
61
107
  function mergeActionHooks (source, target) {
62
108
  Object.keys(source).map(hookName => {
63
109
  if (!target[hookName]) {
@@ -74,10 +120,32 @@ function mergeActionHooks (source, target) {
74
120
  return target;
75
121
  }
76
122
 
123
+ /**
124
+ * Merge lifecycle hooks into a flattened array
125
+ * @param {Array|Function} source Source lifecycle hooks
126
+ * @param {Array|Function} targetSchema Target schema lifecycle hooks
127
+ * @returns {Array} Flattened and compacted lifecycle hooks array
128
+ */
77
129
  function mergeLifecicleHooks (source, targetSchema) {
78
130
  return compact(flatten([targetSchema, source]));
79
131
  }
80
132
 
133
+ /**
134
+ * Merge service schemas with comprehensive property handling
135
+ *
136
+ * Handles different merge strategies for various schema properties:
137
+ * - name, version: Override values
138
+ * - dependencies, mixins: Merge unique arrays
139
+ * - settings, meta: Deep merge objects
140
+ * - actions, events: Merge with handler wrapping
141
+ * - hooks: Merge action hooks by combining arrays
142
+ * - lifecycle hooks: Flatten into arrays
143
+ * - methods: Object assignment
144
+ *
145
+ * @param {ServiceSchema} mixin Mixin service schema
146
+ * @param {ServiceSchema} targetSchema Target service schema to merge into
147
+ * @returns {ServiceSchema} Merged service schema with combined properties
148
+ */
81
149
  function mergeSchemas (mixin, targetSchema) {
82
150
  const mixinSchema = clone(mixin);
83
151
  const resultSchema = clone(targetSchema);