@freshpointcz/fresh-core 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +46 -5
- package/dist/index.d.ts +46 -5
- package/dist/index.js +81 -54
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import dayjs, { Dayjs } from 'dayjs';
|
|
2
|
-
import {
|
|
3
|
-
import { BaseEntity, ColumnOptions, Repository, EntityTarget, EntityManager, DataSourceOptions } from 'typeorm';
|
|
2
|
+
import { BaseEntity, ColumnOptions, Repository, EntityTarget, EntityManager, ObjectLiteral, EntitySubscriberInterface, InsertEvent, UpdateEvent, SoftRemoveEvent, TransactionCommitEvent, DataSourceOptions } from 'typeorm';
|
|
4
3
|
import { Job } from 'node-schedule';
|
|
5
4
|
import * as _eslint_core from '@eslint/core';
|
|
6
5
|
import * as typescript_eslint_dist_compatibility_types from 'typescript-eslint/dist/compatibility-types';
|
|
@@ -54,8 +53,6 @@ declare class SinglePromiseWaiter<T = any> {
|
|
|
54
53
|
get hasPromise(): boolean;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
declare const logger: Logger;
|
|
58
|
-
|
|
59
56
|
declare function isValidCron(expr: string): boolean;
|
|
60
57
|
|
|
61
58
|
/**
|
|
@@ -348,6 +345,50 @@ declare abstract class FreshDao<T extends BaseEntity> {
|
|
|
348
345
|
protected getRepo(manager?: EntityManager, entity?: EntityTarget<T>): Repository<T>;
|
|
349
346
|
}
|
|
350
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Change event types for entity lifecycle tracking.
|
|
350
|
+
*/
|
|
351
|
+
type EntityChangeEvent = "created" | "updated" | "deleted";
|
|
352
|
+
/**
|
|
353
|
+
* Abstract base class for TypeORM EntitySubscribers that need to:
|
|
354
|
+
* 1. Track entity changes (insert/update/soft-remove)
|
|
355
|
+
* 2. Batch pending notifications within a transaction
|
|
356
|
+
* 3. Send notifications only after transaction commit
|
|
357
|
+
*
|
|
358
|
+
* Subclasses must implement:
|
|
359
|
+
* - `listenTo()` — target entity class
|
|
360
|
+
* - `pendingKey` — unique key for storing pending events in `queryRunner.data`
|
|
361
|
+
* - `subscriberName` — name used in log messages
|
|
362
|
+
* - `handleNotification(id, changeEvent, manager)` — actual notification logic
|
|
363
|
+
*/
|
|
364
|
+
declare abstract class BaseEntityChangeSubscriber<Entity extends ObjectLiteral, IdType = number> implements EntitySubscriberInterface<Entity> {
|
|
365
|
+
/**
|
|
366
|
+
* Unique key used to store pending change events in `queryRunner.data`.
|
|
367
|
+
* Must be unique per subscriber to avoid collisions when multiple subscribers
|
|
368
|
+
* share the same queryRunner.
|
|
369
|
+
*/
|
|
370
|
+
protected abstract readonly PENDING_KEY: string;
|
|
371
|
+
/**
|
|
372
|
+
* Human-readable name for log/error messages.
|
|
373
|
+
*/
|
|
374
|
+
protected abstract readonly SUBSCRIBER_NAME: string;
|
|
375
|
+
/**
|
|
376
|
+
* Return the entity class this subscriber listens to.
|
|
377
|
+
*/
|
|
378
|
+
abstract listenTo(): Function;
|
|
379
|
+
/**
|
|
380
|
+
* Implement the actual notification/side-effect logic.
|
|
381
|
+
* Called after transaction commit (or immediately if no transaction is active).
|
|
382
|
+
*/
|
|
383
|
+
protected abstract handleNotification(id: IdType, changeEvent: EntityChangeEvent, manager: EntityManager): Promise<void>;
|
|
384
|
+
afterInsert(event: InsertEvent<Entity>): void;
|
|
385
|
+
afterUpdate(event: UpdateEvent<Entity>): void;
|
|
386
|
+
afterSoftRemove(event: SoftRemoveEvent<Entity>): void;
|
|
387
|
+
afterTransactionCommit(event: TransactionCommitEvent): Promise<void>;
|
|
388
|
+
private addPending;
|
|
389
|
+
private sendNotification;
|
|
390
|
+
}
|
|
391
|
+
|
|
351
392
|
declare class Category extends FreshEntity {
|
|
352
393
|
}
|
|
353
394
|
|
|
@@ -641,4 +682,4 @@ interface HealthCheckResult {
|
|
|
641
682
|
};
|
|
642
683
|
}
|
|
643
684
|
|
|
644
|
-
export { AMOUNT_UNIT, ActionCommandCode, ApiError, type CardNumber, Category, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, FreshDao, FreshEntity, FreshHyperEntity, FreshJob, FreshTranslationBase, type HealthCheckResult, HttpStatus, LanguageCode, Manufacturer, type Maybe, PaymentMethod, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, Product, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TimestampColumn, TransactionType, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, hasOwn, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron
|
|
685
|
+
export { AMOUNT_UNIT, ActionCommandCode, ApiError, BaseEntityChangeSubscriber, type CardNumber, Category, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, type EntityChangeEvent, FreshDao, FreshEntity, FreshHyperEntity, FreshJob, FreshTranslationBase, type HealthCheckResult, HttpStatus, LanguageCode, Manufacturer, type Maybe, PaymentMethod, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, Product, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TimestampColumn, TransactionType, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, hasOwn, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import dayjs, { Dayjs } from 'dayjs';
|
|
2
|
-
import {
|
|
3
|
-
import { BaseEntity, ColumnOptions, Repository, EntityTarget, EntityManager, DataSourceOptions } from 'typeorm';
|
|
2
|
+
import { BaseEntity, ColumnOptions, Repository, EntityTarget, EntityManager, ObjectLiteral, EntitySubscriberInterface, InsertEvent, UpdateEvent, SoftRemoveEvent, TransactionCommitEvent, DataSourceOptions } from 'typeorm';
|
|
4
3
|
import { Job } from 'node-schedule';
|
|
5
4
|
import * as _eslint_core from '@eslint/core';
|
|
6
5
|
import * as typescript_eslint_dist_compatibility_types from 'typescript-eslint/dist/compatibility-types';
|
|
@@ -54,8 +53,6 @@ declare class SinglePromiseWaiter<T = any> {
|
|
|
54
53
|
get hasPromise(): boolean;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
declare const logger: Logger;
|
|
58
|
-
|
|
59
56
|
declare function isValidCron(expr: string): boolean;
|
|
60
57
|
|
|
61
58
|
/**
|
|
@@ -348,6 +345,50 @@ declare abstract class FreshDao<T extends BaseEntity> {
|
|
|
348
345
|
protected getRepo(manager?: EntityManager, entity?: EntityTarget<T>): Repository<T>;
|
|
349
346
|
}
|
|
350
347
|
|
|
348
|
+
/**
|
|
349
|
+
* Change event types for entity lifecycle tracking.
|
|
350
|
+
*/
|
|
351
|
+
type EntityChangeEvent = "created" | "updated" | "deleted";
|
|
352
|
+
/**
|
|
353
|
+
* Abstract base class for TypeORM EntitySubscribers that need to:
|
|
354
|
+
* 1. Track entity changes (insert/update/soft-remove)
|
|
355
|
+
* 2. Batch pending notifications within a transaction
|
|
356
|
+
* 3. Send notifications only after transaction commit
|
|
357
|
+
*
|
|
358
|
+
* Subclasses must implement:
|
|
359
|
+
* - `listenTo()` — target entity class
|
|
360
|
+
* - `pendingKey` — unique key for storing pending events in `queryRunner.data`
|
|
361
|
+
* - `subscriberName` — name used in log messages
|
|
362
|
+
* - `handleNotification(id, changeEvent, manager)` — actual notification logic
|
|
363
|
+
*/
|
|
364
|
+
declare abstract class BaseEntityChangeSubscriber<Entity extends ObjectLiteral, IdType = number> implements EntitySubscriberInterface<Entity> {
|
|
365
|
+
/**
|
|
366
|
+
* Unique key used to store pending change events in `queryRunner.data`.
|
|
367
|
+
* Must be unique per subscriber to avoid collisions when multiple subscribers
|
|
368
|
+
* share the same queryRunner.
|
|
369
|
+
*/
|
|
370
|
+
protected abstract readonly PENDING_KEY: string;
|
|
371
|
+
/**
|
|
372
|
+
* Human-readable name for log/error messages.
|
|
373
|
+
*/
|
|
374
|
+
protected abstract readonly SUBSCRIBER_NAME: string;
|
|
375
|
+
/**
|
|
376
|
+
* Return the entity class this subscriber listens to.
|
|
377
|
+
*/
|
|
378
|
+
abstract listenTo(): Function;
|
|
379
|
+
/**
|
|
380
|
+
* Implement the actual notification/side-effect logic.
|
|
381
|
+
* Called after transaction commit (or immediately if no transaction is active).
|
|
382
|
+
*/
|
|
383
|
+
protected abstract handleNotification(id: IdType, changeEvent: EntityChangeEvent, manager: EntityManager): Promise<void>;
|
|
384
|
+
afterInsert(event: InsertEvent<Entity>): void;
|
|
385
|
+
afterUpdate(event: UpdateEvent<Entity>): void;
|
|
386
|
+
afterSoftRemove(event: SoftRemoveEvent<Entity>): void;
|
|
387
|
+
afterTransactionCommit(event: TransactionCommitEvent): Promise<void>;
|
|
388
|
+
private addPending;
|
|
389
|
+
private sendNotification;
|
|
390
|
+
}
|
|
391
|
+
|
|
351
392
|
declare class Category extends FreshEntity {
|
|
352
393
|
}
|
|
353
394
|
|
|
@@ -641,4 +682,4 @@ interface HealthCheckResult {
|
|
|
641
682
|
};
|
|
642
683
|
}
|
|
643
684
|
|
|
644
|
-
export { AMOUNT_UNIT, ActionCommandCode, ApiError, type CardNumber, Category, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, FreshDao, FreshEntity, FreshHyperEntity, FreshJob, FreshTranslationBase, type HealthCheckResult, HttpStatus, LanguageCode, Manufacturer, type Maybe, PaymentMethod, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, Product, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TimestampColumn, TransactionType, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, hasOwn, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron
|
|
685
|
+
export { AMOUNT_UNIT, ActionCommandCode, ApiError, BaseEntityChangeSubscriber, type CardNumber, Category, DataHelper, DateUtils, type Deferred, DepotPoolStatus, Device, type EntityChangeEvent, FreshDao, FreshEntity, FreshHyperEntity, FreshJob, FreshTranslationBase, type HealthCheckResult, HttpStatus, LanguageCode, Manufacturer, type Maybe, PaymentMethod, PG_DATA_SOURCE_OPTIONS as PgDataSourceOptions, Product, SinglePromiseWaiter, Singleton, type Status, StatusDto, Subcategory, TimestampColumn, TransactionType, createDeferred, FRESH_ESLINT_CONFIG as freshEslintConfig, hasOwn, isEnumValue, isFlag01, isMaybe, isNumber, isNumberInRange, isObject, isString, isValidCron };
|
package/dist/index.js
CHANGED
|
@@ -428,6 +428,7 @@ __export(index_exports, {
|
|
|
428
428
|
AMOUNT_UNIT: () => AMOUNT_UNIT,
|
|
429
429
|
ActionCommandCode: () => ActionCommandCode,
|
|
430
430
|
ApiError: () => ApiError,
|
|
431
|
+
BaseEntityChangeSubscriber: () => BaseEntityChangeSubscriber,
|
|
431
432
|
Category: () => Category,
|
|
432
433
|
DataHelper: () => DataHelper,
|
|
433
434
|
DateUtils: () => DateUtils,
|
|
@@ -460,8 +461,7 @@ __export(index_exports, {
|
|
|
460
461
|
isNumberInRange: () => isNumberInRange,
|
|
461
462
|
isObject: () => isObject,
|
|
462
463
|
isString: () => isString,
|
|
463
|
-
isValidCron: () => isValidCron
|
|
464
|
-
logger: () => logger
|
|
464
|
+
isValidCron: () => isValidCron
|
|
465
465
|
});
|
|
466
466
|
module.exports = __toCommonJS(index_exports);
|
|
467
467
|
|
|
@@ -691,56 +691,6 @@ __name(_SinglePromiseWaiter, "SinglePromiseWaiter");
|
|
|
691
691
|
__publicField(_SinglePromiseWaiter, "_instance");
|
|
692
692
|
var SinglePromiseWaiter = _SinglePromiseWaiter;
|
|
693
693
|
|
|
694
|
-
// src/common/winston.ts
|
|
695
|
-
var import_winston = __toESM(require("winston"));
|
|
696
|
-
var SERVICE = process.env.SERVICE_NAME || "depot-ordering-service";
|
|
697
|
-
var ENV = process.env.NODE_ENV || "localhost";
|
|
698
|
-
var levelToSeverity = {
|
|
699
|
-
silly: "debug",
|
|
700
|
-
verbose: "debug",
|
|
701
|
-
debug: "debug",
|
|
702
|
-
http: "info",
|
|
703
|
-
info: "info",
|
|
704
|
-
warn: "warn",
|
|
705
|
-
error: "error"
|
|
706
|
-
};
|
|
707
|
-
var baseFormat = import_winston.default.format.combine(import_winston.default.format.timestamp({
|
|
708
|
-
format: /* @__PURE__ */ __name(() => (/* @__PURE__ */ new Date()).toISOString(), "format")
|
|
709
|
-
}), import_winston.default.format.errors({
|
|
710
|
-
stack: true
|
|
711
|
-
}), import_winston.default.format.printf((info) => {
|
|
712
|
-
const payload = {
|
|
713
|
-
ts: info.timestamp,
|
|
714
|
-
level: info.level,
|
|
715
|
-
severity: levelToSeverity[info.level] || info.level,
|
|
716
|
-
message: info.message,
|
|
717
|
-
service: SERVICE,
|
|
718
|
-
env: ENV,
|
|
719
|
-
process_name: process.title || process.argv[1] || "node",
|
|
720
|
-
pid: process.pid,
|
|
721
|
-
device: process.env.DEVICE_ID || void 0,
|
|
722
|
-
traceId: info.traceId,
|
|
723
|
-
spanId: info.spanId,
|
|
724
|
-
extra: info.extra || info.meta || void 0,
|
|
725
|
-
stack: info.stack
|
|
726
|
-
};
|
|
727
|
-
return JSON.stringify(payload);
|
|
728
|
-
}));
|
|
729
|
-
var transports = [
|
|
730
|
-
new import_winston.default.transports.Console({
|
|
731
|
-
level: process.env.LOG_LEVEL || "info"
|
|
732
|
-
})
|
|
733
|
-
];
|
|
734
|
-
var logger = import_winston.default.createLogger({
|
|
735
|
-
level: process.env.LOG_LEVEL || "info",
|
|
736
|
-
format: baseFormat,
|
|
737
|
-
transports,
|
|
738
|
-
exitOnError: false
|
|
739
|
-
});
|
|
740
|
-
logger.stream = {
|
|
741
|
-
write: /* @__PURE__ */ __name((message) => logger.info(message.trim()), "write")
|
|
742
|
-
};
|
|
743
|
-
|
|
744
694
|
// src/common/utils/is-cron-valid.ts
|
|
745
695
|
function isValidCron(expr) {
|
|
746
696
|
const parts = expr.trim().split(/\s+/);
|
|
@@ -1207,6 +1157,83 @@ var _FreshDao = class _FreshDao {
|
|
|
1207
1157
|
__name(_FreshDao, "FreshDao");
|
|
1208
1158
|
var FreshDao = _FreshDao;
|
|
1209
1159
|
|
|
1160
|
+
// src/database/subscribers/base-entity-change.subscriber.ts
|
|
1161
|
+
var _BaseEntityChangeSubscriber = class _BaseEntityChangeSubscriber {
|
|
1162
|
+
// ─── TypeORM lifecycle hooks ────────────────────────────────────────
|
|
1163
|
+
afterInsert(event) {
|
|
1164
|
+
var _a;
|
|
1165
|
+
const id = (_a = event.entity) == null ? void 0 : _a.id;
|
|
1166
|
+
if (!id) {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
if (event.queryRunner.isTransactionActive) {
|
|
1170
|
+
this.addPending(event, id, "created");
|
|
1171
|
+
} else {
|
|
1172
|
+
console.warn(`${this.SUBSCRIBER_NAME} - Notification sent outside transaction for id=${id}`);
|
|
1173
|
+
this.sendNotification(id, "created", event.queryRunner.manager);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
afterUpdate(event) {
|
|
1177
|
+
var _a, _b, _c;
|
|
1178
|
+
const id = (_c = (_a = event.entity) == null ? void 0 : _a.id) != null ? _c : (_b = event.databaseEntity) == null ? void 0 : _b.id;
|
|
1179
|
+
if (!id) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
if (event.queryRunner.isTransactionActive) {
|
|
1183
|
+
this.addPending(event, id, "updated");
|
|
1184
|
+
} else {
|
|
1185
|
+
console.warn(`${this.SUBSCRIBER_NAME} - Notification sent outside transaction for id=${id}`);
|
|
1186
|
+
this.sendNotification(id, "updated", event.queryRunner.manager);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
afterSoftRemove(event) {
|
|
1190
|
+
var _a, _b, _c;
|
|
1191
|
+
const id = (_c = (_a = event.entity) == null ? void 0 : _a.id) != null ? _c : (_b = event.databaseEntity) == null ? void 0 : _b.id;
|
|
1192
|
+
if (!id) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
if (event.queryRunner.isTransactionActive) {
|
|
1196
|
+
this.addPending(event, id, "deleted");
|
|
1197
|
+
} else {
|
|
1198
|
+
console.warn(`${this.SUBSCRIBER_NAME} - Notification sent outside transaction for id=${id}`);
|
|
1199
|
+
this.sendNotification(id, "deleted", event.queryRunner.manager);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
async afterTransactionCommit(event) {
|
|
1203
|
+
var _a;
|
|
1204
|
+
const pending = (_a = event.queryRunner.data) == null ? void 0 : _a[this.PENDING_KEY];
|
|
1205
|
+
if (!pending || pending.size === 0) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
event.queryRunner.data[this.PENDING_KEY] = /* @__PURE__ */ new Map();
|
|
1209
|
+
for (const [id, changeEvent] of pending) {
|
|
1210
|
+
await this.sendNotification(id, changeEvent, event.connection.manager);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
// ─── Private helpers ───────────────────────────────────────────────
|
|
1214
|
+
addPending(event, id, changeEvent) {
|
|
1215
|
+
if (!event.queryRunner.data) {
|
|
1216
|
+
event.queryRunner.data = {};
|
|
1217
|
+
}
|
|
1218
|
+
if (!event.queryRunner.data[this.PENDING_KEY]) {
|
|
1219
|
+
event.queryRunner.data[this.PENDING_KEY] = /* @__PURE__ */ new Map();
|
|
1220
|
+
}
|
|
1221
|
+
const existing = event.queryRunner.data[this.PENDING_KEY].get(id);
|
|
1222
|
+
if (!existing || changeEvent === "created" || changeEvent === "deleted") {
|
|
1223
|
+
event.queryRunner.data[this.PENDING_KEY].set(id, changeEvent);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
async sendNotification(id, changeEvent, manager) {
|
|
1227
|
+
try {
|
|
1228
|
+
await this.handleNotification(id, changeEvent, manager);
|
|
1229
|
+
} catch (error) {
|
|
1230
|
+
console.error(`${this.SUBSCRIBER_NAME} - Failed to send notification: ${error instanceof Error ? error.message : error}`);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
__name(_BaseEntityChangeSubscriber, "BaseEntityChangeSubscriber");
|
|
1235
|
+
var BaseEntityChangeSubscriber = _BaseEntityChangeSubscriber;
|
|
1236
|
+
|
|
1210
1237
|
// src/common/schema/entities/category.entity.ts
|
|
1211
1238
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
1212
1239
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -1707,6 +1734,7 @@ var datasource_default = PG_DATA_SOURCE_OPTIONS;
|
|
|
1707
1734
|
AMOUNT_UNIT,
|
|
1708
1735
|
ActionCommandCode,
|
|
1709
1736
|
ApiError,
|
|
1737
|
+
BaseEntityChangeSubscriber,
|
|
1710
1738
|
Category,
|
|
1711
1739
|
DataHelper,
|
|
1712
1740
|
DateUtils,
|
|
@@ -1739,7 +1767,6 @@ var datasource_default = PG_DATA_SOURCE_OPTIONS;
|
|
|
1739
1767
|
isNumberInRange,
|
|
1740
1768
|
isObject,
|
|
1741
1769
|
isString,
|
|
1742
|
-
isValidCron
|
|
1743
|
-
logger
|
|
1770
|
+
isValidCron
|
|
1744
1771
|
});
|
|
1745
1772
|
//# sourceMappingURL=index.js.map
|