@magek/common 0.0.6 → 0.0.7

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.
@@ -8,8 +8,8 @@ export interface ProjectionMetadata<TEntity extends EntityInterface, TReadModel
8
8
  methodName: string;
9
9
  joinKey: keyof TEntity | ReadModelJoinKeyFunction<TEntity, TReadModel>;
10
10
  }
11
- export type ProjectionResult<TReadModel> = TReadModel | ReadModelAction;
12
- export declare enum ReadModelAction {
13
- Delete = 0,
14
- Nothing = 1
11
+ export type ProjectionResult<TReadModel> = TReadModel | ProjectionAction;
12
+ export declare enum ProjectionAction {
13
+ Skip = 0,
14
+ Delete = 1
15
15
  }
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReadModelAction = void 0;
4
- var ReadModelAction;
5
- (function (ReadModelAction) {
6
- ReadModelAction[ReadModelAction["Delete"] = 0] = "Delete";
7
- ReadModelAction[ReadModelAction["Nothing"] = 1] = "Nothing";
8
- })(ReadModelAction || (exports.ReadModelAction = ReadModelAction = {}));
3
+ exports.ProjectionAction = void 0;
4
+ var ProjectionAction;
5
+ (function (ProjectionAction) {
6
+ ProjectionAction[ProjectionAction["Skip"] = 0] = "Skip";
7
+ ProjectionAction[ProjectionAction["Delete"] = 1] = "Delete";
8
+ })(ProjectionAction || (exports.ProjectionAction = ProjectionAction = {}));
@@ -1,5 +1,10 @@
1
1
  import { AnyClass } from '..';
2
+ import { EntityInterface } from './entity';
2
3
  export interface ReducerMetadata {
3
4
  class: AnyClass;
4
5
  methodName: string;
5
6
  }
7
+ export declare enum ReducerAction {
8
+ Skip = 0
9
+ }
10
+ export type ReducerResult<TEntity extends EntityInterface> = TEntity | ReducerAction;
@@ -1,2 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReducerAction = void 0;
4
+ var ReducerAction;
5
+ (function (ReducerAction) {
6
+ ReducerAction[ReducerAction["Skip"] = 0] = "Skip";
7
+ })(ReducerAction || (exports.ReducerAction = ReducerAction = {}));
@@ -23,6 +23,12 @@ exports.Register = void 0;
23
23
  * ```
24
24
  */
25
25
  class Register {
26
+ requestID;
27
+ responseHeaders;
28
+ flusher;
29
+ currentUser;
30
+ context;
31
+ eventList = [];
26
32
  /**
27
33
  * Creates a new instance of Register
28
34
  *
@@ -56,7 +62,6 @@ class Register {
56
62
  this.flusher = flusher;
57
63
  this.currentUser = currentUser;
58
64
  this.context = context;
59
- this.eventList = [];
60
65
  }
61
66
  /**
62
67
  * Register a list of events to be added to the event-store on handler completion
package/dist/config.js CHANGED
@@ -9,74 +9,83 @@ const _1 = require(".");
9
9
  * the Magek config.
10
10
  */
11
11
  class MagekConfig {
12
+ environmentName;
13
+ logLevel = logger_1.Level.debug;
14
+ logPrefix;
15
+ logger;
16
+ _runtime;
17
+ eventStoreAdapter;
18
+ readModelStoreAdapter;
19
+ sessionStoreAdapter;
20
+ appName = 'new-magek-app';
21
+ assets;
22
+ defaultResponseHeaders = {};
23
+ subscriptions = {
24
+ maxConnectionDurationInSeconds: 7 * 24 * 60 * 60, // 7 days
25
+ maxDurationInSeconds: 2 * 24 * 60 * 60, // 2 days
26
+ };
27
+ enableGraphQLIntrospection = true;
28
+ _userProjectRootPath;
29
+ codeRelativePath = 'dist';
30
+ eventDispatcherHandler = path.join(this.codeRelativePath, 'index.eventDispatcher');
31
+ eventStreamConsumer = path.join(this.codeRelativePath, 'index.consumeEventStream');
32
+ eventStreamProducer = path.join(this.codeRelativePath, 'index.produceEventStream');
33
+ serveGraphQLHandler = path.join(this.codeRelativePath, 'index.graphQLDispatcher');
34
+ sensorHealthHandler = path.join(this.codeRelativePath, 'index.health');
35
+ scheduledTaskHandler = path.join(this.codeRelativePath, 'index.triggerScheduledCommands');
36
+ notifySubscribersHandler = path.join(this.codeRelativePath, 'index.notifySubscribers');
37
+ functionRelativePath = path.join('..', this.codeRelativePath, 'index.js');
38
+ events = {};
39
+ notifications = {};
40
+ partitionKeys = {};
41
+ topicToEvent = {};
42
+ eventToTopic = {};
43
+ entities = {};
44
+ reducers = {};
45
+ commandHandlers = {};
46
+ queryHandlers = {};
47
+ eventHandlers = {};
48
+ readModels = {};
49
+ projections = {};
50
+ unProjections = {};
51
+ readModelSequenceKeys = {};
52
+ roles = {};
53
+ schemaMigrations = {};
54
+ scheduledCommandHandlers = {};
55
+ dataMigrationHandlers = {};
56
+ userHealthIndicators = {};
57
+ sensorConfiguration = {
58
+ health: {
59
+ globalAuthorizer: {
60
+ authorize: 'all',
61
+ },
62
+ magek: _1.DEFAULT_SENSOR_HEALTH_CONFIGURATIONS,
63
+ },
64
+ };
65
+ globalErrorsHandler;
66
+ enableSubscriptions = true;
67
+ nonExposedGraphQLMetadataKey = {};
68
+ // TTL for events stored in dispatched events table. Default to 5 minutes (i.e., 300 seconds).
69
+ dispatchedEventsTtl = 300;
70
+ traceConfiguration = {
71
+ enableTraceNotification: false,
72
+ includeInternal: false,
73
+ onStart: async () => { },
74
+ onEnd: async () => { },
75
+ };
76
+ eventStreamConfiguration = { enabled: false };
77
+ /** Environment variables to set when running the application */
78
+ env = {};
79
+ /**
80
+ * Add `TokenVerifier` implementations to this array to enable token verification.
81
+ * When a bearer token arrives in a request 'Authorization' header, it will be checked
82
+ * against all the verifiers registered here.
83
+ */
84
+ tokenVerifiers = [];
12
85
  constructor(environmentName) {
13
86
  this.environmentName = environmentName;
14
- this.logLevel = logger_1.Level.debug;
15
- this.appName = 'new-magek-app';
16
- this.defaultResponseHeaders = {};
17
- this.subscriptions = {
18
- maxConnectionDurationInSeconds: 7 * 24 * 60 * 60, // 7 days
19
- maxDurationInSeconds: 2 * 24 * 60 * 60, // 2 days
20
- };
21
- this.enableGraphQLIntrospection = true;
22
- this.codeRelativePath = 'dist';
23
- this.eventDispatcherHandler = path.join(this.codeRelativePath, 'index.eventDispatcher');
24
- this.eventStreamConsumer = path.join(this.codeRelativePath, 'index.consumeEventStream');
25
- this.eventStreamProducer = path.join(this.codeRelativePath, 'index.produceEventStream');
26
- this.serveGraphQLHandler = path.join(this.codeRelativePath, 'index.graphQLDispatcher');
27
- this.sensorHealthHandler = path.join(this.codeRelativePath, 'index.health');
28
- this.scheduledTaskHandler = path.join(this.codeRelativePath, 'index.triggerScheduledCommands');
29
- this.notifySubscribersHandler = path.join(this.codeRelativePath, 'index.notifySubscribers');
30
- this.functionRelativePath = path.join('..', this.codeRelativePath, 'index.js');
31
- this.events = {};
32
- this.notifications = {};
33
- this.partitionKeys = {};
34
- this.topicToEvent = {};
35
- this.eventToTopic = {};
36
- this.entities = {};
37
- this.reducers = {};
38
- this.commandHandlers = {};
39
- this.queryHandlers = {};
40
- this.eventHandlers = {};
41
- this.readModels = {};
42
- this.projections = {};
43
- this.unProjections = {};
44
- this.readModelSequenceKeys = {};
45
- this.roles = {};
46
- this.schemaMigrations = {};
47
- this.scheduledCommandHandlers = {};
48
- this.dataMigrationHandlers = {};
49
- this.userHealthIndicators = {};
50
- this.sensorConfiguration = {
51
- health: {
52
- globalAuthorizer: {
53
- authorize: 'all',
54
- },
55
- magek: _1.DEFAULT_SENSOR_HEALTH_CONFIGURATIONS,
56
- },
57
- };
58
- this.enableSubscriptions = true;
59
- this.nonExposedGraphQLMetadataKey = {};
60
- // TTL for events stored in dispatched events table. Default to 5 minutes (i.e., 300 seconds).
61
- this.dispatchedEventsTtl = 300;
62
- this.traceConfiguration = {
63
- enableTraceNotification: false,
64
- includeInternal: false,
65
- onStart: async () => { },
66
- onEnd: async () => { },
67
- };
68
- this.eventStreamConfiguration = { enabled: false };
69
- /** Environment variables to set when running the application */
70
- this.env = {};
71
- /**
72
- * Add `TokenVerifier` implementations to this array to enable token verification.
73
- * When a bearer token arrives in a request 'Authorization' header, it will be checked
74
- * against all the verifiers registered here.
75
- */
76
- this.tokenVerifiers = [];
77
87
  }
78
88
  get resourceNames() {
79
- var _a, _b;
80
89
  if (this.appName.length === 0)
81
90
  throw new Error('Application name cannot be empty');
82
91
  const applicationStackName = this.appName + '-app';
@@ -87,7 +96,7 @@ class MagekConfig {
87
96
  eventsDedup: applicationStackName + '-events-dedup',
88
97
  subscriptionsStore: applicationStackName + '-subscriptions-store',
89
98
  connectionsStore: applicationStackName + '-connections-store',
90
- streamTopic: (_b = (_a = this.eventStreamConfiguration.parameters) === null || _a === void 0 ? void 0 : _a.streamTopic) !== null && _b !== void 0 ? _b : 'magek_events',
99
+ streamTopic: this.eventStreamConfiguration.parameters?.streamTopic ?? 'magek_events',
91
100
  forReadModel(readModelName) {
92
101
  return applicationStackName + '-' + readModelName;
93
102
  },
@@ -36,6 +36,7 @@ export interface EventStoreEntryEnvelope extends TypedEnvelope {
36
36
  }
37
37
  export interface NonPersistedEventEnvelope extends EventStoreEntryEnvelope {
38
38
  kind: 'event';
39
+ createdAt: string;
39
40
  }
40
41
  export interface EventEnvelope extends NonPersistedEventEnvelope {
41
42
  id?: string;
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CommandHandlerGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class CommandHandlerGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ commandEnvelope;
7
+ commandMetadata;
6
8
  constructor(commandEnvelope, commandMetadata, originalError) {
7
9
  super(originalError);
8
10
  this.commandEnvelope = commandEnvelope;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EventGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class EventGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ eventEnvelope;
6
7
  constructor(eventEnvelope, originalError) {
7
8
  super(originalError);
8
9
  this.eventEnvelope = eventEnvelope;
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EventHandlerGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class EventHandlerGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ eventEnvelope;
7
+ eventInstance;
8
+ eventHandlerMetadata;
6
9
  constructor(eventEnvelope, eventInstance, eventHandlerMetadata, originalError) {
7
10
  super(originalError);
8
11
  this.eventEnvelope = eventEnvelope;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GlobalErrorContainer = void 0;
4
4
  class GlobalErrorContainer {
5
+ originalError;
5
6
  constructor(originalError) {
6
7
  this.originalError = originalError;
7
8
  }
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProjectionGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class ProjectionGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ entityEnvelope;
7
+ entity;
8
+ readModel;
9
+ projectionMetadata;
6
10
  constructor(entityEnvelope, entity, readModel, projectionMetadata, originalError) {
7
11
  super(originalError);
8
12
  this.entityEnvelope = entityEnvelope;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueryHandlerGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class QueryHandlerGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ query;
6
7
  constructor(query, originalError) {
7
8
  super(originalError);
8
9
  this.query = query;
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ReducerGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class ReducerGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ eventEnvelope;
7
+ eventInstance;
8
+ snapshotInstance;
9
+ reducerMetadata;
6
10
  constructor(eventEnvelope, eventInstance, snapshotInstance, reducerMetadata, originalError) {
7
11
  super(originalError);
8
12
  this.eventEnvelope = eventEnvelope;
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ScheduleCommandGlobalError = void 0;
4
4
  const global_error_container_1 = require("./global-error-container");
5
5
  class ScheduleCommandGlobalError extends global_error_container_1.GlobalErrorContainer {
6
+ scheduleCommandEnvelope;
7
+ scheduleCommandMetadata;
6
8
  constructor(scheduleCommandEnvelope, scheduleCommandMetadata, originalError) {
7
9
  super(originalError);
8
10
  this.scheduleCommandEnvelope = scheduleCommandEnvelope;
@@ -13,6 +13,7 @@ const global_error_container_1 = require("./global-error-container");
13
13
  * This class is kept for backwards compatibility.
14
14
  */
15
15
  class SnapshotPersistHandlerGlobalError extends global_error_container_1.GlobalErrorContainer {
16
+ snapshot;
16
17
  constructor(snapshot, originalError) {
17
18
  super(originalError);
18
19
  this.snapshot = snapshot;
package/dist/errors.js CHANGED
@@ -3,10 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InvalidReducerError = exports.InvalidEventError = exports.OptimisticConcurrencyUnexpectedVersionError = exports.InvalidVersionError = exports.NotFoundError = exports.MagekTokenNotBeforeError = exports.MagekTokenExpiredError = exports.NotAuthorizedError = exports.InvalidProtocolError = exports.InvalidParameterError = exports.MagekError = void 0;
4
4
  exports.httpStatusCodeFor = httpStatusCodeFor;
5
5
  class MagekError extends Error {
6
+ data;
7
+ code;
6
8
  constructor(message, code, data) {
7
9
  super(message);
8
10
  this.data = data;
9
- this.code = code !== null && code !== void 0 ? code : this.constructor.name;
11
+ this.code = code ?? this.constructor.name;
10
12
  }
11
13
  }
12
14
  exports.MagekError = MagekError;
@@ -38,6 +40,8 @@ class InvalidEventError extends MagekError {
38
40
  }
39
41
  exports.InvalidEventError = InvalidEventError;
40
42
  class InvalidReducerError extends MagekError {
43
+ eventInstance;
44
+ snapshotInstance;
41
45
  constructor(message, eventInstance, snapshotInstance) {
42
46
  super(message);
43
47
  this.eventInstance = eventInstance;
@@ -46,7 +50,6 @@ class InvalidReducerError extends MagekError {
46
50
  }
47
51
  exports.InvalidReducerError = InvalidReducerError;
48
52
  function httpStatusCodeFor(error) {
49
- var _a;
50
53
  const errorToHTTPCode = {
51
54
  [InvalidParameterError.name]: 400,
52
55
  [InvalidProtocolError.name]: 400,
@@ -56,5 +59,5 @@ function httpStatusCodeFor(error) {
56
59
  [NotFoundError.name]: 404,
57
60
  [InvalidVersionError.name]: 422,
58
61
  };
59
- return (_a = errorToHTTPCode[error.constructor.name]) !== null && _a !== void 0 ? _a : 500;
62
+ return errorToHTTPCode[error.constructor.name] ?? 500;
60
63
  }
@@ -15,38 +15,42 @@ var MessageTypes;
15
15
  MessageTypes["GQL_STOP"] = "stop";
16
16
  })(MessageTypes || (exports.MessageTypes = MessageTypes = {}));
17
17
  class GraphQLInitError {
18
+ payload;
19
+ type = MessageTypes.GQL_CONNECTION_ERROR;
18
20
  constructor(payload) {
19
21
  this.payload = payload;
20
- this.type = MessageTypes.GQL_CONNECTION_ERROR;
21
22
  }
22
23
  }
23
24
  exports.GraphQLInitError = GraphQLInitError;
24
25
  class GraphQLInitAck {
25
- constructor() {
26
- this.type = MessageTypes.GQL_CONNECTION_ACK;
27
- }
26
+ type = MessageTypes.GQL_CONNECTION_ACK;
28
27
  }
29
28
  exports.GraphQLInitAck = GraphQLInitAck;
30
29
  class GraphQLData {
30
+ id;
31
+ payload;
32
+ type = MessageTypes.GQL_DATA;
31
33
  constructor(id, payload) {
32
34
  this.id = id;
33
35
  this.payload = payload;
34
- this.type = MessageTypes.GQL_DATA;
35
36
  }
36
37
  }
37
38
  exports.GraphQLData = GraphQLData;
38
39
  class GraphQLError {
40
+ id;
41
+ payload;
42
+ type = MessageTypes.GQL_ERROR;
39
43
  constructor(id, payload) {
40
44
  this.id = id;
41
45
  this.payload = payload;
42
- this.type = MessageTypes.GQL_ERROR;
43
46
  }
44
47
  }
45
48
  exports.GraphQLError = GraphQLError;
46
49
  class GraphQLComplete {
50
+ id;
51
+ type = MessageTypes.GQL_COMPLETE;
47
52
  constructor(id) {
48
53
  this.id = id;
49
- this.type = MessageTypes.GQL_COMPLETE;
50
54
  }
51
55
  }
52
56
  exports.GraphQLComplete = GraphQLComplete;
@@ -23,7 +23,7 @@ async function request(url, method = 'GET', data = '', config = {}) {
23
23
  const body = [];
24
24
  res.on('data', (chunk) => body.push(chunk));
25
25
  res.on('end', () => {
26
- if (!(res === null || res === void 0 ? void 0 : res.statusCode)) {
26
+ if (!res?.statusCode) {
27
27
  return reject(new Error('Unknown HTTP status code'));
28
28
  }
29
29
  // Accept 2xx codes or any explicitly accepted status codes
@@ -32,7 +32,7 @@ async function request(url, method = 'GET', data = '', config = {}) {
32
32
  }
33
33
  const buffer = Buffer.concat(body).toString();
34
34
  resolve({
35
- status: res === null || res === void 0 ? void 0 : res.statusCode,
35
+ status: res?.statusCode,
36
36
  body: buffer,
37
37
  });
38
38
  });
package/dist/index.d.ts CHANGED
@@ -26,5 +26,5 @@ export * from './runtime';
26
26
  export * from './event-store-adapter';
27
27
  export * from './read-model-store-adapter';
28
28
  export * from './session-store-adapter';
29
- export * from './field-decorator';
30
29
  export * from './metadata-types';
30
+ export * from './timestamp-generator';
package/dist/index.js CHANGED
@@ -29,5 +29,5 @@ tslib_1.__exportStar(require("./runtime"), exports);
29
29
  tslib_1.__exportStar(require("./event-store-adapter"), exports);
30
30
  tslib_1.__exportStar(require("./read-model-store-adapter"), exports);
31
31
  tslib_1.__exportStar(require("./session-store-adapter"), exports);
32
- tslib_1.__exportStar(require("./field-decorator"), exports);
33
32
  tslib_1.__exportStar(require("./metadata-types"), exports);
33
+ tslib_1.__exportStar(require("./timestamp-generator"), exports);
@@ -37,6 +37,26 @@ export declare function createInstance<T>(instanceClass: Class<T>, rawObject: Re
37
37
  * @see {@link createInstance}
38
38
  */
39
39
  export declare function createInstances<T>(instanceClass: Class<T>, rawObjects: Array<Record<string, any>>): T[];
40
+ /**
41
+ * Applies partial changes to an entity, optionally using defaults when creating a new instance.
42
+ * Designed for plain objects (entity state); use `createInstance` for class instances.
43
+ *
44
+ * @remarks
45
+ * This function always returns a shallow copy, ensuring immutability.
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // Update existing entity
50
+ * const updated = evolve(current, { balance: current.balance + event.amount })
51
+ * // Create new entity with defaults
52
+ * const created = evolve(undefined, { id: event.entityId, name: event.name }, { status: 'active' })
53
+ * // Create new entity without defaults (changes must be complete)
54
+ * const created = evolve(undefined, { id: event.entityId, name: event.name, status: 'active' })
55
+ * ```
56
+ */
57
+ export declare function evolve<T extends object>(current: T, changes: Partial<T>): T;
58
+ export declare function evolve<C extends object, D extends object>(current: undefined, changes: C, defaults: D): C & D;
59
+ export declare function evolve<T extends object>(current: undefined, changes: T): T;
40
60
  /**
41
61
  * Creates an instance of the read model class with the calculated properties included
42
62
  * @param instanceClass The read model class
package/dist/instances.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createInstance = createInstance;
4
4
  exports.createInstances = createInstances;
5
+ exports.evolve = evolve;
5
6
  exports.createInstanceWithCalculatedProperties = createInstanceWithCalculatedProperties;
6
7
  /**
7
8
  * Creates an instance of the given class from the given raw object.
@@ -44,6 +45,15 @@ function createInstance(instanceClass, rawObject) {
44
45
  function createInstances(instanceClass, rawObjects) {
45
46
  return rawObjects.map((rawObject) => createInstance(instanceClass, rawObject));
46
47
  }
48
+ function evolve(current, changes, defaults) {
49
+ if (current !== undefined) {
50
+ return { ...current, ...changes };
51
+ }
52
+ if (defaults !== undefined) {
53
+ return { ...defaults, ...changes };
54
+ }
55
+ return { ...changes };
56
+ }
47
57
  /**
48
58
  * Creates an instance of the read model class with the calculated properties included
49
59
  * @param instanceClass The read model class
package/dist/logger.js CHANGED
@@ -11,12 +11,11 @@ var Level;
11
11
  })(Level || (exports.Level = Level = {}));
12
12
  const defaultLogPrefix = 'Magek';
13
13
  function getLogger(config, location, overridenLogPrefix) {
14
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
15
- const debug = (_b = (_a = config.logger) === null || _a === void 0 ? void 0 : _a.debug) !== null && _b !== void 0 ? _b : console.debug;
16
- const info = (_d = (_c = config.logger) === null || _c === void 0 ? void 0 : _c.info) !== null && _d !== void 0 ? _d : console.info;
17
- const warn = (_f = (_e = config.logger) === null || _e === void 0 ? void 0 : _e.warn) !== null && _f !== void 0 ? _f : console.warn;
18
- const error = (_h = (_g = config.logger) === null || _g === void 0 ? void 0 : _g.error) !== null && _h !== void 0 ? _h : console.error;
19
- const logPrefix = (_j = overridenLogPrefix !== null && overridenLogPrefix !== void 0 ? overridenLogPrefix : config === null || config === void 0 ? void 0 : config.logPrefix) !== null && _j !== void 0 ? _j : defaultLogPrefix;
14
+ const debug = config.logger?.debug ?? console.debug;
15
+ const info = config.logger?.info ?? console.info;
16
+ const warn = config.logger?.warn ?? console.warn;
17
+ const error = config.logger?.error ?? console.error;
18
+ const logPrefix = overridenLogPrefix ?? config?.logPrefix ?? defaultLogPrefix;
20
19
  const locationStr = location ? `|${location}: ` : ': ';
21
20
  const prefix = `[${logPrefix}]${locationStr}`;
22
21
  const prefixedDebugFunction = debug.bind(null, prefix);
@@ -2,6 +2,26 @@ import 'reflect-metadata';
2
2
  export type ClassType = {
3
3
  new (...args: unknown[]): unknown;
4
4
  };
5
+ /**
6
+ * Type function for specifying field types
7
+ * The parameter is optional and not used - it's just for TypeGraphQL-style ergonomics
8
+ */
9
+ export type TypeFunction = (type?: unknown) => unknown;
10
+ /**
11
+ * Options for the @field() decorator
12
+ */
13
+ export interface FieldOptions {
14
+ nullable?: boolean;
15
+ readonly?: boolean;
16
+ }
17
+ /**
18
+ * Metadata stored for each field
19
+ */
20
+ export interface FieldMetadata {
21
+ name: string;
22
+ typeFunction?: TypeFunction;
23
+ options: FieldOptions;
24
+ }
5
25
  export type TypeGroup = 'String' | 'Number' | 'Boolean' | 'Enum' | 'Union' | 'Intersection' | 'Function' | 'Class' | 'Interface' | 'Type' | 'Array' | 'Object' | 'ReadonlyArray' | 'Other';
6
26
  export interface TypeMetadata {
7
27
  name: string;
package/dist/promises.js CHANGED
@@ -33,6 +33,7 @@ class Promises {
33
33
  }
34
34
  exports.Promises = Promises;
35
35
  class PromisesError extends Error {
36
+ failedReasons;
36
37
  constructor(rejectedResults) {
37
38
  const reasons = rejectedResults.map((res) => res.reason);
38
39
  super(reasons.join('. '));
package/dist/retrier.js CHANGED
@@ -15,9 +15,9 @@ async function retryIfError(logicToRetry, errorClassThatRetries, logger, maxRetr
15
15
  let errorAfterMaxTries;
16
16
  for (tryNumber = 1; tryNumber <= maxRetries; tryNumber++) {
17
17
  try {
18
- logger === null || logger === void 0 ? void 0 : logger.debug(`[retryIfError] Try number ${tryNumber}`);
18
+ logger?.debug(`[retryIfError] Try number ${tryNumber}`);
19
19
  const result = await logicToRetry(tryNumber);
20
- logger === null || logger === void 0 ? void 0 : logger.debug(`[retryIfError] Succeeded after ${tryNumber} retries`);
20
+ logger?.debug(`[retryIfError] Succeeded after ${tryNumber} retries`);
21
21
  return result;
22
22
  }
23
23
  catch (e) {
@@ -30,7 +30,7 @@ async function retryIfError(logicToRetry, errorClassThatRetries, logger, maxRetr
30
30
  }
31
31
  function checkRetryError(e, errorClassThatRetries, logger) {
32
32
  if (!(e instanceof errorClassThatRetries)) {
33
- logger === null || logger === void 0 ? void 0 : logger.debug('[checkRetryError] Logic failed with an error that must not be retried. Rethrowing');
33
+ logger?.debug('[checkRetryError] Logic failed with an error that must not be retried. Rethrowing');
34
34
  throw e;
35
35
  }
36
36
  }
package/dist/searcher.js CHANGED
@@ -7,6 +7,16 @@ exports.Searcher = void 0;
7
7
  * Check the documentation on the individual methods to know more about how to do so.
8
8
  */
9
9
  class Searcher {
10
+ objectClass;
11
+ searcherFunction;
12
+ finderByKeyFunction;
13
+ // private offset?: number
14
+ _limit;
15
+ _afterCursor;
16
+ filters = {};
17
+ _sortByList = {};
18
+ _paginatedVersion = false;
19
+ _selectFor;
10
20
  /**
11
21
  * @param objectClass The class of the object you want to run the search for.
12
22
  * @param searcherFunction The function that will receive all the filters and run the actual search
@@ -16,9 +26,6 @@ class Searcher {
16
26
  this.objectClass = objectClass;
17
27
  this.searcherFunction = searcherFunction;
18
28
  this.finderByKeyFunction = finderByKeyFunction;
19
- this.filters = {};
20
- this._sortByList = {};
21
- this._paginatedVersion = false;
22
29
  }
23
30
  /**
24
31
  * Adds a filter for the search. For example: If you want to search for people whose age is greater than 30
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Generates unique, monotonically increasing ISO 8601 timestamps with sub-millisecond precision.
3
+ *
4
+ * Format: 2024-01-28T12:34:56.12345678Z where:
5
+ * - Digits 1-3 (123): actual milliseconds from Date.now()
6
+ * - Digits 4-7 (4567): monotonic counter (0000-9999)
7
+ * - Digit 8 (8): random seed for distributed uniqueness (0-9)
8
+ *
9
+ * This provides:
10
+ * - 10,000 unique orderable timestamps per millisecond per instance
11
+ * - 100,000 total combinations across distributed instances (10,000 counter values × 10 seeds)
12
+ * - Standard ISO 8601 format parseable by any Date library
13
+ * - Deterministic ordering via string comparison
14
+ * - Random component for distributed uniqueness
15
+ */
16
+ export declare class TimestampGenerator {
17
+ private lastMs;
18
+ private counter;
19
+ private readonly randomSeed;
20
+ constructor();
21
+ /**
22
+ * Generates the next unique timestamp with microsecond precision.
23
+ *
24
+ * @returns ISO 8601 timestamp string with 8 fractional digits
25
+ */
26
+ next(): string;
27
+ }
28
+ /**
29
+ * Returns the singleton TimestampGenerator instance.
30
+ * Creates it if it doesn't exist yet.
31
+ *
32
+ * @returns The global TimestampGenerator instance
33
+ */
34
+ export declare function getTimestampGenerator(): TimestampGenerator;
35
+ /**
36
+ * Resets the singleton instance. Primarily for testing purposes.
37
+ */
38
+ export declare function resetTimestampGenerator(): void;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimestampGenerator = void 0;
4
+ exports.getTimestampGenerator = getTimestampGenerator;
5
+ exports.resetTimestampGenerator = resetTimestampGenerator;
6
+ /**
7
+ * Generates unique, monotonically increasing ISO 8601 timestamps with sub-millisecond precision.
8
+ *
9
+ * Format: 2024-01-28T12:34:56.12345678Z where:
10
+ * - Digits 1-3 (123): actual milliseconds from Date.now()
11
+ * - Digits 4-7 (4567): monotonic counter (0000-9999)
12
+ * - Digit 8 (8): random seed for distributed uniqueness (0-9)
13
+ *
14
+ * This provides:
15
+ * - 10,000 unique orderable timestamps per millisecond per instance
16
+ * - 100,000 total combinations across distributed instances (10,000 counter values × 10 seeds)
17
+ * - Standard ISO 8601 format parseable by any Date library
18
+ * - Deterministic ordering via string comparison
19
+ * - Random component for distributed uniqueness
20
+ */
21
+ class TimestampGenerator {
22
+ lastMs = 0;
23
+ counter = 0;
24
+ randomSeed;
25
+ constructor() {
26
+ // Generate random seed 0-9 for distributed uniqueness
27
+ this.randomSeed = Math.floor(Math.random() * 10);
28
+ }
29
+ /**
30
+ * Generates the next unique timestamp with microsecond precision.
31
+ *
32
+ * @returns ISO 8601 timestamp string with 8 fractional digits
33
+ */
34
+ next() {
35
+ const nowMs = Date.now();
36
+ // Reset counter only if we've moved forward to a new millisecond
37
+ // When nowMs <= lastMs (clock skew), continue using lastMs and incrementing counter
38
+ if (nowMs > this.lastMs) {
39
+ this.lastMs = nowMs;
40
+ this.counter = 0;
41
+ }
42
+ // If counter exceeds 9999, advance lastMs to maintain monotonicity
43
+ if (this.counter > 9999) {
44
+ this.lastMs++;
45
+ this.counter = 0;
46
+ }
47
+ // Format: milliseconds (3 digits) + counter (4 digits) + seed (1 digit)
48
+ const microPart = String(this.counter).padStart(4, '0') + String(this.randomSeed);
49
+ this.counter++;
50
+ // Build ISO 8601 timestamp with microsecond precision
51
+ // Use lastMs (which may be clamped due to clock skew) instead of nowMs
52
+ const date = new Date(this.lastMs);
53
+ const isoString = date.toISOString();
54
+ // Replace milliseconds with our extended precision
55
+ // ISO format: 2024-01-28T12:34:56.123Z
56
+ // ^^^
57
+ // We extend to: 2024-01-28T12:34:56.12345678Z
58
+ const withMicros = isoString.slice(0, -1) + microPart + 'Z';
59
+ return withMicros;
60
+ }
61
+ }
62
+ exports.TimestampGenerator = TimestampGenerator;
63
+ /**
64
+ * Global singleton instance of TimestampGenerator.
65
+ */
66
+ let timestampGeneratorInstance;
67
+ /**
68
+ * Returns the singleton TimestampGenerator instance.
69
+ * Creates it if it doesn't exist yet.
70
+ *
71
+ * @returns The global TimestampGenerator instance
72
+ */
73
+ function getTimestampGenerator() {
74
+ if (!timestampGeneratorInstance) {
75
+ timestampGeneratorInstance = new TimestampGenerator();
76
+ }
77
+ return timestampGeneratorInstance;
78
+ }
79
+ /**
80
+ * Resets the singleton instance. Primarily for testing purposes.
81
+ */
82
+ function resetTimestampGenerator() {
83
+ timestampGeneratorInstance = undefined;
84
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magek/common",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Contains Magek common helpers used by the core and provider packages",
5
5
  "keywords": [
6
6
  "framework-common-helpers"
@@ -33,7 +33,7 @@
33
33
  "uuid": "^13.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@magek/eslint-config": "^0.0.6",
36
+ "@magek/eslint-config": "^0.0.7",
37
37
  "@types/chai": "5.2.3",
38
38
  "@types/chai-as-promised": "8.0.2",
39
39
  "@types/mocha": "10.0.10",
@@ -1,63 +0,0 @@
1
- import 'reflect-metadata';
2
- /**
3
- * Type function for specifying field types
4
- * The parameter is optional and not used - it's just for TypeGraphQL-style ergonomics
5
- */
6
- export type TypeFunction = (type?: unknown) => unknown;
7
- /**
8
- * Options for the @Field() decorator
9
- */
10
- export interface FieldOptions {
11
- nullable?: boolean;
12
- readonly?: boolean;
13
- }
14
- /**
15
- * Metadata stored for each field
16
- */
17
- export interface FieldMetadata {
18
- name: string;
19
- typeFunction?: TypeFunction;
20
- options: FieldOptions;
21
- designType?: unknown;
22
- }
23
- /**
24
- * Stage 3 decorator context for class fields (TypeScript 5.0+)
25
- */
26
- interface Stage3FieldContext {
27
- kind: 'field';
28
- name: string | symbol;
29
- static: boolean;
30
- private: boolean;
31
- metadata: Record<string | symbol, unknown>;
32
- access?: {
33
- get: () => unknown;
34
- set: (value: unknown) => void;
35
- };
36
- addInitializer?: (initializer: () => void) => void;
37
- }
38
- /**
39
- * Decorator return type that supports both legacy and Stage 3 formats.
40
- * This is a function that can be called with either signature.
41
- */
42
- type UniversalFieldDecorator = {
43
- (target: object, propertyKey: string | symbol): void;
44
- (value: undefined, context: Stage3FieldContext): void;
45
- };
46
- /**
47
- * @Field() decorator for explicit type declaration
48
- *
49
- * Supports both legacy decorators (experimentalDecorators) and
50
- * Stage 3 TC39 decorators.
51
- *
52
- * Usage:
53
- * @Field() - Simple type (inferred from design:type in legacy mode)
54
- * @Field(type => String) - Explicit type
55
- * @Field(type => [String]) - Array type
56
- * @Field({ nullable: true }) - With options
57
- * @Field(type => String, { nullable: true }) - Type with options
58
- */
59
- export declare function Field(): UniversalFieldDecorator;
60
- export declare function Field(options: FieldOptions): UniversalFieldDecorator;
61
- export declare function Field(typeFunction: TypeFunction): UniversalFieldDecorator;
62
- export declare function Field(typeFunction: TypeFunction, options: FieldOptions): UniversalFieldDecorator;
63
- export {};
@@ -1,122 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Field = Field;
4
- require("reflect-metadata");
5
- // Symbol for storing fields metadata (for Stage 3 decorators)
6
- const FIELDS_KEY = Symbol.for('magek:fields');
7
- /**
8
- * Type guard to detect Stage 3 decorator context
9
- */
10
- function isStage3Context(arg) {
11
- return (arg !== null &&
12
- typeof arg === 'object' &&
13
- 'kind' in arg &&
14
- arg.kind === 'field' &&
15
- 'name' in arg &&
16
- 'metadata' in arg);
17
- }
18
- /**
19
- * Store field metadata on a constructor (works for both legacy and Stage 3)
20
- */
21
- function storeFieldMetadata(constructor, fieldMetadata) {
22
- // Get existing fields
23
- let existingFields = [];
24
- // Try Reflect.getMetadata first
25
- try {
26
- if (typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {
27
- existingFields = Reflect.getMetadata('magek:fields', constructor) || [];
28
- }
29
- }
30
- catch {
31
- // Ignore
32
- }
33
- // Also check fallback property
34
- const ctorWithFields = constructor;
35
- if (existingFields.length === 0 && ctorWithFields.__magek_fields__) {
36
- existingFields = ctorWithFields.__magek_fields__;
37
- }
38
- // Add this field (avoid duplicates by name)
39
- const filteredFields = existingFields.filter((f) => f.name !== fieldMetadata.name);
40
- filteredFields.push(fieldMetadata);
41
- // Store using both mechanisms for reliability
42
- try {
43
- if (typeof Reflect !== 'undefined' && typeof Reflect.defineMetadata === 'function') {
44
- Reflect.defineMetadata('magek:fields', filteredFields, constructor);
45
- }
46
- }
47
- catch {
48
- // Ignore
49
- }
50
- // Also store as a fallback property
51
- ctorWithFields.__magek_fields__ = filteredFields;
52
- }
53
- /**
54
- * Handle legacy decorator format (experimentalDecorators)
55
- */
56
- function handleLegacyDecorator(target, propertyKey, typeFunction, fieldOptions) {
57
- // Get design type from TypeScript decorator metadata
58
- let designType;
59
- try {
60
- if (typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {
61
- designType = Reflect.getMetadata('design:type', target, propertyKey);
62
- }
63
- }
64
- catch {
65
- // Ignore - Reflect.getMetadata may fail if called before initialization
66
- }
67
- const fieldMetadata = {
68
- name: propertyKey.toString(),
69
- typeFunction,
70
- options: fieldOptions,
71
- designType,
72
- };
73
- const constructor = target.constructor;
74
- if (constructor) {
75
- storeFieldMetadata(constructor, fieldMetadata);
76
- }
77
- }
78
- /**
79
- * Handle Stage 3 decorator format (TC39 decorators)
80
- */
81
- function handleStage3Decorator(context, typeFunction, fieldOptions) {
82
- const fieldMetadata = {
83
- name: context.name.toString(),
84
- typeFunction,
85
- options: fieldOptions,
86
- designType: undefined, // Stage 3 doesn't have design:type
87
- };
88
- // Store in context.metadata for later retrieval by class decorators
89
- // Class decorators (like @Command, @Entity, etc.) will transfer this to the class constructor
90
- if (!context.metadata[FIELDS_KEY]) {
91
- context.metadata[FIELDS_KEY] = [];
92
- }
93
- const fields = context.metadata[FIELDS_KEY];
94
- const filteredFields = fields.filter((f) => f.name !== fieldMetadata.name);
95
- filteredFields.push(fieldMetadata);
96
- context.metadata[FIELDS_KEY] = filteredFields;
97
- }
98
- function Field(typeFunctionOrOptions, options) {
99
- // Parse arguments
100
- let typeFunction;
101
- let fieldOptions = {};
102
- if (typeof typeFunctionOrOptions === 'function') {
103
- typeFunction = typeFunctionOrOptions;
104
- fieldOptions = options || {};
105
- }
106
- else if (typeFunctionOrOptions) {
107
- fieldOptions = typeFunctionOrOptions;
108
- }
109
- // Return decorator that handles both formats
110
- return function fieldDecorator(targetOrValue, propertyKeyOrContext) {
111
- // Detect Stage 3 vs Legacy based on the second argument
112
- if (isStage3Context(propertyKeyOrContext)) {
113
- // Stage 3 decorator
114
- handleStage3Decorator(propertyKeyOrContext, typeFunction, fieldOptions);
115
- }
116
- else if (targetOrValue) {
117
- // Legacy decorator
118
- handleLegacyDecorator(targetOrValue, propertyKeyOrContext, typeFunction, fieldOptions);
119
- }
120
- // If targetOrValue is undefined and not Stage 3, silently skip
121
- };
122
- }