@restforgejs/platform 4.3.2 → 4.3.5

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 (178) 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 +181 -171
  8. package/generators/lib/payload/payload-runner.js +1218 -1218
  9. package/generators/lib/payload/schema-diff.js +460 -277
  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/node_modules/readdir-glob/node_modules/brace-expansion/index.js +1 -1
  25. package/node_modules/readdir-glob/node_modules/brace-expansion/package.json +1 -1
  26. package/package.json +1 -1
  27. package/scripts/verify-integrity.js +1 -1
  28. package/server.js +1 -1
  29. package/src/components/handlers/adjust_handler.js +1 -1
  30. package/src/components/handlers/audit_handler.js +1 -1
  31. package/src/components/handlers/delete_handler.js +1 -1
  32. package/src/components/handlers/export_handler.js +1 -1
  33. package/src/components/handlers/import_handler.js +1 -1
  34. package/src/components/handlers/insert_handler.js +1 -1
  35. package/src/components/handlers/update_handler.js +1 -1
  36. package/src/components/handlers/upload_handler.js +1 -1
  37. package/src/components/handlers/workflow_handler.js +1 -1
  38. package/src/components/integrations/webhook.js +1 -1
  39. package/src/consumers/baseConsumer.js +1 -1
  40. package/src/consumers/declarativeMapper.js +1 -1
  41. package/src/consumers/handlers/apiHandler.js +1 -1
  42. package/src/consumers/handlers/consoleHandler.js +1 -1
  43. package/src/consumers/handlers/databaseHandler.js +1 -1
  44. package/src/consumers/handlers/index.js +1 -1
  45. package/src/consumers/handlers/kafkaHandler.js +1 -1
  46. package/src/consumers/index.js +1 -1
  47. package/src/consumers/messageTransformer.js +1 -1
  48. package/src/consumers/validator.js +1 -1
  49. package/src/core/db/dialect/base-dialect.js +1 -1
  50. package/src/core/db/dialect/index.js +1 -1
  51. package/src/core/db/dialect/mysql-dialect.js +1 -1
  52. package/src/core/db/dialect/oracle-dialect.js +1 -1
  53. package/src/core/db/dialect/postgres-dialect.js +1 -1
  54. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  55. package/src/core/db/flatten-helper.js +1 -1
  56. package/src/core/db/query-builder-error.js +1 -1
  57. package/src/core/db/query-builder.js +1 -1
  58. package/src/core/db/relation-helper.js +1 -1
  59. package/src/core/handlers/delete_handler.js +1 -1
  60. package/src/core/handlers/insert_handler.js +1 -1
  61. package/src/core/handlers/update_handler.js +1 -1
  62. package/src/core/models/base-model.js +1 -1
  63. package/src/core/utils/cache-manager.js +1 -1
  64. package/src/core/utils/component-engine.js +1 -1
  65. package/src/core/utils/context-builder.js +1 -1
  66. package/src/core/utils/datetime-formatter.js +1 -1
  67. package/src/core/utils/datetime-parser.js +1 -1
  68. package/src/core/utils/db.js +1 -1
  69. package/src/core/utils/logger.js +1 -1
  70. package/src/core/utils/payload-loader.js +1 -1
  71. package/src/core/utils/security-checks.js +1 -1
  72. package/src/middleware/body-options.js +1 -1
  73. package/src/middleware/cors.js +1 -1
  74. package/src/middleware/idempotency.js +1 -1
  75. package/src/middleware/rate-limiter.js +1 -1
  76. package/src/middleware/request-logger.js +1 -1
  77. package/src/middleware/security-headers.js +1 -1
  78. package/src/models/base-model-mysql.js +1 -1
  79. package/src/models/base-model-oracle.js +1 -1
  80. package/src/models/base-model-sqlite.js +1 -1
  81. package/src/models/base-model.js +1 -1
  82. package/src/pro/caching/redis-client.js +1 -1
  83. package/src/pro/caching/redis-helper.js +1 -1
  84. package/src/pro/consumers/baseConsumer.js +1 -1
  85. package/src/pro/consumers/declarativeMapper.js +1 -1
  86. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  87. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  88. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  89. package/src/pro/consumers/handlers/index.js +1 -1
  90. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  91. package/src/pro/consumers/index.js +1 -1
  92. package/src/pro/consumers/messageTransformer.js +1 -1
  93. package/src/pro/consumers/validator.js +1 -1
  94. package/src/pro/database/base-model-mysql.js +1 -1
  95. package/src/pro/database/base-model-oracle.js +1 -1
  96. package/src/pro/database/base-model-sqlite.js +1 -1
  97. package/src/pro/database/db-mysql.js +1 -1
  98. package/src/pro/database/db-oracle.js +1 -1
  99. package/src/pro/database/db-sqlite.js +1 -1
  100. package/src/pro/excel/excel-generator.js +1 -1
  101. package/src/pro/excel/excel-parser.js +1 -1
  102. package/src/pro/excel/export-service.js +1 -1
  103. package/src/pro/excel/export_handler.js +1 -1
  104. package/src/pro/excel/import-service.js +1 -1
  105. package/src/pro/excel/import-validator.js +1 -1
  106. package/src/pro/excel/import_handler.js +1 -1
  107. package/src/pro/excel/upsert-builder.js +1 -1
  108. package/src/pro/idgen/idgen-routes.js +1 -1
  109. package/src/pro/integrations/lookup-resolver.js +1 -1
  110. package/src/pro/integrations/upload-handler-v2.js +1 -1
  111. package/src/pro/integrations/upload-handler.js +1 -1
  112. package/src/pro/integrations/webhook.js +1 -1
  113. package/src/pro/locking/lock-routes.js +1 -1
  114. package/src/pro/locking/resource-lock-manager.js +1 -1
  115. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  116. package/src/pro/messaging/kafkaService.js +1 -1
  117. package/src/pro/messaging/messagehubService.js +1 -1
  118. package/src/pro/messaging/rabbitmqService.js +1 -1
  119. package/src/pro/scheduler/job-manager.js +1 -1
  120. package/src/pro/scheduler/job-routes.js +1 -1
  121. package/src/pro/scheduler/job-validator.js +1 -1
  122. package/src/pro/storage/base-storage-provider.js +1 -1
  123. package/src/pro/storage/file-metadata-helper.js +1 -1
  124. package/src/pro/storage/index.js +1 -1
  125. package/src/pro/storage/local-storage-provider.js +1 -1
  126. package/src/pro/storage/s3-storage-provider.js +1 -1
  127. package/src/pro/storage/upload-cleanup-job.js +1 -1
  128. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  129. package/src/pro/storage/upload-pending-tracker.js +1 -1
  130. package/src/pro/websocket/broadcast-helper.js +1 -1
  131. package/src/pro/websocket/index.js +1 -1
  132. package/src/pro/websocket/livesync-server.js +1 -1
  133. package/src/pro/websocket/ws-broadcaster.js +1 -1
  134. package/src/services/export-service.js +1 -1
  135. package/src/services/import-service.js +1 -1
  136. package/src/services/kafkaConsumerService.js +1 -1
  137. package/src/services/kafkaService.js +1 -1
  138. package/src/services/messagehubService.js +1 -1
  139. package/src/services/rabbitmqService.js +1 -1
  140. package/src/utils/cache-invalidation-registry.js +1 -1
  141. package/src/utils/cache-manager.js +1 -1
  142. package/src/utils/component-engine.js +1 -1
  143. package/src/utils/config-extractor.js +1 -1
  144. package/src/utils/consumerLogger.js +1 -1
  145. package/src/utils/context-builder.js +1 -1
  146. package/src/utils/dashboard-helpers.js +1 -1
  147. package/src/utils/dateHelper.js +1 -1
  148. package/src/utils/datetime-formatter.js +1 -1
  149. package/src/utils/datetime-parser.js +1 -1
  150. package/src/utils/db-bootstrap.js +1 -1
  151. package/src/utils/db-mysql.js +1 -1
  152. package/src/utils/db-oracle.js +1 -1
  153. package/src/utils/db-sqlite.js +1 -1
  154. package/src/utils/db.js +1 -1
  155. package/src/utils/demo-generator.js +1 -1
  156. package/src/utils/excel-generator.js +1 -1
  157. package/src/utils/excel-parser.js +1 -1
  158. package/src/utils/file-watcher.js +1 -1
  159. package/src/utils/id-generator.js +1 -1
  160. package/src/utils/idempotency-manager.js +1 -1
  161. package/src/utils/import-validator.js +1 -1
  162. package/src/utils/license-client.js +1 -1
  163. package/src/utils/lock-manager.js +1 -1
  164. package/src/utils/logger.js +1 -1
  165. package/src/utils/lookup-resolver.js +1 -1
  166. package/src/utils/payload-loader.js +1 -1
  167. package/src/utils/processor-response.js +1 -1
  168. package/src/utils/rabbitmq.js +1 -1
  169. package/src/utils/redis-client.js +1 -1
  170. package/src/utils/redis-helper.js +1 -1
  171. package/src/utils/request-scope.js +1 -1
  172. package/src/utils/security-checks.js +1 -1
  173. package/src/utils/service-resolver.js +1 -1
  174. package/src/utils/shutdown-coordinator.js +1 -1
  175. package/src/utils/trusted-keys.js +1 -1
  176. package/src/utils/upload-handler.js +1 -1
  177. package/src/utils/upsert-builder.js +1 -1
  178. package/src/utils/workflow-hook-executor.js +1 -1
@@ -34,7 +34,7 @@ class ModelGenerator {
34
34
  return false;
35
35
  }
36
36
 
37
- // Note: SQL file copying sudah ditangani di PayloadProcessor.copyQueryFilesForPreserveMode
37
+ // Note: SQL file references di-expand inline ke output model oleh PayloadProcessor.processFileReferences
38
38
 
39
39
  // Generate model content
40
40
  const modelContent = this.generateModelContent(moduleName, endpointName, processedPayload, databaseType);
@@ -1,171 +1,181 @@
1
- 'use strict';
2
-
3
- /**
4
- * Endpoint Schema Validator
5
- *
6
- * Orchestrator untuk validasi schema database saat `endpoint create` dijalankan.
7
- * Module ini:
8
- * 1. Resolve --config file (via config-resolver)
9
- * 2. Load config + connect ke database (via DatabaseIntrospector)
10
- * 3. Compare payload-vs-database menggunakan compareSchemaStrict
11
- * 4. Map hasil ke exit-code semantics:
12
- * - clean schema -> return { status: 'ok' }
13
- * - drift detected -> throw error dengan exitCode=1 + formatted report
14
- * - connection fail -> throw error dengan exitCode=3
15
- * - usage error -> throw error dengan exitCode=2 (di-handle caller via validateContract)
16
- *
17
- * Module ini sengaja decoupled dari PayloadGenerator agar tidak ikut menjalankan
18
- * payload regenerate/sync flow.
19
- *
20
- * @module lib/payload/endpoint-schema-validator
21
- */
22
-
23
- const { DatabaseIntrospector } = require('../utils/database-introspector');
24
- const { resolveConfig, printDefaultConfigWarning } = require('../utils/config-resolver');
25
- const { compareSchemaStrict, formatDriftReport } = require('./schema-diff');
26
-
27
- /**
28
- * Buat Error object dengan property `exitCode` agar cli-entry dapat
29
- * forward exit code spesifik.
30
- *
31
- * @param {string} message
32
- * @param {number} exitCode
33
- * @returns {Error}
34
- */
35
- function createExitError(message, exitCode) {
36
- const err = new Error(message);
37
- err.exitCode = exitCode;
38
- err.isSchemaValidationError = true;
39
- return err;
40
- }
41
-
42
- /**
43
- * Jalankan validasi schema untuk satu payload + table sebelum codegen.
44
- *
45
- * @param {Object} options
46
- * @param {Object} options.payload - Processed payload object (harus punya tableName)
47
- * @param {string} options.payloadFileName - Nama file payload untuk pesan error
48
- * @param {string} options.configArg - Nilai flag --config dari CLI
49
- * @param {boolean} options.skipSchemaCheck - true bila --skip-schema-check di-set
50
- * @param {string} [options.workingDir] - cwd, default process.cwd()
51
- * @param {Function} [options.IntrospectorClass] - Override untuk testing
52
- * @returns {Promise<{
53
- * status: 'ok' | 'skipped',
54
- * reason?: string,
55
- * columnsChecked?: number
56
- * }>}
57
- * @throws {Error} Dengan property exitCode (1=drift, 2=usage, 3=connection)
58
- */
59
- async function validateEndpointSchema(options) {
60
- const {
61
- payload,
62
- payloadFileName,
63
- configArg,
64
- skipSchemaCheck,
65
- workingDir,
66
- IntrospectorClass
67
- } = options;
68
-
69
- if (!payload || !payload.tableName) {
70
- throw createExitError('Payload missing tableName — cannot run schema validation', 2);
71
- }
72
-
73
- if (skipSchemaCheck) {
74
- return { status: 'skipped', reason: '--skip-schema-check active' };
75
- }
76
-
77
- const resolved = resolveConfig(configArg, workingDir || process.cwd());
78
- if (!resolved) {
79
- const lines = [
80
- 'Error: --config is required for schema validation',
81
- 'Usage: npx restforge endpoint create --project=<P> --name=<N> --payload=<F> --config=<ENV> [--force=true] [--skip-schema-check]'
82
- ];
83
- throw createExitError(lines.join('\n'), 2);
84
- }
85
-
86
- if (resolved.source === 'default') {
87
- printDefaultConfigWarning(resolved.defaultName);
88
- }
89
-
90
- const IntroCtor = IntrospectorClass || DatabaseIntrospector;
91
- const db = new IntroCtor({ quiet: true });
92
-
93
- const loaded = db.loadConfig(resolved.path);
94
- if (!loaded) {
95
- throw createExitError(
96
- buildConnectionErrorMessage(`Cannot load config file: ${resolved.path}`),
97
- 3
98
- );
99
- }
100
-
101
- let connected = false;
102
- try {
103
- connected = await db.connect();
104
- } catch (e) {
105
- try { await db.close(); } catch (_e) { /* ignore */ }
106
- throw createExitError(
107
- buildConnectionErrorMessage(e.message || String(e)),
108
- 3
109
- );
110
- }
111
-
112
- if (!connected) {
113
- try { await db.close(); } catch (_e) { /* ignore */ }
114
- throw createExitError(
115
- buildConnectionErrorMessage('database not reachable'),
116
- 3
117
- );
118
- }
119
-
120
- let comparison;
121
- try {
122
- comparison = await compareSchemaStrict(payload, db);
123
- } finally {
124
- try { await db.close(); } catch (_e) { /* ignore */ }
125
- }
126
-
127
- if (comparison.status === 'error') {
128
- const lines = [
129
- 'Schema Validation:',
130
- ` [ERROR] ${comparison.summary}`,
131
- ' Endpoint generation blocked.',
132
- '',
133
- ' Workarounds:',
134
- ' 1. Verify the table exists in the database',
135
- ' 2. Use --skip-schema-check to bypass validation (NOT recommended for production)'
136
- ];
137
- throw createExitError(lines.join('\n'), 3);
138
- }
139
-
140
- if (comparison.status === 'drift') {
141
- const driftLines = formatDriftReport(comparison, {
142
- payloadFileName,
143
- tableName: payload.tableName
144
- });
145
- const lines = ['Schema Validation:', ...driftLines, '', 'Endpoint generation blocked due to schema drift'];
146
- throw createExitError(lines.join('\n'), 1);
147
- }
148
-
149
- return {
150
- status: 'ok',
151
- columnsChecked: comparison.totalColumnsChecked || 0
152
- };
153
- }
154
-
155
- function buildConnectionErrorMessage(reason) {
156
- const lines = [
157
- 'Schema Validation:',
158
- ` [ERROR] Cannot connect to database: ${reason}`,
159
- ' Endpoint generation blocked.',
160
- '',
161
- ' Workarounds:',
162
- ' 1. Verify db-connection.env is correct and database is reachable',
163
- ' 2. Use --skip-schema-check to bypass validation (NOT recommended for production)'
164
- ];
165
- return lines.join('\n');
166
- }
167
-
168
- module.exports = {
169
- validateEndpointSchema,
170
- createExitError
171
- };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Endpoint Schema Validator
5
+ *
6
+ * Orchestrator untuk validasi schema database saat `endpoint create` dijalankan.
7
+ * Module ini:
8
+ * 1. Resolve --config file (via config-resolver)
9
+ * 2. Load config + connect ke database (via DatabaseIntrospector)
10
+ * 3. Compare payload-vs-database menggunakan compareSchemaStrict
11
+ * 4. Map hasil ke exit-code semantics:
12
+ * - clean schema -> return { status: 'ok' }
13
+ * - drift detected -> throw error dengan exitCode=1 + formatted report
14
+ * - connection fail -> throw error dengan exitCode=3
15
+ * - usage error -> throw error dengan exitCode=2 (di-handle caller via validateContract)
16
+ *
17
+ * Module ini sengaja decoupled dari PayloadGenerator agar tidak ikut menjalankan
18
+ * payload regenerate/sync flow.
19
+ *
20
+ * @module lib/payload/endpoint-schema-validator
21
+ */
22
+
23
+ const path = require('path');
24
+ const { DatabaseIntrospector } = require('../utils/database-introspector');
25
+ const { resolveConfig, printDefaultConfigWarning } = require('../utils/config-resolver');
26
+ const { compareSchemaStrict, formatDriftReport } = require('./schema-diff');
27
+
28
+ /**
29
+ * Buat Error object dengan property `exitCode` agar cli-entry dapat
30
+ * forward exit code spesifik.
31
+ *
32
+ * @param {string} message
33
+ * @param {number} exitCode
34
+ * @returns {Error}
35
+ */
36
+ function createExitError(message, exitCode) {
37
+ const err = new Error(message);
38
+ err.exitCode = exitCode;
39
+ err.isSchemaValidationError = true;
40
+ return err;
41
+ }
42
+
43
+ /**
44
+ * Jalankan validasi schema untuk satu payload + table sebelum codegen.
45
+ *
46
+ * @param {Object} options
47
+ * @param {Object} options.payload - Processed payload object (harus punya tableName)
48
+ * @param {string} options.payloadFileName - Nama file payload untuk pesan error
49
+ * @param {string} [options.payloadFilePath] - Absolute path ke payload file, untuk
50
+ * resolve `file:` reference di viewQuery/datatablesQuery/exportQuery. Jika tidak
51
+ * di-set, JOIN field validation tetap jalan untuk inline SQL tapi `file:` reference
52
+ * akan masuk warning.
53
+ * @param {string} options.configArg - Nilai flag --config dari CLI
54
+ * @param {boolean} options.skipSchemaCheck - true bila --skip-schema-check di-set
55
+ * @param {string} [options.workingDir] - cwd, default process.cwd()
56
+ * @param {Function} [options.IntrospectorClass] - Override untuk testing
57
+ * @returns {Promise<{
58
+ * status: 'ok' | 'skipped',
59
+ * reason?: string,
60
+ * columnsChecked?: number
61
+ * }>}
62
+ * @throws {Error} Dengan property exitCode (1=drift, 2=usage, 3=connection)
63
+ */
64
+ async function validateEndpointSchema(options) {
65
+ const {
66
+ payload,
67
+ payloadFileName,
68
+ payloadFilePath,
69
+ configArg,
70
+ skipSchemaCheck,
71
+ workingDir,
72
+ IntrospectorClass
73
+ } = options;
74
+
75
+ if (!payload || !payload.tableName) {
76
+ throw createExitError('Payload missing tableName — cannot run schema validation', 2);
77
+ }
78
+
79
+ if (skipSchemaCheck) {
80
+ return { status: 'skipped', reason: '--skip-schema-check active' };
81
+ }
82
+
83
+ const resolved = resolveConfig(configArg, workingDir || process.cwd());
84
+ if (!resolved) {
85
+ const lines = [
86
+ 'Error: --config is required for schema validation',
87
+ 'Usage: npx restforge endpoint create --project=<P> --name=<N> --payload=<F> --config=<ENV> [--force=true] [--skip-schema-check]'
88
+ ];
89
+ throw createExitError(lines.join('\n'), 2);
90
+ }
91
+
92
+ if (resolved.source === 'default') {
93
+ printDefaultConfigWarning(resolved.defaultName);
94
+ }
95
+
96
+ const IntroCtor = IntrospectorClass || DatabaseIntrospector;
97
+ const db = new IntroCtor({ quiet: true });
98
+
99
+ const loaded = db.loadConfig(resolved.path);
100
+ if (!loaded) {
101
+ throw createExitError(
102
+ buildConnectionErrorMessage(`Cannot load config file: ${resolved.path}`),
103
+ 3
104
+ );
105
+ }
106
+
107
+ let connected = false;
108
+ try {
109
+ connected = await db.connect();
110
+ } catch (e) {
111
+ try { await db.close(); } catch (_e) { /* ignore */ }
112
+ throw createExitError(
113
+ buildConnectionErrorMessage(e.message || String(e)),
114
+ 3
115
+ );
116
+ }
117
+
118
+ if (!connected) {
119
+ try { await db.close(); } catch (_e) { /* ignore */ }
120
+ throw createExitError(
121
+ buildConnectionErrorMessage('database not reachable'),
122
+ 3
123
+ );
124
+ }
125
+
126
+ const payloadDir = payloadFilePath
127
+ ? path.dirname(payloadFilePath)
128
+ : path.join(workingDir || process.cwd(), 'payload');
129
+
130
+ let comparison;
131
+ try {
132
+ comparison = await compareSchemaStrict(payload, db, { payloadDir });
133
+ } finally {
134
+ try { await db.close(); } catch (_e) { /* ignore */ }
135
+ }
136
+
137
+ if (comparison.status === 'error') {
138
+ const lines = [
139
+ 'Schema Validation:',
140
+ ` [ERROR] ${comparison.summary}`,
141
+ ' Endpoint generation blocked.',
142
+ '',
143
+ ' Workarounds:',
144
+ ' 1. Verify the table exists in the database',
145
+ ' 2. Use --skip-schema-check to bypass validation (NOT recommended for production)'
146
+ ];
147
+ throw createExitError(lines.join('\n'), 3);
148
+ }
149
+
150
+ if (comparison.status === 'drift') {
151
+ const driftLines = formatDriftReport(comparison, {
152
+ payloadFileName,
153
+ tableName: payload.tableName
154
+ });
155
+ const lines = ['Schema Validation:', ...driftLines, '', 'Endpoint generation blocked due to schema drift'];
156
+ throw createExitError(lines.join('\n'), 1);
157
+ }
158
+
159
+ return {
160
+ status: 'ok',
161
+ columnsChecked: comparison.totalColumnsChecked || 0
162
+ };
163
+ }
164
+
165
+ function buildConnectionErrorMessage(reason) {
166
+ const lines = [
167
+ 'Schema Validation:',
168
+ ` [ERROR] Cannot connect to database: ${reason}`,
169
+ ' Endpoint generation blocked.',
170
+ '',
171
+ ' Workarounds:',
172
+ ' 1. Verify db-connection.env is correct and database is reachable',
173
+ ' 2. Use --skip-schema-check to bypass validation (NOT recommended for production)'
174
+ ];
175
+ return lines.join('\n');
176
+ }
177
+
178
+ module.exports = {
179
+ validateEndpointSchema,
180
+ createExitError
181
+ };