@plyaz/core 1.10.0 → 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 +348 -189
- package/dist/entry-backend.js.map +1 -1
- package/dist/entry-backend.mjs +245 -86
- package/dist/entry-backend.mjs.map +1 -1
- package/dist/entry-frontend-browser.js +75 -17
- package/dist/entry-frontend-browser.js.map +1 -1
- package/dist/entry-frontend-browser.mjs +75 -17
- package/dist/entry-frontend-browser.mjs.map +1 -1
- package/dist/entry-frontend.js +75 -17
- package/dist/entry-frontend.js.map +1 -1
- package/dist/entry-frontend.mjs +75 -17
- package/dist/entry-frontend.mjs.map +1 -1
- package/dist/frontend/providers/PlyazProvider.d.ts.map +1 -1
- package/dist/index.js +1284 -1114
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1236 -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 +105 -12
- package/dist/init/nestjs/index.js.map +1 -1
- package/dist/init/nestjs/index.mjs +105 -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,
|
|
@@ -35703,6 +35703,11 @@ var Core = class _Core {
|
|
|
35703
35703
|
environment: globalEnvironment,
|
|
35704
35704
|
runtime,
|
|
35705
35705
|
apiClient: apiConfig ? { baseURL: apiConfig.baseURL, ...apiConfig } : void 0,
|
|
35706
|
+
db: options.db,
|
|
35707
|
+
cache: options.cache,
|
|
35708
|
+
storage: options.storage,
|
|
35709
|
+
notifications: options.notifications,
|
|
35710
|
+
observability: options.observability,
|
|
35706
35711
|
services: mergedServices,
|
|
35707
35712
|
stores: {
|
|
35708
35713
|
// Returns specific slice from namespaced root store (type-safe)
|
|
@@ -36512,26 +36517,76 @@ var Core = class _Core {
|
|
|
36512
36517
|
errorStore,
|
|
36513
36518
|
_Core.buildErrorHandlerConfig(_Core._errorConfig)
|
|
36514
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);
|
|
36515
36552
|
const errorEventCleanup = CoreEventManager.on(
|
|
36516
36553
|
core.CORE_EVENTS.SYSTEM.ERROR,
|
|
36517
36554
|
(event) => {
|
|
36518
36555
|
if (!_Core._rootStore) return;
|
|
36519
36556
|
try {
|
|
36520
36557
|
const { errors } = event.data;
|
|
36521
|
-
if (errors
|
|
36522
|
-
|
|
36523
|
-
|
|
36524
|
-
}
|
|
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);
|
|
36525
36562
|
} catch (e) {
|
|
36526
36563
|
_Core.logger.error("Failed to handle error event", { error: e });
|
|
36527
36564
|
}
|
|
36528
36565
|
}
|
|
36529
36566
|
);
|
|
36530
36567
|
_Core._eventCleanupFns.push(errorEventCleanup);
|
|
36531
|
-
|
|
36532
|
-
|
|
36533
|
-
|
|
36534
|
-
|
|
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);
|
|
36535
36590
|
}
|
|
36536
36591
|
/**
|
|
36537
36592
|
* Create HTTP error handler based on detected runtime.
|
|
@@ -38485,7 +38540,7 @@ var BaseFrontendDomainService = class _BaseFrontendDomainService extends BaseDom
|
|
|
38485
38540
|
}
|
|
38486
38541
|
};
|
|
38487
38542
|
var logger2 = new logger$1.PackageLogger({ packageName: "core", service: "EventPersistence" });
|
|
38488
|
-
|
|
38543
|
+
(class {
|
|
38489
38544
|
static {
|
|
38490
38545
|
__name(this, "BackendEventPersistenceHandler");
|
|
38491
38546
|
}
|
|
@@ -38659,7 +38714,7 @@ var BackendEventPersistenceHandler = class {
|
|
|
38659
38714
|
static getRegisteredDomains() {
|
|
38660
38715
|
return Array.from(this.registeredDomains.keys());
|
|
38661
38716
|
}
|
|
38662
|
-
};
|
|
38717
|
+
});
|
|
38663
38718
|
var logger3 = new logger$1.PackageLogger({ packageName: "core", service: "FrontendEventPersistence" });
|
|
38664
38719
|
var FrontendEventPersistenceHandler = class {
|
|
38665
38720
|
static {
|
|
@@ -43336,6 +43391,7 @@ var ApiFeatureFlagProvider = class extends FeatureFlagProvider {
|
|
|
43336
43391
|
return this.engine.getRules();
|
|
43337
43392
|
}
|
|
43338
43393
|
};
|
|
43394
|
+
var logger4 = new logger$1.PackageLogger({ packageName: "core", service: "DbService" });
|
|
43339
43395
|
var DEFAULT_ENCRYPTION_FIELDS = {
|
|
43340
43396
|
// User PII
|
|
43341
43397
|
users: ["password_hash", "phone_number", "date_of_birth"],
|
|
@@ -43429,6 +43485,41 @@ var DbService = class _DbService {
|
|
|
43429
43485
|
};
|
|
43430
43486
|
CoreEventManager.emit(core.CORE_EVENTS.DATABASE.ERROR, payload);
|
|
43431
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
|
+
}
|
|
43432
43523
|
/**
|
|
43433
43524
|
* Gets the singleton instance of DbService
|
|
43434
43525
|
*
|
|
@@ -43633,6 +43724,8 @@ var DbService = class _DbService {
|
|
|
43633
43724
|
if (cache) dbConfig.cache = cache;
|
|
43634
43725
|
if (audit) dbConfig.audit = audit;
|
|
43635
43726
|
if (encryption) dbConfig.encryption = encryption;
|
|
43727
|
+
const events = _DbService.createMergedEventHandlers(config.events);
|
|
43728
|
+
if (events) dbConfig.events = events;
|
|
43636
43729
|
return dbConfig;
|
|
43637
43730
|
}
|
|
43638
43731
|
/**
|
|
@@ -46198,7 +46291,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46198
46291
|
// Constructor
|
|
46199
46292
|
// ─────────────────────────────────────────────────────────────────────────
|
|
46200
46293
|
constructor(config = {}, options) {
|
|
46201
|
-
const apiBasePath = config.apiBasePath || "
|
|
46294
|
+
const apiBasePath = config.apiBasePath || "";
|
|
46202
46295
|
super({
|
|
46203
46296
|
serviceName: "ExampleFrontendService",
|
|
46204
46297
|
supportedRuntimes: ["frontend"],
|
|
@@ -46223,20 +46316,20 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46223
46316
|
// Note: Use relative paths since apiClient.baseURL is already set to apiBasePath
|
|
46224
46317
|
fetchers: {
|
|
46225
46318
|
fetchAll: /* @__PURE__ */ __name(async (query) => {
|
|
46226
|
-
return this.apiClient.get("", { params: query });
|
|
46319
|
+
return this.apiClient.get("/examples", { params: query });
|
|
46227
46320
|
}, "fetchAll"),
|
|
46228
46321
|
fetchById: /* @__PURE__ */ __name(async (id) => {
|
|
46229
|
-
return this.apiClient.get(
|
|
46322
|
+
return this.apiClient.get(`/examples/${id}`);
|
|
46230
46323
|
}, "fetchById"),
|
|
46231
46324
|
create: /* @__PURE__ */ __name(async (data) => {
|
|
46232
|
-
return this.apiClient.post("", data);
|
|
46325
|
+
return this.apiClient.post("/examples", data);
|
|
46233
46326
|
}, "create"),
|
|
46234
46327
|
update: /* @__PURE__ */ __name(async (payload) => {
|
|
46235
46328
|
const { id, data } = payload;
|
|
46236
|
-
return this.apiClient.patch(
|
|
46329
|
+
return this.apiClient.patch(`/examples/${id}`, data);
|
|
46237
46330
|
}, "update"),
|
|
46238
46331
|
delete: /* @__PURE__ */ __name(async (id) => {
|
|
46239
|
-
return this.apiClient.delete(
|
|
46332
|
+
return this.apiClient.delete(`/examples/${id}`);
|
|
46240
46333
|
}, "delete")
|
|
46241
46334
|
}
|
|
46242
46335
|
// Store handlers - customize how data syncs to store
|
|
@@ -46304,7 +46397,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46304
46397
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
46305
46398
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
46306
46399
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
46307
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
46400
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
46308
46401
|
};
|
|
46309
46402
|
const service = new _FrontendExampleDomainService(mergedConfig, options);
|
|
46310
46403
|
if (mergedConfig.autoFetch) {
|
|
@@ -46685,337 +46778,710 @@ var CacheService = class _CacheService {
|
|
|
46685
46778
|
}
|
|
46686
46779
|
};
|
|
46687
46780
|
var getCacheService = /* @__PURE__ */ __name(() => CacheService.getInstance(), "getCacheService");
|
|
46688
|
-
var
|
|
46689
|
-
|
|
46690
|
-
|
|
46691
|
-
this.config = null;
|
|
46692
|
-
this.initialized = false;
|
|
46693
|
-
}
|
|
46781
|
+
var TABLE_NAME = "media";
|
|
46782
|
+
var DEFAULT_LIMIT2 = 100;
|
|
46783
|
+
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
46694
46784
|
static {
|
|
46695
|
-
__name(this, "
|
|
46785
|
+
__name(this, "FilesRepository");
|
|
46696
46786
|
}
|
|
46697
|
-
|
|
46698
|
-
|
|
46787
|
+
constructor(db) {
|
|
46788
|
+
super(db, TABLE_NAME);
|
|
46699
46789
|
}
|
|
46700
|
-
//
|
|
46701
|
-
//
|
|
46702
|
-
//
|
|
46790
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46791
|
+
// Static Factory
|
|
46792
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46703
46793
|
/**
|
|
46704
|
-
*
|
|
46705
|
-
*
|
|
46794
|
+
* Create repository instance.
|
|
46795
|
+
* Uses DbService if initialized.
|
|
46706
46796
|
*/
|
|
46707
|
-
|
|
46708
|
-
|
|
46709
|
-
|
|
46710
|
-
|
|
46711
|
-
|
|
46712
|
-
|
|
46713
|
-
|
|
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
|
|
46714
46822
|
};
|
|
46715
|
-
|
|
46823
|
+
return super.findMany(mergedOptions, config);
|
|
46716
46824
|
}
|
|
46717
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46718
|
-
// Singleton Management
|
|
46719
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46720
46825
|
/**
|
|
46721
|
-
*
|
|
46826
|
+
* Create new file record with auto-generated ID and timestamps
|
|
46722
46827
|
*/
|
|
46723
|
-
|
|
46724
|
-
|
|
46725
|
-
|
|
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);
|
|
46726
46857
|
}
|
|
46727
46858
|
/**
|
|
46728
|
-
*
|
|
46859
|
+
* Get the table name for this repository
|
|
46729
46860
|
*/
|
|
46730
|
-
|
|
46731
|
-
return
|
|
46861
|
+
getTableName() {
|
|
46862
|
+
return TABLE_NAME;
|
|
46732
46863
|
}
|
|
46864
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46865
|
+
// Domain-Specific Methods
|
|
46866
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46733
46867
|
/**
|
|
46734
|
-
*
|
|
46868
|
+
* Find all files for a user
|
|
46735
46869
|
*/
|
|
46736
|
-
|
|
46737
|
-
|
|
46738
|
-
|
|
46739
|
-
|
|
46740
|
-
|
|
46741
|
-
|
|
46742
|
-
|
|
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
|
+
});
|
|
46743
46878
|
}
|
|
46744
46879
|
/**
|
|
46745
|
-
*
|
|
46746
|
-
*
|
|
46747
|
-
* @param config - Storage service configuration
|
|
46748
|
-
* @returns The initialized StorageService instance
|
|
46880
|
+
* Find files for a specific entity (polymorphic association)
|
|
46749
46881
|
*/
|
|
46750
|
-
|
|
46751
|
-
|
|
46752
|
-
|
|
46753
|
-
|
|
46754
|
-
|
|
46755
|
-
instance.config = config;
|
|
46756
|
-
instance.storageService = new storage$1.StorageService(config);
|
|
46757
|
-
instance.initialized = true;
|
|
46758
|
-
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();
|
|
46759
46887
|
}
|
|
46760
46888
|
/**
|
|
46761
|
-
*
|
|
46762
|
-
* Use this only if you need direct access to the underlying service.
|
|
46763
|
-
*
|
|
46764
|
-
* @returns The raw StorageService instance from @plyaz/storage
|
|
46765
|
-
* @throws {StoragePackageError} When storage is not initialized
|
|
46889
|
+
* Find file by storage path (for deduplication checks)
|
|
46766
46890
|
*/
|
|
46767
|
-
|
|
46768
|
-
|
|
46769
|
-
throw new errors.StoragePackageError(
|
|
46770
|
-
"Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
|
|
46771
|
-
errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
|
|
46772
|
-
);
|
|
46773
|
-
}
|
|
46774
|
-
return this.storageService;
|
|
46891
|
+
async findByStoragePath(storagePath) {
|
|
46892
|
+
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
46775
46893
|
}
|
|
46776
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46777
|
-
// Service Access
|
|
46778
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46779
46894
|
/**
|
|
46780
|
-
*
|
|
46781
|
-
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46782
|
-
* Any method added to @plyaz/storage will be automatically available.
|
|
46783
|
-
*
|
|
46784
|
-
* @example
|
|
46785
|
-
* ```typescript
|
|
46786
|
-
* const storage = StorageService.getInstance().getStorage();
|
|
46787
|
-
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
46788
|
-
* await storage.deleteFile({ fileId: '123' });
|
|
46789
|
-
* ```
|
|
46790
|
-
*
|
|
46791
|
-
* @returns StorageServiceImpl with automatic error handling
|
|
46895
|
+
* Count files for a user
|
|
46792
46896
|
*/
|
|
46793
|
-
|
|
46794
|
-
|
|
46795
|
-
|
|
46796
|
-
|
|
46797
|
-
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
|
|
46801
|
-
|
|
46802
|
-
|
|
46803
|
-
|
|
46804
|
-
|
|
46805
|
-
return (...args) => {
|
|
46806
|
-
try {
|
|
46807
|
-
const result2 = value.apply(storage, args);
|
|
46808
|
-
if (result2 instanceof Promise) {
|
|
46809
|
-
return result2.catch((error) => {
|
|
46810
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46811
|
-
throw error;
|
|
46812
|
-
});
|
|
46813
|
-
}
|
|
46814
|
-
return result2;
|
|
46815
|
-
} catch (error) {
|
|
46816
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46817
|
-
throw error;
|
|
46818
|
-
}
|
|
46819
|
-
};
|
|
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
|
|
46820
46909
|
}
|
|
46821
46910
|
});
|
|
46822
46911
|
}
|
|
46823
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46824
|
-
// Health Check (special handling for response transformation)
|
|
46825
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46826
46912
|
/**
|
|
46827
|
-
*
|
|
46828
|
-
* This method has special handling to transform the response format.
|
|
46913
|
+
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
46829
46914
|
*/
|
|
46830
|
-
async
|
|
46831
|
-
|
|
46832
|
-
|
|
46833
|
-
|
|
46834
|
-
|
|
46835
|
-
|
|
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
|
|
46836
46921
|
}
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46841
|
-
|
|
46842
|
-
|
|
46843
|
-
|
|
46844
|
-
|
|
46845
|
-
} catch (error) {
|
|
46846
|
-
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
46847
|
-
return {
|
|
46848
|
-
isHealthy: false,
|
|
46849
|
-
responseTime: Date.now() - startTime,
|
|
46850
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
46851
|
-
};
|
|
46852
|
-
}
|
|
46922
|
+
});
|
|
46923
|
+
}
|
|
46924
|
+
};
|
|
46925
|
+
|
|
46926
|
+
// src/domain/files/mappers/FilesMapper.ts
|
|
46927
|
+
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
46928
|
+
static {
|
|
46929
|
+
__name(this, "FilesMapperClass");
|
|
46853
46930
|
}
|
|
46854
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46855
|
-
// Lifecycle
|
|
46856
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46857
46931
|
/**
|
|
46858
|
-
*
|
|
46932
|
+
* Type guard for UploadResult from event payloads
|
|
46933
|
+
* Validates that the value has the required structure for DB mapping
|
|
46859
46934
|
*/
|
|
46860
|
-
|
|
46861
|
-
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";
|
|
46862
46941
|
}
|
|
46863
46942
|
/**
|
|
46864
|
-
*
|
|
46943
|
+
* Infer file type from MIME type
|
|
46865
46944
|
*/
|
|
46866
|
-
|
|
46867
|
-
if (
|
|
46868
|
-
|
|
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";
|
|
46869
46951
|
}
|
|
46870
|
-
|
|
46871
|
-
this.initialized = false;
|
|
46872
|
-
this.config = null;
|
|
46952
|
+
return "OTHER";
|
|
46873
46953
|
}
|
|
46874
46954
|
/**
|
|
46875
|
-
*
|
|
46876
|
-
*
|
|
46877
|
-
* Use this when you need an isolated storage connection with its own configuration.
|
|
46878
|
-
*
|
|
46879
|
-
* @param config - Storage service configuration
|
|
46880
|
-
* @returns Promise that resolves to a new dedicated StorageService instance
|
|
46955
|
+
* API Response → Domain Entity
|
|
46881
46956
|
*/
|
|
46882
|
-
|
|
46883
|
-
const
|
|
46884
|
-
|
|
46885
|
-
|
|
46886
|
-
|
|
46887
|
-
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
|
|
46896
|
-
|
|
46897
|
-
|
|
46898
|
-
|
|
46899
|
-
|
|
46900
|
-
|
|
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
|
+
};
|
|
46901
46982
|
}
|
|
46902
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46903
|
-
// Error Handling
|
|
46904
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46905
46983
|
/**
|
|
46906
|
-
*
|
|
46907
|
-
* Called when notification operations fail to integrate with global error handling.
|
|
46984
|
+
* Domain Entity → Store State (serializable)
|
|
46908
46985
|
*/
|
|
46909
|
-
|
|
46910
|
-
|
|
46911
|
-
|
|
46912
|
-
|
|
46913
|
-
|
|
46914
|
-
|
|
46915
|
-
|
|
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
|
|
46916
47005
|
};
|
|
46917
|
-
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
|
|
46918
47006
|
}
|
|
46919
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46920
|
-
// Singleton Management
|
|
46921
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46922
47007
|
/**
|
|
46923
|
-
*
|
|
47008
|
+
* Store State → Domain Entity
|
|
46924
47009
|
*/
|
|
46925
|
-
|
|
46926
|
-
|
|
46927
|
-
|
|
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
|
+
};
|
|
46928
47030
|
}
|
|
46929
47031
|
/**
|
|
46930
|
-
*
|
|
47032
|
+
* Database Row → API Response (for backend)
|
|
46931
47033
|
*/
|
|
46932
|
-
|
|
46933
|
-
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
|
+
};
|
|
46934
47052
|
}
|
|
46935
47053
|
/**
|
|
46936
|
-
*
|
|
47054
|
+
* Create GeneratedFileItem from generation result
|
|
46937
47055
|
*/
|
|
46938
|
-
|
|
46939
|
-
|
|
46940
|
-
|
|
46941
|
-
|
|
46942
|
-
|
|
46943
|
-
|
|
46944
|
-
|
|
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
|
+
};
|
|
46945
47066
|
}
|
|
46946
47067
|
/**
|
|
46947
|
-
*
|
|
47068
|
+
* Convert upload result to database row format
|
|
47069
|
+
* Used by event handlers to persist upload results to DB
|
|
46948
47070
|
*
|
|
46949
|
-
* @param
|
|
46950
|
-
* @
|
|
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()
|
|
46951
47074
|
*/
|
|
46952
|
-
|
|
46953
|
-
|
|
46954
|
-
|
|
46955
|
-
|
|
46956
|
-
|
|
46957
|
-
|
|
46958
|
-
|
|
46959
|
-
|
|
46960
|
-
|
|
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
|
+
};
|
|
46961
47099
|
}
|
|
46962
|
-
|
|
46963
|
-
|
|
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.
|
|
46964
47430
|
* Use this only if you need direct access to the underlying service.
|
|
46965
47431
|
*
|
|
46966
|
-
* @returns The raw
|
|
46967
|
-
* @throws {
|
|
47432
|
+
* @returns The raw StorageService instance from @plyaz/storage
|
|
47433
|
+
* @throws {StoragePackageError} When storage is not initialized
|
|
46968
47434
|
*/
|
|
46969
|
-
|
|
46970
|
-
if (!this.
|
|
46971
|
-
throw new errors.
|
|
46972
|
-
"
|
|
46973
|
-
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
|
|
46974
47440
|
);
|
|
46975
47441
|
}
|
|
46976
|
-
return this.
|
|
47442
|
+
return this.storageService;
|
|
46977
47443
|
}
|
|
46978
47444
|
// ─────────────────────────────────────────────────────────────────
|
|
46979
47445
|
// Service Access
|
|
46980
47446
|
// ─────────────────────────────────────────────────────────────────
|
|
46981
47447
|
/**
|
|
46982
|
-
* Gets the
|
|
47448
|
+
* Gets the storage service with automatic error handling.
|
|
46983
47449
|
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46984
|
-
* Any method added to @plyaz/
|
|
47450
|
+
* Any method added to @plyaz/storage will be automatically available.
|
|
46985
47451
|
*
|
|
46986
47452
|
* @example
|
|
46987
47453
|
* ```typescript
|
|
46988
|
-
* const
|
|
46989
|
-
* await
|
|
46990
|
-
* await
|
|
47454
|
+
* const storage = StorageService.getInstance().getStorage();
|
|
47455
|
+
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
47456
|
+
* await storage.deleteFile({ fileId: '123' });
|
|
46991
47457
|
* ```
|
|
46992
47458
|
*
|
|
46993
|
-
* @returns
|
|
47459
|
+
* @returns StorageServiceImpl with automatic error handling
|
|
46994
47460
|
*/
|
|
46995
|
-
|
|
47461
|
+
getStorage() {
|
|
46996
47462
|
const self2 = this;
|
|
46997
47463
|
return new Proxy({}, {
|
|
46998
47464
|
get(_, prop) {
|
|
46999
47465
|
if (typeof prop === "symbol") {
|
|
47000
47466
|
return void 0;
|
|
47001
47467
|
}
|
|
47002
|
-
const
|
|
47003
|
-
const value =
|
|
47468
|
+
const storage = self2.getRawStorage();
|
|
47469
|
+
const value = storage[prop];
|
|
47004
47470
|
if (typeof value !== "function") {
|
|
47005
47471
|
return value;
|
|
47006
47472
|
}
|
|
47007
47473
|
return (...args) => {
|
|
47008
47474
|
try {
|
|
47009
|
-
const result2 = value.apply(
|
|
47475
|
+
const result2 = value.apply(storage, args);
|
|
47010
47476
|
if (result2 instanceof Promise) {
|
|
47011
47477
|
return result2.catch((error) => {
|
|
47012
|
-
self2.
|
|
47478
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47013
47479
|
throw error;
|
|
47014
47480
|
});
|
|
47015
47481
|
}
|
|
47016
47482
|
return result2;
|
|
47017
47483
|
} catch (error) {
|
|
47018
|
-
self2.
|
|
47484
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47019
47485
|
throw error;
|
|
47020
47486
|
}
|
|
47021
47487
|
};
|
|
@@ -47026,23 +47492,29 @@ var NotificationService = class _NotificationService {
|
|
|
47026
47492
|
// Health Check (special handling for response transformation)
|
|
47027
47493
|
// ─────────────────────────────────────────────────────────────────
|
|
47028
47494
|
/**
|
|
47029
|
-
* Performs a health check on the
|
|
47495
|
+
* Performs a health check on the storage service by checking all adapter health.
|
|
47030
47496
|
* This method has special handling to transform the response format.
|
|
47031
47497
|
*/
|
|
47032
47498
|
async healthCheck() {
|
|
47499
|
+
const startTime = Date.now();
|
|
47033
47500
|
try {
|
|
47034
|
-
const
|
|
47035
|
-
|
|
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;
|
|
47036
47507
|
return {
|
|
47037
|
-
|
|
47038
|
-
|
|
47039
|
-
|
|
47040
|
-
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
|
|
47041
47512
|
};
|
|
47042
47513
|
} catch (error) {
|
|
47043
|
-
this.
|
|
47514
|
+
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
47044
47515
|
return {
|
|
47045
47516
|
isHealthy: false,
|
|
47517
|
+
responseTime: Date.now() - startTime,
|
|
47046
47518
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
47047
47519
|
};
|
|
47048
47520
|
}
|
|
@@ -47057,844 +47529,539 @@ var NotificationService = class _NotificationService {
|
|
|
47057
47529
|
return this.config;
|
|
47058
47530
|
}
|
|
47059
47531
|
/**
|
|
47060
|
-
* Closes the
|
|
47532
|
+
* Closes the storage service and cleans up resources
|
|
47061
47533
|
*/
|
|
47062
47534
|
async close() {
|
|
47063
|
-
this.
|
|
47535
|
+
if (this.storageService) {
|
|
47536
|
+
await this.storageService.destroy();
|
|
47537
|
+
}
|
|
47538
|
+
this.storageService = null;
|
|
47064
47539
|
this.initialized = false;
|
|
47065
47540
|
this.config = null;
|
|
47066
47541
|
}
|
|
47067
47542
|
/**
|
|
47068
|
-
* Creates a dedicated
|
|
47543
|
+
* Creates a dedicated storage service instance (NOT the singleton)
|
|
47069
47544
|
*
|
|
47070
|
-
* Use this when you need an isolated
|
|
47545
|
+
* Use this when you need an isolated storage connection with its own configuration.
|
|
47071
47546
|
*
|
|
47072
|
-
* @param config -
|
|
47073
|
-
* @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
|
|
47074
47549
|
*/
|
|
47075
47550
|
static async createInstance(config) {
|
|
47076
|
-
const dedicatedInstance = new
|
|
47551
|
+
const dedicatedInstance = new _StorageService();
|
|
47077
47552
|
dedicatedInstance.config = config;
|
|
47078
|
-
dedicatedInstance.
|
|
47553
|
+
dedicatedInstance.storageService = new storage$1.StorageService(config);
|
|
47079
47554
|
dedicatedInstance.initialized = true;
|
|
47080
47555
|
return dedicatedInstance;
|
|
47081
47556
|
}
|
|
47082
47557
|
};
|
|
47083
|
-
var
|
|
47084
|
-
|
|
47085
|
-
|
|
47086
|
-
|
|
47087
|
-
|
|
47088
|
-
|
|
47089
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47090
|
-
} catch {
|
|
47091
|
-
try {
|
|
47092
|
-
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)));
|
|
47093
|
-
const currentDir = path.dirname(currentFile);
|
|
47094
|
-
const pkgPath = path.join(currentDir, "..", "package.json");
|
|
47095
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
47096
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47097
|
-
} catch {
|
|
47098
|
-
cachedVersion = "0.0.0";
|
|
47099
|
-
}
|
|
47100
|
-
}
|
|
47101
|
-
return cachedVersion;
|
|
47102
|
-
}
|
|
47103
|
-
__name(getPackageVersion, "getPackageVersion");
|
|
47104
|
-
var VERSION = getPackageVersion();
|
|
47105
|
-
var PACKAGE_NAME = "@plyaz/core";
|
|
47106
|
-
|
|
47107
|
-
// src/backend/index.ts
|
|
47108
|
-
var backend_exports = {};
|
|
47109
|
-
__export(backend_exports, {
|
|
47110
|
-
BACKEND_EXAMPLE_DOMAIN_SERVICE: () => BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47111
|
-
BACKEND_FILES_DOMAIN_SERVICE: () => BACKEND_FILES_DOMAIN_SERVICE,
|
|
47112
|
-
BackendExampleDomainService: () => BackendExampleDomainService,
|
|
47113
|
-
Caching: () => Caching,
|
|
47114
|
-
ErrorHandlingInterceptor: () => ErrorHandlingInterceptor,
|
|
47115
|
-
ExampleController: () => ExampleController,
|
|
47116
|
-
ExampleModule: () => ExampleModule,
|
|
47117
|
-
FeatureDisabled: () => FeatureDisabled,
|
|
47118
|
-
FeatureEnabled: () => FeatureEnabled,
|
|
47119
|
-
FeatureFlagConfigFactory: () => FeatureFlagConfigFactory,
|
|
47120
|
-
FeatureFlagConfigValidator: () => FeatureFlagConfigValidator,
|
|
47121
|
-
FeatureFlagController: () => FeatureFlagController,
|
|
47122
|
-
FeatureFlagDatabaseRepository: () => FeatureFlagDatabaseRepository,
|
|
47123
|
-
FeatureFlagDomainService: () => FeatureFlagDomainService,
|
|
47124
|
-
FeatureFlagGuard: () => FeatureFlagGuard,
|
|
47125
|
-
FeatureFlagLoggingInterceptor: () => FeatureFlagLoggingInterceptor,
|
|
47126
|
-
FeatureFlagMiddleware: () => FeatureFlagMiddleware,
|
|
47127
|
-
FeatureFlagModule: () => FeatureFlagModule,
|
|
47128
|
-
FeatureFlagService: () => FeatureFlagService,
|
|
47129
|
-
FeatureFlagServiceFactory: () => FeatureFlagServiceFactory,
|
|
47130
|
-
FilesController: () => FilesController,
|
|
47131
|
-
FilesModule: () => FilesModule
|
|
47132
|
-
});
|
|
47133
|
-
|
|
47134
|
-
// src/backend/example/example.module.ts
|
|
47135
|
-
var import_common11 = __toESM(require_common(), 1);
|
|
47136
|
-
|
|
47137
|
-
// src/backend/example/example.controller.ts
|
|
47138
|
-
var import_common10 = __toESM(require_common(), 1);
|
|
47139
|
-
var BACKEND_EXAMPLE_DOMAIN_SERVICE = "BACKEND_EXAMPLE_DOMAIN_SERVICE";
|
|
47140
|
-
var ExampleController = class {
|
|
47141
|
-
constructor(exampleService) {
|
|
47142
|
-
this.exampleService = exampleService;
|
|
47143
|
-
}
|
|
47144
|
-
health() {
|
|
47145
|
-
return errors.SuccessResponseStandard("Service is healthy", {
|
|
47146
|
-
service: this.exampleService.isAvailable(),
|
|
47147
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47148
|
-
});
|
|
47149
|
-
}
|
|
47150
|
-
async getEntity(id) {
|
|
47151
|
-
const entity = await this.exampleService.getById(id);
|
|
47152
|
-
return errors.SuccessResponseStandard("Entity retrieved successfully", entity);
|
|
47153
|
-
}
|
|
47154
|
-
async createEntity(dto) {
|
|
47155
|
-
const entity = await this.exampleService.create(dto);
|
|
47156
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47157
|
-
}
|
|
47158
|
-
async updateEntity(id, dto) {
|
|
47159
|
-
const entity = await this.exampleService.patch(id, dto);
|
|
47160
|
-
return errors.SuccessResponseStandard("Entity updated successfully", entity);
|
|
47161
|
-
}
|
|
47162
|
-
async deleteEntity(id) {
|
|
47163
|
-
await this.exampleService.delete(id);
|
|
47164
|
-
return errors.SuccessResponseStandard("Entity deleted successfully", null);
|
|
47165
|
-
}
|
|
47166
|
-
async createEntityWithValidation(dto) {
|
|
47167
|
-
const entity = await this.exampleService.create(dto);
|
|
47168
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47169
|
-
}
|
|
47170
|
-
async demoSingleError() {
|
|
47171
|
-
return await this.exampleService.demoSingleValidationError();
|
|
47172
|
-
}
|
|
47173
|
-
async demoArrayErrors() {
|
|
47174
|
-
return await this.exampleService.demoMultipleValidationErrors();
|
|
47175
|
-
}
|
|
47176
|
-
async sendEmail(dto) {
|
|
47177
|
-
const result2 = await this.exampleService.sendEmail(dto);
|
|
47178
|
-
return errors.SuccessResponseStandard("Email sent successfully", result2);
|
|
47179
|
-
}
|
|
47180
|
-
};
|
|
47181
|
-
__name(ExampleController, "ExampleController");
|
|
47182
|
-
__decorateClass([
|
|
47183
|
-
(0, import_common10.Get)("health")
|
|
47184
|
-
], ExampleController.prototype, "health", 1);
|
|
47185
|
-
__decorateClass([
|
|
47186
|
-
(0, import_common10.Get)("entities/:id"),
|
|
47187
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47188
|
-
], ExampleController.prototype, "getEntity", 1);
|
|
47189
|
-
__decorateClass([
|
|
47190
|
-
(0, import_common10.Post)("entities"),
|
|
47191
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47192
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47193
|
-
], ExampleController.prototype, "createEntity", 1);
|
|
47194
|
-
__decorateClass([
|
|
47195
|
-
(0, import_common10.Patch)("entities/:id"),
|
|
47196
|
-
__decorateParam(0, (0, import_common10.Param)("id")),
|
|
47197
|
-
__decorateParam(1, (0, import_common10.Body)())
|
|
47198
|
-
], ExampleController.prototype, "updateEntity", 1);
|
|
47199
|
-
__decorateClass([
|
|
47200
|
-
(0, import_common10.Delete)("entities/:id"),
|
|
47201
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47202
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47203
|
-
], ExampleController.prototype, "deleteEntity", 1);
|
|
47204
|
-
__decorateClass([
|
|
47205
|
-
(0, import_common10.Post)("entities/validated"),
|
|
47206
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47207
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47208
|
-
], ExampleController.prototype, "createEntityWithValidation", 1);
|
|
47209
|
-
__decorateClass([
|
|
47210
|
-
(0, import_common10.Get)("errors/single")
|
|
47211
|
-
], ExampleController.prototype, "demoSingleError", 1);
|
|
47212
|
-
__decorateClass([
|
|
47213
|
-
(0, import_common10.Get)("errors/array")
|
|
47214
|
-
], ExampleController.prototype, "demoArrayErrors", 1);
|
|
47215
|
-
__decorateClass([
|
|
47216
|
-
(0, import_common10.Post)("email"),
|
|
47217
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47218
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47219
|
-
], ExampleController.prototype, "sendEmail", 1);
|
|
47220
|
-
ExampleController = __decorateClass([
|
|
47221
|
-
(0, import_common10.Controller)("example"),
|
|
47222
|
-
__decorateParam(0, (0, import_common10.Inject)(BACKEND_EXAMPLE_DOMAIN_SERVICE))
|
|
47223
|
-
], ExampleController);
|
|
47224
|
-
|
|
47225
|
-
// src/backend/example/example.module.ts
|
|
47226
|
-
var ExampleModule = class {
|
|
47227
|
-
};
|
|
47228
|
-
__name(ExampleModule, "ExampleModule");
|
|
47229
|
-
ExampleModule = __decorateClass([
|
|
47230
|
-
(0, import_common11.Module)({
|
|
47231
|
-
controllers: [ExampleController],
|
|
47232
|
-
providers: [
|
|
47233
|
-
// Provide BackendExampleDomainService via factory using the singleton instance
|
|
47234
|
-
// This ensures the service is shared across the application
|
|
47235
|
-
{
|
|
47236
|
-
provide: BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47237
|
-
useFactory: /* @__PURE__ */ __name(() => backendExampleDomainService, "useFactory")
|
|
47238
|
-
}
|
|
47239
|
-
],
|
|
47240
|
-
exports: [BACKEND_EXAMPLE_DOMAIN_SERVICE]
|
|
47241
|
-
})
|
|
47242
|
-
], ExampleModule);
|
|
47243
|
-
|
|
47244
|
-
// src/backend/files/files.module.ts
|
|
47245
|
-
var import_common17 = __toESM(require_common(), 1);
|
|
47246
|
-
|
|
47247
|
-
// src/backend/files/files.controller.ts
|
|
47248
|
-
var import_common12 = __toESM(require_common(), 1);
|
|
47249
|
-
var BACKEND_FILES_DOMAIN_SERVICE = "BACKEND_FILES_DOMAIN_SERVICE";
|
|
47250
|
-
var FilesController = class {
|
|
47251
|
-
constructor(filesService) {
|
|
47252
|
-
this.filesService = filesService;
|
|
47253
|
-
}
|
|
47254
|
-
health() {
|
|
47255
|
-
return errors.SuccessResponseStandard("Files service is healthy", {
|
|
47256
|
-
service: this.filesService.isAvailable(),
|
|
47257
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47258
|
-
});
|
|
47259
|
-
}
|
|
47260
|
-
async uploadFile(dto) {
|
|
47261
|
-
const result2 = await this.filesService.uploadFile(dto);
|
|
47262
|
-
return errors.SuccessResponseStandard("File uploaded successfully", result2);
|
|
47263
|
-
}
|
|
47264
|
-
async uploadFiles(dto) {
|
|
47265
|
-
const results = await this.filesService.uploadFiles(dto.files);
|
|
47266
|
-
return errors.SuccessResponseStandard("Files uploaded successfully", results);
|
|
47267
|
-
}
|
|
47268
|
-
async generateDocument(dto) {
|
|
47269
|
-
const buffer = await this.filesService.generateFile(dto);
|
|
47270
|
-
return errors.SuccessResponseStandard("Document generated successfully", {
|
|
47271
|
-
buffer: buffer.toString("base64"),
|
|
47272
|
-
size: buffer.length
|
|
47273
|
-
});
|
|
47274
|
-
}
|
|
47275
|
-
async getFile(id) {
|
|
47276
|
-
const entity = await this.filesService.getById(id);
|
|
47277
|
-
return errors.SuccessResponseStandard("File retrieved", entity);
|
|
47278
|
-
}
|
|
47279
|
-
async downloadFile(id) {
|
|
47280
|
-
const result2 = await this.filesService.downloadFile({ fileId: id });
|
|
47281
|
-
return errors.SuccessResponseStandard("File downloaded", result2);
|
|
47282
|
-
}
|
|
47283
|
-
async getSignedUrl(id) {
|
|
47284
|
-
const result2 = await this.filesService.getSignedUrl({ fileId: id });
|
|
47285
|
-
return errors.SuccessResponseStandard("Signed URL generated", result2);
|
|
47286
|
-
}
|
|
47287
|
-
async deleteFile(id) {
|
|
47288
|
-
await this.filesService.delete(id);
|
|
47289
|
-
return errors.SuccessResponseStandard("File deleted", null);
|
|
47290
|
-
}
|
|
47291
|
-
};
|
|
47292
|
-
__name(FilesController, "FilesController");
|
|
47293
|
-
__decorateClass([
|
|
47294
|
-
(0, import_common12.Get)("health")
|
|
47295
|
-
], FilesController.prototype, "health", 1);
|
|
47296
|
-
__decorateClass([
|
|
47297
|
-
(0, import_common12.Post)("upload"),
|
|
47298
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47299
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47300
|
-
], FilesController.prototype, "uploadFile", 1);
|
|
47301
|
-
__decorateClass([
|
|
47302
|
-
(0, import_common12.Post)("upload/bulk"),
|
|
47303
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47304
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47305
|
-
], FilesController.prototype, "uploadFiles", 1);
|
|
47306
|
-
__decorateClass([
|
|
47307
|
-
(0, import_common12.Post)("generate-document"),
|
|
47308
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47309
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47310
|
-
], FilesController.prototype, "generateDocument", 1);
|
|
47311
|
-
__decorateClass([
|
|
47312
|
-
(0, import_common12.Get)(":id"),
|
|
47313
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47314
|
-
], FilesController.prototype, "getFile", 1);
|
|
47315
|
-
__decorateClass([
|
|
47316
|
-
(0, import_common12.Get)(":id/download"),
|
|
47317
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47318
|
-
], FilesController.prototype, "downloadFile", 1);
|
|
47319
|
-
__decorateClass([
|
|
47320
|
-
(0, import_common12.Get)(":id/signed-url"),
|
|
47321
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47322
|
-
], FilesController.prototype, "getSignedUrl", 1);
|
|
47323
|
-
__decorateClass([
|
|
47324
|
-
(0, import_common12.Delete)(":id"),
|
|
47325
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47326
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47327
|
-
], FilesController.prototype, "deleteFile", 1);
|
|
47328
|
-
FilesController = __decorateClass([
|
|
47329
|
-
(0, import_common12.Controller)("files"),
|
|
47330
|
-
__decorateParam(0, (0, import_common12.Inject)(BACKEND_FILES_DOMAIN_SERVICE))
|
|
47331
|
-
], FilesController);
|
|
47332
|
-
var TABLE_NAME = "media";
|
|
47333
|
-
var DEFAULT_LIMIT2 = 100;
|
|
47334
|
-
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
47335
|
-
static {
|
|
47336
|
-
__name(this, "FilesRepository");
|
|
47337
|
-
}
|
|
47338
|
-
constructor(db) {
|
|
47339
|
-
super(db, TABLE_NAME);
|
|
47340
|
-
}
|
|
47341
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47342
|
-
// Static Factory
|
|
47343
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47344
|
-
/**
|
|
47345
|
-
* Create repository instance.
|
|
47346
|
-
* Uses DbService if initialized.
|
|
47347
|
-
*/
|
|
47348
|
-
static create() {
|
|
47349
|
-
if (!DbService.isInitialized()) {
|
|
47350
|
-
throw new errors.DatabasePackageError(
|
|
47351
|
-
"DbService not initialized. Call DbService.initialize() first.",
|
|
47352
|
-
errors$1.DATABASE_ERROR_CODES.CONNECTION_FAILED
|
|
47353
|
-
);
|
|
47354
|
-
}
|
|
47355
|
-
const db = DbService.getInstance().getDatabase();
|
|
47356
|
-
return new _FilesRepository(db);
|
|
47357
|
-
}
|
|
47358
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47359
|
-
// Overridden Methods (with domain-specific logic)
|
|
47360
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47361
|
-
/**
|
|
47362
|
-
* Find multiple entities with default sorting
|
|
47363
|
-
*/
|
|
47364
|
-
// eslint-disable-next-line complexity
|
|
47365
|
-
async findMany(options, config) {
|
|
47366
|
-
const mergedOptions = {
|
|
47367
|
-
sort: options?.sort ?? [{ field: "created_at", direction: "desc" }],
|
|
47368
|
-
pagination: {
|
|
47369
|
-
limit: options?.pagination?.limit ?? DEFAULT_LIMIT2,
|
|
47370
|
-
offset: options?.pagination?.offset ?? 0
|
|
47371
|
-
},
|
|
47372
|
-
filter: options?.filter
|
|
47373
|
-
};
|
|
47374
|
-
return super.findMany(mergedOptions, config);
|
|
47375
|
-
}
|
|
47376
|
-
/**
|
|
47377
|
-
* Create new file record with auto-generated ID and timestamps
|
|
47378
|
-
*/
|
|
47379
|
-
// eslint-disable-next-line complexity
|
|
47380
|
-
async create(data, config) {
|
|
47381
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47382
|
-
const id = data.id ?? generateId();
|
|
47383
|
-
const row = {
|
|
47384
|
-
id,
|
|
47385
|
-
user_id: data.user_id ?? "",
|
|
47386
|
-
type: data.type ?? "OTHER",
|
|
47387
|
-
filename: data.filename ?? "",
|
|
47388
|
-
original_filename: data.original_filename ?? data.filename ?? "",
|
|
47389
|
-
mime_type: data.mime_type ?? "application/octet-stream",
|
|
47390
|
-
file_size: data.file_size ?? 0,
|
|
47391
|
-
storage_path: data.storage_path ?? "",
|
|
47392
|
-
cdn_url: data.cdn_url ?? null,
|
|
47393
|
-
width: data.width ?? null,
|
|
47394
|
-
height: data.height ?? null,
|
|
47395
|
-
duration: data.duration ?? null,
|
|
47396
|
-
is_virus_scanned: data.is_virus_scanned ?? false,
|
|
47397
|
-
virus_scan_result: data.virus_scan_result ?? null,
|
|
47398
|
-
metadata: data.metadata ?? null,
|
|
47399
|
-
variants: data.variants ?? null,
|
|
47400
|
-
entity_type: data.entity_type ?? null,
|
|
47401
|
-
entity_id: data.entity_id ?? null,
|
|
47402
|
-
access_level: data.access_level ?? null,
|
|
47403
|
-
created_at: now,
|
|
47404
|
-
updated_at: now,
|
|
47405
|
-
deleted_at: null
|
|
47406
|
-
};
|
|
47407
|
-
return super.create(row, config);
|
|
47408
|
-
}
|
|
47409
|
-
/**
|
|
47410
|
-
* Get the table name for this repository
|
|
47411
|
-
*/
|
|
47412
|
-
getTableName() {
|
|
47413
|
-
return TABLE_NAME;
|
|
47414
|
-
}
|
|
47415
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47416
|
-
// Domain-Specific Methods
|
|
47417
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47418
|
-
/**
|
|
47419
|
-
* Find all files for a user
|
|
47420
|
-
*/
|
|
47421
|
-
async findByUserId(userId, options) {
|
|
47422
|
-
return this.findMany({
|
|
47423
|
-
filter: { field: "user_id", operator: "eq", value: userId },
|
|
47424
|
-
pagination: {
|
|
47425
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47426
|
-
offset: options?.offset ?? 0
|
|
47427
|
-
}
|
|
47428
|
-
});
|
|
47429
|
-
}
|
|
47430
|
-
/**
|
|
47431
|
-
* Find files for a specific entity (polymorphic association)
|
|
47432
|
-
*/
|
|
47433
|
-
async findByEntityId(entityType, entityId, options) {
|
|
47434
|
-
return this.query().where("entity_type", "eq", entityType).andWhere("entity_id", "eq", entityId).whereNull("deleted_at").orderByDesc("created_at").paginate(
|
|
47435
|
-
Math.floor((options?.offset ?? 0) / (options?.limit ?? DEFAULT_LIMIT2)) + 1,
|
|
47436
|
-
options?.limit ?? DEFAULT_LIMIT2
|
|
47437
|
-
).execute();
|
|
47438
|
-
}
|
|
47439
|
-
/**
|
|
47440
|
-
* Find file by storage path (for deduplication checks)
|
|
47441
|
-
*/
|
|
47442
|
-
async findByStoragePath(storagePath) {
|
|
47443
|
-
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
47444
|
-
}
|
|
47445
|
-
/**
|
|
47446
|
-
* Count files for a user
|
|
47447
|
-
*/
|
|
47448
|
-
async countByUserId(userId) {
|
|
47449
|
-
return this.count({ field: "user_id", operator: "eq", value: userId });
|
|
47450
|
-
}
|
|
47451
|
-
/**
|
|
47452
|
-
* Find files by MIME type
|
|
47453
|
-
*/
|
|
47454
|
-
async findByMimeType(mimeType, options) {
|
|
47455
|
-
return this.findMany({
|
|
47456
|
-
filter: { field: "mime_type", operator: "eq", value: mimeType },
|
|
47457
|
-
pagination: {
|
|
47458
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47459
|
-
offset: options?.offset ?? 0
|
|
47460
|
-
}
|
|
47461
|
-
});
|
|
47462
|
-
}
|
|
47463
|
-
/**
|
|
47464
|
-
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
47465
|
-
*/
|
|
47466
|
-
async findByType(type, options) {
|
|
47467
|
-
return this.findMany({
|
|
47468
|
-
filter: { field: "type", operator: "eq", value: type },
|
|
47469
|
-
pagination: {
|
|
47470
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47471
|
-
offset: options?.offset ?? 0
|
|
47472
|
-
}
|
|
47473
|
-
});
|
|
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;
|
|
47474
47564
|
}
|
|
47475
|
-
};
|
|
47476
|
-
|
|
47477
|
-
// src/domain/files/mappers/FilesMapper.ts
|
|
47478
|
-
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
47479
47565
|
static {
|
|
47480
|
-
__name(this, "
|
|
47481
|
-
}
|
|
47482
|
-
/**
|
|
47483
|
-
* Type guard for UploadResult from event payloads
|
|
47484
|
-
* Validates that the value has the required structure for DB mapping
|
|
47485
|
-
*/
|
|
47486
|
-
static isUploadResult(value) {
|
|
47487
|
-
if (!isObject(value)) return false;
|
|
47488
|
-
const obj = value;
|
|
47489
|
-
if (!isObject(obj.metadata)) return false;
|
|
47490
|
-
const metadata = obj.metadata;
|
|
47491
|
-
return typeof metadata.fileId === "string" && typeof metadata.filename === "string" && typeof metadata.mimeType === "string" && typeof metadata.size === "number" && typeof metadata.path === "string";
|
|
47492
|
-
}
|
|
47493
|
-
/**
|
|
47494
|
-
* Infer file type from MIME type
|
|
47495
|
-
*/
|
|
47496
|
-
static inferFileType(mimeType) {
|
|
47497
|
-
if (mimeType.startsWith("image/")) return "IMAGE";
|
|
47498
|
-
if (mimeType.startsWith("video/")) return "VIDEO";
|
|
47499
|
-
if (mimeType.startsWith("audio/")) return "AUDIO";
|
|
47500
|
-
if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text/")) {
|
|
47501
|
-
return "DOCUMENT";
|
|
47502
|
-
}
|
|
47503
|
-
return "OTHER";
|
|
47504
|
-
}
|
|
47505
|
-
/**
|
|
47506
|
-
* API Response → Domain Entity
|
|
47507
|
-
*/
|
|
47508
|
-
toDomain(dto) {
|
|
47509
|
-
const type = _FilesMapperClass.inferFileType(dto.mimeType);
|
|
47510
|
-
return {
|
|
47511
|
-
id: dto.id,
|
|
47512
|
-
key: dto.key,
|
|
47513
|
-
filename: dto.filename,
|
|
47514
|
-
mimeType: dto.mimeType,
|
|
47515
|
-
size: dto.size,
|
|
47516
|
-
checksum: dto.checksum,
|
|
47517
|
-
url: dto.url,
|
|
47518
|
-
publicUrl: dto.publicUrl,
|
|
47519
|
-
signedUrl: dto.signedUrl,
|
|
47520
|
-
bucket: dto.bucket,
|
|
47521
|
-
entityType: dto.entityType,
|
|
47522
|
-
entityId: dto.entityId,
|
|
47523
|
-
category: dto.category,
|
|
47524
|
-
uploadedAt: new Date(dto.uploadedAt),
|
|
47525
|
-
expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : void 0,
|
|
47526
|
-
variants: dto.variants,
|
|
47527
|
-
type,
|
|
47528
|
-
isImage: type === "IMAGE",
|
|
47529
|
-
isVideo: type === "VIDEO",
|
|
47530
|
-
isDocument: type === "DOCUMENT",
|
|
47531
|
-
isAudio: type === "AUDIO"
|
|
47532
|
-
};
|
|
47533
|
-
}
|
|
47534
|
-
/**
|
|
47535
|
-
* Domain Entity → Store State (serializable)
|
|
47536
|
-
*/
|
|
47537
|
-
toStoreState(entity) {
|
|
47538
|
-
return {
|
|
47539
|
-
id: entity.id,
|
|
47540
|
-
key: entity.key,
|
|
47541
|
-
filename: entity.filename,
|
|
47542
|
-
mimeType: entity.mimeType,
|
|
47543
|
-
size: entity.size,
|
|
47544
|
-
url: entity.url,
|
|
47545
|
-
publicUrl: entity.publicUrl,
|
|
47546
|
-
bucket: entity.bucket,
|
|
47547
|
-
entityType: entity.entityType,
|
|
47548
|
-
entityId: entity.entityId,
|
|
47549
|
-
category: entity.category,
|
|
47550
|
-
uploadedAt: entity.uploadedAt.toISOString(),
|
|
47551
|
-
type: entity.type,
|
|
47552
|
-
isImage: entity.isImage,
|
|
47553
|
-
isVideo: entity.isVideo,
|
|
47554
|
-
isDocument: entity.isDocument,
|
|
47555
|
-
isAudio: entity.isAudio
|
|
47556
|
-
};
|
|
47557
|
-
}
|
|
47558
|
-
/**
|
|
47559
|
-
* Store State → Domain Entity
|
|
47560
|
-
*/
|
|
47561
|
-
fromStoreState(state) {
|
|
47562
|
-
return {
|
|
47563
|
-
id: state.id,
|
|
47564
|
-
key: state.key,
|
|
47565
|
-
filename: state.filename,
|
|
47566
|
-
mimeType: state.mimeType,
|
|
47567
|
-
size: state.size,
|
|
47568
|
-
url: state.url,
|
|
47569
|
-
publicUrl: state.publicUrl,
|
|
47570
|
-
bucket: state.bucket,
|
|
47571
|
-
entityType: state.entityType,
|
|
47572
|
-
entityId: state.entityId,
|
|
47573
|
-
category: state.category,
|
|
47574
|
-
uploadedAt: new Date(state.uploadedAt),
|
|
47575
|
-
type: state.type,
|
|
47576
|
-
isImage: state.isImage,
|
|
47577
|
-
isVideo: state.isVideo,
|
|
47578
|
-
isDocument: state.isDocument,
|
|
47579
|
-
isAudio: state.isAudio
|
|
47580
|
-
};
|
|
47581
|
-
}
|
|
47582
|
-
/**
|
|
47583
|
-
* Database Row → API Response (for backend)
|
|
47584
|
-
*/
|
|
47585
|
-
toResponseDTO(row) {
|
|
47586
|
-
return {
|
|
47587
|
-
id: row.id,
|
|
47588
|
-
key: row.storage_path,
|
|
47589
|
-
filename: row.filename,
|
|
47590
|
-
mimeType: row.mime_type,
|
|
47591
|
-
size: toNumber(row.file_size),
|
|
47592
|
-
checksum: void 0,
|
|
47593
|
-
url: row.cdn_url ?? void 0,
|
|
47594
|
-
publicUrl: row.cdn_url ?? void 0,
|
|
47595
|
-
signedUrl: void 0,
|
|
47596
|
-
bucket: "media",
|
|
47597
|
-
entityType: row.entity_type ?? void 0,
|
|
47598
|
-
entityId: row.entity_id ?? void 0,
|
|
47599
|
-
category: void 0,
|
|
47600
|
-
uploadedAt: row.created_at,
|
|
47601
|
-
expiresAt: void 0
|
|
47602
|
-
};
|
|
47603
|
-
}
|
|
47604
|
-
/**
|
|
47605
|
-
* Create GeneratedFileItem from generation result
|
|
47606
|
-
*/
|
|
47607
|
-
toGeneratedFileItem(templateId, buffer, size, outputFormat = "pdf") {
|
|
47608
|
-
return {
|
|
47609
|
-
id: crypto.randomUUID(),
|
|
47610
|
-
templateId,
|
|
47611
|
-
buffer,
|
|
47612
|
-
size,
|
|
47613
|
-
mimeType: `application/${outputFormat}`,
|
|
47614
|
-
filename: `${templateId}.${outputFormat}`,
|
|
47615
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47616
|
-
};
|
|
47617
|
-
}
|
|
47618
|
-
/**
|
|
47619
|
-
* Convert upload result to database row format
|
|
47620
|
-
* Used by event handlers to persist upload results to DB
|
|
47621
|
-
*
|
|
47622
|
-
* @param uploadResult - Result from storage upload
|
|
47623
|
-
* @param userId - User ID who uploaded the file (from auth context)
|
|
47624
|
-
* @returns Partial database row ready for repository.create()
|
|
47625
|
-
*/
|
|
47626
|
-
// eslint-disable-next-line complexity
|
|
47627
|
-
toDbRow(uploadResult, userId) {
|
|
47628
|
-
const { metadata, variants } = uploadResult;
|
|
47629
|
-
return {
|
|
47630
|
-
id: metadata.fileId,
|
|
47631
|
-
user_id: userId ?? "system",
|
|
47632
|
-
type: _FilesMapperClass.inferFileType(metadata.mimeType),
|
|
47633
|
-
filename: metadata.filename,
|
|
47634
|
-
original_filename: metadata.filename,
|
|
47635
|
-
mime_type: metadata.mimeType,
|
|
47636
|
-
file_size: metadata.size,
|
|
47637
|
-
storage_path: metadata.path,
|
|
47638
|
-
cdn_url: metadata.url ?? null,
|
|
47639
|
-
width: metadata.extractedMetadata?.width ?? null,
|
|
47640
|
-
height: metadata.extractedMetadata?.height ?? null,
|
|
47641
|
-
duration: metadata.extractedMetadata?.duration ?? null,
|
|
47642
|
-
entity_type: metadata.entityType,
|
|
47643
|
-
entity_id: metadata.entityId,
|
|
47644
|
-
access_level: metadata.accessLevel,
|
|
47645
|
-
is_virus_scanned: false,
|
|
47646
|
-
virus_scan_result: null,
|
|
47647
|
-
metadata: metadata.customMetadata ?? null,
|
|
47648
|
-
variants: variants ?? null
|
|
47649
|
-
};
|
|
47566
|
+
__name(this, "NotificationService");
|
|
47650
47567
|
}
|
|
47651
|
-
};
|
|
47652
|
-
var FilesMapper = new FilesMapperClass();
|
|
47653
|
-
|
|
47654
|
-
// src/domain/files/validators/FilesValidator.ts
|
|
47655
|
-
var FilesValidatorClass = class extends BaseValidator {
|
|
47656
47568
|
static {
|
|
47657
|
-
|
|
47658
|
-
}
|
|
47659
|
-
constructor() {
|
|
47660
|
-
super({});
|
|
47569
|
+
this.instance = null;
|
|
47661
47570
|
}
|
|
47571
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47572
|
+
// Error Handling
|
|
47573
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47662
47574
|
/**
|
|
47663
|
-
*
|
|
47664
|
-
|
|
47665
|
-
|
|
47666
|
-
|
|
47667
|
-
|
|
47668
|
-
|
|
47669
|
-
|
|
47670
|
-
|
|
47671
|
-
|
|
47672
|
-
|
|
47673
|
-
|
|
47674
|
-
|
|
47675
|
-
// src/domain/files/BackendFilesDomainService.ts
|
|
47676
|
-
var BackendFilesDomainService = class _BackendFilesDomainService extends BaseBackendDomainService {
|
|
47677
|
-
constructor(config = {}, injected) {
|
|
47678
|
-
super({
|
|
47679
|
-
serviceName: "BackendFilesDomainService",
|
|
47680
|
-
supportedRuntimes: ["backend"],
|
|
47681
|
-
serviceConfig: {
|
|
47682
|
-
enabled: true,
|
|
47683
|
-
throwOnValidationError: true,
|
|
47684
|
-
throwOnRepositoryError: true,
|
|
47685
|
-
emitEvents: true,
|
|
47686
|
-
...config
|
|
47687
|
-
},
|
|
47688
|
-
mapperClass: FilesMapperClass,
|
|
47689
|
-
validatorClass: FilesValidatorClass,
|
|
47690
|
-
injected
|
|
47691
|
-
});
|
|
47692
|
-
this.eventPrefix = "files";
|
|
47693
|
-
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);
|
|
47694
47587
|
}
|
|
47695
|
-
|
|
47696
|
-
|
|
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
|
+
};
|
|
47697
47639
|
}
|
|
47698
|
-
|
|
47699
|
-
|
|
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;
|
|
47700
47649
|
}
|
|
47701
47650
|
/**
|
|
47702
|
-
*
|
|
47703
|
-
* Throws if DbService is not initialized.
|
|
47651
|
+
* Checks if the notification service has been initialized
|
|
47704
47652
|
*/
|
|
47705
|
-
|
|
47706
|
-
|
|
47707
|
-
return this._repository;
|
|
47653
|
+
static isInitialized() {
|
|
47654
|
+
return _NotificationService.instance?.initialized ?? false;
|
|
47708
47655
|
}
|
|
47709
47656
|
/**
|
|
47710
|
-
*
|
|
47657
|
+
* Resets the notification service by clearing the singleton instance
|
|
47711
47658
|
*/
|
|
47712
|
-
|
|
47713
|
-
|
|
47714
|
-
|
|
47715
|
-
|
|
47716
|
-
|
|
47717
|
-
|
|
47718
|
-
|
|
47719
|
-
storage: options?.storage?.instance,
|
|
47720
|
-
notifications: options?.notifications?.instance
|
|
47721
|
-
};
|
|
47722
|
-
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
|
+
}
|
|
47723
47666
|
}
|
|
47724
47667
|
/**
|
|
47725
|
-
*
|
|
47726
|
-
* Called by CoreInitializer after storage and DB are initialized.
|
|
47727
|
-
*
|
|
47728
|
-
* Events handled:
|
|
47729
|
-
* - files:upload:uploaded - Persist single file to DB
|
|
47730
|
-
* - files:upload:bulk:uploaded - Persist multiple files to DB
|
|
47731
|
-
*
|
|
47732
|
-
* Deduplication: Uses unique constraint on storage_path.
|
|
47668
|
+
* Initializes the notification service
|
|
47733
47669
|
*
|
|
47734
|
-
* @param
|
|
47670
|
+
* @param config - Notification service configuration
|
|
47671
|
+
* @returns The initialized NotificationService instance
|
|
47735
47672
|
*/
|
|
47736
|
-
static
|
|
47737
|
-
|
|
47738
|
-
|
|
47673
|
+
static async initialize(config) {
|
|
47674
|
+
const instance = _NotificationService.getInstance();
|
|
47675
|
+
if (instance.initialized) {
|
|
47676
|
+
return instance;
|
|
47739
47677
|
}
|
|
47740
|
-
|
|
47741
|
-
|
|
47742
|
-
|
|
47743
|
-
|
|
47744
|
-
|
|
47745
|
-
if (!isObject(payload)) return void 0;
|
|
47746
|
-
const p = payload;
|
|
47747
|
-
if (!FilesMapperClass.isUploadResult(p.result)) return void 0;
|
|
47748
|
-
return p.result;
|
|
47749
|
-
}, "extractPayload"),
|
|
47750
|
-
isBulk: false,
|
|
47751
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47752
|
-
},
|
|
47753
|
-
"files:upload:bulk:uploaded": {
|
|
47754
|
-
extractPayload: /* @__PURE__ */ __name((payload) => {
|
|
47755
|
-
if (!isObject(payload)) return [];
|
|
47756
|
-
const p = payload;
|
|
47757
|
-
const results = p.result?.results;
|
|
47758
|
-
if (!Array.isArray(results)) return [];
|
|
47759
|
-
return results.filter(FilesMapperClass.isUploadResult);
|
|
47760
|
-
}, "extractPayload"),
|
|
47761
|
-
isBulk: true,
|
|
47762
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47763
|
-
}
|
|
47764
|
-
},
|
|
47765
|
-
loadDependencies: /* @__PURE__ */ __name(async () => ({
|
|
47766
|
-
repository: FilesRepository.create(),
|
|
47767
|
-
mapper: FilesMapper
|
|
47768
|
-
}), "loadDependencies"),
|
|
47769
|
-
mapToDbRow: /* @__PURE__ */ __name((mapper, item) => mapper.toDbRow(item), "mapToDbRow"),
|
|
47770
|
-
createRecord: /* @__PURE__ */ __name(async (repository, dbRow) => {
|
|
47771
|
-
return repository.create(dbRow);
|
|
47772
|
-
}, "createRecord"),
|
|
47773
|
-
getUniqueKey: /* @__PURE__ */ __name((item) => item.metadata.path ?? item.metadata.fileId, "getUniqueKey"),
|
|
47774
|
-
verbose
|
|
47678
|
+
const mergedEvents = _NotificationService.createMergedEventHandlers(config.events);
|
|
47679
|
+
instance.config = config;
|
|
47680
|
+
instance.notificationService = new notifications.NotificationService({
|
|
47681
|
+
...config,
|
|
47682
|
+
events: mergedEvents
|
|
47775
47683
|
});
|
|
47684
|
+
instance.initialized = true;
|
|
47685
|
+
return instance;
|
|
47776
47686
|
}
|
|
47777
|
-
|
|
47778
|
-
|
|
47779
|
-
|
|
47780
|
-
|
|
47781
|
-
|
|
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;
|
|
47782
47702
|
}
|
|
47783
|
-
//
|
|
47784
|
-
//
|
|
47785
|
-
//
|
|
47703
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47704
|
+
// Service Access
|
|
47705
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47786
47706
|
/**
|
|
47787
|
-
*
|
|
47788
|
-
*
|
|
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.
|
|
47789
47710
|
*
|
|
47790
|
-
*
|
|
47791
|
-
*
|
|
47792
|
-
*
|
|
47793
|
-
*
|
|
47794
|
-
*
|
|
47795
|
-
*
|
|
47796
|
-
* 6. Emit success event
|
|
47797
|
-
* 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
|
+
* ```
|
|
47798
47717
|
*
|
|
47799
|
-
* @
|
|
47800
|
-
* @returns Download result with buffer, filename, mimeType
|
|
47718
|
+
* @returns NotificationServiceImpl with automatic error handling
|
|
47801
47719
|
*/
|
|
47802
|
-
|
|
47803
|
-
|
|
47804
|
-
|
|
47805
|
-
|
|
47806
|
-
|
|
47807
|
-
|
|
47808
|
-
|
|
47809
|
-
|
|
47810
|
-
|
|
47811
|
-
|
|
47812
|
-
|
|
47813
|
-
|
|
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
|
+
};
|
|
47814
47747
|
}
|
|
47815
|
-
|
|
47816
|
-
|
|
47817
|
-
|
|
47818
|
-
|
|
47819
|
-
|
|
47820
|
-
|
|
47821
|
-
|
|
47822
|
-
|
|
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
|
|
47823
47766
|
};
|
|
47824
|
-
await this.afterDownloadFile?.(response);
|
|
47825
|
-
this.emitEvent("download:downloaded", { result: response });
|
|
47826
|
-
this.emitEvent("complete", { success: true, operation: "downloadFile" });
|
|
47827
|
-
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, true);
|
|
47828
|
-
return response;
|
|
47829
47767
|
} catch (error) {
|
|
47830
|
-
|
|
47831
|
-
|
|
47832
|
-
|
|
47768
|
+
this.emitNotificationError(error, "healthCheck", { recoverable: true });
|
|
47769
|
+
return {
|
|
47770
|
+
isHealthy: false,
|
|
47771
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
47772
|
+
};
|
|
47833
47773
|
}
|
|
47834
47774
|
}
|
|
47775
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47776
|
+
// Lifecycle
|
|
47777
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47778
|
+
/**
|
|
47779
|
+
* Gets the current configuration
|
|
47780
|
+
*/
|
|
47781
|
+
getConfig() {
|
|
47782
|
+
return this.config;
|
|
47783
|
+
}
|
|
47835
47784
|
/**
|
|
47836
|
-
*
|
|
47837
|
-
|
|
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)
|
|
47838
47794
|
*
|
|
47839
|
-
*
|
|
47795
|
+
* Use this when you need an isolated notification service with its own configuration.
|
|
47840
47796
|
*
|
|
47841
|
-
* @param
|
|
47842
|
-
* @returns
|
|
47797
|
+
* @param config - Notification service configuration
|
|
47798
|
+
* @returns Promise that resolves to a new dedicated NotificationService instance
|
|
47843
47799
|
*/
|
|
47844
|
-
|
|
47845
|
-
|
|
47846
|
-
|
|
47847
|
-
|
|
47848
|
-
|
|
47849
|
-
|
|
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 {
|
|
47850
47820
|
try {
|
|
47851
|
-
|
|
47852
|
-
|
|
47853
|
-
|
|
47854
|
-
|
|
47855
|
-
|
|
47856
|
-
|
|
47857
|
-
|
|
47858
|
-
const result2 = await storage.getSignedUrl({
|
|
47859
|
-
fileId: params.fileId,
|
|
47860
|
-
expiresIn: params.expiresIn ?? config.DOWNLOAD_CONFIG.DEFAULT_SIGNED_URL_EXPIRY_SECONDS,
|
|
47861
|
-
operation: "get"
|
|
47862
|
-
});
|
|
47863
|
-
const response = {
|
|
47864
|
-
url: result2?.url ?? "",
|
|
47865
|
-
expiresAt: result2?.expiresAt?.toISOString() ?? new Date(Date.now() + config.TIME_CONSTANTS.HOUR).toISOString()
|
|
47866
|
-
};
|
|
47867
|
-
await this.afterGetSignedUrl?.(response);
|
|
47868
|
-
this.emitEvent("signedUrl:received", { result: response });
|
|
47869
|
-
this.emitEvent("complete", { success: true, operation: "getSignedUrl" });
|
|
47870
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, true);
|
|
47871
|
-
return response;
|
|
47872
|
-
} catch (error) {
|
|
47873
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, false);
|
|
47874
|
-
this.emitEvent("signedUrl:error", { error });
|
|
47875
|
-
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";
|
|
47876
47828
|
}
|
|
47877
47829
|
}
|
|
47878
|
-
|
|
47879
|
-
|
|
47880
|
-
|
|
47881
|
-
|
|
47882
|
-
|
|
47883
|
-
|
|
47884
|
-
|
|
47885
|
-
|
|
47886
|
-
|
|
47887
|
-
|
|
47888
|
-
|
|
47889
|
-
|
|
47890
|
-
|
|
47891
|
-
|
|
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
|
+
}
|
|
47892
47909
|
};
|
|
47893
|
-
|
|
47894
|
-
|
|
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" });
|
|
47895
48062
|
var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseFrontendDomainService {
|
|
47896
48063
|
constructor(config = {}, options) {
|
|
47897
|
-
const apiBasePath = config.apiBasePath || "
|
|
48064
|
+
const apiBasePath = config.apiBasePath || "";
|
|
47898
48065
|
super({
|
|
47899
48066
|
serviceName: "FrontendFilesDomainService",
|
|
47900
48067
|
supportedRuntimes: ["frontend"],
|
|
@@ -47957,7 +48124,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47957
48124
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
47958
48125
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
47959
48126
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
47960
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
48127
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
47961
48128
|
};
|
|
47962
48129
|
return new _FrontendFilesDomainService(mergedConfig, options);
|
|
47963
48130
|
}
|
|
@@ -47994,7 +48161,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47994
48161
|
*/
|
|
47995
48162
|
static registerEventHandlers(verbose) {
|
|
47996
48163
|
if (this._eventHandlersRegistered) {
|
|
47997
|
-
|
|
48164
|
+
logger6.debug("Files frontend event handlers already registered");
|
|
47998
48165
|
return () => {
|
|
47999
48166
|
};
|
|
48000
48167
|
}
|
|
@@ -48056,7 +48223,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
48056
48223
|
verbose
|
|
48057
48224
|
});
|
|
48058
48225
|
this._eventHandlersRegistered = true;
|
|
48059
|
-
|
|
48226
|
+
logger6.info("Files frontend event handlers registered");
|
|
48060
48227
|
return () => {
|
|
48061
48228
|
FrontendEventPersistenceHandler.unregisterAll();
|
|
48062
48229
|
this._eventHandlersRegistered = false;
|
|
@@ -48134,7 +48301,7 @@ var FilesModule = class {
|
|
|
48134
48301
|
};
|
|
48135
48302
|
__name(FilesModule, "FilesModule");
|
|
48136
48303
|
FilesModule = __decorateClass([
|
|
48137
|
-
(0,
|
|
48304
|
+
(0, import_common16.Module)({
|
|
48138
48305
|
controllers: [FilesController],
|
|
48139
48306
|
providers: [
|
|
48140
48307
|
// Provide BackendFilesDomainService via factory using the singleton instance
|
|
@@ -48425,10 +48592,10 @@ var FeatureFlagDomainService = class extends BaseDomainService {
|
|
|
48425
48592
|
};
|
|
48426
48593
|
|
|
48427
48594
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
48428
|
-
var
|
|
48595
|
+
var import_common18 = __toESM(require_common(), 1);
|
|
48429
48596
|
|
|
48430
48597
|
// src/backend/featureFlags/feature-flag.controller.ts
|
|
48431
|
-
var
|
|
48598
|
+
var import_common17 = __toESM(require_common(), 1);
|
|
48432
48599
|
var FeatureFlagController = class {
|
|
48433
48600
|
constructor(featureFlagService) {
|
|
48434
48601
|
this.featureFlagService = featureFlagService;
|
|
@@ -48557,54 +48724,54 @@ var FeatureFlagController = class {
|
|
|
48557
48724
|
};
|
|
48558
48725
|
__name(FeatureFlagController, "FeatureFlagController");
|
|
48559
48726
|
__decorateClass([
|
|
48560
|
-
(0,
|
|
48561
|
-
__decorateParam(0, (0,
|
|
48562
|
-
__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)())
|
|
48563
48730
|
], FeatureFlagController.prototype, "evaluateFlag", 1);
|
|
48564
48731
|
__decorateClass([
|
|
48565
|
-
(0,
|
|
48566
|
-
__decorateParam(0, (0,
|
|
48567
|
-
__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)())
|
|
48568
48735
|
], FeatureFlagController.prototype, "isEnabled", 1);
|
|
48569
48736
|
__decorateClass([
|
|
48570
|
-
(0,
|
|
48571
|
-
__decorateParam(0, (0,
|
|
48737
|
+
(0, import_common17.Post)("evaluate-all"),
|
|
48738
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48572
48739
|
], FeatureFlagController.prototype, "evaluateAllFlags", 1);
|
|
48573
48740
|
__decorateClass([
|
|
48574
|
-
(0,
|
|
48575
|
-
__decorateParam(0, (0,
|
|
48741
|
+
(0, import_common17.Post)(),
|
|
48742
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48576
48743
|
], FeatureFlagController.prototype, "createFlag", 1);
|
|
48577
48744
|
__decorateClass([
|
|
48578
|
-
(0,
|
|
48579
|
-
__decorateParam(0, (0,
|
|
48580
|
-
__decorateParam(1, (0,
|
|
48745
|
+
(0, import_common17.Put)(":key"),
|
|
48746
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48747
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48581
48748
|
], FeatureFlagController.prototype, "updateFlag", 1);
|
|
48582
48749
|
__decorateClass([
|
|
48583
|
-
(0,
|
|
48584
|
-
__decorateParam(0, (0,
|
|
48750
|
+
(0, import_common17.Delete)(":key"),
|
|
48751
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48585
48752
|
], FeatureFlagController.prototype, "deleteFlag", 1);
|
|
48586
48753
|
__decorateClass([
|
|
48587
|
-
(0,
|
|
48588
|
-
__decorateParam(0, (0,
|
|
48589
|
-
__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"))
|
|
48590
48757
|
], FeatureFlagController.prototype, "setOverride", 1);
|
|
48591
48758
|
__decorateClass([
|
|
48592
|
-
(0,
|
|
48593
|
-
__decorateParam(0, (0,
|
|
48759
|
+
(0, import_common17.Delete)(":key/override"),
|
|
48760
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48594
48761
|
], FeatureFlagController.prototype, "removeOverride", 1);
|
|
48595
48762
|
__decorateClass([
|
|
48596
|
-
(0,
|
|
48597
|
-
__decorateParam(0, (0,
|
|
48763
|
+
(0, import_common17.Get)(":key/rules"),
|
|
48764
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48598
48765
|
], FeatureFlagController.prototype, "getFlagRules", 1);
|
|
48599
48766
|
__decorateClass([
|
|
48600
|
-
(0,
|
|
48767
|
+
(0, import_common17.Post)("refresh")
|
|
48601
48768
|
], FeatureFlagController.prototype, "refreshCache", 1);
|
|
48602
48769
|
__decorateClass([
|
|
48603
|
-
(0,
|
|
48770
|
+
(0, import_common17.Get)("health")
|
|
48604
48771
|
], FeatureFlagController.prototype, "getHealth", 1);
|
|
48605
48772
|
FeatureFlagController = __decorateClass([
|
|
48606
|
-
(0,
|
|
48607
|
-
__decorateParam(0, (0,
|
|
48773
|
+
(0, import_common17.Controller)("feature-flags"),
|
|
48774
|
+
__decorateParam(0, (0, import_common17.Inject)(FEATURE_FLAG_SERVICE))
|
|
48608
48775
|
], FeatureFlagController);
|
|
48609
48776
|
|
|
48610
48777
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
@@ -48696,16 +48863,16 @@ var FeatureFlagModule = class {
|
|
|
48696
48863
|
__name(FeatureFlagModule, "FeatureFlagModule");
|
|
48697
48864
|
FeatureFlagModule.serviceInstance = null;
|
|
48698
48865
|
FeatureFlagModule = __decorateClass([
|
|
48699
|
-
(0,
|
|
48700
|
-
(0,
|
|
48866
|
+
(0, import_common18.Global)(),
|
|
48867
|
+
(0, import_common18.Module)({
|
|
48701
48868
|
controllers: [FeatureFlagController]
|
|
48702
48869
|
})
|
|
48703
48870
|
], FeatureFlagModule);
|
|
48704
48871
|
|
|
48705
48872
|
// src/backend/featureFlags/decorators/feature-flag.decorator.ts
|
|
48706
|
-
var
|
|
48873
|
+
var import_common19 = __toESM(require_common(), 1);
|
|
48707
48874
|
function FeatureFlag(key, expected = true) {
|
|
48708
|
-
return (0,
|
|
48875
|
+
return (0, import_common19.SetMetadata)(types.FEATURE_FLAG_METADATA.FLAG_CHECK, { key, expected });
|
|
48709
48876
|
}
|
|
48710
48877
|
__name(FeatureFlag, "FeatureFlag");
|
|
48711
48878
|
|
|
@@ -48722,7 +48889,7 @@ function FeatureEnabled(key) {
|
|
|
48722
48889
|
__name(FeatureEnabled, "FeatureEnabled");
|
|
48723
48890
|
|
|
48724
48891
|
// src/backend/featureFlags/guards/feature-flag.guard.ts
|
|
48725
|
-
var
|
|
48892
|
+
var import_common20 = __toESM(require_common(), 1);
|
|
48726
48893
|
var FeatureFlagGuard = class {
|
|
48727
48894
|
constructor(reflector, featureFlagService) {
|
|
48728
48895
|
this.reflector = reflector;
|
|
@@ -48766,12 +48933,12 @@ var FeatureFlagGuard = class {
|
|
|
48766
48933
|
};
|
|
48767
48934
|
__name(FeatureFlagGuard, "FeatureFlagGuard");
|
|
48768
48935
|
FeatureFlagGuard = __decorateClass([
|
|
48769
|
-
(0,
|
|
48770
|
-
__decorateParam(1, (0,
|
|
48936
|
+
(0, import_common20.Injectable)(),
|
|
48937
|
+
__decorateParam(1, (0, import_common20.Inject)(FEATURE_FLAG_SERVICE))
|
|
48771
48938
|
], FeatureFlagGuard);
|
|
48772
48939
|
|
|
48773
48940
|
// src/backend/featureFlags/middleware/feature-flag-middleware.ts
|
|
48774
|
-
var
|
|
48941
|
+
var import_common21 = __toESM(require_common(), 1);
|
|
48775
48942
|
function isFeatureFlagKey(value) {
|
|
48776
48943
|
return Object.keys(config.FEATURES).includes(value);
|
|
48777
48944
|
}
|
|
@@ -48849,12 +49016,12 @@ var FeatureFlagMiddleware = class {
|
|
|
48849
49016
|
};
|
|
48850
49017
|
__name(FeatureFlagMiddleware, "FeatureFlagMiddleware");
|
|
48851
49018
|
FeatureFlagMiddleware = __decorateClass([
|
|
48852
|
-
(0,
|
|
48853
|
-
__decorateParam(0, (0,
|
|
49019
|
+
(0, import_common21.Injectable)(),
|
|
49020
|
+
__decorateParam(0, (0, import_common21.Inject)(FEATURE_FLAG_SERVICE))
|
|
48854
49021
|
], FeatureFlagMiddleware);
|
|
48855
49022
|
|
|
48856
49023
|
// src/backend/featureFlags/interceptors/feature-flag-logging-interceptor.ts
|
|
48857
|
-
var
|
|
49024
|
+
var import_common22 = __toESM(require_common(), 1);
|
|
48858
49025
|
var import_rxjs = __toESM(require_cjs(), 1);
|
|
48859
49026
|
var FeatureFlagLoggingInterceptor = class {
|
|
48860
49027
|
constructor() {
|
|
@@ -48887,11 +49054,11 @@ var FeatureFlagLoggingInterceptor = class {
|
|
|
48887
49054
|
};
|
|
48888
49055
|
__name(FeatureFlagLoggingInterceptor, "FeatureFlagLoggingInterceptor");
|
|
48889
49056
|
FeatureFlagLoggingInterceptor = __decorateClass([
|
|
48890
|
-
(0,
|
|
49057
|
+
(0, import_common22.Injectable)()
|
|
48891
49058
|
], FeatureFlagLoggingInterceptor);
|
|
48892
49059
|
|
|
48893
49060
|
// src/backend/featureFlags/interceptors/error-handling-interceptor.ts
|
|
48894
|
-
var
|
|
49061
|
+
var import_common23 = __toESM(require_common(), 1);
|
|
48895
49062
|
var import_operators = __toESM(require_operators(), 1);
|
|
48896
49063
|
var ErrorHandlingInterceptor = class {
|
|
48897
49064
|
constructor() {
|
|
@@ -48920,9 +49087,9 @@ var ErrorHandlingInterceptor = class {
|
|
|
48920
49087
|
};
|
|
48921
49088
|
__name(ErrorHandlingInterceptor, "ErrorHandlingInterceptor");
|
|
48922
49089
|
ErrorHandlingInterceptor = __decorateClass([
|
|
48923
|
-
(0,
|
|
49090
|
+
(0, import_common23.Injectable)()
|
|
48924
49091
|
], ErrorHandlingInterceptor);
|
|
48925
|
-
var
|
|
49092
|
+
var logger7 = new logger$1.PackageLogger({
|
|
48926
49093
|
packageName: "core",
|
|
48927
49094
|
service: "FeatureFlagConfigValidator"
|
|
48928
49095
|
});
|
|
@@ -49108,7 +49275,7 @@ var FeatureFlagConfigValidator = class {
|
|
|
49108
49275
|
static getWarnings(config$1, environment) {
|
|
49109
49276
|
const env = environment ?? (config$1.isLoggingEnabled ? types.NODE_ENVIRONMENTS.DEVELOPMENT : types.NODE_ENVIRONMENTS.PRODUCTION);
|
|
49110
49277
|
if (config$1.cacheTtl > config.NUMERIC_CONSTANTS.ONE_HOUR_SECONDS) {
|
|
49111
|
-
|
|
49278
|
+
logger7.warn(
|
|
49112
49279
|
"Cache TTL is very high (>1 hour). Consider reducing for better responsiveness.",
|
|
49113
49280
|
{
|
|
49114
49281
|
field: "cacheTtl",
|
|
@@ -49118,13 +49285,13 @@ var FeatureFlagConfigValidator = class {
|
|
|
49118
49285
|
);
|
|
49119
49286
|
}
|
|
49120
49287
|
if (env === types.NODE_ENVIRONMENTS.PRODUCTION && config$1.isLoggingEnabled) {
|
|
49121
|
-
|
|
49288
|
+
logger7.warn("Logging is enabled in production. Consider disabling for performance.", {
|
|
49122
49289
|
field: "isLoggingEnabled",
|
|
49123
49290
|
code: "PRODUCTION_LOGGING_ENABLED"
|
|
49124
49291
|
});
|
|
49125
49292
|
}
|
|
49126
49293
|
if (env === types.NODE_ENVIRONMENTS.DEVELOPMENT && !config$1.isCacheEnabled) {
|
|
49127
|
-
|
|
49294
|
+
logger7.warn("Cache is disabled in development. This may impact performance testing.", {
|
|
49128
49295
|
field: "isCacheEnabled",
|
|
49129
49296
|
code: "DEVELOPMENT_CACHE_DISABLED"
|
|
49130
49297
|
});
|
|
@@ -49267,7 +49434,7 @@ var FeatureFlagConfigFactory = class {
|
|
|
49267
49434
|
};
|
|
49268
49435
|
|
|
49269
49436
|
// src/base/cache/feature/caching.ts
|
|
49270
|
-
var
|
|
49437
|
+
var import_common24 = __toESM(require_common(), 1);
|
|
49271
49438
|
var import_rxjs2 = __toESM(require_cjs(), 1);
|
|
49272
49439
|
var Caching = class {
|
|
49273
49440
|
constructor() {
|
|
@@ -49290,7 +49457,7 @@ var Caching = class {
|
|
|
49290
49457
|
};
|
|
49291
49458
|
__name(Caching, "Caching");
|
|
49292
49459
|
Caching = __decorateClass([
|
|
49293
|
-
(0,
|
|
49460
|
+
(0, import_common24.Injectable)()
|
|
49294
49461
|
], Caching);
|
|
49295
49462
|
|
|
49296
49463
|
// src/frontend/index.ts
|
|
@@ -49417,7 +49584,7 @@ function ApiProvider({
|
|
|
49417
49584
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
49418
49585
|
}
|
|
49419
49586
|
__name(ApiProvider, "ApiProvider");
|
|
49420
|
-
var
|
|
49587
|
+
var logger8 = new logger$1.PackageLogger({ packageName: "core", service: "PlyazProvider" });
|
|
49421
49588
|
var PlyazContext = react.createContext(null);
|
|
49422
49589
|
var FeatureFlagStore = class {
|
|
49423
49590
|
constructor(config = {}) {
|
|
@@ -49512,7 +49679,7 @@ function createStoreRegistry() {
|
|
|
49512
49679
|
getStore(key) {
|
|
49513
49680
|
const state = store.useRootStore.getState();
|
|
49514
49681
|
if (!state) {
|
|
49515
|
-
|
|
49682
|
+
logger8.warn(
|
|
49516
49683
|
"Store state is undefined - store may not be hydrated yet. This can cause side effects if called during SSR or before initialization."
|
|
49517
49684
|
);
|
|
49518
49685
|
return void 0;
|
|
@@ -49528,7 +49695,10 @@ async function initializeServices(config) {
|
|
|
49528
49695
|
globalThis.console.log("[PlyazProvider] Initializing domain services...");
|
|
49529
49696
|
}
|
|
49530
49697
|
await ServiceRegistry.initialize({
|
|
49698
|
+
environment: config.environment,
|
|
49699
|
+
runtime: config.runtime ?? detectRuntime(),
|
|
49531
49700
|
apiClient: { baseURL: config.api.baseURL },
|
|
49701
|
+
observability: config.observability,
|
|
49532
49702
|
services: config.services,
|
|
49533
49703
|
// Provide store registry for injecting stores into services
|
|
49534
49704
|
stores: createStoreRegistry()
|