@restforgejs/platform 5.2.10 → 5.2.12
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/bin/drift-check-linux +0 -0
- package/bin/sdf-tools-linux +0 -0
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/fast-track.js +147 -27
- package/generators/cli/schema/init.js +20 -6
- package/generators/cli/schema/template.js +24 -9
- package/generators/lib/templates/dashboard-catalog.js +1 -1
- package/generators/lib/templates/db-connection-env.js +1 -1
- package/generators/lib/templates/dbschema-catalog.js +1 -1
- package/generators/lib/templates/field-validation-catalog.js +1 -1
- package/generators/lib/templates/mysql-template.js +1 -1
- package/generators/lib/templates/oracle-template.js +1 -1
- package/generators/lib/templates/postgres-template.js +1 -1
- package/generators/lib/templates/query-declarative-catalog.js +1 -1
- package/generators/lib/templates/sqlite-template.js +1 -1
- package/integrity-manifest.json +18 -18
- package/package.json +1 -1
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/soft-delete-dashboard-guard.js +1 -1
- package/src/utils/sql-table-extractor.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
|
@@ -257,8 +257,9 @@ function checkDesigner() {
|
|
|
257
257
|
console.log('');
|
|
258
258
|
console.log('[Preflight]');
|
|
259
259
|
|
|
260
|
-
// Probe nyata: jalankan `restforge-designer --version`.
|
|
261
|
-
|
|
260
|
+
// Probe nyata: jalankan `restforge-designer --version`. shell:true memilih
|
|
261
|
+
// cmd.exe (Windows) atau /bin/sh (Linux/macOS) otomatis, termasuk resolusi PATH.
|
|
262
|
+
const r = spawnSync('restforge-designer --version', { shell: true, encoding: 'utf8' });
|
|
262
263
|
const found = !r.error && r.status === 0;
|
|
263
264
|
let version = '';
|
|
264
265
|
if (found && r.stdout) version = r.stdout.trim().split(/\r?\n/)[0];
|
|
@@ -654,7 +655,7 @@ const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
|
654
655
|
* (list hanya membaca metadata plugin built-in).
|
|
655
656
|
*/
|
|
656
657
|
function runDesignerPluginsList() {
|
|
657
|
-
const r = spawnSync('
|
|
658
|
+
const r = spawnSync('restforge-designer plugins list', { shell: true, encoding: 'utf8' });
|
|
658
659
|
if (r.error || r.status !== 0) return null;
|
|
659
660
|
return r.stdout || '';
|
|
660
661
|
}
|
|
@@ -865,7 +866,7 @@ function phase(title) {
|
|
|
865
866
|
/** Jalankan command CMD inline; hentikan pipeline bila gagal. */
|
|
866
867
|
function run(cmd, cwd, { allowNonZero = false } = {}) {
|
|
867
868
|
console.log(`\n#${cmd}`);
|
|
868
|
-
const r = spawnSync(
|
|
869
|
+
const r = spawnSync(cmd, { cwd, stdio: 'inherit', shell: true });
|
|
869
870
|
if (allowNonZero) {
|
|
870
871
|
if (r.error) console.log(`\n [WARN] ${cmd}\n ${r.error.message}`);
|
|
871
872
|
return r.status;
|
|
@@ -1130,19 +1131,34 @@ function healthHost(serverAddress) {
|
|
|
1130
1131
|
return (!serverAddress || serverAddress === '0.0.0.0') ? 'localhost' : serverAddress;
|
|
1131
1132
|
}
|
|
1132
1133
|
|
|
1133
|
-
/** Bila port dipakai, hentikan proses lama
|
|
1134
|
+
/** Bila port dipakai, hentikan proses lama sebelum serve. */
|
|
1134
1135
|
function freePort(port) {
|
|
1135
|
-
const
|
|
1136
|
+
const isWin = process.platform === 'win32';
|
|
1136
1137
|
const pids = new Set();
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1138
|
+
|
|
1139
|
+
if (isWin) {
|
|
1140
|
+
const res = spawnSync(`netstat -ano | findstr :${port}`, { shell: true, encoding: 'utf8' });
|
|
1141
|
+
for (const line of (res.stdout || '').split(/\r?\n/)) {
|
|
1142
|
+
const p = line.trim().split(/\s+/);
|
|
1143
|
+
if (p.length >= 5 && /LISTENING/i.test(p[3]) && p[1].endsWith(`:${port}`)) {
|
|
1144
|
+
if (/^\d+$/.test(p[4]) && p[4] !== '0') pids.add(p[4]);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
// lsof tidak selalu terinstall (mis. minimal container) - tolerant, skip kalau gagal.
|
|
1149
|
+
const res = spawnSync(`lsof -ti tcp:${port}`, { shell: true, encoding: 'utf8' });
|
|
1150
|
+
for (const line of (res.stdout || '').split(/\r?\n/)) {
|
|
1151
|
+
const pid = line.trim();
|
|
1152
|
+
if (/^\d+$/.test(pid)) pids.add(pid);
|
|
1141
1153
|
}
|
|
1142
1154
|
}
|
|
1155
|
+
|
|
1143
1156
|
if (pids.size === 0) return;
|
|
1144
1157
|
console.log(` Port ${port} in use (PID ${[...pids].join(', ')}); stopping old process...`);
|
|
1145
|
-
for (const pid of pids)
|
|
1158
|
+
for (const pid of pids) {
|
|
1159
|
+
const killCmd = isWin ? `taskkill /PID ${pid} /F` : `kill -9 ${pid}`;
|
|
1160
|
+
spawnSync(killCmd, { shell: true, stdio: 'inherit' });
|
|
1161
|
+
}
|
|
1146
1162
|
}
|
|
1147
1163
|
|
|
1148
1164
|
/** Pipeline REST API nyata: env -> validate -> migrate -> payload+endpoint. */
|
|
@@ -1230,7 +1246,12 @@ function runFrontendPipeline(ctx) {
|
|
|
1230
1246
|
|
|
1231
1247
|
phase('[F3/3] Generate frontend application');
|
|
1232
1248
|
// Hapus index.html lama agar landing page diregenerasi sesuai set page terbaru.
|
|
1233
|
-
|
|
1249
|
+
// Pakai fs langsung (bukan shell command) supaya portable Windows/Linux/macOS.
|
|
1250
|
+
try {
|
|
1251
|
+
fs.unlinkSync(path.join(frontendDir, 'apps', ctx.project, 'index.html'));
|
|
1252
|
+
} catch {
|
|
1253
|
+
// File belum ada (first run) - abaikan.
|
|
1254
|
+
}
|
|
1234
1255
|
run(`restforge-designer generate --payload=payload/${appCode}.json --output=./apps/${ctx.project} ${pluginArg} --overwrite`, frontendDir);
|
|
1235
1256
|
}
|
|
1236
1257
|
|
|
@@ -1271,6 +1292,66 @@ function writeServerStartScript(ctx) {
|
|
|
1271
1292
|
return file;
|
|
1272
1293
|
}
|
|
1273
1294
|
|
|
1295
|
+
/**
|
|
1296
|
+
* Tulis launcher start frontend mandiri di folder app (frontend/apps/<project>/).
|
|
1297
|
+
* Windows -> frontend-start.bat, Linux/macOS -> frontend-start.sh. Sama seperti
|
|
1298
|
+
* writeServerStartScript, dipakai juga sebagai target `pm2 start` di non-Windows.
|
|
1299
|
+
*/
|
|
1300
|
+
function writeFrontendStartScript(ctx) {
|
|
1301
|
+
const serveCmd = `npx serve . -l ${ctx.cfg.WEB_SERVER_PORT}`;
|
|
1302
|
+
const isWin = process.platform === 'win32';
|
|
1303
|
+
const appDir = path.join(ctx.cwd, 'frontend', 'apps', ctx.project);
|
|
1304
|
+
const file = path.join(appDir, isWin ? 'frontend-start.bat' : 'frontend-start.sh');
|
|
1305
|
+
let content;
|
|
1306
|
+
if (isWin) {
|
|
1307
|
+
content = [
|
|
1308
|
+
'@echo off',
|
|
1309
|
+
'REM Start RESTForge frontend app. Generated by fast-track.',
|
|
1310
|
+
'cd /d "%~dp0"',
|
|
1311
|
+
`call ${serveCmd}`,
|
|
1312
|
+
''
|
|
1313
|
+
].join('\r\n');
|
|
1314
|
+
} else {
|
|
1315
|
+
content = [
|
|
1316
|
+
'#!/usr/bin/env bash',
|
|
1317
|
+
'# Start RESTForge frontend app. Generated by fast-track.',
|
|
1318
|
+
'set -e',
|
|
1319
|
+
'cd "$(dirname "$0")"',
|
|
1320
|
+
serveCmd,
|
|
1321
|
+
''
|
|
1322
|
+
].join('\n');
|
|
1323
|
+
}
|
|
1324
|
+
fs.writeFileSync(file, content);
|
|
1325
|
+
if (!isWin) {
|
|
1326
|
+
try { fs.chmodSync(file, 0o755); } catch { /* abaikan bila FS tak dukung chmod */ }
|
|
1327
|
+
}
|
|
1328
|
+
return file;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* pm2 dipakai di Linux/macOS sebagai pengganti "open new window" (konsep
|
|
1333
|
+
* Windows-only) untuk mengelola proses server/frontend: pm2 list/logs/reload/
|
|
1334
|
+
* stop, bukan raw PID. Nama proses dibedakan per-project per-kind agar tidak
|
|
1335
|
+
* collision antar project yang dijalankan bersamaan.
|
|
1336
|
+
*/
|
|
1337
|
+
function pm2Name(project, kind) {
|
|
1338
|
+
return `${project}-${kind}`;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Start (ulang) script launcher via pm2. Idempotent: hapus instance lama dulu
|
|
1343
|
+
* (silent, tolerant bila belum ada) supaya re-run fast-track tidak gagal
|
|
1344
|
+
* dengan "already launched". Return false bila pm2 tidak tersedia/gagal.
|
|
1345
|
+
*/
|
|
1346
|
+
function pm2StartScript(name, scriptPath, cwd) {
|
|
1347
|
+
spawnSync(`pm2 delete ${name} --silent`, { shell: true, stdio: 'ignore' });
|
|
1348
|
+
const r = spawnSync(
|
|
1349
|
+
`pm2 start "${scriptPath}" --name ${name} --cwd "${cwd}" --interpreter bash`,
|
|
1350
|
+
{ shell: true, stdio: 'inherit' }
|
|
1351
|
+
);
|
|
1352
|
+
return !r.error && r.status === 0;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1274
1355
|
function printFinalSummary(ctx) {
|
|
1275
1356
|
const parts = [];
|
|
1276
1357
|
if (ctx.scope.backend) parts.push('REST API generated');
|
|
@@ -1287,6 +1368,9 @@ function printFinalSummary(ctx) {
|
|
|
1287
1368
|
}
|
|
1288
1369
|
if (ctx.scope.frontend) {
|
|
1289
1370
|
console.log(` Frontend : frontend/apps/${ctx.project}/ (start: npx serve . -l ${ctx.cfg.WEB_SERVER_PORT})`);
|
|
1371
|
+
if (ctx.frontendStartFile) {
|
|
1372
|
+
console.log(` Start : ${path.basename(ctx.frontendStartFile)} (start frontend manually)`);
|
|
1373
|
+
}
|
|
1290
1374
|
}
|
|
1291
1375
|
console.log(rule('='));
|
|
1292
1376
|
}
|
|
@@ -1304,20 +1388,35 @@ async function startServerNow(ctx) {
|
|
|
1304
1388
|
const serveCmd = `npx restforge serve --project=${ctx.project} --config=${ctx.configFlag} --watch`;
|
|
1305
1389
|
freePort(ctx.cfg.SERVER_PORT);
|
|
1306
1390
|
const title = `RESTForge Server - ${ctx.project}`;
|
|
1307
|
-
console.log(`\n Opening new window: "${title}"`);
|
|
1308
|
-
console.log(`#${serveCmd}`);
|
|
1309
1391
|
// server.js (dispatcher) memaksa NODE_ENV=production untuk proses cli command,
|
|
1310
1392
|
// sehingga fast-track berjalan production dan secara default akan mewariskannya
|
|
1311
1393
|
// ke serve -> logger memakai format JSON mentah (verbose). Set development agar
|
|
1312
1394
|
// runtime server memakai pino-pretty (rapi), konsisten dengan playbook yang
|
|
1313
1395
|
// menjalankan serve dari plain `node`.
|
|
1314
1396
|
const serveEnv = { ...process.env, NODE_ENV: 'development' };
|
|
1315
|
-
|
|
1316
|
-
if (
|
|
1317
|
-
console.log(
|
|
1318
|
-
|
|
1397
|
+
|
|
1398
|
+
if (process.platform === 'win32') {
|
|
1399
|
+
console.log(`\n Opening new window: "${title}"`);
|
|
1400
|
+
console.log(`#${serveCmd}`);
|
|
1401
|
+
const r = spawnSync('cmd', ['/C', 'start', title, 'cmd', '/k', serveCmd], { cwd: ctx.cwd, stdio: 'inherit', env: serveEnv });
|
|
1402
|
+
if (r.error) {
|
|
1403
|
+
console.log(` Failed to open server window: ${r.error.message}`);
|
|
1404
|
+
return false;
|
|
1405
|
+
}
|
|
1406
|
+
console.log(' ✓ Server window opened. Keep it open. Stop with Ctrl+C.');
|
|
1407
|
+
} else {
|
|
1408
|
+
// Tidak ada konsep "window baru" di Linux/macOS (terutama session SSH headless) -
|
|
1409
|
+
// pakai pm2 supaya proses bisa dikelola normal (pm2 list/logs/reload/stop).
|
|
1410
|
+
console.log(`\n Starting via pm2: "${title}"`);
|
|
1411
|
+
const name = pm2Name(ctx.project, 'server');
|
|
1412
|
+
const ok = pm2StartScript(name, ctx.serverStartFile, ctx.cwd);
|
|
1413
|
+
if (!ok) {
|
|
1414
|
+
console.log(' Failed to start via pm2. Is pm2 installed? (npm install -g pm2)');
|
|
1415
|
+
return false;
|
|
1416
|
+
}
|
|
1417
|
+
console.log(` ✓ Server started via pm2 as "${name}".`);
|
|
1418
|
+
console.log(` pm2 logs ${name} | pm2 reload ${name} | pm2 stop ${name}`);
|
|
1319
1419
|
}
|
|
1320
|
-
console.log(' ✓ Server window opened. Keep it open. Stop with Ctrl+C.');
|
|
1321
1420
|
|
|
1322
1421
|
// Health check: tunggu runtime benar-benar siap menerima request sebelum
|
|
1323
1422
|
// lanjut (mis. ke frontend). URL = banner runtime: /api/<project>/health.
|
|
@@ -1365,14 +1464,27 @@ async function startFrontendNow(ctx) {
|
|
|
1365
1464
|
}
|
|
1366
1465
|
freePort(webPort);
|
|
1367
1466
|
const title = `RESTForge Frontend - ${ctx.project}`;
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1467
|
+
|
|
1468
|
+
if (process.platform === 'win32') {
|
|
1469
|
+
console.log(`\n Opening new window: "${title}"`);
|
|
1470
|
+
console.log(`#${serveCmd}`);
|
|
1471
|
+
const r = spawnSync('cmd', ['/C', 'start', title, 'cmd', '/k', serveCmd], { cwd: appDir, stdio: 'inherit' });
|
|
1472
|
+
if (r.error) {
|
|
1473
|
+
console.log(` Failed to open frontend window: ${r.error.message}`);
|
|
1474
|
+
return false;
|
|
1475
|
+
}
|
|
1476
|
+
console.log(` ✓ Frontend window opened (WEB_SERVER_PORT ${webPort}).`);
|
|
1477
|
+
} else {
|
|
1478
|
+
console.log(`\n Starting via pm2: "${title}"`);
|
|
1479
|
+
const name = pm2Name(ctx.project, 'frontend');
|
|
1480
|
+
const ok = pm2StartScript(name, ctx.frontendStartFile, appDir);
|
|
1481
|
+
if (!ok) {
|
|
1482
|
+
console.log(' Failed to start via pm2. Is pm2 installed? (npm install -g pm2)');
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
console.log(` ✓ Frontend started via pm2 as "${name}" (WEB_SERVER_PORT ${webPort}).`);
|
|
1486
|
+
console.log(` pm2 logs ${name} | pm2 reload ${name} | pm2 stop ${name}`);
|
|
1374
1487
|
}
|
|
1375
|
-
console.log(` ✓ Frontend window opened (WEB_SERVER_PORT ${webPort}).`);
|
|
1376
1488
|
|
|
1377
1489
|
const url = `http://localhost:${webPort}/index.html`;
|
|
1378
1490
|
// Tunggu static server (`npx serve`) benar-benar siap sebelum buka browser,
|
|
@@ -1387,7 +1499,12 @@ async function startFrontendNow(ctx) {
|
|
|
1387
1499
|
if (!ready.ok) {
|
|
1388
1500
|
console.log(' ⚠ Frontend belum merespons - buka URL di atas manual bila browser tidak otomatis terbuka.');
|
|
1389
1501
|
}
|
|
1390
|
-
const
|
|
1502
|
+
const openCmd = process.platform === 'win32'
|
|
1503
|
+
? ['cmd', ['/C', 'start', '""', url]]
|
|
1504
|
+
: process.platform === 'darwin'
|
|
1505
|
+
? ['open', [url]]
|
|
1506
|
+
: ['xdg-open', [url]];
|
|
1507
|
+
const openResult = spawnSync(openCmd[0], openCmd[1], { stdio: 'ignore' });
|
|
1391
1508
|
if (openResult.error) {
|
|
1392
1509
|
console.log(` (Could not open browser automatically: ${openResult.error.message})`);
|
|
1393
1510
|
}
|
|
@@ -1552,6 +1669,9 @@ module.exports = {
|
|
|
1552
1669
|
}
|
|
1553
1670
|
if (ctx.scope.frontend) {
|
|
1554
1671
|
runFrontendPipeline(ctx);
|
|
1672
|
+
// Launcher start frontend mandiri (sesuai OS), dipakai juga sebagai
|
|
1673
|
+
// target `pm2 start` di non-Windows.
|
|
1674
|
+
ctx.frontendStartFile = writeFrontendStartScript(ctx);
|
|
1555
1675
|
}
|
|
1556
1676
|
|
|
1557
1677
|
printFinalSummary(ctx);
|
|
@@ -21,8 +21,14 @@ const path = require('path');
|
|
|
21
21
|
const { spawnSync } = require('child_process');
|
|
22
22
|
|
|
23
23
|
function resolveBinaryPath() {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const platform = os.platform();
|
|
25
|
+
if (platform === 'win32') {
|
|
26
|
+
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools.exe');
|
|
27
|
+
}
|
|
28
|
+
if (platform === 'linux') {
|
|
29
|
+
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools-linux');
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
module.exports = {
|
|
@@ -51,7 +57,7 @@ module.exports = {
|
|
|
51
57
|
const binaryPath = resolveBinaryPath();
|
|
52
58
|
if (!binaryPath) {
|
|
53
59
|
const err = new Error(
|
|
54
|
-
`schema init
|
|
60
|
+
`schema init tidak didukung di platform ini (sdf-tools). Platform saat ini: ${os.platform()}`
|
|
55
61
|
);
|
|
56
62
|
err.exitCode = 3;
|
|
57
63
|
throw err;
|
|
@@ -59,13 +65,21 @@ module.exports = {
|
|
|
59
65
|
|
|
60
66
|
if (!fs.existsSync(binaryPath)) {
|
|
61
67
|
const err = new Error(
|
|
62
|
-
`sdf-tools
|
|
68
|
+
`Binary sdf-tools tidak ditemukan di ${binaryPath}. ` +
|
|
63
69
|
'Pastikan binary sudah di-build dan tersedia di folder bin/ package.'
|
|
64
70
|
);
|
|
65
71
|
err.exitCode = 3;
|
|
66
72
|
throw err;
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
if (os.platform() !== 'win32') {
|
|
76
|
+
try {
|
|
77
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
78
|
+
} catch {
|
|
79
|
+
// FS tak dukung chmod (mis. read-only mount) — lanjut, biarkan spawnSync gagal kalau memang tidak executable.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
const binaryArgs = [
|
|
70
84
|
'--table=dummy',
|
|
71
85
|
'--generate',
|
|
@@ -79,14 +93,14 @@ module.exports = {
|
|
|
79
93
|
});
|
|
80
94
|
|
|
81
95
|
if (result.error) {
|
|
82
|
-
const err = new Error(`Gagal menjalankan sdf-tools
|
|
96
|
+
const err = new Error(`Gagal menjalankan sdf-tools: ${result.error.message}`);
|
|
83
97
|
err.exitCode = 1;
|
|
84
98
|
throw err;
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
const status = typeof result.status === 'number' ? result.status : 1;
|
|
88
102
|
if (status !== 0) {
|
|
89
|
-
const err = new Error(`sdf-tools
|
|
103
|
+
const err = new Error(`sdf-tools exit code ${status}`);
|
|
90
104
|
err.exitCode = status;
|
|
91
105
|
err.silent = true;
|
|
92
106
|
throw err;
|
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
* bin/. Semua filter dan display flag diteruskan ke binary; help text di sisi
|
|
10
10
|
* Node mempertahankan kontrak CLI (contract validator + help generator).
|
|
11
11
|
*
|
|
12
|
-
* Binary lookup: <package-root>/bin/sdf-tools.exe
|
|
12
|
+
* Binary lookup: <package-root>/bin/sdf-tools.exe (Windows) atau
|
|
13
|
+
* <package-root>/bin/sdf-tools-linux (Linux), relatif terhadap file ini
|
|
13
14
|
* (resolusi sama untuk source workspace dan installation di node_modules).
|
|
14
15
|
*
|
|
15
|
-
* Platform:
|
|
16
|
-
*
|
|
16
|
+
* Platform: Windows dan Linux x86_64. Platform lain (mis. macOS) akan
|
|
17
|
+
* return error eksplisit, bukan crash diam-diam.
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
const fs = require('fs');
|
|
@@ -36,8 +37,14 @@ const BOOLEAN_FLAGS = [
|
|
|
36
37
|
];
|
|
37
38
|
|
|
38
39
|
function resolveBinaryPath() {
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
const platform = os.platform();
|
|
41
|
+
if (platform === 'win32') {
|
|
42
|
+
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools.exe');
|
|
43
|
+
}
|
|
44
|
+
if (platform === 'linux') {
|
|
45
|
+
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools-linux');
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
50
|
function buildBinaryArgs(args) {
|
|
@@ -185,7 +192,7 @@ module.exports = {
|
|
|
185
192
|
const binaryPath = resolveBinaryPath();
|
|
186
193
|
if (!binaryPath) {
|
|
187
194
|
const err = new Error(
|
|
188
|
-
`schema template
|
|
195
|
+
`schema template tidak didukung di platform ini (sdf-tools). Platform saat ini: ${os.platform()}`
|
|
189
196
|
);
|
|
190
197
|
err.exitCode = 3;
|
|
191
198
|
throw err;
|
|
@@ -193,13 +200,21 @@ module.exports = {
|
|
|
193
200
|
|
|
194
201
|
if (!fs.existsSync(binaryPath)) {
|
|
195
202
|
const err = new Error(
|
|
196
|
-
`sdf-tools
|
|
203
|
+
`Binary sdf-tools tidak ditemukan di ${binaryPath}. ` +
|
|
197
204
|
'Pastikan binary sudah di-build dan tersedia di folder bin/ package.'
|
|
198
205
|
);
|
|
199
206
|
err.exitCode = 3;
|
|
200
207
|
throw err;
|
|
201
208
|
}
|
|
202
209
|
|
|
210
|
+
if (os.platform() !== 'win32') {
|
|
211
|
+
try {
|
|
212
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
213
|
+
} catch {
|
|
214
|
+
// FS tak dukung chmod (mis. read-only mount) — lanjut, biarkan spawnSync gagal kalau memang tidak executable.
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
203
218
|
const binaryArgs = buildBinaryArgs(args);
|
|
204
219
|
const result = spawnSync(binaryPath, binaryArgs, {
|
|
205
220
|
stdio: 'inherit',
|
|
@@ -207,14 +222,14 @@ module.exports = {
|
|
|
207
222
|
});
|
|
208
223
|
|
|
209
224
|
if (result.error) {
|
|
210
|
-
const err = new Error(`Gagal menjalankan sdf-tools
|
|
225
|
+
const err = new Error(`Gagal menjalankan sdf-tools: ${result.error.message}`);
|
|
211
226
|
err.exitCode = 1;
|
|
212
227
|
throw err;
|
|
213
228
|
}
|
|
214
229
|
|
|
215
230
|
const status = typeof result.status === 'number' ? result.status : 1;
|
|
216
231
|
if (status !== 0) {
|
|
217
|
-
const err = new Error(`sdf-tools
|
|
232
|
+
const err = new Error(`sdf-tools exit code ${status}`);
|
|
218
233
|
err.exitCode = status;
|
|
219
234
|
err.silent = true;
|
|
220
235
|
throw err;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const a0_0x20f86c=a0_0x2283;(function(_0x5b5bff,_0x206b7d){const _0x4bdb08=a0_0x2283,_0x46a584=_0x5b5bff();while(!![]){try{const _0x8d6e45=parseInt(_0x4bdb08(0x134))/0x1+parseInt(_0x4bdb08(0x108))/0x2*(parseInt(_0x4bdb08(0x120))/0x3)+parseInt(_0x4bdb08(0x10f))/0x4+-parseInt(_0x4bdb08(0x10a))/0x5+parseInt(_0x4bdb08(0x12e))/0x6*(parseInt(_0x4bdb08(0x125))/0x7)+parseInt(_0x4bdb08(0x166))/0x8*(parseInt(_0x4bdb08(0x136))/0x9)+-parseInt(_0x4bdb08(0x152))/0xa;if(_0x8d6e45===_0x206b7d)break;else _0x46a584['push'](_0x46a584['shift']());}catch(_0x40804b){_0x46a584['push'](_0x46a584['shift']());}}}(a0_0x1538,0x93c66));function a0_0x2283(_0x2e320c,_0x4f958e){_0x2e320c=_0x2e320c-0x106;const _0x1538ac=a0_0x1538();let _0x2283c5=_0x1538ac[_0x2e320c];if(a0_0x2283['MdNWvK']===undefined){var _0xe908e=function(_0x3bd183){const _0x3fbce5='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x14c42a='',_0x358bd1='';for(let _0x35093b=0x0,_0x4efde2,_0x541bd2,_0x2592a6=0x0;_0x541bd2=_0x3bd183['charAt'](_0x2592a6++);~_0x541bd2&&(_0x4efde2=_0x35093b%0x4?_0x4efde2*0x40+_0x541bd2:_0x541bd2,_0x35093b++%0x4)?_0x14c42a+=String['fromCharCode'](0xff&_0x4efde2>>(-0x2*_0x35093b&0x6)):0x0){_0x541bd2=_0x3fbce5['indexOf'](_0x541bd2);}for(let _0x3160f8=0x0,_0x5d7dab=_0x14c42a['length'];_0x3160f8<_0x5d7dab;_0x3160f8++){_0x358bd1+='%'+('00'+_0x14c42a['charCodeAt'](_0x3160f8)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x358bd1);};a0_0x2283['zLtAEQ']=_0xe908e,a0_0x2283['uYIOpr']={},a0_0x2283['MdNWvK']=!![];}const _0x18f5a0=_0x1538ac[0x0],_0x203ecc=_0x2e320c+_0x18f5a0,_0x228efa=a0_0x2283['uYIOpr'][_0x203ecc];return!_0x228efa?(_0x2283c5=a0_0x2283['zLtAEQ'](_0x2283c5),a0_0x2283['uYIOpr'][_0x203ecc]=_0x2283c5):_0x2283c5=_0x228efa,_0x2283c5;}function a0_0x1538(){const _0x43c469=['Dg9WlwXLDMvSicDWyxjHBxmNig9IAMvJDa','zgfZAc1ZywXLCW','nKzQBLj5ta','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGyNjLywTKB3DUigfJCM9ZCYbJyxrLz29YAwvZlIbtDwL0ywjSzsbMB3iGD2LKz2v0CYbSAwTLicDfEhbLy3rLzcbfyxjUAw5NCYCGDgHHDcbZAg93ihrVDgfSihzHBhvLlcbWzxjJzw50ywDLignOyw5NzsWGyw5KihbLCI1JyxrLz29YEsbJB250CMLIDxrPB24U','rgvMyxvSDcb2ywX1zsbHChbSAwvKihDOzw4GDgHLihjLCxvLC3qGB21PDhmGDgHPCYbWyxjHBs4GvMfSAwrHDg9YigrVzxmGtK9uihn0CMLJDgX5ihr5CguTy2HLy2SGzgvMyxvSDdSGCNvUDgLTzsbPCYbYzxnWB25ZAwjSzsbMB3iGy29TCgf0AwjPBgL0Es4','Dg9WlwXLDMvSicDJywnOzsCGB2jQzwn0','tgLZDcbVzIb3AwrNzxqGzgvMAw5PDgLVBNmUie9YzgvYigLZigLUzM9YBwf0Aw9UywWGB25SEsaOCMvZCg9UC2uGA2v5CYbHCMuGyNKGD2LKz2v0igLKlcbUB3qGyxjYyxKGAw5KzxGPlG','phDPzgDLDf9Pzd4','mtm1nZC1yujnuMXe','tIbYB3DZimoxie0Gy29SCW','mta0nJyZndnNAgnVwvO','DgfYz2v0','zxHWzwn0zwrFzwfYBMLUz3m','vgHLihbYzwzPEcbIzwnVBwvZihbHCNqGB2yGDgHLifvstcbZzwDTzw50lIbuAguGCMvZzxj2zwqGC2nOzw1LigTLzxbZigrHC2HIB2fYzcbLBMrWB2LUDhmGDMLZDwfSBhKGzgLZDgLUy3qGzNjVBsbduLveigvUzhbVAw50CYbPBIb0AguGvvjmihnWywnLigfUzcbHBgXVD3mGzNv0DxjLihjVDxrPBMCGzgLMzMvYzw50Awf0Aw9UlG','vuKGBgfIzwWGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBI4','B2jQzwn0','u2LUz2XLifnrtcbXDwvYEsbMB3iGDgHLihDPzgDLDc4','zgfZAc1PBMjVDw5K','zgfZAc1HDxrOB3iTC3rHDhm','tIbYB3DZimoxidiGy29SDw1UCW','yxjYyxK8C3rYAw5NpIWGB3b0Aw9UywWG4Ocuihn1yNnLDcbVzIb3AwrNzxqGsurZihrVigv4zwn1DguUie9TAxqGDg8GzxHLy3v0zsbHBgWGzgvJBgfYzwqGD2LKz2v0CY4','zMLSztPXDwvYEs88Cgf0Ad4VDhjLBMqUC3fS','qsbWyxLSB2fKihDPDgGGyM90AcaND2LKz2v0CYCGyw5KicD0ywjSzu5HBwuNigLZihjLAMvJDgvKigj5ierHC2HIB2fYzfzHBgLKyxrVCI4GugLJAYbVBMuGC2HHCguU','vMLZDwfSignVBg9YigLZigeGzNjVBNrLBMqGCMvUzgvYAw5NignVBMnLCM4U','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxig11BhrPCgXLignVBhvTBNm','ue9tvcaVyxbPl21PBMKTAw52zw50B3j5l2rHC2GTAw5IB3vUzc9KyxnOyM9HCMq','CxvLCNK','Aw5OzxjPDhmGq0fdsevFvfrmigvUDG','vgfIBguGzgv0zwn0zwqGAw4Gu1fmlcbIDxqGBM90ihjLz2LZDgvYzwqGyxmGq1jvrcbLBMrWB2LUDcbPBIbTzxrHzgf0ysbWCM9Qzwn0icHSAwTLBhKGysb2Awv3lcbdveuGywXPyxmSig9YignYB3nZlxbYB2PLy3qGDgfIBguG4OcuignHC2nHzguGD2LSBcbUB3qGzMLYzsK','zMLSztPXDwvYEs88Cgf0Ad4VCg9PBNrZlNnXBa','D2LKz2v0lNf1zxj5icHZAw5NDwXHCIK','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','BgvUz3rO','ugfYyw0Gzgf0ysb0ExbLlIbwywXPzgf0zxmGCMvXDwvZDcbIB2r5igfUzcbZAgfWzxmGCNvUDgLTzsbWyxjHBwv0zxiGyMLUzgLUzY4','DhjLBMq','zMLSztPXDwvYEs88Cgf0Ad4VDMfSDwuUC3fS','B2jQzwn0iokaLcb2ywX1zxmGzM9YigrLy2XHCMvKihbHCMfTCYaODMfSAwrHDgvKigfNywLUC3qGCgfYyw1ZignVBNrYywn0oYbTAxnZAw5NihjLCxvPCMvKiokgKIa0mdaSihr5CguGBwLZBwf0y2GG4OAsidqWmcK','y2fJAgu','mtmWndy0nJbHqxfKsMK','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGC3bHCMTSAw5Lig1PBMKTy2HHCNqGzM9YihnOB3j0ihDPBMrVD3mGkdCGzgf5CYWGmtiGBw9UDgHZlcbLDgmUks4Gu3vPDgfIBguGzM9YihDPzgDLDhmGBgLRzsaNqxzLCMfNzsbeywLSEsbtywXLCYCU','yM9VBgvHBG','zgLYzwn0Aw9U','q29SBgfWC2uGDg8GB2jQzwn0ihDOB3nLigTLExmGyxjLifnrtcbJB2X1Bw4GBMfTzxmGkgXVD2vYy2fZzwqPlG','yxjYyxK8C3rYAw5NpG','CgvYAw9K','D2LKz2v0CW','msbYB3CGW5CGmsbJB2X1Bw4','DMfSDwu','iJe4mZyI','msbYB3CGW5CGmIbJB2X1Bw5Z','rxzLCNKGCgXHy2vOB2XKzxiGDxnLzcbPBIbtuuWGtvvtvcbIzsbKzwnSyxjLzcbPBIaNCgfYyw1ZjY4GvMfSAwrHDg9YihrOCM93CYbfCNjVCIb3AxrOig1LC3nHz2uGzM9YBwf0oIaIv2LKz2v0icC8Awq+jYbXDwvYEsaNpgXHyMvSpICGDxnLCYb1BMrLy2XHCMvKihbSywnLAg9SzgvYicC6phrVA2vUpICGkgrLy2XHCMuGAw4Gj3bHCMfTCYCPiI4','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','zxHWB3j0CW','C2nHBgfYihbYAw1PDgL2zq','q29SBgfWC2uGDg8GC2nHBgfYihbYAw1PDgL2zsaODgHLihzHBhvLig9MihrOzsbZAw5NBguGy29SDw1Uks4','BM9UlwvTChr5lcb1BMLXDwuGywnYB3nZihDPzgDLDhmGAw4GDgHLihnHBwuGCgf5Bg9Hza','ugfYyw0GBMfTzsbTDxn0ig1HDgnOihrOzsbWBgfJzwHVBgrLCIbYzwDLEcbGw2eTEKeTwL9Dw2eTEKeTwJaTov9DkMaGkgfSCgHHBNvTzxjPyYaRihvUzgvYC2nVCMuSig11C3qGC3rHCNqGD2L0AcbSzxr0zxiGB3iGDw5KzxjZy29YzsKU','w3SGiMXHyMvSiJOGiLnOB2vZiIWGiNzHBhvLiJOGiJC2nJaIih0SihSGiMXHyMvSiJOGiKDHBwLUzYiSicj2ywX1zsi6iciYodiWiIb9lcb7icjSywjLBci6icjpDgHLCNmIlcaIDMfSDwuIoIaInduYntCIih1D','ofzOvuzQAG','BNvTyMvY','AxrLBxm','DgfIBgvoyw1L','mtzyqMDfChG','B3jKzxjZx3rOAxnFBw9UDgG','ntC1ntK1nwT5vwjVAa','Bgf5B3v0','zNjVBNrLBMqTy29Uy2vYBG','Aw52ywXPzgf0zxm','v2HLBIb0CNvLlcb0AguGCMvXDwvZDcbIB2r5ie1vu1qGAw5JBhvKzsb0AgLZihbHCMfTicHVDgHLCNDPC2uGndaWks4','mZy5odG0ogffuvfXBq','zMLSztPXDwvYEs88Cgf0Ad4VyNjLywTKB3DUlNnXBa','yw55icGXihjVDYddLYaXignVBcWGtIbYB3DZimoxie0Gy29SCYWGzxrJlIK','kd88itOPoIHBys16qs1Ax11Bys16qs1Amc05x10Qkq','vgLTzs10BY1SAxzLigLUihnLy29UzhmUidaGzwzMzwn0AxzLBhKGzgLZywjSzxmGy2fJAguGzM9YihrOAxmGzw50CNKU','zgf0zq','qwX3yxLZihSGAxrLBxm6ifSUlI5Dih0GCMvNyxjKBgvZCYbVzIbtuuWGCMvZDwX0ihnOyxbLlG','DgL0Bgu','xMrHC2GTw2eTEKeTwJaTov8TxsSK','C3rYAw5N','iJi0mJaI','CgfYyw1Z','twv0CMLJicSGuhjVz3jLC3mGDg8Gr29HBa','l2fWAs97ChjVAMvJDh0VE25HBwv9l2rHC2HIB2fYza','Ahr0Chm6lY9Yzxn0zM9Yz2uUzgv2l2rVy3mVC2vYDMvYl3f1zxj5lwrHDgeVzgfZAgjVyxjK','iNzHBhvLiJOGiJy5nZaWiG','vg9Nz2XLignHy2HLigzLyxr1CMuGzM9YihrOAxmGzgfZAgjVyxjKlG','mJK4mdq3CwjVBgnl','DhrS','vMLZDwfSihzHCMLHBNqGkgrVBNv0lcbIyxiSihbPzsWGyxjLysKGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBIaOC2vWyxjHDgLVBIbVzIbJB25JzxjUCYKU','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxideGy29SDw1U','twv0CMLJicSGrg9UDxqGqNjLywTKB3DU','mZaWnde5Dw5bEKjY','zMLSztPXDwvYEs88Cgf0Ad4VDgfYz2v0lNnXBa','CMvXDwLYzwq','qwX3yxLZihDYyxaGyxmGEYbPDgvTCZOGwY4UlL0GFsbYzwDHCMrSzxnZig9MifnrtcbYzxn1BhqGC2HHCguU','iNrYzw5KiJOGEYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJiIih0','zgfZAgjVyxjKihbHEwXVywq','rNjVBNrLBMqGzgv0zxjTAw5LCYbKB251Dc9WAwuGDMfYAwfUDcWGy29SB3iGCgvYignHDgvNB3j5lcbHBMqGBgfIzwWGB3jKzxiUieLMihbLCI1JyxrLz29YEsbWzxjJzw50ywDLigLZig5LzwrLzcbMB3iGDgHLigrVBNv0igfYyYWGzNjVBNrLBMqGy29TChv0zxmGAxqGzNjVBsbPDgvTC1TPxs52ywX1zsaVihn1BsHPDgvTC1SQxs52ywX1zsKUie5Vig5LzwqGDg8GC2vUzcaNCgn0jYbMCM9TigjHy2TLBMqGDw5SzxnZihrOzsbMAwD1CMuGAxmGysbZDgfIBguGyNvZAw5LC3mGy2fSy3vSyxrPB24GAw5KzxbLBMrLBNqGB2yGDMLZDwfSihjLBMrLCMLUzY4'];a0_0x1538=function(){return _0x43c469;};return a0_0x1538();}const FORBIDDEN_FRONTEND_FIELDS=['widgetType',a0_0x20f86c(0x10b),a0_0x20f86c(0x116),'subtitle','color'],ALLOWED_PARAM_TYPES=['string','number',a0_0x20f86c(0x154),a0_0x20f86c(0x114)],FRONTEND_CONCERN_REASONS={'widgetType':a0_0x20f86c(0x122),'layout':'Layout\x20is\x20a\x20frontend\x20rendering\x20concern.','title':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','subtitle':a0_0x20f86c(0x13a),'color':a0_0x20f86c(0x143)},PAYLOAD_SHAPE={'discriminator':{'field':a0_0x20f86c(0x159),'presentMeans':a0_0x20f86c(0x12a),'absentMeans':'Not\x20a\x20dashboard\x20payload\x20(likely\x20CRUD\x20with\x20tableName,\x20or\x20invalid)','conflictsWith':'tableName','conflictRationale':a0_0x20f86c(0x142)},'topLevelAllowed':[{'name':a0_0x20f86c(0x159),'type':'array','required':!![],'minItems':0x1,'description':a0_0x20f86c(0x132)},{'name':a0_0x20f86c(0x11a),'type':a0_0x20f86c(0x13b),'required':![],'description':'Parameter\x20contract\x20for\x20the\x20dashboard.\x20Each\x20key\x20is\x20a\x20param\x20name;\x20values\x20describe\x20type/required/default.\x20Placeholders\x20inside\x20widget\x20SQL\x20must\x20reference\x20declared\x20param\x20names.'},{'name':a0_0x20f86c(0x151),'type':'object','required':![],'description':'Optional\x20cache\x20configuration.\x20See\x20cacheSpec\x20for\x20details.'}],'topLevelForbidden':[{'name':a0_0x20f86c(0x107),'category':'shape-conflict','reason':'Reserved\x20for\x20CRUD\x20payloads.\x20A\x20dashboard\x20payload\x20must\x20declare\x20\x27widgets\x27\x20instead.'},...FORBIDDEN_FRONTEND_FIELDS['map'](_0x14c42a=>({'name':_0x14c42a,'category':a0_0x20f86c(0x10c),'reason':FRONTEND_CONCERN_REASONS[_0x14c42a]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':a0_0x20f86c(0x118),'constraint':a0_0x20f86c(0x163),'description':'Widget\x20identifier;\x20used\x20as\x20the\x20response\x20key\x20in\x20the\x20dashboard\x20envelope.'}],'exclusiveQueryFields':{'rule':'A\x20widget\x20MUST\x20declare\x20exactly\x20one\x20of:\x20\x27query\x27\x20OR\x20\x27queries\x27.\x20Both\x20or\x20neither\x20is\x20rejected.','options':[{'name':a0_0x20f86c(0x146),'type':'string','format':'file:relative/path/to/query.sql','description':a0_0x20f86c(0x13c),'responseShape':a0_0x20f86c(0x115)},{'name':'queries','type':a0_0x20f86c(0x13b),'format':'key→file:relative/path/to/query.sql','minKeys':0x1,'description':'Multi-SQL\x20widget.\x20Each\x20key\x20becomes\x20a\x20key\x20in\x20the\x20response\x20object.','responseShape':'Per-key\x20based\x20on\x20scalarCollapseRules\x20below.'}]},'forbiddenFields':FORBIDDEN_FRONTEND_FIELDS},PARAM_SPEC={'container':a0_0x20f86c(0x12c),'keyConvention':a0_0x20f86c(0x164),'perEntryFields':[{'name':'type','required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':a0_0x20f86c(0x14d)},{'name':a0_0x20f86c(0x127),'required':![],'type':a0_0x20f86c(0x154),'default':![],'description':a0_0x20f86c(0x10e)},{'name':'default','required':![],'type':'any\x20(must\x20be\x20compatible\x20with\x20declared\x20\x27type\x27)','description':a0_0x20f86c(0x130)}]},SCALAR_COLLAPSE_RULES=[{'appliesTo':a0_0x20f86c(0x14a),'rule':a0_0x20f86c(0x128),'exampleSqlShape':a0_0x20f86c(0x111),'exampleResponse':'\x22shopping_categories\x22:\x20{\x20\x22items\x22:\x20[{\x20\x22name\x22:\x20\x22Lands\x22\x20},\x20{\x20\x22name\x22:\x20\x22Houses\x22\x20}]\x20}'},{'appliesTo':a0_0x20f86c(0x123),'rule':a0_0x20f86c(0x162),'exampleSqlShape':'1\x20row\x20×\x201\x20col,\x20output\x20column\x20\x27value\x27','exampleResponse':a0_0x20f86c(0x11e)},{'appliesTo':a0_0x20f86c(0x144),'rule':a0_0x20f86c(0x156),'exampleSqlShape':'1\x20row\x20×\x202\x20cols,\x20output\x20columns\x20\x27direction\x27,\x20\x27pct\x27','exampleResponse':a0_0x20f86c(0x129)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x20N\x20rows','rule':'Return\x20as\x20array\x20of\x20objects\x20(no\x20collapse).','exampleSqlShape':a0_0x20f86c(0x135),'exampleResponse':'\x22items\x22:\x20[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20...]'}],COMMON_WIDGET_PATTERNS=[{'id':'metric_donut_breakdown','name':a0_0x20f86c(0x124),'useCase':a0_0x20f86c(0x12f),'payloadShape':{'id':a0_0x20f86c(0x133),'queries':{'value':a0_0x20f86c(0x14f),'trend':'file:query/<path>/trend.sql','items':a0_0x20f86c(0x110)}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x20f86c(0x15a),'outputColumns':['value'],'collapseRule':a0_0x20f86c(0x161)},{'key':a0_0x20f86c(0x14e),'shape':a0_0x20f86c(0x15d),'outputColumns':['direction','pct'],'collapseRule':'object'},{'key':a0_0x20f86c(0x106),'shape':a0_0x20f86c(0x13f),'outputColumns':['label','value'],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':'\x2269700\x22','trend':'{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','items':a0_0x20f86c(0x165)},'referenceWidgetId':a0_0x20f86c(0x138),'socNotes':a0_0x20f86c(0x12b)},{'id':'metric_sparkline','name':'Metric\x20+\x20Sparkline','useCase':a0_0x20f86c(0x153),'payloadShape':{'id':'<widget_id>','queries':{'value':'file:query/<path>/value.sql','trend':a0_0x20f86c(0x141),'points':a0_0x20f86c(0x149)}},'sqlShapesPerKey':[{'key':'value','shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0x20f86c(0x15b)],'collapseRule':a0_0x20f86c(0x161)},{'key':a0_0x20f86c(0x14e),'shape':a0_0x20f86c(0x15d),'outputColumns':['direction','pct'],'collapseRule':'object'},{'key':'points','shape':a0_0x20f86c(0x13f),'outputColumns':[a0_0x20f86c(0x158),'value'],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':a0_0x20f86c(0x119),'trend':'{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.6\x22\x20}','points':'[{\x20\x22period\x22:\x20\x222026-04-24\x22,\x20\x22value\x22:\x20\x221850\x22\x20},\x20...\x20]'},'referenceWidgetId':'avg_daily_sales','socNotes':'Sparkline\x20libraries\x20(ApexCharts,\x20Chartist,\x20etc.)\x20typically\x20need\x20a\x20plain\x20number\x20array.\x20Frontend\x20maps\x20points.map(p\x20=>\x20p.value).\x20The\x20\x27period\x27\x20field\x20stays\x20for\x20tooltip\x20and\x20gap-resilience\x20against\x20missing\x20days.\x20Use\x20generate_series\x20in\x20SQL\x20to\x20ensure\x20consistent\x20row\x20count\x20even\x20for\x20days\x20with\x20no\x20transactions.'},{'id':'metric_progress_to_goal','name':a0_0x20f86c(0x11b),'useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20progress\x20bar\x20against\x20a\x20period\x20target.\x20Suitable\x20for\x20widgets\x20like\x20\x27Orders\x20This\x20Month\x27.','payloadShape':{'id':'<widget_id>','queries':{'value':a0_0x20f86c(0x15f),'trend':'file:query/<path>/trend.sql','target':a0_0x20f86c(0x126)}},'sqlShapesPerKey':[{'key':a0_0x20f86c(0x15b),'shape':'1\x20row\x20×\x201\x20column','outputColumns':['value\x20(or\x20current)'],'collapseRule':a0_0x20f86c(0x161)},{'key':'trend','shape':a0_0x20f86c(0x15d),'outputColumns':[a0_0x20f86c(0x155),'pct'],'collapseRule':a0_0x20f86c(0x13b)},{'key':'target','shape':a0_0x20f86c(0x15a),'outputColumns':[a0_0x20f86c(0x137)],'collapseRule':'scalar\x20primitive'}],'responseShape':{'value':a0_0x20f86c(0x15c),'trend':'{\x20\x22direction\x22:\x20\x22down\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','target':'\x222884\x22'},'referenceWidgetId':a0_0x20f86c(0x109),'socNotes':'Frontend\x20computes\x20to_goal\x20=\x20target\x20-\x20value\x20and\x20pct\x20=\x20round(value\x20/\x20target\x20*\x20100)\x20for\x20the\x20progress\x20bar.\x20Visual\x20width\x20is\x20presentational\x20and\x20must\x20NOT\x20live\x20in\x20the\x20backend\x20payload.\x20If\x20progress\x20involves\x20complex\x20business\x20rules\x20(e.g.\x20exclude\x20weekends,\x20prorated\x20workdays),\x20use\x20a\x20single\x20multi-column\x20query\x20so\x20\x27pct\x27\x20is\x20a\x20stable\x20business\x20fact\x20rather\x20than\x20visual\x20width.'}],NAMING_CONVENTION={'dashboardName':{'constraint':'MUST\x20start\x20with\x20\x27dash-\x27\x20prefix','minLength':0x6,'maxLength':0x32,'regex':a0_0x20f86c(0x117),'examples':[a0_0x20f86c(0x12d),a0_0x20f86c(0x13d),a0_0x20f86c(0x13e)],'rationale':a0_0x20f86c(0x139)}},URL_PATTERN={'method':'POST','path':a0_0x20f86c(0x11c),'exampleFull':a0_0x20f86c(0x145),'requestBodyShape':{'params':a0_0x20f86c(0x150),'widgets':a0_0x20f86c(0x140)},'responseShape':{'envelope':'{\x20success:\x20boolean,\x20data:\x20{\x20<widgetId>:\x20<perWidgetResponse>,\x20...\x20}\x20}','perWidgetResponse':'Determined\x20by\x20scalarCollapseRules.\x20Failed\x20widgets\x20produce\x20{\x20error:\x20\x27...\x27\x20}\x20block\x20with\x20top-level\x20success\x20still\x20true\x20(one\x20widget\x20failure\x20does\x20NOT\x20fail\x20the\x20dashboard).'}},FILE_REFERENCE_CONVENTION={'format':a0_0x20f86c(0x14b),'pathRelativeTo':'payload\x20JSON\x20file\x20location','fileExtensionPolicy':'free;\x20.sql\x20recommended\x20for\x20editor\x20highlight','resolvedAt':'generation\x20time\x20(NOT\x20runtime)','embedStrategy':'SQL\x20file\x20content\x20is\x20embedded\x20as\x20JavaScript\x20template\x20literal\x20inside\x20the\x20generated\x20module\x20file.\x20Runtime\x20performs\x20zero\x20disk\x20I/O\x20per\x20request\x20—\x20all\x20SQL\x20is\x20in\x20memory\x20after\x20module\x20load.','implication':'Updating\x20an\x20SQL\x20file\x20requires\x20regenerating\x20the\x20dashboard\x20module\x20(\x27codegen_create_dashboard\x27)\x20for\x20changes\x20to\x20take\x20effect.'},PLACEHOLDER_CONVENTION={'format':':paramName','regex':a0_0x20f86c(0x112),'regexNotes':'Negative\x20lookbehind\x20prevents\x20matching\x20\x27::\x27\x20(Postgres\x20cast\x20syntax)\x20as\x20a\x20placeholder.','scanScope':'All\x20widget\x20SQL\x20—\x20both\x20\x27query\x27\x20(singular)\x20and\x20every\x20\x27queries.<key>\x27.','constraint':a0_0x20f86c(0x15e),'exampleSql':'SELECT\x20*\x20FROM\x20stock_inbound\x20WHERE\x20EXTRACT(YEAR\x20FROM\x20inbound_date)\x20=\x20:year','exampleParamDeclaration':'{\x20\x22params\x22:\x20{\x20\x22year\x22:\x20{\x20\x22type\x22:\x20\x22number\x22,\x20\x22required\x22:\x20true\x20}\x20}\x20}'},CACHE_SPEC={'container':a0_0x20f86c(0x131),'optional':!![],'rationale':'Dashboard\x20endpoint\x20may\x20opt-in\x20to\x20Redis-based\x20cache.\x20Pattern\x20follows\x20processor\x20cache\x20(see\x20feat-cache.md).\x20Cache\x20scope\x20is\x20the\x20full\x20response\x20envelope;\x20one\x20cache\x20entry\x20per\x20(params\x20+\x20widgets[]\x20subset)\x20combination.','fields':[{'name':'enabled','type':'boolean','required':!![],'description':a0_0x20f86c(0x11f)},{'name':a0_0x20f86c(0x121),'type':a0_0x20f86c(0x167),'required':![],'constraint':'>=\x200\x20(seconds)','default':a0_0x20f86c(0x147),'description':a0_0x20f86c(0x113)},{'name':a0_0x20f86c(0x10d),'type':a0_0x20f86c(0x157),'required':![],'default':'[]','description':'List\x20of\x20CRUD\x20table\x20names\x20that,\x20when\x20written,\x20will\x20trigger\x20invalidation\x20of\x20this\x20dashboard\x20cache.'}],'validation':{'sqlCrossReference':'When\x20cache.enabled\x20===\x20true\x20and\x20invalidates\x20is\x20non-empty:\x20validator\x20extracts\x20table\x20candidates\x20from\x20widget\x20SQL\x20(regex\x20FROM/JOIN),\x20cross-references\x20with\x20metadata/{project}.json\x20(endpoints[*].tableName\x20where\x20type\x20===\x20\x22module\x22),\x20and\x20asserts\x20equality\x20of\x20expected\x20vs\x20declared\x20sets.\x20Mismatches\x20are\x20reported\x20per\x20category\x20(missing,\x20extra,\x20unmatched).','errorOn':['Table\x20appears\x20in\x20SQL\x20AND\x20in\x20metadata\x20project,\x20but\x20missing\x20from\x20invalidates\x20(cache\x20stale\x20risk)','Table\x20declared\x20in\x20invalidates,\x20but\x20not\x20detected\x20in\x20any\x20widget\x20SQL\x20(typo\x20or\x20dead\x20entry)'],'warningOn':[a0_0x20f86c(0x148)]}},DOCUMENTATION_URL=a0_0x20f86c(0x11d),DASHBOARD_CATALOG={'schemaVersion':'1.0','source':'dashboard-catalog','summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE['topLevelAllowed'][a0_0x20f86c(0x14c)],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS[a0_0x20f86c(0x14c)],'totalParamTypes':ALLOWED_PARAM_TYPES['length'],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES['length'],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS[a0_0x20f86c(0x14c)]},'payloadShape':PAYLOAD_SHAPE,'widgetSpec':WIDGET_SPEC,'paramSpec':PARAM_SPEC,'scalarCollapseRules':SCALAR_COLLAPSE_RULES,'commonWidgetPatterns':COMMON_WIDGET_PATTERNS,'namingConvention':NAMING_CONVENTION,'urlPattern':URL_PATTERN,'fileReferenceConvention':FILE_REFERENCE_CONVENTION,'placeholderConvention':PLACEHOLDER_CONVENTION,'cacheSpec':CACHE_SPEC,'documentationUrl':DOCUMENTATION_URL};module[a0_0x20f86c(0x160)]={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};
|
|
1
|
+
const a0_0x2659ec=a0_0x3123;function a0_0x3123(_0x3453ca,_0x3ebf10){_0x3453ca=_0x3453ca-0x1ca;const _0xd56b41=a0_0xd56b();let _0x3123bd=_0xd56b41[_0x3453ca];if(a0_0x3123['LjhHqG']===undefined){var _0x160abd=function(_0x228b94){const _0x3b01bd='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x999290='',_0x554244='';for(let _0x3693f0=0x0,_0x3bf121,_0x4c17c9,_0x1bddf2=0x0;_0x4c17c9=_0x228b94['charAt'](_0x1bddf2++);~_0x4c17c9&&(_0x3bf121=_0x3693f0%0x4?_0x3bf121*0x40+_0x4c17c9:_0x4c17c9,_0x3693f0++%0x4)?_0x999290+=String['fromCharCode'](0xff&_0x3bf121>>(-0x2*_0x3693f0&0x6)):0x0){_0x4c17c9=_0x3b01bd['indexOf'](_0x4c17c9);}for(let _0x182fe0=0x0,_0x2910e6=_0x999290['length'];_0x182fe0<_0x2910e6;_0x182fe0++){_0x554244+='%'+('00'+_0x999290['charCodeAt'](_0x182fe0)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x554244);};a0_0x3123['JvXOmB']=_0x160abd,a0_0x3123['VFxKvD']={},a0_0x3123['LjhHqG']=!![];}const _0x4e576c=_0xd56b41[0x0],_0x1e9a8e=_0x3453ca+_0x4e576c,_0x1bdeca=a0_0x3123['VFxKvD'][_0x1e9a8e];return!_0x1bdeca?(_0x3123bd=a0_0x3123['JvXOmB'](_0x3123bd),a0_0x3123['VFxKvD'][_0x1e9a8e]=_0x3123bd):_0x3123bd=_0x1bdeca,_0x3123bd;}(function(_0x49959a,_0x13afe1){const _0x4b3d5b=a0_0x3123,_0x579a11=_0x49959a();while(!![]){try{const _0xaf9556=-parseInt(_0x4b3d5b(0x1d3))/0x1*(-parseInt(_0x4b3d5b(0x211))/0x2)+parseInt(_0x4b3d5b(0x1ef))/0x3+parseInt(_0x4b3d5b(0x21e))/0x4+-parseInt(_0x4b3d5b(0x226))/0x5+-parseInt(_0x4b3d5b(0x22d))/0x6+-parseInt(_0x4b3d5b(0x20f))/0x7*(parseInt(_0x4b3d5b(0x230))/0x8)+parseInt(_0x4b3d5b(0x20d))/0x9*(parseInt(_0x4b3d5b(0x22b))/0xa);if(_0xaf9556===_0x13afe1)break;else _0x579a11['push'](_0x579a11['shift']());}catch(_0x5773d1){_0x579a11['push'](_0x579a11['shift']());}}}(a0_0xd56b,0xdcd92));const FORBIDDEN_FRONTEND_FIELDS=['widgetType',a0_0x2659ec(0x1f6),a0_0x2659ec(0x213),'subtitle','color'],ALLOWED_PARAM_TYPES=[a0_0x2659ec(0x210),'number','boolean',a0_0x2659ec(0x1f5)],FRONTEND_CONCERN_REASONS={'widgetType':a0_0x2659ec(0x206),'layout':'Layout\x20is\x20a\x20frontend\x20rendering\x20concern.','title':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','subtitle':a0_0x2659ec(0x200),'color':a0_0x2659ec(0x222)},PAYLOAD_SHAPE={'discriminator':{'field':a0_0x2659ec(0x1fd),'presentMeans':'dashboard\x20payload','absentMeans':a0_0x2659ec(0x1e4),'conflictsWith':'tableName','conflictRationale':'A\x20payload\x20with\x20both\x20\x27widgets\x27\x20and\x20\x27tableName\x27\x20is\x20rejected\x20by\x20DashboardValidator.\x20Pick\x20one\x20shape.'},'topLevelAllowed':[{'name':a0_0x2659ec(0x1fd),'type':a0_0x2659ec(0x1f3),'required':!![],'minItems':0x1,'description':a0_0x2659ec(0x21a)},{'name':a0_0x2659ec(0x1f2),'type':a0_0x2659ec(0x1ec),'required':![],'description':a0_0x2659ec(0x212)},{'name':'cache','type':'object','required':![],'description':a0_0x2659ec(0x1e9)}],'topLevelForbidden':[{'name':a0_0x2659ec(0x1ff),'category':a0_0x2659ec(0x20e),'reason':a0_0x2659ec(0x1df)},...FORBIDDEN_FRONTEND_FIELDS[a0_0x2659ec(0x1ee)](_0x999290=>({'name':_0x999290,'category':a0_0x2659ec(0x1d1),'reason':FRONTEND_CONCERN_REASONS[_0x999290]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':'string','constraint':a0_0x2659ec(0x1f8),'description':a0_0x2659ec(0x221)}],'exclusiveQueryFields':{'rule':'A\x20widget\x20MUST\x20declare\x20exactly\x20one\x20of:\x20\x27query\x27\x20OR\x20\x27queries\x27.\x20Both\x20or\x20neither\x20is\x20rejected.','options':[{'name':'query','type':a0_0x2659ec(0x210),'format':'file:relative/path/to/query.sql','description':'Single\x20SQL\x20query\x20for\x20the\x20widget.','responseShape':a0_0x2659ec(0x1da)},{'name':'queries','type':'object','format':a0_0x2659ec(0x1ce),'minKeys':0x1,'description':a0_0x2659ec(0x1dc),'responseShape':'Per-key\x20based\x20on\x20scalarCollapseRules\x20below.'}]},'forbiddenFields':FORBIDDEN_FRONTEND_FIELDS},PARAM_SPEC={'container':'top-level\x20\x27params\x27\x20object','keyConvention':a0_0x2659ec(0x21d),'perEntryFields':[{'name':'type','required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':a0_0x2659ec(0x1d0)},{'name':a0_0x2659ec(0x215),'required':![],'type':a0_0x2659ec(0x216),'default':![],'description':'When\x20true,\x20the\x20request\x20body\x20MUST\x20include\x20this\x20param\x20(otherwise\x20400).'},{'name':a0_0x2659ec(0x1fa),'required':![],'type':a0_0x2659ec(0x234),'description':'Default\x20value\x20applied\x20when\x20the\x20request\x20omits\x20this\x20param.\x20Validator\x20does\x20NOT\x20strictly\x20type-check\x20default;\x20runtime\x20is\x20responsible\x20for\x20compatibility.'}]},SCALAR_COLLAPSE_RULES=[{'appliesTo':'widget.query\x20(singular)','rule':a0_0x2659ec(0x1d4),'exampleSqlShape':a0_0x2659ec(0x1d8),'exampleResponse':a0_0x2659ec(0x21f)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x201\x20row\x20×\x201\x20column','rule':'Collapse\x20to\x20scalar\x20primitive\x20(the\x20value\x20of\x20the\x20single\x20column).','exampleSqlShape':'1\x20row\x20×\x201\x20col,\x20output\x20column\x20\x27value\x27','exampleResponse':a0_0x2659ec(0x208)},{'appliesTo':a0_0x2659ec(0x205),'rule':'Collapse\x20to\x20object\x20whose\x20keys\x20are\x20SQL\x20column\x20names\x20(lowercased).','exampleSqlShape':'1\x20row\x20×\x202\x20cols,\x20output\x20columns\x20\x27direction\x27,\x20\x27pct\x27','exampleResponse':a0_0x2659ec(0x1d9)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x20N\x20rows','rule':a0_0x2659ec(0x231),'exampleSqlShape':a0_0x2659ec(0x1eb),'exampleResponse':'\x22items\x22:\x20[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20...]'}],COMMON_WIDGET_PATTERNS=[{'id':a0_0x2659ec(0x214),'name':a0_0x2659ec(0x1e8),'useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20breakdown\x20across\x20categories.\x20Suitable\x20for\x20widgets\x20like\x20\x27Expected\x20Earnings\x27\x20that\x20show\x20total\x20value,\x20percentage\x20change,\x20and\x20per-category\x20contribution.','payloadShape':{'id':a0_0x2659ec(0x1d5),'queries':{'value':a0_0x2659ec(0x235),'trend':'file:query/<path>/trend.sql','items':'file:query/<path>/breakdown.sql'}},'sqlShapesPerKey':[{'key':a0_0x2659ec(0x21c),'shape':a0_0x2659ec(0x1d7),'outputColumns':[a0_0x2659ec(0x21c)],'collapseRule':'scalar\x20primitive'},{'key':a0_0x2659ec(0x1d6),'shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction','pct'],'collapseRule':'object'},{'key':'items','shape':'N\x20rows\x20×\x202\x20columns','outputColumns':[a0_0x2659ec(0x20c),a0_0x2659ec(0x21c)],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':a0_0x2659ec(0x22c),'trend':a0_0x2659ec(0x1db),'items':a0_0x2659ec(0x218)},'referenceWidgetId':a0_0x2659ec(0x228),'socNotes':'Frontend\x20determines\x20donut/pie\x20variant,\x20color\x20per\x20category,\x20and\x20label\x20order.\x20If\x20per-category\x20percentage\x20is\x20needed\x20for\x20the\x20donut\x20arc,\x20frontend\x20computes\x20it\x20from\x20items[i].value\x20/\x20sum(items[*].value).\x20No\x20need\x20to\x20send\x20\x27pct\x27\x20from\x20backend\x20unless\x20the\x20figure\x20is\x20a\x20stable\x20business\x20calculation\x20independent\x20of\x20visual\x20rendering.'},{'id':a0_0x2659ec(0x22f),'name':a0_0x2659ec(0x209),'useCase':a0_0x2659ec(0x22e),'payloadShape':{'id':'<widget_id>','queries':{'value':'file:query/<path>/value.sql','trend':a0_0x2659ec(0x1f9),'points':'file:query/<path>/points.sql'}},'sqlShapesPerKey':[{'key':'value','shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0x2659ec(0x21c)],'collapseRule':a0_0x2659ec(0x229)},{'key':'trend','shape':'1\x20row\x20×\x202\x20columns','outputColumns':[a0_0x2659ec(0x1ed),a0_0x2659ec(0x207)],'collapseRule':a0_0x2659ec(0x1ec)},{'key':a0_0x2659ec(0x201),'shape':'N\x20rows\x20×\x202\x20columns','outputColumns':[a0_0x2659ec(0x1f4),a0_0x2659ec(0x21c)],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':'\x222420\x22','trend':a0_0x2659ec(0x1cd),'points':a0_0x2659ec(0x233)},'referenceWidgetId':a0_0x2659ec(0x217),'socNotes':a0_0x2659ec(0x1cc)},{'id':'metric_progress_to_goal','name':'Metric\x20+\x20Progress\x20to\x20Goal','useCase':a0_0x2659ec(0x204),'payloadShape':{'id':a0_0x2659ec(0x1d5),'queries':{'value':a0_0x2659ec(0x22a),'trend':'file:query/<path>/trend.sql','target':'file:query/<path>/target.sql'}},'sqlShapesPerKey':[{'key':a0_0x2659ec(0x21c),'shape':a0_0x2659ec(0x1d7),'outputColumns':['value\x20(or\x20current)'],'collapseRule':a0_0x2659ec(0x229)},{'key':'trend','shape':a0_0x2659ec(0x1fc),'outputColumns':['direction','pct'],'collapseRule':'object'},{'key':'target','shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0x2659ec(0x202)],'collapseRule':a0_0x2659ec(0x229)}],'responseShape':{'value':'\x221836\x22','trend':'{\x20\x22direction\x22:\x20\x22down\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','target':'\x222884\x22'},'referenceWidgetId':a0_0x2659ec(0x1e0),'socNotes':a0_0x2659ec(0x1d2)}],NAMING_CONVENTION={'dashboardName':{'constraint':a0_0x2659ec(0x224),'minLength':0x6,'maxLength':0x32,'regex':'^dash-[a-zA-Z0-9_-]+$','examples':[a0_0x2659ec(0x1ca),'dash-inbound',a0_0x2659ec(0x1e2)],'rationale':a0_0x2659ec(0x1de)}},URL_PATTERN={'method':a0_0x2659ec(0x1cb),'path':'/api/{project}/{name}/dashboard','exampleFull':'POST\x20/api/mini-inventory/dash-inbound/dashboard','requestBodyShape':{'params':a0_0x2659ec(0x20b),'widgets':a0_0x2659ec(0x203)},'responseShape':{'envelope':a0_0x2659ec(0x21b),'perWidgetResponse':'Determined\x20by\x20scalarCollapseRules.\x20Failed\x20widgets\x20produce\x20{\x20error:\x20\x27...\x27\x20}\x20block\x20with\x20top-level\x20success\x20still\x20true\x20(one\x20widget\x20failure\x20does\x20NOT\x20fail\x20the\x20dashboard).'}},FILE_REFERENCE_CONVENTION={'format':a0_0x2659ec(0x1ea),'pathRelativeTo':'payload\x20JSON\x20file\x20location','fileExtensionPolicy':a0_0x2659ec(0x1e6),'resolvedAt':a0_0x2659ec(0x1e7),'embedStrategy':a0_0x2659ec(0x1f7),'implication':a0_0x2659ec(0x1e5)},PLACEHOLDER_CONVENTION={'format':a0_0x2659ec(0x223),'regex':a0_0x2659ec(0x1e1),'regexNotes':'Negative\x20lookbehind\x20prevents\x20matching\x20\x27::\x27\x20(Postgres\x20cast\x20syntax)\x20as\x20a\x20placeholder.','scanScope':a0_0x2659ec(0x20a),'constraint':'Every\x20placeholder\x20used\x20in\x20SQL\x20MUST\x20be\x20declared\x20in\x20\x27params\x27.\x20Validator\x20throws\x20Error\x20with\x20message\x20format:\x20\x22Widget\x20\x27<id>\x27\x20query\x20\x27<label>\x27\x20uses\x20undeclared\x20placeholder\x20\x27:<token>\x27\x20(declare\x20in\x20\x27params\x27)\x22.','exampleSql':a0_0x2659ec(0x1fb),'exampleParamDeclaration':a0_0x2659ec(0x1f1)},CACHE_SPEC={'container':a0_0x2659ec(0x1f0),'optional':!![],'rationale':'Dashboard\x20endpoint\x20may\x20opt-in\x20to\x20Redis-based\x20cache.\x20Pattern\x20follows\x20processor\x20cache\x20(see\x20feat-cache.md).\x20Cache\x20scope\x20is\x20the\x20full\x20response\x20envelope;\x20one\x20cache\x20entry\x20per\x20(params\x20+\x20widgets[]\x20subset)\x20combination.','fields':[{'name':'enabled','type':'boolean','required':!![],'description':a0_0x2659ec(0x227)},{'name':'ttl','type':'number','required':![],'constraint':a0_0x2659ec(0x220),'default':'inherits\x20CACHE_TTL\x20env','description':'Time-to-live\x20in\x20seconds.\x200\x20effectively\x20disables\x20cache\x20for\x20this\x20entry.'},{'name':a0_0x2659ec(0x1cf),'type':'array<string>','required':![],'default':'[]','description':a0_0x2659ec(0x232)}],'validation':{'sqlCrossReference':'When\x20cache.enabled\x20===\x20true\x20and\x20invalidates\x20is\x20non-empty:\x20validator\x20extracts\x20table\x20candidates\x20from\x20widget\x20SQL\x20(regex\x20FROM/JOIN),\x20cross-references\x20with\x20metadata/{project}.json\x20(endpoints[*].tableName\x20where\x20type\x20===\x20\x22module\x22),\x20and\x20asserts\x20equality\x20of\x20expected\x20vs\x20declared\x20sets.\x20Mismatches\x20are\x20reported\x20per\x20category\x20(missing,\x20extra,\x20unmatched).','errorOn':[a0_0x2659ec(0x1fe),'Table\x20declared\x20in\x20invalidates,\x20but\x20not\x20detected\x20in\x20any\x20widget\x20SQL\x20(typo\x20or\x20dead\x20entry)'],'warningOn':[a0_0x2659ec(0x225)]}},DOCUMENTATION_URL=a0_0x2659ec(0x1e3),DASHBOARD_CATALOG={'schemaVersion':a0_0x2659ec(0x219),'source':'dashboard-catalog','summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE['topLevelAllowed']['length'],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS['length'],'totalParamTypes':ALLOWED_PARAM_TYPES[a0_0x2659ec(0x1dd)],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES[a0_0x2659ec(0x1dd)],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS[a0_0x2659ec(0x1dd)]},'payloadShape':PAYLOAD_SHAPE,'widgetSpec':WIDGET_SPEC,'paramSpec':PARAM_SPEC,'scalarCollapseRules':SCALAR_COLLAPSE_RULES,'commonWidgetPatterns':COMMON_WIDGET_PATTERNS,'namingConvention':NAMING_CONVENTION,'urlPattern':URL_PATTERN,'fileReferenceConvention':FILE_REFERENCE_CONVENTION,'placeholderConvention':PLACEHOLDER_CONVENTION,'cacheSpec':CACHE_SPEC,'documentationUrl':DOCUMENTATION_URL};function a0_0xd56b(){const _0x40fc8a=['tvvtvcbZDgfYDcb3AxrOicDKyxnOlsCGChjLzML4','vgfIBguGzgv0zwn0zwqGAw4Gu1fmlcbIDxqGBM90ihjLz2LZDgvYzwqGyxmGq1jvrcbLBMrWB2LUDcbPBIbTzxrHzgf0ysbWCM9Qzwn0icHSAwTLBhKGysb2Awv3lcbdveuGywXPyxmSig9YignYB3nZlxbYB2PLy3qGDgfIBguG4OcuignHC2nHzguGD2LSBcbUB3qGzMLYzsK','mZC2mdy2mgjyEMjSvW','vg9Nz2XLignHy2HLigzLyxr1CMuGzM9YihrOAxmGzgfZAgjVyxjKlG','zxHWzwn0zwrFzwfYBMLUz3m','C2nHBgfYihbYAw1PDgL2zq','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','otK1ntKZmgnxwerzqW','iJy5nZaWiG','ntm1mdyWogP3rNH6Aq','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGC3bHCMTSAw5Lig1PBMKTy2HHCNqGzM9YihnOB3j0ihDPBMrVD3mGkdCGzgf5CYWGmtiGBw9UDgHZlcbLDgmUks4Gu3vPDgfIBguGzM9YihDPzgDLDhmGBgLRzsaNqxzLCMfNzsbeywLSEsbtywXLCYCU','Bwv0CMLJx3nWyxjRBgLUzq','ohrbs1nzzW','uMv0DxjUigfZigfYCMf5ig9Mig9IAMvJDhmGkg5VignVBgXHChnLks4','tgLZDcbVzIbduLveihrHyMXLig5HBwvZihrOyxqSihDOzw4GD3jPDhrLBIWGD2LSBcb0CMLNz2vYigLUDMfSAwrHDgLVBIbVzIb0AgLZigrHC2HIB2fYzcbJywnOzs4','w3SGiNbLCMLVzci6iciYmdi2lta0lti0iIWGiNzHBhvLiJOGiJe4ntaIih0Sic4UlIbD','yw55icHTDxn0igjLignVBxbHDgLIBguGD2L0AcbKzwnSyxjLzcaNDhLWzsCP','zMLSztPXDwvYEs88Cgf0Ad4VDMfSDwuUC3fS','zgfZAc1ZywXLCW','ue9tva','u3bHCMTSAw5LigXPyNjHCMLLCYaOqxbLEenOyxj0CYWGq2HHCNrPC3qSigv0yY4Pihr5CgLJywXSEsbUzwvKigeGCgXHAw4GBNvTyMvYigfYCMf5lIbgCM9UDgvUzcbTyxbZihbVAw50CY5TyxaOCca9pIbWlNzHBhvLks4GvgHLicDWzxjPB2qNigzPzwXKihn0yxLZigzVCIb0B29SDgLWigfUzcbNyxaTCMvZAwXPzw5JzsbHz2fPBNn0ig1PC3nPBMCGzgf5CY4GvxnLigDLBMvYyxrLx3nLCMLLCYbPBIbtuuWGDg8Gzw5ZDxjLignVBNnPC3rLBNqGCM93ignVDw50igv2zw4GzM9YigrHExmGD2L0AcbUBYb0CMfUC2fJDgLVBNmU','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJyIih0','A2v54OAszMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','Aw52ywXPzgf0zxm','ugfYyw0Gzgf0ysb0ExbLlIbwywXPzgf0zxmGCMvXDwvZDcbIB2r5igfUzcbZAgfWzxmGCNvUDgLTzsbWyxjHBwv0zxiGyMLUzgLUzY4','zNjVBNrLBMqTy29Uy2vYBG','rNjVBNrLBMqGy29TChv0zxmGDg9Fz29HBca9ihrHCMDLDcaTihzHBhvLigfUzcbWy3qGpsbYB3vUzcH2ywX1zsaVihrHCMDLDcaQideWmcKGzM9YihrOzsbWCM9NCMvZCYbIyxiUifzPC3vHBcb3Awr0AcbPCYbWCMvZzw50yxrPB25HBcbHBMqGBxvZDcbot1qGBgL2zsbPBIb0AguGyMfJA2vUzcbWyxLSB2fKlIbjzIbWCM9NCMvZCYbPBNzVBhzLCYbJB21WBgv4igj1C2LUzxnZihj1BgvZicHLlMCUigv4y2X1zguGD2vLA2vUzhmSihbYB3jHDgvKihDVCMTKyxLZksWGDxnLigeGC2LUz2XLig11BhrPlwnVBhvTBIbXDwvYEsbZBYaNCgn0jYbPCYbHihn0ywjSzsbIDxnPBMvZCYbMywn0ihjHDgHLCIb0AgfUihzPC3vHBcb3Awr0Ac4','mtvVy1Drq3u','qwX3yxLZihDYyxaGyxmGEYbPDgvTCZOGwY4UlL0GFsbYzwDHCMrSzxnZig9MifnrtcbYzxn1BhqGC2HHCguU','phDPzgDLDf9Pzd4','DhjLBMq','msbYB3CGW5CGmsbJB2X1Bw4','yw55icGXihjVDYddLYaXignVBcWGtIbYB3DZimoxie0Gy29SCYWGzxrJlIK','iNrYzw5KiJOGEYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJiIih0','qwX3yxLZihSGAxrLBxm6ifSUlI5Dih0GCMvNyxjKBgvZCYbVzIbtuuWGCMvZDwX0ihnOyxbLlG','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJiIih0','txvSDgKTu1fmihDPzgDLDc4GrwfJAcbRzxKGyMvJB21LCYbHigTLEsbPBIb0AguGCMvZCg9UC2uGB2jQzwn0lG','BgvUz3rO','vgHLihbYzwzPEcbIzwnVBwvZihbHCNqGB2yGDgHLifvstcbZzwDTzw50lIbuAguGCMvZzxj2zwqGC2nOzw1LigTLzxbZigrHC2HIB2fYzcbLBMrWB2LUDhmGDMLZDwfSBhKGzgLZDgLUy3qGzNjVBsbduLveigvUzhbVAw50CYbPBIb0AguGvvjmihnWywnLigfUzcbHBgXVD3mGzNv0DxjLihjVDxrPBMCGzgLMzMvYzw50Awf0Aw9UlG','uMvZzxj2zwqGzM9YiensvuqGCgf5Bg9HzhmUieeGzgfZAgjVyxjKihbHEwXVywqGBxvZDcbKzwnSyxjLicD3AwrNzxrZjYbPBNn0zwfKlG','B3jKzxjZx3rOAxnFBw9UDgG','kd88itOPoIHBys16qs1Ax11Bys16qs1Amc05x10Qkq','zgfZAc1HDxrOB3iTC3rHDhm','Ahr0Chm6lY9Yzxn0zM9Yz2uUzgv2l2rVy3mVC2vYDMvYl3f1zxj5lwrHDgeVzgfZAgjVyxjK','tM90igeGzgfZAgjVyxjKihbHEwXVywqGkgXPA2vSEsbduLveihDPDgGGDgfIBgvoyw1LlcbVCIbPBNzHBgLKkq','vxbKyxrPBMCGyw4Gu1fmigzPBguGCMvXDwLYzxmGCMvNzw5LCMf0Aw5NihrOzsbKyxnOyM9HCMqGBw9KDwXLicGNy29KzwDLBL9JCMvHDgvFzgfZAgjVyxjKjYKGzM9YignOyw5NzxmGDg8GDgfRzsbLzMzLy3qU','zNjLztSGlNnXBcbYzwnVBw1LBMrLzcbMB3iGzwrPDg9YigHPz2HSAwDODa','z2vUzxjHDgLVBIb0Aw1LicHot1qGCNvUDgLTzsK','twv0CMLJicSGrg9UDxqGqNjLywTKB3DU','t3b0Aw9UywWGy2fJAguGy29UzMLNDxjHDgLVBI4Gu2vLignHy2HLu3bLyYbMB3iGzgv0ywLSCY4','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','tIbYB3DZimoxie0Gy29SCW','B2jQzwn0','zgLYzwn0Aw9U','BwfW','mtm5ndG3n0fWCvjbqW','Dg9WlwXLDMvSicDJywnOzsCGB2jQzwn0','EYaICgfYyw1ZiJOGEYaIEwvHCIi6ihSGiNr5CguIoIaIBNvTyMvYiIWGiNjLCxvPCMvKiJOGDhj1zsb9ih0GFq','CgfYyw1Z','yxjYyxK','CgvYAw9K','zgf0zq','Bgf5B3v0','u1fmigzPBguGy29UDgvUDcbPCYbLBwjLzgrLzcbHCYbkyxzHu2nYAxb0ihrLBxbSyxrLigXPDgvYywWGAw5ZAwrLihrOzsbNzw5LCMf0zwqGBw9KDwXLigzPBguUifj1BNrPBwuGCgvYzM9YBxmGEMvYBYbKAxnRieKVtYbWzxiGCMvXDwvZDcdIGjqGywXSifnrtcbPCYbPBIbTzw1VCNKGywz0zxiGBw9KDwXLigXVywqU','BM9UlwvTChr5lcb1BMLXDwuGywnYB3nZihDPzgDLDhmGAw4GDgHLihnHBwuGCgf5Bg9Hza','zMLSztPXDwvYEs88Cgf0Ad4VDhjLBMqUC3fS','zgvMyxvSDa','u0vmrunuicOGrLjptsbZDg9JA19PBMjVDw5KifDirvjfievyvfjbq1qOwuvbuIbguK9nigLUyM91BMrFzgf0zsKGpsa6EwvHCG','msbYB3CGW5CGmIbJB2X1Bw5Z','D2LKz2v0CW','vgfIBguGyxbWzwfYCYbPBIbtuuWGqu5eigLUig1LDgfKyxrHihbYB2PLy3qSigj1DcbTAxnZAw5NigzYB20GAw52ywXPzgf0zxmGkgnHy2HLihn0ywXLihjPC2SP','DgfIBgvoyw1L','vuKGBgfIzwWGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBI4','Cg9PBNrZ','DgfYz2v0','yxjYyxK8C3rYAw5NpIWGB3b0Aw9UywWG4Ocuihn1yNnLDcbVzIb3AwrNzxqGsurZihrVigv4zwn1DguUie9TAxqGDg8GzxHLy3v0zsbHBgWGzgvJBgfYzwqGD2LKz2v0CY4','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGChjVz3jLC3mGyMfYigfNywLUC3qGysbWzxjPB2qGDgfYz2v0lIbtDwL0ywjSzsbMB3iGD2LKz2v0CYbSAwTLicDpCMrLCNmGvgHPCYbnB250AcCU','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxig11BhrPCgXLignVBhvTBNm','vMLZDwfSihzHCMLHBNqGkgrVBNv0lcbIyxiSihbPzsWGyxjLysKGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBIaOC2vWyxjHDgLVBIbVzIbJB25JzxjUCYKU','Cgn0','iNzHBhvLiJOGiJy5nZaWiG','twv0CMLJicSGu3bHCMTSAw5L','qwXSihDPzgDLDcbtuuWG4OcuigjVDgGGj3f1zxj5jYaOC2LUz3vSyxiPigfUzcbLDMvYEsaNCxvLCMLLCY48A2v5pICU','B2jQzwn0iokaLcb2ywX1zxmGzM9YigrLy2XHCMvKihbHCMfTCYaODMfSAwrHDgvKigfNywLUC3qGCgfYyw1ZignVBNrYywn0oYbTAxnZAw5NihjLCxvPCMvKiokgKIa0mdaSihr5CguGBwLZBwf0y2GG4OAsidqWmcK','BgfIzwW','owXvDuT1rq','C2HHCguTy29UzMXPy3q','mtC1otaZn0v2r3LTvW','C3rYAw5N','mZq4ntzgB3HWq1O','ugfYyw1LDgvYignVBNrYywn0igzVCIb0AguGzgfZAgjVyxjKlIbfywnOigTLEsbPCYbHihbHCMfTig5HBwu7ihzHBhvLCYbKzxnJCMLIzsb0ExbLl3jLCxvPCMvKl2rLzMf1BhqUifbSywnLAg9SzgvYCYbPBNnPzguGD2LKz2v0ifnrtcbTDxn0ihjLzMvYzw5JzsbKzwnSyxjLzcbWyxjHBsbUyw1LCY4','DgL0Bgu','Bwv0CMLJx2rVBNv0x2jYzwfRzg93BG','CMvXDwLYzwq','yM9VBgvHBG','yxzNx2rHAwX5x3nHBgvZ','w3SGiMXHyMvSiJOGiLnOB2vZiIWGiNzHBhvLiJOGiJC2nJaIih0SihSGiMXHyMvSiJOGiKDHBwLUzYiSicj2ywX1zsi6iciYodiWiIb9lcb7icjSywjLBci6icjpDgHLCNmIlcaIDMfSDwuIoIaInduYntCIih1D','ms4W','tgLZDcbVzIb3AwrNzxqGzgvMAw5PDgLVBNmUie9YzgvYigLZigLUzM9YBwf0Aw9UywWGB25SEsaOCMvZCg9UC2uGA2v5CYbHCMuGyNKGD2LKz2v0igLKlcbUB3qGyxjYyxKGAw5KzxGPlG','EYbZDwnJzxnZoIbIB29SzwfUlcbKyxrHoIb7idX3AwrNzxrjzd46idXWzxjxAwrNzxrszxnWB25Zzt4Sic4UlIb9ih0','DMfSDwu','ugfYyw0GBMfTzsbTDxn0ig1HDgnOihrOzsbWBgfJzwHVBgrLCIbYzwDLEcbGw2eTEKeTwL9Dw2eTEKeTwJaTov9DkMaGkgfSCgHHBNvTzxjPyYaRihvUzgvYC2nVCMuSig11C3qGC3rHCNqGD2L0AcbSzxr0zxiGB3iGDw5KzxjZy29YzsKU','ndmXmti1mLfqELHJsa','iNnOB3bWAw5Nx2nHDgvNB3jPzxmIoIb7icjPDgvTCYi6ifT7icjUyw1LiJOGiKXHBMrZiIb9lcb7icjUyw1LiJOGiKHVDxnLCYiGFv0GFq','pJ0GmcaOC2vJB25KCYK','v2LKz2v0igLKzw50AwzPzxi7ihvZzwqGyxmGDgHLihjLC3bVBNnLigTLEsbPBIb0AguGzgfZAgjVyxjKigvUDMvSB3bLlG','vMLZDwfSignVBg9YigLZigeGzNjVBNrLBMqGCMvUzgvYAw5NignVBMnLCM4U','oNbHCMfTtMfTzq'];a0_0xd56b=function(){return _0x40fc8a;};return a0_0xd56b();}module['exports']={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function a0_0x2877(){const _0x4b30b3=['DhjPBq','AgfZ','mta0uu9pB2fb','mJqWAvvyEKHV','otC4ne5ouujsBW','rejFvfLqrq','Aw50zwDLCG','rejFtKfnrq','C3rHCNrZv2L0Aa','mti2ote4AuvOzxbe','mZCYnJf2r2fVtvm','nZCXnZyWrM1zr2HL','neXyD0fYBa','ntuZnhnuuhjIra','ChvZAa','mtu5EwnbCxDT','C2XPy2u','sePbAg4','rejFvvnfuG','rejFse9tva','mJa3otGXmefxwwDStW','yM9VBgvHBG','teLdru5trq','C3bSAxq','Aw5KzxHpzG','rejFueftu1DpuKq','D0nhC04','sKHjvLq','Dhj1zq','zxHWB3j0CW','ntKYmJi5suPRrMTc','BgvUz3rO'];a0_0x2877=function(){return _0x4b30b3;};return a0_0x2877();}const a0_0x1b76c4=a0_0x4446;(function(_0x60483d,_0x59c50a){const _0x35a29a=a0_0x4446,_0x438d06=_0x60483d();while(!![]){try{const _0xe45e12=parseInt(_0x35a29a(0xc5))/0x1*(parseInt(_0x35a29a(0xc4))/0x2)+-parseInt(_0x35a29a(0xc7))/0x3*(-parseInt(_0x35a29a(0xdc))/0x4)+-parseInt(_0x35a29a(0xc3))/0x5+parseInt(_0x35a29a(0xdb))/0x6*(-parseInt(_0x35a29a(0xe2))/0x7)+-parseInt(_0x35a29a(0xda))/0x8*(-parseInt(_0x35a29a(0xe1))/0x9)+parseInt(_0x35a29a(0xcc))/0xa+-parseInt(_0x35a29a(0xd6))/0xb;if(_0xe45e12===_0x59c50a)break;else _0x438d06['push'](_0x438d06['shift']());}catch(_0x3ba4d8){_0x438d06['push'](_0x438d06['shift']());}}}(a0_0x2877,0x1b136));const DB_CONNECTION_ENV_TEMPLATE='#\x20License\x0aLICENSE=XXXX-XXXX-XXXX-XXXX\x0a\x0a#\x20Server\x0aSERVER_ADDRESS=127.0.0.1\x0aSERVER_PORT=3000\x0a\x0a#\x20Live\x20Sync\x20(WebSocket)\x20Configuration\x0a#\x20NOTE:\x20LIVE_SYNC_ENABLED=true\x20requires\x20an\x20API\x20Key\x20(KEY=...)\x20to\x20authenticate\x20WebSocket\x20clients\x0aLIVE_SYNC_ENABLED=false\x0aLIVE_SYNC_PORT=3033\x0a\x0a#\x20Redis\x20Configuration\x0aREDIS_HOST=localhost\x0aREDIS_PORT=6380\x0aREDIS_PASSWORD=\x0aREDIS_DB=0\x0a\x0a#\x20Export\x20Configuration\x0aEXPORT_FILE_EXPIRY=3600000\x0aEXPORT_CHUNK_SIZE=1000\x0a\x0a#\x20Kafka\x20Configuration\x0aKAFKA_ENABLED=false\x0a#\x20Broker\x20list\x20(comma-separated\x20for\x20multiple\x20brokers:\x20broker1:9092,broker2:9092,broker3:9092)\x0aKAFKA_BROKERS=localhost:9092\x0a#\x20Client\x20ID\x20(optional,\x20default:\x20restforge-{project}-producer\x20/\x20-consumer)\x0a#\x20KAFKA_CLIENT_ID=\x0aKAFKA_CONNECTION_TIMEOUT=3000\x0aKAFKA_REQUEST_TIMEOUT=25000\x0aKAFKA_TOPIC_PATTERN={module}.{endpoint}.events\x0aKAFKA_TENANT_ID=default\x0aKAFKA_SESSION_TIMEOUT=30000\x0aKAFKA_HEARTBEAT_INTERVAL=3000\x0aKAFKA_MAX_BYTES_PER_PARTITION=1048576\x0aKAFKA_AUTO_COMMIT=false\x0aKAFKA_AUTO_COMMIT_INTERVAL=5000\x0aKAFKA_RETRY_ATTEMPTS=3\x0aKAFKA_RETRY_DELAY=1000\x0aKAFKA_RETRY_MAX_DELAY=30000\x0aKAFKA_SSL=false\x0aKAFKA_LOG_LEVEL=info\x0a#\x20SASL\x20Authentication\x20(optional,\x20uncomment\x20if\x20the\x20broker\x20requires\x20authentication)\x0a#\x20Supported\x20mechanisms:\x20plain,\x20scram-sha-256,\x20scram-sha-512\x0a#\x20KAFKA_SASL_MECHANISM=plain\x0a#\x20KAFKA_SASL_USERNAME=\x0a#\x20KAFKA_SASL_PASSWORD=\x0a\x0a#\x20Database\x20Configuration\x0a#\x20Supported:\x20postgresql,\x20mysql,\x20oracle,\x20sqlite\x0aDB_TYPE=postgresql\x0aDB_HOST=127.0.0.1\x0aDB_PORT=5432\x0aDB_USER=postgres\x0aDB_PASSWORD=your_password_here\x0aDB_NAME=your_database_name\x0a#\x20For\x20SQLite:\x20set\x20DB_TYPE=sqlite\x20and\x20DB_NAME=./data/myapp.db\x0a#\x20DB_HOST,\x20DB_PORT,\x20DB_USER,\x20DB_PASSWORD\x20are\x20ignored\x20for\x20SQLite\x0a\x0a#\x20Logging\x20Configuration\x0aLOG_LEVEL=debug\x0aLOG_TO_FILE=true\x0a\x0a#\x20SQL\x20Logging\x0aSQL_LOG_ENABLED=false\x0aSQL_LOG_LEVEL=debug\x0aSQL_LOG_PARAMS=false\x0aSQL_LOG_SLOW_THRESHOLD=1000\x0a\x0a#\x20Cache\x20Configuration\x0aCACHE_ENABLED=false\x0aCACHE_TTL=300\x0a\x0a#\x20Job\x20Scheduler\x0aJOB_ENABLED=false\x0aJOB_CONCURRENCY=5\x0aJOB_RETENTION_HOURS=72\x0aJOB_FAILED_RETENTION_HOURS=168\x0aJOB_SHUTDOWN_TIMEOUT=10000\x0aJOB_STALLED_INTERVAL=30000\x0aJOB_MAX_STALLED_COUNT=2\x0a\x0a#\x20Distributed\x20Lock\x20Configuration\x0aLOCK_DISTRIBUTED_ENABLED=false\x0aLOCK_DISTRIBUTED_TTL=10\x0aLOCK_RESOURCE_MAX_TTL=600\x0aLOCK_DISTRIBUTED_RETRY=3\x0aLOCK_DISTRIBUTED_RETRY_DELAY=100\x0aLOCK_DISTRIBUTED_STRATEGY=reject\x0a\x0a#\x20ID\x20Generator\x20Configuration\x0aIDGEN_ENABLED=false\x0aIDGEN_IDEM_TTL=600\x0aIDGEN_COUNTER_TTL_MONTHLY=2764800\x0aIDGEN_COUNTER_TTL_DAILY=172800\x0aIDGEN_DEFAULT_MAX_RETRY=10\x0aIDGEN_DEFAULT_PIN_DIGITS=6\x0aIDGEN_DEFAULT_SERIAL_PATTERN=XXXX-XXXX-XXXX-XXXX\x0aIDGEN_DEFAULT_CODE_PATTERN=9999-9999\x0aIDGEN_ALLOW_RESET=false\x0a',REQUIRED_KEYS=new Set([a0_0x1b76c4(0xce),'SERVER_ADDRESS','SERVER_PORT',a0_0x1b76c4(0xdd),a0_0x1b76c4(0xcb),'DB_PORT',a0_0x1b76c4(0xca),a0_0x1b76c4(0xd1),a0_0x1b76c4(0xdf)]);function a0_0x4446(_0x232634,_0x41706b){_0x232634=_0x232634-0xc3;const _0x2877a7=a0_0x2877();let _0x444611=_0x2877a7[_0x232634];if(a0_0x4446['rVZLoE']===undefined){var _0x575ce7=function(_0x1d5e48){const _0x31ca05='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2465c9='',_0x25ce98='';for(let _0x20aed2=0x0,_0x400b80,_0x3a33df,_0x3ac963=0x0;_0x3a33df=_0x1d5e48['charAt'](_0x3ac963++);~_0x3a33df&&(_0x400b80=_0x20aed2%0x4?_0x400b80*0x40+_0x3a33df:_0x3a33df,_0x20aed2++%0x4)?_0x2465c9+=String['fromCharCode'](0xff&_0x400b80>>(-0x2*_0x20aed2&0x6)):0x0){_0x3a33df=_0x31ca05['indexOf'](_0x3a33df);}for(let _0x983e1b=0x0,_0xe09f57=_0x2465c9['length'];_0x983e1b<_0xe09f57;_0x983e1b++){_0x25ce98+='%'+('00'+_0x2465c9['charCodeAt'](_0x983e1b)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x25ce98);};a0_0x4446['DLFRjw']=_0x575ce7,a0_0x4446['bQQxYk']={},a0_0x4446['rVZLoE']=!![];}const _0x1be273=_0x2877a7[0x0],_0x478130=_0x232634+_0x1be273,_0x4bd96b=a0_0x4446['bQQxYk'][_0x478130];return!_0x4bd96b?(_0x444611=a0_0x4446['DLFRjw'](_0x444611),a0_0x4446['bQQxYk'][_0x478130]=_0x444611):_0x444611=_0x4bd96b,_0x444611;}function parseTemplateAsSchema(_0x566ee5){const _0x405f53=a0_0x1b76c4,_0x1e2f92={'HJAhn':function(_0x362179,_0x1e5414){return _0x362179===_0x1e5414;},'JHIVT':'string','wCGsN':_0x405f53(0xd4),'rslgb':_0x405f53(0xcd),'vqpPX':_0x405f53(0xde)},_0x181ad8=_0x566ee5||DB_CONNECTION_ENV_TEMPLATE,_0x148d82=_0x181ad8[_0x405f53(0xcf)]('\x0a'),_0x33ec1b=[];let _0x228082=null,_0x19dab5=[];for(const _0x555e7e of _0x148d82){const _0x26898b=_0x555e7e[_0x405f53(0xd8)]();if(_0x26898b===''){_0x19dab5=[];continue;}if(_0x26898b[_0x405f53(0xe0)]('#')){const _0x179293=_0x26898b[_0x405f53(0xc8)](0x1)['trim'](),_0x54659d=_0x179293[_0x405f53(0xd7)]>0x0&&_0x179293[_0x405f53(0xd7)]<0x3c&&!_0x179293['includes'](':')&&!/^[A-Z_]+=/['test'](_0x179293)&&/^[A-Z]/['test'](_0x179293);_0x54659d&&_0x1e2f92[_0x405f53(0xc9)](_0x19dab5['length'],0x0)?_0x228082=_0x179293:_0x19dab5[_0x405f53(0xc6)](_0x179293);continue;}const _0x47f7f7=_0x555e7e[_0x405f53(0xd0)]('=');if(_0x47f7f7>0x0){const _0x302fc3=_0x555e7e['slice'](0x0,_0x47f7f7)['trim'](),_0x38e72f=_0x555e7e['slice'](_0x47f7f7+0x1);let _0x161f0d=_0x1e2f92[_0x405f53(0xd3)];if(_0x38e72f===_0x1e2f92[_0x405f53(0xd2)]||_0x38e72f==='false')_0x161f0d=_0x1e2f92['rslgb'];else/^-?\d+$/['test'](_0x38e72f)&&(_0x161f0d=_0x1e2f92['vqpPX']);_0x33ec1b['push']({'name':_0x302fc3,'section':_0x228082,'type':_0x161f0d,'default':_0x38e72f,'description':_0x19dab5['join']('\x20')||null,'required':REQUIRED_KEYS[_0x405f53(0xd9)](_0x302fc3)}),_0x19dab5=[];}}return _0x33ec1b;}module[a0_0x1b76c4(0xd5)]={'DB_CONNECTION_ENV_TEMPLATE':DB_CONNECTION_ENV_TEMPLATE,'REQUIRED_KEYS':REQUIRED_KEYS,'parseTemplateAsSchema':parseTemplateAsSchema};
|