@plyaz/core 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/files/BackendFilesDomainService.d.ts +10 -13
- package/dist/domain/files/BackendFilesDomainService.d.ts.map +1 -1
- package/dist/entry-backend.js +343 -189
- package/dist/entry-backend.js.map +1 -1
- package/dist/entry-backend.mjs +240 -86
- package/dist/entry-backend.mjs.map +1 -1
- package/dist/entry-frontend-browser.js +67 -17
- package/dist/entry-frontend-browser.js.map +1 -1
- package/dist/entry-frontend-browser.mjs +67 -17
- package/dist/entry-frontend-browser.mjs.map +1 -1
- package/dist/entry-frontend.js +67 -17
- package/dist/entry-frontend.js.map +1 -1
- package/dist/entry-frontend.mjs +67 -17
- package/dist/entry-frontend.mjs.map +1 -1
- package/dist/index.js +1276 -1114
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1228 -1066
- package/dist/index.mjs.map +1 -1
- package/dist/init/CoreInitializer.d.ts +16 -0
- package/dist/init/CoreInitializer.d.ts.map +1 -1
- package/dist/init/nestjs/index.js +100 -12
- package/dist/init/nestjs/index.js.map +1 -1
- package/dist/init/nestjs/index.mjs +100 -12
- package/dist/init/nestjs/index.mjs.map +1 -1
- package/dist/services/DbService.d.ts +12 -0
- package/dist/services/DbService.d.ts.map +1 -1
- package/dist/services/NotificationService.d.ts +8 -0
- package/dist/services/NotificationService.d.ts.map +1 -1
- package/dist/services/StorageService.d.ts +8 -0
- package/dist/services/StorageService.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4708,18 +4708,18 @@ var require_logger_service = __commonJS({
|
|
|
4708
4708
|
static getTimestamp() {
|
|
4709
4709
|
return dateTimeFormatter.format(Date.now());
|
|
4710
4710
|
}
|
|
4711
|
-
static overrideLogger(
|
|
4712
|
-
if (Array.isArray(
|
|
4713
|
-
Logger_1.logLevels =
|
|
4714
|
-
return this.staticInstanceRef?.setLogLevels?.(
|
|
4711
|
+
static overrideLogger(logger9) {
|
|
4712
|
+
if (Array.isArray(logger9)) {
|
|
4713
|
+
Logger_1.logLevels = logger9;
|
|
4714
|
+
return this.staticInstanceRef?.setLogLevels?.(logger9);
|
|
4715
4715
|
}
|
|
4716
|
-
if ((0, shared_utils_1.isObject)(
|
|
4717
|
-
if (
|
|
4716
|
+
if ((0, shared_utils_1.isObject)(logger9)) {
|
|
4717
|
+
if (logger9 instanceof Logger_1 && logger9.constructor !== Logger_1) {
|
|
4718
4718
|
const errorMessage = `Using the "extends Logger" instruction is not allowed in Nest v9. Please, use "extends ConsoleLogger" instead.`;
|
|
4719
4719
|
this.staticInstanceRef?.error(errorMessage);
|
|
4720
4720
|
throw new Error(errorMessage);
|
|
4721
4721
|
}
|
|
4722
|
-
this.staticInstanceRef =
|
|
4722
|
+
this.staticInstanceRef = logger9;
|
|
4723
4723
|
} else {
|
|
4724
4724
|
this.staticInstanceRef = void 0;
|
|
4725
4725
|
}
|
|
@@ -5760,7 +5760,7 @@ var require_file_type_validator = __commonJS({
|
|
|
5760
5760
|
var logger_service_1 = require_logger_service();
|
|
5761
5761
|
var file_validator_interface_1 = require_file_validator_interface();
|
|
5762
5762
|
var load_esm_1 = require_load_esm();
|
|
5763
|
-
var
|
|
5763
|
+
var logger9 = new logger_service_1.Logger("FileTypeValidator");
|
|
5764
5764
|
var FileTypeValidator = class extends file_validator_interface_1.FileValidator {
|
|
5765
5765
|
static {
|
|
5766
5766
|
__name(this, "FileTypeValidator");
|
|
@@ -5814,7 +5814,7 @@ var require_file_type_validator = __commonJS({
|
|
|
5814
5814
|
} catch (error) {
|
|
5815
5815
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5816
5816
|
if (errorMessage.includes("ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING") || errorMessage.includes("Cannot find module") || errorMessage.includes("ERR_MODULE_NOT_FOUND")) {
|
|
5817
|
-
|
|
5817
|
+
logger9.warn(`Failed to load the "file-type" package for magic number validation. If you are using Jest, run it with NODE_OPTIONS="--experimental-vm-modules". Error: ${errorMessage}`);
|
|
5818
5818
|
}
|
|
5819
5819
|
if (this.validationOptions.fallbackToMimetype) {
|
|
5820
5820
|
return !!file.mimetype.match(this.validationOptions.fileType);
|
|
@@ -6461,12 +6461,12 @@ var require_load_package_util = __commonJS({
|
|
|
6461
6461
|
exports$1.loadPackage = loadPackage;
|
|
6462
6462
|
var logger_service_1 = require_logger_service();
|
|
6463
6463
|
var MISSING_REQUIRED_DEPENDENCY = /* @__PURE__ */ __name((name, reason) => `The "${name}" package is missing. Please, make sure to install it to take advantage of ${reason}.`, "MISSING_REQUIRED_DEPENDENCY");
|
|
6464
|
-
var
|
|
6464
|
+
var logger9 = new logger_service_1.Logger("PackageLoader");
|
|
6465
6465
|
function loadPackage(packageName, context, loaderFn) {
|
|
6466
6466
|
try {
|
|
6467
6467
|
return loaderFn ? loaderFn() : __require(packageName);
|
|
6468
6468
|
} catch (e) {
|
|
6469
|
-
|
|
6469
|
+
logger9.error(MISSING_REQUIRED_DEPENDENCY(packageName, context));
|
|
6470
6470
|
logger_service_1.Logger.flush();
|
|
6471
6471
|
process.exit(1);
|
|
6472
6472
|
}
|
|
@@ -33950,7 +33950,7 @@ var LoggerAdapter = class extends BaseAdapter {
|
|
|
33950
33950
|
let status = "unset";
|
|
33951
33951
|
let statusMessage;
|
|
33952
33952
|
const logSpans = this.logSpans;
|
|
33953
|
-
const
|
|
33953
|
+
const logger9 = this.observabilityLogger;
|
|
33954
33954
|
return {
|
|
33955
33955
|
context,
|
|
33956
33956
|
setAttribute: /* @__PURE__ */ __name((key, value) => {
|
|
@@ -33962,7 +33962,7 @@ var LoggerAdapter = class extends BaseAdapter {
|
|
|
33962
33962
|
addEvent: /* @__PURE__ */ __name((event) => {
|
|
33963
33963
|
events.push(event);
|
|
33964
33964
|
if (logSpans) {
|
|
33965
|
-
|
|
33965
|
+
logger9.debug(`[SPAN EVENT] ${options.name}: ${event.name}`, {
|
|
33966
33966
|
traceId: context.traceId,
|
|
33967
33967
|
spanId: context.spanId,
|
|
33968
33968
|
eventAttributes: event.attributes
|
|
@@ -33977,7 +33977,7 @@ var LoggerAdapter = class extends BaseAdapter {
|
|
|
33977
33977
|
const duration = (endTime ?? Date.now()) - startTime;
|
|
33978
33978
|
if (logSpans) {
|
|
33979
33979
|
const logMethod = status === "error" ? "warn" : "debug";
|
|
33980
|
-
|
|
33980
|
+
logger9[logMethod](`[SPAN END] ${options.name}`, {
|
|
33981
33981
|
traceId: context.traceId,
|
|
33982
33982
|
spanId: context.spanId,
|
|
33983
33983
|
durationMs: duration,
|
|
@@ -33990,7 +33990,7 @@ var LoggerAdapter = class extends BaseAdapter {
|
|
|
33990
33990
|
}, "end"),
|
|
33991
33991
|
recordException: /* @__PURE__ */ __name((error) => {
|
|
33992
33992
|
if (logSpans) {
|
|
33993
|
-
|
|
33993
|
+
logger9.error(`[SPAN ERROR] ${options.name}`, {
|
|
33994
33994
|
traceId: context.traceId,
|
|
33995
33995
|
spanId: context.spanId,
|
|
33996
33996
|
error: error.message,
|
|
@@ -36517,26 +36517,76 @@ var Core = class _Core {
|
|
|
36517
36517
|
errorStore,
|
|
36518
36518
|
_Core.buildErrorHandlerConfig(_Core._errorConfig)
|
|
36519
36519
|
);
|
|
36520
|
+
_Core.setupErrorEventSubscription(verbose);
|
|
36521
|
+
_Core.setupErrorStoreSubscription(verbose);
|
|
36522
|
+
_Core.log("Global error handler initialized with CoreEventManager integration", verbose);
|
|
36523
|
+
if (_Core._errorConfig.httpHandler !== false) {
|
|
36524
|
+
await _Core.createHttpErrorHandler(_Core._errorConfig, verbose);
|
|
36525
|
+
}
|
|
36526
|
+
}
|
|
36527
|
+
/**
|
|
36528
|
+
* Log serialized errors with full details.
|
|
36529
|
+
*/
|
|
36530
|
+
static logErrors(errors, prefix = "ErrorStore") {
|
|
36531
|
+
for (const err of errors) {
|
|
36532
|
+
_Core.logger.error(`[${prefix}] ${err.code}: ${err.message}`, {
|
|
36533
|
+
id: err.id,
|
|
36534
|
+
code: err.code,
|
|
36535
|
+
message: err.message,
|
|
36536
|
+
category: err.category,
|
|
36537
|
+
source: err.source,
|
|
36538
|
+
status: err.status,
|
|
36539
|
+
isRetryable: err.isRetryable,
|
|
36540
|
+
context: err.context,
|
|
36541
|
+
timestamp: err.timestamp
|
|
36542
|
+
});
|
|
36543
|
+
}
|
|
36544
|
+
}
|
|
36545
|
+
/**
|
|
36546
|
+
* Setup SYSTEM.ERROR event subscription for error store updates.
|
|
36547
|
+
* Backend: Also logs errors with full details.
|
|
36548
|
+
* Frontend: Only updates store (logging handled by store subscription).
|
|
36549
|
+
*/
|
|
36550
|
+
static setupErrorEventSubscription(verbose) {
|
|
36551
|
+
const isBackend = types.BACKEND_RUNTIMES.includes(_Core._coreServices.runtime);
|
|
36520
36552
|
const errorEventCleanup = CoreEventManager.on(
|
|
36521
36553
|
core.CORE_EVENTS.SYSTEM.ERROR,
|
|
36522
36554
|
(event) => {
|
|
36523
36555
|
if (!_Core._rootStore) return;
|
|
36524
36556
|
try {
|
|
36525
36557
|
const { errors } = event.data;
|
|
36526
|
-
if (errors
|
|
36527
|
-
|
|
36528
|
-
|
|
36529
|
-
}
|
|
36558
|
+
if (!errors || errors.length === 0) return;
|
|
36559
|
+
_Core._rootStore.getState().errors.addErrors(errors);
|
|
36560
|
+
if (isBackend) _Core.logErrors(errors);
|
|
36561
|
+
_Core.log(`Added ${errors.length} error(s) to store`, verbose);
|
|
36530
36562
|
} catch (e) {
|
|
36531
36563
|
_Core.logger.error("Failed to handle error event", { error: e });
|
|
36532
36564
|
}
|
|
36533
36565
|
}
|
|
36534
36566
|
);
|
|
36535
36567
|
_Core._eventCleanupFns.push(errorEventCleanup);
|
|
36536
|
-
|
|
36537
|
-
|
|
36538
|
-
|
|
36539
|
-
|
|
36568
|
+
}
|
|
36569
|
+
/**
|
|
36570
|
+
* Setup error store subscription for frontend logging.
|
|
36571
|
+
* Logs new errors when they're added to the store.
|
|
36572
|
+
* Only active for non-backend runtimes (browser, nextjs, nuxt, edge).
|
|
36573
|
+
*/
|
|
36574
|
+
static setupErrorStoreSubscription(verbose) {
|
|
36575
|
+
const isFrontend = !types.BACKEND_RUNTIMES.includes(_Core._coreServices.runtime);
|
|
36576
|
+
if (!isFrontend || !_Core._rootStore) return;
|
|
36577
|
+
let prevErrorCount = 0;
|
|
36578
|
+
const storeUnsubscribe = _Core._rootStore.subscribe((state) => {
|
|
36579
|
+
const currentCount = state.errors.errorCount;
|
|
36580
|
+
if (currentCount <= prevErrorCount) {
|
|
36581
|
+
prevErrorCount = currentCount;
|
|
36582
|
+
return;
|
|
36583
|
+
}
|
|
36584
|
+
const newErrors = state.errors.errors.slice(0, currentCount - prevErrorCount);
|
|
36585
|
+
_Core.logErrors(newErrors, "ErrorStore:FE");
|
|
36586
|
+
prevErrorCount = currentCount;
|
|
36587
|
+
});
|
|
36588
|
+
_Core._eventCleanupFns.push(storeUnsubscribe);
|
|
36589
|
+
_Core.log("Error store subscription initialized for frontend", verbose);
|
|
36540
36590
|
}
|
|
36541
36591
|
/**
|
|
36542
36592
|
* Create HTTP error handler based on detected runtime.
|
|
@@ -38490,7 +38540,7 @@ var BaseFrontendDomainService = class _BaseFrontendDomainService extends BaseDom
|
|
|
38490
38540
|
}
|
|
38491
38541
|
};
|
|
38492
38542
|
var logger2 = new logger$1.PackageLogger({ packageName: "core", service: "EventPersistence" });
|
|
38493
|
-
|
|
38543
|
+
(class {
|
|
38494
38544
|
static {
|
|
38495
38545
|
__name(this, "BackendEventPersistenceHandler");
|
|
38496
38546
|
}
|
|
@@ -38664,7 +38714,7 @@ var BackendEventPersistenceHandler = class {
|
|
|
38664
38714
|
static getRegisteredDomains() {
|
|
38665
38715
|
return Array.from(this.registeredDomains.keys());
|
|
38666
38716
|
}
|
|
38667
|
-
};
|
|
38717
|
+
});
|
|
38668
38718
|
var logger3 = new logger$1.PackageLogger({ packageName: "core", service: "FrontendEventPersistence" });
|
|
38669
38719
|
var FrontendEventPersistenceHandler = class {
|
|
38670
38720
|
static {
|
|
@@ -43341,6 +43391,7 @@ var ApiFeatureFlagProvider = class extends FeatureFlagProvider {
|
|
|
43341
43391
|
return this.engine.getRules();
|
|
43342
43392
|
}
|
|
43343
43393
|
};
|
|
43394
|
+
var logger4 = new logger$1.PackageLogger({ packageName: "core", service: "DbService" });
|
|
43344
43395
|
var DEFAULT_ENCRYPTION_FIELDS = {
|
|
43345
43396
|
// User PII
|
|
43346
43397
|
users: ["password_hash", "phone_number", "date_of_birth"],
|
|
@@ -43434,6 +43485,41 @@ var DbService = class _DbService {
|
|
|
43434
43485
|
};
|
|
43435
43486
|
CoreEventManager.emit(core.CORE_EVENTS.DATABASE.ERROR, payload);
|
|
43436
43487
|
}
|
|
43488
|
+
/**
|
|
43489
|
+
* Creates merged event handlers that wrap user-provided handlers.
|
|
43490
|
+
* Adds Core-level logging and forwards to user handlers.
|
|
43491
|
+
*
|
|
43492
|
+
* Note: Unlike StorageService/NotificationService, DB events don't emit
|
|
43493
|
+
* to CoreEventManager by default (too verbose). User handlers can emit
|
|
43494
|
+
* if needed.
|
|
43495
|
+
*
|
|
43496
|
+
* @param userHandlers - User-provided event handlers from config
|
|
43497
|
+
* @returns Merged handlers with Core logging + user handlers
|
|
43498
|
+
*/
|
|
43499
|
+
static createMergedEventHandlers(userHandlers) {
|
|
43500
|
+
return {
|
|
43501
|
+
...userHandlers,
|
|
43502
|
+
onAfterWrite: /* @__PURE__ */ __name(async (event) => {
|
|
43503
|
+
logger4.debug("Database write completed", {
|
|
43504
|
+
operation: event.operation,
|
|
43505
|
+
table: event.table,
|
|
43506
|
+
duration: event.duration
|
|
43507
|
+
});
|
|
43508
|
+
if (userHandlers?.onAfterWrite) {
|
|
43509
|
+
await userHandlers.onAfterWrite(event);
|
|
43510
|
+
}
|
|
43511
|
+
}, "onAfterWrite"),
|
|
43512
|
+
onAfterRead: /* @__PURE__ */ __name(async (event) => {
|
|
43513
|
+
logger4.debug("Database read completed", {
|
|
43514
|
+
table: event.table,
|
|
43515
|
+
duration: event.duration
|
|
43516
|
+
});
|
|
43517
|
+
if (userHandlers?.onAfterRead) {
|
|
43518
|
+
await userHandlers.onAfterRead(event);
|
|
43519
|
+
}
|
|
43520
|
+
}, "onAfterRead")
|
|
43521
|
+
};
|
|
43522
|
+
}
|
|
43437
43523
|
/**
|
|
43438
43524
|
* Gets the singleton instance of DbService
|
|
43439
43525
|
*
|
|
@@ -43638,6 +43724,8 @@ var DbService = class _DbService {
|
|
|
43638
43724
|
if (cache) dbConfig.cache = cache;
|
|
43639
43725
|
if (audit) dbConfig.audit = audit;
|
|
43640
43726
|
if (encryption) dbConfig.encryption = encryption;
|
|
43727
|
+
const events = _DbService.createMergedEventHandlers(config.events);
|
|
43728
|
+
if (events) dbConfig.events = events;
|
|
43641
43729
|
return dbConfig;
|
|
43642
43730
|
}
|
|
43643
43731
|
/**
|
|
@@ -46203,7 +46291,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46203
46291
|
// Constructor
|
|
46204
46292
|
// ─────────────────────────────────────────────────────────────────────────
|
|
46205
46293
|
constructor(config = {}, options) {
|
|
46206
|
-
const apiBasePath = config.apiBasePath || "
|
|
46294
|
+
const apiBasePath = config.apiBasePath || "";
|
|
46207
46295
|
super({
|
|
46208
46296
|
serviceName: "ExampleFrontendService",
|
|
46209
46297
|
supportedRuntimes: ["frontend"],
|
|
@@ -46228,20 +46316,20 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46228
46316
|
// Note: Use relative paths since apiClient.baseURL is already set to apiBasePath
|
|
46229
46317
|
fetchers: {
|
|
46230
46318
|
fetchAll: /* @__PURE__ */ __name(async (query) => {
|
|
46231
|
-
return this.apiClient.get("", { params: query });
|
|
46319
|
+
return this.apiClient.get("/examples", { params: query });
|
|
46232
46320
|
}, "fetchAll"),
|
|
46233
46321
|
fetchById: /* @__PURE__ */ __name(async (id) => {
|
|
46234
|
-
return this.apiClient.get(
|
|
46322
|
+
return this.apiClient.get(`/examples/${id}`);
|
|
46235
46323
|
}, "fetchById"),
|
|
46236
46324
|
create: /* @__PURE__ */ __name(async (data) => {
|
|
46237
|
-
return this.apiClient.post("", data);
|
|
46325
|
+
return this.apiClient.post("/examples", data);
|
|
46238
46326
|
}, "create"),
|
|
46239
46327
|
update: /* @__PURE__ */ __name(async (payload) => {
|
|
46240
46328
|
const { id, data } = payload;
|
|
46241
|
-
return this.apiClient.patch(
|
|
46329
|
+
return this.apiClient.patch(`/examples/${id}`, data);
|
|
46242
46330
|
}, "update"),
|
|
46243
46331
|
delete: /* @__PURE__ */ __name(async (id) => {
|
|
46244
|
-
return this.apiClient.delete(
|
|
46332
|
+
return this.apiClient.delete(`/examples/${id}`);
|
|
46245
46333
|
}, "delete")
|
|
46246
46334
|
}
|
|
46247
46335
|
// Store handlers - customize how data syncs to store
|
|
@@ -46309,7 +46397,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46309
46397
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
46310
46398
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
46311
46399
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
46312
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
46400
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
46313
46401
|
};
|
|
46314
46402
|
const service = new _FrontendExampleDomainService(mergedConfig, options);
|
|
46315
46403
|
if (mergedConfig.autoFetch) {
|
|
@@ -46690,337 +46778,710 @@ var CacheService = class _CacheService {
|
|
|
46690
46778
|
}
|
|
46691
46779
|
};
|
|
46692
46780
|
var getCacheService = /* @__PURE__ */ __name(() => CacheService.getInstance(), "getCacheService");
|
|
46693
|
-
var
|
|
46694
|
-
|
|
46695
|
-
|
|
46696
|
-
this.config = null;
|
|
46697
|
-
this.initialized = false;
|
|
46698
|
-
}
|
|
46781
|
+
var TABLE_NAME = "media";
|
|
46782
|
+
var DEFAULT_LIMIT2 = 100;
|
|
46783
|
+
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
46699
46784
|
static {
|
|
46700
|
-
__name(this, "
|
|
46785
|
+
__name(this, "FilesRepository");
|
|
46701
46786
|
}
|
|
46702
|
-
|
|
46703
|
-
|
|
46787
|
+
constructor(db) {
|
|
46788
|
+
super(db, TABLE_NAME);
|
|
46704
46789
|
}
|
|
46705
|
-
//
|
|
46706
|
-
//
|
|
46707
|
-
//
|
|
46790
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46791
|
+
// Static Factory
|
|
46792
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46708
46793
|
/**
|
|
46709
|
-
*
|
|
46710
|
-
*
|
|
46794
|
+
* Create repository instance.
|
|
46795
|
+
* Uses DbService if initialized.
|
|
46711
46796
|
*/
|
|
46712
|
-
|
|
46713
|
-
|
|
46714
|
-
|
|
46715
|
-
|
|
46716
|
-
|
|
46717
|
-
|
|
46718
|
-
|
|
46797
|
+
static create() {
|
|
46798
|
+
if (!DbService.isInitialized()) {
|
|
46799
|
+
throw new errors.DatabasePackageError(
|
|
46800
|
+
"DbService not initialized. Call DbService.initialize() first.",
|
|
46801
|
+
errors$1.DATABASE_ERROR_CODES.CONNECTION_FAILED
|
|
46802
|
+
);
|
|
46803
|
+
}
|
|
46804
|
+
const db = DbService.getInstance().getDatabase();
|
|
46805
|
+
return new _FilesRepository(db);
|
|
46806
|
+
}
|
|
46807
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46808
|
+
// Overridden Methods (with domain-specific logic)
|
|
46809
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46810
|
+
/**
|
|
46811
|
+
* Find multiple entities with default sorting
|
|
46812
|
+
*/
|
|
46813
|
+
// eslint-disable-next-line complexity
|
|
46814
|
+
async findMany(options, config) {
|
|
46815
|
+
const mergedOptions = {
|
|
46816
|
+
sort: options?.sort ?? [{ field: "created_at", direction: "desc" }],
|
|
46817
|
+
pagination: {
|
|
46818
|
+
limit: options?.pagination?.limit ?? DEFAULT_LIMIT2,
|
|
46819
|
+
offset: options?.pagination?.offset ?? 0
|
|
46820
|
+
},
|
|
46821
|
+
filter: options?.filter
|
|
46719
46822
|
};
|
|
46720
|
-
|
|
46823
|
+
return super.findMany(mergedOptions, config);
|
|
46721
46824
|
}
|
|
46722
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46723
|
-
// Singleton Management
|
|
46724
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46725
46825
|
/**
|
|
46726
|
-
*
|
|
46826
|
+
* Create new file record with auto-generated ID and timestamps
|
|
46727
46827
|
*/
|
|
46728
|
-
|
|
46729
|
-
|
|
46730
|
-
|
|
46828
|
+
// eslint-disable-next-line complexity
|
|
46829
|
+
async create(data, config) {
|
|
46830
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
46831
|
+
const id = data.id ?? generateId();
|
|
46832
|
+
const row = {
|
|
46833
|
+
id,
|
|
46834
|
+
user_id: data.user_id ?? "",
|
|
46835
|
+
type: data.type ?? "OTHER",
|
|
46836
|
+
filename: data.filename ?? "",
|
|
46837
|
+
original_filename: data.original_filename ?? data.filename ?? "",
|
|
46838
|
+
mime_type: data.mime_type ?? "application/octet-stream",
|
|
46839
|
+
file_size: data.file_size ?? 0,
|
|
46840
|
+
storage_path: data.storage_path ?? "",
|
|
46841
|
+
cdn_url: data.cdn_url ?? null,
|
|
46842
|
+
width: data.width ?? null,
|
|
46843
|
+
height: data.height ?? null,
|
|
46844
|
+
duration: data.duration ?? null,
|
|
46845
|
+
is_virus_scanned: data.is_virus_scanned ?? false,
|
|
46846
|
+
virus_scan_result: data.virus_scan_result ?? null,
|
|
46847
|
+
metadata: data.metadata ?? null,
|
|
46848
|
+
variants: data.variants ?? null,
|
|
46849
|
+
entity_type: data.entity_type ?? null,
|
|
46850
|
+
entity_id: data.entity_id ?? null,
|
|
46851
|
+
access_level: data.access_level ?? null,
|
|
46852
|
+
created_at: now,
|
|
46853
|
+
updated_at: now,
|
|
46854
|
+
deleted_at: null
|
|
46855
|
+
};
|
|
46856
|
+
return super.create(row, config);
|
|
46731
46857
|
}
|
|
46732
46858
|
/**
|
|
46733
|
-
*
|
|
46859
|
+
* Get the table name for this repository
|
|
46734
46860
|
*/
|
|
46735
|
-
|
|
46736
|
-
return
|
|
46861
|
+
getTableName() {
|
|
46862
|
+
return TABLE_NAME;
|
|
46737
46863
|
}
|
|
46864
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46865
|
+
// Domain-Specific Methods
|
|
46866
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46738
46867
|
/**
|
|
46739
|
-
*
|
|
46868
|
+
* Find all files for a user
|
|
46740
46869
|
*/
|
|
46741
|
-
|
|
46742
|
-
|
|
46743
|
-
|
|
46744
|
-
|
|
46745
|
-
|
|
46746
|
-
|
|
46747
|
-
|
|
46870
|
+
async findByUserId(userId, options) {
|
|
46871
|
+
return this.findMany({
|
|
46872
|
+
filter: { field: "user_id", operator: "eq", value: userId },
|
|
46873
|
+
pagination: {
|
|
46874
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46875
|
+
offset: options?.offset ?? 0
|
|
46876
|
+
}
|
|
46877
|
+
});
|
|
46748
46878
|
}
|
|
46749
46879
|
/**
|
|
46750
|
-
*
|
|
46751
|
-
*
|
|
46752
|
-
* @param config - Storage service configuration
|
|
46753
|
-
* @returns The initialized StorageService instance
|
|
46880
|
+
* Find files for a specific entity (polymorphic association)
|
|
46754
46881
|
*/
|
|
46755
|
-
|
|
46756
|
-
|
|
46757
|
-
|
|
46758
|
-
|
|
46759
|
-
|
|
46760
|
-
instance.config = config;
|
|
46761
|
-
instance.storageService = new storage$1.StorageService(config);
|
|
46762
|
-
instance.initialized = true;
|
|
46763
|
-
return instance;
|
|
46882
|
+
async findByEntityId(entityType, entityId, options) {
|
|
46883
|
+
return this.query().where("entity_type", "eq", entityType).andWhere("entity_id", "eq", entityId).whereNull("deleted_at").orderByDesc("created_at").paginate(
|
|
46884
|
+
Math.floor((options?.offset ?? 0) / (options?.limit ?? DEFAULT_LIMIT2)) + 1,
|
|
46885
|
+
options?.limit ?? DEFAULT_LIMIT2
|
|
46886
|
+
).execute();
|
|
46764
46887
|
}
|
|
46765
46888
|
/**
|
|
46766
|
-
*
|
|
46767
|
-
* Use this only if you need direct access to the underlying service.
|
|
46768
|
-
*
|
|
46769
|
-
* @returns The raw StorageService instance from @plyaz/storage
|
|
46770
|
-
* @throws {StoragePackageError} When storage is not initialized
|
|
46889
|
+
* Find file by storage path (for deduplication checks)
|
|
46771
46890
|
*/
|
|
46772
|
-
|
|
46773
|
-
|
|
46774
|
-
throw new errors.StoragePackageError(
|
|
46775
|
-
"Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
|
|
46776
|
-
errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
|
|
46777
|
-
);
|
|
46778
|
-
}
|
|
46779
|
-
return this.storageService;
|
|
46891
|
+
async findByStoragePath(storagePath) {
|
|
46892
|
+
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
46780
46893
|
}
|
|
46781
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46782
|
-
// Service Access
|
|
46783
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46784
46894
|
/**
|
|
46785
|
-
*
|
|
46786
|
-
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46787
|
-
* Any method added to @plyaz/storage will be automatically available.
|
|
46788
|
-
*
|
|
46789
|
-
* @example
|
|
46790
|
-
* ```typescript
|
|
46791
|
-
* const storage = StorageService.getInstance().getStorage();
|
|
46792
|
-
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
46793
|
-
* await storage.deleteFile({ fileId: '123' });
|
|
46794
|
-
* ```
|
|
46795
|
-
*
|
|
46796
|
-
* @returns StorageServiceImpl with automatic error handling
|
|
46895
|
+
* Count files for a user
|
|
46797
46896
|
*/
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
46804
|
-
|
|
46805
|
-
|
|
46806
|
-
|
|
46807
|
-
|
|
46808
|
-
|
|
46809
|
-
|
|
46810
|
-
return (...args) => {
|
|
46811
|
-
try {
|
|
46812
|
-
const result2 = value.apply(storage, args);
|
|
46813
|
-
if (result2 instanceof Promise) {
|
|
46814
|
-
return result2.catch((error) => {
|
|
46815
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46816
|
-
throw error;
|
|
46817
|
-
});
|
|
46818
|
-
}
|
|
46819
|
-
return result2;
|
|
46820
|
-
} catch (error) {
|
|
46821
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46822
|
-
throw error;
|
|
46823
|
-
}
|
|
46824
|
-
};
|
|
46897
|
+
async countByUserId(userId) {
|
|
46898
|
+
return this.count({ field: "user_id", operator: "eq", value: userId });
|
|
46899
|
+
}
|
|
46900
|
+
/**
|
|
46901
|
+
* Find files by MIME type
|
|
46902
|
+
*/
|
|
46903
|
+
async findByMimeType(mimeType, options) {
|
|
46904
|
+
return this.findMany({
|
|
46905
|
+
filter: { field: "mime_type", operator: "eq", value: mimeType },
|
|
46906
|
+
pagination: {
|
|
46907
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46908
|
+
offset: options?.offset ?? 0
|
|
46825
46909
|
}
|
|
46826
46910
|
});
|
|
46827
46911
|
}
|
|
46828
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46829
|
-
// Health Check (special handling for response transformation)
|
|
46830
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46831
46912
|
/**
|
|
46832
|
-
*
|
|
46833
|
-
* This method has special handling to transform the response format.
|
|
46913
|
+
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
46834
46914
|
*/
|
|
46835
|
-
async
|
|
46836
|
-
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46915
|
+
async findByType(type, options) {
|
|
46916
|
+
return this.findMany({
|
|
46917
|
+
filter: { field: "type", operator: "eq", value: type },
|
|
46918
|
+
pagination: {
|
|
46919
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46920
|
+
offset: options?.offset ?? 0
|
|
46841
46921
|
}
|
|
46842
|
-
|
|
46843
|
-
|
|
46844
|
-
|
|
46845
|
-
|
|
46846
|
-
|
|
46847
|
-
|
|
46848
|
-
|
|
46849
|
-
|
|
46850
|
-
} catch (error) {
|
|
46851
|
-
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
46852
|
-
return {
|
|
46853
|
-
isHealthy: false,
|
|
46854
|
-
responseTime: Date.now() - startTime,
|
|
46855
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
46856
|
-
};
|
|
46857
|
-
}
|
|
46922
|
+
});
|
|
46923
|
+
}
|
|
46924
|
+
};
|
|
46925
|
+
|
|
46926
|
+
// src/domain/files/mappers/FilesMapper.ts
|
|
46927
|
+
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
46928
|
+
static {
|
|
46929
|
+
__name(this, "FilesMapperClass");
|
|
46858
46930
|
}
|
|
46859
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46860
|
-
// Lifecycle
|
|
46861
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46862
46931
|
/**
|
|
46863
|
-
*
|
|
46932
|
+
* Type guard for UploadResult from event payloads
|
|
46933
|
+
* Validates that the value has the required structure for DB mapping
|
|
46864
46934
|
*/
|
|
46865
|
-
|
|
46866
|
-
return
|
|
46935
|
+
static isUploadResult(value) {
|
|
46936
|
+
if (!isObject(value)) return false;
|
|
46937
|
+
const obj = value;
|
|
46938
|
+
if (!isObject(obj.metadata)) return false;
|
|
46939
|
+
const metadata = obj.metadata;
|
|
46940
|
+
return typeof metadata.fileId === "string" && typeof metadata.filename === "string" && typeof metadata.mimeType === "string" && typeof metadata.size === "number" && typeof metadata.path === "string";
|
|
46867
46941
|
}
|
|
46868
46942
|
/**
|
|
46869
|
-
*
|
|
46943
|
+
* Infer file type from MIME type
|
|
46870
46944
|
*/
|
|
46871
|
-
|
|
46872
|
-
if (
|
|
46873
|
-
|
|
46945
|
+
static inferFileType(mimeType) {
|
|
46946
|
+
if (mimeType.startsWith("image/")) return "IMAGE";
|
|
46947
|
+
if (mimeType.startsWith("video/")) return "VIDEO";
|
|
46948
|
+
if (mimeType.startsWith("audio/")) return "AUDIO";
|
|
46949
|
+
if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text/")) {
|
|
46950
|
+
return "DOCUMENT";
|
|
46874
46951
|
}
|
|
46875
|
-
|
|
46876
|
-
this.initialized = false;
|
|
46877
|
-
this.config = null;
|
|
46952
|
+
return "OTHER";
|
|
46878
46953
|
}
|
|
46879
46954
|
/**
|
|
46880
|
-
*
|
|
46881
|
-
*
|
|
46882
|
-
* Use this when you need an isolated storage connection with its own configuration.
|
|
46883
|
-
*
|
|
46884
|
-
* @param config - Storage service configuration
|
|
46885
|
-
* @returns Promise that resolves to a new dedicated StorageService instance
|
|
46955
|
+
* API Response → Domain Entity
|
|
46886
46956
|
*/
|
|
46887
|
-
|
|
46888
|
-
const
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
|
|
46896
|
-
|
|
46897
|
-
|
|
46898
|
-
|
|
46899
|
-
|
|
46900
|
-
|
|
46901
|
-
|
|
46902
|
-
|
|
46903
|
-
|
|
46904
|
-
|
|
46905
|
-
|
|
46957
|
+
toDomain(dto) {
|
|
46958
|
+
const type = _FilesMapperClass.inferFileType(dto.mimeType);
|
|
46959
|
+
return {
|
|
46960
|
+
id: dto.id,
|
|
46961
|
+
key: dto.key,
|
|
46962
|
+
filename: dto.filename,
|
|
46963
|
+
mimeType: dto.mimeType,
|
|
46964
|
+
size: dto.size,
|
|
46965
|
+
checksum: dto.checksum,
|
|
46966
|
+
url: dto.url,
|
|
46967
|
+
publicUrl: dto.publicUrl,
|
|
46968
|
+
signedUrl: dto.signedUrl,
|
|
46969
|
+
bucket: dto.bucket,
|
|
46970
|
+
entityType: dto.entityType,
|
|
46971
|
+
entityId: dto.entityId,
|
|
46972
|
+
category: dto.category,
|
|
46973
|
+
uploadedAt: new Date(dto.uploadedAt),
|
|
46974
|
+
expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : void 0,
|
|
46975
|
+
variants: dto.variants,
|
|
46976
|
+
type,
|
|
46977
|
+
isImage: type === "IMAGE",
|
|
46978
|
+
isVideo: type === "VIDEO",
|
|
46979
|
+
isDocument: type === "DOCUMENT",
|
|
46980
|
+
isAudio: type === "AUDIO"
|
|
46981
|
+
};
|
|
46906
46982
|
}
|
|
46907
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46908
|
-
// Error Handling
|
|
46909
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46910
46983
|
/**
|
|
46911
|
-
*
|
|
46912
|
-
* Called when notification operations fail to integrate with global error handling.
|
|
46984
|
+
* Domain Entity → Store State (serializable)
|
|
46913
46985
|
*/
|
|
46914
|
-
|
|
46915
|
-
|
|
46916
|
-
|
|
46917
|
-
|
|
46918
|
-
|
|
46919
|
-
|
|
46920
|
-
|
|
46986
|
+
toStoreState(entity) {
|
|
46987
|
+
return {
|
|
46988
|
+
id: entity.id,
|
|
46989
|
+
key: entity.key,
|
|
46990
|
+
filename: entity.filename,
|
|
46991
|
+
mimeType: entity.mimeType,
|
|
46992
|
+
size: entity.size,
|
|
46993
|
+
url: entity.url,
|
|
46994
|
+
publicUrl: entity.publicUrl,
|
|
46995
|
+
bucket: entity.bucket,
|
|
46996
|
+
entityType: entity.entityType,
|
|
46997
|
+
entityId: entity.entityId,
|
|
46998
|
+
category: entity.category,
|
|
46999
|
+
uploadedAt: entity.uploadedAt.toISOString(),
|
|
47000
|
+
type: entity.type,
|
|
47001
|
+
isImage: entity.isImage,
|
|
47002
|
+
isVideo: entity.isVideo,
|
|
47003
|
+
isDocument: entity.isDocument,
|
|
47004
|
+
isAudio: entity.isAudio
|
|
46921
47005
|
};
|
|
46922
|
-
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
|
|
46923
47006
|
}
|
|
46924
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46925
|
-
// Singleton Management
|
|
46926
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46927
47007
|
/**
|
|
46928
|
-
*
|
|
47008
|
+
* Store State → Domain Entity
|
|
46929
47009
|
*/
|
|
46930
|
-
|
|
46931
|
-
|
|
46932
|
-
|
|
47010
|
+
fromStoreState(state) {
|
|
47011
|
+
return {
|
|
47012
|
+
id: state.id,
|
|
47013
|
+
key: state.key,
|
|
47014
|
+
filename: state.filename,
|
|
47015
|
+
mimeType: state.mimeType,
|
|
47016
|
+
size: state.size,
|
|
47017
|
+
url: state.url,
|
|
47018
|
+
publicUrl: state.publicUrl,
|
|
47019
|
+
bucket: state.bucket,
|
|
47020
|
+
entityType: state.entityType,
|
|
47021
|
+
entityId: state.entityId,
|
|
47022
|
+
category: state.category,
|
|
47023
|
+
uploadedAt: new Date(state.uploadedAt),
|
|
47024
|
+
type: state.type,
|
|
47025
|
+
isImage: state.isImage,
|
|
47026
|
+
isVideo: state.isVideo,
|
|
47027
|
+
isDocument: state.isDocument,
|
|
47028
|
+
isAudio: state.isAudio
|
|
47029
|
+
};
|
|
46933
47030
|
}
|
|
46934
47031
|
/**
|
|
46935
|
-
*
|
|
47032
|
+
* Database Row → API Response (for backend)
|
|
46936
47033
|
*/
|
|
46937
|
-
|
|
46938
|
-
return
|
|
47034
|
+
toResponseDTO(row) {
|
|
47035
|
+
return {
|
|
47036
|
+
id: row.id,
|
|
47037
|
+
key: row.storage_path,
|
|
47038
|
+
filename: row.filename,
|
|
47039
|
+
mimeType: row.mime_type,
|
|
47040
|
+
size: toNumber(row.file_size),
|
|
47041
|
+
checksum: void 0,
|
|
47042
|
+
url: row.cdn_url ?? void 0,
|
|
47043
|
+
publicUrl: row.cdn_url ?? void 0,
|
|
47044
|
+
signedUrl: void 0,
|
|
47045
|
+
bucket: "media",
|
|
47046
|
+
entityType: row.entity_type ?? void 0,
|
|
47047
|
+
entityId: row.entity_id ?? void 0,
|
|
47048
|
+
category: void 0,
|
|
47049
|
+
uploadedAt: row.created_at,
|
|
47050
|
+
expiresAt: void 0
|
|
47051
|
+
};
|
|
46939
47052
|
}
|
|
46940
47053
|
/**
|
|
46941
|
-
*
|
|
47054
|
+
* Create GeneratedFileItem from generation result
|
|
46942
47055
|
*/
|
|
46943
|
-
|
|
46944
|
-
|
|
46945
|
-
|
|
46946
|
-
|
|
46947
|
-
|
|
46948
|
-
|
|
46949
|
-
|
|
47056
|
+
toGeneratedFileItem(templateId, buffer, size, outputFormat = "pdf") {
|
|
47057
|
+
return {
|
|
47058
|
+
id: crypto.randomUUID(),
|
|
47059
|
+
templateId,
|
|
47060
|
+
buffer,
|
|
47061
|
+
size,
|
|
47062
|
+
mimeType: `application/${outputFormat}`,
|
|
47063
|
+
filename: `${templateId}.${outputFormat}`,
|
|
47064
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47065
|
+
};
|
|
46950
47066
|
}
|
|
46951
47067
|
/**
|
|
46952
|
-
*
|
|
47068
|
+
* Convert upload result to database row format
|
|
47069
|
+
* Used by event handlers to persist upload results to DB
|
|
46953
47070
|
*
|
|
46954
|
-
* @param
|
|
46955
|
-
* @
|
|
47071
|
+
* @param uploadResult - Result from storage upload
|
|
47072
|
+
* @param userId - User ID who uploaded the file (from auth context)
|
|
47073
|
+
* @returns Partial database row ready for repository.create()
|
|
46956
47074
|
*/
|
|
46957
|
-
|
|
46958
|
-
|
|
46959
|
-
|
|
46960
|
-
|
|
46961
|
-
|
|
46962
|
-
|
|
46963
|
-
|
|
46964
|
-
|
|
46965
|
-
|
|
47075
|
+
// eslint-disable-next-line complexity
|
|
47076
|
+
toDbRow(uploadResult, userId) {
|
|
47077
|
+
const { metadata, variants } = uploadResult;
|
|
47078
|
+
return {
|
|
47079
|
+
id: metadata.fileId,
|
|
47080
|
+
user_id: userId ?? "system",
|
|
47081
|
+
type: _FilesMapperClass.inferFileType(metadata.mimeType),
|
|
47082
|
+
filename: metadata.filename,
|
|
47083
|
+
original_filename: metadata.filename,
|
|
47084
|
+
mime_type: metadata.mimeType,
|
|
47085
|
+
file_size: metadata.size,
|
|
47086
|
+
storage_path: metadata.path,
|
|
47087
|
+
cdn_url: metadata.url ?? null,
|
|
47088
|
+
width: metadata.extractedMetadata?.width ?? null,
|
|
47089
|
+
height: metadata.extractedMetadata?.height ?? null,
|
|
47090
|
+
duration: metadata.extractedMetadata?.duration ?? null,
|
|
47091
|
+
entity_type: metadata.entityType,
|
|
47092
|
+
entity_id: metadata.entityId,
|
|
47093
|
+
access_level: metadata.accessLevel,
|
|
47094
|
+
is_virus_scanned: false,
|
|
47095
|
+
virus_scan_result: null,
|
|
47096
|
+
metadata: metadata.customMetadata ?? null,
|
|
47097
|
+
variants: variants ?? null
|
|
47098
|
+
};
|
|
46966
47099
|
}
|
|
46967
|
-
|
|
46968
|
-
|
|
47100
|
+
};
|
|
47101
|
+
var FilesMapper = new FilesMapperClass();
|
|
47102
|
+
|
|
47103
|
+
// src/domain/files/validators/FilesValidator.ts
|
|
47104
|
+
var FilesValidatorClass = class extends BaseValidator {
|
|
47105
|
+
static {
|
|
47106
|
+
__name(this, "FilesValidatorClass");
|
|
47107
|
+
}
|
|
47108
|
+
constructor() {
|
|
47109
|
+
super({});
|
|
47110
|
+
}
|
|
47111
|
+
/**
|
|
47112
|
+
* Check if user has permission to access file
|
|
47113
|
+
*/
|
|
47114
|
+
validateUserAccess(userId, fileOwnerId, accessLevel, isAdmin = false) {
|
|
47115
|
+
if (isAdmin) return true;
|
|
47116
|
+
if (userId === fileOwnerId) return true;
|
|
47117
|
+
if (accessLevel === "public") return true;
|
|
47118
|
+
if (accessLevel === "protected" && userId) return true;
|
|
47119
|
+
return false;
|
|
47120
|
+
}
|
|
47121
|
+
};
|
|
47122
|
+
new FilesValidatorClass();
|
|
47123
|
+
|
|
47124
|
+
// src/domain/files/BackendFilesDomainService.ts
|
|
47125
|
+
var BackendFilesDomainService = class _BackendFilesDomainService extends BaseBackendDomainService {
|
|
47126
|
+
constructor(config = {}, injected) {
|
|
47127
|
+
super({
|
|
47128
|
+
serviceName: "BackendFilesDomainService",
|
|
47129
|
+
supportedRuntimes: ["backend"],
|
|
47130
|
+
serviceConfig: {
|
|
47131
|
+
enabled: true,
|
|
47132
|
+
throwOnValidationError: true,
|
|
47133
|
+
throwOnRepositoryError: true,
|
|
47134
|
+
emitEvents: true,
|
|
47135
|
+
...config
|
|
47136
|
+
},
|
|
47137
|
+
mapperClass: FilesMapperClass,
|
|
47138
|
+
validatorClass: FilesValidatorClass,
|
|
47139
|
+
injected
|
|
47140
|
+
});
|
|
47141
|
+
this.eventPrefix = "files";
|
|
47142
|
+
this.cachePrefix = "files";
|
|
47143
|
+
}
|
|
47144
|
+
static {
|
|
47145
|
+
__name(this, "BackendFilesDomainService");
|
|
47146
|
+
}
|
|
47147
|
+
static {
|
|
47148
|
+
this.serviceKey = "files";
|
|
47149
|
+
}
|
|
47150
|
+
/**
|
|
47151
|
+
* Lazy repository getter - creates repository on first access.
|
|
47152
|
+
* Throws if DbService is not initialized.
|
|
47153
|
+
*/
|
|
47154
|
+
get repository() {
|
|
47155
|
+
this._repository ??= FilesRepository.create();
|
|
47156
|
+
return this._repository;
|
|
47157
|
+
}
|
|
47158
|
+
/**
|
|
47159
|
+
* Create service instance
|
|
47160
|
+
*/
|
|
47161
|
+
// eslint-disable-next-line complexity
|
|
47162
|
+
static async create(config = {}, options) {
|
|
47163
|
+
const injected = {
|
|
47164
|
+
cache: options?.cache?.instance,
|
|
47165
|
+
db: options?.db?.instance,
|
|
47166
|
+
api: options?.apiClient?.instance,
|
|
47167
|
+
storage: options?.storage?.instance,
|
|
47168
|
+
notifications: options?.notifications?.instance
|
|
47169
|
+
};
|
|
47170
|
+
return new _BackendFilesDomainService(config, injected);
|
|
47171
|
+
}
|
|
47172
|
+
isAvailable() {
|
|
47173
|
+
return this.isServiceEnabled;
|
|
47174
|
+
}
|
|
47175
|
+
dispose() {
|
|
47176
|
+
this.logInfo("Service disposed");
|
|
47177
|
+
}
|
|
47178
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47179
|
+
// Storage operations (via @plyaz/storage)
|
|
47180
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47181
|
+
/**
|
|
47182
|
+
* Download file content
|
|
47183
|
+
* GET /files/:id/download
|
|
47184
|
+
*
|
|
47185
|
+
* Follows same pattern as base class CRUD methods:
|
|
47186
|
+
* 1. assertReady
|
|
47187
|
+
* 2. Record start time
|
|
47188
|
+
* 3. Log debug info
|
|
47189
|
+
* 4. Emit starting event
|
|
47190
|
+
* 5. Execute operation
|
|
47191
|
+
* 6. Emit success event
|
|
47192
|
+
* 7. Record metrics
|
|
47193
|
+
*
|
|
47194
|
+
* @param params - Download parameters (fileId required)
|
|
47195
|
+
* @returns Download result with buffer, filename, mimeType
|
|
47196
|
+
*/
|
|
47197
|
+
// eslint-disable-next-line complexity
|
|
47198
|
+
async downloadFile(params) {
|
|
47199
|
+
this.assertReady();
|
|
47200
|
+
const startTime = Date.now();
|
|
47201
|
+
this.logDebug("Downloading file", { fileId: params.fileId });
|
|
47202
|
+
this.emitEvent("download:downloading", { request: params });
|
|
47203
|
+
try {
|
|
47204
|
+
await this.beforeDownloadFile?.(params);
|
|
47205
|
+
if (!this.storageService) {
|
|
47206
|
+
throw new Error(
|
|
47207
|
+
"Storage service not available. Ensure storage is configured in Core.initialize()."
|
|
47208
|
+
);
|
|
47209
|
+
}
|
|
47210
|
+
const storage = this.storageService.getStorage();
|
|
47211
|
+
const result2 = await storage.downloadFile({
|
|
47212
|
+
fileId: params.fileId
|
|
47213
|
+
});
|
|
47214
|
+
const response = {
|
|
47215
|
+
buffer: result2?.file?.toString("base64") ?? "",
|
|
47216
|
+
filename: result2?.metadata?.filename ?? "download",
|
|
47217
|
+
mimeType: result2?.metadata?.mimeType ?? "application/octet-stream"
|
|
47218
|
+
};
|
|
47219
|
+
await this.afterDownloadFile?.(response);
|
|
47220
|
+
this.emitEvent("download:downloaded", { result: response });
|
|
47221
|
+
this.emitEvent("complete", { success: true, operation: "downloadFile" });
|
|
47222
|
+
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, true);
|
|
47223
|
+
return response;
|
|
47224
|
+
} catch (error) {
|
|
47225
|
+
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, false);
|
|
47226
|
+
this.emitEvent("download:error", { error });
|
|
47227
|
+
throw error;
|
|
47228
|
+
}
|
|
47229
|
+
}
|
|
47230
|
+
/**
|
|
47231
|
+
* Get signed URL for file
|
|
47232
|
+
* GET /files/:id/signed-url
|
|
47233
|
+
*
|
|
47234
|
+
* Follows same pattern as base class CRUD methods.
|
|
47235
|
+
*
|
|
47236
|
+
* @param params - Signed URL parameters (fileId required)
|
|
47237
|
+
* @returns Signed URL result with url and expiresAt
|
|
47238
|
+
*/
|
|
47239
|
+
// eslint-disable-next-line complexity
|
|
47240
|
+
async getSignedUrl(params) {
|
|
47241
|
+
this.assertReady();
|
|
47242
|
+
const startTime = Date.now();
|
|
47243
|
+
this.logDebug("Getting signed URL", { fileId: params.fileId, expiresIn: params.expiresIn });
|
|
47244
|
+
this.emitEvent("signedUrl:requesting", { request: params });
|
|
47245
|
+
try {
|
|
47246
|
+
await this.beforeGetSignedUrl?.(params);
|
|
47247
|
+
if (!this.storageService) {
|
|
47248
|
+
throw new Error(
|
|
47249
|
+
"Storage service not available. Ensure storage is configured in Core.initialize()."
|
|
47250
|
+
);
|
|
47251
|
+
}
|
|
47252
|
+
const storage = this.storageService.getStorage();
|
|
47253
|
+
const result2 = await storage.getSignedUrl({
|
|
47254
|
+
fileId: params.fileId,
|
|
47255
|
+
expiresIn: params.expiresIn ?? config.DOWNLOAD_CONFIG.DEFAULT_SIGNED_URL_EXPIRY_SECONDS,
|
|
47256
|
+
operation: "get"
|
|
47257
|
+
});
|
|
47258
|
+
const response = {
|
|
47259
|
+
url: result2?.url ?? "",
|
|
47260
|
+
expiresAt: result2?.expiresAt?.toISOString() ?? new Date(Date.now() + config.TIME_CONSTANTS.HOUR).toISOString()
|
|
47261
|
+
};
|
|
47262
|
+
await this.afterGetSignedUrl?.(response);
|
|
47263
|
+
this.emitEvent("signedUrl:received", { result: response });
|
|
47264
|
+
this.emitEvent("complete", { success: true, operation: "getSignedUrl" });
|
|
47265
|
+
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, true);
|
|
47266
|
+
return response;
|
|
47267
|
+
} catch (error) {
|
|
47268
|
+
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, false);
|
|
47269
|
+
this.emitEvent("signedUrl:error", { error });
|
|
47270
|
+
throw error;
|
|
47271
|
+
}
|
|
47272
|
+
}
|
|
47273
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47274
|
+
// DB Persistence (called by StorageService on upload complete)
|
|
47275
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47276
|
+
/**
|
|
47277
|
+
* Persist uploaded file metadata to the media table.
|
|
47278
|
+
* Called by StorageService.onFileUploaded event handler.
|
|
47279
|
+
*
|
|
47280
|
+
* @param metadata - File metadata from storage upload
|
|
47281
|
+
* @param variants - Optional file variants (thumbnails, etc.)
|
|
47282
|
+
* @param userId - Optional user ID who uploaded the file
|
|
47283
|
+
*/
|
|
47284
|
+
async persistUploadedFile(metadata, variants, userId) {
|
|
47285
|
+
const startTime = Date.now();
|
|
47286
|
+
this.logDebug("Persisting uploaded file to DB", {
|
|
47287
|
+
fileId: metadata.fileId,
|
|
47288
|
+
filename: metadata.filename
|
|
47289
|
+
});
|
|
47290
|
+
try {
|
|
47291
|
+
const dbRow = FilesMapper.toDbRow({ metadata, variants }, userId);
|
|
47292
|
+
await this.repository.create(dbRow);
|
|
47293
|
+
this.logDebug("File persisted to media table", {
|
|
47294
|
+
fileId: metadata.fileId,
|
|
47295
|
+
filename: metadata.filename
|
|
47296
|
+
});
|
|
47297
|
+
await this.recordOperationMetrics("persistUploadedFile", Date.now() - startTime, true);
|
|
47298
|
+
} catch (error) {
|
|
47299
|
+
await this.recordOperationMetrics("persistUploadedFile", Date.now() - startTime, false);
|
|
47300
|
+
throw error;
|
|
47301
|
+
}
|
|
47302
|
+
}
|
|
47303
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47304
|
+
// NOTE: CRUD and Storage Methods Are Inherited from BaseBackendDomainService
|
|
47305
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47306
|
+
//
|
|
47307
|
+
// CRUD methods:
|
|
47308
|
+
// - getById(id) - for GET /files/:id
|
|
47309
|
+
// - getAll(query) - for listing files
|
|
47310
|
+
// - delete(id) - for DELETE /files/:id
|
|
47311
|
+
// - exists(id) - check if file exists
|
|
47312
|
+
//
|
|
47313
|
+
// Storage methods (inherited):
|
|
47314
|
+
// - uploadFile(params) - for POST /files/upload
|
|
47315
|
+
// - generateFile(params) - for POST /files/generate-document
|
|
47316
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47317
|
+
};
|
|
47318
|
+
var backendFilesDomainService = new BackendFilesDomainService();
|
|
47319
|
+
var _instance = null;
|
|
47320
|
+
async function getBackendFilesDomainService(config, options) {
|
|
47321
|
+
_instance ??= await BackendFilesDomainService.create(config, options);
|
|
47322
|
+
return _instance;
|
|
47323
|
+
}
|
|
47324
|
+
__name(getBackendFilesDomainService, "getBackendFilesDomainService");
|
|
47325
|
+
|
|
47326
|
+
// src/services/StorageService.ts
|
|
47327
|
+
var logger5 = new logger$1.PackageLogger({ packageName: "core", service: "StorageService" });
|
|
47328
|
+
var StorageService = class _StorageService {
|
|
47329
|
+
constructor() {
|
|
47330
|
+
this.storageService = null;
|
|
47331
|
+
this.config = null;
|
|
47332
|
+
this.initialized = false;
|
|
47333
|
+
}
|
|
47334
|
+
static {
|
|
47335
|
+
__name(this, "StorageService");
|
|
47336
|
+
}
|
|
47337
|
+
static {
|
|
47338
|
+
this.instance = null;
|
|
47339
|
+
}
|
|
47340
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47341
|
+
// Error Handling
|
|
47342
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47343
|
+
/**
|
|
47344
|
+
* Emits a storage error event via CoreEventManager.
|
|
47345
|
+
* Called when storage operations fail to integrate with global error handling.
|
|
47346
|
+
*/
|
|
47347
|
+
emitStorageError(error, operation, options) {
|
|
47348
|
+
const payload = {
|
|
47349
|
+
error,
|
|
47350
|
+
operation,
|
|
47351
|
+
fileId: options?.fileId,
|
|
47352
|
+
filename: options?.filename,
|
|
47353
|
+
recoverable: options?.recoverable ?? false
|
|
47354
|
+
};
|
|
47355
|
+
CoreEventManager.emit(core.CORE_EVENTS.STORAGE.ERROR, payload);
|
|
47356
|
+
}
|
|
47357
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47358
|
+
// Singleton Management
|
|
47359
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47360
|
+
/**
|
|
47361
|
+
* Gets the singleton instance of StorageService
|
|
47362
|
+
*/
|
|
47363
|
+
static getInstance() {
|
|
47364
|
+
_StorageService.instance ??= new _StorageService();
|
|
47365
|
+
return _StorageService.instance;
|
|
47366
|
+
}
|
|
47367
|
+
/**
|
|
47368
|
+
* Checks if the storage service has been initialized
|
|
47369
|
+
*/
|
|
47370
|
+
static isInitialized() {
|
|
47371
|
+
return _StorageService.instance?.initialized ?? false;
|
|
47372
|
+
}
|
|
47373
|
+
/**
|
|
47374
|
+
* Resets the storage service by clearing the singleton instance
|
|
47375
|
+
*/
|
|
47376
|
+
static async reset() {
|
|
47377
|
+
if (_StorageService.instance) {
|
|
47378
|
+
_StorageService.instance.storageService = null;
|
|
47379
|
+
_StorageService.instance.config = null;
|
|
47380
|
+
_StorageService.instance.initialized = false;
|
|
47381
|
+
_StorageService.instance = null;
|
|
47382
|
+
}
|
|
47383
|
+
}
|
|
47384
|
+
/**
|
|
47385
|
+
* Creates merged event handlers that persist uploads to the media table.
|
|
47386
|
+
* Merges Core's internal DB persistence handler with user-provided handlers.
|
|
47387
|
+
*
|
|
47388
|
+
* @param userHandlers - User-provided event handlers from config
|
|
47389
|
+
* @returns Merged handlers with DB persistence + user handlers
|
|
47390
|
+
*/
|
|
47391
|
+
static createMergedEventHandlers(userHandlers) {
|
|
47392
|
+
return {
|
|
47393
|
+
...userHandlers,
|
|
47394
|
+
// Persist uploaded files to media table, then call user handler
|
|
47395
|
+
onFileUploaded: /* @__PURE__ */ __name(async (payload) => {
|
|
47396
|
+
if (payload.metadata) {
|
|
47397
|
+
const filesService = await getBackendFilesDomainService();
|
|
47398
|
+
await filesService.persistUploadedFile(payload.metadata);
|
|
47399
|
+
}
|
|
47400
|
+
if (userHandlers?.onFileUploaded) {
|
|
47401
|
+
await userHandlers.onFileUploaded(payload);
|
|
47402
|
+
}
|
|
47403
|
+
}, "onFileUploaded")
|
|
47404
|
+
};
|
|
47405
|
+
}
|
|
47406
|
+
/**
|
|
47407
|
+
* Initializes the storage service
|
|
47408
|
+
*
|
|
47409
|
+
* @param config - Storage service configuration
|
|
47410
|
+
* @returns The initialized StorageService instance
|
|
47411
|
+
*/
|
|
47412
|
+
static async initialize(config) {
|
|
47413
|
+
const instance = _StorageService.getInstance();
|
|
47414
|
+
if (instance.initialized) {
|
|
47415
|
+
return instance;
|
|
47416
|
+
}
|
|
47417
|
+
instance.config = config;
|
|
47418
|
+
const mergedHandlers = _StorageService.createMergedEventHandlers(config.handlers);
|
|
47419
|
+
const mergedConfig = {
|
|
47420
|
+
...config,
|
|
47421
|
+
handlers: mergedHandlers
|
|
47422
|
+
};
|
|
47423
|
+
logger5.info("[StorageService] Initializing with merged event handlers for DB persistence");
|
|
47424
|
+
instance.storageService = new storage$1.StorageService(mergedConfig);
|
|
47425
|
+
instance.initialized = true;
|
|
47426
|
+
return instance;
|
|
47427
|
+
}
|
|
47428
|
+
/**
|
|
47429
|
+
* Gets the raw underlying storage service instance without error handling wrapper.
|
|
46969
47430
|
* Use this only if you need direct access to the underlying service.
|
|
46970
47431
|
*
|
|
46971
|
-
* @returns The raw
|
|
46972
|
-
* @throws {
|
|
47432
|
+
* @returns The raw StorageService instance from @plyaz/storage
|
|
47433
|
+
* @throws {StoragePackageError} When storage is not initialized
|
|
46973
47434
|
*/
|
|
46974
|
-
|
|
46975
|
-
if (!this.
|
|
46976
|
-
throw new errors.
|
|
46977
|
-
"
|
|
46978
|
-
errors$1.
|
|
47435
|
+
getRawStorage() {
|
|
47436
|
+
if (!this.storageService) {
|
|
47437
|
+
throw new errors.StoragePackageError(
|
|
47438
|
+
"Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
|
|
47439
|
+
errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
|
|
46979
47440
|
);
|
|
46980
47441
|
}
|
|
46981
|
-
return this.
|
|
47442
|
+
return this.storageService;
|
|
46982
47443
|
}
|
|
46983
47444
|
// ─────────────────────────────────────────────────────────────────
|
|
46984
47445
|
// Service Access
|
|
46985
47446
|
// ─────────────────────────────────────────────────────────────────
|
|
46986
47447
|
/**
|
|
46987
|
-
* Gets the
|
|
47448
|
+
* Gets the storage service with automatic error handling.
|
|
46988
47449
|
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46989
|
-
* Any method added to @plyaz/
|
|
47450
|
+
* Any method added to @plyaz/storage will be automatically available.
|
|
46990
47451
|
*
|
|
46991
47452
|
* @example
|
|
46992
47453
|
* ```typescript
|
|
46993
|
-
* const
|
|
46994
|
-
* await
|
|
46995
|
-
* await
|
|
47454
|
+
* const storage = StorageService.getInstance().getStorage();
|
|
47455
|
+
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
47456
|
+
* await storage.deleteFile({ fileId: '123' });
|
|
46996
47457
|
* ```
|
|
46997
47458
|
*
|
|
46998
|
-
* @returns
|
|
47459
|
+
* @returns StorageServiceImpl with automatic error handling
|
|
46999
47460
|
*/
|
|
47000
|
-
|
|
47461
|
+
getStorage() {
|
|
47001
47462
|
const self2 = this;
|
|
47002
47463
|
return new Proxy({}, {
|
|
47003
47464
|
get(_, prop) {
|
|
47004
47465
|
if (typeof prop === "symbol") {
|
|
47005
47466
|
return void 0;
|
|
47006
47467
|
}
|
|
47007
|
-
const
|
|
47008
|
-
const value =
|
|
47468
|
+
const storage = self2.getRawStorage();
|
|
47469
|
+
const value = storage[prop];
|
|
47009
47470
|
if (typeof value !== "function") {
|
|
47010
47471
|
return value;
|
|
47011
47472
|
}
|
|
47012
47473
|
return (...args) => {
|
|
47013
47474
|
try {
|
|
47014
|
-
const result2 = value.apply(
|
|
47475
|
+
const result2 = value.apply(storage, args);
|
|
47015
47476
|
if (result2 instanceof Promise) {
|
|
47016
47477
|
return result2.catch((error) => {
|
|
47017
|
-
self2.
|
|
47478
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47018
47479
|
throw error;
|
|
47019
47480
|
});
|
|
47020
47481
|
}
|
|
47021
47482
|
return result2;
|
|
47022
47483
|
} catch (error) {
|
|
47023
|
-
self2.
|
|
47484
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47024
47485
|
throw error;
|
|
47025
47486
|
}
|
|
47026
47487
|
};
|
|
@@ -47031,23 +47492,29 @@ var NotificationService = class _NotificationService {
|
|
|
47031
47492
|
// Health Check (special handling for response transformation)
|
|
47032
47493
|
// ─────────────────────────────────────────────────────────────────
|
|
47033
47494
|
/**
|
|
47034
|
-
* Performs a health check on the
|
|
47495
|
+
* Performs a health check on the storage service by checking all adapter health.
|
|
47035
47496
|
* This method has special handling to transform the response format.
|
|
47036
47497
|
*/
|
|
47037
47498
|
async healthCheck() {
|
|
47499
|
+
const startTime = Date.now();
|
|
47038
47500
|
try {
|
|
47039
|
-
const
|
|
47040
|
-
|
|
47501
|
+
const storage = this.getRawStorage();
|
|
47502
|
+
if (typeof storage.checkAllAdaptersHealth === "function") {
|
|
47503
|
+
await storage.checkAllAdaptersHealth();
|
|
47504
|
+
}
|
|
47505
|
+
const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
|
|
47506
|
+
const responseTime = Date.now() - startTime;
|
|
47041
47507
|
return {
|
|
47042
|
-
|
|
47043
|
-
|
|
47044
|
-
|
|
47045
|
-
error:
|
|
47508
|
+
// Check if all adapters are healthy (healthy count equals total count)
|
|
47509
|
+
isHealthy: summary ? summary.healthy === summary.total : true,
|
|
47510
|
+
responseTime,
|
|
47511
|
+
error: void 0
|
|
47046
47512
|
};
|
|
47047
47513
|
} catch (error) {
|
|
47048
|
-
this.
|
|
47514
|
+
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
47049
47515
|
return {
|
|
47050
47516
|
isHealthy: false,
|
|
47517
|
+
responseTime: Date.now() - startTime,
|
|
47051
47518
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
47052
47519
|
};
|
|
47053
47520
|
}
|
|
@@ -47062,844 +47529,539 @@ var NotificationService = class _NotificationService {
|
|
|
47062
47529
|
return this.config;
|
|
47063
47530
|
}
|
|
47064
47531
|
/**
|
|
47065
|
-
* Closes the
|
|
47532
|
+
* Closes the storage service and cleans up resources
|
|
47066
47533
|
*/
|
|
47067
47534
|
async close() {
|
|
47068
|
-
this.
|
|
47535
|
+
if (this.storageService) {
|
|
47536
|
+
await this.storageService.destroy();
|
|
47537
|
+
}
|
|
47538
|
+
this.storageService = null;
|
|
47069
47539
|
this.initialized = false;
|
|
47070
47540
|
this.config = null;
|
|
47071
47541
|
}
|
|
47072
47542
|
/**
|
|
47073
|
-
* Creates a dedicated
|
|
47543
|
+
* Creates a dedicated storage service instance (NOT the singleton)
|
|
47074
47544
|
*
|
|
47075
|
-
* Use this when you need an isolated
|
|
47545
|
+
* Use this when you need an isolated storage connection with its own configuration.
|
|
47076
47546
|
*
|
|
47077
|
-
* @param config -
|
|
47078
|
-
* @returns Promise that resolves to a new dedicated
|
|
47547
|
+
* @param config - Storage service configuration
|
|
47548
|
+
* @returns Promise that resolves to a new dedicated StorageService instance
|
|
47079
47549
|
*/
|
|
47080
47550
|
static async createInstance(config) {
|
|
47081
|
-
const dedicatedInstance = new
|
|
47551
|
+
const dedicatedInstance = new _StorageService();
|
|
47082
47552
|
dedicatedInstance.config = config;
|
|
47083
|
-
dedicatedInstance.
|
|
47553
|
+
dedicatedInstance.storageService = new storage$1.StorageService(config);
|
|
47084
47554
|
dedicatedInstance.initialized = true;
|
|
47085
47555
|
return dedicatedInstance;
|
|
47086
47556
|
}
|
|
47087
47557
|
};
|
|
47088
|
-
var
|
|
47089
|
-
|
|
47090
|
-
|
|
47091
|
-
|
|
47092
|
-
|
|
47093
|
-
|
|
47094
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47095
|
-
} catch {
|
|
47096
|
-
try {
|
|
47097
|
-
const currentFile = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
47098
|
-
const currentDir = path.dirname(currentFile);
|
|
47099
|
-
const pkgPath = path.join(currentDir, "..", "package.json");
|
|
47100
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
47101
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47102
|
-
} catch {
|
|
47103
|
-
cachedVersion = "0.0.0";
|
|
47104
|
-
}
|
|
47105
|
-
}
|
|
47106
|
-
return cachedVersion;
|
|
47107
|
-
}
|
|
47108
|
-
__name(getPackageVersion, "getPackageVersion");
|
|
47109
|
-
var VERSION = getPackageVersion();
|
|
47110
|
-
var PACKAGE_NAME = "@plyaz/core";
|
|
47111
|
-
|
|
47112
|
-
// src/backend/index.ts
|
|
47113
|
-
var backend_exports = {};
|
|
47114
|
-
__export(backend_exports, {
|
|
47115
|
-
BACKEND_EXAMPLE_DOMAIN_SERVICE: () => BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47116
|
-
BACKEND_FILES_DOMAIN_SERVICE: () => BACKEND_FILES_DOMAIN_SERVICE,
|
|
47117
|
-
BackendExampleDomainService: () => BackendExampleDomainService,
|
|
47118
|
-
Caching: () => Caching,
|
|
47119
|
-
ErrorHandlingInterceptor: () => ErrorHandlingInterceptor,
|
|
47120
|
-
ExampleController: () => ExampleController,
|
|
47121
|
-
ExampleModule: () => ExampleModule,
|
|
47122
|
-
FeatureDisabled: () => FeatureDisabled,
|
|
47123
|
-
FeatureEnabled: () => FeatureEnabled,
|
|
47124
|
-
FeatureFlagConfigFactory: () => FeatureFlagConfigFactory,
|
|
47125
|
-
FeatureFlagConfigValidator: () => FeatureFlagConfigValidator,
|
|
47126
|
-
FeatureFlagController: () => FeatureFlagController,
|
|
47127
|
-
FeatureFlagDatabaseRepository: () => FeatureFlagDatabaseRepository,
|
|
47128
|
-
FeatureFlagDomainService: () => FeatureFlagDomainService,
|
|
47129
|
-
FeatureFlagGuard: () => FeatureFlagGuard,
|
|
47130
|
-
FeatureFlagLoggingInterceptor: () => FeatureFlagLoggingInterceptor,
|
|
47131
|
-
FeatureFlagMiddleware: () => FeatureFlagMiddleware,
|
|
47132
|
-
FeatureFlagModule: () => FeatureFlagModule,
|
|
47133
|
-
FeatureFlagService: () => FeatureFlagService,
|
|
47134
|
-
FeatureFlagServiceFactory: () => FeatureFlagServiceFactory,
|
|
47135
|
-
FilesController: () => FilesController,
|
|
47136
|
-
FilesModule: () => FilesModule
|
|
47137
|
-
});
|
|
47138
|
-
|
|
47139
|
-
// src/backend/example/example.module.ts
|
|
47140
|
-
var import_common11 = __toESM(require_common(), 1);
|
|
47141
|
-
|
|
47142
|
-
// src/backend/example/example.controller.ts
|
|
47143
|
-
var import_common10 = __toESM(require_common(), 1);
|
|
47144
|
-
var BACKEND_EXAMPLE_DOMAIN_SERVICE = "BACKEND_EXAMPLE_DOMAIN_SERVICE";
|
|
47145
|
-
var ExampleController = class {
|
|
47146
|
-
constructor(exampleService) {
|
|
47147
|
-
this.exampleService = exampleService;
|
|
47148
|
-
}
|
|
47149
|
-
health() {
|
|
47150
|
-
return errors.SuccessResponseStandard("Service is healthy", {
|
|
47151
|
-
service: this.exampleService.isAvailable(),
|
|
47152
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47153
|
-
});
|
|
47154
|
-
}
|
|
47155
|
-
async getEntity(id) {
|
|
47156
|
-
const entity = await this.exampleService.getById(id);
|
|
47157
|
-
return errors.SuccessResponseStandard("Entity retrieved successfully", entity);
|
|
47158
|
-
}
|
|
47159
|
-
async createEntity(dto) {
|
|
47160
|
-
const entity = await this.exampleService.create(dto);
|
|
47161
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47162
|
-
}
|
|
47163
|
-
async updateEntity(id, dto) {
|
|
47164
|
-
const entity = await this.exampleService.patch(id, dto);
|
|
47165
|
-
return errors.SuccessResponseStandard("Entity updated successfully", entity);
|
|
47166
|
-
}
|
|
47167
|
-
async deleteEntity(id) {
|
|
47168
|
-
await this.exampleService.delete(id);
|
|
47169
|
-
return errors.SuccessResponseStandard("Entity deleted successfully", null);
|
|
47170
|
-
}
|
|
47171
|
-
async createEntityWithValidation(dto) {
|
|
47172
|
-
const entity = await this.exampleService.create(dto);
|
|
47173
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47174
|
-
}
|
|
47175
|
-
async demoSingleError() {
|
|
47176
|
-
return await this.exampleService.demoSingleValidationError();
|
|
47177
|
-
}
|
|
47178
|
-
async demoArrayErrors() {
|
|
47179
|
-
return await this.exampleService.demoMultipleValidationErrors();
|
|
47180
|
-
}
|
|
47181
|
-
async sendEmail(dto) {
|
|
47182
|
-
const result2 = await this.exampleService.sendEmail(dto);
|
|
47183
|
-
return errors.SuccessResponseStandard("Email sent successfully", result2);
|
|
47184
|
-
}
|
|
47185
|
-
};
|
|
47186
|
-
__name(ExampleController, "ExampleController");
|
|
47187
|
-
__decorateClass([
|
|
47188
|
-
(0, import_common10.Get)("health")
|
|
47189
|
-
], ExampleController.prototype, "health", 1);
|
|
47190
|
-
__decorateClass([
|
|
47191
|
-
(0, import_common10.Get)("entities/:id"),
|
|
47192
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47193
|
-
], ExampleController.prototype, "getEntity", 1);
|
|
47194
|
-
__decorateClass([
|
|
47195
|
-
(0, import_common10.Post)("entities"),
|
|
47196
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47197
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47198
|
-
], ExampleController.prototype, "createEntity", 1);
|
|
47199
|
-
__decorateClass([
|
|
47200
|
-
(0, import_common10.Patch)("entities/:id"),
|
|
47201
|
-
__decorateParam(0, (0, import_common10.Param)("id")),
|
|
47202
|
-
__decorateParam(1, (0, import_common10.Body)())
|
|
47203
|
-
], ExampleController.prototype, "updateEntity", 1);
|
|
47204
|
-
__decorateClass([
|
|
47205
|
-
(0, import_common10.Delete)("entities/:id"),
|
|
47206
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47207
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47208
|
-
], ExampleController.prototype, "deleteEntity", 1);
|
|
47209
|
-
__decorateClass([
|
|
47210
|
-
(0, import_common10.Post)("entities/validated"),
|
|
47211
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47212
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47213
|
-
], ExampleController.prototype, "createEntityWithValidation", 1);
|
|
47214
|
-
__decorateClass([
|
|
47215
|
-
(0, import_common10.Get)("errors/single")
|
|
47216
|
-
], ExampleController.prototype, "demoSingleError", 1);
|
|
47217
|
-
__decorateClass([
|
|
47218
|
-
(0, import_common10.Get)("errors/array")
|
|
47219
|
-
], ExampleController.prototype, "demoArrayErrors", 1);
|
|
47220
|
-
__decorateClass([
|
|
47221
|
-
(0, import_common10.Post)("email"),
|
|
47222
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47223
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47224
|
-
], ExampleController.prototype, "sendEmail", 1);
|
|
47225
|
-
ExampleController = __decorateClass([
|
|
47226
|
-
(0, import_common10.Controller)("example"),
|
|
47227
|
-
__decorateParam(0, (0, import_common10.Inject)(BACKEND_EXAMPLE_DOMAIN_SERVICE))
|
|
47228
|
-
], ExampleController);
|
|
47229
|
-
|
|
47230
|
-
// src/backend/example/example.module.ts
|
|
47231
|
-
var ExampleModule = class {
|
|
47232
|
-
};
|
|
47233
|
-
__name(ExampleModule, "ExampleModule");
|
|
47234
|
-
ExampleModule = __decorateClass([
|
|
47235
|
-
(0, import_common11.Module)({
|
|
47236
|
-
controllers: [ExampleController],
|
|
47237
|
-
providers: [
|
|
47238
|
-
// Provide BackendExampleDomainService via factory using the singleton instance
|
|
47239
|
-
// This ensures the service is shared across the application
|
|
47240
|
-
{
|
|
47241
|
-
provide: BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47242
|
-
useFactory: /* @__PURE__ */ __name(() => backendExampleDomainService, "useFactory")
|
|
47243
|
-
}
|
|
47244
|
-
],
|
|
47245
|
-
exports: [BACKEND_EXAMPLE_DOMAIN_SERVICE]
|
|
47246
|
-
})
|
|
47247
|
-
], ExampleModule);
|
|
47248
|
-
|
|
47249
|
-
// src/backend/files/files.module.ts
|
|
47250
|
-
var import_common17 = __toESM(require_common(), 1);
|
|
47251
|
-
|
|
47252
|
-
// src/backend/files/files.controller.ts
|
|
47253
|
-
var import_common12 = __toESM(require_common(), 1);
|
|
47254
|
-
var BACKEND_FILES_DOMAIN_SERVICE = "BACKEND_FILES_DOMAIN_SERVICE";
|
|
47255
|
-
var FilesController = class {
|
|
47256
|
-
constructor(filesService) {
|
|
47257
|
-
this.filesService = filesService;
|
|
47258
|
-
}
|
|
47259
|
-
health() {
|
|
47260
|
-
return errors.SuccessResponseStandard("Files service is healthy", {
|
|
47261
|
-
service: this.filesService.isAvailable(),
|
|
47262
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47263
|
-
});
|
|
47264
|
-
}
|
|
47265
|
-
async uploadFile(dto) {
|
|
47266
|
-
const result2 = await this.filesService.uploadFile(dto);
|
|
47267
|
-
return errors.SuccessResponseStandard("File uploaded successfully", result2);
|
|
47268
|
-
}
|
|
47269
|
-
async uploadFiles(dto) {
|
|
47270
|
-
const results = await this.filesService.uploadFiles(dto.files);
|
|
47271
|
-
return errors.SuccessResponseStandard("Files uploaded successfully", results);
|
|
47272
|
-
}
|
|
47273
|
-
async generateDocument(dto) {
|
|
47274
|
-
const buffer = await this.filesService.generateFile(dto);
|
|
47275
|
-
return errors.SuccessResponseStandard("Document generated successfully", {
|
|
47276
|
-
buffer: buffer.toString("base64"),
|
|
47277
|
-
size: buffer.length
|
|
47278
|
-
});
|
|
47279
|
-
}
|
|
47280
|
-
async getFile(id) {
|
|
47281
|
-
const entity = await this.filesService.getById(id);
|
|
47282
|
-
return errors.SuccessResponseStandard("File retrieved", entity);
|
|
47283
|
-
}
|
|
47284
|
-
async downloadFile(id) {
|
|
47285
|
-
const result2 = await this.filesService.downloadFile({ fileId: id });
|
|
47286
|
-
return errors.SuccessResponseStandard("File downloaded", result2);
|
|
47287
|
-
}
|
|
47288
|
-
async getSignedUrl(id) {
|
|
47289
|
-
const result2 = await this.filesService.getSignedUrl({ fileId: id });
|
|
47290
|
-
return errors.SuccessResponseStandard("Signed URL generated", result2);
|
|
47291
|
-
}
|
|
47292
|
-
async deleteFile(id) {
|
|
47293
|
-
await this.filesService.delete(id);
|
|
47294
|
-
return errors.SuccessResponseStandard("File deleted", null);
|
|
47295
|
-
}
|
|
47296
|
-
};
|
|
47297
|
-
__name(FilesController, "FilesController");
|
|
47298
|
-
__decorateClass([
|
|
47299
|
-
(0, import_common12.Get)("health")
|
|
47300
|
-
], FilesController.prototype, "health", 1);
|
|
47301
|
-
__decorateClass([
|
|
47302
|
-
(0, import_common12.Post)("upload"),
|
|
47303
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47304
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47305
|
-
], FilesController.prototype, "uploadFile", 1);
|
|
47306
|
-
__decorateClass([
|
|
47307
|
-
(0, import_common12.Post)("upload/bulk"),
|
|
47308
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47309
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47310
|
-
], FilesController.prototype, "uploadFiles", 1);
|
|
47311
|
-
__decorateClass([
|
|
47312
|
-
(0, import_common12.Post)("generate-document"),
|
|
47313
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47314
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47315
|
-
], FilesController.prototype, "generateDocument", 1);
|
|
47316
|
-
__decorateClass([
|
|
47317
|
-
(0, import_common12.Get)(":id"),
|
|
47318
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47319
|
-
], FilesController.prototype, "getFile", 1);
|
|
47320
|
-
__decorateClass([
|
|
47321
|
-
(0, import_common12.Get)(":id/download"),
|
|
47322
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47323
|
-
], FilesController.prototype, "downloadFile", 1);
|
|
47324
|
-
__decorateClass([
|
|
47325
|
-
(0, import_common12.Get)(":id/signed-url"),
|
|
47326
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47327
|
-
], FilesController.prototype, "getSignedUrl", 1);
|
|
47328
|
-
__decorateClass([
|
|
47329
|
-
(0, import_common12.Delete)(":id"),
|
|
47330
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47331
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47332
|
-
], FilesController.prototype, "deleteFile", 1);
|
|
47333
|
-
FilesController = __decorateClass([
|
|
47334
|
-
(0, import_common12.Controller)("files"),
|
|
47335
|
-
__decorateParam(0, (0, import_common12.Inject)(BACKEND_FILES_DOMAIN_SERVICE))
|
|
47336
|
-
], FilesController);
|
|
47337
|
-
var TABLE_NAME = "media";
|
|
47338
|
-
var DEFAULT_LIMIT2 = 100;
|
|
47339
|
-
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
47340
|
-
static {
|
|
47341
|
-
__name(this, "FilesRepository");
|
|
47342
|
-
}
|
|
47343
|
-
constructor(db) {
|
|
47344
|
-
super(db, TABLE_NAME);
|
|
47345
|
-
}
|
|
47346
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47347
|
-
// Static Factory
|
|
47348
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47349
|
-
/**
|
|
47350
|
-
* Create repository instance.
|
|
47351
|
-
* Uses DbService if initialized.
|
|
47352
|
-
*/
|
|
47353
|
-
static create() {
|
|
47354
|
-
if (!DbService.isInitialized()) {
|
|
47355
|
-
throw new errors.DatabasePackageError(
|
|
47356
|
-
"DbService not initialized. Call DbService.initialize() first.",
|
|
47357
|
-
errors$1.DATABASE_ERROR_CODES.CONNECTION_FAILED
|
|
47358
|
-
);
|
|
47359
|
-
}
|
|
47360
|
-
const db = DbService.getInstance().getDatabase();
|
|
47361
|
-
return new _FilesRepository(db);
|
|
47362
|
-
}
|
|
47363
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47364
|
-
// Overridden Methods (with domain-specific logic)
|
|
47365
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47366
|
-
/**
|
|
47367
|
-
* Find multiple entities with default sorting
|
|
47368
|
-
*/
|
|
47369
|
-
// eslint-disable-next-line complexity
|
|
47370
|
-
async findMany(options, config) {
|
|
47371
|
-
const mergedOptions = {
|
|
47372
|
-
sort: options?.sort ?? [{ field: "created_at", direction: "desc" }],
|
|
47373
|
-
pagination: {
|
|
47374
|
-
limit: options?.pagination?.limit ?? DEFAULT_LIMIT2,
|
|
47375
|
-
offset: options?.pagination?.offset ?? 0
|
|
47376
|
-
},
|
|
47377
|
-
filter: options?.filter
|
|
47378
|
-
};
|
|
47379
|
-
return super.findMany(mergedOptions, config);
|
|
47380
|
-
}
|
|
47381
|
-
/**
|
|
47382
|
-
* Create new file record with auto-generated ID and timestamps
|
|
47383
|
-
*/
|
|
47384
|
-
// eslint-disable-next-line complexity
|
|
47385
|
-
async create(data, config) {
|
|
47386
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47387
|
-
const id = data.id ?? generateId();
|
|
47388
|
-
const row = {
|
|
47389
|
-
id,
|
|
47390
|
-
user_id: data.user_id ?? "",
|
|
47391
|
-
type: data.type ?? "OTHER",
|
|
47392
|
-
filename: data.filename ?? "",
|
|
47393
|
-
original_filename: data.original_filename ?? data.filename ?? "",
|
|
47394
|
-
mime_type: data.mime_type ?? "application/octet-stream",
|
|
47395
|
-
file_size: data.file_size ?? 0,
|
|
47396
|
-
storage_path: data.storage_path ?? "",
|
|
47397
|
-
cdn_url: data.cdn_url ?? null,
|
|
47398
|
-
width: data.width ?? null,
|
|
47399
|
-
height: data.height ?? null,
|
|
47400
|
-
duration: data.duration ?? null,
|
|
47401
|
-
is_virus_scanned: data.is_virus_scanned ?? false,
|
|
47402
|
-
virus_scan_result: data.virus_scan_result ?? null,
|
|
47403
|
-
metadata: data.metadata ?? null,
|
|
47404
|
-
variants: data.variants ?? null,
|
|
47405
|
-
entity_type: data.entity_type ?? null,
|
|
47406
|
-
entity_id: data.entity_id ?? null,
|
|
47407
|
-
access_level: data.access_level ?? null,
|
|
47408
|
-
created_at: now,
|
|
47409
|
-
updated_at: now,
|
|
47410
|
-
deleted_at: null
|
|
47411
|
-
};
|
|
47412
|
-
return super.create(row, config);
|
|
47413
|
-
}
|
|
47414
|
-
/**
|
|
47415
|
-
* Get the table name for this repository
|
|
47416
|
-
*/
|
|
47417
|
-
getTableName() {
|
|
47418
|
-
return TABLE_NAME;
|
|
47419
|
-
}
|
|
47420
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47421
|
-
// Domain-Specific Methods
|
|
47422
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47423
|
-
/**
|
|
47424
|
-
* Find all files for a user
|
|
47425
|
-
*/
|
|
47426
|
-
async findByUserId(userId, options) {
|
|
47427
|
-
return this.findMany({
|
|
47428
|
-
filter: { field: "user_id", operator: "eq", value: userId },
|
|
47429
|
-
pagination: {
|
|
47430
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47431
|
-
offset: options?.offset ?? 0
|
|
47432
|
-
}
|
|
47433
|
-
});
|
|
47434
|
-
}
|
|
47435
|
-
/**
|
|
47436
|
-
* Find files for a specific entity (polymorphic association)
|
|
47437
|
-
*/
|
|
47438
|
-
async findByEntityId(entityType, entityId, options) {
|
|
47439
|
-
return this.query().where("entity_type", "eq", entityType).andWhere("entity_id", "eq", entityId).whereNull("deleted_at").orderByDesc("created_at").paginate(
|
|
47440
|
-
Math.floor((options?.offset ?? 0) / (options?.limit ?? DEFAULT_LIMIT2)) + 1,
|
|
47441
|
-
options?.limit ?? DEFAULT_LIMIT2
|
|
47442
|
-
).execute();
|
|
47443
|
-
}
|
|
47444
|
-
/**
|
|
47445
|
-
* Find file by storage path (for deduplication checks)
|
|
47446
|
-
*/
|
|
47447
|
-
async findByStoragePath(storagePath) {
|
|
47448
|
-
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
47449
|
-
}
|
|
47450
|
-
/**
|
|
47451
|
-
* Count files for a user
|
|
47452
|
-
*/
|
|
47453
|
-
async countByUserId(userId) {
|
|
47454
|
-
return this.count({ field: "user_id", operator: "eq", value: userId });
|
|
47455
|
-
}
|
|
47456
|
-
/**
|
|
47457
|
-
* Find files by MIME type
|
|
47458
|
-
*/
|
|
47459
|
-
async findByMimeType(mimeType, options) {
|
|
47460
|
-
return this.findMany({
|
|
47461
|
-
filter: { field: "mime_type", operator: "eq", value: mimeType },
|
|
47462
|
-
pagination: {
|
|
47463
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47464
|
-
offset: options?.offset ?? 0
|
|
47465
|
-
}
|
|
47466
|
-
});
|
|
47467
|
-
}
|
|
47468
|
-
/**
|
|
47469
|
-
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
47470
|
-
*/
|
|
47471
|
-
async findByType(type, options) {
|
|
47472
|
-
return this.findMany({
|
|
47473
|
-
filter: { field: "type", operator: "eq", value: type },
|
|
47474
|
-
pagination: {
|
|
47475
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47476
|
-
offset: options?.offset ?? 0
|
|
47477
|
-
}
|
|
47478
|
-
});
|
|
47558
|
+
var MAX_FAIL_ATTEMPTS = 3;
|
|
47559
|
+
var NotificationService = class _NotificationService {
|
|
47560
|
+
constructor() {
|
|
47561
|
+
this.notificationService = null;
|
|
47562
|
+
this.config = null;
|
|
47563
|
+
this.initialized = false;
|
|
47479
47564
|
}
|
|
47480
|
-
};
|
|
47481
|
-
|
|
47482
|
-
// src/domain/files/mappers/FilesMapper.ts
|
|
47483
|
-
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
47484
47565
|
static {
|
|
47485
|
-
__name(this, "
|
|
47486
|
-
}
|
|
47487
|
-
/**
|
|
47488
|
-
* Type guard for UploadResult from event payloads
|
|
47489
|
-
* Validates that the value has the required structure for DB mapping
|
|
47490
|
-
*/
|
|
47491
|
-
static isUploadResult(value) {
|
|
47492
|
-
if (!isObject(value)) return false;
|
|
47493
|
-
const obj = value;
|
|
47494
|
-
if (!isObject(obj.metadata)) return false;
|
|
47495
|
-
const metadata = obj.metadata;
|
|
47496
|
-
return typeof metadata.fileId === "string" && typeof metadata.filename === "string" && typeof metadata.mimeType === "string" && typeof metadata.size === "number" && typeof metadata.path === "string";
|
|
47497
|
-
}
|
|
47498
|
-
/**
|
|
47499
|
-
* Infer file type from MIME type
|
|
47500
|
-
*/
|
|
47501
|
-
static inferFileType(mimeType) {
|
|
47502
|
-
if (mimeType.startsWith("image/")) return "IMAGE";
|
|
47503
|
-
if (mimeType.startsWith("video/")) return "VIDEO";
|
|
47504
|
-
if (mimeType.startsWith("audio/")) return "AUDIO";
|
|
47505
|
-
if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text/")) {
|
|
47506
|
-
return "DOCUMENT";
|
|
47507
|
-
}
|
|
47508
|
-
return "OTHER";
|
|
47509
|
-
}
|
|
47510
|
-
/**
|
|
47511
|
-
* API Response → Domain Entity
|
|
47512
|
-
*/
|
|
47513
|
-
toDomain(dto) {
|
|
47514
|
-
const type = _FilesMapperClass.inferFileType(dto.mimeType);
|
|
47515
|
-
return {
|
|
47516
|
-
id: dto.id,
|
|
47517
|
-
key: dto.key,
|
|
47518
|
-
filename: dto.filename,
|
|
47519
|
-
mimeType: dto.mimeType,
|
|
47520
|
-
size: dto.size,
|
|
47521
|
-
checksum: dto.checksum,
|
|
47522
|
-
url: dto.url,
|
|
47523
|
-
publicUrl: dto.publicUrl,
|
|
47524
|
-
signedUrl: dto.signedUrl,
|
|
47525
|
-
bucket: dto.bucket,
|
|
47526
|
-
entityType: dto.entityType,
|
|
47527
|
-
entityId: dto.entityId,
|
|
47528
|
-
category: dto.category,
|
|
47529
|
-
uploadedAt: new Date(dto.uploadedAt),
|
|
47530
|
-
expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : void 0,
|
|
47531
|
-
variants: dto.variants,
|
|
47532
|
-
type,
|
|
47533
|
-
isImage: type === "IMAGE",
|
|
47534
|
-
isVideo: type === "VIDEO",
|
|
47535
|
-
isDocument: type === "DOCUMENT",
|
|
47536
|
-
isAudio: type === "AUDIO"
|
|
47537
|
-
};
|
|
47538
|
-
}
|
|
47539
|
-
/**
|
|
47540
|
-
* Domain Entity → Store State (serializable)
|
|
47541
|
-
*/
|
|
47542
|
-
toStoreState(entity) {
|
|
47543
|
-
return {
|
|
47544
|
-
id: entity.id,
|
|
47545
|
-
key: entity.key,
|
|
47546
|
-
filename: entity.filename,
|
|
47547
|
-
mimeType: entity.mimeType,
|
|
47548
|
-
size: entity.size,
|
|
47549
|
-
url: entity.url,
|
|
47550
|
-
publicUrl: entity.publicUrl,
|
|
47551
|
-
bucket: entity.bucket,
|
|
47552
|
-
entityType: entity.entityType,
|
|
47553
|
-
entityId: entity.entityId,
|
|
47554
|
-
category: entity.category,
|
|
47555
|
-
uploadedAt: entity.uploadedAt.toISOString(),
|
|
47556
|
-
type: entity.type,
|
|
47557
|
-
isImage: entity.isImage,
|
|
47558
|
-
isVideo: entity.isVideo,
|
|
47559
|
-
isDocument: entity.isDocument,
|
|
47560
|
-
isAudio: entity.isAudio
|
|
47561
|
-
};
|
|
47562
|
-
}
|
|
47563
|
-
/**
|
|
47564
|
-
* Store State → Domain Entity
|
|
47565
|
-
*/
|
|
47566
|
-
fromStoreState(state) {
|
|
47567
|
-
return {
|
|
47568
|
-
id: state.id,
|
|
47569
|
-
key: state.key,
|
|
47570
|
-
filename: state.filename,
|
|
47571
|
-
mimeType: state.mimeType,
|
|
47572
|
-
size: state.size,
|
|
47573
|
-
url: state.url,
|
|
47574
|
-
publicUrl: state.publicUrl,
|
|
47575
|
-
bucket: state.bucket,
|
|
47576
|
-
entityType: state.entityType,
|
|
47577
|
-
entityId: state.entityId,
|
|
47578
|
-
category: state.category,
|
|
47579
|
-
uploadedAt: new Date(state.uploadedAt),
|
|
47580
|
-
type: state.type,
|
|
47581
|
-
isImage: state.isImage,
|
|
47582
|
-
isVideo: state.isVideo,
|
|
47583
|
-
isDocument: state.isDocument,
|
|
47584
|
-
isAudio: state.isAudio
|
|
47585
|
-
};
|
|
47586
|
-
}
|
|
47587
|
-
/**
|
|
47588
|
-
* Database Row → API Response (for backend)
|
|
47589
|
-
*/
|
|
47590
|
-
toResponseDTO(row) {
|
|
47591
|
-
return {
|
|
47592
|
-
id: row.id,
|
|
47593
|
-
key: row.storage_path,
|
|
47594
|
-
filename: row.filename,
|
|
47595
|
-
mimeType: row.mime_type,
|
|
47596
|
-
size: toNumber(row.file_size),
|
|
47597
|
-
checksum: void 0,
|
|
47598
|
-
url: row.cdn_url ?? void 0,
|
|
47599
|
-
publicUrl: row.cdn_url ?? void 0,
|
|
47600
|
-
signedUrl: void 0,
|
|
47601
|
-
bucket: "media",
|
|
47602
|
-
entityType: row.entity_type ?? void 0,
|
|
47603
|
-
entityId: row.entity_id ?? void 0,
|
|
47604
|
-
category: void 0,
|
|
47605
|
-
uploadedAt: row.created_at,
|
|
47606
|
-
expiresAt: void 0
|
|
47607
|
-
};
|
|
47608
|
-
}
|
|
47609
|
-
/**
|
|
47610
|
-
* Create GeneratedFileItem from generation result
|
|
47611
|
-
*/
|
|
47612
|
-
toGeneratedFileItem(templateId, buffer, size, outputFormat = "pdf") {
|
|
47613
|
-
return {
|
|
47614
|
-
id: crypto.randomUUID(),
|
|
47615
|
-
templateId,
|
|
47616
|
-
buffer,
|
|
47617
|
-
size,
|
|
47618
|
-
mimeType: `application/${outputFormat}`,
|
|
47619
|
-
filename: `${templateId}.${outputFormat}`,
|
|
47620
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47621
|
-
};
|
|
47622
|
-
}
|
|
47623
|
-
/**
|
|
47624
|
-
* Convert upload result to database row format
|
|
47625
|
-
* Used by event handlers to persist upload results to DB
|
|
47626
|
-
*
|
|
47627
|
-
* @param uploadResult - Result from storage upload
|
|
47628
|
-
* @param userId - User ID who uploaded the file (from auth context)
|
|
47629
|
-
* @returns Partial database row ready for repository.create()
|
|
47630
|
-
*/
|
|
47631
|
-
// eslint-disable-next-line complexity
|
|
47632
|
-
toDbRow(uploadResult, userId) {
|
|
47633
|
-
const { metadata, variants } = uploadResult;
|
|
47634
|
-
return {
|
|
47635
|
-
id: metadata.fileId,
|
|
47636
|
-
user_id: userId ?? "system",
|
|
47637
|
-
type: _FilesMapperClass.inferFileType(metadata.mimeType),
|
|
47638
|
-
filename: metadata.filename,
|
|
47639
|
-
original_filename: metadata.filename,
|
|
47640
|
-
mime_type: metadata.mimeType,
|
|
47641
|
-
file_size: metadata.size,
|
|
47642
|
-
storage_path: metadata.path,
|
|
47643
|
-
cdn_url: metadata.url ?? null,
|
|
47644
|
-
width: metadata.extractedMetadata?.width ?? null,
|
|
47645
|
-
height: metadata.extractedMetadata?.height ?? null,
|
|
47646
|
-
duration: metadata.extractedMetadata?.duration ?? null,
|
|
47647
|
-
entity_type: metadata.entityType,
|
|
47648
|
-
entity_id: metadata.entityId,
|
|
47649
|
-
access_level: metadata.accessLevel,
|
|
47650
|
-
is_virus_scanned: false,
|
|
47651
|
-
virus_scan_result: null,
|
|
47652
|
-
metadata: metadata.customMetadata ?? null,
|
|
47653
|
-
variants: variants ?? null
|
|
47654
|
-
};
|
|
47566
|
+
__name(this, "NotificationService");
|
|
47655
47567
|
}
|
|
47656
|
-
};
|
|
47657
|
-
var FilesMapper = new FilesMapperClass();
|
|
47658
|
-
|
|
47659
|
-
// src/domain/files/validators/FilesValidator.ts
|
|
47660
|
-
var FilesValidatorClass = class extends BaseValidator {
|
|
47661
47568
|
static {
|
|
47662
|
-
|
|
47663
|
-
}
|
|
47664
|
-
constructor() {
|
|
47665
|
-
super({});
|
|
47569
|
+
this.instance = null;
|
|
47666
47570
|
}
|
|
47571
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47572
|
+
// Error Handling
|
|
47573
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47667
47574
|
/**
|
|
47668
|
-
*
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
47672
|
-
|
|
47673
|
-
|
|
47674
|
-
|
|
47675
|
-
|
|
47676
|
-
|
|
47677
|
-
|
|
47678
|
-
|
|
47679
|
-
|
|
47680
|
-
// src/domain/files/BackendFilesDomainService.ts
|
|
47681
|
-
var BackendFilesDomainService = class _BackendFilesDomainService extends BaseBackendDomainService {
|
|
47682
|
-
constructor(config = {}, injected) {
|
|
47683
|
-
super({
|
|
47684
|
-
serviceName: "BackendFilesDomainService",
|
|
47685
|
-
supportedRuntimes: ["backend"],
|
|
47686
|
-
serviceConfig: {
|
|
47687
|
-
enabled: true,
|
|
47688
|
-
throwOnValidationError: true,
|
|
47689
|
-
throwOnRepositoryError: true,
|
|
47690
|
-
emitEvents: true,
|
|
47691
|
-
...config
|
|
47692
|
-
},
|
|
47693
|
-
mapperClass: FilesMapperClass,
|
|
47694
|
-
validatorClass: FilesValidatorClass,
|
|
47695
|
-
injected
|
|
47696
|
-
});
|
|
47697
|
-
this.eventPrefix = "files";
|
|
47698
|
-
this.cachePrefix = "files";
|
|
47575
|
+
* Emits a notification error event via CoreEventManager.
|
|
47576
|
+
* Called when notification operations fail to integrate with global error handling.
|
|
47577
|
+
*/
|
|
47578
|
+
emitNotificationError(error, operation, options) {
|
|
47579
|
+
const payload = {
|
|
47580
|
+
error,
|
|
47581
|
+
operation,
|
|
47582
|
+
recipientId: options?.recipientId,
|
|
47583
|
+
channel: options?.channel,
|
|
47584
|
+
recoverable: options?.recoverable ?? false
|
|
47585
|
+
};
|
|
47586
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
|
|
47699
47587
|
}
|
|
47700
|
-
|
|
47701
|
-
|
|
47588
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47589
|
+
// Merged Event Handlers
|
|
47590
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47591
|
+
/**
|
|
47592
|
+
* Creates merged event handlers that emit to CoreEventManager.
|
|
47593
|
+
* Merges Core's internal handlers with user-provided handlers.
|
|
47594
|
+
*
|
|
47595
|
+
* @param userHandlers - User-provided event handlers from config
|
|
47596
|
+
* @returns Merged handlers with Core event emission + user handlers
|
|
47597
|
+
*/
|
|
47598
|
+
static createMergedEventHandlers(userHandlers) {
|
|
47599
|
+
return {
|
|
47600
|
+
...userHandlers,
|
|
47601
|
+
// Emit to CoreEventManager on sent, then call user handler
|
|
47602
|
+
onSent: /* @__PURE__ */ __name(async (payload) => {
|
|
47603
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.SENT, {
|
|
47604
|
+
notificationId: payload.notificationId,
|
|
47605
|
+
recipientId: payload.recipientId,
|
|
47606
|
+
channel: payload.channel,
|
|
47607
|
+
provider: payload.provider
|
|
47608
|
+
});
|
|
47609
|
+
if (userHandlers?.onSent) {
|
|
47610
|
+
await userHandlers.onSent(payload);
|
|
47611
|
+
}
|
|
47612
|
+
}, "onSent"),
|
|
47613
|
+
// Emit to CoreEventManager on failed, then call user handler
|
|
47614
|
+
onFailed: /* @__PURE__ */ __name(async (payload) => {
|
|
47615
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.FAILED, {
|
|
47616
|
+
notificationId: payload.notificationId,
|
|
47617
|
+
recipientId: payload.recipientId,
|
|
47618
|
+
channel: payload.channel,
|
|
47619
|
+
error: payload.error,
|
|
47620
|
+
retryable: payload.retryCount < MAX_FAIL_ATTEMPTS
|
|
47621
|
+
});
|
|
47622
|
+
if (userHandlers?.onFailed) {
|
|
47623
|
+
await userHandlers.onFailed(payload);
|
|
47624
|
+
}
|
|
47625
|
+
}, "onFailed"),
|
|
47626
|
+
// Emit to CoreEventManager on delivered, then call user handler
|
|
47627
|
+
onDelivered: /* @__PURE__ */ __name(async (payload) => {
|
|
47628
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.DELIVERED, {
|
|
47629
|
+
notificationId: payload.notificationId,
|
|
47630
|
+
recipientId: payload.recipientId,
|
|
47631
|
+
channel: payload.channel,
|
|
47632
|
+
deliveredAt: payload.deliveredAt
|
|
47633
|
+
});
|
|
47634
|
+
if (userHandlers?.onDelivered) {
|
|
47635
|
+
await userHandlers.onDelivered(payload);
|
|
47636
|
+
}
|
|
47637
|
+
}, "onDelivered")
|
|
47638
|
+
};
|
|
47702
47639
|
}
|
|
47703
|
-
|
|
47704
|
-
|
|
47640
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47641
|
+
// Singleton Management
|
|
47642
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47643
|
+
/**
|
|
47644
|
+
* Gets the singleton instance of NotificationService
|
|
47645
|
+
*/
|
|
47646
|
+
static getInstance() {
|
|
47647
|
+
_NotificationService.instance ??= new _NotificationService();
|
|
47648
|
+
return _NotificationService.instance;
|
|
47705
47649
|
}
|
|
47706
47650
|
/**
|
|
47707
|
-
*
|
|
47708
|
-
* Throws if DbService is not initialized.
|
|
47651
|
+
* Checks if the notification service has been initialized
|
|
47709
47652
|
*/
|
|
47710
|
-
|
|
47711
|
-
|
|
47712
|
-
return this._repository;
|
|
47653
|
+
static isInitialized() {
|
|
47654
|
+
return _NotificationService.instance?.initialized ?? false;
|
|
47713
47655
|
}
|
|
47714
47656
|
/**
|
|
47715
|
-
*
|
|
47657
|
+
* Resets the notification service by clearing the singleton instance
|
|
47716
47658
|
*/
|
|
47717
|
-
|
|
47718
|
-
|
|
47719
|
-
|
|
47720
|
-
|
|
47721
|
-
|
|
47722
|
-
|
|
47723
|
-
|
|
47724
|
-
storage: options?.storage?.instance,
|
|
47725
|
-
notifications: options?.notifications?.instance
|
|
47726
|
-
};
|
|
47727
|
-
return new _BackendFilesDomainService(config, injected);
|
|
47659
|
+
static async reset() {
|
|
47660
|
+
if (_NotificationService.instance) {
|
|
47661
|
+
_NotificationService.instance.notificationService = null;
|
|
47662
|
+
_NotificationService.instance.config = null;
|
|
47663
|
+
_NotificationService.instance.initialized = false;
|
|
47664
|
+
_NotificationService.instance = null;
|
|
47665
|
+
}
|
|
47728
47666
|
}
|
|
47729
47667
|
/**
|
|
47730
|
-
*
|
|
47731
|
-
* Called by CoreInitializer after storage and DB are initialized.
|
|
47732
|
-
*
|
|
47733
|
-
* Events handled:
|
|
47734
|
-
* - files:upload:uploaded - Persist single file to DB
|
|
47735
|
-
* - files:upload:bulk:uploaded - Persist multiple files to DB
|
|
47736
|
-
*
|
|
47737
|
-
* Deduplication: Uses unique constraint on storage_path.
|
|
47668
|
+
* Initializes the notification service
|
|
47738
47669
|
*
|
|
47739
|
-
* @param
|
|
47670
|
+
* @param config - Notification service configuration
|
|
47671
|
+
* @returns The initialized NotificationService instance
|
|
47740
47672
|
*/
|
|
47741
|
-
static
|
|
47742
|
-
|
|
47743
|
-
|
|
47673
|
+
static async initialize(config) {
|
|
47674
|
+
const instance = _NotificationService.getInstance();
|
|
47675
|
+
if (instance.initialized) {
|
|
47676
|
+
return instance;
|
|
47744
47677
|
}
|
|
47745
|
-
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
if (!isObject(payload)) return void 0;
|
|
47751
|
-
const p = payload;
|
|
47752
|
-
if (!FilesMapperClass.isUploadResult(p.result)) return void 0;
|
|
47753
|
-
return p.result;
|
|
47754
|
-
}, "extractPayload"),
|
|
47755
|
-
isBulk: false,
|
|
47756
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47757
|
-
},
|
|
47758
|
-
"files:upload:bulk:uploaded": {
|
|
47759
|
-
extractPayload: /* @__PURE__ */ __name((payload) => {
|
|
47760
|
-
if (!isObject(payload)) return [];
|
|
47761
|
-
const p = payload;
|
|
47762
|
-
const results = p.result?.results;
|
|
47763
|
-
if (!Array.isArray(results)) return [];
|
|
47764
|
-
return results.filter(FilesMapperClass.isUploadResult);
|
|
47765
|
-
}, "extractPayload"),
|
|
47766
|
-
isBulk: true,
|
|
47767
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47768
|
-
}
|
|
47769
|
-
},
|
|
47770
|
-
loadDependencies: /* @__PURE__ */ __name(async () => ({
|
|
47771
|
-
repository: FilesRepository.create(),
|
|
47772
|
-
mapper: FilesMapper
|
|
47773
|
-
}), "loadDependencies"),
|
|
47774
|
-
mapToDbRow: /* @__PURE__ */ __name((mapper, item) => mapper.toDbRow(item), "mapToDbRow"),
|
|
47775
|
-
createRecord: /* @__PURE__ */ __name(async (repository, dbRow) => {
|
|
47776
|
-
return repository.create(dbRow);
|
|
47777
|
-
}, "createRecord"),
|
|
47778
|
-
getUniqueKey: /* @__PURE__ */ __name((item) => item.metadata.path ?? item.metadata.fileId, "getUniqueKey"),
|
|
47779
|
-
verbose
|
|
47678
|
+
const mergedEvents = _NotificationService.createMergedEventHandlers(config.events);
|
|
47679
|
+
instance.config = config;
|
|
47680
|
+
instance.notificationService = new notifications.NotificationService({
|
|
47681
|
+
...config,
|
|
47682
|
+
events: mergedEvents
|
|
47780
47683
|
});
|
|
47684
|
+
instance.initialized = true;
|
|
47685
|
+
return instance;
|
|
47781
47686
|
}
|
|
47782
|
-
|
|
47783
|
-
|
|
47784
|
-
|
|
47785
|
-
|
|
47786
|
-
|
|
47687
|
+
/**
|
|
47688
|
+
* Gets the raw underlying notification service instance without error handling wrapper.
|
|
47689
|
+
* Use this only if you need direct access to the underlying service.
|
|
47690
|
+
*
|
|
47691
|
+
* @returns The raw NotificationService instance from @plyaz/notifications
|
|
47692
|
+
* @throws {NotificationsPackageError} When notifications is not initialized
|
|
47693
|
+
*/
|
|
47694
|
+
getRawNotifications() {
|
|
47695
|
+
if (!this.notificationService) {
|
|
47696
|
+
throw new errors.NotificationPackageError(
|
|
47697
|
+
"Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
|
|
47698
|
+
errors$1.NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
|
|
47699
|
+
);
|
|
47700
|
+
}
|
|
47701
|
+
return this.notificationService;
|
|
47787
47702
|
}
|
|
47788
|
-
//
|
|
47789
|
-
//
|
|
47790
|
-
//
|
|
47703
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47704
|
+
// Service Access
|
|
47705
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47791
47706
|
/**
|
|
47792
|
-
*
|
|
47793
|
-
*
|
|
47707
|
+
* Gets the notification service with automatic error handling.
|
|
47708
|
+
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
47709
|
+
* Any method added to @plyaz/notifications will be automatically available.
|
|
47794
47710
|
*
|
|
47795
|
-
*
|
|
47796
|
-
*
|
|
47797
|
-
*
|
|
47798
|
-
*
|
|
47799
|
-
*
|
|
47800
|
-
*
|
|
47801
|
-
* 6. Emit success event
|
|
47802
|
-
* 7. Record metrics
|
|
47711
|
+
* @example
|
|
47712
|
+
* ```typescript
|
|
47713
|
+
* const notifications = NotificationService.getInstance().getNotifications();
|
|
47714
|
+
* await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
|
|
47715
|
+
* await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
|
|
47716
|
+
* ```
|
|
47803
47717
|
*
|
|
47804
|
-
* @
|
|
47805
|
-
* @returns Download result with buffer, filename, mimeType
|
|
47718
|
+
* @returns NotificationServiceImpl with automatic error handling
|
|
47806
47719
|
*/
|
|
47807
|
-
|
|
47808
|
-
|
|
47809
|
-
|
|
47810
|
-
|
|
47811
|
-
|
|
47812
|
-
|
|
47813
|
-
|
|
47814
|
-
|
|
47815
|
-
|
|
47816
|
-
|
|
47817
|
-
|
|
47818
|
-
|
|
47720
|
+
getNotifications() {
|
|
47721
|
+
const self2 = this;
|
|
47722
|
+
return new Proxy({}, {
|
|
47723
|
+
get(_, prop) {
|
|
47724
|
+
if (typeof prop === "symbol") {
|
|
47725
|
+
return void 0;
|
|
47726
|
+
}
|
|
47727
|
+
const notifications = self2.getRawNotifications();
|
|
47728
|
+
const value = notifications[prop];
|
|
47729
|
+
if (typeof value !== "function") {
|
|
47730
|
+
return value;
|
|
47731
|
+
}
|
|
47732
|
+
return (...args) => {
|
|
47733
|
+
try {
|
|
47734
|
+
const result2 = value.apply(notifications, args);
|
|
47735
|
+
if (result2 instanceof Promise) {
|
|
47736
|
+
return result2.catch((error) => {
|
|
47737
|
+
self2.emitNotificationError(error, prop, { recoverable: true });
|
|
47738
|
+
throw error;
|
|
47739
|
+
});
|
|
47740
|
+
}
|
|
47741
|
+
return result2;
|
|
47742
|
+
} catch (error) {
|
|
47743
|
+
self2.emitNotificationError(error, prop, { recoverable: true });
|
|
47744
|
+
throw error;
|
|
47745
|
+
}
|
|
47746
|
+
};
|
|
47819
47747
|
}
|
|
47820
|
-
|
|
47821
|
-
|
|
47822
|
-
|
|
47823
|
-
|
|
47824
|
-
|
|
47825
|
-
|
|
47826
|
-
|
|
47827
|
-
|
|
47748
|
+
});
|
|
47749
|
+
}
|
|
47750
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47751
|
+
// Health Check (special handling for response transformation)
|
|
47752
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47753
|
+
/**
|
|
47754
|
+
* Performs a health check on the notification service.
|
|
47755
|
+
* This method has special handling to transform the response format.
|
|
47756
|
+
*/
|
|
47757
|
+
async healthCheck() {
|
|
47758
|
+
try {
|
|
47759
|
+
const notifications = this.getRawNotifications();
|
|
47760
|
+
const result2 = await notifications.healthCheck();
|
|
47761
|
+
return {
|
|
47762
|
+
isHealthy: result2.healthy,
|
|
47763
|
+
providers: result2.providers,
|
|
47764
|
+
// Use optional chaining since error may not exist on all health check results
|
|
47765
|
+
error: "error" in result2 ? result2.error : void 0
|
|
47828
47766
|
};
|
|
47829
|
-
await this.afterDownloadFile?.(response);
|
|
47830
|
-
this.emitEvent("download:downloaded", { result: response });
|
|
47831
|
-
this.emitEvent("complete", { success: true, operation: "downloadFile" });
|
|
47832
|
-
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, true);
|
|
47833
|
-
return response;
|
|
47834
47767
|
} catch (error) {
|
|
47835
|
-
|
|
47836
|
-
|
|
47837
|
-
|
|
47768
|
+
this.emitNotificationError(error, "healthCheck", { recoverable: true });
|
|
47769
|
+
return {
|
|
47770
|
+
isHealthy: false,
|
|
47771
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
47772
|
+
};
|
|
47838
47773
|
}
|
|
47839
47774
|
}
|
|
47775
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47776
|
+
// Lifecycle
|
|
47777
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47778
|
+
/**
|
|
47779
|
+
* Gets the current configuration
|
|
47780
|
+
*/
|
|
47781
|
+
getConfig() {
|
|
47782
|
+
return this.config;
|
|
47783
|
+
}
|
|
47840
47784
|
/**
|
|
47841
|
-
*
|
|
47842
|
-
|
|
47785
|
+
* Closes the notification service and cleans up resources
|
|
47786
|
+
*/
|
|
47787
|
+
async close() {
|
|
47788
|
+
this.notificationService = null;
|
|
47789
|
+
this.initialized = false;
|
|
47790
|
+
this.config = null;
|
|
47791
|
+
}
|
|
47792
|
+
/**
|
|
47793
|
+
* Creates a dedicated notification service instance (NOT the singleton)
|
|
47843
47794
|
*
|
|
47844
|
-
*
|
|
47795
|
+
* Use this when you need an isolated notification service with its own configuration.
|
|
47845
47796
|
*
|
|
47846
|
-
* @param
|
|
47847
|
-
* @returns
|
|
47797
|
+
* @param config - Notification service configuration
|
|
47798
|
+
* @returns Promise that resolves to a new dedicated NotificationService instance
|
|
47848
47799
|
*/
|
|
47849
|
-
|
|
47850
|
-
|
|
47851
|
-
|
|
47852
|
-
|
|
47853
|
-
|
|
47854
|
-
|
|
47800
|
+
static async createInstance(config) {
|
|
47801
|
+
const mergedEvents = _NotificationService.createMergedEventHandlers(config.events);
|
|
47802
|
+
const dedicatedInstance = new _NotificationService();
|
|
47803
|
+
dedicatedInstance.config = config;
|
|
47804
|
+
dedicatedInstance.notificationService = new notifications.NotificationService({
|
|
47805
|
+
...config,
|
|
47806
|
+
events: mergedEvents
|
|
47807
|
+
});
|
|
47808
|
+
dedicatedInstance.initialized = true;
|
|
47809
|
+
return dedicatedInstance;
|
|
47810
|
+
}
|
|
47811
|
+
};
|
|
47812
|
+
var cachedVersion = "";
|
|
47813
|
+
function getPackageVersion() {
|
|
47814
|
+
if (cachedVersion) return cachedVersion;
|
|
47815
|
+
try {
|
|
47816
|
+
const require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
47817
|
+
const pkg = require2("../package.json");
|
|
47818
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
47819
|
+
} catch {
|
|
47855
47820
|
try {
|
|
47856
|
-
|
|
47857
|
-
|
|
47858
|
-
|
|
47859
|
-
|
|
47860
|
-
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
const result2 = await storage.getSignedUrl({
|
|
47864
|
-
fileId: params.fileId,
|
|
47865
|
-
expiresIn: params.expiresIn ?? config.DOWNLOAD_CONFIG.DEFAULT_SIGNED_URL_EXPIRY_SECONDS,
|
|
47866
|
-
operation: "get"
|
|
47867
|
-
});
|
|
47868
|
-
const response = {
|
|
47869
|
-
url: result2?.url ?? "",
|
|
47870
|
-
expiresAt: result2?.expiresAt?.toISOString() ?? new Date(Date.now() + config.TIME_CONSTANTS.HOUR).toISOString()
|
|
47871
|
-
};
|
|
47872
|
-
await this.afterGetSignedUrl?.(response);
|
|
47873
|
-
this.emitEvent("signedUrl:received", { result: response });
|
|
47874
|
-
this.emitEvent("complete", { success: true, operation: "getSignedUrl" });
|
|
47875
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, true);
|
|
47876
|
-
return response;
|
|
47877
|
-
} catch (error) {
|
|
47878
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, false);
|
|
47879
|
-
this.emitEvent("signedUrl:error", { error });
|
|
47880
|
-
throw error;
|
|
47821
|
+
const currentFile = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
47822
|
+
const currentDir = path.dirname(currentFile);
|
|
47823
|
+
const pkgPath = path.join(currentDir, "..", "package.json");
|
|
47824
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
47825
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
47826
|
+
} catch {
|
|
47827
|
+
cachedVersion = "0.0.0";
|
|
47881
47828
|
}
|
|
47882
47829
|
}
|
|
47883
|
-
|
|
47884
|
-
|
|
47885
|
-
|
|
47886
|
-
|
|
47887
|
-
|
|
47888
|
-
|
|
47889
|
-
|
|
47890
|
-
|
|
47891
|
-
|
|
47892
|
-
|
|
47893
|
-
|
|
47894
|
-
|
|
47895
|
-
|
|
47896
|
-
|
|
47830
|
+
return cachedVersion;
|
|
47831
|
+
}
|
|
47832
|
+
__name(getPackageVersion, "getPackageVersion");
|
|
47833
|
+
var VERSION = getPackageVersion();
|
|
47834
|
+
var PACKAGE_NAME = "@plyaz/core";
|
|
47835
|
+
|
|
47836
|
+
// src/backend/index.ts
|
|
47837
|
+
var backend_exports = {};
|
|
47838
|
+
__export(backend_exports, {
|
|
47839
|
+
BACKEND_EXAMPLE_DOMAIN_SERVICE: () => BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47840
|
+
BACKEND_FILES_DOMAIN_SERVICE: () => BACKEND_FILES_DOMAIN_SERVICE,
|
|
47841
|
+
BackendExampleDomainService: () => BackendExampleDomainService,
|
|
47842
|
+
Caching: () => Caching,
|
|
47843
|
+
ErrorHandlingInterceptor: () => ErrorHandlingInterceptor,
|
|
47844
|
+
ExampleController: () => ExampleController,
|
|
47845
|
+
ExampleModule: () => ExampleModule,
|
|
47846
|
+
FeatureDisabled: () => FeatureDisabled,
|
|
47847
|
+
FeatureEnabled: () => FeatureEnabled,
|
|
47848
|
+
FeatureFlagConfigFactory: () => FeatureFlagConfigFactory,
|
|
47849
|
+
FeatureFlagConfigValidator: () => FeatureFlagConfigValidator,
|
|
47850
|
+
FeatureFlagController: () => FeatureFlagController,
|
|
47851
|
+
FeatureFlagDatabaseRepository: () => FeatureFlagDatabaseRepository,
|
|
47852
|
+
FeatureFlagDomainService: () => FeatureFlagDomainService,
|
|
47853
|
+
FeatureFlagGuard: () => FeatureFlagGuard,
|
|
47854
|
+
FeatureFlagLoggingInterceptor: () => FeatureFlagLoggingInterceptor,
|
|
47855
|
+
FeatureFlagMiddleware: () => FeatureFlagMiddleware,
|
|
47856
|
+
FeatureFlagModule: () => FeatureFlagModule,
|
|
47857
|
+
FeatureFlagService: () => FeatureFlagService,
|
|
47858
|
+
FeatureFlagServiceFactory: () => FeatureFlagServiceFactory,
|
|
47859
|
+
FilesController: () => FilesController,
|
|
47860
|
+
FilesModule: () => FilesModule
|
|
47861
|
+
});
|
|
47862
|
+
|
|
47863
|
+
// src/backend/example/example.module.ts
|
|
47864
|
+
var import_common14 = __toESM(require_common(), 1);
|
|
47865
|
+
|
|
47866
|
+
// src/backend/example/example.controller.ts
|
|
47867
|
+
var import_common13 = __toESM(require_common(), 1);
|
|
47868
|
+
var BACKEND_EXAMPLE_DOMAIN_SERVICE = "BACKEND_EXAMPLE_DOMAIN_SERVICE";
|
|
47869
|
+
var ExampleController = class {
|
|
47870
|
+
constructor(exampleService) {
|
|
47871
|
+
this.exampleService = exampleService;
|
|
47872
|
+
}
|
|
47873
|
+
health() {
|
|
47874
|
+
return errors.SuccessResponseStandard("Service is healthy", {
|
|
47875
|
+
service: this.exampleService.isAvailable(),
|
|
47876
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47877
|
+
});
|
|
47878
|
+
}
|
|
47879
|
+
async getEntity(id) {
|
|
47880
|
+
const entity = await this.exampleService.getById(id);
|
|
47881
|
+
return errors.SuccessResponseStandard("Entity retrieved successfully", entity);
|
|
47882
|
+
}
|
|
47883
|
+
async createEntity(dto) {
|
|
47884
|
+
const entity = await this.exampleService.create(dto);
|
|
47885
|
+
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47886
|
+
}
|
|
47887
|
+
async updateEntity(id, dto) {
|
|
47888
|
+
const entity = await this.exampleService.patch(id, dto);
|
|
47889
|
+
return errors.SuccessResponseStandard("Entity updated successfully", entity);
|
|
47890
|
+
}
|
|
47891
|
+
async deleteEntity(id) {
|
|
47892
|
+
await this.exampleService.delete(id);
|
|
47893
|
+
return errors.SuccessResponseStandard("Entity deleted successfully", null);
|
|
47894
|
+
}
|
|
47895
|
+
async createEntityWithValidation(dto) {
|
|
47896
|
+
const entity = await this.exampleService.create(dto);
|
|
47897
|
+
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47898
|
+
}
|
|
47899
|
+
async demoSingleError() {
|
|
47900
|
+
return await this.exampleService.demoSingleValidationError();
|
|
47901
|
+
}
|
|
47902
|
+
async demoArrayErrors() {
|
|
47903
|
+
return await this.exampleService.demoMultipleValidationErrors();
|
|
47904
|
+
}
|
|
47905
|
+
async sendEmail(dto) {
|
|
47906
|
+
const result2 = await this.exampleService.sendEmail(dto);
|
|
47907
|
+
return errors.SuccessResponseStandard("Email sent successfully", result2);
|
|
47908
|
+
}
|
|
47897
47909
|
};
|
|
47898
|
-
|
|
47899
|
-
|
|
47910
|
+
__name(ExampleController, "ExampleController");
|
|
47911
|
+
__decorateClass([
|
|
47912
|
+
(0, import_common13.Get)("health")
|
|
47913
|
+
], ExampleController.prototype, "health", 1);
|
|
47914
|
+
__decorateClass([
|
|
47915
|
+
(0, import_common13.Get)("entities/:id"),
|
|
47916
|
+
__decorateParam(0, (0, import_common13.Param)("id"))
|
|
47917
|
+
], ExampleController.prototype, "getEntity", 1);
|
|
47918
|
+
__decorateClass([
|
|
47919
|
+
(0, import_common13.Post)("entities"),
|
|
47920
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.CREATED),
|
|
47921
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47922
|
+
], ExampleController.prototype, "createEntity", 1);
|
|
47923
|
+
__decorateClass([
|
|
47924
|
+
(0, import_common13.Patch)("entities/:id"),
|
|
47925
|
+
__decorateParam(0, (0, import_common13.Param)("id")),
|
|
47926
|
+
__decorateParam(1, (0, import_common13.Body)())
|
|
47927
|
+
], ExampleController.prototype, "updateEntity", 1);
|
|
47928
|
+
__decorateClass([
|
|
47929
|
+
(0, import_common13.Delete)("entities/:id"),
|
|
47930
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.OK),
|
|
47931
|
+
__decorateParam(0, (0, import_common13.Param)("id"))
|
|
47932
|
+
], ExampleController.prototype, "deleteEntity", 1);
|
|
47933
|
+
__decorateClass([
|
|
47934
|
+
(0, import_common13.Post)("entities/validated"),
|
|
47935
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.CREATED),
|
|
47936
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47937
|
+
], ExampleController.prototype, "createEntityWithValidation", 1);
|
|
47938
|
+
__decorateClass([
|
|
47939
|
+
(0, import_common13.Get)("errors/single")
|
|
47940
|
+
], ExampleController.prototype, "demoSingleError", 1);
|
|
47941
|
+
__decorateClass([
|
|
47942
|
+
(0, import_common13.Get)("errors/array")
|
|
47943
|
+
], ExampleController.prototype, "demoArrayErrors", 1);
|
|
47944
|
+
__decorateClass([
|
|
47945
|
+
(0, import_common13.Post)("email"),
|
|
47946
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.OK),
|
|
47947
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47948
|
+
], ExampleController.prototype, "sendEmail", 1);
|
|
47949
|
+
ExampleController = __decorateClass([
|
|
47950
|
+
(0, import_common13.Controller)("example"),
|
|
47951
|
+
__decorateParam(0, (0, import_common13.Inject)(BACKEND_EXAMPLE_DOMAIN_SERVICE))
|
|
47952
|
+
], ExampleController);
|
|
47953
|
+
|
|
47954
|
+
// src/backend/example/example.module.ts
|
|
47955
|
+
var ExampleModule = class {
|
|
47956
|
+
};
|
|
47957
|
+
__name(ExampleModule, "ExampleModule");
|
|
47958
|
+
ExampleModule = __decorateClass([
|
|
47959
|
+
(0, import_common14.Module)({
|
|
47960
|
+
controllers: [ExampleController],
|
|
47961
|
+
providers: [
|
|
47962
|
+
// Provide BackendExampleDomainService via factory using the singleton instance
|
|
47963
|
+
// This ensures the service is shared across the application
|
|
47964
|
+
{
|
|
47965
|
+
provide: BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47966
|
+
useFactory: /* @__PURE__ */ __name(() => backendExampleDomainService, "useFactory")
|
|
47967
|
+
}
|
|
47968
|
+
],
|
|
47969
|
+
exports: [BACKEND_EXAMPLE_DOMAIN_SERVICE]
|
|
47970
|
+
})
|
|
47971
|
+
], ExampleModule);
|
|
47972
|
+
|
|
47973
|
+
// src/backend/files/files.module.ts
|
|
47974
|
+
var import_common16 = __toESM(require_common(), 1);
|
|
47975
|
+
|
|
47976
|
+
// src/backend/files/files.controller.ts
|
|
47977
|
+
var import_common15 = __toESM(require_common(), 1);
|
|
47978
|
+
var BACKEND_FILES_DOMAIN_SERVICE = "BACKEND_FILES_DOMAIN_SERVICE";
|
|
47979
|
+
var FilesController = class {
|
|
47980
|
+
constructor(filesService) {
|
|
47981
|
+
this.filesService = filesService;
|
|
47982
|
+
}
|
|
47983
|
+
health() {
|
|
47984
|
+
return errors.SuccessResponseStandard("Files service is healthy", {
|
|
47985
|
+
service: this.filesService.isAvailable(),
|
|
47986
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47987
|
+
});
|
|
47988
|
+
}
|
|
47989
|
+
async uploadFile(dto) {
|
|
47990
|
+
const result2 = await this.filesService.uploadFile(dto);
|
|
47991
|
+
return errors.SuccessResponseStandard("File uploaded successfully", result2);
|
|
47992
|
+
}
|
|
47993
|
+
async uploadFiles(dto) {
|
|
47994
|
+
const results = await this.filesService.uploadFiles(dto.files);
|
|
47995
|
+
return errors.SuccessResponseStandard("Files uploaded successfully", results);
|
|
47996
|
+
}
|
|
47997
|
+
async generateDocument(dto) {
|
|
47998
|
+
const buffer = await this.filesService.generateFile(dto);
|
|
47999
|
+
return errors.SuccessResponseStandard("Document generated successfully", {
|
|
48000
|
+
buffer: buffer.toString("base64"),
|
|
48001
|
+
size: buffer.length
|
|
48002
|
+
});
|
|
48003
|
+
}
|
|
48004
|
+
async getFile(id) {
|
|
48005
|
+
const entity = await this.filesService.getById(id);
|
|
48006
|
+
return errors.SuccessResponseStandard("File retrieved", entity);
|
|
48007
|
+
}
|
|
48008
|
+
async downloadFile(id) {
|
|
48009
|
+
const result2 = await this.filesService.downloadFile({ fileId: id });
|
|
48010
|
+
return errors.SuccessResponseStandard("File downloaded", result2);
|
|
48011
|
+
}
|
|
48012
|
+
async getSignedUrl(id) {
|
|
48013
|
+
const result2 = await this.filesService.getSignedUrl({ fileId: id });
|
|
48014
|
+
return errors.SuccessResponseStandard("Signed URL generated", result2);
|
|
48015
|
+
}
|
|
48016
|
+
async deleteFile(id) {
|
|
48017
|
+
await this.filesService.delete(id);
|
|
48018
|
+
return errors.SuccessResponseStandard("File deleted", null);
|
|
48019
|
+
}
|
|
48020
|
+
};
|
|
48021
|
+
__name(FilesController, "FilesController");
|
|
48022
|
+
__decorateClass([
|
|
48023
|
+
(0, import_common15.Get)("health")
|
|
48024
|
+
], FilesController.prototype, "health", 1);
|
|
48025
|
+
__decorateClass([
|
|
48026
|
+
(0, import_common15.Post)("upload"),
|
|
48027
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48028
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48029
|
+
], FilesController.prototype, "uploadFile", 1);
|
|
48030
|
+
__decorateClass([
|
|
48031
|
+
(0, import_common15.Post)("upload/bulk"),
|
|
48032
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48033
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48034
|
+
], FilesController.prototype, "uploadFiles", 1);
|
|
48035
|
+
__decorateClass([
|
|
48036
|
+
(0, import_common15.Post)("generate-document"),
|
|
48037
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48038
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48039
|
+
], FilesController.prototype, "generateDocument", 1);
|
|
48040
|
+
__decorateClass([
|
|
48041
|
+
(0, import_common15.Get)(":id"),
|
|
48042
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48043
|
+
], FilesController.prototype, "getFile", 1);
|
|
48044
|
+
__decorateClass([
|
|
48045
|
+
(0, import_common15.Get)(":id/download"),
|
|
48046
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48047
|
+
], FilesController.prototype, "downloadFile", 1);
|
|
48048
|
+
__decorateClass([
|
|
48049
|
+
(0, import_common15.Get)(":id/signed-url"),
|
|
48050
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48051
|
+
], FilesController.prototype, "getSignedUrl", 1);
|
|
48052
|
+
__decorateClass([
|
|
48053
|
+
(0, import_common15.Delete)(":id"),
|
|
48054
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48055
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48056
|
+
], FilesController.prototype, "deleteFile", 1);
|
|
48057
|
+
FilesController = __decorateClass([
|
|
48058
|
+
(0, import_common15.Controller)("files"),
|
|
48059
|
+
__decorateParam(0, (0, import_common15.Inject)(BACKEND_FILES_DOMAIN_SERVICE))
|
|
48060
|
+
], FilesController);
|
|
48061
|
+
var logger6 = new logger$1.PackageLogger({ packageName: "core", service: "FrontendFilesDomainService" });
|
|
47900
48062
|
var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseFrontendDomainService {
|
|
47901
48063
|
constructor(config = {}, options) {
|
|
47902
|
-
const apiBasePath = config.apiBasePath || "
|
|
48064
|
+
const apiBasePath = config.apiBasePath || "";
|
|
47903
48065
|
super({
|
|
47904
48066
|
serviceName: "FrontendFilesDomainService",
|
|
47905
48067
|
supportedRuntimes: ["frontend"],
|
|
@@ -47962,7 +48124,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47962
48124
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
47963
48125
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
47964
48126
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
47965
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
48127
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
47966
48128
|
};
|
|
47967
48129
|
return new _FrontendFilesDomainService(mergedConfig, options);
|
|
47968
48130
|
}
|
|
@@ -47999,7 +48161,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47999
48161
|
*/
|
|
48000
48162
|
static registerEventHandlers(verbose) {
|
|
48001
48163
|
if (this._eventHandlersRegistered) {
|
|
48002
|
-
|
|
48164
|
+
logger6.debug("Files frontend event handlers already registered");
|
|
48003
48165
|
return () => {
|
|
48004
48166
|
};
|
|
48005
48167
|
}
|
|
@@ -48061,7 +48223,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
48061
48223
|
verbose
|
|
48062
48224
|
});
|
|
48063
48225
|
this._eventHandlersRegistered = true;
|
|
48064
|
-
|
|
48226
|
+
logger6.info("Files frontend event handlers registered");
|
|
48065
48227
|
return () => {
|
|
48066
48228
|
FrontendEventPersistenceHandler.unregisterAll();
|
|
48067
48229
|
this._eventHandlersRegistered = false;
|
|
@@ -48139,7 +48301,7 @@ var FilesModule = class {
|
|
|
48139
48301
|
};
|
|
48140
48302
|
__name(FilesModule, "FilesModule");
|
|
48141
48303
|
FilesModule = __decorateClass([
|
|
48142
|
-
(0,
|
|
48304
|
+
(0, import_common16.Module)({
|
|
48143
48305
|
controllers: [FilesController],
|
|
48144
48306
|
providers: [
|
|
48145
48307
|
// Provide BackendFilesDomainService via factory using the singleton instance
|
|
@@ -48430,10 +48592,10 @@ var FeatureFlagDomainService = class extends BaseDomainService {
|
|
|
48430
48592
|
};
|
|
48431
48593
|
|
|
48432
48594
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
48433
|
-
var
|
|
48595
|
+
var import_common18 = __toESM(require_common(), 1);
|
|
48434
48596
|
|
|
48435
48597
|
// src/backend/featureFlags/feature-flag.controller.ts
|
|
48436
|
-
var
|
|
48598
|
+
var import_common17 = __toESM(require_common(), 1);
|
|
48437
48599
|
var FeatureFlagController = class {
|
|
48438
48600
|
constructor(featureFlagService) {
|
|
48439
48601
|
this.featureFlagService = featureFlagService;
|
|
@@ -48562,54 +48724,54 @@ var FeatureFlagController = class {
|
|
|
48562
48724
|
};
|
|
48563
48725
|
__name(FeatureFlagController, "FeatureFlagController");
|
|
48564
48726
|
__decorateClass([
|
|
48565
|
-
(0,
|
|
48566
|
-
__decorateParam(0, (0,
|
|
48567
|
-
__decorateParam(1, (0,
|
|
48727
|
+
(0, import_common17.Post)(":key/evaluate"),
|
|
48728
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48729
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48568
48730
|
], FeatureFlagController.prototype, "evaluateFlag", 1);
|
|
48569
48731
|
__decorateClass([
|
|
48570
|
-
(0,
|
|
48571
|
-
__decorateParam(0, (0,
|
|
48572
|
-
__decorateParam(1, (0,
|
|
48732
|
+
(0, import_common17.Post)(":key/enabled"),
|
|
48733
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48734
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48573
48735
|
], FeatureFlagController.prototype, "isEnabled", 1);
|
|
48574
48736
|
__decorateClass([
|
|
48575
|
-
(0,
|
|
48576
|
-
__decorateParam(0, (0,
|
|
48737
|
+
(0, import_common17.Post)("evaluate-all"),
|
|
48738
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48577
48739
|
], FeatureFlagController.prototype, "evaluateAllFlags", 1);
|
|
48578
48740
|
__decorateClass([
|
|
48579
|
-
(0,
|
|
48580
|
-
__decorateParam(0, (0,
|
|
48741
|
+
(0, import_common17.Post)(),
|
|
48742
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48581
48743
|
], FeatureFlagController.prototype, "createFlag", 1);
|
|
48582
48744
|
__decorateClass([
|
|
48583
|
-
(0,
|
|
48584
|
-
__decorateParam(0, (0,
|
|
48585
|
-
__decorateParam(1, (0,
|
|
48745
|
+
(0, import_common17.Put)(":key"),
|
|
48746
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48747
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48586
48748
|
], FeatureFlagController.prototype, "updateFlag", 1);
|
|
48587
48749
|
__decorateClass([
|
|
48588
|
-
(0,
|
|
48589
|
-
__decorateParam(0, (0,
|
|
48750
|
+
(0, import_common17.Delete)(":key"),
|
|
48751
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48590
48752
|
], FeatureFlagController.prototype, "deleteFlag", 1);
|
|
48591
48753
|
__decorateClass([
|
|
48592
|
-
(0,
|
|
48593
|
-
__decorateParam(0, (0,
|
|
48594
|
-
__decorateParam(1, (0,
|
|
48754
|
+
(0, import_common17.Post)(":key/override"),
|
|
48755
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48756
|
+
__decorateParam(1, (0, import_common17.Body)("value"))
|
|
48595
48757
|
], FeatureFlagController.prototype, "setOverride", 1);
|
|
48596
48758
|
__decorateClass([
|
|
48597
|
-
(0,
|
|
48598
|
-
__decorateParam(0, (0,
|
|
48759
|
+
(0, import_common17.Delete)(":key/override"),
|
|
48760
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48599
48761
|
], FeatureFlagController.prototype, "removeOverride", 1);
|
|
48600
48762
|
__decorateClass([
|
|
48601
|
-
(0,
|
|
48602
|
-
__decorateParam(0, (0,
|
|
48763
|
+
(0, import_common17.Get)(":key/rules"),
|
|
48764
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48603
48765
|
], FeatureFlagController.prototype, "getFlagRules", 1);
|
|
48604
48766
|
__decorateClass([
|
|
48605
|
-
(0,
|
|
48767
|
+
(0, import_common17.Post)("refresh")
|
|
48606
48768
|
], FeatureFlagController.prototype, "refreshCache", 1);
|
|
48607
48769
|
__decorateClass([
|
|
48608
|
-
(0,
|
|
48770
|
+
(0, import_common17.Get)("health")
|
|
48609
48771
|
], FeatureFlagController.prototype, "getHealth", 1);
|
|
48610
48772
|
FeatureFlagController = __decorateClass([
|
|
48611
|
-
(0,
|
|
48612
|
-
__decorateParam(0, (0,
|
|
48773
|
+
(0, import_common17.Controller)("feature-flags"),
|
|
48774
|
+
__decorateParam(0, (0, import_common17.Inject)(FEATURE_FLAG_SERVICE))
|
|
48613
48775
|
], FeatureFlagController);
|
|
48614
48776
|
|
|
48615
48777
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
@@ -48701,16 +48863,16 @@ var FeatureFlagModule = class {
|
|
|
48701
48863
|
__name(FeatureFlagModule, "FeatureFlagModule");
|
|
48702
48864
|
FeatureFlagModule.serviceInstance = null;
|
|
48703
48865
|
FeatureFlagModule = __decorateClass([
|
|
48704
|
-
(0,
|
|
48705
|
-
(0,
|
|
48866
|
+
(0, import_common18.Global)(),
|
|
48867
|
+
(0, import_common18.Module)({
|
|
48706
48868
|
controllers: [FeatureFlagController]
|
|
48707
48869
|
})
|
|
48708
48870
|
], FeatureFlagModule);
|
|
48709
48871
|
|
|
48710
48872
|
// src/backend/featureFlags/decorators/feature-flag.decorator.ts
|
|
48711
|
-
var
|
|
48873
|
+
var import_common19 = __toESM(require_common(), 1);
|
|
48712
48874
|
function FeatureFlag(key, expected = true) {
|
|
48713
|
-
return (0,
|
|
48875
|
+
return (0, import_common19.SetMetadata)(types.FEATURE_FLAG_METADATA.FLAG_CHECK, { key, expected });
|
|
48714
48876
|
}
|
|
48715
48877
|
__name(FeatureFlag, "FeatureFlag");
|
|
48716
48878
|
|
|
@@ -48727,7 +48889,7 @@ function FeatureEnabled(key) {
|
|
|
48727
48889
|
__name(FeatureEnabled, "FeatureEnabled");
|
|
48728
48890
|
|
|
48729
48891
|
// src/backend/featureFlags/guards/feature-flag.guard.ts
|
|
48730
|
-
var
|
|
48892
|
+
var import_common20 = __toESM(require_common(), 1);
|
|
48731
48893
|
var FeatureFlagGuard = class {
|
|
48732
48894
|
constructor(reflector, featureFlagService) {
|
|
48733
48895
|
this.reflector = reflector;
|
|
@@ -48771,12 +48933,12 @@ var FeatureFlagGuard = class {
|
|
|
48771
48933
|
};
|
|
48772
48934
|
__name(FeatureFlagGuard, "FeatureFlagGuard");
|
|
48773
48935
|
FeatureFlagGuard = __decorateClass([
|
|
48774
|
-
(0,
|
|
48775
|
-
__decorateParam(1, (0,
|
|
48936
|
+
(0, import_common20.Injectable)(),
|
|
48937
|
+
__decorateParam(1, (0, import_common20.Inject)(FEATURE_FLAG_SERVICE))
|
|
48776
48938
|
], FeatureFlagGuard);
|
|
48777
48939
|
|
|
48778
48940
|
// src/backend/featureFlags/middleware/feature-flag-middleware.ts
|
|
48779
|
-
var
|
|
48941
|
+
var import_common21 = __toESM(require_common(), 1);
|
|
48780
48942
|
function isFeatureFlagKey(value) {
|
|
48781
48943
|
return Object.keys(config.FEATURES).includes(value);
|
|
48782
48944
|
}
|
|
@@ -48854,12 +49016,12 @@ var FeatureFlagMiddleware = class {
|
|
|
48854
49016
|
};
|
|
48855
49017
|
__name(FeatureFlagMiddleware, "FeatureFlagMiddleware");
|
|
48856
49018
|
FeatureFlagMiddleware = __decorateClass([
|
|
48857
|
-
(0,
|
|
48858
|
-
__decorateParam(0, (0,
|
|
49019
|
+
(0, import_common21.Injectable)(),
|
|
49020
|
+
__decorateParam(0, (0, import_common21.Inject)(FEATURE_FLAG_SERVICE))
|
|
48859
49021
|
], FeatureFlagMiddleware);
|
|
48860
49022
|
|
|
48861
49023
|
// src/backend/featureFlags/interceptors/feature-flag-logging-interceptor.ts
|
|
48862
|
-
var
|
|
49024
|
+
var import_common22 = __toESM(require_common(), 1);
|
|
48863
49025
|
var import_rxjs = __toESM(require_cjs(), 1);
|
|
48864
49026
|
var FeatureFlagLoggingInterceptor = class {
|
|
48865
49027
|
constructor() {
|
|
@@ -48892,11 +49054,11 @@ var FeatureFlagLoggingInterceptor = class {
|
|
|
48892
49054
|
};
|
|
48893
49055
|
__name(FeatureFlagLoggingInterceptor, "FeatureFlagLoggingInterceptor");
|
|
48894
49056
|
FeatureFlagLoggingInterceptor = __decorateClass([
|
|
48895
|
-
(0,
|
|
49057
|
+
(0, import_common22.Injectable)()
|
|
48896
49058
|
], FeatureFlagLoggingInterceptor);
|
|
48897
49059
|
|
|
48898
49060
|
// src/backend/featureFlags/interceptors/error-handling-interceptor.ts
|
|
48899
|
-
var
|
|
49061
|
+
var import_common23 = __toESM(require_common(), 1);
|
|
48900
49062
|
var import_operators = __toESM(require_operators(), 1);
|
|
48901
49063
|
var ErrorHandlingInterceptor = class {
|
|
48902
49064
|
constructor() {
|
|
@@ -48925,9 +49087,9 @@ var ErrorHandlingInterceptor = class {
|
|
|
48925
49087
|
};
|
|
48926
49088
|
__name(ErrorHandlingInterceptor, "ErrorHandlingInterceptor");
|
|
48927
49089
|
ErrorHandlingInterceptor = __decorateClass([
|
|
48928
|
-
(0,
|
|
49090
|
+
(0, import_common23.Injectable)()
|
|
48929
49091
|
], ErrorHandlingInterceptor);
|
|
48930
|
-
var
|
|
49092
|
+
var logger7 = new logger$1.PackageLogger({
|
|
48931
49093
|
packageName: "core",
|
|
48932
49094
|
service: "FeatureFlagConfigValidator"
|
|
48933
49095
|
});
|
|
@@ -49113,7 +49275,7 @@ var FeatureFlagConfigValidator = class {
|
|
|
49113
49275
|
static getWarnings(config$1, environment) {
|
|
49114
49276
|
const env = environment ?? (config$1.isLoggingEnabled ? types.NODE_ENVIRONMENTS.DEVELOPMENT : types.NODE_ENVIRONMENTS.PRODUCTION);
|
|
49115
49277
|
if (config$1.cacheTtl > config.NUMERIC_CONSTANTS.ONE_HOUR_SECONDS) {
|
|
49116
|
-
|
|
49278
|
+
logger7.warn(
|
|
49117
49279
|
"Cache TTL is very high (>1 hour). Consider reducing for better responsiveness.",
|
|
49118
49280
|
{
|
|
49119
49281
|
field: "cacheTtl",
|
|
@@ -49123,13 +49285,13 @@ var FeatureFlagConfigValidator = class {
|
|
|
49123
49285
|
);
|
|
49124
49286
|
}
|
|
49125
49287
|
if (env === types.NODE_ENVIRONMENTS.PRODUCTION && config$1.isLoggingEnabled) {
|
|
49126
|
-
|
|
49288
|
+
logger7.warn("Logging is enabled in production. Consider disabling for performance.", {
|
|
49127
49289
|
field: "isLoggingEnabled",
|
|
49128
49290
|
code: "PRODUCTION_LOGGING_ENABLED"
|
|
49129
49291
|
});
|
|
49130
49292
|
}
|
|
49131
49293
|
if (env === types.NODE_ENVIRONMENTS.DEVELOPMENT && !config$1.isCacheEnabled) {
|
|
49132
|
-
|
|
49294
|
+
logger7.warn("Cache is disabled in development. This may impact performance testing.", {
|
|
49133
49295
|
field: "isCacheEnabled",
|
|
49134
49296
|
code: "DEVELOPMENT_CACHE_DISABLED"
|
|
49135
49297
|
});
|
|
@@ -49272,7 +49434,7 @@ var FeatureFlagConfigFactory = class {
|
|
|
49272
49434
|
};
|
|
49273
49435
|
|
|
49274
49436
|
// src/base/cache/feature/caching.ts
|
|
49275
|
-
var
|
|
49437
|
+
var import_common24 = __toESM(require_common(), 1);
|
|
49276
49438
|
var import_rxjs2 = __toESM(require_cjs(), 1);
|
|
49277
49439
|
var Caching = class {
|
|
49278
49440
|
constructor() {
|
|
@@ -49295,7 +49457,7 @@ var Caching = class {
|
|
|
49295
49457
|
};
|
|
49296
49458
|
__name(Caching, "Caching");
|
|
49297
49459
|
Caching = __decorateClass([
|
|
49298
|
-
(0,
|
|
49460
|
+
(0, import_common24.Injectable)()
|
|
49299
49461
|
], Caching);
|
|
49300
49462
|
|
|
49301
49463
|
// src/frontend/index.ts
|
|
@@ -49422,7 +49584,7 @@ function ApiProvider({
|
|
|
49422
49584
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
49423
49585
|
}
|
|
49424
49586
|
__name(ApiProvider, "ApiProvider");
|
|
49425
|
-
var
|
|
49587
|
+
var logger8 = new logger$1.PackageLogger({ packageName: "core", service: "PlyazProvider" });
|
|
49426
49588
|
var PlyazContext = react.createContext(null);
|
|
49427
49589
|
var FeatureFlagStore = class {
|
|
49428
49590
|
constructor(config = {}) {
|
|
@@ -49517,7 +49679,7 @@ function createStoreRegistry() {
|
|
|
49517
49679
|
getStore(key) {
|
|
49518
49680
|
const state = store.useRootStore.getState();
|
|
49519
49681
|
if (!state) {
|
|
49520
|
-
|
|
49682
|
+
logger8.warn(
|
|
49521
49683
|
"Store state is undefined - store may not be hydrated yet. This can cause side effects if called during SSR or before initialization."
|
|
49522
49684
|
);
|
|
49523
49685
|
return void 0;
|