@restforgejs/platform 5.2.11 → 5.2.13
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/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/fast-track.js +151 -34
- 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
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* CMD baru (Windows).
|
|
17
17
|
*
|
|
18
18
|
* Scope Frontend (dan bagian frontend pada ALL) juga dieksekusi NYATA: payload
|
|
19
|
-
* migrate (RDF -> UDF) per tabel -> restforge-designer
|
|
19
|
+
* migrate (RDF -> UDF) per tabel -> restforge-designer generate.
|
|
20
20
|
*
|
|
21
21
|
* Catatan: contract ini global verb (snapshot key = `fast-track`), file berada
|
|
22
22
|
* di root `generators/cli/` sehingga ter-discover otomatis sejajar dengan `init`.
|
|
@@ -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. */
|
|
@@ -1191,7 +1207,7 @@ function runBackendPipeline(ctx) {
|
|
|
1191
1207
|
|
|
1192
1208
|
/**
|
|
1193
1209
|
* Pipeline frontend nyata: migrate RDF->UDF per tabel (agregator di-akumulasi),
|
|
1194
|
-
* lalu designer
|
|
1210
|
+
* lalu designer generate. Urutan mengikuti fast-track.mjs/quick-start.
|
|
1195
1211
|
* appCode default = project, sehingga agregator = frontend/payload/<project>.json.
|
|
1196
1212
|
*/
|
|
1197
1213
|
function runFrontendPipeline(ctx) {
|
|
@@ -1202,7 +1218,7 @@ function runFrontendPipeline(ctx) {
|
|
|
1202
1218
|
const plugin = ctx.plugin || DESIGNER_DEFAULT_PLUGIN;
|
|
1203
1219
|
const pluginArg = `--plugin=${plugin}`;
|
|
1204
1220
|
|
|
1205
|
-
phase('[F1/
|
|
1221
|
+
phase('[F1/2] Migrate RDF -> UDF (per tabel, agregator di-akumulasi)');
|
|
1206
1222
|
fs.mkdirSync(path.join(frontendDir, 'payload'), { recursive: true });
|
|
1207
1223
|
for (const t of ctx.tableEntries) {
|
|
1208
1224
|
// Lewati tabel yang murni FK-parent (tanpa FK sendiri): page-nya dibuat
|
|
@@ -1225,12 +1241,14 @@ function runFrontendPipeline(ctx) {
|
|
|
1225
1241
|
: ` [WARN] could not inject auth block into ${aggregatorPath}; app will generate without auth`);
|
|
1226
1242
|
}
|
|
1227
1243
|
|
|
1228
|
-
phase('[F2/
|
|
1229
|
-
run(`restforge-designer activate --key=${ctx.cfg.LICENSE}`, frontendDir, { allowNonZero: true });
|
|
1230
|
-
|
|
1231
|
-
phase('[F3/3] Generate frontend application');
|
|
1244
|
+
phase('[F2/2] Generate frontend application');
|
|
1232
1245
|
// Hapus index.html lama agar landing page diregenerasi sesuai set page terbaru.
|
|
1233
|
-
|
|
1246
|
+
// Pakai fs langsung (bukan shell command) supaya portable Windows/Linux/macOS.
|
|
1247
|
+
try {
|
|
1248
|
+
fs.unlinkSync(path.join(frontendDir, 'apps', ctx.project, 'index.html'));
|
|
1249
|
+
} catch {
|
|
1250
|
+
// File belum ada (first run) - abaikan.
|
|
1251
|
+
}
|
|
1234
1252
|
run(`restforge-designer generate --payload=payload/${appCode}.json --output=./apps/${ctx.project} ${pluginArg} --overwrite`, frontendDir);
|
|
1235
1253
|
}
|
|
1236
1254
|
|
|
@@ -1271,6 +1289,66 @@ function writeServerStartScript(ctx) {
|
|
|
1271
1289
|
return file;
|
|
1272
1290
|
}
|
|
1273
1291
|
|
|
1292
|
+
/**
|
|
1293
|
+
* Tulis launcher start frontend mandiri di folder app (frontend/apps/<project>/).
|
|
1294
|
+
* Windows -> frontend-start.bat, Linux/macOS -> frontend-start.sh. Sama seperti
|
|
1295
|
+
* writeServerStartScript, dipakai juga sebagai target `pm2 start` di non-Windows.
|
|
1296
|
+
*/
|
|
1297
|
+
function writeFrontendStartScript(ctx) {
|
|
1298
|
+
const serveCmd = `npx serve . -l ${ctx.cfg.WEB_SERVER_PORT}`;
|
|
1299
|
+
const isWin = process.platform === 'win32';
|
|
1300
|
+
const appDir = path.join(ctx.cwd, 'frontend', 'apps', ctx.project);
|
|
1301
|
+
const file = path.join(appDir, isWin ? 'frontend-start.bat' : 'frontend-start.sh');
|
|
1302
|
+
let content;
|
|
1303
|
+
if (isWin) {
|
|
1304
|
+
content = [
|
|
1305
|
+
'@echo off',
|
|
1306
|
+
'REM Start RESTForge frontend app. Generated by fast-track.',
|
|
1307
|
+
'cd /d "%~dp0"',
|
|
1308
|
+
`call ${serveCmd}`,
|
|
1309
|
+
''
|
|
1310
|
+
].join('\r\n');
|
|
1311
|
+
} else {
|
|
1312
|
+
content = [
|
|
1313
|
+
'#!/usr/bin/env bash',
|
|
1314
|
+
'# Start RESTForge frontend app. Generated by fast-track.',
|
|
1315
|
+
'set -e',
|
|
1316
|
+
'cd "$(dirname "$0")"',
|
|
1317
|
+
serveCmd,
|
|
1318
|
+
''
|
|
1319
|
+
].join('\n');
|
|
1320
|
+
}
|
|
1321
|
+
fs.writeFileSync(file, content);
|
|
1322
|
+
if (!isWin) {
|
|
1323
|
+
try { fs.chmodSync(file, 0o755); } catch { /* abaikan bila FS tak dukung chmod */ }
|
|
1324
|
+
}
|
|
1325
|
+
return file;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* pm2 dipakai di Linux/macOS sebagai pengganti "open new window" (konsep
|
|
1330
|
+
* Windows-only) untuk mengelola proses server/frontend: pm2 list/logs/reload/
|
|
1331
|
+
* stop, bukan raw PID. Nama proses dibedakan per-project per-kind agar tidak
|
|
1332
|
+
* collision antar project yang dijalankan bersamaan.
|
|
1333
|
+
*/
|
|
1334
|
+
function pm2Name(project, kind) {
|
|
1335
|
+
return `${project}-${kind}`;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* Start (ulang) script launcher via pm2. Idempotent: hapus instance lama dulu
|
|
1340
|
+
* (silent, tolerant bila belum ada) supaya re-run fast-track tidak gagal
|
|
1341
|
+
* dengan "already launched". Return false bila pm2 tidak tersedia/gagal.
|
|
1342
|
+
*/
|
|
1343
|
+
function pm2StartScript(name, scriptPath, cwd) {
|
|
1344
|
+
spawnSync(`pm2 delete ${name} --silent`, { shell: true, stdio: 'ignore' });
|
|
1345
|
+
const r = spawnSync(
|
|
1346
|
+
`pm2 start "${scriptPath}" --name ${name} --cwd "${cwd}" --interpreter bash`,
|
|
1347
|
+
{ shell: true, stdio: 'inherit' }
|
|
1348
|
+
);
|
|
1349
|
+
return !r.error && r.status === 0;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1274
1352
|
function printFinalSummary(ctx) {
|
|
1275
1353
|
const parts = [];
|
|
1276
1354
|
if (ctx.scope.backend) parts.push('REST API generated');
|
|
@@ -1287,6 +1365,9 @@ function printFinalSummary(ctx) {
|
|
|
1287
1365
|
}
|
|
1288
1366
|
if (ctx.scope.frontend) {
|
|
1289
1367
|
console.log(` Frontend : frontend/apps/${ctx.project}/ (start: npx serve . -l ${ctx.cfg.WEB_SERVER_PORT})`);
|
|
1368
|
+
if (ctx.frontendStartFile) {
|
|
1369
|
+
console.log(` Start : ${path.basename(ctx.frontendStartFile)} (start frontend manually)`);
|
|
1370
|
+
}
|
|
1290
1371
|
}
|
|
1291
1372
|
console.log(rule('='));
|
|
1292
1373
|
}
|
|
@@ -1304,20 +1385,35 @@ async function startServerNow(ctx) {
|
|
|
1304
1385
|
const serveCmd = `npx restforge serve --project=${ctx.project} --config=${ctx.configFlag} --watch`;
|
|
1305
1386
|
freePort(ctx.cfg.SERVER_PORT);
|
|
1306
1387
|
const title = `RESTForge Server - ${ctx.project}`;
|
|
1307
|
-
console.log(`\n Opening new window: "${title}"`);
|
|
1308
|
-
console.log(`#${serveCmd}`);
|
|
1309
1388
|
// server.js (dispatcher) memaksa NODE_ENV=production untuk proses cli command,
|
|
1310
1389
|
// sehingga fast-track berjalan production dan secara default akan mewariskannya
|
|
1311
1390
|
// ke serve -> logger memakai format JSON mentah (verbose). Set development agar
|
|
1312
1391
|
// runtime server memakai pino-pretty (rapi), konsisten dengan playbook yang
|
|
1313
1392
|
// menjalankan serve dari plain `node`.
|
|
1314
1393
|
const serveEnv = { ...process.env, NODE_ENV: 'development' };
|
|
1315
|
-
|
|
1316
|
-
if (
|
|
1317
|
-
console.log(
|
|
1318
|
-
|
|
1394
|
+
|
|
1395
|
+
if (process.platform === 'win32') {
|
|
1396
|
+
console.log(`\n Opening new window: "${title}"`);
|
|
1397
|
+
console.log(`#${serveCmd}`);
|
|
1398
|
+
const r = spawnSync('cmd', ['/C', 'start', title, 'cmd', '/k', serveCmd], { cwd: ctx.cwd, stdio: 'inherit', env: serveEnv });
|
|
1399
|
+
if (r.error) {
|
|
1400
|
+
console.log(` Failed to open server window: ${r.error.message}`);
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
console.log(' ✓ Server window opened. Keep it open. Stop with Ctrl+C.');
|
|
1404
|
+
} else {
|
|
1405
|
+
// Tidak ada konsep "window baru" di Linux/macOS (terutama session SSH headless) -
|
|
1406
|
+
// pakai pm2 supaya proses bisa dikelola normal (pm2 list/logs/reload/stop).
|
|
1407
|
+
console.log(`\n Starting via pm2: "${title}"`);
|
|
1408
|
+
const name = pm2Name(ctx.project, 'server');
|
|
1409
|
+
const ok = pm2StartScript(name, ctx.serverStartFile, ctx.cwd);
|
|
1410
|
+
if (!ok) {
|
|
1411
|
+
console.log(' Failed to start via pm2. Is pm2 installed? (npm install -g pm2)');
|
|
1412
|
+
return false;
|
|
1413
|
+
}
|
|
1414
|
+
console.log(` ✓ Server started via pm2 as "${name}".`);
|
|
1415
|
+
console.log(` pm2 logs ${name} | pm2 reload ${name} | pm2 stop ${name}`);
|
|
1319
1416
|
}
|
|
1320
|
-
console.log(' ✓ Server window opened. Keep it open. Stop with Ctrl+C.');
|
|
1321
1417
|
|
|
1322
1418
|
// Health check: tunggu runtime benar-benar siap menerima request sebelum
|
|
1323
1419
|
// lanjut (mis. ke frontend). URL = banner runtime: /api/<project>/health.
|
|
@@ -1365,14 +1461,27 @@ async function startFrontendNow(ctx) {
|
|
|
1365
1461
|
}
|
|
1366
1462
|
freePort(webPort);
|
|
1367
1463
|
const title = `RESTForge Frontend - ${ctx.project}`;
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1464
|
+
|
|
1465
|
+
if (process.platform === 'win32') {
|
|
1466
|
+
console.log(`\n Opening new window: "${title}"`);
|
|
1467
|
+
console.log(`#${serveCmd}`);
|
|
1468
|
+
const r = spawnSync('cmd', ['/C', 'start', title, 'cmd', '/k', serveCmd], { cwd: appDir, stdio: 'inherit' });
|
|
1469
|
+
if (r.error) {
|
|
1470
|
+
console.log(` Failed to open frontend window: ${r.error.message}`);
|
|
1471
|
+
return false;
|
|
1472
|
+
}
|
|
1473
|
+
console.log(` ✓ Frontend window opened (WEB_SERVER_PORT ${webPort}).`);
|
|
1474
|
+
} else {
|
|
1475
|
+
console.log(`\n Starting via pm2: "${title}"`);
|
|
1476
|
+
const name = pm2Name(ctx.project, 'frontend');
|
|
1477
|
+
const ok = pm2StartScript(name, ctx.frontendStartFile, appDir);
|
|
1478
|
+
if (!ok) {
|
|
1479
|
+
console.log(' Failed to start via pm2. Is pm2 installed? (npm install -g pm2)');
|
|
1480
|
+
return false;
|
|
1481
|
+
}
|
|
1482
|
+
console.log(` ✓ Frontend started via pm2 as "${name}" (WEB_SERVER_PORT ${webPort}).`);
|
|
1483
|
+
console.log(` pm2 logs ${name} | pm2 reload ${name} | pm2 stop ${name}`);
|
|
1374
1484
|
}
|
|
1375
|
-
console.log(` ✓ Frontend window opened (WEB_SERVER_PORT ${webPort}).`);
|
|
1376
1485
|
|
|
1377
1486
|
const url = `http://localhost:${webPort}/index.html`;
|
|
1378
1487
|
// Tunggu static server (`npx serve`) benar-benar siap sebelum buka browser,
|
|
@@ -1387,7 +1496,12 @@ async function startFrontendNow(ctx) {
|
|
|
1387
1496
|
if (!ready.ok) {
|
|
1388
1497
|
console.log(' ⚠ Frontend belum merespons - buka URL di atas manual bila browser tidak otomatis terbuka.');
|
|
1389
1498
|
}
|
|
1390
|
-
const
|
|
1499
|
+
const openCmd = process.platform === 'win32'
|
|
1500
|
+
? ['cmd', ['/C', 'start', '""', url]]
|
|
1501
|
+
: process.platform === 'darwin'
|
|
1502
|
+
? ['open', [url]]
|
|
1503
|
+
: ['xdg-open', [url]];
|
|
1504
|
+
const openResult = spawnSync(openCmd[0], openCmd[1], { stdio: 'ignore' });
|
|
1391
1505
|
if (openResult.error) {
|
|
1392
1506
|
console.log(` (Could not open browser automatically: ${openResult.error.message})`);
|
|
1393
1507
|
}
|
|
@@ -1552,6 +1666,9 @@ module.exports = {
|
|
|
1552
1666
|
}
|
|
1553
1667
|
if (ctx.scope.frontend) {
|
|
1554
1668
|
runFrontendPipeline(ctx);
|
|
1669
|
+
// Launcher start frontend mandiri (sesuai OS), dipakai juga sebagai
|
|
1670
|
+
// target `pm2 start` di non-Windows.
|
|
1671
|
+
ctx.frontendStartFile = writeFrontendStartScript(ctx);
|
|
1555
1672
|
}
|
|
1556
1673
|
|
|
1557
1674
|
printFinalSummary(ctx);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a0_0x4d0b(_0x15ca17,_0x2cce2a){_0x15ca17=_0x15ca17-0xaa;const _0x30b410=a0_0x30b4();let _0x4d0bad=_0x30b410[_0x15ca17];if(a0_0x4d0b['tafAzt']===undefined){var _0x4f1e31=function(_0x318eed){const _0x151004='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xb3efe3='',_0x46fd12='';for(let _0x43f95d=0x0,_0x2121d3,_0x3aa25e,_0x539667=0x0;_0x3aa25e=_0x318eed['charAt'](_0x539667++);~_0x3aa25e&&(_0x2121d3=_0x43f95d%0x4?_0x2121d3*0x40+_0x3aa25e:_0x3aa25e,_0x43f95d++%0x4)?_0xb3efe3+=String['fromCharCode'](0xff&_0x2121d3>>(-0x2*_0x43f95d&0x6)):0x0){_0x3aa25e=_0x151004['indexOf'](_0x3aa25e);}for(let _0x19b81d=0x0,_0x3b66ff=_0xb3efe3['length'];_0x19b81d<_0x3b66ff;_0x19b81d++){_0x46fd12+='%'+('00'+_0xb3efe3['charCodeAt'](_0x19b81d)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x46fd12);};a0_0x4d0b['fiTAxp']=_0x4f1e31,a0_0x4d0b['bNqqil']={},a0_0x4d0b['tafAzt']=!![];}const _0x2f6fc6=_0x30b410[0x0],_0x2d3dc2=_0x15ca17+_0x2f6fc6,_0x4abd93=a0_0x4d0b['bNqqil'][_0x2d3dc2];return!_0x4abd93?(_0x4d0bad=a0_0x4d0b['fiTAxp'](_0x4d0bad),a0_0x4d0b['bNqqil'][_0x2d3dc2]=_0x4d0bad):_0x4d0bad=_0x4abd93,_0x4d0bad;}const a0_0x4756bb=a0_0x4d0b;(function(_0x40bce1,_0x4d7f13){const _0xfd4b57=a0_0x4d0b,_0x85f2a=_0x40bce1();while(!![]){try{const _0x4e0739=-parseInt(_0xfd4b57(0xe8))/0x1*(-parseInt(_0xfd4b57(0xc8))/0x2)+-parseInt(_0xfd4b57(0xc5))/0x3*(parseInt(_0xfd4b57(0xb1))/0x4)+parseInt(_0xfd4b57(0xb3))/0x5*(parseInt(_0xfd4b57(0xe0))/0x6)+parseInt(_0xfd4b57(0xf2))/0x7+-parseInt(_0xfd4b57(0xbb))/0x8+-parseInt(_0xfd4b57(0xb5))/0x9*(parseInt(_0xfd4b57(0xb7))/0xa)+parseInt(_0xfd4b57(0xe9))/0xb;if(_0x4e0739===_0x4d7f13)break;else _0x85f2a['push'](_0x85f2a['shift']());}catch(_0x295b1c){_0x85f2a['push'](_0x85f2a['shift']());}}}(a0_0x30b4,0xbbf75));function a0_0x30b4(){const _0x53a7c7=['EYbZDwnJzxnZoIbIB29SzwfUlcbKyxrHoIb7idX3AwrNzxrjzd46idXWzxjxAwrNzxrszxnWB25Zzt4Sic4UlIb9ih0','AxrLBxm','yxzNx2rHAwX5x3nHBgvZ','zgLYzwn0Aw9U','zMLSztPXDwvYEs88Cgf0Ad4VyNjLywTKB3DUlNnXBa','BM9UlwvTChr5lcb1BMLXDwuGywnYB3nZihDPzgDLDhmGAw4GDgHLihnHBwuGCgf5Bg9Hza','iJi4odqI','Bwv0CMLJx3nWyxjRBgLUzq','yxjYyxKGB2yGB2jQzwn0CW','rgv0zxjTAw5LzcbIEsbZy2fSyxjdB2XSyxbZzvj1BgvZlIbgywLSzwqGD2LKz2v0CYbWCM9KDwnLihSGzxjYB3i6icCUlI4Nih0GyMXVy2SGD2L0Acb0B3aTBgv2zwWGC3vJy2vZCYbZDgLSBcb0CNvLicHVBMuGD2LKz2v0igzHAwX1CMuGzg9LCYbot1qGzMfPBcb0AguGzgfZAgjVyxjKks4','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGC3bHCMTSAw5Lig1PBMKTy2HHCNqGzM9YihnOB3j0ihDPBMrVD3mGkdCGzgf5CYWGmtiGBw9UDgHZlcbLDgmUks4Gu3vPDgfIBguGzM9YihDPzgDLDhmGBgLRzsaNqxzLCMfNzsbeywLSEsbtywXLCYCU','DhrS','C3vIDgL0Bgu','msbYB3CGW5CGmsbJB2WSig91Dhb1DcbJB2X1Bw4Gj3zHBhvLjW','u3bHCMTSAw5LigXPyNjHCMLLCYaOqxbLEenOyxj0CYWGq2HHCNrPC3qSigv0yY4Pihr5CgLJywXSEsbUzwvKigeGCgXHAw4GBNvTyMvYigfYCMf5lIbgCM9UDgvUzcbTyxbZihbVAw50CY5TyxaOCca9pIbWlNzHBhvLks4GvgHLicDWzxjPB2qNigzPzwXKihn0yxLZigzVCIb0B29SDgLWigfUzcbNyxaTCMvZAwXPzw5JzsbHz2fPBNn0ig1PC3nPBMCGzgf5CY4GvxnLigDLBMvYyxrLx3nLCMLLCYbPBIbtuuWGDg8Gzw5ZDxjLignVBNnPC3rLBNqGCM93ignVDw50igv2zw4GzM9YigrHExmGD2L0AcbUBYb0CMfUC2fJDgLVBNmU','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGChjVz3jLC3mGyMfYigfNywLUC3qGysbWzxjPB2qGDgfYz2v0lIbtDwL0ywjSzsbMB3iGD2LKz2v0CYbSAwTLicDpCMrLCNmGvgHPCYbnB250AcCU','zgfZAc1ZywXLCW','v2LKz2v0igLKzw50AwzPzxi7ihvZzwqGyxmGDgHLihjLC3bVBNnLigTLEsbPBIb0AguGzgfZAgjVyxjKigvUDMvSB3bLlG','D2LKz2v0CW','iJe4mZyI','CxvLCNK','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','Cgn0','mZC2mdG0tLbJv2rg','vg9Nz2XLignHy2HLigzLyxr1CMuGzM9YihrOAxmGzgfZAgjVyxjKlG','mJuWvNL0y2fm','BwfW','mJi0nJrcENfoDwe','iJi0mJaI','nty5mgjLww9msa','D2LKz2v0lNf1zxj5icHZAw5NDwXHCIK','iNnOB3bWAw5Nx2nHDgvNB3jPzxmIoIb7icjPDgvTCYi6ifT7icjUyw1LiJOGiKXHBMrZiIb9lcb7icjUyw1LiJOGiKHVDxnLCYiGFv0GFq','yw55icGXihjVDYddLYaXignVBcWGtIbYB3DZimoxie0Gy29SCYWGzxrJlIK','mte5mdu3mdrOuLbQALK','BNvTyMvY','Dg9WlwXLDMvSicDWyxjHBxmNig9IAMvJDa','DMfSDwuGkg9Yign1CNjLBNqP','l2fWAs97ChjVAMvJDh0VE25HBwv9l2rHC2HIB2fYza','BgvUz3rO','qsbWyxLSB2fKihDPDgGGyM90AcaND2LKz2v0CYCGyw5KicD0ywjSzu5HBwuNigLZihjLAMvJDgvKigj5ierHC2HIB2fYzfzHBgLKyxrVCI4GugLJAYbVBMuGC2HHCguU','kd88itOPoIHBys16qs1Ax11Bys16qs1Amc05x10Qkq','vMLZDwfSihzHCMLHBNqGkgrVBNv0lcbIyxiSihbPzsWGyxjLysKGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBIaOC2vWyxjHDgLVBIbVzIbJB25JzxjUCYKU','B2jQzwn0','mtvJBLzTEKG','yxjYyxK8C3rYAw5NpG','qwX3yxLZihSGAxrLBxm6ifSUlI5Dih0GCMvNyxjKBgvZCYbVzIbtuuWGCMvZDwX0ihnOyxbLlG','mtaWnZKWBuTAENvj','Bgf5B3v0','B3jKzxjZx3rOAxnFBw9UDgG','rNjVBNrLBMqGy29TChv0zxmGDg9Fz29HBca9ihrHCMDLDcaTihzHBhvLigfUzcbWy3qGpsbYB3vUzcH2ywX1zsaVihrHCMDLDcaQideWmcKGzM9YihrOzsbWCM9NCMvZCYbIyxiUifzPC3vHBcb3Awr0AcbPCYbWCMvZzw50yxrPB25HBcbHBMqGBxvZDcbot1qGBgL2zsbPBIb0AguGyMfJA2vUzcbWyxLSB2fKlIbjzIbWCM9NCMvZCYbPBNzVBhzLCYbJB21WBgv4igj1C2LUzxnZihj1BgvZicHLlMCUigv4y2X1zguGD2vLA2vUzhmSihbYB3jHDgvKihDVCMTKyxLZksWGDxnLigeGC2LUz2XLig11BhrPlwnVBhvTBIbXDwvYEsbZBYaNCgn0jYbPCYbHihn0ywjSzsbIDxnPBMvZCYbMywn0ihjHDgHLCIb0AgfUihzPC3vHBcb3Awr0Ac4','zgfZAgjVyxjKlwnHDgfSB2C','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJiIih0','qwXSihDPzgDLDcbtuuWG4OcuigjVDgGGj3f1zxj5jYaOC2LUz3vSyxiPigfUzcbLDMvYEsaNCxvLCMLLCY48A2v5pICU','zNjVBNrLBMqTy29Uy2vYBG','DgfIBgvoyw1L','EYaICgfYyw1ZiJOGEYaIEwvHCIi6ihSGiNr5CguIoIaIBNvTyMvYiIWGiNjLCxvPCMvKiJOGDhj1zsb9ih0GFq','yM9VBgvHBG','q29SBgfWC2uGDg8GB2jQzwn0ihDOB3nLigTLExmGyxjLifnrtcbJB2X1Bw4GBMfTzxmGkgXVD2vYy2fZzwqPlG','tgLZDcbVzIbduLveihrHyMXLig5HBwvZihrOyxqSihDOzw4GD3jPDhrLBIWGD2LSBcb0CMLNz2vYigLUDMfSAwrHDgLVBIbVzIb0AgLZigrHC2HIB2fYzcbJywnOzs4','DhjLBMq','phDPzgDLDf9Pzd4','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxideGy29SDw1U','Dg9Wtgv2zwXbBgXVD2vK','t3b0Aw9UywWGy2fJAguGy29UzMLNDxjHDgLVBI4Gu2vLignHy2HLu3bLyYbMB3iGzgv0ywLSCY4','A2v54OAszMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','DMfSDwu','tIbYB3DZimoxidiGy29SDw1UCW','q29SBgfWC2uGDg8GC2nHBgfYihbYAw1PDgL2zsaODgHLihzHBhvLig9MihrOzsbZAw5NBguGy29SDw1Uks4','vgfIBguGzgvJBgfYzwqGAw4GAw52ywXPzgf0zxmSigj1DcbUB3qGzgv0zwn0zwqGAw4Gyw55ihDPzgDLDcbtuuWGkhr5Cg8GB3iGzgvHzcbLBNrYEsK','ndi0mJbLu1PrEeW','D2LKz2v0vhLWzq','qsb3AwrNzxqGtvvtvcbKzwnSyxjLigv4ywn0BhKGB25Lig9MoIaNCxvLCNKNie9sicDXDwvYAwvZjY4GqM90AcbVCIbUzwL0AgvYigLZihjLAMvJDgvKlG','msbYB3CGW5CGmIbJB2X1Bw5Z','ue9tvcaVyxbPl21PBMKTAw52zw50B3j5l2rHC2GTAw5IB3vUzc9KyxnOyM9HCMq','vuKGBgfIzwWGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBI4','rxzLCNKGCgXHy2vOB2XKzxiGDxnLzcbPBIbtuuWGtvvtvcbIzsbKzwnSyxjLzcbPBIaNCgfYyw1ZjY4GvMfSAwrHDg9YihrOCM93CYbfCNjVCIb3AxrOig1LC3nHz2uGzM9YBwf0oIaIv2LKz2v0icC8Awq+jYbXDwvYEsaNpgXHyMvSpICGDxnLCYb1BMrLy2XHCMvKihbSywnLAg9SzgvYicC6phrVA2vUpICGkgrLy2XHCMuGAw4Gj3bHCMfTCYCPiI4','msbYB3CGW5CGmsbJB2X1Bw4','mtnQse1nyMK','mJe3odq4mdDgDhLNDwu','u1fmigzPBguGy29UDgvUDcbPCYbLBwjLzgrLzcbHCYbkyxzHu2nYAxb0ihrLBxbSyxrLigXPDgvYywWGAw5ZAwrLihrOzsbNzw5LCMf0zwqGBw9KDwXLigzPBguUifj1BNrPBwuGCgvYzM9YBxmGEMvYBYbKAxnRieKVtYbWzxiGCMvXDwvZDcdIGjqGywXSifnrtcbPCYbPBIbTzw1VCNKGywz0zxiGBw9KDwXLigXVywqU','zMLSztPXDwvYEs88Cgf0Ad4VCg9PBNrZlNnXBa','vxbKyxrPBMCGyw4Gu1fmigzPBguGCMvXDwLYzxmGCMvNzw5LCMf0Aw5NihrOzsbKyxnOyM9HCMqGBw9KDwXLicGNy29KzwDLBL9JCMvHDgvFzgfZAgjVyxjKjYKGzM9YignOyw5NzxmGDg8GDgfRzsbLzMzLy3qU','zxHWzwn0zwrFzwfYBMLUz3m','twv0CMLJicSGuhjVz3jLC3mGDg8Gr29HBa','iNzHBhvLiJOGiJy5nZaWiG','C2nHBgfYihbYAw1PDgL2zq','u2LUz2XLifnrtcbXDwvYEsbMB3iGDgHLihDPzgDLDc4','odeXnty1m3vxs3HHCW','yxjYyxK'];a0_0x30b4=function(){return _0x53a7c7;};return a0_0x30b4();}const FORBIDDEN_FRONTEND_FIELDS=[a0_0x4756bb(0xe1),a0_0x4756bb(0xc9),'title',a0_0x4756bb(0x100),'color'],ALLOWED_PARAM_TYPES=['string',a0_0x4756bb(0xbc),a0_0x4756bb(0xd2),'date'],FRONTEND_CONCERN_REASONS={'widgetType':a0_0x4756bb(0xc3),'layout':'Layout\x20is\x20a\x20frontend\x20rendering\x20concern.','title':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','subtitle':a0_0x4756bb(0xe5),'color':'Visual\x20color\x20is\x20a\x20frontend\x20rendering\x20concern.'},PAYLOAD_SHAPE={'discriminator':{'field':a0_0x4756bb(0xac),'presentMeans':'dashboard\x20payload','absentMeans':'Not\x20a\x20dashboard\x20payload\x20(likely\x20CRUD\x20with\x20tableName,\x20or\x20invalid)','conflictsWith':a0_0x4756bb(0xd0),'conflictRationale':a0_0x4756bb(0xc1)},'topLevelAllowed':[{'name':a0_0x4756bb(0xac),'type':a0_0x4756bb(0xf3),'required':!![],'minItems':0x1,'description':'List\x20of\x20widget\x20definitions.\x20Order\x20is\x20informational\x20only\x20(response\x20keys\x20are\x20by\x20widget\x20id,\x20not\x20array\x20index).'},{'name':'params','type':'object','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':'cache','type':'object','required':![],'description':a0_0x4756bb(0xd9)}],'topLevelForbidden':[{'name':a0_0x4756bb(0xd0),'category':'shape-conflict','reason':'Reserved\x20for\x20CRUD\x20payloads.\x20A\x20dashboard\x20payload\x20must\x20declare\x20\x27widgets\x27\x20instead.'},...FORBIDDEN_FRONTEND_FIELDS[a0_0x4756bb(0xb4)](_0xb3efe3=>({'name':_0xb3efe3,'category':a0_0x4756bb(0xcf),'reason':FRONTEND_CONCERN_REASONS[_0xb3efe3]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':'string','constraint':a0_0x4756bb(0xf9),'description':a0_0x4756bb(0xab)}],'exclusiveQueryFields':{'rule':a0_0x4756bb(0xe2),'options':[{'name':a0_0x4756bb(0xae),'type':'string','format':'file:relative/path/to/query.sql','description':a0_0x4756bb(0xf1),'responseShape':a0_0x4756bb(0xc7)},{'name':'queries','type':a0_0x4756bb(0xc4),'format':a0_0x4756bb(0xda),'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_0x4756bb(0xbd),'keyConvention':'Param\x20name\x20must\x20match\x20the\x20placeholder\x20regex\x20`[a-zA-Z_][a-zA-Z0-9_]*`\x20(alphanumeric\x20+\x20underscore,\x20must\x20start\x20with\x20letter\x20or\x20underscore).','perEntryFields':[{'name':'type','required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':'Param\x20data\x20type.\x20Validates\x20request\x20body\x20and\x20shapes\x20runtime\x20parameter\x20binding.'},{'name':'required','required':![],'type':a0_0x4756bb(0xd2),'default':![],'description':'When\x20true,\x20the\x20request\x20body\x20MUST\x20include\x20this\x20param\x20(otherwise\x20400).'},{'name':'default','required':![],'type':'any\x20(must\x20be\x20compatible\x20with\x20declared\x20\x27type\x27)','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':a0_0x4756bb(0xb8),'rule':'Always\x20wrap\x20as\x20{\x20items:\x20[...]\x20}\x20regardless\x20of\x20SQL\x20result\x20shape.','exampleSqlShape':a0_0x4756bb(0xba),'exampleResponse':a0_0x4756bb(0xb9)},{'appliesTo':a0_0x4756bb(0xd7),'rule':a0_0x4756bb(0xde),'exampleSqlShape':a0_0x4756bb(0x101),'exampleResponse':a0_0x4756bb(0xef)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x201\x20row\x20×\x20multiple\x20columns','rule':a0_0x4756bb(0xd3),'exampleSqlShape':'1\x20row\x20×\x202\x20cols,\x20output\x20columns\x20\x27direction\x27,\x20\x27pct\x27','exampleResponse':'\x22trend\x22:\x20{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}'},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x20N\x20rows','rule':'Return\x20as\x20array\x20of\x20objects\x20(no\x20collapse).','exampleSqlShape':'N\x20rows\x20×\x20M\x20cols','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':'Metric\x20+\x20Donut\x20Breakdown','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':'<widget_id>','queries':{'value':'file:query/<path>/value.sql','trend':'file:query/<path>/trend.sql','items':a0_0x4756bb(0xf8)}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x4756bb(0xe7),'outputColumns':[a0_0x4756bb(0xdc)],'collapseRule':a0_0x4756bb(0xf0)},{'key':a0_0x4756bb(0xd5),'shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction',a0_0x4756bb(0xb0)],'collapseRule':a0_0x4756bb(0xc4)},{'key':a0_0x4756bb(0xf5),'shape':a0_0x4756bb(0xdd),'outputColumns':['label',a0_0x4756bb(0xdc)],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':'\x2269700\x22','trend':a0_0x4756bb(0xcd),'items':'[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20{\x20\x22label\x22:\x20\x22Gaming\x22,\x20\x22value\x22:\x20\x222820\x22\x20},\x20{\x20\x22label\x22:\x20\x22Others\x22,\x20\x22value\x22:\x20\x2245257\x22\x20}]'},'referenceWidgetId':a0_0x4756bb(0xed),'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_0x4756bb(0xfb),'name':'Metric\x20+\x20Sparkline','useCase':a0_0x4756bb(0xfe),'payloadShape':{'id':a0_0x4756bb(0xd6),'queries':{'value':'file:query/<path>/value.sql','trend':'file:query/<path>/trend.sql','points':a0_0x4756bb(0xeb)}},'sqlShapesPerKey':[{'key':a0_0x4756bb(0xdc),'shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0x4756bb(0xdc)],'collapseRule':'scalar\x20primitive'},{'key':'trend','shape':'1\x20row\x20×\x202\x20columns','outputColumns':[a0_0x4756bb(0xf7),a0_0x4756bb(0xb0)],'collapseRule':a0_0x4756bb(0xc4)},{'key':'points','shape':a0_0x4756bb(0xdd),'outputColumns':['period',a0_0x4756bb(0xdc)],'collapseRule':a0_0x4756bb(0xfc)}],'responseShape':{'value':a0_0x4756bb(0xb6),'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':a0_0x4756bb(0xf6),'socNotes':a0_0x4756bb(0x102)},{'id':'metric_progress_to_goal','name':a0_0x4756bb(0xee),'useCase':a0_0x4756bb(0x103),'payloadShape':{'id':a0_0x4756bb(0xd6),'queries':{'value':a0_0x4756bb(0xdb),'trend':'file:query/<path>/trend.sql','target':'file:query/<path>/target.sql'}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x4756bb(0xe7),'outputColumns':[a0_0x4756bb(0xbe)],'collapseRule':'scalar\x20primitive'},{'key':'trend','shape':a0_0x4756bb(0xe3),'outputColumns':[a0_0x4756bb(0xf7),'pct'],'collapseRule':a0_0x4756bb(0xc4)},{'key':'target','shape':a0_0x4756bb(0xe7),'outputColumns':['target'],'collapseRule':'scalar\x20primitive'}],'responseShape':{'value':a0_0x4756bb(0xad),'trend':'{\x20\x22direction\x22:\x20\x22down\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','target':a0_0x4756bb(0xfa)},'referenceWidgetId':a0_0x4756bb(0xca),'socNotes':a0_0x4756bb(0xcb)}],NAMING_CONVENTION={'dashboardName':{'constraint':'MUST\x20start\x20with\x20\x27dash-\x27\x20prefix','minLength':0x6,'maxLength':0x32,'regex':'^dash-[a-zA-Z0-9_-]+$','examples':[a0_0x4756bb(0xaa),'dash-inbound','dash-author-stats'],'rationale':'The\x20prefix\x20becomes\x20part\x20of\x20the\x20URL\x20segment.\x20The\x20reserved\x20scheme\x20keeps\x20dashboard\x20endpoints\x20visually\x20distinct\x20from\x20CRUD\x20endpoints\x20in\x20the\x20URL\x20space\x20and\x20allows\x20future\x20routing\x20differentiation.'}},URL_PATTERN={'method':'POST','path':a0_0x4756bb(0xbf),'exampleFull':a0_0x4756bb(0xe4),'requestBodyShape':{'params':'object\x20—\x20values\x20for\x20declared\x20params\x20(validated\x20against\x20params\x20contract;\x20missing\x20required\x20→\x20400,\x20type\x20mismatch\x20→\x20400)','widgets':'array<string>,\x20optional\x20—\x20subset\x20of\x20widget\x20IDs\x20to\x20execute.\x20Omit\x20to\x20execute\x20all\x20declared\x20widgets.'},'responseShape':{'envelope':a0_0x4756bb(0xf4),'perWidgetResponse':a0_0x4756bb(0xfd)}},FILE_REFERENCE_CONVENTION={'format':a0_0x4756bb(0xaf),'pathRelativeTo':'payload\x20JSON\x20file\x20location','fileExtensionPolicy':'free;\x20.sql\x20recommended\x20for\x20editor\x20highlight','resolvedAt':'generation\x20time\x20(NOT\x20runtime)','embedStrategy':a0_0x4756bb(0xea),'implication':a0_0x4756bb(0xec)},PLACEHOLDER_CONVENTION={'format':':paramName','regex':a0_0x4756bb(0xc2),'regexNotes':'Negative\x20lookbehind\x20prevents\x20matching\x20\x27::\x27\x20(Postgres\x20cast\x20syntax)\x20as\x20a\x20placeholder.','scanScope':a0_0x4756bb(0xce),'constraint':a0_0x4756bb(0xe6),'exampleSql':'SELECT\x20*\x20FROM\x20stock_inbound\x20WHERE\x20EXTRACT(YEAR\x20FROM\x20inbound_date)\x20=\x20:year','exampleParamDeclaration':a0_0x4756bb(0xd1)},CACHE_SPEC={'container':'top-level\x20\x27cache\x27\x20object','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':a0_0x4756bb(0xd2),'required':!![],'description':a0_0x4756bb(0xb2)},{'name':a0_0x4756bb(0xff),'type':'number','required':![],'constraint':'>=\x200\x20(seconds)','default':'inherits\x20CACHE_TTL\x20env','description':'Time-to-live\x20in\x20seconds.\x200\x20effectively\x20disables\x20cache\x20for\x20this\x20entry.'},{'name':'invalidates','type':a0_0x4756bb(0xc6),'required':![],'default':'[]','description':a0_0x4756bb(0xd4)}],'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)',a0_0x4756bb(0xdf)],'warningOn':['Table\x20detected\x20in\x20SQL,\x20but\x20not\x20registered\x20as\x20CRUD\x20endpoint\x20in\x20metadata\x20project\x20(likely\x20a\x20view,\x20CTE\x20alias,\x20or\x20cross-project\x20table\x20—\x20cascade\x20will\x20not\x20fire)']}},DOCUMENTATION_URL='https://restforge.dev/docs/server/query-data/dashboard',DASHBOARD_CATALOG={'schemaVersion':'1.0','source':a0_0x4756bb(0xcc),'summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE[a0_0x4756bb(0xd8)]['length'],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS['length'],'totalParamTypes':ALLOWED_PARAM_TYPES['length'],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES['length'],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS[a0_0x4756bb(0xc0)]},'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['exports']={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};
|
|
1
|
+
function a0_0x86fc(_0x4b6322,_0x201b4a){_0x4b6322=_0x4b6322-0xc2;const _0x429e10=a0_0x429e();let _0x86fcf4=_0x429e10[_0x4b6322];if(a0_0x86fc['oygnUl']===undefined){var _0x3e571f=function(_0x249b38){const _0x98c856='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x1a57b1='',_0xc49523='';for(let _0x57add7=0x0,_0x2173fc,_0x3cf499,_0x7d9ea8=0x0;_0x3cf499=_0x249b38['charAt'](_0x7d9ea8++);~_0x3cf499&&(_0x2173fc=_0x57add7%0x4?_0x2173fc*0x40+_0x3cf499:_0x3cf499,_0x57add7++%0x4)?_0x1a57b1+=String['fromCharCode'](0xff&_0x2173fc>>(-0x2*_0x57add7&0x6)):0x0){_0x3cf499=_0x98c856['indexOf'](_0x3cf499);}for(let _0x166573=0x0,_0x4536eb=_0x1a57b1['length'];_0x166573<_0x4536eb;_0x166573++){_0xc49523+='%'+('00'+_0x1a57b1['charCodeAt'](_0x166573)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xc49523);};a0_0x86fc['BeIIsc']=_0x3e571f,a0_0x86fc['OCUAag']={},a0_0x86fc['oygnUl']=!![];}const _0x45d5b7=_0x429e10[0x0],_0xbee60f=_0x4b6322+_0x45d5b7,_0x159cf4=a0_0x86fc['OCUAag'][_0xbee60f];return!_0x159cf4?(_0x86fcf4=a0_0x86fc['BeIIsc'](_0x86fcf4),a0_0x86fc['OCUAag'][_0xbee60f]=_0x86fcf4):_0x86fcf4=_0x159cf4,_0x86fcf4;}const a0_0x30d08c=a0_0x86fc;(function(_0x2182a5,_0x5a3726){const _0x194a5c=a0_0x86fc,_0x1bc3a1=_0x2182a5();while(!![]){try{const _0x247141=parseInt(_0x194a5c(0xec))/0x1*(parseInt(_0x194a5c(0xf6))/0x2)+-parseInt(_0x194a5c(0x109))/0x3*(parseInt(_0x194a5c(0x111))/0x4)+parseInt(_0x194a5c(0xd0))/0x5+parseInt(_0x194a5c(0xfb))/0x6*(-parseInt(_0x194a5c(0x11b))/0x7)+-parseInt(_0x194a5c(0xe3))/0x8*(parseInt(_0x194a5c(0x127))/0x9)+parseInt(_0x194a5c(0xc4))/0xa*(parseInt(_0x194a5c(0xeb))/0xb)+parseInt(_0x194a5c(0xdb))/0xc;if(_0x247141===_0x5a3726)break;else _0x1bc3a1['push'](_0x1bc3a1['shift']());}catch(_0x129657){_0x1bc3a1['push'](_0x1bc3a1['shift']());}}}(a0_0x429e,0x34b3e));const FORBIDDEN_FRONTEND_FIELDS=['widgetType',a0_0x30d08c(0x118),a0_0x30d08c(0xd3),'subtitle','color'],ALLOWED_PARAM_TYPES=['string','number','boolean',a0_0x30d08c(0x10d)],FRONTEND_CONCERN_REASONS={'widgetType':a0_0x30d08c(0xf3),'layout':'Layout\x20is\x20a\x20frontend\x20rendering\x20concern.','title':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','subtitle':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','color':a0_0x30d08c(0xd4)},PAYLOAD_SHAPE={'discriminator':{'field':a0_0x30d08c(0xe2),'presentMeans':a0_0x30d08c(0xf2),'absentMeans':a0_0x30d08c(0x124),'conflictsWith':'tableName','conflictRationale':'A\x20payload\x20with\x20both\x20\x27widgets\x27\x20and\x20\x27tableName\x27\x20is\x20rejected\x20by\x20DashboardValidator.\x20Pick\x20one\x20shape.'},'topLevelAllowed':[{'name':'widgets','type':'array','required':!![],'minItems':0x1,'description':'List\x20of\x20widget\x20definitions.\x20Order\x20is\x20informational\x20only\x20(response\x20keys\x20are\x20by\x20widget\x20id,\x20not\x20array\x20index).'},{'name':a0_0x30d08c(0xd2),'type':'object','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_0x30d08c(0xd5),'type':'object','required':![],'description':'Optional\x20cache\x20configuration.\x20See\x20cacheSpec\x20for\x20details.'}],'topLevelForbidden':[{'name':'tableName','category':'shape-conflict','reason':'Reserved\x20for\x20CRUD\x20payloads.\x20A\x20dashboard\x20payload\x20must\x20declare\x20\x27widgets\x27\x20instead.'},...FORBIDDEN_FRONTEND_FIELDS['map'](_0x1a57b1=>({'name':_0x1a57b1,'category':'frontend-concern','reason':FRONTEND_CONCERN_REASONS[_0x1a57b1]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':'string','constraint':'non-empty,\x20unique\x20across\x20widgets\x20in\x20the\x20same\x20payload','description':a0_0x30d08c(0xce)}],'exclusiveQueryFields':{'rule':a0_0x30d08c(0xdf),'options':[{'name':a0_0x30d08c(0x11f),'type':a0_0x30d08c(0xd7),'format':a0_0x30d08c(0x11e),'description':'Single\x20SQL\x20query\x20for\x20the\x20widget.','responseShape':'Always\x20{\x20items:\x20[...]\x20}\x20regardless\x20of\x20SQL\x20result\x20shape.'},{'name':'queries','type':'object','format':a0_0x30d08c(0xf4),'minKeys':0x1,'description':a0_0x30d08c(0x101),'responseShape':'Per-key\x20based\x20on\x20scalarCollapseRules\x20below.'}]},'forbiddenFields':FORBIDDEN_FRONTEND_FIELDS},PARAM_SPEC={'container':'top-level\x20\x27params\x27\x20object','keyConvention':a0_0x30d08c(0x112),'perEntryFields':[{'name':'type','required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':a0_0x30d08c(0x120)},{'name':a0_0x30d08c(0xe6),'required':![],'type':a0_0x30d08c(0x119),'default':![],'description':a0_0x30d08c(0xc8)},{'name':a0_0x30d08c(0xf0),'required':![],'type':a0_0x30d08c(0x122),'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_0x30d08c(0xfd),'exampleSqlShape':'any\x20(1\x20row\x20×\x201\x20col,\x20N\x20rows\x20×\x20M\x20cols,\x20etc.)','exampleResponse':a0_0x30d08c(0x117)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x201\x20row\x20×\x201\x20column','rule':a0_0x30d08c(0x103),'exampleSqlShape':'1\x20row\x20×\x201\x20col,\x20output\x20column\x20\x27value\x27','exampleResponse':'\x22value\x22:\x20\x2269700\x22'},{'appliesTo':a0_0x30d08c(0x106),'rule':a0_0x30d08c(0xca),'exampleSqlShape':a0_0x30d08c(0xf9),'exampleResponse':'\x22trend\x22:\x20{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}'},{'appliesTo':a0_0x30d08c(0xf8),'rule':'Return\x20as\x20array\x20of\x20objects\x20(no\x20collapse).','exampleSqlShape':a0_0x30d08c(0x113),'exampleResponse':'\x22items\x22:\x20[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20...]'}],COMMON_WIDGET_PATTERNS=[{'id':a0_0x30d08c(0xde),'name':a0_0x30d08c(0xfa),'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':'<widget_id>','queries':{'value':a0_0x30d08c(0xff),'trend':'file:query/<path>/trend.sql','items':'file:query/<path>/breakdown.sql'}},'sqlShapesPerKey':[{'key':a0_0x30d08c(0xda),'shape':'1\x20row\x20×\x201\x20column','outputColumns':['value'],'collapseRule':'scalar\x20primitive'},{'key':'trend','shape':a0_0x30d08c(0xed),'outputColumns':['direction','pct'],'collapseRule':'object'},{'key':a0_0x30d08c(0x121),'shape':'N\x20rows\x20×\x202\x20columns','outputColumns':['label','value'],'collapseRule':a0_0x30d08c(0xdc)}],'responseShape':{'value':'\x2269700\x22','trend':'{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','items':'[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20{\x20\x22label\x22:\x20\x22Gaming\x22,\x20\x22value\x22:\x20\x222820\x22\x20},\x20{\x20\x22label\x22:\x20\x22Others\x22,\x20\x22value\x22:\x20\x2245257\x22\x20}]'},'referenceWidgetId':a0_0x30d08c(0x104),'socNotes':a0_0x30d08c(0x129)},{'id':a0_0x30d08c(0x110),'name':a0_0x30d08c(0xdd),'useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20sparkline\x20mini-chart\x20for\x20short\x20windows\x20(7\x20days,\x2012\x20months,\x20etc.).\x20Suitable\x20for\x20widgets\x20like\x20\x27Average\x20Daily\x20Sales\x27.','payloadShape':{'id':'<widget_id>','queries':{'value':a0_0x30d08c(0xff),'trend':a0_0x30d08c(0xcd),'points':'file:query/<path>/points.sql'}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x30d08c(0x102),'outputColumns':['value'],'collapseRule':'scalar\x20primitive'},{'key':a0_0x30d08c(0xe9),'shape':a0_0x30d08c(0xed),'outputColumns':['direction','pct'],'collapseRule':a0_0x30d08c(0xc6)},{'key':'points','shape':a0_0x30d08c(0x10b),'outputColumns':[a0_0x30d08c(0xfe),'value'],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':'\x222420\x22','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':a0_0x30d08c(0x11a)},{'id':'metric_progress_to_goal','name':'Metric\x20+\x20Progress\x20to\x20Goal','useCase':a0_0x30d08c(0xe1),'payloadShape':{'id':'<widget_id>','queries':{'value':a0_0x30d08c(0xea),'trend':a0_0x30d08c(0xcd),'target':a0_0x30d08c(0xfc)}},'sqlShapesPerKey':[{'key':'value','shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0x30d08c(0xe8)],'collapseRule':'scalar\x20primitive'},{'key':a0_0x30d08c(0xe9),'shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction','pct'],'collapseRule':a0_0x30d08c(0xc6)},{'key':'target','shape':a0_0x30d08c(0x102),'outputColumns':[a0_0x30d08c(0xd8)],'collapseRule':a0_0x30d08c(0xc5)}],'responseShape':{'value':a0_0x30d08c(0xc9),'trend':a0_0x30d08c(0x125),'target':'\x222884\x22'},'referenceWidgetId':'orders_this_month','socNotes':a0_0x30d08c(0xe5)}],NAMING_CONVENTION={'dashboardName':{'constraint':'MUST\x20start\x20with\x20\x27dash-\x27\x20prefix','minLength':0x6,'maxLength':0x32,'regex':a0_0x30d08c(0x116),'examples':['dash-sales',a0_0x30d08c(0xf7),a0_0x30d08c(0xe7)],'rationale':a0_0x30d08c(0x11c)}},URL_PATTERN={'method':a0_0x30d08c(0x10f),'path':a0_0x30d08c(0xcc),'exampleFull':'POST\x20/api/mini-inventory/dash-inbound/dashboard','requestBodyShape':{'params':a0_0x30d08c(0xee),'widgets':a0_0x30d08c(0x128)},'responseShape':{'envelope':a0_0x30d08c(0x123),'perWidgetResponse':a0_0x30d08c(0x114)}},FILE_REFERENCE_CONVENTION={'format':a0_0x30d08c(0x11e),'pathRelativeTo':'payload\x20JSON\x20file\x20location','fileExtensionPolicy':'free;\x20.sql\x20recommended\x20for\x20editor\x20highlight','resolvedAt':a0_0x30d08c(0xc2),'embedStrategy':a0_0x30d08c(0x100),'implication':a0_0x30d08c(0xc7)},PLACEHOLDER_CONVENTION={'format':a0_0x30d08c(0x107),'regex':'(?<!:):([a-zA-Z_][a-zA-Z0-9_]*)','regexNotes':'Negative\x20lookbehind\x20prevents\x20matching\x20\x27::\x27\x20(Postgres\x20cast\x20syntax)\x20as\x20a\x20placeholder.','scanScope':a0_0x30d08c(0xf1),'constraint':a0_0x30d08c(0x10c),'exampleSql':a0_0x30d08c(0x10e),'exampleParamDeclaration':a0_0x30d08c(0x115)},CACHE_SPEC={'container':a0_0x30d08c(0xd9),'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':a0_0x30d08c(0xe4),'type':'boolean','required':!![],'description':a0_0x30d08c(0xef)},{'name':'ttl','type':a0_0x30d08c(0xd6),'required':![],'constraint':'>=\x200\x20(seconds)','default':'inherits\x20CACHE_TTL\x20env','description':a0_0x30d08c(0xd1)},{'name':a0_0x30d08c(0x105),'type':a0_0x30d08c(0xc3),'required':![],'default':'[]','description':a0_0x30d08c(0x10a)}],'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_0x30d08c(0x11d),a0_0x30d08c(0xe0)],'warningOn':['Table\x20detected\x20in\x20SQL,\x20but\x20not\x20registered\x20as\x20CRUD\x20endpoint\x20in\x20metadata\x20project\x20(likely\x20a\x20view,\x20CTE\x20alias,\x20or\x20cross-project\x20table\x20—\x20cascade\x20will\x20not\x20fire)']}},DOCUMENTATION_URL=a0_0x30d08c(0x126),DASHBOARD_CATALOG={'schemaVersion':a0_0x30d08c(0x108),'source':'dashboard-catalog','summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE[a0_0x30d08c(0xf5)]['length'],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS['length'],'totalParamTypes':ALLOWED_PARAM_TYPES['length'],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES[a0_0x30d08c(0xcb)],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS['length']},'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_0x30d08c(0xcf)]={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};function a0_0x429e(){const _0x56d514=['nJaWnJC1A2v4s0zO','vgLTzs10BY1SAxzLigLUihnLy29UzhmUidaGzwzMzwn0AxzLBhKGzgLZywjSzxmGy2fJAguGzM9YihrOAxmGzw50CNKU','CgfYyw1Z','DgL0Bgu','vMLZDwfSignVBg9YigLZigeGzNjVBNrLBMqGCMvUzgvYAw5NignVBMnLCM4U','y2fJAgu','BNvTyMvY','C3rYAw5N','DgfYz2v0','Dg9WlwXLDMvSicDJywnOzsCGB2jQzwn0','DMfSDwu','mZa4odi0ohDJsej6CG','yxjYyxKGB2yGB2jQzwn0CW','twv0CMLJicSGu3bHCMTSAw5L','Bwv0CMLJx2rVBNv0x2jYzwfRzg93BG','qsb3AwrNzxqGtvvtvcbKzwnSyxjLigv4ywn0BhKGB25Lig9MoIaNCxvLCNKNie9sicDXDwvYAwvZjY4GqM90AcbVCIbUzwL0AgvYigLZihjLAMvJDgvKlG','vgfIBguGzgvJBgfYzwqGAw4GAw52ywXPzgf0zxmSigj1DcbUB3qGzgv0zwn0zwqGAw4Gyw55ihDPzgDLDcbtuuWGkhr5Cg8GB3iGzgvHzcbLBNrYEsK','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGChjVz3jLC3mGyMfYigfNywLUC3qGysbWzxjPB2qGDgfYz2v0lIbtDwL0ywjSzsbMB3iGD2LKz2v0CYbSAwTLicDpCMrLCNmGvgHPCYbnB250AcCU','D2LKz2v0CW','mJaWruX6twPU','zw5HyMXLza','rNjVBNrLBMqGy29TChv0zxmGDg9Fz29HBca9ihrHCMDLDcaTihzHBhvLigfUzcbWy3qGpsbYB3vUzcH2ywX1zsaVihrHCMDLDcaQideWmcKGzM9YihrOzsbWCM9NCMvZCYbIyxiUifzPC3vHBcb3Awr0AcbPCYbWCMvZzw50yxrPB25HBcbHBMqGBxvZDcbot1qGBgL2zsbPBIb0AguGyMfJA2vUzcbWyxLSB2fKlIbjzIbWCM9NCMvZCYbPBNzVBhzLCYbJB21WBgv4igj1C2LUzxnZihj1BgvZicHLlMCUigv4y2X1zguGD2vLA2vUzhmSihbYB3jHDgvKihDVCMTKyxLZksWGDxnLigeGC2LUz2XLig11BhrPlwnVBhvTBIbXDwvYEsbZBYaNCgn0jYbPCYbHihn0ywjSzsbIDxnPBMvZCYbMywn0ihjHDgHLCIb0AgfUihzPC3vHBcb3Awr0Ac4','CMvXDwLYzwq','zgfZAc1HDxrOB3iTC3rHDhm','DMfSDwuGkg9Yign1CNjLBNqP','DhjLBMq','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','mtuZmtuZD0TduvLO','mtL1CxzrtvO','msbYB3CGW5CGmIbJB2X1Bw5Z','B2jQzwn0iokaLcb2ywX1zxmGzM9YigrLy2XHCMvKihbHCMfTCYaODMfSAwrHDgvKigfNywLUC3qGCgfYyw1ZignVBNrYywn0oYbTAxnZAw5NihjLCxvPCMvKiokgKIa0mdaSihr5CguGBwLZBwf0y2GG4OAsidqWmcK','vg9Nz2XLignHy2HLigzLyxr1CMuGzM9YihrOAxmGzgfZAgjVyxjKlG','zgvMyxvSDa','qwXSihDPzgDLDcbtuuWG4OcuigjVDgGGj3f1zxj5jYaOC2LUz3vSyxiPigfUzcbLDMvYEsaNCxvLCMLLCY48A2v5pICU','zgfZAgjVyxjKihbHEwXVywq','vMLZDwfSihzHCMLHBNqGkgrVBNv0lcbIyxiSihbPzsWGyxjLysKGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBIaOC2vWyxjHDgLVBIbVzIbJB25JzxjUCYKU','A2v54OAszMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','Dg9Wtgv2zwXbBgXVD2vK','mZGXmtHoD2vIvLK','zgfZAc1PBMjVDw5K','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5Nie4GCM93CW','msbYB3CGW5CGmIbJB2XZlcbVDxrWDxqGy29SDw1UCYaNzgLYzwn0Aw9UjYWGj3bJDcC','twv0CMLJicSGrg9UDxqGqNjLywTKB3DU','mte5ntHRwLnQC3y','zMLSztPXDwvYEs88Cgf0Ad4VDgfYz2v0lNnXBa','qwX3yxLZihDYyxaGyxmGEYbPDgvTCZOGwY4UlL0GFsbYzwDHCMrSzxnZig9MifnrtcbYzxn1BhqGC2HHCguU','CgvYAw9K','zMLSztPXDwvYEs88Cgf0Ad4VDMfSDwuUC3fS','u1fmigzPBguGy29UDgvUDcbPCYbLBwjLzgrLzcbHCYbkyxzHu2nYAxb0ihrLBxbSyxrLigXPDgvYywWGAw5ZAwrLihrOzsbNzw5LCMf0zwqGBw9KDwXLigzPBguUifj1BNrPBwuGCgvYzM9YBxmGEMvYBYbKAxnRieKVtYbWzxiGCMvXDwvZDcdIGjqGywXSifnrtcbPCYbPBIbTzw1VCNKGywz0zxiGBw9KDwXLigXVywqU','txvSDgKTu1fmihDPzgDLDc4GrwfJAcbRzxKGyMvJB21LCYbHigTLEsbPBIb0AguGCMvZCg9UC2uGB2jQzwn0lG','msbYB3CGW5CGmsbJB2X1Bw4','q29SBgfWC2uGDg8GC2nHBgfYihbYAw1PDgL2zsaODgHLihzHBhvLig9MihrOzsbZAw5NBguGy29SDw1Uks4','zxHWzwn0zwrFzwfYBMLUz3m','Aw52ywXPzgf0zxm','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxig11BhrPCgXLignVBhvTBNm','oNbHCMfTtMfTzq','ms4W','mtHMv3vbAMm','tgLZDcbVzIbduLveihrHyMXLig5HBwvZihrOyxqSihDOzw4GD3jPDhrLBIWGD2LSBcb0CMLNz2vYigLUDMfSAwrHDgLVBIbVzIb0AgLZigrHC2HIB2fYzcbJywnOzs4','tIbYB3DZimoxidiGy29SDw1UCW','rxzLCNKGCgXHy2vOB2XKzxiGDxnLzcbPBIbtuuWGtvvtvcbIzsbKzwnSyxjLzcbPBIaNCgfYyw1ZjY4GvMfSAwrHDg9YihrOCM93CYbfCNjVCIb3AxrOig1LC3nHz2uGzM9YBwf0oIaIv2LKz2v0icC8Awq+jYbXDwvYEsaNpgXHyMvSpICGDxnLCYb1BMrLy2XHCMvKihbSywnLAg9SzgvYicC6phrVA2vUpICGkgrLy2XHCMuGAw4Gj3bHCMfTCYCPiI4','zgf0zq','u0vmrunuicOGrLjptsbZDg9JA19PBMjVDw5KifDirvjfievyvfjbq1qOwuvbuIbguK9nigLUyM91BMrFzgf0zsKGpsa6EwvHCG','ue9tva','Bwv0CMLJx3nWyxjRBgLUzq','odu5mZzMwxLoEMG','ugfYyw0GBMfTzsbTDxn0ig1HDgnOihrOzsbWBgfJzwHVBgrLCIbYzwDLEcbGw2eTEKeTwL9Dw2eTEKeTwJaTov9DkMaGkgfSCgHHBNvTzxjPyYaRihvUzgvYC2nVCMuSig11C3qGC3rHCNqGD2L0AcbSzxr0zxiGB3iGDw5KzxjZy29YzsKU','tIbYB3DZimoxie0Gy29SCW','rgv0zxjTAw5LzcbIEsbZy2fSyxjdB2XSyxbZzvj1BgvZlIbgywLSzwqGD2LKz2v0CYbWCM9KDwnLihSGzxjYB3i6icCUlI4Nih0GyMXVy2SGD2L0Acb0B3aTBgv2zwWGC3vJy2vZCYbZDgLSBcb0CNvLicHVBMuGD2LKz2v0igzHAwX1CMuGzg9LCYbot1qGzMfPBcb0AguGzgfZAgjVyxjKks4','EYaICgfYyw1ZiJOGEYaIEwvHCIi6ihSGiNr5CguIoIaIBNvTyMvYiIWGiNjLCxvPCMvKiJOGDhj1zsb9ih0GFq','xMrHC2GTw2eTEKeTwJaTov8TxsSK','iNnOB3bWAw5Nx2nHDgvNB3jPzxmIoIb7icjPDgvTCYi6ifT7icjUyw1LiJOGiKXHBMrZiIb9lcb7icjUyw1LiJOGiKHVDxnLCYiGFv0GFq','Bgf5B3v0','yM9VBgvHBG','u3bHCMTSAw5LigXPyNjHCMLLCYaOqxbLEenOyxj0CYWGq2HHCNrPC3qSigv0yY4Pihr5CgLJywXSEsbUzwvKigeGCgXHAw4GBNvTyMvYigfYCMf5lIbgCM9UDgvUzcbTyxbZihbVAw50CY5TyxaOCca9pIbWlNzHBhvLks4GvgHLicDWzxjPB2qNigzPzwXKihn0yxLZigzVCIb0B29SDgLWigfUzcbNyxaTCMvZAwXPzw5JzsbHz2fPBNn0ig1PC3nPBMCGzgf5CY4GvxnLigDLBMvYyxrLx3nLCMLLCYbPBIbtuuWGDg8Gzw5ZDxjLignVBNnPC3rLBNqGCM93ignVDw50igv2zw4GzM9YigrHExmGD2L0AcbUBYb0CMfUC2fJDgLVBNmU','mti2n21Nrez5zG','vgHLihbYzwzPEcbIzwnVBwvZihbHCNqGB2yGDgHLifvstcbZzwDTzw50lIbuAguGCMvZzxj2zwqGC2nOzw1LigTLzxbZigrHC2HIB2fYzcbLBMrWB2LUDhmGDMLZDwfSBhKGzgLZDgLUy3qGzNjVBsbduLveigvUzhbVAw50CYbPBIb0AguGvvjmihnWywnLigfUzcbHBgXVD3mGzNv0DxjLihjVDxrPBMCGzgLMzMvYzw50Awf0Aw9UlG','vgfIBguGyxbWzwfYCYbPBIbtuuWGqu5eigLUig1LDgfKyxrHihbYB2PLy3qSigj1DcbTAxnZAw5NigzYB20GAw52ywXPzgf0zxmGkgnHy2HLihn0ywXLihjPC2SP','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','CxvLCNK','ugfYyw0Gzgf0ysb0ExbLlIbwywXPzgf0zxmGCMvXDwvZDcbIB2r5igfUzcbZAgfWzxmGCNvUDgLTzsbWyxjHBwv0zxiGyMLUzgLUzY4','AxrLBxm','yw55icHTDxn0igjLignVBxbHDgLIBguGD2L0AcbKzwnSyxjLzcaNDhLWzsCP','EYbZDwnJzxnZoIbIB29SzwfUlcbKyxrHoIb7idX3AwrNzxrjzd46idXWzxjxAwrNzxrszxnWB25Zzt4Sic4UlIb9ih0','tM90igeGzgfZAgjVyxjKihbHEwXVywqGkgXPA2vSEsbduLveihDPDgGGDgfIBgvoyw1LlcbVCIbPBNzHBgLKkq','EYaIzgLYzwn0Aw9UiJOGiMrVD24IlcaICgn0iJOGiJiUmIiGFq','Ahr0Chm6lY9Yzxn0zM9Yz2uUzgv2l2rVy3mVC2vYDMvYl3f1zxj5lwrHDgeVzgfZAgjVyxjK','odi0ndLfBxDgsfu','yxjYyxK8C3rYAw5NpIWGB3b0Aw9UywWG4Ocuihn1yNnLDcbVzIb3AwrNzxqGsurZihrVigv4zwn1DguUie9TAxqGDg8GzxHLy3v0zsbHBgWGzgvJBgfYzwqGD2LKz2v0CY4','rNjVBNrLBMqGzgv0zxjTAw5LCYbKB251Dc9WAwuGDMfYAwfUDcWGy29SB3iGCgvYignHDgvNB3j5lcbHBMqGBgfIzwWGB3jKzxiUieLMihbLCI1JyxrLz29YEsbWzxjJzw50ywDLigLZig5LzwrLzcbMB3iGDgHLigrVBNv0igfYyYWGzNjVBNrLBMqGy29TChv0zxmGAxqGzNjVBsbPDgvTC1TPxs52ywX1zsaVihn1BsHPDgvTC1SQxs52ywX1zsKUie5Vig5LzwqGDg8GC2vUzcaNCgn0jYbMCM9TigjHy2TLBMqGDw5SzxnZihrOzsbMAwD1CMuGAxmGysbZDgfIBguGyNvZAw5LC3mGy2fSy3vSyxrPB24GAw5KzxbLBMrLBNqGB2yGDMLZDwfSihjLBMrLCMLUzY4','z2vUzxjHDgLVBIb0Aw1LicHot1qGCNvUDgLTzsK','yxjYyxK8C3rYAw5NpG','mtqWALrIvwTK','C2nHBgfYihbYAw1PDgL2zq','B2jQzwn0','vxbKyxrPBMCGyw4Gu1fmigzPBguGCMvXDwLYzxmGCMvNzw5LCMf0Aw5NihrOzsbKyxnOyM9HCMqGBw9KDwXLicGNy29KzwDLBL9JCMvHDgvFzgfZAgjVyxjKjYKGzM9YignOyw5NzxmGDg8GDgfRzsbLzMzLy3qU','v2HLBIb0CNvLlcb0AguGCMvXDwvZDcbIB2r5ie1vu1qGAw5JBhvKzsb0AgLZihbHCMfTicHVDgHLCNDPC2uGndaWks4','iJe4mZyI','q29SBgfWC2uGDg8GB2jQzwn0ihDOB3nLigTLExmGyxjLifnrtcbJB2X1Bw4GBMfTzxmGkgXVD2vYy2fZzwqPlG','BgvUz3rO','l2fWAs97ChjVAMvJDh0VE25HBwv9l2rHC2HIB2fYza','zMLSztPXDwvYEs88Cgf0Ad4VDhjLBMqUC3fS','v2LKz2v0igLKzw50AwzPzxi7ihvZzwqGyxmGDgHLihjLC3bVBNnLigTLEsbPBIb0AguGzgfZAgjVyxjKigvUDMvSB3bLlG','zxHWB3j0CW'];a0_0x429e=function(){return _0x56d514;};return a0_0x429e();}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const a0_0x70dee4=a0_0x3e43;function a0_0x4f18(){const _0x1fc8c3=['DhjPBq','nZeZn015weDIsa','mJC1nZG0nu9XBfDfva','C3rHCNrZv2L0Aa','ndCWwM90wKzS','C3bSAxq','u0vsvKvsx1bpuLq','AM9PBG','Aw5KzxHpzG','nLDmvw1xsG','mtC3mJa4mZj6DfzeBhi','mtr3vK5MreS','u0vsvKvsx0ferfjfu1m','ndy4ndfmtMDRDwC','owHqt1rVvq','rejFvfLqrq','rejFtKfnrq','mta5mJmWAhrqAwTf','teLdru5trq','qvnRq24','DgvZDa','rejFse9tva','iYbmAwnLBNnLcKXjq0vou0u9wfHywc1ywfHylvHywfGTwfHywaOkiYbtzxj2zxiku0vsvKvsx0ferfjfu1m9mti3lJaUmc4XcLnfuLzfuL9qt1juptmWmdakcImGtgL2zsbtEw5JicHxzwjtB2nRzxqPienVBMzPz3vYyxrPB24kiYbot1rfoIbmsvzfx1nztKnFru5bqKXfrd10CNvLihjLCxvPCMvZigfUiefqssblzxKGkeTfwt0UlI4PihrVigf1DgHLBNrPy2f0zsbxzwjtB2nRzxqGy2XPzw50CWPmsvzfx1nztKnFru5bqKXfrd1MywXZzqPmsvzfx1nztKnFue9svd0ZmdmZcGOJifjLzgLZienVBMzPz3vYyxrPB24kuKvesvnFse9tvd1SB2nHBgHVC3qkuKvesvnFue9svd02mZGWcLjfreLtx1bbu1nxt1jepqPsrurju19eqJ0WcGOJiev4Cg9YDcbdB25MAwD1CMf0Aw9UcKvyue9svf9gsuXfx0vyueLswt0ZnJaWmdaWcKvyue9svf9dsfvos19tsvPfpteWmdakcImGs2fMA2eGq29UzMLNDxjHDgLVBGPlquzlqv9ftKfctevepwzHBhnLcImGqNjVA2vYigXPC3qGkgnVBw1HlxnLCgfYyxrLzcbMB3iGBxvSDgLWBguGyNjVA2vYCZOGyNjVA2vYmtO5mdKYlgjYB2TLCJi6ota5mIXICM9RzxiZoJKWotiPcKTbrKTbx0jst0TfuLm9Bg9JywXOB3n0oJKWotikiYbdBgLLBNqGsuqGkg9WDgLVBMfSlcbKzwzHDwX0oIbYzxn0zM9Yz2uTE3bYB2PLy3r9lxbYB2r1y2vYic8GlwnVBNn1BwvYkqOJieTbrKTbx0nmsuvovf9jrd0ks0fgs0fFq09otKvdveLptL9usu1ft1vuptmWmdaks0fgs0fFuKvrvuvtvf9usu1ft1vupti1mdaWcKTbrKTbx1rpueLdx1bbvfrfuK49E21VzhvSzx0UE2vUzhbVAw50Fs5LDMvUDhmks0fgs0fFvevoqu5ux0LepwrLzMf1Bhqks0fgs0fFu0vtu0LptL9usu1ft1vuptmWmdaWcKTbrKTbx0HfqvjuqKvbvf9jtLrfuLzbtd0ZmdaWcKTbrKTbx01bwf9cwvrfu19qrvjFuefsveLusu9opteWndG1nZyks0fgs0fFqvvut19dt01nsvq9zMfSC2uks0fgs0fFqvvut19dt01nsvrFsu5urvjwquW9ntaWmaPlquzlqv9srvrswv9bvfrftvbuuZ0ZcKTbrKTbx1jfvfjzx0rftefzpteWmdaks0fgs0fFuKvuuLLFtufyx0rftefzptmWmdaWcKTbrKTbx1nttd1MywXZzqPlquzlqv9mt0DFtevwruW9Aw5MBWOJifnbu0WGqxv0AgvUDgLJyxrPB24Gkg9WDgLVBMfSlcb1BMnVBw1LBNqGAwyGDgHLigjYB2TLCIbYzxf1AxjLCYbHDxrOzw50AwnHDgLVBIKkiYbtDxbWB3j0zwqGBwvJAgfUAxnTCZOGCgXHAw4SihnJCMfTlxnOys0YntySihnJCMfTlxnOys01mtikiYblquzlqv9tqvnmx01fq0HbtKLttt1WBgfPBGOJieTbrKTbx1nbu0XFvvnfuK5btuu9cImGs0fgs0fFu0fttf9qqvntv09srd0kcImGrgf0ywjHC2uGq29UzMLNDxjHDgLVBGOJifn1ChbVCNrLzdOGCg9ZDgDYzxnXBcWGBxLZCwWSig9YywnSzsWGC3fSAxrLcKrcx1rzueu9Cg9ZDgDYzxnXBaPeqL9it1nupteYnY4WlJaUmqPeqL9qt1juptu0mZikrejFvvnfuJ1WB3n0z3jLCWPeqL9qqvntv09srd15B3vYx3bHC3n3B3jKx2HLCMukrejFtKfnrt15B3vYx2rHDgfIyxnLx25HBwukiYbgB3iGu1fmAxrLoIbZzxqGrejFvfLqrt1ZCwXPDguGyw5Kiercx05btuu9lI9KyxrHl215yxbWlMrIcImGrejFse9tvcWGrejFue9svcWGrejFvvnfuIWGrejFueftu1DpuKqGyxjLigLNBM9YzwqGzM9YifnrtgL0zqOkiYbmB2DNAw5NienVBMzPz3vYyxrPB24kte9hx0XfvKvmpwrLyNvNcKXpr19ut19gsuXfpxrYDwukcImGu1fmieXVz2DPBMCku1fmx0Xpr19ftKfctevepwzHBhnLcLnrtf9mt0DFtevwruW9zgvIDwCku1fmx0Xpr19qqvjbtvm9zMfSC2uku1fmx0Xpr19tte9xx1riuKvtse9mrd0XmdaWcGOJienHy2HLienVBMzPz3vYyxrPB24kq0fdsevFru5bqKXfrd1MywXZzqPdqunirv9uveW9mZaWcGOJiePVyIbty2HLzhvSzxiksK9cx0voqujmruq9zMfSC2uksK9cx0nptKnvuLjftKnzptuksK9cx1jfvevoveLptL9it1vsuZ03mGPkt0jFrKfjtevex1jfvevoveLptL9it1vsuZ0XnJGksK9cx1nivvret1Dox1rjtuvpvvq9mtaWmdaksK9cx1nuquXmrurFsu5urvjwquW9mZaWmdaksK9cx01bwf9tvefmtevex0npvu5uptikcImGrgLZDhjPyNv0zwqGtg9JAYbdB25MAwD1CMf0Aw9UcKXpq0TFreLtvfjjqLvururFru5bqKXfrd1MywXZzqPmt0nlx0rju1rssujvvevex1rutd0XmaPmt0nlx1jfu09vuKnfx01bwf9uveW9nJaWcKXpq0TFreLtvfjjqLvururFuKvuuLK9mWPmt0nlx0rju1rssujvvevex1jfvfjzx0rftefzpteWmaPmt0nlx0rju1rssujvvevex1nuuKfuruDzpxjLAMvJDaOkiYbjrcbhzw5LCMf0B3iGq29UzMLNDxjHDgLVBGPjreDftL9ftKfctevepwzHBhnLcKLer0vox0Leru1FvfrmptyWmaPjreDftL9dt1vovevsx1rutf9nt05useXzpti3nJq4mdaksurhru5Fq09vtLrfuL9uveXFrefjtfK9mtCYodaWcKLer0vox0rfrKfvtfrFtufyx1jfvfjzpteWcKLer0vox0rfrKfvtfrFueLox0rjr0LuuZ02cKLer0vox0rfrKfvtfrFu0vssufmx1bbvfrfuK49wfHywc1ywfHylvHywfGTwfHywaPjreDftL9eruzbvuXux0nprevFuefuvevstJ05otK5ltK5otKksurhru5FquXmt1DFuKvtrvq9zMfSC2uk','C2XPy2u','ChvZAa','yxDfwu8','mZyXnZm2ovvzsKzuvq','otmYCujhzMHQ','zMfSC2u','Aw50zwDLCG','rejFueftu1DpuKq','BgvUz3rO','mJmWnJmZnLb5sxf3tq'];a0_0x4f18=function(){return _0x1fc8c3;};return a0_0x4f18();}(function(_0x21606d,_0x4e92d8){const _0xe25a9=a0_0x3e43,_0x33083d=_0x21606d();while(!![]){try{const _0x15775d=-parseInt(_0xe25a9(0x1a7))/0x1*(-parseInt(_0xe25a9(0x1a5))/0x2)+-parseInt(_0xe25a9(0x19b))/0x3*(-parseInt(_0xe25a9(0x1b5))/0x4)+-parseInt(_0xe25a9(0x19c))/0x5*(-parseInt(_0xe25a9(0x1a3))/0x6)+parseInt(_0xe25a9(0x1b4))/0x7+parseInt(_0xe25a9(0x199))/0x8*(parseInt(_0xe25a9(0x1a8))/0x9)+parseInt(_0xe25a9(0x19e))/0xa*(-parseInt(_0xe25a9(0x1ab))/0xb)+-parseInt(_0xe25a9(0x1a4))/0xc;if(_0x15775d===_0x4e92d8)break;else _0x33083d['push'](_0x33083d['shift']());}catch(_0x4449ab){_0x33083d['push'](_0x33083d['shift']());}}}(a0_0x4f18,0x481d0));function a0_0x3e43(_0x591ebc,_0xa9a6ad){_0x591ebc=_0x591ebc-0x195;const _0x4f180c=a0_0x4f18();let _0x3e434c=_0x4f180c[_0x591ebc];if(a0_0x3e43['NHXGad']===undefined){var _0x588b50=function(_0x3b50f5){const _0x1f5e7d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2832fa='',_0x165db9='';for(let _0x3808b6=0x0,_0x5f42e4,_0x1a0c64,_0x133c2f=0x0;_0x1a0c64=_0x3b50f5['charAt'](_0x133c2f++);~_0x1a0c64&&(_0x5f42e4=_0x3808b6%0x4?_0x5f42e4*0x40+_0x1a0c64:_0x1a0c64,_0x3808b6++%0x4)?_0x2832fa+=String['fromCharCode'](0xff&_0x5f42e4>>(-0x2*_0x3808b6&0x6)):0x0){_0x1a0c64=_0x1f5e7d['indexOf'](_0x1a0c64);}for(let _0x175e65=0x0,_0x4f655e=_0x2832fa['length'];_0x175e65<_0x4f655e;_0x175e65++){_0x165db9+='%'+('00'+_0x2832fa['charCodeAt'](_0x175e65)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x165db9);};a0_0x3e43['nvhgPM']=_0x588b50,a0_0x3e43['pgUQQx']={},a0_0x3e43['NHXGad']=!![];}const _0x57c7a8=_0x4f180c[0x0],_0x472291=_0x591ebc+_0x57c7a8,_0x11caeb=a0_0x3e43['pgUQQx'][_0x472291];return!_0x11caeb?(_0x3e434c=a0_0x3e43['nvhgPM'](_0x3e434c),a0_0x3e43['pgUQQx'][_0x472291]=_0x3e434c):_0x3e434c=_0x11caeb,_0x3e434c;}const DB_CONNECTION_ENV_TEMPLATE=a0_0x70dee4(0x1b0),REQUIRED_KEYS=new Set([a0_0x70dee4(0x1ac),a0_0x70dee4(0x1a6),a0_0x70dee4(0x1a0),a0_0x70dee4(0x1a9),a0_0x70dee4(0x1af),'DB_PORT','DB_USER',a0_0x70dee4(0x197),a0_0x70dee4(0x1aa)]);function parseTemplateAsSchema(_0x4ffeb4){const _0x5b65a2=a0_0x70dee4,_0x11d627={'XKTeY':function(_0x21288a,_0xb1759e){return _0x21288a<_0xb1759e;},'awEYO':function(_0x2c3cb2,_0x4744e3){return _0x2c3cb2===_0x4744e3;},'gbriV':function(_0x53895a,_0x1bc8d4){return _0x53895a>_0x1bc8d4;},'DlDuA':function(_0x4ccddc,_0x1f3099){return _0x4ccddc+_0x1f3099;},'ASkCn':'true','cMcGa':'boolean','ZzQOS':_0x5b65a2(0x196)},_0x5cfece=_0x4ffeb4||DB_CONNECTION_ENV_TEMPLATE,_0x463f3d=_0x5cfece[_0x5b65a2(0x19f)]('\x0a'),_0x55b0d9=[];let _0x228df5=null,_0x5274b1=[];for(const _0x42dbe4 of _0x463f3d){const _0x1c8e04=_0x42dbe4[_0x5b65a2(0x19a)]();if(_0x1c8e04===''){_0x5274b1=[];continue;}if(_0x1c8e04[_0x5b65a2(0x19d)]('#')){const _0x3750f5=_0x1c8e04['slice'](0x1)[_0x5b65a2(0x19a)](),_0x26e864=_0x3750f5['length']>0x0&&_0x11d627['XKTeY'](_0x3750f5['length'],0x3c)&&!_0x3750f5['includes'](':')&&!/^[A-Z_]+=/['test'](_0x3750f5)&&/^[A-Z]/[_0x5b65a2(0x1ae)](_0x3750f5);_0x26e864&&_0x11d627[_0x5b65a2(0x1b3)](_0x5274b1[_0x5b65a2(0x198)],0x0)?_0x228df5=_0x3750f5:_0x5274b1[_0x5b65a2(0x1b2)](_0x3750f5);continue;}const _0xd317bc=_0x42dbe4[_0x5b65a2(0x1a2)]('=');if(_0x11d627['gbriV'](_0xd317bc,0x0)){const _0x29fdda=_0x42dbe4[_0x5b65a2(0x1b1)](0x0,_0xd317bc)['trim'](),_0x387381=_0x42dbe4[_0x5b65a2(0x1b1)](_0x11d627['DlDuA'](_0xd317bc,0x1));let _0x264e82='string';if(_0x387381===_0x11d627[_0x5b65a2(0x1ad)]||_0x387381===_0x5b65a2(0x195))_0x264e82=_0x11d627['cMcGa'];else/^-?\d+$/[_0x5b65a2(0x1ae)](_0x387381)&&(_0x264e82=_0x11d627['ZzQOS']);_0x55b0d9[_0x5b65a2(0x1b2)]({'name':_0x29fdda,'section':_0x228df5,'type':_0x264e82,'default':_0x387381,'description':_0x5274b1[_0x5b65a2(0x1a1)]('\x20')||null,'required':REQUIRED_KEYS['has'](_0x29fdda)}),_0x5274b1=[];}}return _0x55b0d9;}module['exports']={'DB_CONNECTION_ENV_TEMPLATE':DB_CONNECTION_ENV_TEMPLATE,'REQUIRED_KEYS':REQUIRED_KEYS,'parseTemplateAsSchema':parseTemplateAsSchema};
|