@plyaz/core 1.10.1 → 1.11.1
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/base/observability/DatadogAdapter.d.ts.map +1 -1
- package/dist/domain/example/FrontendExampleDomainService.d.ts.map +1 -1
- package/dist/domain/featureFlags/module.d.ts.map +1 -1
- package/dist/domain/files/BackendFilesDomainService.d.ts +10 -13
- package/dist/domain/files/BackendFilesDomainService.d.ts.map +1 -1
- package/dist/entry-backend.js +382 -200
- package/dist/entry-backend.js.map +1 -1
- package/dist/entry-backend.mjs +280 -98
- package/dist/entry-backend.mjs.map +1 -1
- package/dist/entry-frontend-browser.js +122 -35
- package/dist/entry-frontend-browser.js.map +1 -1
- package/dist/entry-frontend-browser.mjs +123 -33
- package/dist/entry-frontend-browser.mjs.map +1 -1
- package/dist/entry-frontend.js +122 -35
- package/dist/entry-frontend.js.map +1 -1
- package/dist/entry-frontend.mjs +123 -33
- package/dist/entry-frontend.mjs.map +1 -1
- package/dist/frontend/providers/PlyazProvider.d.ts +1 -3
- package/dist/frontend/providers/PlyazProvider.d.ts.map +1 -1
- package/dist/index.js +1339 -1134
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1290 -1085
- package/dist/index.mjs.map +1 -1
- package/dist/init/CoreInitializer.d.ts +31 -1
- package/dist/init/CoreInitializer.d.ts.map +1 -1
- package/dist/init/nestjs/index.js +126 -14
- package/dist/init/nestjs/index.js.map +1 -1
- package/dist/init/nestjs/index.mjs +127 -15
- 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,
|
|
@@ -35497,6 +35497,24 @@ var Core = class _Core {
|
|
|
35497
35497
|
*/
|
|
35498
35498
|
this._rootStore = null;
|
|
35499
35499
|
}
|
|
35500
|
+
static {
|
|
35501
|
+
/**
|
|
35502
|
+
* Injected store hook for frontend (set via setRootStoreHook before initialize).
|
|
35503
|
+
* This is used instead of directly importing from @plyaz/store to prevent
|
|
35504
|
+
* duplicate store instances when bundlers create multiple module copies.
|
|
35505
|
+
*/
|
|
35506
|
+
this._injectedStoreHook = null;
|
|
35507
|
+
}
|
|
35508
|
+
/**
|
|
35509
|
+
* Set the root store hook for frontend use.
|
|
35510
|
+
* Must be called before Core.initialize() when running in browser.
|
|
35511
|
+
* PlyazProvider calls this automatically with the store prop.
|
|
35512
|
+
*
|
|
35513
|
+
* @param store - The useRootStore hook from @plyaz/store
|
|
35514
|
+
*/
|
|
35515
|
+
static setRootStoreHook(store) {
|
|
35516
|
+
_Core._injectedStoreHook = store;
|
|
35517
|
+
}
|
|
35500
35518
|
/**
|
|
35501
35519
|
* Setup environment and context
|
|
35502
35520
|
*/
|
|
@@ -36407,8 +36425,14 @@ var Core = class _Core {
|
|
|
36407
36425
|
static async initializeRootStore(config, verbose) {
|
|
36408
36426
|
const isFrontend = typeof window !== "undefined";
|
|
36409
36427
|
if (isFrontend) {
|
|
36410
|
-
_Core.
|
|
36411
|
-
|
|
36428
|
+
if (!_Core._injectedStoreHook) {
|
|
36429
|
+
throw new errors.CorePackageError(
|
|
36430
|
+
"Root store hook not set. Call Core.setRootStoreHook(useRootStore) before Core.initialize(), or use PlyazProvider with the store prop: <PlyazProvider store={useRootStore} ...>",
|
|
36431
|
+
types.ERROR_CODES.CLIENT_INITIALIZATION_FAILED
|
|
36432
|
+
);
|
|
36433
|
+
}
|
|
36434
|
+
_Core.log("Using frontend root store (Zustand) - injected via setRootStoreHook", verbose);
|
|
36435
|
+
_Core._rootStore = _Core._injectedStoreHook;
|
|
36412
36436
|
} else {
|
|
36413
36437
|
_Core.log("Creating backend composite store (in-memory)", verbose);
|
|
36414
36438
|
const ServerErrorMiddleware = getCoreDependency("ServerErrorMiddleware");
|
|
@@ -36517,26 +36541,76 @@ var Core = class _Core {
|
|
|
36517
36541
|
errorStore,
|
|
36518
36542
|
_Core.buildErrorHandlerConfig(_Core._errorConfig)
|
|
36519
36543
|
);
|
|
36544
|
+
_Core.setupErrorEventSubscription(verbose);
|
|
36545
|
+
_Core.setupErrorStoreSubscription(verbose);
|
|
36546
|
+
_Core.log("Global error handler initialized with CoreEventManager integration", verbose);
|
|
36547
|
+
if (_Core._errorConfig.httpHandler !== false) {
|
|
36548
|
+
await _Core.createHttpErrorHandler(_Core._errorConfig, verbose);
|
|
36549
|
+
}
|
|
36550
|
+
}
|
|
36551
|
+
/**
|
|
36552
|
+
* Log serialized errors with full details.
|
|
36553
|
+
*/
|
|
36554
|
+
static logErrors(errors, prefix = "ErrorStore") {
|
|
36555
|
+
for (const err of errors) {
|
|
36556
|
+
_Core.logger.error(`[${prefix}] ${err.code}: ${err.message}`, {
|
|
36557
|
+
id: err.id,
|
|
36558
|
+
code: err.code,
|
|
36559
|
+
message: err.message,
|
|
36560
|
+
category: err.category,
|
|
36561
|
+
source: err.source,
|
|
36562
|
+
status: err.status,
|
|
36563
|
+
isRetryable: err.isRetryable,
|
|
36564
|
+
context: err.context,
|
|
36565
|
+
timestamp: err.timestamp
|
|
36566
|
+
});
|
|
36567
|
+
}
|
|
36568
|
+
}
|
|
36569
|
+
/**
|
|
36570
|
+
* Setup SYSTEM.ERROR event subscription for error store updates.
|
|
36571
|
+
* Backend: Also logs errors with full details.
|
|
36572
|
+
* Frontend: Only updates store (logging handled by store subscription).
|
|
36573
|
+
*/
|
|
36574
|
+
static setupErrorEventSubscription(verbose) {
|
|
36575
|
+
const isBackend = types.BACKEND_RUNTIMES.includes(_Core._coreServices.runtime);
|
|
36520
36576
|
const errorEventCleanup = CoreEventManager.on(
|
|
36521
36577
|
core.CORE_EVENTS.SYSTEM.ERROR,
|
|
36522
36578
|
(event) => {
|
|
36523
36579
|
if (!_Core._rootStore) return;
|
|
36524
36580
|
try {
|
|
36525
36581
|
const { errors } = event.data;
|
|
36526
|
-
if (errors
|
|
36527
|
-
|
|
36528
|
-
|
|
36529
|
-
}
|
|
36582
|
+
if (!errors || errors.length === 0) return;
|
|
36583
|
+
_Core._rootStore.getState().errors.addErrors(errors);
|
|
36584
|
+
if (isBackend) _Core.logErrors(errors);
|
|
36585
|
+
_Core.log(`Added ${errors.length} error(s) to store`, verbose);
|
|
36530
36586
|
} catch (e) {
|
|
36531
36587
|
_Core.logger.error("Failed to handle error event", { error: e });
|
|
36532
36588
|
}
|
|
36533
36589
|
}
|
|
36534
36590
|
);
|
|
36535
36591
|
_Core._eventCleanupFns.push(errorEventCleanup);
|
|
36536
|
-
|
|
36537
|
-
|
|
36538
|
-
|
|
36539
|
-
|
|
36592
|
+
}
|
|
36593
|
+
/**
|
|
36594
|
+
* Setup error store subscription for frontend logging.
|
|
36595
|
+
* Logs new errors when they're added to the store.
|
|
36596
|
+
* Only active for non-backend runtimes (browser, nextjs, nuxt, edge).
|
|
36597
|
+
*/
|
|
36598
|
+
static setupErrorStoreSubscription(verbose) {
|
|
36599
|
+
const isFrontend = !types.BACKEND_RUNTIMES.includes(_Core._coreServices.runtime);
|
|
36600
|
+
if (!isFrontend || !_Core._rootStore) return;
|
|
36601
|
+
let prevErrorCount = 0;
|
|
36602
|
+
const storeUnsubscribe = _Core._rootStore.subscribe((state) => {
|
|
36603
|
+
const currentCount = state.errors.errorCount;
|
|
36604
|
+
if (currentCount <= prevErrorCount) {
|
|
36605
|
+
prevErrorCount = currentCount;
|
|
36606
|
+
return;
|
|
36607
|
+
}
|
|
36608
|
+
const newErrors = state.errors.errors.slice(0, currentCount - prevErrorCount);
|
|
36609
|
+
_Core.logErrors(newErrors, "ErrorStore:FE");
|
|
36610
|
+
prevErrorCount = currentCount;
|
|
36611
|
+
});
|
|
36612
|
+
_Core._eventCleanupFns.push(storeUnsubscribe);
|
|
36613
|
+
_Core.log("Error store subscription initialized for frontend", verbose);
|
|
36540
36614
|
}
|
|
36541
36615
|
/**
|
|
36542
36616
|
* Create HTTP error handler based on detected runtime.
|
|
@@ -38490,7 +38564,7 @@ var BaseFrontendDomainService = class _BaseFrontendDomainService extends BaseDom
|
|
|
38490
38564
|
}
|
|
38491
38565
|
};
|
|
38492
38566
|
var logger2 = new logger$1.PackageLogger({ packageName: "core", service: "EventPersistence" });
|
|
38493
|
-
|
|
38567
|
+
(class {
|
|
38494
38568
|
static {
|
|
38495
38569
|
__name(this, "BackendEventPersistenceHandler");
|
|
38496
38570
|
}
|
|
@@ -38664,7 +38738,7 @@ var BackendEventPersistenceHandler = class {
|
|
|
38664
38738
|
static getRegisteredDomains() {
|
|
38665
38739
|
return Array.from(this.registeredDomains.keys());
|
|
38666
38740
|
}
|
|
38667
|
-
};
|
|
38741
|
+
});
|
|
38668
38742
|
var logger3 = new logger$1.PackageLogger({ packageName: "core", service: "FrontendEventPersistence" });
|
|
38669
38743
|
var FrontendEventPersistenceHandler = class {
|
|
38670
38744
|
static {
|
|
@@ -43341,6 +43415,7 @@ var ApiFeatureFlagProvider = class extends FeatureFlagProvider {
|
|
|
43341
43415
|
return this.engine.getRules();
|
|
43342
43416
|
}
|
|
43343
43417
|
};
|
|
43418
|
+
var logger4 = new logger$1.PackageLogger({ packageName: "core", service: "DbService" });
|
|
43344
43419
|
var DEFAULT_ENCRYPTION_FIELDS = {
|
|
43345
43420
|
// User PII
|
|
43346
43421
|
users: ["password_hash", "phone_number", "date_of_birth"],
|
|
@@ -43434,6 +43509,41 @@ var DbService = class _DbService {
|
|
|
43434
43509
|
};
|
|
43435
43510
|
CoreEventManager.emit(core.CORE_EVENTS.DATABASE.ERROR, payload);
|
|
43436
43511
|
}
|
|
43512
|
+
/**
|
|
43513
|
+
* Creates merged event handlers that wrap user-provided handlers.
|
|
43514
|
+
* Adds Core-level logging and forwards to user handlers.
|
|
43515
|
+
*
|
|
43516
|
+
* Note: Unlike StorageService/NotificationService, DB events don't emit
|
|
43517
|
+
* to CoreEventManager by default (too verbose). User handlers can emit
|
|
43518
|
+
* if needed.
|
|
43519
|
+
*
|
|
43520
|
+
* @param userHandlers - User-provided event handlers from config
|
|
43521
|
+
* @returns Merged handlers with Core logging + user handlers
|
|
43522
|
+
*/
|
|
43523
|
+
static createMergedEventHandlers(userHandlers) {
|
|
43524
|
+
return {
|
|
43525
|
+
...userHandlers,
|
|
43526
|
+
onAfterWrite: /* @__PURE__ */ __name(async (event) => {
|
|
43527
|
+
logger4.debug("Database write completed", {
|
|
43528
|
+
operation: event.operation,
|
|
43529
|
+
table: event.table,
|
|
43530
|
+
duration: event.duration
|
|
43531
|
+
});
|
|
43532
|
+
if (userHandlers?.onAfterWrite) {
|
|
43533
|
+
await userHandlers.onAfterWrite(event);
|
|
43534
|
+
}
|
|
43535
|
+
}, "onAfterWrite"),
|
|
43536
|
+
onAfterRead: /* @__PURE__ */ __name(async (event) => {
|
|
43537
|
+
logger4.debug("Database read completed", {
|
|
43538
|
+
table: event.table,
|
|
43539
|
+
duration: event.duration
|
|
43540
|
+
});
|
|
43541
|
+
if (userHandlers?.onAfterRead) {
|
|
43542
|
+
await userHandlers.onAfterRead(event);
|
|
43543
|
+
}
|
|
43544
|
+
}, "onAfterRead")
|
|
43545
|
+
};
|
|
43546
|
+
}
|
|
43437
43547
|
/**
|
|
43438
43548
|
* Gets the singleton instance of DbService
|
|
43439
43549
|
*
|
|
@@ -43638,6 +43748,8 @@ var DbService = class _DbService {
|
|
|
43638
43748
|
if (cache) dbConfig.cache = cache;
|
|
43639
43749
|
if (audit) dbConfig.audit = audit;
|
|
43640
43750
|
if (encryption) dbConfig.encryption = encryption;
|
|
43751
|
+
const events = _DbService.createMergedEventHandlers(config.events);
|
|
43752
|
+
if (events) dbConfig.events = events;
|
|
43641
43753
|
return dbConfig;
|
|
43642
43754
|
}
|
|
43643
43755
|
/**
|
|
@@ -44879,8 +44991,9 @@ function buildDatabaseProviderConfig(config) {
|
|
|
44879
44991
|
__name(buildDatabaseProviderConfig, "buildDatabaseProviderConfig");
|
|
44880
44992
|
function buildRedisProviderConfig(config) {
|
|
44881
44993
|
if (!config.redis?.url) {
|
|
44882
|
-
throw new
|
|
44883
|
-
'Redis URL is required when using redis provider. Provide redis: { url: "redis://..." }'
|
|
44994
|
+
throw new errors.CorePackageError(
|
|
44995
|
+
'Redis URL is required when using redis provider. Provide redis: { url: "redis://..." }',
|
|
44996
|
+
types.ERROR_CODES.CORE_CONFIGURATION_INVALID
|
|
44884
44997
|
);
|
|
44885
44998
|
}
|
|
44886
44999
|
return {
|
|
@@ -46203,7 +46316,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46203
46316
|
// Constructor
|
|
46204
46317
|
// ─────────────────────────────────────────────────────────────────────────
|
|
46205
46318
|
constructor(config = {}, options) {
|
|
46206
|
-
const apiBasePath = config.apiBasePath || "
|
|
46319
|
+
const apiBasePath = config.apiBasePath || "";
|
|
46207
46320
|
super({
|
|
46208
46321
|
serviceName: "ExampleFrontendService",
|
|
46209
46322
|
supportedRuntimes: ["frontend"],
|
|
@@ -46228,20 +46341,20 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46228
46341
|
// Note: Use relative paths since apiClient.baseURL is already set to apiBasePath
|
|
46229
46342
|
fetchers: {
|
|
46230
46343
|
fetchAll: /* @__PURE__ */ __name(async (query) => {
|
|
46231
|
-
return this.apiClient.get("", { params: query });
|
|
46344
|
+
return this.apiClient.get("/examples", { params: query });
|
|
46232
46345
|
}, "fetchAll"),
|
|
46233
46346
|
fetchById: /* @__PURE__ */ __name(async (id) => {
|
|
46234
|
-
return this.apiClient.get(
|
|
46347
|
+
return this.apiClient.get(`/examples/${id}`);
|
|
46235
46348
|
}, "fetchById"),
|
|
46236
46349
|
create: /* @__PURE__ */ __name(async (data) => {
|
|
46237
|
-
return this.apiClient.post("", data);
|
|
46350
|
+
return this.apiClient.post("/examples", data);
|
|
46238
46351
|
}, "create"),
|
|
46239
46352
|
update: /* @__PURE__ */ __name(async (payload) => {
|
|
46240
46353
|
const { id, data } = payload;
|
|
46241
|
-
return this.apiClient.patch(
|
|
46354
|
+
return this.apiClient.patch(`/examples/${id}`, data);
|
|
46242
46355
|
}, "update"),
|
|
46243
46356
|
delete: /* @__PURE__ */ __name(async (id) => {
|
|
46244
|
-
return this.apiClient.delete(
|
|
46357
|
+
return this.apiClient.delete(`/examples/${id}`);
|
|
46245
46358
|
}, "delete")
|
|
46246
46359
|
}
|
|
46247
46360
|
// Store handlers - customize how data syncs to store
|
|
@@ -46309,7 +46422,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46309
46422
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
46310
46423
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
46311
46424
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
46312
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
46425
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
46313
46426
|
};
|
|
46314
46427
|
const service = new _FrontendExampleDomainService(mergedConfig, options);
|
|
46315
46428
|
if (mergedConfig.autoFetch) {
|
|
@@ -46470,7 +46583,10 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
|
|
|
46470
46583
|
const response = await this.apiClient.post(endpoint, data);
|
|
46471
46584
|
if (!this.isResponseSuccess(response)) {
|
|
46472
46585
|
const error = this.extractResponseError(response);
|
|
46473
|
-
throw new
|
|
46586
|
+
throw new errors.CorePackageError(
|
|
46587
|
+
`Failed to send email: ${JSON.stringify(error)}`,
|
|
46588
|
+
types.ERROR_CODES.CORE_OPERATION_FAILED
|
|
46589
|
+
);
|
|
46474
46590
|
}
|
|
46475
46591
|
const result2 = this.unwrapResponseData(response.data);
|
|
46476
46592
|
CoreEventManager.emit(`${this.eventPrefix}:email:sent`, { result: result2 });
|
|
@@ -46690,337 +46806,712 @@ var CacheService = class _CacheService {
|
|
|
46690
46806
|
}
|
|
46691
46807
|
};
|
|
46692
46808
|
var getCacheService = /* @__PURE__ */ __name(() => CacheService.getInstance(), "getCacheService");
|
|
46693
|
-
var
|
|
46694
|
-
|
|
46695
|
-
|
|
46696
|
-
this.config = null;
|
|
46697
|
-
this.initialized = false;
|
|
46698
|
-
}
|
|
46809
|
+
var TABLE_NAME = "media";
|
|
46810
|
+
var DEFAULT_LIMIT2 = 100;
|
|
46811
|
+
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
46699
46812
|
static {
|
|
46700
|
-
__name(this, "
|
|
46813
|
+
__name(this, "FilesRepository");
|
|
46701
46814
|
}
|
|
46702
|
-
|
|
46703
|
-
|
|
46815
|
+
constructor(db) {
|
|
46816
|
+
super(db, TABLE_NAME);
|
|
46704
46817
|
}
|
|
46705
|
-
//
|
|
46706
|
-
//
|
|
46707
|
-
//
|
|
46818
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46819
|
+
// Static Factory
|
|
46820
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46708
46821
|
/**
|
|
46709
|
-
*
|
|
46710
|
-
*
|
|
46822
|
+
* Create repository instance.
|
|
46823
|
+
* Uses DbService if initialized.
|
|
46711
46824
|
*/
|
|
46712
|
-
|
|
46713
|
-
|
|
46714
|
-
|
|
46715
|
-
|
|
46716
|
-
|
|
46717
|
-
|
|
46718
|
-
|
|
46825
|
+
static create() {
|
|
46826
|
+
if (!DbService.isInitialized()) {
|
|
46827
|
+
throw new errors.DatabasePackageError(
|
|
46828
|
+
"DbService not initialized. Call DbService.initialize() first.",
|
|
46829
|
+
errors$1.DATABASE_ERROR_CODES.CONNECTION_FAILED
|
|
46830
|
+
);
|
|
46831
|
+
}
|
|
46832
|
+
const db = DbService.getInstance().getDatabase();
|
|
46833
|
+
return new _FilesRepository(db);
|
|
46834
|
+
}
|
|
46835
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46836
|
+
// Overridden Methods (with domain-specific logic)
|
|
46837
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46838
|
+
/**
|
|
46839
|
+
* Find multiple entities with default sorting
|
|
46840
|
+
*/
|
|
46841
|
+
// eslint-disable-next-line complexity
|
|
46842
|
+
async findMany(options, config) {
|
|
46843
|
+
const mergedOptions = {
|
|
46844
|
+
sort: options?.sort ?? [{ field: "created_at", direction: "desc" }],
|
|
46845
|
+
pagination: {
|
|
46846
|
+
limit: options?.pagination?.limit ?? DEFAULT_LIMIT2,
|
|
46847
|
+
offset: options?.pagination?.offset ?? 0
|
|
46848
|
+
},
|
|
46849
|
+
filter: options?.filter
|
|
46719
46850
|
};
|
|
46720
|
-
|
|
46851
|
+
return super.findMany(mergedOptions, config);
|
|
46721
46852
|
}
|
|
46722
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46723
|
-
// Singleton Management
|
|
46724
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46725
46853
|
/**
|
|
46726
|
-
*
|
|
46854
|
+
* Create new file record with auto-generated ID and timestamps
|
|
46727
46855
|
*/
|
|
46728
|
-
|
|
46729
|
-
|
|
46730
|
-
|
|
46856
|
+
// eslint-disable-next-line complexity
|
|
46857
|
+
async create(data, config) {
|
|
46858
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
46859
|
+
const id = data.id ?? generateId();
|
|
46860
|
+
const row = {
|
|
46861
|
+
id,
|
|
46862
|
+
user_id: data.user_id ?? "",
|
|
46863
|
+
type: data.type ?? "OTHER",
|
|
46864
|
+
filename: data.filename ?? "",
|
|
46865
|
+
original_filename: data.original_filename ?? data.filename ?? "",
|
|
46866
|
+
mime_type: data.mime_type ?? "application/octet-stream",
|
|
46867
|
+
file_size: data.file_size ?? 0,
|
|
46868
|
+
storage_path: data.storage_path ?? "",
|
|
46869
|
+
cdn_url: data.cdn_url ?? null,
|
|
46870
|
+
width: data.width ?? null,
|
|
46871
|
+
height: data.height ?? null,
|
|
46872
|
+
duration: data.duration ?? null,
|
|
46873
|
+
is_virus_scanned: data.is_virus_scanned ?? false,
|
|
46874
|
+
virus_scan_result: data.virus_scan_result ?? null,
|
|
46875
|
+
metadata: data.metadata ?? null,
|
|
46876
|
+
variants: data.variants ?? null,
|
|
46877
|
+
entity_type: data.entity_type ?? null,
|
|
46878
|
+
entity_id: data.entity_id ?? null,
|
|
46879
|
+
access_level: data.access_level ?? null,
|
|
46880
|
+
created_at: now,
|
|
46881
|
+
updated_at: now,
|
|
46882
|
+
deleted_at: null
|
|
46883
|
+
};
|
|
46884
|
+
return super.create(row, config);
|
|
46731
46885
|
}
|
|
46732
46886
|
/**
|
|
46733
|
-
*
|
|
46887
|
+
* Get the table name for this repository
|
|
46734
46888
|
*/
|
|
46735
|
-
|
|
46736
|
-
return
|
|
46889
|
+
getTableName() {
|
|
46890
|
+
return TABLE_NAME;
|
|
46737
46891
|
}
|
|
46892
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46893
|
+
// Domain-Specific Methods
|
|
46894
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
46738
46895
|
/**
|
|
46739
|
-
*
|
|
46896
|
+
* Find all files for a user
|
|
46740
46897
|
*/
|
|
46741
|
-
|
|
46742
|
-
|
|
46743
|
-
|
|
46744
|
-
|
|
46745
|
-
|
|
46746
|
-
|
|
46747
|
-
|
|
46898
|
+
async findByUserId(userId, options) {
|
|
46899
|
+
return this.findMany({
|
|
46900
|
+
filter: { field: "user_id", operator: "eq", value: userId },
|
|
46901
|
+
pagination: {
|
|
46902
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46903
|
+
offset: options?.offset ?? 0
|
|
46904
|
+
}
|
|
46905
|
+
});
|
|
46748
46906
|
}
|
|
46749
46907
|
/**
|
|
46750
|
-
*
|
|
46751
|
-
*
|
|
46752
|
-
* @param config - Storage service configuration
|
|
46753
|
-
* @returns The initialized StorageService instance
|
|
46908
|
+
* Find files for a specific entity (polymorphic association)
|
|
46754
46909
|
*/
|
|
46755
|
-
|
|
46756
|
-
|
|
46757
|
-
|
|
46758
|
-
|
|
46759
|
-
|
|
46760
|
-
instance.config = config;
|
|
46761
|
-
instance.storageService = new storage$1.StorageService(config);
|
|
46762
|
-
instance.initialized = true;
|
|
46763
|
-
return instance;
|
|
46910
|
+
async findByEntityId(entityType, entityId, options) {
|
|
46911
|
+
return this.query().where("entity_type", "eq", entityType).andWhere("entity_id", "eq", entityId).whereNull("deleted_at").orderByDesc("created_at").paginate(
|
|
46912
|
+
Math.floor((options?.offset ?? 0) / (options?.limit ?? DEFAULT_LIMIT2)) + 1,
|
|
46913
|
+
options?.limit ?? DEFAULT_LIMIT2
|
|
46914
|
+
).execute();
|
|
46764
46915
|
}
|
|
46765
46916
|
/**
|
|
46766
|
-
*
|
|
46767
|
-
* Use this only if you need direct access to the underlying service.
|
|
46768
|
-
*
|
|
46769
|
-
* @returns The raw StorageService instance from @plyaz/storage
|
|
46770
|
-
* @throws {StoragePackageError} When storage is not initialized
|
|
46917
|
+
* Find file by storage path (for deduplication checks)
|
|
46771
46918
|
*/
|
|
46772
|
-
|
|
46773
|
-
|
|
46774
|
-
throw new errors.StoragePackageError(
|
|
46775
|
-
"Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
|
|
46776
|
-
errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
|
|
46777
|
-
);
|
|
46778
|
-
}
|
|
46779
|
-
return this.storageService;
|
|
46919
|
+
async findByStoragePath(storagePath) {
|
|
46920
|
+
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
46780
46921
|
}
|
|
46781
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46782
|
-
// Service Access
|
|
46783
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46784
46922
|
/**
|
|
46785
|
-
*
|
|
46786
|
-
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46787
|
-
* Any method added to @plyaz/storage will be automatically available.
|
|
46788
|
-
*
|
|
46789
|
-
* @example
|
|
46790
|
-
* ```typescript
|
|
46791
|
-
* const storage = StorageService.getInstance().getStorage();
|
|
46792
|
-
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
46793
|
-
* await storage.deleteFile({ fileId: '123' });
|
|
46794
|
-
* ```
|
|
46795
|
-
*
|
|
46796
|
-
* @returns StorageServiceImpl with automatic error handling
|
|
46923
|
+
* Count files for a user
|
|
46797
46924
|
*/
|
|
46798
|
-
|
|
46799
|
-
|
|
46800
|
-
return new Proxy({}, {
|
|
46801
|
-
get(_, prop) {
|
|
46802
|
-
if (typeof prop === "symbol") {
|
|
46803
|
-
return void 0;
|
|
46804
|
-
}
|
|
46805
|
-
const storage = self2.getRawStorage();
|
|
46806
|
-
const value = storage[prop];
|
|
46807
|
-
if (typeof value !== "function") {
|
|
46808
|
-
return value;
|
|
46809
|
-
}
|
|
46810
|
-
return (...args) => {
|
|
46811
|
-
try {
|
|
46812
|
-
const result2 = value.apply(storage, args);
|
|
46813
|
-
if (result2 instanceof Promise) {
|
|
46814
|
-
return result2.catch((error) => {
|
|
46815
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46816
|
-
throw error;
|
|
46817
|
-
});
|
|
46818
|
-
}
|
|
46819
|
-
return result2;
|
|
46820
|
-
} catch (error) {
|
|
46821
|
-
self2.emitStorageError(error, prop, { recoverable: true });
|
|
46822
|
-
throw error;
|
|
46823
|
-
}
|
|
46824
|
-
};
|
|
46825
|
-
}
|
|
46826
|
-
});
|
|
46925
|
+
async countByUserId(userId) {
|
|
46926
|
+
return this.count({ field: "user_id", operator: "eq", value: userId });
|
|
46827
46927
|
}
|
|
46828
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46829
|
-
// Health Check (special handling for response transformation)
|
|
46830
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46831
46928
|
/**
|
|
46832
|
-
*
|
|
46833
|
-
* This method has special handling to transform the response format.
|
|
46929
|
+
* Find files by MIME type
|
|
46834
46930
|
*/
|
|
46835
|
-
async
|
|
46836
|
-
|
|
46837
|
-
|
|
46838
|
-
|
|
46839
|
-
|
|
46840
|
-
|
|
46931
|
+
async findByMimeType(mimeType, options) {
|
|
46932
|
+
return this.findMany({
|
|
46933
|
+
filter: { field: "mime_type", operator: "eq", value: mimeType },
|
|
46934
|
+
pagination: {
|
|
46935
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46936
|
+
offset: options?.offset ?? 0
|
|
46841
46937
|
}
|
|
46842
|
-
|
|
46843
|
-
const responseTime = Date.now() - startTime;
|
|
46844
|
-
return {
|
|
46845
|
-
// Check if all adapters are healthy (healthy count equals total count)
|
|
46846
|
-
isHealthy: summary ? summary.healthy === summary.total : true,
|
|
46847
|
-
responseTime,
|
|
46848
|
-
error: void 0
|
|
46849
|
-
};
|
|
46850
|
-
} catch (error) {
|
|
46851
|
-
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
46852
|
-
return {
|
|
46853
|
-
isHealthy: false,
|
|
46854
|
-
responseTime: Date.now() - startTime,
|
|
46855
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
46856
|
-
};
|
|
46857
|
-
}
|
|
46938
|
+
});
|
|
46858
46939
|
}
|
|
46859
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46860
|
-
// Lifecycle
|
|
46861
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46862
46940
|
/**
|
|
46863
|
-
*
|
|
46941
|
+
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
46864
46942
|
*/
|
|
46865
|
-
|
|
46866
|
-
return this.
|
|
46943
|
+
async findByType(type, options) {
|
|
46944
|
+
return this.findMany({
|
|
46945
|
+
filter: { field: "type", operator: "eq", value: type },
|
|
46946
|
+
pagination: {
|
|
46947
|
+
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
46948
|
+
offset: options?.offset ?? 0
|
|
46949
|
+
}
|
|
46950
|
+
});
|
|
46951
|
+
}
|
|
46952
|
+
};
|
|
46953
|
+
|
|
46954
|
+
// src/domain/files/mappers/FilesMapper.ts
|
|
46955
|
+
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
46956
|
+
static {
|
|
46957
|
+
__name(this, "FilesMapperClass");
|
|
46867
46958
|
}
|
|
46868
46959
|
/**
|
|
46869
|
-
*
|
|
46960
|
+
* Type guard for UploadResult from event payloads
|
|
46961
|
+
* Validates that the value has the required structure for DB mapping
|
|
46870
46962
|
*/
|
|
46871
|
-
|
|
46872
|
-
if (
|
|
46873
|
-
|
|
46874
|
-
|
|
46875
|
-
|
|
46876
|
-
|
|
46877
|
-
this.config = null;
|
|
46963
|
+
static isUploadResult(value) {
|
|
46964
|
+
if (!isObject(value)) return false;
|
|
46965
|
+
const obj = value;
|
|
46966
|
+
if (!isObject(obj.metadata)) return false;
|
|
46967
|
+
const metadata = obj.metadata;
|
|
46968
|
+
return typeof metadata.fileId === "string" && typeof metadata.filename === "string" && typeof metadata.mimeType === "string" && typeof metadata.size === "number" && typeof metadata.path === "string";
|
|
46878
46969
|
}
|
|
46879
46970
|
/**
|
|
46880
|
-
*
|
|
46881
|
-
*
|
|
46882
|
-
* Use this when you need an isolated storage connection with its own configuration.
|
|
46883
|
-
*
|
|
46884
|
-
* @param config - Storage service configuration
|
|
46885
|
-
* @returns Promise that resolves to a new dedicated StorageService instance
|
|
46971
|
+
* Infer file type from MIME type
|
|
46886
46972
|
*/
|
|
46887
|
-
static
|
|
46888
|
-
|
|
46889
|
-
|
|
46890
|
-
|
|
46891
|
-
|
|
46892
|
-
|
|
46893
|
-
|
|
46894
|
-
|
|
46895
|
-
var NotificationService = class _NotificationService {
|
|
46896
|
-
constructor() {
|
|
46897
|
-
this.notificationService = null;
|
|
46898
|
-
this.config = null;
|
|
46899
|
-
this.initialized = false;
|
|
46900
|
-
}
|
|
46901
|
-
static {
|
|
46902
|
-
__name(this, "NotificationService");
|
|
46903
|
-
}
|
|
46904
|
-
static {
|
|
46905
|
-
this.instance = null;
|
|
46973
|
+
static inferFileType(mimeType) {
|
|
46974
|
+
if (mimeType.startsWith("image/")) return "IMAGE";
|
|
46975
|
+
if (mimeType.startsWith("video/")) return "VIDEO";
|
|
46976
|
+
if (mimeType.startsWith("audio/")) return "AUDIO";
|
|
46977
|
+
if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text/")) {
|
|
46978
|
+
return "DOCUMENT";
|
|
46979
|
+
}
|
|
46980
|
+
return "OTHER";
|
|
46906
46981
|
}
|
|
46907
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46908
|
-
// Error Handling
|
|
46909
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46910
46982
|
/**
|
|
46911
|
-
*
|
|
46912
|
-
* Called when notification operations fail to integrate with global error handling.
|
|
46983
|
+
* API Response → Domain Entity
|
|
46913
46984
|
*/
|
|
46914
|
-
|
|
46915
|
-
const
|
|
46916
|
-
|
|
46917
|
-
|
|
46918
|
-
|
|
46919
|
-
|
|
46920
|
-
|
|
46985
|
+
toDomain(dto) {
|
|
46986
|
+
const type = _FilesMapperClass.inferFileType(dto.mimeType);
|
|
46987
|
+
return {
|
|
46988
|
+
id: dto.id,
|
|
46989
|
+
key: dto.key,
|
|
46990
|
+
filename: dto.filename,
|
|
46991
|
+
mimeType: dto.mimeType,
|
|
46992
|
+
size: dto.size,
|
|
46993
|
+
checksum: dto.checksum,
|
|
46994
|
+
url: dto.url,
|
|
46995
|
+
publicUrl: dto.publicUrl,
|
|
46996
|
+
signedUrl: dto.signedUrl,
|
|
46997
|
+
bucket: dto.bucket,
|
|
46998
|
+
entityType: dto.entityType,
|
|
46999
|
+
entityId: dto.entityId,
|
|
47000
|
+
category: dto.category,
|
|
47001
|
+
uploadedAt: new Date(dto.uploadedAt),
|
|
47002
|
+
expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : void 0,
|
|
47003
|
+
variants: dto.variants,
|
|
47004
|
+
type,
|
|
47005
|
+
isImage: type === "IMAGE",
|
|
47006
|
+
isVideo: type === "VIDEO",
|
|
47007
|
+
isDocument: type === "DOCUMENT",
|
|
47008
|
+
isAudio: type === "AUDIO"
|
|
46921
47009
|
};
|
|
46922
|
-
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
|
|
46923
47010
|
}
|
|
46924
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46925
|
-
// Singleton Management
|
|
46926
|
-
// ─────────────────────────────────────────────────────────────────
|
|
46927
47011
|
/**
|
|
46928
|
-
*
|
|
47012
|
+
* Domain Entity → Store State (serializable)
|
|
46929
47013
|
*/
|
|
46930
|
-
|
|
46931
|
-
|
|
46932
|
-
|
|
47014
|
+
toStoreState(entity) {
|
|
47015
|
+
return {
|
|
47016
|
+
id: entity.id,
|
|
47017
|
+
key: entity.key,
|
|
47018
|
+
filename: entity.filename,
|
|
47019
|
+
mimeType: entity.mimeType,
|
|
47020
|
+
size: entity.size,
|
|
47021
|
+
url: entity.url,
|
|
47022
|
+
publicUrl: entity.publicUrl,
|
|
47023
|
+
bucket: entity.bucket,
|
|
47024
|
+
entityType: entity.entityType,
|
|
47025
|
+
entityId: entity.entityId,
|
|
47026
|
+
category: entity.category,
|
|
47027
|
+
uploadedAt: entity.uploadedAt.toISOString(),
|
|
47028
|
+
type: entity.type,
|
|
47029
|
+
isImage: entity.isImage,
|
|
47030
|
+
isVideo: entity.isVideo,
|
|
47031
|
+
isDocument: entity.isDocument,
|
|
47032
|
+
isAudio: entity.isAudio
|
|
47033
|
+
};
|
|
46933
47034
|
}
|
|
46934
47035
|
/**
|
|
46935
|
-
*
|
|
47036
|
+
* Store State → Domain Entity
|
|
46936
47037
|
*/
|
|
46937
|
-
|
|
46938
|
-
return
|
|
47038
|
+
fromStoreState(state) {
|
|
47039
|
+
return {
|
|
47040
|
+
id: state.id,
|
|
47041
|
+
key: state.key,
|
|
47042
|
+
filename: state.filename,
|
|
47043
|
+
mimeType: state.mimeType,
|
|
47044
|
+
size: state.size,
|
|
47045
|
+
url: state.url,
|
|
47046
|
+
publicUrl: state.publicUrl,
|
|
47047
|
+
bucket: state.bucket,
|
|
47048
|
+
entityType: state.entityType,
|
|
47049
|
+
entityId: state.entityId,
|
|
47050
|
+
category: state.category,
|
|
47051
|
+
uploadedAt: new Date(state.uploadedAt),
|
|
47052
|
+
type: state.type,
|
|
47053
|
+
isImage: state.isImage,
|
|
47054
|
+
isVideo: state.isVideo,
|
|
47055
|
+
isDocument: state.isDocument,
|
|
47056
|
+
isAudio: state.isAudio
|
|
47057
|
+
};
|
|
46939
47058
|
}
|
|
46940
47059
|
/**
|
|
46941
|
-
*
|
|
47060
|
+
* Database Row → API Response (for backend)
|
|
46942
47061
|
*/
|
|
46943
|
-
|
|
46944
|
-
|
|
46945
|
-
|
|
46946
|
-
|
|
46947
|
-
|
|
46948
|
-
|
|
46949
|
-
|
|
47062
|
+
toResponseDTO(row) {
|
|
47063
|
+
return {
|
|
47064
|
+
id: row.id,
|
|
47065
|
+
key: row.storage_path,
|
|
47066
|
+
filename: row.filename,
|
|
47067
|
+
mimeType: row.mime_type,
|
|
47068
|
+
size: toNumber(row.file_size),
|
|
47069
|
+
checksum: void 0,
|
|
47070
|
+
url: row.cdn_url ?? void 0,
|
|
47071
|
+
publicUrl: row.cdn_url ?? void 0,
|
|
47072
|
+
signedUrl: void 0,
|
|
47073
|
+
bucket: "media",
|
|
47074
|
+
entityType: row.entity_type ?? void 0,
|
|
47075
|
+
entityId: row.entity_id ?? void 0,
|
|
47076
|
+
category: void 0,
|
|
47077
|
+
uploadedAt: row.created_at,
|
|
47078
|
+
expiresAt: void 0
|
|
47079
|
+
};
|
|
46950
47080
|
}
|
|
46951
47081
|
/**
|
|
46952
|
-
*
|
|
46953
|
-
*
|
|
46954
|
-
* @param config - Notification service configuration
|
|
46955
|
-
* @returns The initialized NotificationService instance
|
|
47082
|
+
* Create GeneratedFileItem from generation result
|
|
46956
47083
|
*/
|
|
46957
|
-
|
|
46958
|
-
|
|
46959
|
-
|
|
46960
|
-
|
|
46961
|
-
|
|
46962
|
-
|
|
46963
|
-
|
|
46964
|
-
|
|
46965
|
-
|
|
47084
|
+
toGeneratedFileItem(templateId, buffer, size, outputFormat = "pdf") {
|
|
47085
|
+
return {
|
|
47086
|
+
id: crypto.randomUUID(),
|
|
47087
|
+
templateId,
|
|
47088
|
+
buffer,
|
|
47089
|
+
size,
|
|
47090
|
+
mimeType: `application/${outputFormat}`,
|
|
47091
|
+
filename: `${templateId}.${outputFormat}`,
|
|
47092
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47093
|
+
};
|
|
46966
47094
|
}
|
|
46967
47095
|
/**
|
|
46968
|
-
*
|
|
46969
|
-
*
|
|
47096
|
+
* Convert upload result to database row format
|
|
47097
|
+
* Used by event handlers to persist upload results to DB
|
|
46970
47098
|
*
|
|
46971
|
-
* @
|
|
46972
|
-
* @
|
|
47099
|
+
* @param uploadResult - Result from storage upload
|
|
47100
|
+
* @param userId - User ID who uploaded the file (from auth context)
|
|
47101
|
+
* @returns Partial database row ready for repository.create()
|
|
46973
47102
|
*/
|
|
46974
|
-
|
|
46975
|
-
|
|
46976
|
-
|
|
46977
|
-
|
|
46978
|
-
|
|
47103
|
+
// eslint-disable-next-line complexity
|
|
47104
|
+
toDbRow(uploadResult, userId) {
|
|
47105
|
+
const { metadata, variants } = uploadResult;
|
|
47106
|
+
return {
|
|
47107
|
+
id: metadata.fileId,
|
|
47108
|
+
user_id: userId ?? "system",
|
|
47109
|
+
type: _FilesMapperClass.inferFileType(metadata.mimeType),
|
|
47110
|
+
filename: metadata.filename,
|
|
47111
|
+
original_filename: metadata.filename,
|
|
47112
|
+
mime_type: metadata.mimeType,
|
|
47113
|
+
file_size: metadata.size,
|
|
47114
|
+
storage_path: metadata.path,
|
|
47115
|
+
cdn_url: metadata.url ?? null,
|
|
47116
|
+
width: metadata.extractedMetadata?.width ?? null,
|
|
47117
|
+
height: metadata.extractedMetadata?.height ?? null,
|
|
47118
|
+
duration: metadata.extractedMetadata?.duration ?? null,
|
|
47119
|
+
entity_type: metadata.entityType,
|
|
47120
|
+
entity_id: metadata.entityId,
|
|
47121
|
+
access_level: metadata.accessLevel,
|
|
47122
|
+
is_virus_scanned: false,
|
|
47123
|
+
virus_scan_result: null,
|
|
47124
|
+
metadata: metadata.customMetadata ?? null,
|
|
47125
|
+
variants: variants ?? null
|
|
47126
|
+
};
|
|
47127
|
+
}
|
|
47128
|
+
};
|
|
47129
|
+
var FilesMapper = new FilesMapperClass();
|
|
47130
|
+
|
|
47131
|
+
// src/domain/files/validators/FilesValidator.ts
|
|
47132
|
+
var FilesValidatorClass = class extends BaseValidator {
|
|
47133
|
+
static {
|
|
47134
|
+
__name(this, "FilesValidatorClass");
|
|
47135
|
+
}
|
|
47136
|
+
constructor() {
|
|
47137
|
+
super({});
|
|
47138
|
+
}
|
|
47139
|
+
/**
|
|
47140
|
+
* Check if user has permission to access file
|
|
47141
|
+
*/
|
|
47142
|
+
validateUserAccess(userId, fileOwnerId, accessLevel, isAdmin = false) {
|
|
47143
|
+
if (isAdmin) return true;
|
|
47144
|
+
if (userId === fileOwnerId) return true;
|
|
47145
|
+
if (accessLevel === "public") return true;
|
|
47146
|
+
if (accessLevel === "protected" && userId) return true;
|
|
47147
|
+
return false;
|
|
47148
|
+
}
|
|
47149
|
+
};
|
|
47150
|
+
new FilesValidatorClass();
|
|
47151
|
+
|
|
47152
|
+
// src/domain/files/BackendFilesDomainService.ts
|
|
47153
|
+
var BackendFilesDomainService = class _BackendFilesDomainService extends BaseBackendDomainService {
|
|
47154
|
+
constructor(config = {}, injected) {
|
|
47155
|
+
super({
|
|
47156
|
+
serviceName: "BackendFilesDomainService",
|
|
47157
|
+
supportedRuntimes: ["backend"],
|
|
47158
|
+
serviceConfig: {
|
|
47159
|
+
enabled: true,
|
|
47160
|
+
throwOnValidationError: true,
|
|
47161
|
+
throwOnRepositoryError: true,
|
|
47162
|
+
emitEvents: true,
|
|
47163
|
+
...config
|
|
47164
|
+
},
|
|
47165
|
+
mapperClass: FilesMapperClass,
|
|
47166
|
+
validatorClass: FilesValidatorClass,
|
|
47167
|
+
injected
|
|
47168
|
+
});
|
|
47169
|
+
this.eventPrefix = "files";
|
|
47170
|
+
this.cachePrefix = "files";
|
|
47171
|
+
}
|
|
47172
|
+
static {
|
|
47173
|
+
__name(this, "BackendFilesDomainService");
|
|
47174
|
+
}
|
|
47175
|
+
static {
|
|
47176
|
+
this.serviceKey = "files";
|
|
47177
|
+
}
|
|
47178
|
+
/**
|
|
47179
|
+
* Lazy repository getter - creates repository on first access.
|
|
47180
|
+
* Throws if DbService is not initialized.
|
|
47181
|
+
*/
|
|
47182
|
+
get repository() {
|
|
47183
|
+
this._repository ??= FilesRepository.create();
|
|
47184
|
+
return this._repository;
|
|
47185
|
+
}
|
|
47186
|
+
/**
|
|
47187
|
+
* Create service instance
|
|
47188
|
+
*/
|
|
47189
|
+
// eslint-disable-next-line complexity
|
|
47190
|
+
static async create(config = {}, options) {
|
|
47191
|
+
const injected = {
|
|
47192
|
+
cache: options?.cache?.instance,
|
|
47193
|
+
db: options?.db?.instance,
|
|
47194
|
+
api: options?.apiClient?.instance,
|
|
47195
|
+
storage: options?.storage?.instance,
|
|
47196
|
+
notifications: options?.notifications?.instance
|
|
47197
|
+
};
|
|
47198
|
+
return new _BackendFilesDomainService(config, injected);
|
|
47199
|
+
}
|
|
47200
|
+
isAvailable() {
|
|
47201
|
+
return this.isServiceEnabled;
|
|
47202
|
+
}
|
|
47203
|
+
dispose() {
|
|
47204
|
+
this.logInfo("Service disposed");
|
|
47205
|
+
}
|
|
47206
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47207
|
+
// Storage operations (via @plyaz/storage)
|
|
47208
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47209
|
+
/**
|
|
47210
|
+
* Download file content
|
|
47211
|
+
* GET /files/:id/download
|
|
47212
|
+
*
|
|
47213
|
+
* Follows same pattern as base class CRUD methods:
|
|
47214
|
+
* 1. assertReady
|
|
47215
|
+
* 2. Record start time
|
|
47216
|
+
* 3. Log debug info
|
|
47217
|
+
* 4. Emit starting event
|
|
47218
|
+
* 5. Execute operation
|
|
47219
|
+
* 6. Emit success event
|
|
47220
|
+
* 7. Record metrics
|
|
47221
|
+
*
|
|
47222
|
+
* @param params - Download parameters (fileId required)
|
|
47223
|
+
* @returns Download result with buffer, filename, mimeType
|
|
47224
|
+
*/
|
|
47225
|
+
// eslint-disable-next-line complexity
|
|
47226
|
+
async downloadFile(params) {
|
|
47227
|
+
this.assertReady();
|
|
47228
|
+
const startTime = Date.now();
|
|
47229
|
+
this.logDebug("Downloading file", { fileId: params.fileId });
|
|
47230
|
+
this.emitEvent("download:downloading", { request: params });
|
|
47231
|
+
try {
|
|
47232
|
+
await this.beforeDownloadFile?.(params);
|
|
47233
|
+
if (!this.storageService) {
|
|
47234
|
+
throw new errors.CorePackageError(
|
|
47235
|
+
"Storage service not available. Ensure storage is configured in Core.initialize().",
|
|
47236
|
+
types.ERROR_CODES.CORE_PROVIDER_INITIALIZATION_FAILED
|
|
47237
|
+
);
|
|
47238
|
+
}
|
|
47239
|
+
const storage = this.storageService.getStorage();
|
|
47240
|
+
const result2 = await storage.downloadFile({
|
|
47241
|
+
fileId: params.fileId
|
|
47242
|
+
});
|
|
47243
|
+
const response = {
|
|
47244
|
+
buffer: result2?.file?.toString("base64") ?? "",
|
|
47245
|
+
filename: result2?.metadata?.filename ?? "download",
|
|
47246
|
+
mimeType: result2?.metadata?.mimeType ?? "application/octet-stream"
|
|
47247
|
+
};
|
|
47248
|
+
await this.afterDownloadFile?.(response);
|
|
47249
|
+
this.emitEvent("download:downloaded", { result: response });
|
|
47250
|
+
this.emitEvent("complete", { success: true, operation: "downloadFile" });
|
|
47251
|
+
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, true);
|
|
47252
|
+
return response;
|
|
47253
|
+
} catch (error) {
|
|
47254
|
+
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, false);
|
|
47255
|
+
this.emitEvent("download:error", { error });
|
|
47256
|
+
throw error;
|
|
47257
|
+
}
|
|
47258
|
+
}
|
|
47259
|
+
/**
|
|
47260
|
+
* Get signed URL for file
|
|
47261
|
+
* GET /files/:id/signed-url
|
|
47262
|
+
*
|
|
47263
|
+
* Follows same pattern as base class CRUD methods.
|
|
47264
|
+
*
|
|
47265
|
+
* @param params - Signed URL parameters (fileId required)
|
|
47266
|
+
* @returns Signed URL result with url and expiresAt
|
|
47267
|
+
*/
|
|
47268
|
+
// eslint-disable-next-line complexity
|
|
47269
|
+
async getSignedUrl(params) {
|
|
47270
|
+
this.assertReady();
|
|
47271
|
+
const startTime = Date.now();
|
|
47272
|
+
this.logDebug("Getting signed URL", { fileId: params.fileId, expiresIn: params.expiresIn });
|
|
47273
|
+
this.emitEvent("signedUrl:requesting", { request: params });
|
|
47274
|
+
try {
|
|
47275
|
+
await this.beforeGetSignedUrl?.(params);
|
|
47276
|
+
if (!this.storageService) {
|
|
47277
|
+
throw new errors.CorePackageError(
|
|
47278
|
+
"Storage service not available. Ensure storage is configured in Core.initialize().",
|
|
47279
|
+
types.ERROR_CODES.CORE_PROVIDER_INITIALIZATION_FAILED
|
|
47280
|
+
);
|
|
47281
|
+
}
|
|
47282
|
+
const storage = this.storageService.getStorage();
|
|
47283
|
+
const result2 = await storage.getSignedUrl({
|
|
47284
|
+
fileId: params.fileId,
|
|
47285
|
+
expiresIn: params.expiresIn ?? config.DOWNLOAD_CONFIG.DEFAULT_SIGNED_URL_EXPIRY_SECONDS,
|
|
47286
|
+
operation: "get"
|
|
47287
|
+
});
|
|
47288
|
+
const response = {
|
|
47289
|
+
url: result2?.url ?? "",
|
|
47290
|
+
expiresAt: result2?.expiresAt?.toISOString() ?? new Date(Date.now() + config.TIME_CONSTANTS.HOUR).toISOString()
|
|
47291
|
+
};
|
|
47292
|
+
await this.afterGetSignedUrl?.(response);
|
|
47293
|
+
this.emitEvent("signedUrl:received", { result: response });
|
|
47294
|
+
this.emitEvent("complete", { success: true, operation: "getSignedUrl" });
|
|
47295
|
+
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, true);
|
|
47296
|
+
return response;
|
|
47297
|
+
} catch (error) {
|
|
47298
|
+
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, false);
|
|
47299
|
+
this.emitEvent("signedUrl:error", { error });
|
|
47300
|
+
throw error;
|
|
47301
|
+
}
|
|
47302
|
+
}
|
|
47303
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47304
|
+
// DB Persistence (called by StorageService on upload complete)
|
|
47305
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47306
|
+
/**
|
|
47307
|
+
* Persist uploaded file metadata to the media table.
|
|
47308
|
+
* Called by StorageService.onFileUploaded event handler.
|
|
47309
|
+
*
|
|
47310
|
+
* @param metadata - File metadata from storage upload
|
|
47311
|
+
* @param variants - Optional file variants (thumbnails, etc.)
|
|
47312
|
+
* @param userId - Optional user ID who uploaded the file
|
|
47313
|
+
*/
|
|
47314
|
+
async persistUploadedFile(metadata, variants, userId) {
|
|
47315
|
+
const startTime = Date.now();
|
|
47316
|
+
this.logDebug("Persisting uploaded file to DB", {
|
|
47317
|
+
fileId: metadata.fileId,
|
|
47318
|
+
filename: metadata.filename
|
|
47319
|
+
});
|
|
47320
|
+
try {
|
|
47321
|
+
const dbRow = FilesMapper.toDbRow({ metadata, variants }, userId);
|
|
47322
|
+
await this.repository.create(dbRow);
|
|
47323
|
+
this.logDebug("File persisted to media table", {
|
|
47324
|
+
fileId: metadata.fileId,
|
|
47325
|
+
filename: metadata.filename
|
|
47326
|
+
});
|
|
47327
|
+
await this.recordOperationMetrics("persistUploadedFile", Date.now() - startTime, true);
|
|
47328
|
+
} catch (error) {
|
|
47329
|
+
await this.recordOperationMetrics("persistUploadedFile", Date.now() - startTime, false);
|
|
47330
|
+
throw error;
|
|
47331
|
+
}
|
|
47332
|
+
}
|
|
47333
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47334
|
+
// NOTE: CRUD and Storage Methods Are Inherited from BaseBackendDomainService
|
|
47335
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47336
|
+
//
|
|
47337
|
+
// CRUD methods:
|
|
47338
|
+
// - getById(id) - for GET /files/:id
|
|
47339
|
+
// - getAll(query) - for listing files
|
|
47340
|
+
// - delete(id) - for DELETE /files/:id
|
|
47341
|
+
// - exists(id) - check if file exists
|
|
47342
|
+
//
|
|
47343
|
+
// Storage methods (inherited):
|
|
47344
|
+
// - uploadFile(params) - for POST /files/upload
|
|
47345
|
+
// - generateFile(params) - for POST /files/generate-document
|
|
47346
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
47347
|
+
};
|
|
47348
|
+
var backendFilesDomainService = new BackendFilesDomainService();
|
|
47349
|
+
var _instance = null;
|
|
47350
|
+
async function getBackendFilesDomainService(config, options) {
|
|
47351
|
+
_instance ??= await BackendFilesDomainService.create(config, options);
|
|
47352
|
+
return _instance;
|
|
47353
|
+
}
|
|
47354
|
+
__name(getBackendFilesDomainService, "getBackendFilesDomainService");
|
|
47355
|
+
|
|
47356
|
+
// src/services/StorageService.ts
|
|
47357
|
+
var logger5 = new logger$1.PackageLogger({ packageName: "core", service: "StorageService" });
|
|
47358
|
+
var StorageService = class _StorageService {
|
|
47359
|
+
constructor() {
|
|
47360
|
+
this.storageService = null;
|
|
47361
|
+
this.config = null;
|
|
47362
|
+
this.initialized = false;
|
|
47363
|
+
}
|
|
47364
|
+
static {
|
|
47365
|
+
__name(this, "StorageService");
|
|
47366
|
+
}
|
|
47367
|
+
static {
|
|
47368
|
+
this.instance = null;
|
|
47369
|
+
}
|
|
47370
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47371
|
+
// Error Handling
|
|
47372
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47373
|
+
/**
|
|
47374
|
+
* Emits a storage error event via CoreEventManager.
|
|
47375
|
+
* Called when storage operations fail to integrate with global error handling.
|
|
47376
|
+
*/
|
|
47377
|
+
emitStorageError(error, operation, options) {
|
|
47378
|
+
const payload = {
|
|
47379
|
+
error,
|
|
47380
|
+
operation,
|
|
47381
|
+
fileId: options?.fileId,
|
|
47382
|
+
filename: options?.filename,
|
|
47383
|
+
recoverable: options?.recoverable ?? false
|
|
47384
|
+
};
|
|
47385
|
+
CoreEventManager.emit(core.CORE_EVENTS.STORAGE.ERROR, payload);
|
|
47386
|
+
}
|
|
47387
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47388
|
+
// Singleton Management
|
|
47389
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47390
|
+
/**
|
|
47391
|
+
* Gets the singleton instance of StorageService
|
|
47392
|
+
*/
|
|
47393
|
+
static getInstance() {
|
|
47394
|
+
_StorageService.instance ??= new _StorageService();
|
|
47395
|
+
return _StorageService.instance;
|
|
47396
|
+
}
|
|
47397
|
+
/**
|
|
47398
|
+
* Checks if the storage service has been initialized
|
|
47399
|
+
*/
|
|
47400
|
+
static isInitialized() {
|
|
47401
|
+
return _StorageService.instance?.initialized ?? false;
|
|
47402
|
+
}
|
|
47403
|
+
/**
|
|
47404
|
+
* Resets the storage service by clearing the singleton instance
|
|
47405
|
+
*/
|
|
47406
|
+
static async reset() {
|
|
47407
|
+
if (_StorageService.instance) {
|
|
47408
|
+
_StorageService.instance.storageService = null;
|
|
47409
|
+
_StorageService.instance.config = null;
|
|
47410
|
+
_StorageService.instance.initialized = false;
|
|
47411
|
+
_StorageService.instance = null;
|
|
47412
|
+
}
|
|
47413
|
+
}
|
|
47414
|
+
/**
|
|
47415
|
+
* Creates merged event handlers that persist uploads to the media table.
|
|
47416
|
+
* Merges Core's internal DB persistence handler with user-provided handlers.
|
|
47417
|
+
*
|
|
47418
|
+
* @param userHandlers - User-provided event handlers from config
|
|
47419
|
+
* @returns Merged handlers with DB persistence + user handlers
|
|
47420
|
+
*/
|
|
47421
|
+
static createMergedEventHandlers(userHandlers) {
|
|
47422
|
+
return {
|
|
47423
|
+
...userHandlers,
|
|
47424
|
+
// Persist uploaded files to media table, then call user handler
|
|
47425
|
+
onFileUploaded: /* @__PURE__ */ __name(async (payload) => {
|
|
47426
|
+
if (payload.metadata) {
|
|
47427
|
+
const filesService = await getBackendFilesDomainService();
|
|
47428
|
+
await filesService.persistUploadedFile(payload.metadata);
|
|
47429
|
+
}
|
|
47430
|
+
if (userHandlers?.onFileUploaded) {
|
|
47431
|
+
await userHandlers.onFileUploaded(payload);
|
|
47432
|
+
}
|
|
47433
|
+
}, "onFileUploaded")
|
|
47434
|
+
};
|
|
47435
|
+
}
|
|
47436
|
+
/**
|
|
47437
|
+
* Initializes the storage service
|
|
47438
|
+
*
|
|
47439
|
+
* @param config - Storage service configuration
|
|
47440
|
+
* @returns The initialized StorageService instance
|
|
47441
|
+
*/
|
|
47442
|
+
static async initialize(config) {
|
|
47443
|
+
const instance = _StorageService.getInstance();
|
|
47444
|
+
if (instance.initialized) {
|
|
47445
|
+
return instance;
|
|
47446
|
+
}
|
|
47447
|
+
instance.config = config;
|
|
47448
|
+
const mergedHandlers = _StorageService.createMergedEventHandlers(config.handlers);
|
|
47449
|
+
const mergedConfig = {
|
|
47450
|
+
...config,
|
|
47451
|
+
handlers: mergedHandlers
|
|
47452
|
+
};
|
|
47453
|
+
logger5.info("[StorageService] Initializing with merged event handlers for DB persistence");
|
|
47454
|
+
instance.storageService = new storage$1.StorageService(mergedConfig);
|
|
47455
|
+
instance.initialized = true;
|
|
47456
|
+
return instance;
|
|
47457
|
+
}
|
|
47458
|
+
/**
|
|
47459
|
+
* Gets the raw underlying storage service instance without error handling wrapper.
|
|
47460
|
+
* Use this only if you need direct access to the underlying service.
|
|
47461
|
+
*
|
|
47462
|
+
* @returns The raw StorageService instance from @plyaz/storage
|
|
47463
|
+
* @throws {StoragePackageError} When storage is not initialized
|
|
47464
|
+
*/
|
|
47465
|
+
getRawStorage() {
|
|
47466
|
+
if (!this.storageService) {
|
|
47467
|
+
throw new errors.StoragePackageError(
|
|
47468
|
+
"Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
|
|
47469
|
+
errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
|
|
46979
47470
|
);
|
|
46980
47471
|
}
|
|
46981
|
-
return this.
|
|
47472
|
+
return this.storageService;
|
|
46982
47473
|
}
|
|
46983
47474
|
// ─────────────────────────────────────────────────────────────────
|
|
46984
47475
|
// Service Access
|
|
46985
47476
|
// ─────────────────────────────────────────────────────────────────
|
|
46986
47477
|
/**
|
|
46987
|
-
* Gets the
|
|
47478
|
+
* Gets the storage service with automatic error handling.
|
|
46988
47479
|
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
46989
|
-
* Any method added to @plyaz/
|
|
47480
|
+
* Any method added to @plyaz/storage will be automatically available.
|
|
46990
47481
|
*
|
|
46991
47482
|
* @example
|
|
46992
47483
|
* ```typescript
|
|
46993
|
-
* const
|
|
46994
|
-
* await
|
|
46995
|
-
* await
|
|
47484
|
+
* const storage = StorageService.getInstance().getStorage();
|
|
47485
|
+
* await storage.uploadFile({ file, filename: 'doc.pdf' });
|
|
47486
|
+
* await storage.deleteFile({ fileId: '123' });
|
|
46996
47487
|
* ```
|
|
46997
47488
|
*
|
|
46998
|
-
* @returns
|
|
47489
|
+
* @returns StorageServiceImpl with automatic error handling
|
|
46999
47490
|
*/
|
|
47000
|
-
|
|
47491
|
+
getStorage() {
|
|
47001
47492
|
const self2 = this;
|
|
47002
47493
|
return new Proxy({}, {
|
|
47003
47494
|
get(_, prop) {
|
|
47004
47495
|
if (typeof prop === "symbol") {
|
|
47005
47496
|
return void 0;
|
|
47006
47497
|
}
|
|
47007
|
-
const
|
|
47008
|
-
const value =
|
|
47498
|
+
const storage = self2.getRawStorage();
|
|
47499
|
+
const value = storage[prop];
|
|
47009
47500
|
if (typeof value !== "function") {
|
|
47010
47501
|
return value;
|
|
47011
47502
|
}
|
|
47012
47503
|
return (...args) => {
|
|
47013
47504
|
try {
|
|
47014
|
-
const result2 = value.apply(
|
|
47505
|
+
const result2 = value.apply(storage, args);
|
|
47015
47506
|
if (result2 instanceof Promise) {
|
|
47016
47507
|
return result2.catch((error) => {
|
|
47017
|
-
self2.
|
|
47508
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47018
47509
|
throw error;
|
|
47019
47510
|
});
|
|
47020
47511
|
}
|
|
47021
47512
|
return result2;
|
|
47022
47513
|
} catch (error) {
|
|
47023
|
-
self2.
|
|
47514
|
+
self2.emitStorageError(error, prop, { recoverable: true });
|
|
47024
47515
|
throw error;
|
|
47025
47516
|
}
|
|
47026
47517
|
};
|
|
@@ -47031,23 +47522,29 @@ var NotificationService = class _NotificationService {
|
|
|
47031
47522
|
// Health Check (special handling for response transformation)
|
|
47032
47523
|
// ─────────────────────────────────────────────────────────────────
|
|
47033
47524
|
/**
|
|
47034
|
-
* Performs a health check on the
|
|
47525
|
+
* Performs a health check on the storage service by checking all adapter health.
|
|
47035
47526
|
* This method has special handling to transform the response format.
|
|
47036
47527
|
*/
|
|
47037
47528
|
async healthCheck() {
|
|
47529
|
+
const startTime = Date.now();
|
|
47038
47530
|
try {
|
|
47039
|
-
const
|
|
47040
|
-
|
|
47531
|
+
const storage = this.getRawStorage();
|
|
47532
|
+
if (typeof storage.checkAllAdaptersHealth === "function") {
|
|
47533
|
+
await storage.checkAllAdaptersHealth();
|
|
47534
|
+
}
|
|
47535
|
+
const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
|
|
47536
|
+
const responseTime = Date.now() - startTime;
|
|
47041
47537
|
return {
|
|
47042
|
-
|
|
47043
|
-
|
|
47044
|
-
|
|
47045
|
-
error:
|
|
47538
|
+
// Check if all adapters are healthy (healthy count equals total count)
|
|
47539
|
+
isHealthy: summary ? summary.healthy === summary.total : true,
|
|
47540
|
+
responseTime,
|
|
47541
|
+
error: void 0
|
|
47046
47542
|
};
|
|
47047
47543
|
} catch (error) {
|
|
47048
|
-
this.
|
|
47544
|
+
this.emitStorageError(error, "healthCheck", { recoverable: true });
|
|
47049
47545
|
return {
|
|
47050
47546
|
isHealthy: false,
|
|
47547
|
+
responseTime: Date.now() - startTime,
|
|
47051
47548
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
47052
47549
|
};
|
|
47053
47550
|
}
|
|
@@ -47062,844 +47559,539 @@ var NotificationService = class _NotificationService {
|
|
|
47062
47559
|
return this.config;
|
|
47063
47560
|
}
|
|
47064
47561
|
/**
|
|
47065
|
-
* Closes the
|
|
47562
|
+
* Closes the storage service and cleans up resources
|
|
47066
47563
|
*/
|
|
47067
47564
|
async close() {
|
|
47068
|
-
this.
|
|
47565
|
+
if (this.storageService) {
|
|
47566
|
+
await this.storageService.destroy();
|
|
47567
|
+
}
|
|
47568
|
+
this.storageService = null;
|
|
47069
47569
|
this.initialized = false;
|
|
47070
47570
|
this.config = null;
|
|
47071
47571
|
}
|
|
47072
47572
|
/**
|
|
47073
|
-
* Creates a dedicated
|
|
47573
|
+
* Creates a dedicated storage service instance (NOT the singleton)
|
|
47074
47574
|
*
|
|
47075
|
-
* Use this when you need an isolated
|
|
47575
|
+
* Use this when you need an isolated storage connection with its own configuration.
|
|
47076
47576
|
*
|
|
47077
|
-
* @param config -
|
|
47078
|
-
* @returns Promise that resolves to a new dedicated
|
|
47577
|
+
* @param config - Storage service configuration
|
|
47578
|
+
* @returns Promise that resolves to a new dedicated StorageService instance
|
|
47079
47579
|
*/
|
|
47080
47580
|
static async createInstance(config) {
|
|
47081
|
-
const dedicatedInstance = new
|
|
47581
|
+
const dedicatedInstance = new _StorageService();
|
|
47082
47582
|
dedicatedInstance.config = config;
|
|
47083
|
-
dedicatedInstance.
|
|
47583
|
+
dedicatedInstance.storageService = new storage$1.StorageService(config);
|
|
47084
47584
|
dedicatedInstance.initialized = true;
|
|
47085
47585
|
return dedicatedInstance;
|
|
47086
47586
|
}
|
|
47087
47587
|
};
|
|
47088
|
-
var
|
|
47089
|
-
|
|
47090
|
-
|
|
47091
|
-
|
|
47092
|
-
|
|
47093
|
-
|
|
47094
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47095
|
-
} catch {
|
|
47096
|
-
try {
|
|
47097
|
-
const currentFile = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
47098
|
-
const currentDir = path.dirname(currentFile);
|
|
47099
|
-
const pkgPath = path.join(currentDir, "..", "package.json");
|
|
47100
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
47101
|
-
cachedVersion = pkg.version ?? "0.0.0";
|
|
47102
|
-
} catch {
|
|
47103
|
-
cachedVersion = "0.0.0";
|
|
47104
|
-
}
|
|
47105
|
-
}
|
|
47106
|
-
return cachedVersion;
|
|
47107
|
-
}
|
|
47108
|
-
__name(getPackageVersion, "getPackageVersion");
|
|
47109
|
-
var VERSION = getPackageVersion();
|
|
47110
|
-
var PACKAGE_NAME = "@plyaz/core";
|
|
47111
|
-
|
|
47112
|
-
// src/backend/index.ts
|
|
47113
|
-
var backend_exports = {};
|
|
47114
|
-
__export(backend_exports, {
|
|
47115
|
-
BACKEND_EXAMPLE_DOMAIN_SERVICE: () => BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47116
|
-
BACKEND_FILES_DOMAIN_SERVICE: () => BACKEND_FILES_DOMAIN_SERVICE,
|
|
47117
|
-
BackendExampleDomainService: () => BackendExampleDomainService,
|
|
47118
|
-
Caching: () => Caching,
|
|
47119
|
-
ErrorHandlingInterceptor: () => ErrorHandlingInterceptor,
|
|
47120
|
-
ExampleController: () => ExampleController,
|
|
47121
|
-
ExampleModule: () => ExampleModule,
|
|
47122
|
-
FeatureDisabled: () => FeatureDisabled,
|
|
47123
|
-
FeatureEnabled: () => FeatureEnabled,
|
|
47124
|
-
FeatureFlagConfigFactory: () => FeatureFlagConfigFactory,
|
|
47125
|
-
FeatureFlagConfigValidator: () => FeatureFlagConfigValidator,
|
|
47126
|
-
FeatureFlagController: () => FeatureFlagController,
|
|
47127
|
-
FeatureFlagDatabaseRepository: () => FeatureFlagDatabaseRepository,
|
|
47128
|
-
FeatureFlagDomainService: () => FeatureFlagDomainService,
|
|
47129
|
-
FeatureFlagGuard: () => FeatureFlagGuard,
|
|
47130
|
-
FeatureFlagLoggingInterceptor: () => FeatureFlagLoggingInterceptor,
|
|
47131
|
-
FeatureFlagMiddleware: () => FeatureFlagMiddleware,
|
|
47132
|
-
FeatureFlagModule: () => FeatureFlagModule,
|
|
47133
|
-
FeatureFlagService: () => FeatureFlagService,
|
|
47134
|
-
FeatureFlagServiceFactory: () => FeatureFlagServiceFactory,
|
|
47135
|
-
FilesController: () => FilesController,
|
|
47136
|
-
FilesModule: () => FilesModule
|
|
47137
|
-
});
|
|
47138
|
-
|
|
47139
|
-
// src/backend/example/example.module.ts
|
|
47140
|
-
var import_common11 = __toESM(require_common(), 1);
|
|
47141
|
-
|
|
47142
|
-
// src/backend/example/example.controller.ts
|
|
47143
|
-
var import_common10 = __toESM(require_common(), 1);
|
|
47144
|
-
var BACKEND_EXAMPLE_DOMAIN_SERVICE = "BACKEND_EXAMPLE_DOMAIN_SERVICE";
|
|
47145
|
-
var ExampleController = class {
|
|
47146
|
-
constructor(exampleService) {
|
|
47147
|
-
this.exampleService = exampleService;
|
|
47148
|
-
}
|
|
47149
|
-
health() {
|
|
47150
|
-
return errors.SuccessResponseStandard("Service is healthy", {
|
|
47151
|
-
service: this.exampleService.isAvailable(),
|
|
47152
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47153
|
-
});
|
|
47154
|
-
}
|
|
47155
|
-
async getEntity(id) {
|
|
47156
|
-
const entity = await this.exampleService.getById(id);
|
|
47157
|
-
return errors.SuccessResponseStandard("Entity retrieved successfully", entity);
|
|
47158
|
-
}
|
|
47159
|
-
async createEntity(dto) {
|
|
47160
|
-
const entity = await this.exampleService.create(dto);
|
|
47161
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47162
|
-
}
|
|
47163
|
-
async updateEntity(id, dto) {
|
|
47164
|
-
const entity = await this.exampleService.patch(id, dto);
|
|
47165
|
-
return errors.SuccessResponseStandard("Entity updated successfully", entity);
|
|
47166
|
-
}
|
|
47167
|
-
async deleteEntity(id) {
|
|
47168
|
-
await this.exampleService.delete(id);
|
|
47169
|
-
return errors.SuccessResponseStandard("Entity deleted successfully", null);
|
|
47170
|
-
}
|
|
47171
|
-
async createEntityWithValidation(dto) {
|
|
47172
|
-
const entity = await this.exampleService.create(dto);
|
|
47173
|
-
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47174
|
-
}
|
|
47175
|
-
async demoSingleError() {
|
|
47176
|
-
return await this.exampleService.demoSingleValidationError();
|
|
47177
|
-
}
|
|
47178
|
-
async demoArrayErrors() {
|
|
47179
|
-
return await this.exampleService.demoMultipleValidationErrors();
|
|
47180
|
-
}
|
|
47181
|
-
async sendEmail(dto) {
|
|
47182
|
-
const result2 = await this.exampleService.sendEmail(dto);
|
|
47183
|
-
return errors.SuccessResponseStandard("Email sent successfully", result2);
|
|
47184
|
-
}
|
|
47185
|
-
};
|
|
47186
|
-
__name(ExampleController, "ExampleController");
|
|
47187
|
-
__decorateClass([
|
|
47188
|
-
(0, import_common10.Get)("health")
|
|
47189
|
-
], ExampleController.prototype, "health", 1);
|
|
47190
|
-
__decorateClass([
|
|
47191
|
-
(0, import_common10.Get)("entities/:id"),
|
|
47192
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47193
|
-
], ExampleController.prototype, "getEntity", 1);
|
|
47194
|
-
__decorateClass([
|
|
47195
|
-
(0, import_common10.Post)("entities"),
|
|
47196
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47197
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47198
|
-
], ExampleController.prototype, "createEntity", 1);
|
|
47199
|
-
__decorateClass([
|
|
47200
|
-
(0, import_common10.Patch)("entities/:id"),
|
|
47201
|
-
__decorateParam(0, (0, import_common10.Param)("id")),
|
|
47202
|
-
__decorateParam(1, (0, import_common10.Body)())
|
|
47203
|
-
], ExampleController.prototype, "updateEntity", 1);
|
|
47204
|
-
__decorateClass([
|
|
47205
|
-
(0, import_common10.Delete)("entities/:id"),
|
|
47206
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47207
|
-
__decorateParam(0, (0, import_common10.Param)("id"))
|
|
47208
|
-
], ExampleController.prototype, "deleteEntity", 1);
|
|
47209
|
-
__decorateClass([
|
|
47210
|
-
(0, import_common10.Post)("entities/validated"),
|
|
47211
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.CREATED),
|
|
47212
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47213
|
-
], ExampleController.prototype, "createEntityWithValidation", 1);
|
|
47214
|
-
__decorateClass([
|
|
47215
|
-
(0, import_common10.Get)("errors/single")
|
|
47216
|
-
], ExampleController.prototype, "demoSingleError", 1);
|
|
47217
|
-
__decorateClass([
|
|
47218
|
-
(0, import_common10.Get)("errors/array")
|
|
47219
|
-
], ExampleController.prototype, "demoArrayErrors", 1);
|
|
47220
|
-
__decorateClass([
|
|
47221
|
-
(0, import_common10.Post)("email"),
|
|
47222
|
-
(0, import_common10.HttpCode)(import_common10.HttpStatus.OK),
|
|
47223
|
-
__decorateParam(0, (0, import_common10.Body)())
|
|
47224
|
-
], ExampleController.prototype, "sendEmail", 1);
|
|
47225
|
-
ExampleController = __decorateClass([
|
|
47226
|
-
(0, import_common10.Controller)("example"),
|
|
47227
|
-
__decorateParam(0, (0, import_common10.Inject)(BACKEND_EXAMPLE_DOMAIN_SERVICE))
|
|
47228
|
-
], ExampleController);
|
|
47229
|
-
|
|
47230
|
-
// src/backend/example/example.module.ts
|
|
47231
|
-
var ExampleModule = class {
|
|
47232
|
-
};
|
|
47233
|
-
__name(ExampleModule, "ExampleModule");
|
|
47234
|
-
ExampleModule = __decorateClass([
|
|
47235
|
-
(0, import_common11.Module)({
|
|
47236
|
-
controllers: [ExampleController],
|
|
47237
|
-
providers: [
|
|
47238
|
-
// Provide BackendExampleDomainService via factory using the singleton instance
|
|
47239
|
-
// This ensures the service is shared across the application
|
|
47240
|
-
{
|
|
47241
|
-
provide: BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47242
|
-
useFactory: /* @__PURE__ */ __name(() => backendExampleDomainService, "useFactory")
|
|
47243
|
-
}
|
|
47244
|
-
],
|
|
47245
|
-
exports: [BACKEND_EXAMPLE_DOMAIN_SERVICE]
|
|
47246
|
-
})
|
|
47247
|
-
], ExampleModule);
|
|
47248
|
-
|
|
47249
|
-
// src/backend/files/files.module.ts
|
|
47250
|
-
var import_common17 = __toESM(require_common(), 1);
|
|
47251
|
-
|
|
47252
|
-
// src/backend/files/files.controller.ts
|
|
47253
|
-
var import_common12 = __toESM(require_common(), 1);
|
|
47254
|
-
var BACKEND_FILES_DOMAIN_SERVICE = "BACKEND_FILES_DOMAIN_SERVICE";
|
|
47255
|
-
var FilesController = class {
|
|
47256
|
-
constructor(filesService) {
|
|
47257
|
-
this.filesService = filesService;
|
|
47258
|
-
}
|
|
47259
|
-
health() {
|
|
47260
|
-
return errors.SuccessResponseStandard("Files service is healthy", {
|
|
47261
|
-
service: this.filesService.isAvailable(),
|
|
47262
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47263
|
-
});
|
|
47264
|
-
}
|
|
47265
|
-
async uploadFile(dto) {
|
|
47266
|
-
const result2 = await this.filesService.uploadFile(dto);
|
|
47267
|
-
return errors.SuccessResponseStandard("File uploaded successfully", result2);
|
|
47268
|
-
}
|
|
47269
|
-
async uploadFiles(dto) {
|
|
47270
|
-
const results = await this.filesService.uploadFiles(dto.files);
|
|
47271
|
-
return errors.SuccessResponseStandard("Files uploaded successfully", results);
|
|
47272
|
-
}
|
|
47273
|
-
async generateDocument(dto) {
|
|
47274
|
-
const buffer = await this.filesService.generateFile(dto);
|
|
47275
|
-
return errors.SuccessResponseStandard("Document generated successfully", {
|
|
47276
|
-
buffer: buffer.toString("base64"),
|
|
47277
|
-
size: buffer.length
|
|
47278
|
-
});
|
|
47279
|
-
}
|
|
47280
|
-
async getFile(id) {
|
|
47281
|
-
const entity = await this.filesService.getById(id);
|
|
47282
|
-
return errors.SuccessResponseStandard("File retrieved", entity);
|
|
47283
|
-
}
|
|
47284
|
-
async downloadFile(id) {
|
|
47285
|
-
const result2 = await this.filesService.downloadFile({ fileId: id });
|
|
47286
|
-
return errors.SuccessResponseStandard("File downloaded", result2);
|
|
47287
|
-
}
|
|
47288
|
-
async getSignedUrl(id) {
|
|
47289
|
-
const result2 = await this.filesService.getSignedUrl({ fileId: id });
|
|
47290
|
-
return errors.SuccessResponseStandard("Signed URL generated", result2);
|
|
47291
|
-
}
|
|
47292
|
-
async deleteFile(id) {
|
|
47293
|
-
await this.filesService.delete(id);
|
|
47294
|
-
return errors.SuccessResponseStandard("File deleted", null);
|
|
47295
|
-
}
|
|
47296
|
-
};
|
|
47297
|
-
__name(FilesController, "FilesController");
|
|
47298
|
-
__decorateClass([
|
|
47299
|
-
(0, import_common12.Get)("health")
|
|
47300
|
-
], FilesController.prototype, "health", 1);
|
|
47301
|
-
__decorateClass([
|
|
47302
|
-
(0, import_common12.Post)("upload"),
|
|
47303
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47304
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47305
|
-
], FilesController.prototype, "uploadFile", 1);
|
|
47306
|
-
__decorateClass([
|
|
47307
|
-
(0, import_common12.Post)("upload/bulk"),
|
|
47308
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47309
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47310
|
-
], FilesController.prototype, "uploadFiles", 1);
|
|
47311
|
-
__decorateClass([
|
|
47312
|
-
(0, import_common12.Post)("generate-document"),
|
|
47313
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47314
|
-
__decorateParam(0, (0, import_common12.Body)())
|
|
47315
|
-
], FilesController.prototype, "generateDocument", 1);
|
|
47316
|
-
__decorateClass([
|
|
47317
|
-
(0, import_common12.Get)(":id"),
|
|
47318
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47319
|
-
], FilesController.prototype, "getFile", 1);
|
|
47320
|
-
__decorateClass([
|
|
47321
|
-
(0, import_common12.Get)(":id/download"),
|
|
47322
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47323
|
-
], FilesController.prototype, "downloadFile", 1);
|
|
47324
|
-
__decorateClass([
|
|
47325
|
-
(0, import_common12.Get)(":id/signed-url"),
|
|
47326
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47327
|
-
], FilesController.prototype, "getSignedUrl", 1);
|
|
47328
|
-
__decorateClass([
|
|
47329
|
-
(0, import_common12.Delete)(":id"),
|
|
47330
|
-
(0, import_common12.HttpCode)(import_common12.HttpStatus.OK),
|
|
47331
|
-
__decorateParam(0, (0, import_common12.Param)("id"))
|
|
47332
|
-
], FilesController.prototype, "deleteFile", 1);
|
|
47333
|
-
FilesController = __decorateClass([
|
|
47334
|
-
(0, import_common12.Controller)("files"),
|
|
47335
|
-
__decorateParam(0, (0, import_common12.Inject)(BACKEND_FILES_DOMAIN_SERVICE))
|
|
47336
|
-
], FilesController);
|
|
47337
|
-
var TABLE_NAME = "media";
|
|
47338
|
-
var DEFAULT_LIMIT2 = 100;
|
|
47339
|
-
var FilesRepository = class _FilesRepository extends db.BaseRepository {
|
|
47340
|
-
static {
|
|
47341
|
-
__name(this, "FilesRepository");
|
|
47342
|
-
}
|
|
47343
|
-
constructor(db) {
|
|
47344
|
-
super(db, TABLE_NAME);
|
|
47345
|
-
}
|
|
47346
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47347
|
-
// Static Factory
|
|
47348
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47349
|
-
/**
|
|
47350
|
-
* Create repository instance.
|
|
47351
|
-
* Uses DbService if initialized.
|
|
47352
|
-
*/
|
|
47353
|
-
static create() {
|
|
47354
|
-
if (!DbService.isInitialized()) {
|
|
47355
|
-
throw new errors.DatabasePackageError(
|
|
47356
|
-
"DbService not initialized. Call DbService.initialize() first.",
|
|
47357
|
-
errors$1.DATABASE_ERROR_CODES.CONNECTION_FAILED
|
|
47358
|
-
);
|
|
47359
|
-
}
|
|
47360
|
-
const db = DbService.getInstance().getDatabase();
|
|
47361
|
-
return new _FilesRepository(db);
|
|
47362
|
-
}
|
|
47363
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47364
|
-
// Overridden Methods (with domain-specific logic)
|
|
47365
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47366
|
-
/**
|
|
47367
|
-
* Find multiple entities with default sorting
|
|
47368
|
-
*/
|
|
47369
|
-
// eslint-disable-next-line complexity
|
|
47370
|
-
async findMany(options, config) {
|
|
47371
|
-
const mergedOptions = {
|
|
47372
|
-
sort: options?.sort ?? [{ field: "created_at", direction: "desc" }],
|
|
47373
|
-
pagination: {
|
|
47374
|
-
limit: options?.pagination?.limit ?? DEFAULT_LIMIT2,
|
|
47375
|
-
offset: options?.pagination?.offset ?? 0
|
|
47376
|
-
},
|
|
47377
|
-
filter: options?.filter
|
|
47378
|
-
};
|
|
47379
|
-
return super.findMany(mergedOptions, config);
|
|
47380
|
-
}
|
|
47381
|
-
/**
|
|
47382
|
-
* Create new file record with auto-generated ID and timestamps
|
|
47383
|
-
*/
|
|
47384
|
-
// eslint-disable-next-line complexity
|
|
47385
|
-
async create(data, config) {
|
|
47386
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
47387
|
-
const id = data.id ?? generateId();
|
|
47388
|
-
const row = {
|
|
47389
|
-
id,
|
|
47390
|
-
user_id: data.user_id ?? "",
|
|
47391
|
-
type: data.type ?? "OTHER",
|
|
47392
|
-
filename: data.filename ?? "",
|
|
47393
|
-
original_filename: data.original_filename ?? data.filename ?? "",
|
|
47394
|
-
mime_type: data.mime_type ?? "application/octet-stream",
|
|
47395
|
-
file_size: data.file_size ?? 0,
|
|
47396
|
-
storage_path: data.storage_path ?? "",
|
|
47397
|
-
cdn_url: data.cdn_url ?? null,
|
|
47398
|
-
width: data.width ?? null,
|
|
47399
|
-
height: data.height ?? null,
|
|
47400
|
-
duration: data.duration ?? null,
|
|
47401
|
-
is_virus_scanned: data.is_virus_scanned ?? false,
|
|
47402
|
-
virus_scan_result: data.virus_scan_result ?? null,
|
|
47403
|
-
metadata: data.metadata ?? null,
|
|
47404
|
-
variants: data.variants ?? null,
|
|
47405
|
-
entity_type: data.entity_type ?? null,
|
|
47406
|
-
entity_id: data.entity_id ?? null,
|
|
47407
|
-
access_level: data.access_level ?? null,
|
|
47408
|
-
created_at: now,
|
|
47409
|
-
updated_at: now,
|
|
47410
|
-
deleted_at: null
|
|
47411
|
-
};
|
|
47412
|
-
return super.create(row, config);
|
|
47413
|
-
}
|
|
47414
|
-
/**
|
|
47415
|
-
* Get the table name for this repository
|
|
47416
|
-
*/
|
|
47417
|
-
getTableName() {
|
|
47418
|
-
return TABLE_NAME;
|
|
47419
|
-
}
|
|
47420
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47421
|
-
// Domain-Specific Methods
|
|
47422
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
47423
|
-
/**
|
|
47424
|
-
* Find all files for a user
|
|
47425
|
-
*/
|
|
47426
|
-
async findByUserId(userId, options) {
|
|
47427
|
-
return this.findMany({
|
|
47428
|
-
filter: { field: "user_id", operator: "eq", value: userId },
|
|
47429
|
-
pagination: {
|
|
47430
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47431
|
-
offset: options?.offset ?? 0
|
|
47432
|
-
}
|
|
47433
|
-
});
|
|
47434
|
-
}
|
|
47435
|
-
/**
|
|
47436
|
-
* Find files for a specific entity (polymorphic association)
|
|
47437
|
-
*/
|
|
47438
|
-
async findByEntityId(entityType, entityId, options) {
|
|
47439
|
-
return this.query().where("entity_type", "eq", entityType).andWhere("entity_id", "eq", entityId).whereNull("deleted_at").orderByDesc("created_at").paginate(
|
|
47440
|
-
Math.floor((options?.offset ?? 0) / (options?.limit ?? DEFAULT_LIMIT2)) + 1,
|
|
47441
|
-
options?.limit ?? DEFAULT_LIMIT2
|
|
47442
|
-
).execute();
|
|
47443
|
-
}
|
|
47444
|
-
/**
|
|
47445
|
-
* Find file by storage path (for deduplication checks)
|
|
47446
|
-
*/
|
|
47447
|
-
async findByStoragePath(storagePath) {
|
|
47448
|
-
return this.findOne({ field: "storage_path", operator: "eq", value: storagePath });
|
|
47449
|
-
}
|
|
47450
|
-
/**
|
|
47451
|
-
* Count files for a user
|
|
47452
|
-
*/
|
|
47453
|
-
async countByUserId(userId) {
|
|
47454
|
-
return this.count({ field: "user_id", operator: "eq", value: userId });
|
|
47455
|
-
}
|
|
47456
|
-
/**
|
|
47457
|
-
* Find files by MIME type
|
|
47458
|
-
*/
|
|
47459
|
-
async findByMimeType(mimeType, options) {
|
|
47460
|
-
return this.findMany({
|
|
47461
|
-
filter: { field: "mime_type", operator: "eq", value: mimeType },
|
|
47462
|
-
pagination: {
|
|
47463
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47464
|
-
offset: options?.offset ?? 0
|
|
47465
|
-
}
|
|
47466
|
-
});
|
|
47467
|
-
}
|
|
47468
|
-
/**
|
|
47469
|
-
* Find files by type (IMAGE, VIDEO, DOCUMENT, AUDIO)
|
|
47470
|
-
*/
|
|
47471
|
-
async findByType(type, options) {
|
|
47472
|
-
return this.findMany({
|
|
47473
|
-
filter: { field: "type", operator: "eq", value: type },
|
|
47474
|
-
pagination: {
|
|
47475
|
-
limit: options?.limit ?? DEFAULT_LIMIT2,
|
|
47476
|
-
offset: options?.offset ?? 0
|
|
47477
|
-
}
|
|
47478
|
-
});
|
|
47588
|
+
var MAX_FAIL_ATTEMPTS = 3;
|
|
47589
|
+
var NotificationService = class _NotificationService {
|
|
47590
|
+
constructor() {
|
|
47591
|
+
this.notificationService = null;
|
|
47592
|
+
this.config = null;
|
|
47593
|
+
this.initialized = false;
|
|
47479
47594
|
}
|
|
47480
|
-
};
|
|
47481
|
-
|
|
47482
|
-
// src/domain/files/mappers/FilesMapper.ts
|
|
47483
|
-
var FilesMapperClass = class _FilesMapperClass extends BaseMapper {
|
|
47484
47595
|
static {
|
|
47485
|
-
__name(this, "
|
|
47486
|
-
}
|
|
47487
|
-
/**
|
|
47488
|
-
* Type guard for UploadResult from event payloads
|
|
47489
|
-
* Validates that the value has the required structure for DB mapping
|
|
47490
|
-
*/
|
|
47491
|
-
static isUploadResult(value) {
|
|
47492
|
-
if (!isObject(value)) return false;
|
|
47493
|
-
const obj = value;
|
|
47494
|
-
if (!isObject(obj.metadata)) return false;
|
|
47495
|
-
const metadata = obj.metadata;
|
|
47496
|
-
return typeof metadata.fileId === "string" && typeof metadata.filename === "string" && typeof metadata.mimeType === "string" && typeof metadata.size === "number" && typeof metadata.path === "string";
|
|
47497
|
-
}
|
|
47498
|
-
/**
|
|
47499
|
-
* Infer file type from MIME type
|
|
47500
|
-
*/
|
|
47501
|
-
static inferFileType(mimeType) {
|
|
47502
|
-
if (mimeType.startsWith("image/")) return "IMAGE";
|
|
47503
|
-
if (mimeType.startsWith("video/")) return "VIDEO";
|
|
47504
|
-
if (mimeType.startsWith("audio/")) return "AUDIO";
|
|
47505
|
-
if (mimeType.includes("pdf") || mimeType.includes("document") || mimeType.includes("text/")) {
|
|
47506
|
-
return "DOCUMENT";
|
|
47507
|
-
}
|
|
47508
|
-
return "OTHER";
|
|
47509
|
-
}
|
|
47510
|
-
/**
|
|
47511
|
-
* API Response → Domain Entity
|
|
47512
|
-
*/
|
|
47513
|
-
toDomain(dto) {
|
|
47514
|
-
const type = _FilesMapperClass.inferFileType(dto.mimeType);
|
|
47515
|
-
return {
|
|
47516
|
-
id: dto.id,
|
|
47517
|
-
key: dto.key,
|
|
47518
|
-
filename: dto.filename,
|
|
47519
|
-
mimeType: dto.mimeType,
|
|
47520
|
-
size: dto.size,
|
|
47521
|
-
checksum: dto.checksum,
|
|
47522
|
-
url: dto.url,
|
|
47523
|
-
publicUrl: dto.publicUrl,
|
|
47524
|
-
signedUrl: dto.signedUrl,
|
|
47525
|
-
bucket: dto.bucket,
|
|
47526
|
-
entityType: dto.entityType,
|
|
47527
|
-
entityId: dto.entityId,
|
|
47528
|
-
category: dto.category,
|
|
47529
|
-
uploadedAt: new Date(dto.uploadedAt),
|
|
47530
|
-
expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : void 0,
|
|
47531
|
-
variants: dto.variants,
|
|
47532
|
-
type,
|
|
47533
|
-
isImage: type === "IMAGE",
|
|
47534
|
-
isVideo: type === "VIDEO",
|
|
47535
|
-
isDocument: type === "DOCUMENT",
|
|
47536
|
-
isAudio: type === "AUDIO"
|
|
47537
|
-
};
|
|
47538
|
-
}
|
|
47539
|
-
/**
|
|
47540
|
-
* Domain Entity → Store State (serializable)
|
|
47541
|
-
*/
|
|
47542
|
-
toStoreState(entity) {
|
|
47543
|
-
return {
|
|
47544
|
-
id: entity.id,
|
|
47545
|
-
key: entity.key,
|
|
47546
|
-
filename: entity.filename,
|
|
47547
|
-
mimeType: entity.mimeType,
|
|
47548
|
-
size: entity.size,
|
|
47549
|
-
url: entity.url,
|
|
47550
|
-
publicUrl: entity.publicUrl,
|
|
47551
|
-
bucket: entity.bucket,
|
|
47552
|
-
entityType: entity.entityType,
|
|
47553
|
-
entityId: entity.entityId,
|
|
47554
|
-
category: entity.category,
|
|
47555
|
-
uploadedAt: entity.uploadedAt.toISOString(),
|
|
47556
|
-
type: entity.type,
|
|
47557
|
-
isImage: entity.isImage,
|
|
47558
|
-
isVideo: entity.isVideo,
|
|
47559
|
-
isDocument: entity.isDocument,
|
|
47560
|
-
isAudio: entity.isAudio
|
|
47561
|
-
};
|
|
47562
|
-
}
|
|
47563
|
-
/**
|
|
47564
|
-
* Store State → Domain Entity
|
|
47565
|
-
*/
|
|
47566
|
-
fromStoreState(state) {
|
|
47567
|
-
return {
|
|
47568
|
-
id: state.id,
|
|
47569
|
-
key: state.key,
|
|
47570
|
-
filename: state.filename,
|
|
47571
|
-
mimeType: state.mimeType,
|
|
47572
|
-
size: state.size,
|
|
47573
|
-
url: state.url,
|
|
47574
|
-
publicUrl: state.publicUrl,
|
|
47575
|
-
bucket: state.bucket,
|
|
47576
|
-
entityType: state.entityType,
|
|
47577
|
-
entityId: state.entityId,
|
|
47578
|
-
category: state.category,
|
|
47579
|
-
uploadedAt: new Date(state.uploadedAt),
|
|
47580
|
-
type: state.type,
|
|
47581
|
-
isImage: state.isImage,
|
|
47582
|
-
isVideo: state.isVideo,
|
|
47583
|
-
isDocument: state.isDocument,
|
|
47584
|
-
isAudio: state.isAudio
|
|
47585
|
-
};
|
|
47586
|
-
}
|
|
47587
|
-
/**
|
|
47588
|
-
* Database Row → API Response (for backend)
|
|
47589
|
-
*/
|
|
47590
|
-
toResponseDTO(row) {
|
|
47591
|
-
return {
|
|
47592
|
-
id: row.id,
|
|
47593
|
-
key: row.storage_path,
|
|
47594
|
-
filename: row.filename,
|
|
47595
|
-
mimeType: row.mime_type,
|
|
47596
|
-
size: toNumber(row.file_size),
|
|
47597
|
-
checksum: void 0,
|
|
47598
|
-
url: row.cdn_url ?? void 0,
|
|
47599
|
-
publicUrl: row.cdn_url ?? void 0,
|
|
47600
|
-
signedUrl: void 0,
|
|
47601
|
-
bucket: "media",
|
|
47602
|
-
entityType: row.entity_type ?? void 0,
|
|
47603
|
-
entityId: row.entity_id ?? void 0,
|
|
47604
|
-
category: void 0,
|
|
47605
|
-
uploadedAt: row.created_at,
|
|
47606
|
-
expiresAt: void 0
|
|
47607
|
-
};
|
|
47608
|
-
}
|
|
47609
|
-
/**
|
|
47610
|
-
* Create GeneratedFileItem from generation result
|
|
47611
|
-
*/
|
|
47612
|
-
toGeneratedFileItem(templateId, buffer, size, outputFormat = "pdf") {
|
|
47613
|
-
return {
|
|
47614
|
-
id: crypto.randomUUID(),
|
|
47615
|
-
templateId,
|
|
47616
|
-
buffer,
|
|
47617
|
-
size,
|
|
47618
|
-
mimeType: `application/${outputFormat}`,
|
|
47619
|
-
filename: `${templateId}.${outputFormat}`,
|
|
47620
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47621
|
-
};
|
|
47622
|
-
}
|
|
47623
|
-
/**
|
|
47624
|
-
* Convert upload result to database row format
|
|
47625
|
-
* Used by event handlers to persist upload results to DB
|
|
47626
|
-
*
|
|
47627
|
-
* @param uploadResult - Result from storage upload
|
|
47628
|
-
* @param userId - User ID who uploaded the file (from auth context)
|
|
47629
|
-
* @returns Partial database row ready for repository.create()
|
|
47630
|
-
*/
|
|
47631
|
-
// eslint-disable-next-line complexity
|
|
47632
|
-
toDbRow(uploadResult, userId) {
|
|
47633
|
-
const { metadata, variants } = uploadResult;
|
|
47634
|
-
return {
|
|
47635
|
-
id: metadata.fileId,
|
|
47636
|
-
user_id: userId ?? "system",
|
|
47637
|
-
type: _FilesMapperClass.inferFileType(metadata.mimeType),
|
|
47638
|
-
filename: metadata.filename,
|
|
47639
|
-
original_filename: metadata.filename,
|
|
47640
|
-
mime_type: metadata.mimeType,
|
|
47641
|
-
file_size: metadata.size,
|
|
47642
|
-
storage_path: metadata.path,
|
|
47643
|
-
cdn_url: metadata.url ?? null,
|
|
47644
|
-
width: metadata.extractedMetadata?.width ?? null,
|
|
47645
|
-
height: metadata.extractedMetadata?.height ?? null,
|
|
47646
|
-
duration: metadata.extractedMetadata?.duration ?? null,
|
|
47647
|
-
entity_type: metadata.entityType,
|
|
47648
|
-
entity_id: metadata.entityId,
|
|
47649
|
-
access_level: metadata.accessLevel,
|
|
47650
|
-
is_virus_scanned: false,
|
|
47651
|
-
virus_scan_result: null,
|
|
47652
|
-
metadata: metadata.customMetadata ?? null,
|
|
47653
|
-
variants: variants ?? null
|
|
47654
|
-
};
|
|
47596
|
+
__name(this, "NotificationService");
|
|
47655
47597
|
}
|
|
47656
|
-
};
|
|
47657
|
-
var FilesMapper = new FilesMapperClass();
|
|
47658
|
-
|
|
47659
|
-
// src/domain/files/validators/FilesValidator.ts
|
|
47660
|
-
var FilesValidatorClass = class extends BaseValidator {
|
|
47661
47598
|
static {
|
|
47662
|
-
|
|
47663
|
-
}
|
|
47664
|
-
constructor() {
|
|
47665
|
-
super({});
|
|
47599
|
+
this.instance = null;
|
|
47666
47600
|
}
|
|
47601
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47602
|
+
// Error Handling
|
|
47603
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47667
47604
|
/**
|
|
47668
|
-
*
|
|
47605
|
+
* Emits a notification error event via CoreEventManager.
|
|
47606
|
+
* Called when notification operations fail to integrate with global error handling.
|
|
47669
47607
|
*/
|
|
47670
|
-
|
|
47671
|
-
|
|
47672
|
-
|
|
47673
|
-
|
|
47674
|
-
|
|
47675
|
-
|
|
47676
|
-
|
|
47677
|
-
};
|
|
47678
|
-
|
|
47679
|
-
|
|
47680
|
-
// src/domain/files/BackendFilesDomainService.ts
|
|
47681
|
-
var BackendFilesDomainService = class _BackendFilesDomainService extends BaseBackendDomainService {
|
|
47682
|
-
constructor(config = {}, injected) {
|
|
47683
|
-
super({
|
|
47684
|
-
serviceName: "BackendFilesDomainService",
|
|
47685
|
-
supportedRuntimes: ["backend"],
|
|
47686
|
-
serviceConfig: {
|
|
47687
|
-
enabled: true,
|
|
47688
|
-
throwOnValidationError: true,
|
|
47689
|
-
throwOnRepositoryError: true,
|
|
47690
|
-
emitEvents: true,
|
|
47691
|
-
...config
|
|
47692
|
-
},
|
|
47693
|
-
mapperClass: FilesMapperClass,
|
|
47694
|
-
validatorClass: FilesValidatorClass,
|
|
47695
|
-
injected
|
|
47696
|
-
});
|
|
47697
|
-
this.eventPrefix = "files";
|
|
47698
|
-
this.cachePrefix = "files";
|
|
47608
|
+
emitNotificationError(error, operation, options) {
|
|
47609
|
+
const payload = {
|
|
47610
|
+
error,
|
|
47611
|
+
operation,
|
|
47612
|
+
recipientId: options?.recipientId,
|
|
47613
|
+
channel: options?.channel,
|
|
47614
|
+
recoverable: options?.recoverable ?? false
|
|
47615
|
+
};
|
|
47616
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
|
|
47699
47617
|
}
|
|
47700
|
-
|
|
47701
|
-
|
|
47618
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47619
|
+
// Merged Event Handlers
|
|
47620
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47621
|
+
/**
|
|
47622
|
+
* Creates merged event handlers that emit to CoreEventManager.
|
|
47623
|
+
* Merges Core's internal handlers with user-provided handlers.
|
|
47624
|
+
*
|
|
47625
|
+
* @param userHandlers - User-provided event handlers from config
|
|
47626
|
+
* @returns Merged handlers with Core event emission + user handlers
|
|
47627
|
+
*/
|
|
47628
|
+
static createMergedEventHandlers(userHandlers) {
|
|
47629
|
+
return {
|
|
47630
|
+
...userHandlers,
|
|
47631
|
+
// Emit to CoreEventManager on sent, then call user handler
|
|
47632
|
+
onSent: /* @__PURE__ */ __name(async (payload) => {
|
|
47633
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.SENT, {
|
|
47634
|
+
notificationId: payload.notificationId,
|
|
47635
|
+
recipientId: payload.recipientId,
|
|
47636
|
+
channel: payload.channel,
|
|
47637
|
+
provider: payload.provider
|
|
47638
|
+
});
|
|
47639
|
+
if (userHandlers?.onSent) {
|
|
47640
|
+
await userHandlers.onSent(payload);
|
|
47641
|
+
}
|
|
47642
|
+
}, "onSent"),
|
|
47643
|
+
// Emit to CoreEventManager on failed, then call user handler
|
|
47644
|
+
onFailed: /* @__PURE__ */ __name(async (payload) => {
|
|
47645
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.FAILED, {
|
|
47646
|
+
notificationId: payload.notificationId,
|
|
47647
|
+
recipientId: payload.recipientId,
|
|
47648
|
+
channel: payload.channel,
|
|
47649
|
+
error: payload.error,
|
|
47650
|
+
retryable: payload.retryCount < MAX_FAIL_ATTEMPTS
|
|
47651
|
+
});
|
|
47652
|
+
if (userHandlers?.onFailed) {
|
|
47653
|
+
await userHandlers.onFailed(payload);
|
|
47654
|
+
}
|
|
47655
|
+
}, "onFailed"),
|
|
47656
|
+
// Emit to CoreEventManager on delivered, then call user handler
|
|
47657
|
+
onDelivered: /* @__PURE__ */ __name(async (payload) => {
|
|
47658
|
+
CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.DELIVERED, {
|
|
47659
|
+
notificationId: payload.notificationId,
|
|
47660
|
+
recipientId: payload.recipientId,
|
|
47661
|
+
channel: payload.channel,
|
|
47662
|
+
deliveredAt: payload.deliveredAt
|
|
47663
|
+
});
|
|
47664
|
+
if (userHandlers?.onDelivered) {
|
|
47665
|
+
await userHandlers.onDelivered(payload);
|
|
47666
|
+
}
|
|
47667
|
+
}, "onDelivered")
|
|
47668
|
+
};
|
|
47702
47669
|
}
|
|
47703
|
-
|
|
47704
|
-
|
|
47670
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47671
|
+
// Singleton Management
|
|
47672
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47673
|
+
/**
|
|
47674
|
+
* Gets the singleton instance of NotificationService
|
|
47675
|
+
*/
|
|
47676
|
+
static getInstance() {
|
|
47677
|
+
_NotificationService.instance ??= new _NotificationService();
|
|
47678
|
+
return _NotificationService.instance;
|
|
47705
47679
|
}
|
|
47706
47680
|
/**
|
|
47707
|
-
*
|
|
47708
|
-
* Throws if DbService is not initialized.
|
|
47681
|
+
* Checks if the notification service has been initialized
|
|
47709
47682
|
*/
|
|
47710
|
-
|
|
47711
|
-
|
|
47712
|
-
return this._repository;
|
|
47683
|
+
static isInitialized() {
|
|
47684
|
+
return _NotificationService.instance?.initialized ?? false;
|
|
47713
47685
|
}
|
|
47714
47686
|
/**
|
|
47715
|
-
*
|
|
47687
|
+
* Resets the notification service by clearing the singleton instance
|
|
47716
47688
|
*/
|
|
47717
|
-
|
|
47718
|
-
|
|
47719
|
-
|
|
47720
|
-
|
|
47721
|
-
|
|
47722
|
-
|
|
47723
|
-
|
|
47724
|
-
storage: options?.storage?.instance,
|
|
47725
|
-
notifications: options?.notifications?.instance
|
|
47726
|
-
};
|
|
47727
|
-
return new _BackendFilesDomainService(config, injected);
|
|
47689
|
+
static async reset() {
|
|
47690
|
+
if (_NotificationService.instance) {
|
|
47691
|
+
_NotificationService.instance.notificationService = null;
|
|
47692
|
+
_NotificationService.instance.config = null;
|
|
47693
|
+
_NotificationService.instance.initialized = false;
|
|
47694
|
+
_NotificationService.instance = null;
|
|
47695
|
+
}
|
|
47728
47696
|
}
|
|
47729
47697
|
/**
|
|
47730
|
-
*
|
|
47731
|
-
* Called by CoreInitializer after storage and DB are initialized.
|
|
47732
|
-
*
|
|
47733
|
-
* Events handled:
|
|
47734
|
-
* - files:upload:uploaded - Persist single file to DB
|
|
47735
|
-
* - files:upload:bulk:uploaded - Persist multiple files to DB
|
|
47736
|
-
*
|
|
47737
|
-
* Deduplication: Uses unique constraint on storage_path.
|
|
47698
|
+
* Initializes the notification service
|
|
47738
47699
|
*
|
|
47739
|
-
* @param
|
|
47700
|
+
* @param config - Notification service configuration
|
|
47701
|
+
* @returns The initialized NotificationService instance
|
|
47740
47702
|
*/
|
|
47741
|
-
static
|
|
47742
|
-
|
|
47743
|
-
|
|
47703
|
+
static async initialize(config) {
|
|
47704
|
+
const instance = _NotificationService.getInstance();
|
|
47705
|
+
if (instance.initialized) {
|
|
47706
|
+
return instance;
|
|
47744
47707
|
}
|
|
47745
|
-
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
47749
|
-
|
|
47750
|
-
if (!isObject(payload)) return void 0;
|
|
47751
|
-
const p = payload;
|
|
47752
|
-
if (!FilesMapperClass.isUploadResult(p.result)) return void 0;
|
|
47753
|
-
return p.result;
|
|
47754
|
-
}, "extractPayload"),
|
|
47755
|
-
isBulk: false,
|
|
47756
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47757
|
-
},
|
|
47758
|
-
"files:upload:bulk:uploaded": {
|
|
47759
|
-
extractPayload: /* @__PURE__ */ __name((payload) => {
|
|
47760
|
-
if (!isObject(payload)) return [];
|
|
47761
|
-
const p = payload;
|
|
47762
|
-
const results = p.result?.results;
|
|
47763
|
-
if (!Array.isArray(results)) return [];
|
|
47764
|
-
return results.filter(FilesMapperClass.isUploadResult);
|
|
47765
|
-
}, "extractPayload"),
|
|
47766
|
-
isBulk: true,
|
|
47767
|
-
validate: /* @__PURE__ */ __name((item) => Boolean(item.metadata?.fileId), "validate")
|
|
47768
|
-
}
|
|
47769
|
-
},
|
|
47770
|
-
loadDependencies: /* @__PURE__ */ __name(async () => ({
|
|
47771
|
-
repository: FilesRepository.create(),
|
|
47772
|
-
mapper: FilesMapper
|
|
47773
|
-
}), "loadDependencies"),
|
|
47774
|
-
mapToDbRow: /* @__PURE__ */ __name((mapper, item) => mapper.toDbRow(item), "mapToDbRow"),
|
|
47775
|
-
createRecord: /* @__PURE__ */ __name(async (repository, dbRow) => {
|
|
47776
|
-
return repository.create(dbRow);
|
|
47777
|
-
}, "createRecord"),
|
|
47778
|
-
getUniqueKey: /* @__PURE__ */ __name((item) => item.metadata.path ?? item.metadata.fileId, "getUniqueKey"),
|
|
47779
|
-
verbose
|
|
47708
|
+
const mergedEvents = _NotificationService.createMergedEventHandlers(config.events);
|
|
47709
|
+
instance.config = config;
|
|
47710
|
+
instance.notificationService = new notifications.NotificationService({
|
|
47711
|
+
...config,
|
|
47712
|
+
events: mergedEvents
|
|
47780
47713
|
});
|
|
47714
|
+
instance.initialized = true;
|
|
47715
|
+
return instance;
|
|
47781
47716
|
}
|
|
47782
|
-
|
|
47783
|
-
|
|
47784
|
-
|
|
47785
|
-
|
|
47786
|
-
|
|
47717
|
+
/**
|
|
47718
|
+
* Gets the raw underlying notification service instance without error handling wrapper.
|
|
47719
|
+
* Use this only if you need direct access to the underlying service.
|
|
47720
|
+
*
|
|
47721
|
+
* @returns The raw NotificationService instance from @plyaz/notifications
|
|
47722
|
+
* @throws {NotificationsPackageError} When notifications is not initialized
|
|
47723
|
+
*/
|
|
47724
|
+
getRawNotifications() {
|
|
47725
|
+
if (!this.notificationService) {
|
|
47726
|
+
throw new errors.NotificationPackageError(
|
|
47727
|
+
"Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
|
|
47728
|
+
errors$1.NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
|
|
47729
|
+
);
|
|
47730
|
+
}
|
|
47731
|
+
return this.notificationService;
|
|
47787
47732
|
}
|
|
47788
|
-
//
|
|
47789
|
-
//
|
|
47790
|
-
//
|
|
47733
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47734
|
+
// Service Access
|
|
47735
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47791
47736
|
/**
|
|
47792
|
-
*
|
|
47793
|
-
*
|
|
47737
|
+
* Gets the notification service with automatic error handling.
|
|
47738
|
+
* All method calls are wrapped with try/catch and emit error events on failure.
|
|
47739
|
+
* Any method added to @plyaz/notifications will be automatically available.
|
|
47794
47740
|
*
|
|
47795
|
-
*
|
|
47796
|
-
*
|
|
47797
|
-
*
|
|
47798
|
-
*
|
|
47799
|
-
*
|
|
47800
|
-
*
|
|
47801
|
-
* 6. Emit success event
|
|
47802
|
-
* 7. Record metrics
|
|
47741
|
+
* @example
|
|
47742
|
+
* ```typescript
|
|
47743
|
+
* const notifications = NotificationService.getInstance().getNotifications();
|
|
47744
|
+
* await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
|
|
47745
|
+
* await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
|
|
47746
|
+
* ```
|
|
47803
47747
|
*
|
|
47804
|
-
* @
|
|
47805
|
-
* @returns Download result with buffer, filename, mimeType
|
|
47748
|
+
* @returns NotificationServiceImpl with automatic error handling
|
|
47806
47749
|
*/
|
|
47807
|
-
|
|
47808
|
-
|
|
47809
|
-
|
|
47810
|
-
|
|
47811
|
-
|
|
47812
|
-
|
|
47813
|
-
|
|
47814
|
-
|
|
47815
|
-
|
|
47816
|
-
|
|
47817
|
-
|
|
47818
|
-
|
|
47750
|
+
getNotifications() {
|
|
47751
|
+
const self2 = this;
|
|
47752
|
+
return new Proxy({}, {
|
|
47753
|
+
get(_, prop) {
|
|
47754
|
+
if (typeof prop === "symbol") {
|
|
47755
|
+
return void 0;
|
|
47756
|
+
}
|
|
47757
|
+
const notifications = self2.getRawNotifications();
|
|
47758
|
+
const value = notifications[prop];
|
|
47759
|
+
if (typeof value !== "function") {
|
|
47760
|
+
return value;
|
|
47761
|
+
}
|
|
47762
|
+
return (...args) => {
|
|
47763
|
+
try {
|
|
47764
|
+
const result2 = value.apply(notifications, args);
|
|
47765
|
+
if (result2 instanceof Promise) {
|
|
47766
|
+
return result2.catch((error) => {
|
|
47767
|
+
self2.emitNotificationError(error, prop, { recoverable: true });
|
|
47768
|
+
throw error;
|
|
47769
|
+
});
|
|
47770
|
+
}
|
|
47771
|
+
return result2;
|
|
47772
|
+
} catch (error) {
|
|
47773
|
+
self2.emitNotificationError(error, prop, { recoverable: true });
|
|
47774
|
+
throw error;
|
|
47775
|
+
}
|
|
47776
|
+
};
|
|
47819
47777
|
}
|
|
47820
|
-
|
|
47821
|
-
|
|
47822
|
-
|
|
47823
|
-
|
|
47824
|
-
|
|
47825
|
-
|
|
47826
|
-
|
|
47827
|
-
|
|
47778
|
+
});
|
|
47779
|
+
}
|
|
47780
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47781
|
+
// Health Check (special handling for response transformation)
|
|
47782
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47783
|
+
/**
|
|
47784
|
+
* Performs a health check on the notification service.
|
|
47785
|
+
* This method has special handling to transform the response format.
|
|
47786
|
+
*/
|
|
47787
|
+
async healthCheck() {
|
|
47788
|
+
try {
|
|
47789
|
+
const notifications = this.getRawNotifications();
|
|
47790
|
+
const result2 = await notifications.healthCheck();
|
|
47791
|
+
return {
|
|
47792
|
+
isHealthy: result2.healthy,
|
|
47793
|
+
providers: result2.providers,
|
|
47794
|
+
// Use optional chaining since error may not exist on all health check results
|
|
47795
|
+
error: "error" in result2 ? result2.error : void 0
|
|
47828
47796
|
};
|
|
47829
|
-
await this.afterDownloadFile?.(response);
|
|
47830
|
-
this.emitEvent("download:downloaded", { result: response });
|
|
47831
|
-
this.emitEvent("complete", { success: true, operation: "downloadFile" });
|
|
47832
|
-
await this.recordOperationMetrics("downloadFile", Date.now() - startTime, true);
|
|
47833
|
-
return response;
|
|
47834
47797
|
} catch (error) {
|
|
47835
|
-
|
|
47836
|
-
|
|
47837
|
-
|
|
47798
|
+
this.emitNotificationError(error, "healthCheck", { recoverable: true });
|
|
47799
|
+
return {
|
|
47800
|
+
isHealthy: false,
|
|
47801
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
47802
|
+
};
|
|
47838
47803
|
}
|
|
47839
47804
|
}
|
|
47805
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47806
|
+
// Lifecycle
|
|
47807
|
+
// ─────────────────────────────────────────────────────────────────
|
|
47840
47808
|
/**
|
|
47841
|
-
*
|
|
47842
|
-
|
|
47809
|
+
* Gets the current configuration
|
|
47810
|
+
*/
|
|
47811
|
+
getConfig() {
|
|
47812
|
+
return this.config;
|
|
47813
|
+
}
|
|
47814
|
+
/**
|
|
47815
|
+
* Closes the notification service and cleans up resources
|
|
47816
|
+
*/
|
|
47817
|
+
async close() {
|
|
47818
|
+
this.notificationService = null;
|
|
47819
|
+
this.initialized = false;
|
|
47820
|
+
this.config = null;
|
|
47821
|
+
}
|
|
47822
|
+
/**
|
|
47823
|
+
* Creates a dedicated notification service instance (NOT the singleton)
|
|
47843
47824
|
*
|
|
47844
|
-
*
|
|
47825
|
+
* Use this when you need an isolated notification service with its own configuration.
|
|
47845
47826
|
*
|
|
47846
|
-
* @param
|
|
47847
|
-
* @returns
|
|
47827
|
+
* @param config - Notification service configuration
|
|
47828
|
+
* @returns Promise that resolves to a new dedicated NotificationService instance
|
|
47848
47829
|
*/
|
|
47849
|
-
|
|
47850
|
-
|
|
47851
|
-
|
|
47852
|
-
|
|
47853
|
-
|
|
47854
|
-
|
|
47830
|
+
static async createInstance(config) {
|
|
47831
|
+
const mergedEvents = _NotificationService.createMergedEventHandlers(config.events);
|
|
47832
|
+
const dedicatedInstance = new _NotificationService();
|
|
47833
|
+
dedicatedInstance.config = config;
|
|
47834
|
+
dedicatedInstance.notificationService = new notifications.NotificationService({
|
|
47835
|
+
...config,
|
|
47836
|
+
events: mergedEvents
|
|
47837
|
+
});
|
|
47838
|
+
dedicatedInstance.initialized = true;
|
|
47839
|
+
return dedicatedInstance;
|
|
47840
|
+
}
|
|
47841
|
+
};
|
|
47842
|
+
var cachedVersion = "";
|
|
47843
|
+
function getPackageVersion() {
|
|
47844
|
+
if (cachedVersion) return cachedVersion;
|
|
47845
|
+
try {
|
|
47846
|
+
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)));
|
|
47847
|
+
const pkg = require2("../package.json");
|
|
47848
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
47849
|
+
} catch {
|
|
47855
47850
|
try {
|
|
47856
|
-
|
|
47857
|
-
|
|
47858
|
-
|
|
47859
|
-
|
|
47860
|
-
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
const result2 = await storage.getSignedUrl({
|
|
47864
|
-
fileId: params.fileId,
|
|
47865
|
-
expiresIn: params.expiresIn ?? config.DOWNLOAD_CONFIG.DEFAULT_SIGNED_URL_EXPIRY_SECONDS,
|
|
47866
|
-
operation: "get"
|
|
47867
|
-
});
|
|
47868
|
-
const response = {
|
|
47869
|
-
url: result2?.url ?? "",
|
|
47870
|
-
expiresAt: result2?.expiresAt?.toISOString() ?? new Date(Date.now() + config.TIME_CONSTANTS.HOUR).toISOString()
|
|
47871
|
-
};
|
|
47872
|
-
await this.afterGetSignedUrl?.(response);
|
|
47873
|
-
this.emitEvent("signedUrl:received", { result: response });
|
|
47874
|
-
this.emitEvent("complete", { success: true, operation: "getSignedUrl" });
|
|
47875
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, true);
|
|
47876
|
-
return response;
|
|
47877
|
-
} catch (error) {
|
|
47878
|
-
await this.recordOperationMetrics("getSignedUrl", Date.now() - startTime, false);
|
|
47879
|
-
this.emitEvent("signedUrl:error", { error });
|
|
47880
|
-
throw error;
|
|
47851
|
+
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)));
|
|
47852
|
+
const currentDir = path.dirname(currentFile);
|
|
47853
|
+
const pkgPath = path.join(currentDir, "..", "package.json");
|
|
47854
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
47855
|
+
cachedVersion = pkg.version ?? "0.0.0";
|
|
47856
|
+
} catch {
|
|
47857
|
+
cachedVersion = "0.0.0";
|
|
47881
47858
|
}
|
|
47882
47859
|
}
|
|
47883
|
-
|
|
47884
|
-
|
|
47885
|
-
|
|
47886
|
-
|
|
47887
|
-
|
|
47888
|
-
|
|
47889
|
-
|
|
47890
|
-
|
|
47891
|
-
|
|
47892
|
-
|
|
47893
|
-
|
|
47894
|
-
|
|
47895
|
-
|
|
47896
|
-
|
|
47860
|
+
return cachedVersion;
|
|
47861
|
+
}
|
|
47862
|
+
__name(getPackageVersion, "getPackageVersion");
|
|
47863
|
+
var VERSION = getPackageVersion();
|
|
47864
|
+
var PACKAGE_NAME = "@plyaz/core";
|
|
47865
|
+
|
|
47866
|
+
// src/backend/index.ts
|
|
47867
|
+
var backend_exports = {};
|
|
47868
|
+
__export(backend_exports, {
|
|
47869
|
+
BACKEND_EXAMPLE_DOMAIN_SERVICE: () => BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47870
|
+
BACKEND_FILES_DOMAIN_SERVICE: () => BACKEND_FILES_DOMAIN_SERVICE,
|
|
47871
|
+
BackendExampleDomainService: () => BackendExampleDomainService,
|
|
47872
|
+
Caching: () => Caching,
|
|
47873
|
+
ErrorHandlingInterceptor: () => ErrorHandlingInterceptor,
|
|
47874
|
+
ExampleController: () => ExampleController,
|
|
47875
|
+
ExampleModule: () => ExampleModule,
|
|
47876
|
+
FeatureDisabled: () => FeatureDisabled,
|
|
47877
|
+
FeatureEnabled: () => FeatureEnabled,
|
|
47878
|
+
FeatureFlagConfigFactory: () => FeatureFlagConfigFactory,
|
|
47879
|
+
FeatureFlagConfigValidator: () => FeatureFlagConfigValidator,
|
|
47880
|
+
FeatureFlagController: () => FeatureFlagController,
|
|
47881
|
+
FeatureFlagDatabaseRepository: () => FeatureFlagDatabaseRepository,
|
|
47882
|
+
FeatureFlagDomainService: () => FeatureFlagDomainService,
|
|
47883
|
+
FeatureFlagGuard: () => FeatureFlagGuard,
|
|
47884
|
+
FeatureFlagLoggingInterceptor: () => FeatureFlagLoggingInterceptor,
|
|
47885
|
+
FeatureFlagMiddleware: () => FeatureFlagMiddleware,
|
|
47886
|
+
FeatureFlagModule: () => FeatureFlagModule,
|
|
47887
|
+
FeatureFlagService: () => FeatureFlagService,
|
|
47888
|
+
FeatureFlagServiceFactory: () => FeatureFlagServiceFactory,
|
|
47889
|
+
FilesController: () => FilesController,
|
|
47890
|
+
FilesModule: () => FilesModule
|
|
47891
|
+
});
|
|
47892
|
+
|
|
47893
|
+
// src/backend/example/example.module.ts
|
|
47894
|
+
var import_common14 = __toESM(require_common(), 1);
|
|
47895
|
+
|
|
47896
|
+
// src/backend/example/example.controller.ts
|
|
47897
|
+
var import_common13 = __toESM(require_common(), 1);
|
|
47898
|
+
var BACKEND_EXAMPLE_DOMAIN_SERVICE = "BACKEND_EXAMPLE_DOMAIN_SERVICE";
|
|
47899
|
+
var ExampleController = class {
|
|
47900
|
+
constructor(exampleService) {
|
|
47901
|
+
this.exampleService = exampleService;
|
|
47902
|
+
}
|
|
47903
|
+
health() {
|
|
47904
|
+
return errors.SuccessResponseStandard("Service is healthy", {
|
|
47905
|
+
service: this.exampleService.isAvailable(),
|
|
47906
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
47907
|
+
});
|
|
47908
|
+
}
|
|
47909
|
+
async getEntity(id) {
|
|
47910
|
+
const entity = await this.exampleService.getById(id);
|
|
47911
|
+
return errors.SuccessResponseStandard("Entity retrieved successfully", entity);
|
|
47912
|
+
}
|
|
47913
|
+
async createEntity(dto) {
|
|
47914
|
+
const entity = await this.exampleService.create(dto);
|
|
47915
|
+
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47916
|
+
}
|
|
47917
|
+
async updateEntity(id, dto) {
|
|
47918
|
+
const entity = await this.exampleService.patch(id, dto);
|
|
47919
|
+
return errors.SuccessResponseStandard("Entity updated successfully", entity);
|
|
47920
|
+
}
|
|
47921
|
+
async deleteEntity(id) {
|
|
47922
|
+
await this.exampleService.delete(id);
|
|
47923
|
+
return errors.SuccessResponseStandard("Entity deleted successfully", null);
|
|
47924
|
+
}
|
|
47925
|
+
async createEntityWithValidation(dto) {
|
|
47926
|
+
const entity = await this.exampleService.create(dto);
|
|
47927
|
+
return errors.SuccessResponseStandard("Entity created successfully", entity, types.HTTP_STATUS.CREATED);
|
|
47928
|
+
}
|
|
47929
|
+
async demoSingleError() {
|
|
47930
|
+
return await this.exampleService.demoSingleValidationError();
|
|
47931
|
+
}
|
|
47932
|
+
async demoArrayErrors() {
|
|
47933
|
+
return await this.exampleService.demoMultipleValidationErrors();
|
|
47934
|
+
}
|
|
47935
|
+
async sendEmail(dto) {
|
|
47936
|
+
const result2 = await this.exampleService.sendEmail(dto);
|
|
47937
|
+
return errors.SuccessResponseStandard("Email sent successfully", result2);
|
|
47938
|
+
}
|
|
47897
47939
|
};
|
|
47898
|
-
|
|
47899
|
-
|
|
47940
|
+
__name(ExampleController, "ExampleController");
|
|
47941
|
+
__decorateClass([
|
|
47942
|
+
(0, import_common13.Get)("health")
|
|
47943
|
+
], ExampleController.prototype, "health", 1);
|
|
47944
|
+
__decorateClass([
|
|
47945
|
+
(0, import_common13.Get)("entities/:id"),
|
|
47946
|
+
__decorateParam(0, (0, import_common13.Param)("id"))
|
|
47947
|
+
], ExampleController.prototype, "getEntity", 1);
|
|
47948
|
+
__decorateClass([
|
|
47949
|
+
(0, import_common13.Post)("entities"),
|
|
47950
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.CREATED),
|
|
47951
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47952
|
+
], ExampleController.prototype, "createEntity", 1);
|
|
47953
|
+
__decorateClass([
|
|
47954
|
+
(0, import_common13.Patch)("entities/:id"),
|
|
47955
|
+
__decorateParam(0, (0, import_common13.Param)("id")),
|
|
47956
|
+
__decorateParam(1, (0, import_common13.Body)())
|
|
47957
|
+
], ExampleController.prototype, "updateEntity", 1);
|
|
47958
|
+
__decorateClass([
|
|
47959
|
+
(0, import_common13.Delete)("entities/:id"),
|
|
47960
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.OK),
|
|
47961
|
+
__decorateParam(0, (0, import_common13.Param)("id"))
|
|
47962
|
+
], ExampleController.prototype, "deleteEntity", 1);
|
|
47963
|
+
__decorateClass([
|
|
47964
|
+
(0, import_common13.Post)("entities/validated"),
|
|
47965
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.CREATED),
|
|
47966
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47967
|
+
], ExampleController.prototype, "createEntityWithValidation", 1);
|
|
47968
|
+
__decorateClass([
|
|
47969
|
+
(0, import_common13.Get)("errors/single")
|
|
47970
|
+
], ExampleController.prototype, "demoSingleError", 1);
|
|
47971
|
+
__decorateClass([
|
|
47972
|
+
(0, import_common13.Get)("errors/array")
|
|
47973
|
+
], ExampleController.prototype, "demoArrayErrors", 1);
|
|
47974
|
+
__decorateClass([
|
|
47975
|
+
(0, import_common13.Post)("email"),
|
|
47976
|
+
(0, import_common13.HttpCode)(import_common13.HttpStatus.OK),
|
|
47977
|
+
__decorateParam(0, (0, import_common13.Body)())
|
|
47978
|
+
], ExampleController.prototype, "sendEmail", 1);
|
|
47979
|
+
ExampleController = __decorateClass([
|
|
47980
|
+
(0, import_common13.Controller)("example"),
|
|
47981
|
+
__decorateParam(0, (0, import_common13.Inject)(BACKEND_EXAMPLE_DOMAIN_SERVICE))
|
|
47982
|
+
], ExampleController);
|
|
47983
|
+
|
|
47984
|
+
// src/backend/example/example.module.ts
|
|
47985
|
+
var ExampleModule = class {
|
|
47986
|
+
};
|
|
47987
|
+
__name(ExampleModule, "ExampleModule");
|
|
47988
|
+
ExampleModule = __decorateClass([
|
|
47989
|
+
(0, import_common14.Module)({
|
|
47990
|
+
controllers: [ExampleController],
|
|
47991
|
+
providers: [
|
|
47992
|
+
// Provide BackendExampleDomainService via factory using the singleton instance
|
|
47993
|
+
// This ensures the service is shared across the application
|
|
47994
|
+
{
|
|
47995
|
+
provide: BACKEND_EXAMPLE_DOMAIN_SERVICE,
|
|
47996
|
+
useFactory: /* @__PURE__ */ __name(() => backendExampleDomainService, "useFactory")
|
|
47997
|
+
}
|
|
47998
|
+
],
|
|
47999
|
+
exports: [BACKEND_EXAMPLE_DOMAIN_SERVICE]
|
|
48000
|
+
})
|
|
48001
|
+
], ExampleModule);
|
|
48002
|
+
|
|
48003
|
+
// src/backend/files/files.module.ts
|
|
48004
|
+
var import_common16 = __toESM(require_common(), 1);
|
|
48005
|
+
|
|
48006
|
+
// src/backend/files/files.controller.ts
|
|
48007
|
+
var import_common15 = __toESM(require_common(), 1);
|
|
48008
|
+
var BACKEND_FILES_DOMAIN_SERVICE = "BACKEND_FILES_DOMAIN_SERVICE";
|
|
48009
|
+
var FilesController = class {
|
|
48010
|
+
constructor(filesService) {
|
|
48011
|
+
this.filesService = filesService;
|
|
48012
|
+
}
|
|
48013
|
+
health() {
|
|
48014
|
+
return errors.SuccessResponseStandard("Files service is healthy", {
|
|
48015
|
+
service: this.filesService.isAvailable(),
|
|
48016
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
48017
|
+
});
|
|
48018
|
+
}
|
|
48019
|
+
async uploadFile(dto) {
|
|
48020
|
+
const result2 = await this.filesService.uploadFile(dto);
|
|
48021
|
+
return errors.SuccessResponseStandard("File uploaded successfully", result2);
|
|
48022
|
+
}
|
|
48023
|
+
async uploadFiles(dto) {
|
|
48024
|
+
const results = await this.filesService.uploadFiles(dto.files);
|
|
48025
|
+
return errors.SuccessResponseStandard("Files uploaded successfully", results);
|
|
48026
|
+
}
|
|
48027
|
+
async generateDocument(dto) {
|
|
48028
|
+
const buffer = await this.filesService.generateFile(dto);
|
|
48029
|
+
return errors.SuccessResponseStandard("Document generated successfully", {
|
|
48030
|
+
buffer: buffer.toString("base64"),
|
|
48031
|
+
size: buffer.length
|
|
48032
|
+
});
|
|
48033
|
+
}
|
|
48034
|
+
async getFile(id) {
|
|
48035
|
+
const entity = await this.filesService.getById(id);
|
|
48036
|
+
return errors.SuccessResponseStandard("File retrieved", entity);
|
|
48037
|
+
}
|
|
48038
|
+
async downloadFile(id) {
|
|
48039
|
+
const result2 = await this.filesService.downloadFile({ fileId: id });
|
|
48040
|
+
return errors.SuccessResponseStandard("File downloaded", result2);
|
|
48041
|
+
}
|
|
48042
|
+
async getSignedUrl(id) {
|
|
48043
|
+
const result2 = await this.filesService.getSignedUrl({ fileId: id });
|
|
48044
|
+
return errors.SuccessResponseStandard("Signed URL generated", result2);
|
|
48045
|
+
}
|
|
48046
|
+
async deleteFile(id) {
|
|
48047
|
+
await this.filesService.delete(id);
|
|
48048
|
+
return errors.SuccessResponseStandard("File deleted", null);
|
|
48049
|
+
}
|
|
48050
|
+
};
|
|
48051
|
+
__name(FilesController, "FilesController");
|
|
48052
|
+
__decorateClass([
|
|
48053
|
+
(0, import_common15.Get)("health")
|
|
48054
|
+
], FilesController.prototype, "health", 1);
|
|
48055
|
+
__decorateClass([
|
|
48056
|
+
(0, import_common15.Post)("upload"),
|
|
48057
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48058
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48059
|
+
], FilesController.prototype, "uploadFile", 1);
|
|
48060
|
+
__decorateClass([
|
|
48061
|
+
(0, import_common15.Post)("upload/bulk"),
|
|
48062
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48063
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48064
|
+
], FilesController.prototype, "uploadFiles", 1);
|
|
48065
|
+
__decorateClass([
|
|
48066
|
+
(0, import_common15.Post)("generate-document"),
|
|
48067
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48068
|
+
__decorateParam(0, (0, import_common15.Body)())
|
|
48069
|
+
], FilesController.prototype, "generateDocument", 1);
|
|
48070
|
+
__decorateClass([
|
|
48071
|
+
(0, import_common15.Get)(":id"),
|
|
48072
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48073
|
+
], FilesController.prototype, "getFile", 1);
|
|
48074
|
+
__decorateClass([
|
|
48075
|
+
(0, import_common15.Get)(":id/download"),
|
|
48076
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48077
|
+
], FilesController.prototype, "downloadFile", 1);
|
|
48078
|
+
__decorateClass([
|
|
48079
|
+
(0, import_common15.Get)(":id/signed-url"),
|
|
48080
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48081
|
+
], FilesController.prototype, "getSignedUrl", 1);
|
|
48082
|
+
__decorateClass([
|
|
48083
|
+
(0, import_common15.Delete)(":id"),
|
|
48084
|
+
(0, import_common15.HttpCode)(import_common15.HttpStatus.OK),
|
|
48085
|
+
__decorateParam(0, (0, import_common15.Param)("id"))
|
|
48086
|
+
], FilesController.prototype, "deleteFile", 1);
|
|
48087
|
+
FilesController = __decorateClass([
|
|
48088
|
+
(0, import_common15.Controller)("files"),
|
|
48089
|
+
__decorateParam(0, (0, import_common15.Inject)(BACKEND_FILES_DOMAIN_SERVICE))
|
|
48090
|
+
], FilesController);
|
|
48091
|
+
var logger6 = new logger$1.PackageLogger({ packageName: "core", service: "FrontendFilesDomainService" });
|
|
47900
48092
|
var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseFrontendDomainService {
|
|
47901
48093
|
constructor(config = {}, options) {
|
|
47902
|
-
const apiBasePath = config.apiBasePath || "
|
|
48094
|
+
const apiBasePath = config.apiBasePath || "";
|
|
47903
48095
|
super({
|
|
47904
48096
|
serviceName: "FrontendFilesDomainService",
|
|
47905
48097
|
supportedRuntimes: ["frontend"],
|
|
@@ -47962,7 +48154,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47962
48154
|
// The ?? operator only falls through on null/undefined, not empty strings.
|
|
47963
48155
|
// An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
|
|
47964
48156
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
47965
|
-
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "
|
|
48157
|
+
apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || ""
|
|
47966
48158
|
};
|
|
47967
48159
|
return new _FrontendFilesDomainService(mergedConfig, options);
|
|
47968
48160
|
}
|
|
@@ -47999,7 +48191,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
47999
48191
|
*/
|
|
48000
48192
|
static registerEventHandlers(verbose) {
|
|
48001
48193
|
if (this._eventHandlersRegistered) {
|
|
48002
|
-
|
|
48194
|
+
logger6.debug("Files frontend event handlers already registered");
|
|
48003
48195
|
return () => {
|
|
48004
48196
|
};
|
|
48005
48197
|
}
|
|
@@ -48061,7 +48253,7 @@ var FrontendFilesDomainService = class _FrontendFilesDomainService extends BaseF
|
|
|
48061
48253
|
verbose
|
|
48062
48254
|
});
|
|
48063
48255
|
this._eventHandlersRegistered = true;
|
|
48064
|
-
|
|
48256
|
+
logger6.info("Files frontend event handlers registered");
|
|
48065
48257
|
return () => {
|
|
48066
48258
|
FrontendEventPersistenceHandler.unregisterAll();
|
|
48067
48259
|
this._eventHandlersRegistered = false;
|
|
@@ -48139,7 +48331,7 @@ var FilesModule = class {
|
|
|
48139
48331
|
};
|
|
48140
48332
|
__name(FilesModule, "FilesModule");
|
|
48141
48333
|
FilesModule = __decorateClass([
|
|
48142
|
-
(0,
|
|
48334
|
+
(0, import_common16.Module)({
|
|
48143
48335
|
controllers: [FilesController],
|
|
48144
48336
|
providers: [
|
|
48145
48337
|
// Provide BackendFilesDomainService via factory using the singleton instance
|
|
@@ -48430,10 +48622,10 @@ var FeatureFlagDomainService = class extends BaseDomainService {
|
|
|
48430
48622
|
};
|
|
48431
48623
|
|
|
48432
48624
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
48433
|
-
var
|
|
48625
|
+
var import_common18 = __toESM(require_common(), 1);
|
|
48434
48626
|
|
|
48435
48627
|
// src/backend/featureFlags/feature-flag.controller.ts
|
|
48436
|
-
var
|
|
48628
|
+
var import_common17 = __toESM(require_common(), 1);
|
|
48437
48629
|
var FeatureFlagController = class {
|
|
48438
48630
|
constructor(featureFlagService) {
|
|
48439
48631
|
this.featureFlagService = featureFlagService;
|
|
@@ -48562,54 +48754,54 @@ var FeatureFlagController = class {
|
|
|
48562
48754
|
};
|
|
48563
48755
|
__name(FeatureFlagController, "FeatureFlagController");
|
|
48564
48756
|
__decorateClass([
|
|
48565
|
-
(0,
|
|
48566
|
-
__decorateParam(0, (0,
|
|
48567
|
-
__decorateParam(1, (0,
|
|
48757
|
+
(0, import_common17.Post)(":key/evaluate"),
|
|
48758
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48759
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48568
48760
|
], FeatureFlagController.prototype, "evaluateFlag", 1);
|
|
48569
48761
|
__decorateClass([
|
|
48570
|
-
(0,
|
|
48571
|
-
__decorateParam(0, (0,
|
|
48572
|
-
__decorateParam(1, (0,
|
|
48762
|
+
(0, import_common17.Post)(":key/enabled"),
|
|
48763
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48764
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48573
48765
|
], FeatureFlagController.prototype, "isEnabled", 1);
|
|
48574
48766
|
__decorateClass([
|
|
48575
|
-
(0,
|
|
48576
|
-
__decorateParam(0, (0,
|
|
48767
|
+
(0, import_common17.Post)("evaluate-all"),
|
|
48768
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48577
48769
|
], FeatureFlagController.prototype, "evaluateAllFlags", 1);
|
|
48578
48770
|
__decorateClass([
|
|
48579
|
-
(0,
|
|
48580
|
-
__decorateParam(0, (0,
|
|
48771
|
+
(0, import_common17.Post)(),
|
|
48772
|
+
__decorateParam(0, (0, import_common17.Body)())
|
|
48581
48773
|
], FeatureFlagController.prototype, "createFlag", 1);
|
|
48582
48774
|
__decorateClass([
|
|
48583
|
-
(0,
|
|
48584
|
-
__decorateParam(0, (0,
|
|
48585
|
-
__decorateParam(1, (0,
|
|
48775
|
+
(0, import_common17.Put)(":key"),
|
|
48776
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48777
|
+
__decorateParam(1, (0, import_common17.Body)())
|
|
48586
48778
|
], FeatureFlagController.prototype, "updateFlag", 1);
|
|
48587
48779
|
__decorateClass([
|
|
48588
|
-
(0,
|
|
48589
|
-
__decorateParam(0, (0,
|
|
48780
|
+
(0, import_common17.Delete)(":key"),
|
|
48781
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48590
48782
|
], FeatureFlagController.prototype, "deleteFlag", 1);
|
|
48591
48783
|
__decorateClass([
|
|
48592
|
-
(0,
|
|
48593
|
-
__decorateParam(0, (0,
|
|
48594
|
-
__decorateParam(1, (0,
|
|
48784
|
+
(0, import_common17.Post)(":key/override"),
|
|
48785
|
+
__decorateParam(0, (0, import_common17.Param)("key")),
|
|
48786
|
+
__decorateParam(1, (0, import_common17.Body)("value"))
|
|
48595
48787
|
], FeatureFlagController.prototype, "setOverride", 1);
|
|
48596
48788
|
__decorateClass([
|
|
48597
|
-
(0,
|
|
48598
|
-
__decorateParam(0, (0,
|
|
48789
|
+
(0, import_common17.Delete)(":key/override"),
|
|
48790
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48599
48791
|
], FeatureFlagController.prototype, "removeOverride", 1);
|
|
48600
48792
|
__decorateClass([
|
|
48601
|
-
(0,
|
|
48602
|
-
__decorateParam(0, (0,
|
|
48793
|
+
(0, import_common17.Get)(":key/rules"),
|
|
48794
|
+
__decorateParam(0, (0, import_common17.Param)("key"))
|
|
48603
48795
|
], FeatureFlagController.prototype, "getFlagRules", 1);
|
|
48604
48796
|
__decorateClass([
|
|
48605
|
-
(0,
|
|
48797
|
+
(0, import_common17.Post)("refresh")
|
|
48606
48798
|
], FeatureFlagController.prototype, "refreshCache", 1);
|
|
48607
48799
|
__decorateClass([
|
|
48608
|
-
(0,
|
|
48800
|
+
(0, import_common17.Get)("health")
|
|
48609
48801
|
], FeatureFlagController.prototype, "getHealth", 1);
|
|
48610
48802
|
FeatureFlagController = __decorateClass([
|
|
48611
|
-
(0,
|
|
48612
|
-
__decorateParam(0, (0,
|
|
48803
|
+
(0, import_common17.Controller)("feature-flags"),
|
|
48804
|
+
__decorateParam(0, (0, import_common17.Inject)(FEATURE_FLAG_SERVICE))
|
|
48613
48805
|
], FeatureFlagController);
|
|
48614
48806
|
|
|
48615
48807
|
// src/backend/featureFlags/feature-flag.module.ts
|
|
@@ -48701,16 +48893,16 @@ var FeatureFlagModule = class {
|
|
|
48701
48893
|
__name(FeatureFlagModule, "FeatureFlagModule");
|
|
48702
48894
|
FeatureFlagModule.serviceInstance = null;
|
|
48703
48895
|
FeatureFlagModule = __decorateClass([
|
|
48704
|
-
(0,
|
|
48705
|
-
(0,
|
|
48896
|
+
(0, import_common18.Global)(),
|
|
48897
|
+
(0, import_common18.Module)({
|
|
48706
48898
|
controllers: [FeatureFlagController]
|
|
48707
48899
|
})
|
|
48708
48900
|
], FeatureFlagModule);
|
|
48709
48901
|
|
|
48710
48902
|
// src/backend/featureFlags/decorators/feature-flag.decorator.ts
|
|
48711
|
-
var
|
|
48903
|
+
var import_common19 = __toESM(require_common(), 1);
|
|
48712
48904
|
function FeatureFlag(key, expected = true) {
|
|
48713
|
-
return (0,
|
|
48905
|
+
return (0, import_common19.SetMetadata)(types.FEATURE_FLAG_METADATA.FLAG_CHECK, { key, expected });
|
|
48714
48906
|
}
|
|
48715
48907
|
__name(FeatureFlag, "FeatureFlag");
|
|
48716
48908
|
|
|
@@ -48727,7 +48919,7 @@ function FeatureEnabled(key) {
|
|
|
48727
48919
|
__name(FeatureEnabled, "FeatureEnabled");
|
|
48728
48920
|
|
|
48729
48921
|
// src/backend/featureFlags/guards/feature-flag.guard.ts
|
|
48730
|
-
var
|
|
48922
|
+
var import_common20 = __toESM(require_common(), 1);
|
|
48731
48923
|
var FeatureFlagGuard = class {
|
|
48732
48924
|
constructor(reflector, featureFlagService) {
|
|
48733
48925
|
this.reflector = reflector;
|
|
@@ -48771,12 +48963,12 @@ var FeatureFlagGuard = class {
|
|
|
48771
48963
|
};
|
|
48772
48964
|
__name(FeatureFlagGuard, "FeatureFlagGuard");
|
|
48773
48965
|
FeatureFlagGuard = __decorateClass([
|
|
48774
|
-
(0,
|
|
48775
|
-
__decorateParam(1, (0,
|
|
48966
|
+
(0, import_common20.Injectable)(),
|
|
48967
|
+
__decorateParam(1, (0, import_common20.Inject)(FEATURE_FLAG_SERVICE))
|
|
48776
48968
|
], FeatureFlagGuard);
|
|
48777
48969
|
|
|
48778
48970
|
// src/backend/featureFlags/middleware/feature-flag-middleware.ts
|
|
48779
|
-
var
|
|
48971
|
+
var import_common21 = __toESM(require_common(), 1);
|
|
48780
48972
|
function isFeatureFlagKey(value) {
|
|
48781
48973
|
return Object.keys(config.FEATURES).includes(value);
|
|
48782
48974
|
}
|
|
@@ -48854,12 +49046,12 @@ var FeatureFlagMiddleware = class {
|
|
|
48854
49046
|
};
|
|
48855
49047
|
__name(FeatureFlagMiddleware, "FeatureFlagMiddleware");
|
|
48856
49048
|
FeatureFlagMiddleware = __decorateClass([
|
|
48857
|
-
(0,
|
|
48858
|
-
__decorateParam(0, (0,
|
|
49049
|
+
(0, import_common21.Injectable)(),
|
|
49050
|
+
__decorateParam(0, (0, import_common21.Inject)(FEATURE_FLAG_SERVICE))
|
|
48859
49051
|
], FeatureFlagMiddleware);
|
|
48860
49052
|
|
|
48861
49053
|
// src/backend/featureFlags/interceptors/feature-flag-logging-interceptor.ts
|
|
48862
|
-
var
|
|
49054
|
+
var import_common22 = __toESM(require_common(), 1);
|
|
48863
49055
|
var import_rxjs = __toESM(require_cjs(), 1);
|
|
48864
49056
|
var FeatureFlagLoggingInterceptor = class {
|
|
48865
49057
|
constructor() {
|
|
@@ -48892,11 +49084,11 @@ var FeatureFlagLoggingInterceptor = class {
|
|
|
48892
49084
|
};
|
|
48893
49085
|
__name(FeatureFlagLoggingInterceptor, "FeatureFlagLoggingInterceptor");
|
|
48894
49086
|
FeatureFlagLoggingInterceptor = __decorateClass([
|
|
48895
|
-
(0,
|
|
49087
|
+
(0, import_common22.Injectable)()
|
|
48896
49088
|
], FeatureFlagLoggingInterceptor);
|
|
48897
49089
|
|
|
48898
49090
|
// src/backend/featureFlags/interceptors/error-handling-interceptor.ts
|
|
48899
|
-
var
|
|
49091
|
+
var import_common23 = __toESM(require_common(), 1);
|
|
48900
49092
|
var import_operators = __toESM(require_operators(), 1);
|
|
48901
49093
|
var ErrorHandlingInterceptor = class {
|
|
48902
49094
|
constructor() {
|
|
@@ -48925,9 +49117,9 @@ var ErrorHandlingInterceptor = class {
|
|
|
48925
49117
|
};
|
|
48926
49118
|
__name(ErrorHandlingInterceptor, "ErrorHandlingInterceptor");
|
|
48927
49119
|
ErrorHandlingInterceptor = __decorateClass([
|
|
48928
|
-
(0,
|
|
49120
|
+
(0, import_common23.Injectable)()
|
|
48929
49121
|
], ErrorHandlingInterceptor);
|
|
48930
|
-
var
|
|
49122
|
+
var logger7 = new logger$1.PackageLogger({
|
|
48931
49123
|
packageName: "core",
|
|
48932
49124
|
service: "FeatureFlagConfigValidator"
|
|
48933
49125
|
});
|
|
@@ -49113,7 +49305,7 @@ var FeatureFlagConfigValidator = class {
|
|
|
49113
49305
|
static getWarnings(config$1, environment) {
|
|
49114
49306
|
const env = environment ?? (config$1.isLoggingEnabled ? types.NODE_ENVIRONMENTS.DEVELOPMENT : types.NODE_ENVIRONMENTS.PRODUCTION);
|
|
49115
49307
|
if (config$1.cacheTtl > config.NUMERIC_CONSTANTS.ONE_HOUR_SECONDS) {
|
|
49116
|
-
|
|
49308
|
+
logger7.warn(
|
|
49117
49309
|
"Cache TTL is very high (>1 hour). Consider reducing for better responsiveness.",
|
|
49118
49310
|
{
|
|
49119
49311
|
field: "cacheTtl",
|
|
@@ -49123,13 +49315,13 @@ var FeatureFlagConfigValidator = class {
|
|
|
49123
49315
|
);
|
|
49124
49316
|
}
|
|
49125
49317
|
if (env === types.NODE_ENVIRONMENTS.PRODUCTION && config$1.isLoggingEnabled) {
|
|
49126
|
-
|
|
49318
|
+
logger7.warn("Logging is enabled in production. Consider disabling for performance.", {
|
|
49127
49319
|
field: "isLoggingEnabled",
|
|
49128
49320
|
code: "PRODUCTION_LOGGING_ENABLED"
|
|
49129
49321
|
});
|
|
49130
49322
|
}
|
|
49131
49323
|
if (env === types.NODE_ENVIRONMENTS.DEVELOPMENT && !config$1.isCacheEnabled) {
|
|
49132
|
-
|
|
49324
|
+
logger7.warn("Cache is disabled in development. This may impact performance testing.", {
|
|
49133
49325
|
field: "isCacheEnabled",
|
|
49134
49326
|
code: "DEVELOPMENT_CACHE_DISABLED"
|
|
49135
49327
|
});
|
|
@@ -49272,7 +49464,7 @@ var FeatureFlagConfigFactory = class {
|
|
|
49272
49464
|
};
|
|
49273
49465
|
|
|
49274
49466
|
// src/base/cache/feature/caching.ts
|
|
49275
|
-
var
|
|
49467
|
+
var import_common24 = __toESM(require_common(), 1);
|
|
49276
49468
|
var import_rxjs2 = __toESM(require_cjs(), 1);
|
|
49277
49469
|
var Caching = class {
|
|
49278
49470
|
constructor() {
|
|
@@ -49295,7 +49487,7 @@ var Caching = class {
|
|
|
49295
49487
|
};
|
|
49296
49488
|
__name(Caching, "Caching");
|
|
49297
49489
|
Caching = __decorateClass([
|
|
49298
|
-
(0,
|
|
49490
|
+
(0, import_common24.Injectable)()
|
|
49299
49491
|
], Caching);
|
|
49300
49492
|
|
|
49301
49493
|
// src/frontend/index.ts
|
|
@@ -49331,7 +49523,6 @@ __export(frontend_exports, {
|
|
|
49331
49523
|
useHasService: () => useHasService,
|
|
49332
49524
|
usePlyaz: () => usePlyaz,
|
|
49333
49525
|
usePlyazReady: () => usePlyazReady,
|
|
49334
|
-
useRootStore: () => store.useRootStore,
|
|
49335
49526
|
useService: () => useService,
|
|
49336
49527
|
useServiceAsync: () => useServiceAsync,
|
|
49337
49528
|
useServiceKeys: () => useServiceKeys,
|
|
@@ -49422,7 +49613,7 @@ function ApiProvider({
|
|
|
49422
49613
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
49423
49614
|
}
|
|
49424
49615
|
__name(ApiProvider, "ApiProvider");
|
|
49425
|
-
var
|
|
49616
|
+
var logger8 = new logger$1.PackageLogger({ packageName: "core", service: "PlyazProvider" });
|
|
49426
49617
|
var PlyazContext = react.createContext(null);
|
|
49427
49618
|
var FeatureFlagStore = class {
|
|
49428
49619
|
constructor(config = {}) {
|
|
@@ -49512,22 +49703,27 @@ async function initializeCore(config) {
|
|
|
49512
49703
|
});
|
|
49513
49704
|
}
|
|
49514
49705
|
__name(initializeCore, "initializeCore");
|
|
49515
|
-
function createStoreRegistry() {
|
|
49706
|
+
function createStoreRegistry(store) {
|
|
49516
49707
|
return {
|
|
49517
49708
|
getStore(key) {
|
|
49518
|
-
const state = store.
|
|
49709
|
+
const state = store.getState();
|
|
49519
49710
|
if (!state) {
|
|
49520
|
-
|
|
49711
|
+
logger8.warn(
|
|
49521
49712
|
"Store state is undefined - store may not be hydrated yet. This can cause side effects if called during SSR or before initialization."
|
|
49522
49713
|
);
|
|
49523
49714
|
return void 0;
|
|
49524
49715
|
}
|
|
49525
|
-
|
|
49716
|
+
const slice = state[key];
|
|
49717
|
+
logger8.debug(`[StoreRegistry] getStore('${key}')`, {
|
|
49718
|
+
hasSlice: !!slice,
|
|
49719
|
+
sliceKeys: slice ? Object.keys(slice) : []
|
|
49720
|
+
});
|
|
49721
|
+
return slice;
|
|
49526
49722
|
}
|
|
49527
49723
|
};
|
|
49528
49724
|
}
|
|
49529
49725
|
__name(createStoreRegistry, "createStoreRegistry");
|
|
49530
|
-
async function initializeServices(config) {
|
|
49726
|
+
async function initializeServices(config, store) {
|
|
49531
49727
|
if (!config.services || config.services.length === 0) return;
|
|
49532
49728
|
if (config.verbose) {
|
|
49533
49729
|
globalThis.console.log("[PlyazProvider] Initializing domain services...");
|
|
@@ -49539,7 +49735,7 @@ async function initializeServices(config) {
|
|
|
49539
49735
|
observability: config.observability,
|
|
49540
49736
|
services: config.services,
|
|
49541
49737
|
// Provide store registry for injecting stores into services
|
|
49542
|
-
stores: createStoreRegistry()
|
|
49738
|
+
stores: createStoreRegistry(store)
|
|
49543
49739
|
});
|
|
49544
49740
|
if (config.verbose) {
|
|
49545
49741
|
globalThis.console.log(
|
|
@@ -49576,6 +49772,7 @@ function createServicesObject(config, featureFlagStore) {
|
|
|
49576
49772
|
__name(createServicesObject, "createServicesObject");
|
|
49577
49773
|
function PlyazProvider({
|
|
49578
49774
|
children,
|
|
49775
|
+
store,
|
|
49579
49776
|
config,
|
|
49580
49777
|
loading,
|
|
49581
49778
|
error: errorComponent,
|
|
@@ -49589,8 +49786,9 @@ function PlyazProvider({
|
|
|
49589
49786
|
const initialize = react.useCallback(async () => {
|
|
49590
49787
|
try {
|
|
49591
49788
|
setError(null);
|
|
49789
|
+
Core.setRootStoreHook(store);
|
|
49592
49790
|
await initializeCore(config);
|
|
49593
|
-
await initializeServices(config);
|
|
49791
|
+
await initializeServices(config, store);
|
|
49594
49792
|
await initializeFeatureFlags(featureFlagStore);
|
|
49595
49793
|
setIsReady(true);
|
|
49596
49794
|
onReady?.(createServicesObject(config, featureFlagStore));
|
|
@@ -49600,7 +49798,7 @@ function PlyazProvider({
|
|
|
49600
49798
|
onError?.(initError);
|
|
49601
49799
|
globalThis.console.error("[PlyazProvider] Initialization failed:", initError);
|
|
49602
49800
|
}
|
|
49603
|
-
}, [config, featureFlagStore, onReady, onError]);
|
|
49801
|
+
}, [config, store, featureFlagStore, onReady, onError]);
|
|
49604
49802
|
const reinitialize = react.useCallback(async () => {
|
|
49605
49803
|
setIsReady(false);
|
|
49606
49804
|
ServiceRegistry.disposeAll();
|
|
@@ -49649,8 +49847,9 @@ __name(PlyazProvider, "PlyazProvider");
|
|
|
49649
49847
|
function usePlyaz() {
|
|
49650
49848
|
const context = react.useContext(PlyazContext);
|
|
49651
49849
|
if (!context) {
|
|
49652
|
-
throw new
|
|
49653
|
-
"usePlyaz must be used within a PlyazProvider. Wrap your app with <PlyazProvider config={...}>...</PlyazProvider>"
|
|
49850
|
+
throw new errors.CorePackageError(
|
|
49851
|
+
"usePlyaz must be used within a PlyazProvider. Wrap your app with <PlyazProvider config={...}>...</PlyazProvider>",
|
|
49852
|
+
types.ERROR_CODES.CORE_PROVIDER_NOT_FOUND
|
|
49654
49853
|
);
|
|
49655
49854
|
}
|
|
49656
49855
|
return context;
|
|
@@ -49659,7 +49858,10 @@ __name(usePlyaz, "usePlyaz");
|
|
|
49659
49858
|
function useApi() {
|
|
49660
49859
|
const { api, isReady } = usePlyaz();
|
|
49661
49860
|
if (!isReady || !api) {
|
|
49662
|
-
throw new
|
|
49861
|
+
throw new errors.CorePackageError(
|
|
49862
|
+
"API client is not ready. Make sure PlyazProvider has finished initializing.",
|
|
49863
|
+
types.ERROR_CODES.CORE_PROVIDER_INITIALIZATION_FAILED
|
|
49864
|
+
);
|
|
49663
49865
|
}
|
|
49664
49866
|
return api;
|
|
49665
49867
|
}
|
|
@@ -49702,7 +49904,10 @@ __name(useEnvironment, "useEnvironment");
|
|
|
49702
49904
|
function useService(key) {
|
|
49703
49905
|
const { getService, isReady } = usePlyaz();
|
|
49704
49906
|
if (!isReady) {
|
|
49705
|
-
throw new
|
|
49907
|
+
throw new errors.CorePackageError(
|
|
49908
|
+
`PlyazProvider not ready. Cannot get service '${key}'.`,
|
|
49909
|
+
types.ERROR_CODES.CORE_PROVIDER_INITIALIZATION_FAILED
|
|
49910
|
+
);
|
|
49706
49911
|
}
|
|
49707
49912
|
return react.useMemo(() => getService(key), [getService, key]);
|
|
49708
49913
|
}
|