@kaikybrofc/omnizap-system 2.2.10 → 2.3.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/README.md +13 -13
- package/app/config/adminIdentity.js +1 -3
- package/app/connection/socketController.js +10 -20
- package/app/controllers/messageController.js +7 -28
- package/app/modules/aiModule/catCommand.js +29 -192
- package/app/modules/broadcastModule/noticeCommand.js +28 -97
- package/app/modules/gameModule/diceCommand.js +6 -32
- package/app/modules/playModule/playCommand.js +57 -258
- package/app/modules/quoteModule/quoteCommand.js +2 -4
- package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1 -13
- package/app/modules/statsModule/noMessageCommand.js +16 -84
- package/app/modules/statsModule/rankingCommand.js +5 -25
- package/app/modules/statsModule/rankingCommon.js +1 -9
- package/app/modules/stickerModule/convertToWebp.js +4 -27
- package/app/modules/stickerModule/stickerCommand.js +13 -24
- package/app/modules/stickerModule/stickerTextCommand.js +13 -25
- package/app/modules/stickerPackModule/autoPackCollectorService.js +16 -7
- package/app/modules/stickerPackModule/domainEventOutboxRepository.js +20 -36
- package/app/modules/stickerPackModule/domainEvents.js +2 -11
- package/app/modules/stickerPackModule/semanticReclassificationEngine.js +13 -50
- package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +2 -15
- package/app/modules/stickerPackModule/semanticThemeClusterService.js +14 -41
- package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +25 -95
- package/app/modules/stickerPackModule/stickerAssetRepository.js +12 -31
- package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +13 -18
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +284 -709
- package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +27 -106
- package/app/modules/stickerPackModule/stickerClassificationService.js +46 -77
- package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +13 -53
- package/app/modules/stickerPackModule/stickerDomainEventBus.js +10 -16
- package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +40 -39
- package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +1 -4
- package/app/modules/stickerPackModule/stickerObjectStorageService.js +26 -26
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +32 -187
- package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +6 -15
- package/app/modules/stickerPackModule/stickerPackItemRepository.js +6 -32
- package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +12 -36
- package/app/modules/stickerPackModule/stickerPackMessageService.js +12 -40
- package/app/modules/stickerPackModule/stickerPackRepository.js +23 -66
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +9 -21
- package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +10 -40
- package/app/modules/stickerPackModule/stickerPackService.js +50 -115
- package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +2 -21
- package/app/modules/stickerPackModule/stickerPackUtils.js +13 -3
- package/app/modules/stickerPackModule/stickerStorageService.js +16 -65
- package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +4 -22
- package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +14 -29
- package/app/modules/systemMetricsModule/pingCommand.js +9 -39
- package/app/modules/tiktokModule/tiktokCommand.js +17 -109
- package/app/modules/userModule/userCommand.js +2 -88
- package/app/observability/metrics.js +5 -16
- package/app/services/captchaService.js +1 -6
- package/app/services/dbWriteQueue.js +3 -18
- package/app/services/featureFlagService.js +2 -8
- package/app/services/newsBroadcastService.js +0 -1
- package/app/services/queueUtils.js +2 -4
- package/app/services/whatsappLoginLinkService.js +7 -9
- package/app/store/premiumUserStore.js +1 -2
- package/app/utils/antiLink/antiLinkModule.js +3 -233
- package/app/utils/logger/loggerModule.js +9 -34
- package/app/utils/systemMetrics/systemMetricsModule.js +1 -4
- package/database/index.js +1 -0
- package/database/init.js +1 -8
- package/database/migrations/20260228_0027_web_visit_event.sql +15 -0
- package/docker-compose.yml +27 -27
- package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +26 -0
- package/docs/seo/satellite-page-template.md +2 -0
- package/docs/seo/satellite-pages-phase1.json +40 -177
- package/eslint.config.js +2 -15
- package/index.js +8 -36
- package/ml/clip_classifier/README.md +4 -6
- package/observability/alert-rules.yml +12 -12
- package/observability/grafana/provisioning/dashboards/dashboards.yml +1 -1
- package/package.json +6 -3
- package/public/api-docs/index.html +220 -193
- package/public/bot-whatsapp-para-grupo/index.html +291 -261
- package/public/bot-whatsapp-sem-programar/index.html +291 -261
- package/public/comandos/index.html +421 -406
- package/public/como-automatizar-avisos-no-whatsapp/index.html +291 -261
- package/public/como-criar-comandos-whatsapp/index.html +291 -261
- package/public/como-evitar-spam-no-whatsapp/index.html +291 -261
- package/public/como-moderar-grupo-whatsapp/index.html +291 -261
- package/public/como-organizar-comunidade-whatsapp/index.html +291 -261
- package/public/css/github-project-panel.css +13 -8
- package/public/css/stickers-admin.css +25 -9
- package/public/css/styles.css +23 -16
- package/public/index.html +1106 -993
- package/public/js/apps/apiDocsApp.js +17 -167
- package/public/js/apps/createPackApp.js +69 -332
- package/public/js/apps/homeApp.js +274 -101
- package/public/js/apps/loginApp.js +3 -12
- package/public/js/apps/stickersAdminApp.js +190 -181
- package/public/js/apps/stickersApp.js +482 -1411
- package/public/js/apps/userApp.js +217 -1
- package/public/js/catalog.js +11 -74
- package/public/js/github-panel/components/ErrorState.js +1 -8
- package/public/js/github-panel/components/GithubProjectPanel.js +2 -9
- package/public/js/github-panel/components/SkeletonPanel.js +1 -11
- package/public/js/github-panel/components/StatCard.js +1 -7
- package/public/js/github-panel/vendor/react.js +1 -9
- package/public/js/runtime/react-runtime.js +1 -9
- package/public/licenca/index.html +200 -86
- package/public/login/index.html +315 -325
- package/public/melhor-bot-whatsapp-para-grupos/index.html +291 -261
- package/public/stickers/admin/index.html +14 -19
- package/public/stickers/create/index.html +39 -44
- package/public/stickers/index.html +96 -107
- package/public/termos-de-uso/index.html +369 -122
- package/public/user/index.html +527 -350
- package/scripts/cache-bust.mjs +5 -24
- package/scripts/generate-seo-satellite-pages.mjs +10 -13
- package/scripts/run-prettier-all.mjs +25 -0
- package/scripts/sticker-catalog-loadtest.mjs +13 -11
- package/scripts/sticker-worker-task.mjs +1 -4
- package/scripts/sync-readme-snapshot.mjs +3 -2
- package/server/auth/googleWebAuth/googleWebAuthService.js +614 -0
- package/server/controllers/stickerCatalogController.js +297 -632
- package/server/http/httpServer.js +2 -10
- package/server/routes/stickerCatalog/catalogHandlers/catalogAdminHttp.js +1 -8
- package/server/routes/stickerCatalog/catalogHandlers/catalogAuthHttp.js +1 -9
- package/server/routes/stickerCatalog/catalogHandlers/catalogPublicHttp.js +10 -11
- package/server/routes/stickerCatalog/catalogHandlers/catalogUploadHttp.js +1 -10
- package/server/routes/stickerCatalog/catalogRouter.js +11 -13
|
@@ -5,22 +5,9 @@ import logger from '../../utils/logger/loggerModule.js';
|
|
|
5
5
|
import { recordStickerClassificationCycle, setQueueDepth } from '../../observability/metrics.js';
|
|
6
6
|
import { listStickerAssetsPendingClassification, findStickerAssetById } from './stickerAssetRepository.js';
|
|
7
7
|
import { classifierConfig, ensureStickerAssetClassified } from './stickerClassificationService.js';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
listAssetsForModelUpgradeReprocess,
|
|
12
|
-
} from './stickerAssetClassificationRepository.js';
|
|
13
|
-
import {
|
|
14
|
-
claimStickerAssetReprocessTask,
|
|
15
|
-
completeStickerAssetReprocessTask,
|
|
16
|
-
countStickerAssetReprocessQueueByStatus,
|
|
17
|
-
enqueueStickerAssetReprocess,
|
|
18
|
-
failStickerAssetReprocessTask,
|
|
19
|
-
} from './stickerAssetReprocessQueueRepository.js';
|
|
20
|
-
import {
|
|
21
|
-
batchReprocess as runDeterministicSemanticReclassification,
|
|
22
|
-
deterministicReclassificationConfig,
|
|
23
|
-
} from './semanticReclassificationEngine.js';
|
|
8
|
+
import { listAssetsForPrioritySignalBackfillReprocess, listAssetsForLowConfidenceReprocess, listAssetsForModelUpgradeReprocess } from './stickerAssetClassificationRepository.js';
|
|
9
|
+
import { claimStickerAssetReprocessTask, completeStickerAssetReprocessTask, countStickerAssetReprocessQueueByStatus, enqueueStickerAssetReprocess, failStickerAssetReprocessTask } from './stickerAssetReprocessQueueRepository.js';
|
|
10
|
+
import { batchReprocess as runDeterministicSemanticReclassification, deterministicReclassificationConfig } from './semanticReclassificationEngine.js';
|
|
24
11
|
|
|
25
12
|
const parseEnvBool = (value, fallback) => {
|
|
26
13
|
if (value === undefined || value === null || value === '') return fallback;
|
|
@@ -37,58 +24,26 @@ const INTERVAL_MIN_MS_RAW = Number(process.env.STICKER_CLASSIFICATION_BACKGROUND
|
|
|
37
24
|
const INTERVAL_MAX_MS_RAW = Number(process.env.STICKER_CLASSIFICATION_BACKGROUND_INTERVAL_MAX_MS);
|
|
38
25
|
const DEFAULT_INTERVAL_MIN_MS = 5 * 60_000;
|
|
39
26
|
const DEFAULT_INTERVAL_MAX_MS = 10 * 60_000;
|
|
40
|
-
const INTERVAL_MIN_MS = Number.isFinite(INTERVAL_MIN_MS_RAW)
|
|
41
|
-
|
|
42
|
-
: DEFAULT_INTERVAL_MIN_MS;
|
|
43
|
-
const INTERVAL_MAX_MS_FROM_ENV = Number.isFinite(INTERVAL_MAX_MS_RAW)
|
|
44
|
-
? Math.max(60_000, Math.min(3_600_000, INTERVAL_MAX_MS_RAW))
|
|
45
|
-
: DEFAULT_INTERVAL_MAX_MS;
|
|
27
|
+
const INTERVAL_MIN_MS = Number.isFinite(INTERVAL_MIN_MS_RAW) ? Math.max(60_000, Math.min(3_600_000, INTERVAL_MIN_MS_RAW)) : DEFAULT_INTERVAL_MIN_MS;
|
|
28
|
+
const INTERVAL_MAX_MS_FROM_ENV = Number.isFinite(INTERVAL_MAX_MS_RAW) ? Math.max(60_000, Math.min(3_600_000, INTERVAL_MAX_MS_RAW)) : DEFAULT_INTERVAL_MAX_MS;
|
|
46
29
|
const INTERVAL_MAX_MS = Math.max(INTERVAL_MIN_MS, INTERVAL_MAX_MS_FROM_ENV);
|
|
47
|
-
const LEGACY_FIXED_INTERVAL_MS = Number.isFinite(LEGACY_INTERVAL_MS) && LEGACY_INTERVAL_MS > 0
|
|
48
|
-
? Math.max(60_000, Math.min(3_600_000, LEGACY_INTERVAL_MS))
|
|
49
|
-
: null;
|
|
30
|
+
const LEGACY_FIXED_INTERVAL_MS = Number.isFinite(LEGACY_INTERVAL_MS) && LEGACY_INTERVAL_MS > 0 ? Math.max(60_000, Math.min(3_600_000, LEGACY_INTERVAL_MS)) : null;
|
|
50
31
|
const EFFECTIVE_INTERVAL_MIN_MS = LEGACY_FIXED_INTERVAL_MS || INTERVAL_MIN_MS;
|
|
51
32
|
const EFFECTIVE_INTERVAL_MAX_MS = LEGACY_FIXED_INTERVAL_MS || INTERVAL_MAX_MS;
|
|
52
33
|
const cpuCount = Math.max(1, Number(os.cpus()?.length || 1));
|
|
53
|
-
const BACKGROUND_CONCURRENCY = Math.max(
|
|
54
|
-
|
|
55
|
-
Math.min(16, Number(process.env.STICKER_CLASSIFICATION_BACKGROUND_CONCURRENCY) || cpuCount),
|
|
56
|
-
);
|
|
57
|
-
const BATCH_SIZE = Math.max(
|
|
58
|
-
1,
|
|
59
|
-
Math.min(300, Number(process.env.STICKER_CLASSIFICATION_BACKGROUND_BATCH_SIZE) || BACKGROUND_CONCURRENCY * 2),
|
|
60
|
-
);
|
|
34
|
+
const BACKGROUND_CONCURRENCY = Math.max(1, Math.min(16, Number(process.env.STICKER_CLASSIFICATION_BACKGROUND_CONCURRENCY) || cpuCount));
|
|
35
|
+
const BATCH_SIZE = Math.max(1, Math.min(300, Number(process.env.STICKER_CLASSIFICATION_BACKGROUND_BATCH_SIZE) || BACKGROUND_CONCURRENCY * 2));
|
|
61
36
|
|
|
62
37
|
const REPROCESS_ENABLED = parseEnvBool(process.env.STICKER_REPROCESS_QUEUE_ENABLED, true);
|
|
63
38
|
const REPROCESS_MAX_PER_CYCLE = Math.max(0, Math.min(300, Number(process.env.STICKER_REPROCESS_MAX_PER_CYCLE) || BATCH_SIZE));
|
|
64
|
-
const REPROCESS_MODEL_UPGRADE_SCAN_LIMIT = Math.max(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
);
|
|
68
|
-
const REPROCESS_LOW_CONFIDENCE_SCAN_LIMIT = Math.max(
|
|
69
|
-
0,
|
|
70
|
-
Math.min(2000, Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_SCAN_LIMIT) || 250),
|
|
71
|
-
);
|
|
72
|
-
const REPROCESS_LOW_CONFIDENCE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_THRESHOLD))
|
|
73
|
-
? Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_THRESHOLD)
|
|
74
|
-
: 0.65;
|
|
75
|
-
const REPROCESS_LOW_CONFIDENCE_STALE_HOURS = Math.max(
|
|
76
|
-
1,
|
|
77
|
-
Math.min(24 * 365, Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_STALE_HOURS) || 48),
|
|
78
|
-
);
|
|
39
|
+
const REPROCESS_MODEL_UPGRADE_SCAN_LIMIT = Math.max(0, Math.min(2000, Number(process.env.STICKER_REPROCESS_MODEL_UPGRADE_SCAN_LIMIT) || 350));
|
|
40
|
+
const REPROCESS_LOW_CONFIDENCE_SCAN_LIMIT = Math.max(0, Math.min(2000, Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_SCAN_LIMIT) || 250));
|
|
41
|
+
const REPROCESS_LOW_CONFIDENCE_THRESHOLD = Number.isFinite(Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_THRESHOLD)) ? Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_THRESHOLD) : 0.65;
|
|
42
|
+
const REPROCESS_LOW_CONFIDENCE_STALE_HOURS = Math.max(1, Math.min(24 * 365, Number(process.env.STICKER_REPROCESS_LOW_CONFIDENCE_STALE_HOURS) || 48));
|
|
79
43
|
const REPROCESS_PRIORITY_BACKFILL_ENABLED = parseEnvBool(process.env.STICKER_REPROCESS_PRIORITY_BACKFILL_ENABLED, true);
|
|
80
|
-
const REPROCESS_PRIORITY_BACKFILL_SCAN_LIMIT = Math.max(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
);
|
|
84
|
-
const REPROCESS_PRIORITY_BACKFILL_PRIORITY = Math.max(
|
|
85
|
-
1,
|
|
86
|
-
Math.min(100, Number(process.env.STICKER_REPROCESS_PRIORITY_BACKFILL_PRIORITY) || 95),
|
|
87
|
-
);
|
|
88
|
-
const REPROCESS_RETRY_DELAY_SECONDS = Math.max(
|
|
89
|
-
5,
|
|
90
|
-
Math.min(3600, Number(process.env.STICKER_REPROCESS_RETRY_DELAY_SECONDS) || 120),
|
|
91
|
-
);
|
|
44
|
+
const REPROCESS_PRIORITY_BACKFILL_SCAN_LIMIT = Math.max(0, Math.min(3000, Number(process.env.STICKER_REPROCESS_PRIORITY_BACKFILL_SCAN_LIMIT) || 300));
|
|
45
|
+
const REPROCESS_PRIORITY_BACKFILL_PRIORITY = Math.max(1, Math.min(100, Number(process.env.STICKER_REPROCESS_PRIORITY_BACKFILL_PRIORITY) || 95));
|
|
46
|
+
const REPROCESS_RETRY_DELAY_SECONDS = Math.max(5, Math.min(3600, Number(process.env.STICKER_REPROCESS_RETRY_DELAY_SECONDS) || 120));
|
|
92
47
|
|
|
93
48
|
let cycleHandle = null;
|
|
94
49
|
let startupTimeoutHandle = null;
|
|
@@ -306,10 +261,7 @@ const processReprocessQueue = async ({ limit = REPROCESS_MAX_PER_CYCLE } = {}) =
|
|
|
306
261
|
}
|
|
307
262
|
|
|
308
263
|
try {
|
|
309
|
-
const [pendingDepth, processingDepth] = await Promise.all([
|
|
310
|
-
countStickerAssetReprocessQueueByStatus('pending'),
|
|
311
|
-
countStickerAssetReprocessQueueByStatus('processing'),
|
|
312
|
-
]);
|
|
264
|
+
const [pendingDepth, processingDepth] = await Promise.all([countStickerAssetReprocessQueueByStatus('pending'), countStickerAssetReprocessQueueByStatus('processing')]);
|
|
313
265
|
setQueueDepth('sticker_reprocess_pending', pendingDepth);
|
|
314
266
|
setQueueDepth('sticker_reprocess_processing', processingDepth);
|
|
315
267
|
} catch (error) {
|
|
@@ -346,11 +298,7 @@ const processDeterministicReclassification = async () => {
|
|
|
346
298
|
});
|
|
347
299
|
};
|
|
348
300
|
|
|
349
|
-
export const runStickerClassificationCycle = async ({
|
|
350
|
-
processPending = true,
|
|
351
|
-
processReprocess = true,
|
|
352
|
-
processDeterministic = true,
|
|
353
|
-
} = {}) => {
|
|
301
|
+
export const runStickerClassificationCycle = async ({ processPending = true, processReprocess = true, processDeterministic = true } = {}) => {
|
|
354
302
|
const startedAt = Date.now();
|
|
355
303
|
const shouldProcessClassifier = classifierConfig.enabled;
|
|
356
304
|
const shouldProcessDeterministic = deterministicReclassificationConfig.enabled;
|
|
@@ -372,22 +320,11 @@ export const runStickerClassificationCycle = async ({
|
|
|
372
320
|
try {
|
|
373
321
|
const reprocessStats = processReprocess && shouldProcessClassifier ? await processReprocessQueue() : null;
|
|
374
322
|
const pendingStats = processPending && shouldProcessClassifier ? await processPendingAssets() : null;
|
|
375
|
-
const deterministicStats = processDeterministic
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const
|
|
380
|
-
Number(pendingStats?.processed || 0)
|
|
381
|
-
+ Number(reprocessStats?.processed || 0)
|
|
382
|
-
+ Number(deterministicStats?.processed || 0);
|
|
383
|
-
const classified =
|
|
384
|
-
Number(pendingStats?.classified || 0)
|
|
385
|
-
+ Number(reprocessStats?.classified || 0)
|
|
386
|
-
+ Number(deterministicStats?.updated || 0);
|
|
387
|
-
const failed =
|
|
388
|
-
Number(pendingStats?.failed || 0)
|
|
389
|
-
+ Number(reprocessStats?.failed || 0)
|
|
390
|
-
+ Number(deterministicStats?.failed || 0);
|
|
323
|
+
const deterministicStats = processDeterministic ? await processDeterministicReclassification() : null;
|
|
324
|
+
|
|
325
|
+
const processed = Number(pendingStats?.processed || 0) + Number(reprocessStats?.processed || 0) + Number(deterministicStats?.processed || 0);
|
|
326
|
+
const classified = Number(pendingStats?.classified || 0) + Number(reprocessStats?.classified || 0) + Number(deterministicStats?.updated || 0);
|
|
327
|
+
const failed = Number(pendingStats?.failed || 0) + Number(reprocessStats?.failed || 0) + Number(deterministicStats?.failed || 0);
|
|
391
328
|
const durationMs = Date.now() - startedAt;
|
|
392
329
|
|
|
393
330
|
recordStickerClassificationCycle({
|
|
@@ -428,8 +365,7 @@ const resolveNextCycleDelayMs = () => {
|
|
|
428
365
|
return EFFECTIVE_INTERVAL_MIN_MS;
|
|
429
366
|
}
|
|
430
367
|
|
|
431
|
-
return EFFECTIVE_INTERVAL_MIN_MS
|
|
432
|
-
+ Math.floor(Math.random() * (EFFECTIVE_INTERVAL_MAX_MS - EFFECTIVE_INTERVAL_MIN_MS + 1));
|
|
368
|
+
return EFFECTIVE_INTERVAL_MIN_MS + Math.floor(Math.random() * (EFFECTIVE_INTERVAL_MAX_MS - EFFECTIVE_INTERVAL_MIN_MS + 1));
|
|
433
369
|
};
|
|
434
370
|
|
|
435
371
|
const scheduleNextCycle = () => {
|
|
@@ -500,27 +436,12 @@ const classifyBatch = async () => {
|
|
|
500
436
|
affinity_threshold: deterministicReclassificationConfig.affinity_threshold,
|
|
501
437
|
};
|
|
502
438
|
|
|
503
|
-
const processed =
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
+ Number(deterministic.processed || 0);
|
|
507
|
-
const classified =
|
|
508
|
-
Number(pending.classified || 0)
|
|
509
|
-
+ Number(reprocess.classified || 0)
|
|
510
|
-
+ Number(deterministic.updated || 0);
|
|
511
|
-
const failed =
|
|
512
|
-
Number(pending.failed || 0)
|
|
513
|
-
+ Number(reprocess.failed || 0)
|
|
514
|
-
+ Number(deterministic.failed || 0);
|
|
439
|
+
const processed = Number(pending.processed || 0) + Number(reprocess.processed || 0) + Number(deterministic.processed || 0);
|
|
440
|
+
const classified = Number(pending.classified || 0) + Number(reprocess.classified || 0) + Number(deterministic.updated || 0);
|
|
441
|
+
const failed = Number(pending.failed || 0) + Number(reprocess.failed || 0) + Number(deterministic.failed || 0);
|
|
515
442
|
const gainCount = classified;
|
|
516
443
|
|
|
517
|
-
if (
|
|
518
|
-
processed > 0
|
|
519
|
-
|| reprocess.enqueued_priority_backfill > 0
|
|
520
|
-
|| reprocess.enqueued_model_upgrade > 0
|
|
521
|
-
|| reprocess.enqueued_low_confidence > 0
|
|
522
|
-
|| deterministic.updated > 0
|
|
523
|
-
) {
|
|
444
|
+
if (processed > 0 || reprocess.enqueued_priority_backfill > 0 || reprocess.enqueued_model_upgrade > 0 || reprocess.enqueued_low_confidence > 0 || deterministic.updated > 0) {
|
|
524
445
|
logger.info('Worker de classificação executado.', {
|
|
525
446
|
action: 'sticker_classification_background_cycle',
|
|
526
447
|
processed,
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import logger from '../../utils/logger/loggerModule.js';
|
|
2
|
-
import {
|
|
3
|
-
findStickerClassificationByAssetId,
|
|
4
|
-
listStickerClassificationsByAssetIds,
|
|
5
|
-
upsertStickerAssetClassification,
|
|
6
|
-
} from './stickerAssetClassificationRepository.js';
|
|
2
|
+
import { findStickerClassificationByAssetId, listStickerClassificationsByAssetIds, upsertStickerAssetClassification } from './stickerAssetClassificationRepository.js';
|
|
7
3
|
import { enqueueSemanticClusterResolution } from './semanticThemeClusterService.js';
|
|
8
4
|
|
|
9
5
|
const parseEnvBool = (value, fallback) => {
|
|
@@ -15,26 +11,14 @@ const parseEnvBool = (value, fallback) => {
|
|
|
15
11
|
};
|
|
16
12
|
|
|
17
13
|
const CLIP_CLASSIFIER_ENABLED = parseEnvBool(process.env.CLIP_CLASSIFIER_ENABLED, true);
|
|
18
|
-
const CLIP_CLASSIFIER_API_URL =
|
|
19
|
-
|
|
20
|
-
'http://127.0.0.1:8008/classify';
|
|
21
|
-
const CLIP_CLASSIFIER_FEEDBACK_API_URL = String(
|
|
22
|
-
process.env.CLIP_CLASSIFIER_FEEDBACK_API_URL
|
|
23
|
-
|| CLIP_CLASSIFIER_API_URL.replace(/\/classify\/?$/i, '/feedback'),
|
|
24
|
-
).trim();
|
|
14
|
+
const CLIP_CLASSIFIER_API_URL = String(process.env.CLIP_CLASSIFIER_API_URL || 'http://127.0.0.1:8008/classify').trim() || 'http://127.0.0.1:8008/classify';
|
|
15
|
+
const CLIP_CLASSIFIER_FEEDBACK_API_URL = String(process.env.CLIP_CLASSIFIER_FEEDBACK_API_URL || CLIP_CLASSIFIER_API_URL.replace(/\/classify\/?$/i, '/feedback')).trim();
|
|
25
16
|
const CLIP_CLASSIFIER_TIMEOUT_MS = Math.max(500, Number(process.env.CLIP_CLASSIFIER_TIMEOUT_MS) || 3000);
|
|
26
17
|
const CLIP_CLASSIFIER_PROVIDER = String(process.env.CLIP_CLASSIFIER_PROVIDER || 'clip').trim() || 'clip';
|
|
27
|
-
const CLIP_CLASSIFIER_CLASSIFICATION_VERSION =
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
: null;
|
|
32
|
-
const STICKER_TAG_MIN_SCORE = Number.isFinite(Number(process.env.STICKER_CLASSIFICATION_TAG_MIN_SCORE))
|
|
33
|
-
? Number(process.env.STICKER_CLASSIFICATION_TAG_MIN_SCORE)
|
|
34
|
-
: 0.2;
|
|
35
|
-
const PACK_TAG_MIN_SCORE = Number.isFinite(Number(process.env.PACK_CLASSIFICATION_TAG_MIN_SCORE))
|
|
36
|
-
? Number(process.env.PACK_CLASSIFICATION_TAG_MIN_SCORE)
|
|
37
|
-
: 0.18;
|
|
18
|
+
const CLIP_CLASSIFIER_CLASSIFICATION_VERSION = String(process.env.CLIP_CLASSIFIER_CLASSIFICATION_VERSION || process.env.CLIP_CLASSIFIER_MODEL_VERSION || 'v1').trim() || 'v1';
|
|
19
|
+
const CLIP_CLASSIFIER_NSFW_THRESHOLD = Number.isFinite(Number(process.env.CLIP_CLASSIFIER_NSFW_THRESHOLD)) ? Number(process.env.CLIP_CLASSIFIER_NSFW_THRESHOLD) : null;
|
|
20
|
+
const STICKER_TAG_MIN_SCORE = Number.isFinite(Number(process.env.STICKER_CLASSIFICATION_TAG_MIN_SCORE)) ? Number(process.env.STICKER_CLASSIFICATION_TAG_MIN_SCORE) : 0.2;
|
|
21
|
+
const PACK_TAG_MIN_SCORE = Number.isFinite(Number(process.env.PACK_CLASSIFICATION_TAG_MIN_SCORE)) ? Number(process.env.PACK_CLASSIFICATION_TAG_MIN_SCORE) : 0.18;
|
|
38
22
|
const MAX_TAGS_PER_ENTITY = Math.max(1, Math.min(10, Number(process.env.CLASSIFICATION_MAX_TAGS) || 6));
|
|
39
23
|
|
|
40
24
|
const LABEL_TO_TAG = {
|
|
@@ -59,7 +43,9 @@ const normalizeTag = (value) => {
|
|
|
59
43
|
};
|
|
60
44
|
|
|
61
45
|
const mapLabelToTag = (label) => {
|
|
62
|
-
const key = String(label || '')
|
|
46
|
+
const key = String(label || '')
|
|
47
|
+
.trim()
|
|
48
|
+
.toLowerCase();
|
|
63
49
|
return LABEL_TO_TAG[key] || normalizeTag(key);
|
|
64
50
|
};
|
|
65
51
|
|
|
@@ -116,32 +102,18 @@ const normalizeClassificationResult = (payload) => {
|
|
|
116
102
|
const topFromScores = scoreEntries[0] || null;
|
|
117
103
|
const topFromLabels = topLabels[0] || null;
|
|
118
104
|
const category = explicitCategory || topFromLabels?.label || topFromScores?.[0] || null;
|
|
119
|
-
const confidence = Number.isFinite(Number(payload?.confidence))
|
|
120
|
-
? Number(Number(payload.confidence).toFixed(6))
|
|
121
|
-
: Number.isFinite(Number(topFromLabels?.score))
|
|
122
|
-
? Number(Number(topFromLabels.score).toFixed(6))
|
|
123
|
-
: topFromScores
|
|
124
|
-
? Number(Number(topFromScores[1]).toFixed(6))
|
|
125
|
-
: null;
|
|
105
|
+
const confidence = Number.isFinite(Number(payload?.confidence)) ? Number(Number(payload.confidence).toFixed(6)) : Number.isFinite(Number(topFromLabels?.score)) ? Number(Number(topFromLabels.score).toFixed(6)) : topFromScores ? Number(Number(topFromScores[1]).toFixed(6)) : null;
|
|
126
106
|
const nsfwScore = Number.isFinite(Number(payload?.nsfw_score)) ? Number(Number(payload.nsfw_score).toFixed(6)) : null;
|
|
127
107
|
const entropy = Number.isFinite(Number(payload?.entropy)) ? Number(Number(payload.entropy).toFixed(6)) : null;
|
|
128
|
-
const entropyNormalized = Number.isFinite(Number(payload?.entropy_normalized))
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const affinityWeightRaw = Number.isFinite(Number(payload?.affinity_weight_raw))
|
|
138
|
-
? Number(Number(payload.affinity_weight_raw).toFixed(6))
|
|
139
|
-
: null;
|
|
140
|
-
const imageHash = String(payload?.image_hash || '').trim().toLowerCase();
|
|
141
|
-
|
|
142
|
-
const llmExpansion = payload?.llm_expansion && typeof payload.llm_expansion === 'object'
|
|
143
|
-
? payload.llm_expansion
|
|
144
|
-
: {};
|
|
108
|
+
const entropyNormalized = Number.isFinite(Number(payload?.entropy_normalized)) ? Number(Number(payload.entropy_normalized).toFixed(6)) : null;
|
|
109
|
+
const confidenceMargin = Number.isFinite(Number(payload?.confidence_margin)) ? Number(Number(payload.confidence_margin).toFixed(6)) : null;
|
|
110
|
+
const affinityWeight = Number.isFinite(Number(payload?.affinity_weight)) ? Number(Number(payload.affinity_weight).toFixed(6)) : null;
|
|
111
|
+
const affinityWeightRaw = Number.isFinite(Number(payload?.affinity_weight_raw)) ? Number(Number(payload.affinity_weight_raw).toFixed(6)) : null;
|
|
112
|
+
const imageHash = String(payload?.image_hash || '')
|
|
113
|
+
.trim()
|
|
114
|
+
.toLowerCase();
|
|
115
|
+
|
|
116
|
+
const llmExpansion = payload?.llm_expansion && typeof payload.llm_expansion === 'object' ? payload.llm_expansion : {};
|
|
145
117
|
const llmSubtags = normalizeListOfStrings(llmExpansion?.subtags, 40);
|
|
146
118
|
const llmStyleTraits = normalizeListOfStrings(llmExpansion?.style_traits, 20);
|
|
147
119
|
const llmEmotions = normalizeListOfStrings(llmExpansion?.emotions, 20);
|
|
@@ -149,13 +121,15 @@ const normalizeClassificationResult = (payload) => {
|
|
|
149
121
|
|
|
150
122
|
const similarImages = Array.isArray(payload?.similar_images)
|
|
151
123
|
? payload.similar_images
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
124
|
+
.map((entry) => ({
|
|
125
|
+
image_hash: String(entry?.image_hash || '')
|
|
126
|
+
.trim()
|
|
127
|
+
.toLowerCase(),
|
|
128
|
+
asset_id: entry?.asset_id ? String(entry.asset_id) : null,
|
|
129
|
+
similarity: Number.isFinite(Number(entry?.similarity)) ? Number(Number(entry.similarity).toFixed(6)) : null,
|
|
130
|
+
}))
|
|
131
|
+
.filter((entry) => entry.image_hash && Number.isFinite(Number(entry.similarity)))
|
|
132
|
+
.slice(0, 40)
|
|
159
133
|
: [];
|
|
160
134
|
|
|
161
135
|
return {
|
|
@@ -188,18 +162,12 @@ const isClassifierNonRetryableError = (error) => {
|
|
|
188
162
|
if (NON_RETRYABLE_CLASSIFIER_HTTP_STATUSES.has(status)) return true;
|
|
189
163
|
|
|
190
164
|
const message = String(error?.message || '').toLowerCase();
|
|
191
|
-
return (
|
|
192
|
-
message.includes('could not create decoder object')
|
|
193
|
-
|| message.includes('nao foi possivel decodificar a imagem')
|
|
194
|
-
|| message.includes('não foi possível decodificar a imagem')
|
|
195
|
-
);
|
|
165
|
+
return message.includes('could not create decoder object') || message.includes('nao foi possivel decodificar a imagem') || message.includes('não foi possível decodificar a imagem');
|
|
196
166
|
};
|
|
197
167
|
|
|
198
168
|
const buildFallbackClassificationFromError = ({ asset, error }) => {
|
|
199
169
|
const message = String(error?.message || '').toLowerCase();
|
|
200
|
-
const reasonTag = message.includes('decoder') || message.includes('decodificar')
|
|
201
|
-
? 'decoder-error'
|
|
202
|
-
: 'non-retryable-error';
|
|
170
|
+
const reasonTag = message.includes('decoder') || message.includes('decodificar') ? 'decoder-error' : 'non-retryable-error';
|
|
203
171
|
|
|
204
172
|
return {
|
|
205
173
|
asset_id: asset.id,
|
|
@@ -210,12 +178,14 @@ const buildFallbackClassificationFromError = ({ asset, error }) => {
|
|
|
210
178
|
confidence: 0,
|
|
211
179
|
entropy: 0,
|
|
212
180
|
confidence_margin: 0,
|
|
213
|
-
top_labels: [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
181
|
+
top_labels: [
|
|
182
|
+
{
|
|
183
|
+
label: 'invalid image',
|
|
184
|
+
score: 1,
|
|
185
|
+
logit: null,
|
|
186
|
+
clip_score: null,
|
|
187
|
+
},
|
|
188
|
+
],
|
|
219
189
|
affinity_weight: 0,
|
|
220
190
|
image_hash: asset?.sha256 || null,
|
|
221
191
|
ambiguous: true,
|
|
@@ -541,15 +511,14 @@ export const classifierConfig = {
|
|
|
541
511
|
classification_version: CLIP_CLASSIFIER_CLASSIFICATION_VERSION,
|
|
542
512
|
};
|
|
543
513
|
|
|
544
|
-
export const submitStickerClassificationFeedback = async ({
|
|
545
|
-
imageHash,
|
|
546
|
-
theme,
|
|
547
|
-
accepted,
|
|
548
|
-
assetId = null,
|
|
549
|
-
}) => {
|
|
514
|
+
export const submitStickerClassificationFeedback = async ({ imageHash, theme, accepted, assetId = null }) => {
|
|
550
515
|
if (!CLIP_CLASSIFIER_ENABLED) return false;
|
|
551
|
-
const normalizedHash = String(imageHash || '')
|
|
552
|
-
|
|
516
|
+
const normalizedHash = String(imageHash || '')
|
|
517
|
+
.trim()
|
|
518
|
+
.toLowerCase();
|
|
519
|
+
const normalizedTheme = String(theme || '')
|
|
520
|
+
.trim()
|
|
521
|
+
.toLowerCase();
|
|
553
522
|
if (!normalizedHash || !normalizedTheme) return false;
|
|
554
523
|
if (typeof globalThis.fetch !== 'function') return false;
|
|
555
524
|
|
|
@@ -3,12 +3,7 @@ import { setQueueDepth } from '../../observability/metrics.js';
|
|
|
3
3
|
import { isFeatureEnabled } from '../../services/featureFlagService.js';
|
|
4
4
|
import { runStickerClassificationCycle } from './stickerClassificationBackgroundRuntime.js';
|
|
5
5
|
import { runStickerAutoPackByTagsCycle } from './stickerAutoPackByTagsRuntime.js';
|
|
6
|
-
import {
|
|
7
|
-
claimWorkerTask,
|
|
8
|
-
completeWorkerTask,
|
|
9
|
-
countWorkerTasksByStatus,
|
|
10
|
-
failWorkerTask,
|
|
11
|
-
} from './stickerWorkerTaskQueueRepository.js';
|
|
6
|
+
import { claimWorkerTask, completeWorkerTask, countWorkerTasksByStatus, failWorkerTask } from './stickerWorkerTaskQueueRepository.js';
|
|
12
7
|
|
|
13
8
|
const parseEnvBool = (value, fallback) => {
|
|
14
9
|
if (value === undefined || value === null || value === '') return fallback;
|
|
@@ -26,36 +21,17 @@ const clampInt = (value, fallback, min, max) => {
|
|
|
26
21
|
|
|
27
22
|
const DEDICATED_WORKERS_ENABLED = parseEnvBool(process.env.STICKER_DEDICATED_WORKERS_ENABLED, true);
|
|
28
23
|
const DEDICATED_WORKERS_FORCE_ENABLED = parseEnvBool(process.env.STICKER_DEDICATED_WORKERS_FORCE_ENABLED, false);
|
|
29
|
-
const DEDICATED_WORKER_RETRY_DELAY_SECONDS = clampInt(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
);
|
|
35
|
-
const DEDICATED_WORKER_POLL_INTERVAL_MS = clampInt(
|
|
36
|
-
process.env.STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS,
|
|
37
|
-
2500,
|
|
38
|
-
250,
|
|
39
|
-
60_000,
|
|
40
|
-
);
|
|
41
|
-
const DEDICATED_WORKER_MAX_TASKS_PER_TICK = clampInt(
|
|
42
|
-
process.env.STICKER_DEDICATED_WORKER_MAX_TASKS_PER_TICK,
|
|
43
|
-
1,
|
|
44
|
-
1,
|
|
45
|
-
25,
|
|
46
|
-
);
|
|
47
|
-
const DEDICATED_WORKER_COHORT_KEY =
|
|
48
|
-
String(process.env.STICKER_DEDICATED_WORKER_COHORT_KEY || process.env.HOSTNAME || process.pid).trim()
|
|
49
|
-
|| 'worker';
|
|
50
|
-
|
|
51
|
-
const SUPPORTED_TASK_TYPES = new Set([
|
|
52
|
-
'classification_cycle',
|
|
53
|
-
'curation_cycle',
|
|
54
|
-
'rebuild_cycle',
|
|
55
|
-
]);
|
|
24
|
+
const DEDICATED_WORKER_RETRY_DELAY_SECONDS = clampInt(process.env.STICKER_DEDICATED_WORKER_RETRY_DELAY_SECONDS, 60, 5, 3600);
|
|
25
|
+
const DEDICATED_WORKER_POLL_INTERVAL_MS = clampInt(process.env.STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS, 2500, 250, 60_000);
|
|
26
|
+
const DEDICATED_WORKER_MAX_TASKS_PER_TICK = clampInt(process.env.STICKER_DEDICATED_WORKER_MAX_TASKS_PER_TICK, 1, 1, 25);
|
|
27
|
+
const DEDICATED_WORKER_COHORT_KEY = String(process.env.STICKER_DEDICATED_WORKER_COHORT_KEY || process.env.HOSTNAME || process.pid).trim() || 'worker';
|
|
28
|
+
|
|
29
|
+
const SUPPORTED_TASK_TYPES = new Set(['classification_cycle', 'curation_cycle', 'rebuild_cycle']);
|
|
56
30
|
|
|
57
31
|
const normalizeTaskType = (value) => {
|
|
58
|
-
const normalized = String(value || '')
|
|
32
|
+
const normalized = String(value || '')
|
|
33
|
+
.trim()
|
|
34
|
+
.toLowerCase();
|
|
59
35
|
return SUPPORTED_TASK_TYPES.has(normalized) ? normalized : null;
|
|
60
36
|
};
|
|
61
37
|
|
|
@@ -86,11 +62,7 @@ const runTaskHandler = async (taskType, payload = {}) => {
|
|
|
86
62
|
};
|
|
87
63
|
|
|
88
64
|
const refreshQueueDepthMetrics = async () => {
|
|
89
|
-
const [pending, processing, failed] = await Promise.all([
|
|
90
|
-
countWorkerTasksByStatus('pending'),
|
|
91
|
-
countWorkerTasksByStatus('processing'),
|
|
92
|
-
countWorkerTasksByStatus('failed'),
|
|
93
|
-
]);
|
|
65
|
+
const [pending, processing, failed] = await Promise.all([countWorkerTasksByStatus('pending'), countWorkerTasksByStatus('processing'), countWorkerTasksByStatus('failed')]);
|
|
94
66
|
setQueueDepth('sticker_worker_tasks_pending', pending);
|
|
95
67
|
setQueueDepth('sticker_worker_tasks_processing', processing);
|
|
96
68
|
setQueueDepth('sticker_worker_tasks_failed', failed);
|
|
@@ -107,13 +79,7 @@ const canRunDedicatedWorkers = async (taskType) => {
|
|
|
107
79
|
|
|
108
80
|
export const isSupportedStickerWorkerTaskType = (taskType) => Boolean(normalizeTaskType(taskType));
|
|
109
81
|
|
|
110
|
-
export const runDedicatedStickerWorkerTick = async (
|
|
111
|
-
{
|
|
112
|
-
taskType,
|
|
113
|
-
maxTasks = DEDICATED_WORKER_MAX_TASKS_PER_TICK,
|
|
114
|
-
retryDelaySeconds = DEDICATED_WORKER_RETRY_DELAY_SECONDS,
|
|
115
|
-
} = {},
|
|
116
|
-
) => {
|
|
82
|
+
export const runDedicatedStickerWorkerTick = async ({ taskType, maxTasks = DEDICATED_WORKER_MAX_TASKS_PER_TICK, retryDelaySeconds = DEDICATED_WORKER_RETRY_DELAY_SECONDS } = {}) => {
|
|
117
83
|
const normalizedTaskType = normalizeTaskType(taskType);
|
|
118
84
|
if (!normalizedTaskType) {
|
|
119
85
|
return { executed: false, reason: 'invalid_task_type', task_type: taskType || null };
|
|
@@ -167,13 +133,7 @@ export const runDedicatedStickerWorkerTick = async (
|
|
|
167
133
|
return stats;
|
|
168
134
|
};
|
|
169
135
|
|
|
170
|
-
export const startDedicatedStickerWorker = ({
|
|
171
|
-
taskType,
|
|
172
|
-
pollIntervalMs = DEDICATED_WORKER_POLL_INTERVAL_MS,
|
|
173
|
-
maxTasksPerTick = DEDICATED_WORKER_MAX_TASKS_PER_TICK,
|
|
174
|
-
retryDelaySeconds = DEDICATED_WORKER_RETRY_DELAY_SECONDS,
|
|
175
|
-
label = '',
|
|
176
|
-
} = {}) => {
|
|
136
|
+
export const startDedicatedStickerWorker = ({ taskType, pollIntervalMs = DEDICATED_WORKER_POLL_INTERVAL_MS, maxTasksPerTick = DEDICATED_WORKER_MAX_TASKS_PER_TICK, retryDelaySeconds = DEDICATED_WORKER_RETRY_DELAY_SECONDS, label = '' } = {}) => {
|
|
177
137
|
const normalizedTaskType = normalizeTaskType(taskType);
|
|
178
138
|
if (!normalizedTaskType) {
|
|
179
139
|
throw new Error(`invalid_task_type:${taskType}`);
|
|
@@ -2,36 +2,30 @@ import logger from '../../utils/logger/loggerModule.js';
|
|
|
2
2
|
import { isFeatureEnabled } from '../../services/featureFlagService.js';
|
|
3
3
|
import { enqueueDomainEvent } from './domainEventOutboxRepository.js';
|
|
4
4
|
|
|
5
|
-
const resolveDefaultIdempotencyKey = ({
|
|
6
|
-
eventType,
|
|
7
|
-
aggregateType,
|
|
8
|
-
aggregateId,
|
|
9
|
-
payload = null,
|
|
10
|
-
}) => {
|
|
5
|
+
const resolveDefaultIdempotencyKey = ({ eventType, aggregateType, aggregateId, payload = null }) => {
|
|
11
6
|
const payloadKey = payload && typeof payload === 'object' ? JSON.stringify(payload).slice(0, 80) : '';
|
|
12
7
|
return `${eventType}:${aggregateType}:${aggregateId}:${payloadKey}`.slice(0, 180);
|
|
13
8
|
};
|
|
14
9
|
|
|
15
|
-
export const publishStickerDomainEvent = async (
|
|
16
|
-
eventPayload,
|
|
17
|
-
{ connection = null, force = false } = {},
|
|
18
|
-
) => {
|
|
10
|
+
export const publishStickerDomainEvent = async (eventPayload, { connection = null, force = false } = {}) => {
|
|
19
11
|
const eventType = String(eventPayload?.eventType || '').trim();
|
|
20
12
|
const aggregateType = String(eventPayload?.aggregateType || '').trim();
|
|
21
13
|
const aggregateId = String(eventPayload?.aggregateId || '').trim();
|
|
22
14
|
|
|
23
15
|
if (!eventType || !aggregateType || !aggregateId) return false;
|
|
24
16
|
|
|
25
|
-
const enabled = force
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
const enabled = force
|
|
18
|
+
? true
|
|
19
|
+
: await isFeatureEnabled('enable_domain_event_outbox', {
|
|
20
|
+
fallback: true,
|
|
21
|
+
subjectKey: `${aggregateType}:${aggregateId}`,
|
|
22
|
+
});
|
|
29
23
|
if (!enabled) return false;
|
|
30
24
|
|
|
31
25
|
try {
|
|
32
26
|
const idempotencyKey =
|
|
33
|
-
String(eventPayload?.idempotencyKey || '').trim()
|
|
34
|
-
|
|
27
|
+
String(eventPayload?.idempotencyKey || '').trim() ||
|
|
28
|
+
resolveDefaultIdempotencyKey({
|
|
35
29
|
eventType,
|
|
36
30
|
aggregateType,
|
|
37
31
|
aggregateId,
|