@restforgejs/platform 4.3.1 → 4.3.4

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.
Files changed (176) hide show
  1. package/build-info.json +2 -2
  2. package/cli/consumer-deploy.js +1 -1
  3. package/cli/consumer.js +1 -1
  4. package/generators/cli/dashboard/create.js +0 -1
  5. package/generators/cli/endpoint/create.js +1 -1
  6. package/generators/lib/generators/model-generator.js +1 -1
  7. package/generators/lib/payload/endpoint-schema-validator.js +11 -1
  8. package/generators/lib/payload/payload-runner.js +4 -4
  9. package/generators/lib/payload/schema-diff.js +186 -3
  10. package/generators/lib/templates/dashboard-catalog.js +1 -1
  11. package/generators/lib/templates/db-connection-env.js +1 -1
  12. package/generators/lib/templates/dbschema-catalog.js +1 -1
  13. package/generators/lib/templates/field-validation-catalog.js +1 -1
  14. package/generators/lib/templates/mysql-template.js +1 -1
  15. package/generators/lib/templates/oracle-template.js +1 -1
  16. package/generators/lib/templates/postgres-template.js +1 -1
  17. package/generators/lib/templates/query-declarative-catalog.js +1 -1
  18. package/generators/lib/templates/sqlite-template.js +1 -1
  19. package/generators/lib/utils/conflict-checker.js +9 -57
  20. package/generators/lib/utils/database-introspector.js +84 -0
  21. package/generators/lib/utils/file-utils.js +0 -159
  22. package/generators/lib/utils/payload-processor.js +21 -112
  23. package/integrity-manifest.json +18 -18
  24. package/package.json +1 -1
  25. package/scripts/verify-integrity.js +1 -1
  26. package/server.js +1 -1
  27. package/src/components/handlers/adjust_handler.js +1 -1
  28. package/src/components/handlers/audit_handler.js +1 -1
  29. package/src/components/handlers/delete_handler.js +1 -1
  30. package/src/components/handlers/export_handler.js +1 -1
  31. package/src/components/handlers/import_handler.js +1 -1
  32. package/src/components/handlers/insert_handler.js +1 -1
  33. package/src/components/handlers/update_handler.js +1 -1
  34. package/src/components/handlers/upload_handler.js +1 -1
  35. package/src/components/handlers/workflow_handler.js +1 -1
  36. package/src/components/integrations/webhook.js +1 -1
  37. package/src/consumers/baseConsumer.js +1 -1
  38. package/src/consumers/declarativeMapper.js +1 -1
  39. package/src/consumers/handlers/apiHandler.js +1 -1
  40. package/src/consumers/handlers/consoleHandler.js +1 -1
  41. package/src/consumers/handlers/databaseHandler.js +1 -1
  42. package/src/consumers/handlers/index.js +1 -1
  43. package/src/consumers/handlers/kafkaHandler.js +1 -1
  44. package/src/consumers/index.js +1 -1
  45. package/src/consumers/messageTransformer.js +1 -1
  46. package/src/consumers/validator.js +1 -1
  47. package/src/core/db/dialect/base-dialect.js +1 -1
  48. package/src/core/db/dialect/index.js +1 -1
  49. package/src/core/db/dialect/mysql-dialect.js +1 -1
  50. package/src/core/db/dialect/oracle-dialect.js +1 -1
  51. package/src/core/db/dialect/postgres-dialect.js +1 -1
  52. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  53. package/src/core/db/flatten-helper.js +1 -1
  54. package/src/core/db/query-builder-error.js +1 -1
  55. package/src/core/db/query-builder.js +1 -1
  56. package/src/core/db/relation-helper.js +1 -1
  57. package/src/core/handlers/delete_handler.js +1 -1
  58. package/src/core/handlers/insert_handler.js +1 -1
  59. package/src/core/handlers/update_handler.js +1 -1
  60. package/src/core/models/base-model.js +1 -1
  61. package/src/core/utils/cache-manager.js +1 -1
  62. package/src/core/utils/component-engine.js +1 -1
  63. package/src/core/utils/context-builder.js +1 -1
  64. package/src/core/utils/datetime-formatter.js +1 -1
  65. package/src/core/utils/datetime-parser.js +1 -1
  66. package/src/core/utils/db.js +1 -1
  67. package/src/core/utils/logger.js +1 -1
  68. package/src/core/utils/payload-loader.js +1 -1
  69. package/src/core/utils/security-checks.js +1 -1
  70. package/src/middleware/body-options.js +1 -1
  71. package/src/middleware/cors.js +1 -1
  72. package/src/middleware/idempotency.js +1 -1
  73. package/src/middleware/rate-limiter.js +1 -1
  74. package/src/middleware/request-logger.js +1 -1
  75. package/src/middleware/security-headers.js +1 -1
  76. package/src/models/base-model-mysql.js +1 -1
  77. package/src/models/base-model-oracle.js +1 -1
  78. package/src/models/base-model-sqlite.js +1 -1
  79. package/src/models/base-model.js +1 -1
  80. package/src/pro/caching/redis-client.js +1 -1
  81. package/src/pro/caching/redis-helper.js +1 -1
  82. package/src/pro/consumers/baseConsumer.js +1 -1
  83. package/src/pro/consumers/declarativeMapper.js +1 -1
  84. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  85. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  86. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  87. package/src/pro/consumers/handlers/index.js +1 -1
  88. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  89. package/src/pro/consumers/index.js +1 -1
  90. package/src/pro/consumers/messageTransformer.js +1 -1
  91. package/src/pro/consumers/validator.js +1 -1
  92. package/src/pro/database/base-model-mysql.js +1 -1
  93. package/src/pro/database/base-model-oracle.js +1 -1
  94. package/src/pro/database/base-model-sqlite.js +1 -1
  95. package/src/pro/database/db-mysql.js +1 -1
  96. package/src/pro/database/db-oracle.js +1 -1
  97. package/src/pro/database/db-sqlite.js +1 -1
  98. package/src/pro/excel/excel-generator.js +1 -1
  99. package/src/pro/excel/excel-parser.js +1 -1
  100. package/src/pro/excel/export-service.js +1 -1
  101. package/src/pro/excel/export_handler.js +1 -1
  102. package/src/pro/excel/import-service.js +1 -1
  103. package/src/pro/excel/import-validator.js +1 -1
  104. package/src/pro/excel/import_handler.js +1 -1
  105. package/src/pro/excel/upsert-builder.js +1 -1
  106. package/src/pro/idgen/idgen-routes.js +1 -1
  107. package/src/pro/integrations/lookup-resolver.js +1 -1
  108. package/src/pro/integrations/upload-handler-v2.js +1 -1
  109. package/src/pro/integrations/upload-handler.js +1 -1
  110. package/src/pro/integrations/webhook.js +1 -1
  111. package/src/pro/locking/lock-routes.js +1 -1
  112. package/src/pro/locking/resource-lock-manager.js +1 -1
  113. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  114. package/src/pro/messaging/kafkaService.js +1 -1
  115. package/src/pro/messaging/messagehubService.js +1 -1
  116. package/src/pro/messaging/rabbitmqService.js +1 -1
  117. package/src/pro/scheduler/job-manager.js +1 -1
  118. package/src/pro/scheduler/job-routes.js +1 -1
  119. package/src/pro/scheduler/job-validator.js +1 -1
  120. package/src/pro/storage/base-storage-provider.js +1 -1
  121. package/src/pro/storage/file-metadata-helper.js +1 -1
  122. package/src/pro/storage/index.js +1 -1
  123. package/src/pro/storage/local-storage-provider.js +1 -1
  124. package/src/pro/storage/s3-storage-provider.js +1 -1
  125. package/src/pro/storage/upload-cleanup-job.js +1 -1
  126. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  127. package/src/pro/storage/upload-pending-tracker.js +1 -1
  128. package/src/pro/websocket/broadcast-helper.js +1 -1
  129. package/src/pro/websocket/index.js +1 -1
  130. package/src/pro/websocket/livesync-server.js +1 -1
  131. package/src/pro/websocket/ws-broadcaster.js +1 -1
  132. package/src/services/export-service.js +1 -1
  133. package/src/services/import-service.js +1 -1
  134. package/src/services/kafkaConsumerService.js +1 -1
  135. package/src/services/kafkaService.js +1 -1
  136. package/src/services/messagehubService.js +1 -1
  137. package/src/services/rabbitmqService.js +1 -1
  138. package/src/utils/cache-invalidation-registry.js +1 -1
  139. package/src/utils/cache-manager.js +1 -1
  140. package/src/utils/component-engine.js +1 -1
  141. package/src/utils/config-extractor.js +1 -1
  142. package/src/utils/consumerLogger.js +1 -1
  143. package/src/utils/context-builder.js +1 -1
  144. package/src/utils/dashboard-helpers.js +1 -1
  145. package/src/utils/dateHelper.js +1 -1
  146. package/src/utils/datetime-formatter.js +1 -1
  147. package/src/utils/datetime-parser.js +1 -1
  148. package/src/utils/db-bootstrap.js +1 -1
  149. package/src/utils/db-mysql.js +1 -1
  150. package/src/utils/db-oracle.js +1 -1
  151. package/src/utils/db-sqlite.js +1 -1
  152. package/src/utils/db.js +1 -1
  153. package/src/utils/demo-generator.js +1 -1
  154. package/src/utils/excel-generator.js +1 -1
  155. package/src/utils/excel-parser.js +1 -1
  156. package/src/utils/file-watcher.js +1 -1
  157. package/src/utils/id-generator.js +1 -1
  158. package/src/utils/idempotency-manager.js +1 -1
  159. package/src/utils/import-validator.js +1 -1
  160. package/src/utils/license-client.js +1 -1
  161. package/src/utils/lock-manager.js +1 -1
  162. package/src/utils/logger.js +1 -1
  163. package/src/utils/lookup-resolver.js +1 -1
  164. package/src/utils/payload-loader.js +1 -1
  165. package/src/utils/processor-response.js +1 -1
  166. package/src/utils/rabbitmq.js +1 -1
  167. package/src/utils/redis-client.js +1 -1
  168. package/src/utils/redis-helper.js +1 -1
  169. package/src/utils/request-scope.js +1 -1
  170. package/src/utils/security-checks.js +1 -1
  171. package/src/utils/service-resolver.js +1 -1
  172. package/src/utils/shutdown-coordinator.js +1 -1
  173. package/src/utils/trusted-keys.js +1 -1
  174. package/src/utils/upload-handler.js +1 -1
  175. package/src/utils/upsert-builder.js +1 -1
  176. package/src/utils/workflow-hook-executor.js +1 -1
@@ -78,47 +78,22 @@ class ConflictChecker {
78
78
  conflicts.hasConflicts = true;
79
79
  }
80
80
 
81
- // 3. Check query directory conflicts jika ada SQL files dalam payload
82
- const queryDir = path.join(workingDir, 'src', 'models', moduleName, 'query');
83
- if (this.hasQueryFiles(payload) && fs.existsSync(queryDir)) {
84
- const fileInfo = FileUtils.getFileInfo(queryDir);
85
- conflicts.fileConflicts.push({
86
- type: 'queryDir',
87
- path: queryDir,
88
- relativePath: path.relative(workingDir, queryDir),
89
- fileInfo: fileInfo
90
- });
91
- conflicts.hasConflicts = true;
92
- }
93
-
94
- // 4. Check metadata conflicts (optional, tidak urgent)
95
- if (MetadataManager.endpointExists(moduleName, endpointName)) {
96
- const endpointMetadata = MetadataManager.getEndpointMetadata(moduleName, endpointName);
97
- conflicts.metadataConflicts.push({
98
- type: 'endpoint_metadata',
99
- endpointName: endpointName,
100
- metadata: endpointMetadata
101
- });
102
- // Metadata conflicts tidak mengaktifkan hasConflicts untuk module
103
- }
104
-
105
- // 5. Check system-level conflicts
81
+ // 3. Check system-level conflicts
106
82
  const systemConflict = this.checkSystemConflicts(moduleName, endpointName);
107
83
  if (systemConflict) {
108
84
  conflicts.systemConflicts.push(systemConflict);
109
85
  conflicts.hasConflicts = true;
110
86
  }
111
87
 
112
- // 6. Add summary details
88
+ // 5. Add summary details
113
89
  conflicts.details = {
114
90
  moduleName: moduleName,
115
91
  endpointName: endpointName,
116
- totalConflicts: conflicts.fileConflicts.length + conflicts.metadataConflicts.length + conflicts.systemConflicts.length,
92
+ totalConflicts: conflicts.fileConflicts.length + conflicts.systemConflicts.length,
117
93
  totalFiles: conflicts.fileConflicts.length,
118
94
  submoduleFiles: conflicts.fileConflicts.filter(f => f.type === 'submoduleFile').length,
119
95
  modelFiles: conflicts.fileConflicts.filter(f => f.type === 'modelFile').length,
120
96
  queryDirs: conflicts.fileConflicts.filter(f => f.type === 'queryDir').length,
121
- metadataFiles: conflicts.metadataConflicts.length,
122
97
  systemIssues: conflicts.systemConflicts.length,
123
98
  riskLevel: this.assessRiskLevel(conflicts)
124
99
  };
@@ -277,33 +252,21 @@ class ConflictChecker {
277
252
  }
278
253
  }
279
254
 
280
- // 3. Check metadata conflicts (optional, tidak urgent)
281
- if (MetadataManager.endpointExists(moduleName, endpointName)) {
282
- const endpointMetadata = MetadataManager.getEndpointMetadata(moduleName, endpointName);
283
- conflicts.metadataConflicts.push({
284
- type: 'endpoint_metadata',
285
- endpointName: endpointName,
286
- metadata: endpointMetadata
287
- });
288
- // Metadata conflicts tidak mengaktifkan hasConflicts untuk processor
289
- }
290
-
291
- // 4. Check system-level conflicts
255
+ // 3. Check system-level conflicts
292
256
  const systemConflict = this.checkSystemConflicts(moduleName, endpointName);
293
257
  if (systemConflict) {
294
258
  conflicts.systemConflicts.push(systemConflict);
295
259
  conflicts.hasConflicts = true;
296
260
  }
297
261
 
298
- // 5. Add summary details
262
+ // 4. Add summary details
299
263
  conflicts.details = {
300
264
  moduleName: moduleName,
301
265
  endpointName: endpointName,
302
- totalConflicts: conflicts.fileConflicts.length + conflicts.metadataConflicts.length + conflicts.systemConflicts.length,
266
+ totalConflicts: conflicts.fileConflicts.length + conflicts.systemConflicts.length,
303
267
  totalFiles: conflicts.fileConflicts.length,
304
268
  endpointFiles: conflicts.fileConflicts.filter(f => f.type === 'endpointFile').length,
305
269
  processorFiles: conflicts.fileConflicts.filter(f => f.type === 'processorFile').length,
306
- metadataFiles: conflicts.metadataConflicts.length,
307
270
  systemIssues: conflicts.systemConflicts.length,
308
271
  riskLevel: this.assessRiskLevel(conflicts)
309
272
  };
@@ -344,29 +307,18 @@ class ConflictChecker {
344
307
  }
345
308
  }
346
309
 
347
- // 2. Check metadata conflicts
348
- if (MetadataManager.endpointExists(moduleName, endpointName)) {
349
- const endpointMetadata = MetadataManager.getEndpointMetadata(moduleName, endpointName);
350
- conflicts.metadataConflicts.push({
351
- type: 'endpoint_metadata',
352
- endpointName: endpointName,
353
- metadata: endpointMetadata
354
- });
355
- conflicts.hasConflicts = true;
356
- }
357
-
358
- // 3. Check system conflicts (reserved names, etc)
310
+ // 2. Check system conflicts (reserved names, etc)
359
311
  const systemConflict = this.checkSystemConflicts(moduleName, endpointName);
360
312
  if (systemConflict) {
361
313
  conflicts.systemConflicts.push(systemConflict);
362
314
  conflicts.hasConflicts = true;
363
315
  }
364
316
 
365
- // 4. Collect detailed information
317
+ // 3. Collect detailed information
366
318
  conflicts.details = {
367
319
  moduleName: moduleName,
368
320
  endpointName: endpointName,
369
- totalConflicts: conflicts.fileConflicts.length + conflicts.metadataConflicts.length + conflicts.systemConflicts.length,
321
+ totalConflicts: conflicts.fileConflicts.length + conflicts.systemConflicts.length,
370
322
  riskLevel: this.assessRiskLevel(conflicts)
371
323
  };
372
324
 
@@ -1257,6 +1257,90 @@ class DatabaseIntrospector {
1257
1257
  }
1258
1258
  }
1259
1259
 
1260
+ /**
1261
+ * Describe kolom output dari arbitrary SELECT query tanpa mengkonsumsi row.
1262
+ * Pendekatan: wrap query dalam subquery `WHERE false LIMIT 0` agar DB engine
1263
+ * tetap resolve column metadata (alias, JOIN, subquery) tanpa execute baris.
1264
+ *
1265
+ * Dipakai oleh schema-diff untuk extract kolom dari viewQuery/datatablesQuery/
1266
+ * exportQuery, sehingga JOIN field (mis. `category_name`) bisa di-treat sebagai
1267
+ * valid column saat drift check terhadap `fieldName`.
1268
+ *
1269
+ * @param {string} sql - SELECT statement
1270
+ * @returns {Promise<{ok: boolean, columns?: string[], error?: {code: string, message: string}}>}
1271
+ */
1272
+ async describeQueryColumns(sql) {
1273
+ if (!this.pool) {
1274
+ throw new Error('Database not connected');
1275
+ }
1276
+
1277
+ const trimmed = (sql || '').trim().replace(/;+\s*$/, '');
1278
+ if (!trimmed) {
1279
+ return { ok: false, error: { code: 'empty_sql', message: 'SQL query is empty' } };
1280
+ }
1281
+
1282
+ switch (this.dbType) {
1283
+ case 'postgresql': {
1284
+ const wrapped = `SELECT * FROM (${trimmed}) _describe WHERE false`;
1285
+ try {
1286
+ const result = await this.pool.query(wrapped);
1287
+ const columns = (result.fields || []).map(f => String(f.name).toLowerCase());
1288
+ return { ok: true, columns };
1289
+ } catch (err) {
1290
+ return {
1291
+ ok: false,
1292
+ error: {
1293
+ code: err.code || 'unknown',
1294
+ message: err.message
1295
+ }
1296
+ };
1297
+ }
1298
+ }
1299
+
1300
+ case 'mysql': {
1301
+ const wrapped = `SELECT * FROM (${trimmed}) _describe WHERE 1=0`;
1302
+ try {
1303
+ const [, fields] = await this.pool.query(wrapped);
1304
+ const columns = (fields || []).map(f => String(f.name).toLowerCase());
1305
+ return { ok: true, columns };
1306
+ } catch (err) {
1307
+ return {
1308
+ ok: false,
1309
+ error: {
1310
+ code: err.code || (err.errno ? String(err.errno) : 'unknown'),
1311
+ message: err.sqlMessage || err.message
1312
+ }
1313
+ };
1314
+ }
1315
+ }
1316
+
1317
+ case 'oracle': {
1318
+ const wrapped = `SELECT * FROM (${trimmed}) _describe WHERE 1=0`;
1319
+ const conn = await this.pool.getConnection();
1320
+ try {
1321
+ const result = await conn.execute(wrapped, [], { maxRows: 0 });
1322
+ const columns = (result.metaData || []).map(m => String(m.name).toLowerCase());
1323
+ return { ok: true, columns };
1324
+ } catch (err) {
1325
+ return {
1326
+ ok: false,
1327
+ error: {
1328
+ code: err.errorNum
1329
+ ? `ORA-${String(err.errorNum).padStart(5, '0')}`
1330
+ : 'unknown',
1331
+ message: err.message
1332
+ }
1333
+ };
1334
+ } finally {
1335
+ try { await conn.close(); } catch (e) { /* ignore */ }
1336
+ }
1337
+ }
1338
+
1339
+ default:
1340
+ throw new Error(`Unsupported DB_TYPE: ${this.dbType}`);
1341
+ }
1342
+ }
1343
+
1260
1344
  async validateQuery(sql) {
1261
1345
  if (!this.pool) {
1262
1346
  throw new Error('Database not connected');
@@ -210,165 +210,6 @@ class FileUtils {
210
210
  .toLowerCase();
211
211
  }
212
212
 
213
- /**
214
- * Menyalin file SQL dari array file references ke folder model (untuk preserve mode)
215
- * @param {Array} filesToCopy - Array file references (format: file:path)
216
- * @param {string} payloadDir - Directory dimana payload berada
217
- * @param {string} moduleName - Nama module
218
- * @returns {Array} Array file yang berhasil disalin
219
- */
220
- static copyQueryFiles(filesToCopy, payloadDir, moduleName) {
221
- const workingDir = ConfigReader.getWorkingDirectory();
222
- const modelQueryDir = path.join(workingDir, 'src', 'models', moduleName, 'query');
223
-
224
- // Pastikan direktori query ada
225
- this.ensureDirectoryExists(modelQueryDir);
226
-
227
- const copyResults = [];
228
-
229
- for (const fileReference of filesToCopy) {
230
- try {
231
- // Parse file reference
232
- const relativePath = fileReference.replace('file:', '');
233
- const sourceFilePath = path.join(payloadDir, relativePath);
234
- const fileName = path.basename(relativePath);
235
- const destFilePath = path.join(modelQueryDir, fileName);
236
-
237
- console.log(`Copying SQL file: ${relativePath} -> query/${fileName}`);
238
-
239
- // Validasi source file exists
240
- if (!fs.existsSync(sourceFilePath)) {
241
- console.error(`Source file not found: ${sourceFilePath}`);
242
- continue;
243
- }
244
-
245
- // Copy file
246
- fs.copyFileSync(sourceFilePath, destFilePath);
247
-
248
- // Validasi hasil copy
249
- if (!fs.existsSync(destFilePath)) {
250
- console.error(`Failed to copy file: ${fileName}`);
251
- continue;
252
- }
253
-
254
- const destStats = fs.statSync(destFilePath);
255
- console.log(`SQL file copied: ${fileName} (${destStats.size} bytes)`);
256
-
257
- copyResults.push({
258
- source: sourceFilePath,
259
- dest: destFilePath,
260
- fileName: fileName,
261
- size: destStats.size
262
- });
263
-
264
- } catch (error) {
265
- console.error(`Error copying file ${fileReference}:`, error.message);
266
- }
267
- }
268
-
269
- console.log(`Successfully copied ${copyResults.length} of ${filesToCopy.length} SQL files`);
270
- return copyResults;
271
- }
272
-
273
- /**
274
- * Menyalin file SQL ke folder model (khusus untuk Node.js mode) - LEGACY METHOD
275
- * @param {string} moduleName - Nama module
276
- * @param {string} endpointName - Nama endpoint
277
- * @param {Object} payload - Payload object
278
- * @returns {Array} Array file yang berhasil disalin
279
- */
280
- static copyQueryFilesLegacy(moduleName, endpointName, payload) {
281
- const isPkg = ConfigReader.isPkg;
282
-
283
- if (isPkg) {
284
- // Dalam PKG mode, skip file copying karena file sudah di-bundle
285
- console.log('🎁 PKG mode: Skip copying SQL files (assumed to be bundled)');
286
- return [];
287
- }
288
-
289
- console.log('Processing SQL file copying in Node.js mode...');
290
-
291
- const workingDir = ConfigReader.getWorkingDirectory();
292
- const modelQueryDir = path.join(workingDir, 'src', 'models', moduleName, 'query');
293
-
294
- // Pastikan direktori query ada
295
- this.ensureDirectoryExists(modelQueryDir);
296
-
297
- const neededFiles = [];
298
-
299
- // Proses advancedQueries jika ada
300
- if (payload.advancedQueries && typeof payload.advancedQueries === 'object') {
301
- for (const [queryName, querySource] of Object.entries(payload.advancedQueries)) {
302
- if (typeof querySource === 'string' && querySource.startsWith('file:')) {
303
- const fileInfo = this.prepareFileForCopy(
304
- querySource,
305
- queryName,
306
- 'advancedQuery',
307
- modelQueryDir
308
- );
309
- if (fileInfo) {
310
- neededFiles.push(fileInfo);
311
- }
312
- }
313
- }
314
- }
315
-
316
- // Proses nestedQueries jika ada
317
- if (payload.nestedQueries && Array.isArray(payload.nestedQueries)) {
318
- for (const nestedQuery of payload.nestedQueries) {
319
- if (nestedQuery.query && typeof nestedQuery.query === 'string' && nestedQuery.query.startsWith('file:')) {
320
- const fileInfo = this.prepareFileForCopy(
321
- nestedQuery.query,
322
- nestedQuery.name || 'nested',
323
- 'nestedQuery',
324
- modelQueryDir
325
- );
326
- if (fileInfo) {
327
- neededFiles.push(fileInfo);
328
- }
329
- }
330
- }
331
- }
332
-
333
- // Proses datatablesQuery - cek original payload untuk file reference
334
- if (payload.datatablesQuery && typeof payload.datatablesQuery === 'string' && payload.datatablesQuery.startsWith('file:')) {
335
- const fileInfo = this.prepareFileForCopy(
336
- payload.datatablesQuery,
337
- 'datatables',
338
- 'datatablesQuery',
339
- modelQueryDir
340
- );
341
- if (fileInfo) {
342
- neededFiles.push(fileInfo);
343
- }
344
- } else if (payload._originalDataTablesQuery && typeof payload._originalDataTablesQuery === 'string' && payload._originalDataTablesQuery.startsWith('file:')) {
345
- // Fallback untuk payload yang sudah di-expand tapi masih punya original reference
346
- const fileInfo = this.prepareFileForCopy(
347
- payload._originalDataTablesQuery,
348
- 'datatables',
349
- 'datatablesQuery',
350
- modelQueryDir
351
- );
352
- if (fileInfo) {
353
- neededFiles.push(fileInfo);
354
- }
355
- }
356
-
357
- // Salin semua file yang dibutuhkan
358
- const copyResult = this.executeBulkFileCopy(neededFiles);
359
-
360
- console.log(`Total ${copyResult.success} of ${neededFiles.length} SQL files copied successfully`);
361
-
362
- if (copyResult.failed > 0) {
363
- console.warn(`${copyResult.failed} files failed to copy`);
364
- copyResult.errors.forEach(error => {
365
- console.error(` ${error.file}: ${error.message}`);
366
- });
367
- }
368
-
369
- return copyResult.successFiles;
370
- }
371
-
372
213
  /**
373
214
  * Prepare file information untuk copy operation
374
215
  * @param {string} querySource - Source query dengan format file:path
@@ -41,15 +41,7 @@ class PayloadProcessor {
41
41
  */
42
42
  static processFileReferences(payload, payloadPath, options = {}) {
43
43
  const isPkg = ConfigReader.isPkg;
44
-
45
- // Jika preserveFileReferences = true, skip expansion tapi tetap copy file
46
- if (options.preserveFileReferences) {
47
- console.log('Preserving file references mode: Files will be copied but references preserved');
48
- // Copy file query tetap dilakukan di preserveFileReferences mode (baik JS maupun PKG)
49
- this.copyQueryFilesForPreserveMode(payload, payloadPath, options);
50
- return payload;
51
- }
52
-
44
+
53
45
  if (isPkg) {
54
46
  console.log('Compiled binary mode: Skipping file reference processing (files assumed bundled)');
55
47
  return payload;
@@ -80,6 +72,26 @@ class PayloadProcessor {
80
72
  );
81
73
  }
82
74
 
75
+ // Process masterDetail.detailConfig.detailQuery (digunakan oleh readComposite)
76
+ if (
77
+ processedPayload.masterDetail &&
78
+ processedPayload.masterDetail.detailConfig &&
79
+ this.isFileReference(processedPayload.masterDetail.detailConfig.detailQuery)
80
+ ) {
81
+ processedPayload.masterDetail = {
82
+ ...processedPayload.masterDetail,
83
+ detailConfig: {
84
+ ...processedPayload.masterDetail.detailConfig,
85
+ detailQuery: this.loadSqlFile(
86
+ processedPayload.masterDetail.detailConfig.detailQuery,
87
+ payloadDir,
88
+ 'masterDetail.detailConfig.detailQuery',
89
+ options
90
+ )
91
+ }
92
+ };
93
+ }
94
+
83
95
  // Process advancedQueries
84
96
  if (processedPayload.advancedQueries && typeof processedPayload.advancedQueries === 'object') {
85
97
  processedPayload.advancedQueries = this.processAdvancedQueries(
@@ -880,109 +892,6 @@ class PayloadProcessor {
880
892
  return count;
881
893
  }
882
894
 
883
- /**
884
- * Copy query files untuk preserve mode (baik JS maupun PKG)
885
- * @param {Object} payload - Payload object
886
- * @param {string} payloadPath - Path file payload
887
- * @param {Object} options - Options dengan moduleName dan targetDir
888
- */
889
- static copyQueryFilesForPreserveMode(payload, payloadPath, options = {}) {
890
- const FileUtils = require('./file-utils');
891
- const path = require('path');
892
-
893
- if (!options.moduleName) {
894
- console.warn('moduleName not available, skipping file copying');
895
- return;
896
- }
897
-
898
- const payloadDir = path.dirname(payloadPath);
899
- const filesToCopy = this.collectFileReferences(payload);
900
-
901
- if (filesToCopy.length === 0) {
902
- console.log('No file references found to copy');
903
- return;
904
- }
905
-
906
- console.log(`Copying ${filesToCopy.length} query files for module: ${options.moduleName}`);
907
-
908
- // Copy files menggunakan FileUtils
909
- try {
910
- FileUtils.copyQueryFiles(filesToCopy, payloadDir, options.moduleName);
911
- console.log(`Query files copied successfully for ${options.moduleName}`);
912
- } catch (error) {
913
- console.error(`Error copying query files: ${error.message}`);
914
- throw error;
915
- }
916
- }
917
-
918
- /**
919
- * Collect semua file references dari payload
920
- * @param {Object} payload - Payload object
921
- * @returns {Array} Array of file references
922
- */
923
- static collectFileReferences(payload) {
924
- const fileReferences = [];
925
-
926
- // Check datatablesQuery
927
- if (payload.datatablesQuery && this.isFileReference(payload.datatablesQuery)) {
928
- fileReferences.push(payload.datatablesQuery);
929
- }
930
-
931
- // Check viewQuery
932
- if (payload.viewQuery && this.isFileReference(payload.viewQuery)) {
933
- fileReferences.push(payload.viewQuery);
934
- }
935
-
936
- // Check advancedQueries
937
- if (payload.advancedQueries && typeof payload.advancedQueries === 'object') {
938
- for (const query of Object.values(payload.advancedQueries)) {
939
- if (this.isFileReference(query)) {
940
- fileReferences.push(query);
941
- }
942
- }
943
- }
944
-
945
- // Check nestedQueries
946
- if (payload.nestedQueries && Array.isArray(payload.nestedQueries)) {
947
- for (const nested of payload.nestedQueries) {
948
- if (nested.query && this.isFileReference(nested.query)) {
949
- fileReferences.push(nested.query);
950
- }
951
- }
952
- }
953
-
954
- // Check masterDetail.detailConfig.detailQuery (digunakan oleh readComposite)
955
- if (
956
- payload.masterDetail &&
957
- payload.masterDetail.detailConfig &&
958
- typeof payload.masterDetail.detailConfig.detailQuery === 'string' &&
959
- this.isFileReference(payload.masterDetail.detailConfig.detailQuery)
960
- ) {
961
- fileReferences.push(payload.masterDetail.detailConfig.detailQuery);
962
- }
963
-
964
- // Check customQueries
965
- if (payload.customQueries && typeof payload.customQueries === 'object') {
966
- for (const queries of Object.values(payload.customQueries)) {
967
- if (Array.isArray(queries)) {
968
- for (const query of queries) {
969
- if (typeof query === 'object' && query.query && this.isFileReference(query.query)) {
970
- fileReferences.push(query.query);
971
- }
972
- }
973
- } else if (typeof queries === 'object') {
974
- for (const subQuery of Object.values(queries)) {
975
- if (this.isFileReference(subQuery)) {
976
- fileReferences.push(subQuery);
977
- }
978
- }
979
- }
980
- }
981
- }
982
-
983
- // Remove duplicates
984
- return [...new Set(fileReferences)];
985
- }
986
895
  }
987
896
 
988
897
  module.exports = PayloadProcessor;
@@ -1,27 +1,27 @@
1
1
  {
2
- "version": "4.3.1",
3
- "generated": "2026-05-23T07:28:02.234Z",
2
+ "version": "4.3.4",
3
+ "generated": "2026-05-24T08:55:59.215Z",
4
4
  "generator": "restforge-build-system",
5
5
  "algorithm": "sha256",
6
6
  "files": {
7
- "server.js": "2ef2e146c66d74df2413398fa86944396ca20c310606237d2819eea504a3692c",
8
- "src/utils/license-client.js": "5842a6fefa0ef4035cbd7ec1cac2ba65a6918e7faa1afa38812b2bb6e5be93b0",
9
- "src/utils/trusted-keys.js": "2440fca5a73a633d9b37a2df2e740a8a00e131ecbabb05700cb6969cdf868da1",
10
- "cli/consumer.js": "fcadb7f7c5b4c09c328ffb1ae882df823f5046d1a0c9ec61d25142bcca262663",
11
- "src/utils/security-checks.js": "ca6d75ee3c20051f4931bd28d2ab12f0f5892e8d74e223bdac3038731979f557",
12
- "scripts/verify-integrity.js": "bcd4ab356a196676235ffc81ab086b6fa7204e2720549f58006054f8cf7aafd3",
7
+ "server.js": "a541483503b66baa6e0469b0f8e73f0e70fe88b2d6a57c6994d04c68507a2690",
8
+ "src/utils/license-client.js": "03046d6e1a996f315ae22cec97609f09baef51d02386e489ea129cbf60443cd6",
9
+ "src/utils/trusted-keys.js": "416fc5be0a3bae7ef2182ddc75729be9765925ff82c9537353094983b68b7227",
10
+ "cli/consumer.js": "76513a635092c822144fc30a387386231de168df8955da3726fcdfc271779ea3",
11
+ "src/utils/security-checks.js": "56f14123951dc6a2bba07f2895b2c999d639c3075e5313635173c2900f88f407",
12
+ "scripts/verify-integrity.js": "2ad808831357c4e3b3b6efd178c9e4aeadadab6cd43290c28fa3f4aa9c533a07",
13
13
  "bin/restforge-hwinfo-linux": "d9a0071b0acf58a020e738a29837de356f531a5a84d363a2adc50563e3874b8f",
14
14
  "bin/restforge-hwinfo-darwin": "d35b15d4e6d7bbdd8317490335ba9602ce5c218519898fa3eabe18cc9c5bb1b6",
15
15
  "bin/restforge-hwinfo.exe": "351fa4d33459d30de804ee78deb5eb977b77b688fe1b7b461cdaa214a82f145e",
16
- "generators/lib/templates/mysql-template.js": "f0328973fb28dd1d01f314e1328d817aed4fde9243f8c9896f950cb57a3fcffb",
17
- "generators/lib/templates/oracle-template.js": "58f3a1cff3fbcffc39ae6cacb72a6c88a8434e8c33b8ae7463806095c84cf1b3",
18
- "generators/lib/templates/postgres-template.js": "d339fd5f0ce260233e3c80831a637dd8d27e4f4ca72aa39a3cd6946f4bd9886e",
19
- "generators/lib/templates/sqlite-template.js": "778b0e44514694e3e1a4e0a4ce5d9b6bb2e4f716e4769331a723dd9ad0b250e4",
20
- "generators/lib/templates/dashboard-catalog.js": "7ab933e347c60eff7359ca621cd3f40d493641bcb25870d4150a9dbf740c2105",
21
- "generators/lib/templates/dbschema-catalog.js": "779388a04c512ec24f8f7822b4d8feb3c20ad8d70787a3dc3478ece1df823daf",
22
- "generators/lib/templates/field-validation-catalog.js": "85f925cfe158ce6c00f98dcecbcdf7c45971c5ec64d694b7707f784bdd1a650c",
23
- "generators/lib/templates/query-declarative-catalog.js": "d60fb26d9336e0aa2913d94d14b79a0934ed8cc848013bbd6d77a5cdda32bf9f",
24
- "generators/lib/templates/db-connection-env.js": "85cd3f5b68121294b32fc706b4578ba7581e1e1f8399eee2e656ab1dadb5adcf"
16
+ "generators/lib/templates/mysql-template.js": "8fd769a6f95221304dce32fa290ab277814d8295714d5ca14ec0db236627c7eb",
17
+ "generators/lib/templates/oracle-template.js": "ed34df2f73cced76a9ac354f7f2634f327caa9c6bf3cfc34e04452ecf750eb8c",
18
+ "generators/lib/templates/postgres-template.js": "222e43e24c3dc1c3689104e4ec9ad66ade134f312990ac358ad5078c93833835",
19
+ "generators/lib/templates/sqlite-template.js": "bc96cfb1bb4a296e909b10e848d7937ac27c81d0bc8ea486337ef06dc1577414",
20
+ "generators/lib/templates/dashboard-catalog.js": "8187cd98803de8dfab3a4ddd90ec25cf19b5d5b6dbe47302b56dbe63e5f259b0",
21
+ "generators/lib/templates/dbschema-catalog.js": "327e8d5244759d628a7ecf04cee961d728834784466801a83b154b7dac374abc",
22
+ "generators/lib/templates/field-validation-catalog.js": "79d2ad274531a307b09c5fc549d90807c97a7eb2b03a179354a29e8218b1fc8e",
23
+ "generators/lib/templates/query-declarative-catalog.js": "488726e976d6a4dd7e0d1e14fb8daea8b666391eb2424e75682a418f62c55b68",
24
+ "generators/lib/templates/db-connection-env.js": "e2cc385a4fa8d7a4332ed47e21509e401d88ddb7104295a6c2e54b17f55f7382"
25
25
  },
26
26
  "stats": {
27
27
  "totalFiles": 18,
@@ -31,7 +31,7 @@
31
31
  "signature": {
32
32
  "algorithm": "ed25519",
33
33
  "keyId": "rfs-manifest-2026-05",
34
- "value": "340f2df9ae9c75e0c51cee4be5dd7ac0ccc4a3daedc2fa732a24bbe9b4d3e35d7215358ca313d5dcbdd03b08bdd6242ed7e9f701907aad2fb2f91acf9cb92009",
34
+ "value": "5c3fc721c306b53950d2cdf0d0407a163eb334ec41b1c954ddc3af428385277dd2bfe6e2da3cffeebee3a82c082fcc18d0c858c743a3e1898684bd4e3d7b700d",
35
35
  "scope": "canonical-json(manifest-without-signature)"
36
36
  }
37
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@restforgejs/platform",
3
- "version": "4.3.1",
3
+ "version": "4.3.4",
4
4
  "description": "RESTForge Platform — Schema-driven backend framework and code generator for full-stack Node.js applications. Generates production backend APIs with multi-database support (PostgreSQL, MySQL, Oracle). A platform builder and backend runtime, not an API testing or client tool.",
5
5
  "main": "server.js",
6
6
  "bin": {