@restforgejs/platform 5.1.21 → 5.2.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 (214) hide show
  1. package/build-info.json +2 -2
  2. package/cli/consumer-deploy.js +2 -2
  3. package/cli/consumer.js +2 -2
  4. package/generators/cli/catalog/dashboard.js +1 -1
  5. package/generators/cli/catalog/dbschema.js +3 -3
  6. package/generators/cli/catalog/field-validation.js +1 -1
  7. package/generators/cli/catalog/query-declarative.js +1 -1
  8. package/generators/cli/config/clear-default.js +1 -1
  9. package/generators/cli/config/get-default.js +1 -1
  10. package/generators/cli/config/list.js +1 -1
  11. package/generators/cli/config/schema.js +1 -1
  12. package/generators/cli/config/set-default.js +2 -2
  13. package/generators/cli/config/template.js +1 -1
  14. package/generators/cli/dashboard/create.js +7 -7
  15. package/generators/cli/data/pull.js +12 -12
  16. package/generators/cli/data/push.js +9 -9
  17. package/generators/cli/endpoint/create.js +11 -11
  18. package/generators/cli/endpoint/list.js +3 -3
  19. package/generators/cli/fast-track.js +65 -12
  20. package/generators/cli/init.js +2 -2
  21. package/generators/cli/kafka/consumer-create.js +5 -5
  22. package/generators/cli/key/generate.js +3 -3
  23. package/generators/cli/key/list.js +2 -2
  24. package/generators/cli/key/revoke.js +3 -3
  25. package/generators/cli/payload/diff.js +3 -3
  26. package/generators/cli/payload/generate.js +5 -5
  27. package/generators/cli/payload/sync.js +5 -5
  28. package/generators/cli/payload/validate.js +3 -3
  29. package/generators/cli/processor/create.js +7 -7
  30. package/generators/cli/processor/list.js +3 -3
  31. package/generators/cli/project/delete.js +2 -2
  32. package/generators/cli/project/list.js +1 -1
  33. package/generators/cli/query/validate.js +3 -3
  34. package/generators/cli/schema/apply.js +13 -13
  35. package/generators/cli/schema/describe.js +6 -6
  36. package/generators/cli/schema/diff.js +10 -10
  37. package/generators/cli/schema/generate-ddl.js +11 -11
  38. package/generators/cli/schema/init.js +95 -95
  39. package/generators/cli/schema/introspect.js +8 -8
  40. package/generators/cli/schema/list.js +6 -6
  41. package/generators/cli/schema/migrate.js +91 -13
  42. package/generators/cli/schema/models.js +6 -6
  43. package/generators/cli/schema/template.js +223 -222
  44. package/generators/cli/schema/validate.js +6 -6
  45. package/generators/cli/test/generate.js +6 -6
  46. package/generators/lib/dbschema-kit/introspect-mapper.js +20 -0
  47. package/generators/lib/migrate/migrate-runner.js +12 -2
  48. package/generators/lib/migrate/sql-parser.js +5 -3
  49. package/generators/lib/payload/payload-runner.js +31 -5
  50. package/generators/lib/templates/dashboard-catalog.js +1 -1
  51. package/generators/lib/templates/db-connection-env.js +1 -1
  52. package/generators/lib/templates/dbschema-catalog.js +1 -1
  53. package/generators/lib/templates/field-validation-catalog.js +1 -1
  54. package/generators/lib/templates/mysql-template.js +1 -1
  55. package/generators/lib/templates/oracle-template.js +1 -1
  56. package/generators/lib/templates/postgres-template.js +1 -1
  57. package/generators/lib/templates/query-declarative-catalog.js +1 -1
  58. package/generators/lib/templates/sqlite-template.js +1 -1
  59. package/integrity-manifest.json +18 -18
  60. package/package.json +1 -1
  61. package/scripts/verify-integrity.js +1 -1
  62. package/server.js +2 -2
  63. package/src/components/handlers/adjust_handler.js +1 -1
  64. package/src/components/handlers/audit_handler.js +1 -1
  65. package/src/components/handlers/delete_handler.js +1 -1
  66. package/src/components/handlers/export_handler.js +1 -1
  67. package/src/components/handlers/import_handler.js +1 -1
  68. package/src/components/handlers/insert_handler.js +1 -1
  69. package/src/components/handlers/update_handler.js +1 -1
  70. package/src/components/handlers/upload_handler.js +1 -1
  71. package/src/components/handlers/workflow_handler.js +1 -1
  72. package/src/components/integrations/webhook.js +1 -1
  73. package/src/consumers/baseConsumer.js +1 -1
  74. package/src/consumers/declarativeMapper.js +1 -1
  75. package/src/consumers/handlers/apiHandler.js +1 -1
  76. package/src/consumers/handlers/consoleHandler.js +1 -1
  77. package/src/consumers/handlers/databaseHandler.js +1 -1
  78. package/src/consumers/handlers/index.js +1 -1
  79. package/src/consumers/handlers/kafkaHandler.js +1 -1
  80. package/src/consumers/index.js +1 -1
  81. package/src/consumers/messageTransformer.js +1 -1
  82. package/src/consumers/validator.js +1 -1
  83. package/src/core/db/dialect/base-dialect.js +1 -1
  84. package/src/core/db/dialect/index.js +1 -1
  85. package/src/core/db/dialect/mysql-dialect.js +1 -1
  86. package/src/core/db/dialect/oracle-dialect.js +1 -1
  87. package/src/core/db/dialect/postgres-dialect.js +1 -1
  88. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  89. package/src/core/db/flatten-helper.js +1 -1
  90. package/src/core/db/query-builder-error.js +1 -1
  91. package/src/core/db/query-builder.js +1 -1
  92. package/src/core/db/relation-helper.js +1 -1
  93. package/src/core/handlers/delete_handler.js +1 -1
  94. package/src/core/handlers/insert_handler.js +1 -1
  95. package/src/core/handlers/update_handler.js +1 -1
  96. package/src/core/models/base-model.js +1 -1
  97. package/src/core/utils/cache-manager.js +1 -1
  98. package/src/core/utils/component-engine.js +1 -1
  99. package/src/core/utils/context-builder.js +1 -1
  100. package/src/core/utils/datetime-formatter.js +1 -1
  101. package/src/core/utils/datetime-parser.js +1 -1
  102. package/src/core/utils/db.js +1 -1
  103. package/src/core/utils/logger.js +1 -1
  104. package/src/core/utils/payload-loader.js +1 -1
  105. package/src/core/utils/security-checks.js +1 -1
  106. package/src/middleware/body-options.js +1 -1
  107. package/src/middleware/cors.js +1 -1
  108. package/src/middleware/idempotency.js +1 -1
  109. package/src/middleware/rate-limiter.js +1 -1
  110. package/src/middleware/request-logger.js +1 -1
  111. package/src/middleware/security-headers.js +1 -1
  112. package/src/models/base-model-mysql.js +1 -1
  113. package/src/models/base-model-oracle.js +1 -1
  114. package/src/models/base-model-sqlite.js +1 -1
  115. package/src/models/base-model.js +1 -1
  116. package/src/pro/caching/redis-client.js +1 -1
  117. package/src/pro/caching/redis-helper.js +1 -1
  118. package/src/pro/consumers/baseConsumer.js +1 -1
  119. package/src/pro/consumers/declarativeMapper.js +1 -1
  120. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  121. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  122. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  123. package/src/pro/consumers/handlers/index.js +1 -1
  124. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  125. package/src/pro/consumers/index.js +1 -1
  126. package/src/pro/consumers/messageTransformer.js +1 -1
  127. package/src/pro/consumers/validator.js +1 -1
  128. package/src/pro/database/base-model-mysql.js +1 -1
  129. package/src/pro/database/base-model-oracle.js +1 -1
  130. package/src/pro/database/base-model-sqlite.js +1 -1
  131. package/src/pro/database/db-mysql.js +1 -1
  132. package/src/pro/database/db-oracle.js +1 -1
  133. package/src/pro/database/db-sqlite.js +1 -1
  134. package/src/pro/excel/excel-generator.js +1 -1
  135. package/src/pro/excel/excel-parser.js +1 -1
  136. package/src/pro/excel/export-service.js +1 -1
  137. package/src/pro/excel/export_handler.js +1 -1
  138. package/src/pro/excel/import-service.js +1 -1
  139. package/src/pro/excel/import-validator.js +1 -1
  140. package/src/pro/excel/import_handler.js +1 -1
  141. package/src/pro/excel/upsert-builder.js +1 -1
  142. package/src/pro/idgen/idgen-routes.js +1 -1
  143. package/src/pro/integrations/lookup-resolver.js +1 -1
  144. package/src/pro/integrations/upload-handler-v2.js +1 -1
  145. package/src/pro/integrations/upload-handler.js +1 -1
  146. package/src/pro/integrations/webhook.js +1 -1
  147. package/src/pro/locking/lock-routes.js +1 -1
  148. package/src/pro/locking/resource-lock-manager.js +1 -1
  149. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  150. package/src/pro/messaging/kafkaService.js +1 -1
  151. package/src/pro/messaging/messagehubService.js +1 -1
  152. package/src/pro/messaging/rabbitmqService.js +1 -1
  153. package/src/pro/scheduler/job-manager.js +1 -1
  154. package/src/pro/scheduler/job-routes.js +1 -1
  155. package/src/pro/scheduler/job-validator.js +1 -1
  156. package/src/pro/storage/base-storage-provider.js +1 -1
  157. package/src/pro/storage/file-metadata-helper.js +1 -1
  158. package/src/pro/storage/index.js +1 -1
  159. package/src/pro/storage/local-storage-provider.js +1 -1
  160. package/src/pro/storage/s3-storage-provider.js +1 -1
  161. package/src/pro/storage/upload-cleanup-job.js +1 -1
  162. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  163. package/src/pro/storage/upload-pending-tracker.js +1 -1
  164. package/src/pro/websocket/broadcast-helper.js +1 -1
  165. package/src/pro/websocket/index.js +1 -1
  166. package/src/pro/websocket/livesync-server.js +1 -1
  167. package/src/pro/websocket/ws-broadcaster.js +1 -1
  168. package/src/services/export-service.js +1 -1
  169. package/src/services/import-service.js +1 -1
  170. package/src/services/kafkaConsumerService.js +1 -1
  171. package/src/services/kafkaService.js +1 -1
  172. package/src/services/messagehubService.js +1 -1
  173. package/src/services/rabbitmqService.js +1 -1
  174. package/src/utils/cache-invalidation-registry.js +1 -1
  175. package/src/utils/cache-manager.js +1 -1
  176. package/src/utils/component-engine.js +1 -1
  177. package/src/utils/config-extractor.js +1 -1
  178. package/src/utils/consumerLogger.js +1 -1
  179. package/src/utils/context-builder.js +1 -1
  180. package/src/utils/dashboard-helpers.js +1 -1
  181. package/src/utils/dateHelper.js +1 -1
  182. package/src/utils/datetime-formatter.js +1 -1
  183. package/src/utils/datetime-parser.js +1 -1
  184. package/src/utils/db-bootstrap.js +1 -1
  185. package/src/utils/db-mysql.js +1 -1
  186. package/src/utils/db-oracle.js +1 -1
  187. package/src/utils/db-sqlite.js +1 -1
  188. package/src/utils/db.js +1 -1
  189. package/src/utils/demo-generator.js +1 -1
  190. package/src/utils/excel-generator.js +1 -1
  191. package/src/utils/excel-parser.js +1 -1
  192. package/src/utils/file-watcher.js +1 -1
  193. package/src/utils/id-generator.js +1 -1
  194. package/src/utils/idempotency-manager.js +1 -1
  195. package/src/utils/import-validator.js +1 -1
  196. package/src/utils/license-client.js +1 -1
  197. package/src/utils/lock-manager.js +1 -1
  198. package/src/utils/logger.js +1 -1
  199. package/src/utils/lookup-resolver.js +1 -1
  200. package/src/utils/payload-loader.js +1 -1
  201. package/src/utils/processor-response.js +1 -1
  202. package/src/utils/rabbitmq.js +1 -1
  203. package/src/utils/redis-client.js +1 -1
  204. package/src/utils/redis-helper.js +1 -1
  205. package/src/utils/request-scope.js +1 -1
  206. package/src/utils/security-checks.js +1 -1
  207. package/src/utils/service-resolver.js +1 -1
  208. package/src/utils/shutdown-coordinator.js +1 -1
  209. package/src/utils/soft-delete-dashboard-guard.js +1 -1
  210. package/src/utils/sql-table-extractor.js +1 -1
  211. package/src/utils/trusted-keys.js +1 -1
  212. package/src/utils/upload-handler.js +1 -1
  213. package/src/utils/upsert-builder.js +1 -1
  214. package/src/utils/workflow-hook-executor.js +1 -1
@@ -129,19 +129,19 @@ module.exports = {
129
129
  type: 'string',
130
130
  required: false,
131
131
  default: null,
132
- description: 'Filter berdasarkan section (defineModelOptions, fieldTypes, constraints, relationTypes, referentialActions, checkOperations, auditColumns, softDelete, shorthandSyntax, namingRules, dialectSupport)'
132
+ description: 'Filter by section (defineModelOptions, fieldTypes, constraints, relationTypes, referentialActions, checkOperations, auditColumns, softDelete, shorthandSyntax, namingRules, dialectSupport)'
133
133
  },
134
134
  name: {
135
135
  type: 'string',
136
136
  required: false,
137
137
  default: null,
138
- description: 'Filter berdasarkan nama exact (hanya valid bersama --section untuk array sections)'
138
+ description: 'Filter by exact name (only valid with --section for array sections)'
139
139
  },
140
140
  kind: {
141
141
  type: 'string',
142
142
  required: false,
143
143
  default: null,
144
- description: 'Filter constraint berdasarkan kind: standalone atau value (hanya valid dengan --section=constraints)'
144
+ description: 'Filter constraints by kind: standalone or value (only valid with --section=constraints)'
145
145
  },
146
146
  pretty: {
147
147
  type: 'boolean',
@@ -18,7 +18,7 @@ const { FIELD_VALIDATION_CATALOG } = require('../../lib/templates/field-validati
18
18
  module.exports = {
19
19
  resource: 'catalog',
20
20
  verb: 'field-validation',
21
- description: 'Output JSON catalog tipe field validation, constraint, dan format preset yang didukung',
21
+ description: 'Output JSON catalog of supported field validation types, constraints, and format presets',
22
22
  category: 'introspection',
23
23
  flags: {
24
24
  pretty: {
@@ -19,7 +19,7 @@ const { QUERY_DECLARATIVE_CATALOG } = require('../../lib/templates/query-declara
19
19
  module.exports = {
20
20
  resource: 'catalog',
21
21
  verb: 'query-declarative',
22
- description: 'Output JSON catalog query declarative properties, endpoint resolution, dan file reference convention',
22
+ description: 'Output JSON catalog of query declarative properties, endpoint resolution, and file reference conventions',
23
23
  category: 'introspection',
24
24
  flags: {
25
25
  pretty: {
@@ -20,7 +20,7 @@ const {
20
20
  module.exports = {
21
21
  resource: 'config',
22
22
  verb: 'clear-default',
23
- description: 'Menghapus default config untuk working directory saat ini',
23
+ description: 'Remove the default config for the current working directory',
24
24
  category: 'management',
25
25
  flags: {},
26
26
  examples: [
@@ -23,7 +23,7 @@ const {
23
23
  module.exports = {
24
24
  resource: 'config',
25
25
  verb: 'get-default',
26
- description: 'Menampilkan file config default yang aktif untuk working directory saat ini',
26
+ description: 'Show the active default config file for the current working directory',
27
27
  category: 'introspection',
28
28
  flags: {
29
29
  pretty: {
@@ -60,7 +60,7 @@ function isMatchingDefault(fileName, location, defaultName) {
60
60
  module.exports = {
61
61
  resource: 'config',
62
62
  verb: 'list',
63
- description: 'Menampilkan daftar file .env yang tersedia di working directory dan folder config/',
63
+ description: 'List available .env files in the working directory and config/ folder',
64
64
  category: 'introspection',
65
65
  flags: {
66
66
  pretty: {
@@ -19,7 +19,7 @@ const {
19
19
  module.exports = {
20
20
  resource: 'config',
21
21
  verb: 'schema',
22
- description: 'Output JSON schema dari parameter db-connection.env',
22
+ description: 'Output JSON schema for db-connection.env parameters',
23
23
  category: 'introspection',
24
24
  flags: {
25
25
  pretty: {
@@ -22,13 +22,13 @@ const {
22
22
  module.exports = {
23
23
  resource: 'config',
24
24
  verb: 'set-default',
25
- description: 'Set file config sebagai default untuk working directory saat ini (disimpan di .restforge/defaults.json)',
25
+ description: 'Set a config file as default for the current working directory (stored in .restforge/defaults.json)',
26
26
  category: 'management',
27
27
  flags: {
28
28
  config: {
29
29
  type: 'string',
30
30
  required: true,
31
- description: 'File config yang dijadikan default (lookup: cwd -> config/ folder -> +.env extension)'
31
+ description: 'Config file to set as default (lookup: cwd config/ folder +.env extension)'
32
32
  }
33
33
  },
34
34
  examples: [
@@ -16,7 +16,7 @@ const { DB_CONNECTION_ENV_TEMPLATE } = require('../../lib/templates/db-connectio
16
16
  module.exports = {
17
17
  resource: 'config',
18
18
  verb: 'template',
19
- description: 'Output raw template dari db-connection.env (format KEY=VALUE)',
19
+ description: 'Output the raw db-connection.env template (KEY=VALUE format)',
20
20
  category: 'utility',
21
21
  flags: {},
22
22
  examples: [
@@ -27,41 +27,41 @@ const { validateSafeName } = require('../../lib/utils/path-validator');
27
27
  module.exports = {
28
28
  resource: 'dashboard',
29
29
  verb: 'create',
30
- description: 'Generate dashboard endpoint module dari payload (multi-widget aggregator)',
30
+ description: 'Generate dashboard endpoint module from payload (multi-widget aggregator)',
31
31
  category: 'generation',
32
32
  flags: {
33
33
  project: {
34
34
  type: 'string',
35
35
  required: true,
36
- description: 'Nama project target'
36
+ description: 'Target project name'
37
37
  },
38
38
  name: {
39
39
  type: 'string',
40
40
  required: true,
41
- description: 'Nama dashboard (wajib diawali "dash-", mis. dash-sales)'
41
+ description: 'Dashboard name (must start with "dash-", e.g., dash-sales)'
42
42
  },
43
43
  payload: {
44
44
  type: 'string',
45
45
  required: true,
46
- description: 'Path atau nama file payload JSON dashboard'
46
+ description: 'Path or filename of the dashboard JSON payload'
47
47
  },
48
48
  database: {
49
49
  type: 'string',
50
50
  required: false,
51
51
  default: null,
52
- description: 'Tipe database (postgres|mysql|oracle|sqlite). Default: postgres'
52
+ description: 'Database type (postgres|mysql|oracle|sqlite). Default: postgres'
53
53
  },
54
54
  force: {
55
55
  type: 'boolean',
56
56
  required: false,
57
57
  default: false,
58
- description: 'Timpa file existing di output directory'
58
+ description: 'Overwrite existing files in the output directory'
59
59
  },
60
60
  'skip-sql-validation': {
61
61
  type: 'boolean',
62
62
  required: false,
63
63
  default: false,
64
- description: 'Lewati validasi keyword SQL'
64
+ description: 'Skip SQL keyword validation'
65
65
  }
66
66
  },
67
67
  examples: [
@@ -21,74 +21,74 @@
21
21
  module.exports = {
22
22
  resource: 'data',
23
23
  verb: 'pull',
24
- description: 'Export isi tabel database ke file envelope JSON (data-storage/<schema>/<table>.json) berdasarkan metadata SDF',
24
+ description: 'Export database table contents to JSON envelope files (data-storage/<schema>/<table>.json) based on SDF metadata',
25
25
  category: 'introspection',
26
26
  flags: {
27
27
  table: {
28
28
  type: 'string',
29
29
  required: false,
30
30
  default: null,
31
- description: 'Nama tabel sumber yang akan di-pull (harus terdaftar di SDF)'
31
+ description: 'Source table name to pull (must be registered in SDF)'
32
32
  },
33
33
  schema: {
34
34
  type: 'string',
35
35
  required: false,
36
36
  default: null,
37
- description: 'Filter schema: satu atau comma-separated (mutual-exclusive dengan --table/--all-schemas)'
37
+ description: 'Filter by schema: single or comma-separated (mutually exclusive with --table/--all-schemas)'
38
38
  },
39
39
  'all-schemas': {
40
40
  type: 'boolean',
41
41
  required: false,
42
42
  default: false,
43
- description: 'Pull seluruh tabel di semua schema (mutual-exclusive dengan --table/--schema)'
43
+ description: 'Pull all tables across all schemas (mutually exclusive with --table/--schema)'
44
44
  },
45
45
  config: {
46
46
  type: 'string',
47
47
  required: false,
48
48
  default: null,
49
- description: 'File config database (.env). Fallback ke `.restforge/defaults.json` bila tidak disediakan eksplisit (set via `config set-default`)'
49
+ description: 'Database config file (.env). Fallback to `.restforge/defaults.json` if not explicitly provided (set via `config set-default`)'
50
50
  },
51
51
  'schema-path': {
52
52
  type: 'string',
53
53
  required: false,
54
54
  default: 'schema',
55
- description: 'Lokasi SDF (file atau folder) sumber metadata tabel'
55
+ description: 'SDF location (file or folder) for table metadata'
56
56
  },
57
57
  format: {
58
58
  type: 'string',
59
59
  required: false,
60
60
  default: 'json',
61
- description: "Format penyimpanan nilai; saat ini hanya menerima 'json'"
61
+ description: "Storage format for values; currently only accepts 'json'"
62
62
  },
63
63
  limit: {
64
64
  type: 'number',
65
65
  required: false,
66
66
  default: null,
67
- description: 'Batas maksimum total rows yang di-export (null = seluruh tabel)'
67
+ description: 'Maximum number of rows to export (null = entire table)'
68
68
  },
69
69
  'batch-size': {
70
70
  type: 'number',
71
71
  required: false,
72
72
  default: 1000,
73
- description: 'Ukuran batch baca internal dari database'
73
+ description: 'Internal read batch size from database'
74
74
  },
75
75
  'storage-path': {
76
76
  type: 'string',
77
77
  required: false,
78
78
  default: 'data-storage',
79
- description: 'Folder output relatif terhadap working directory'
79
+ description: 'Output folder relative to working directory'
80
80
  },
81
81
  force: {
82
82
  type: 'boolean',
83
83
  required: false,
84
84
  default: false,
85
- description: 'Overwrite file output bila sudah ada'
85
+ description: 'Overwrite output file if it already exists'
86
86
  },
87
87
  json: {
88
88
  type: 'boolean',
89
89
  required: false,
90
90
  default: false,
91
- description: 'Output ringkasan dalam format JSON (untuk konsumsi CI/CD)'
91
+ description: 'Output summary in JSON format (for CI/CD consumption)'
92
92
  }
93
93
  },
94
94
  examples: [
@@ -30,56 +30,56 @@
30
30
  module.exports = {
31
31
  resource: 'data',
32
32
  verb: 'push',
33
- description: 'Muat isi file envelope JSON (data-storage/<schema>/<table>.json) ke tabel tujuan via INSERT batch berdasarkan metadata SDF',
33
+ description: 'Load JSON envelope files (data-storage/<schema>/<table>.json) into the target table via batch INSERT based on SDF metadata',
34
34
  category: 'management',
35
35
  flags: {
36
36
  table: {
37
37
  type: 'string',
38
38
  required: false,
39
39
  default: null,
40
- description: 'Nama tabel tujuan yang akan di-push (harus terdaftar di SDF)'
40
+ description: 'Target table name to push (must be registered in SDF)'
41
41
  },
42
42
  schema: {
43
43
  type: 'string',
44
44
  required: false,
45
45
  default: null,
46
- description: 'Filter schema: satu atau comma-separated (mutual-exclusive dengan --table/--all-schemas)'
46
+ description: 'Filter by schema: single or comma-separated (mutually exclusive with --table/--all-schemas)'
47
47
  },
48
48
  'all-schemas': {
49
49
  type: 'boolean',
50
50
  required: false,
51
51
  default: false,
52
- description: 'Push seluruh tabel di semua schema, urut topological FK parent→child (mutual-exclusive dengan --table/--schema)'
52
+ description: 'Push all tables across all schemas in topological FK order parent→child (mutually exclusive with --table/--schema)'
53
53
  },
54
54
  config: {
55
55
  type: 'string',
56
56
  required: false,
57
57
  default: null,
58
- description: 'File config database tujuan (.env). Fallback ke `.restforge/defaults.json` bila tidak disediakan eksplisit (set via `config set-default`)'
58
+ description: 'Target database config file (.env). Fallback to `.restforge/defaults.json` if not explicitly provided (set via `config set-default`)'
59
59
  },
60
60
  'schema-path': {
61
61
  type: 'string',
62
62
  required: false,
63
63
  default: 'schema',
64
- description: 'Lokasi SDF (file atau folder) sumber metadata tabel'
64
+ description: 'SDF location (file or folder) for table metadata'
65
65
  },
66
66
  'storage-path': {
67
67
  type: 'string',
68
68
  required: false,
69
69
  default: 'data-storage',
70
- description: 'Folder sumber file envelope relatif terhadap working directory'
70
+ description: 'Source folder for envelope files relative to working directory'
71
71
  },
72
72
  'batch-size': {
73
73
  type: 'number',
74
74
  required: false,
75
75
  default: 1000,
76
- description: 'Ukuran batch INSERT, sekaligus unit commit per batch'
76
+ description: 'INSERT batch size, also the commit unit per batch'
77
77
  },
78
78
  json: {
79
79
  type: 'boolean',
80
80
  required: false,
81
81
  default: false,
82
- description: 'Output ringkasan dalam format JSON (untuk konsumsi CI/CD)'
82
+ description: 'Output summary in JSON format (for CI/CD consumption)'
83
83
  }
84
84
  },
85
85
  examples: [
@@ -68,47 +68,47 @@ async function runAuditMigrationHook(payload, opts) {
68
68
  module.exports = {
69
69
  resource: 'endpoint',
70
70
  verb: 'create',
71
- description: 'Generate endpoint REST baru dari payload JSON',
71
+ description: 'Generate a new REST endpoint from a JSON payload',
72
72
  category: 'generation',
73
73
  flags: {
74
74
  project: {
75
75
  type: 'string',
76
76
  required: true,
77
- description: 'Nama project target'
77
+ description: 'Target project name'
78
78
  },
79
79
  name: {
80
80
  type: 'string',
81
81
  required: true,
82
- description: 'Nama endpoint yang akan dibuat'
82
+ description: 'Endpoint name to create'
83
83
  },
84
84
  payload: {
85
85
  type: 'string',
86
86
  required: true,
87
- description: 'Path atau nama file payload JSON'
87
+ description: 'Path or filename of the JSON payload'
88
88
  },
89
89
  database: {
90
90
  type: 'string',
91
91
  required: false,
92
92
  default: null,
93
- description: 'Tipe database (postgres|mysql|oracle|sqlite). Default: postgres'
93
+ description: 'Database type (postgres|mysql|oracle|sqlite). Default: postgres'
94
94
  },
95
95
  config: {
96
96
  type: 'string',
97
97
  required: false,
98
98
  default: null,
99
- description: 'File config database (.env) untuk validasi schema payload-vs-database. Wajib kecuali `--skip-schema-check` aktif atau default config sudah di-set via `config set-default`. Fallback ke `.restforge/defaults.json` bila tidak disediakan eksplisit'
99
+ description: 'Database config file (.env) for payload-vs-database schema validation. Required unless `--skip-schema-check` is active or a default config is set via `config set-default`. Fallback to `.restforge/defaults.json` if not explicitly provided'
100
100
  },
101
101
  'skip-schema-check': {
102
102
  type: 'boolean',
103
103
  required: false,
104
104
  default: false,
105
- description: 'Lewati validasi schema database (escape hatch untuk DB offline atau maintenance). Shape RDF tetap divalidasi'
105
+ description: 'Skip database schema validation (escape hatch for offline DB or maintenance). RDF shape is still validated'
106
106
  },
107
107
  force: {
108
108
  type: 'boolean',
109
109
  required: false,
110
110
  default: false,
111
- description: 'Timpa file existing di output directory'
111
+ description: 'Overwrite existing files in the output directory'
112
112
  },
113
113
  'create-examples': {
114
114
  type: 'boolean',
@@ -120,19 +120,19 @@ module.exports = {
120
120
  type: 'boolean',
121
121
  required: false,
122
122
  default: false,
123
- description: 'Lewati validasi keyword SQL'
123
+ description: 'Skip SQL keyword validation'
124
124
  },
125
125
  'no-audit-migration': {
126
126
  type: 'boolean',
127
127
  required: false,
128
128
  default: false,
129
- description: 'Skip eksekusi audit table migration saat payload pakai fieldPolicy strategies "audit" (file SQL tetap ditulis ke migrations/audit/)'
129
+ description: 'Skip audit table migration execution when payload uses fieldPolicy strategies "audit" (SQL file is still written to migrations/audit/)'
130
130
  },
131
131
  verbose: {
132
132
  type: 'boolean',
133
133
  required: false,
134
134
  default: false,
135
- description: 'Tampilkan output verbose untuk debugging'
135
+ description: 'Show verbose output for debugging'
136
136
  }
137
137
  },
138
138
  examples: [
@@ -202,20 +202,20 @@ function renderHumanTable(entries) {
202
202
  module.exports = {
203
203
  resource: 'endpoint',
204
204
  verb: 'list',
205
- description: 'Menampilkan daftar endpoint dari metadata project di working directory',
205
+ description: 'List endpoints from project metadata in the working directory',
206
206
  category: 'management',
207
207
  flags: {
208
208
  format: {
209
209
  type: 'string',
210
210
  required: false,
211
211
  default: 'text',
212
- description: 'Format output: `text` (table human-readable) atau `json` (untuk AI agent / mcp-server)'
212
+ description: 'Output format: `text` (human-readable table) or `json` (for AI agent / mcp-server)'
213
213
  },
214
214
  name: {
215
215
  type: 'string',
216
216
  required: false,
217
217
  default: null,
218
- description: 'Filter nama endpoint, case-insensitive. Wildcard `*` = karakter apa pun (mis. `*product*`); tanpa wildcard berarti exact match'
218
+ description: 'Filter endpoint name, case-insensitive. Wildcard `*` matches any characters (e.g., `*product*`); without wildcard means exact match'
219
219
  }
220
220
  },
221
221
  examples: [
@@ -856,19 +856,49 @@ function tableToKebab(table) {
856
856
  * displayCols = kolom code/name di luar PK & kolom audit, dipakai sebagai kolom
857
857
  * display saat tabel ini menjadi parent FK (untuk `payload sync --expand-fk`).
858
858
  */
859
+ // Postgres 'public' diperlakukan sebagai default implisit (selalu di search_path
860
+ // secara konvensi), SAMA seperti pengecualian di `qualifiedRefTable()`
861
+ // (generators/lib/payload/payload-runner.js). `schema introspect` SELALU menulis
862
+ // field `schema:` eksplisit di SDF hasil introspeksi, termasuk untuk tabel yang
863
+ // sebenarnya di schema default ('public') — tanpa pengecualian ini, SETIAP SDF
864
+ // hasil introspect Postgres default-schema akan ikut di-qualify ('public.visitors'),
865
+ // menghasilkan nama file RDF berprefix 'public-' yang tidak konsisten dengan JOIN
866
+ // SQL (qualifiedRefTable() di payload-runner.js TIDAK menulis prefix 'public.' pada
867
+ // klausa JOIN) — JOIN auto-discovery di `payload migrate` (migrate-runner.js) jadi
868
+ // gagal menemukan file RDF parent, dan page UDF parent tidak pernah dibuat.
869
+ const DEFAULT_SCHEMA_SENTINEL = 'public';
870
+ function isQualifyingSchema(schemaName) {
871
+ return !!schemaName && schemaName !== DEFAULT_SCHEMA_SENTINEL;
872
+ }
873
+
859
874
  function loadModels(schemaDir) {
860
875
  const models = loadSchemaPath(schemaDir);
861
876
  const entries = [];
862
877
  for (const model of models.values()) {
863
- const table = model.tableName;
878
+ // qualifiedName (mis. 'myschema.guest_book') dipakai, bukan tableName
879
+ // bare, agar `--table=` yang dikirim ke `payload generate`/`payload sync`
880
+ // tetap menemukan tabel yang ada di custom schema (tanpa prefix, resolver
881
+ // koneksi default ke schema 'public'/setara dan tabel tidak ditemukan).
882
+ // Schema 'public' dikecualikan (lihat isQualifyingSchema) karena memang
883
+ // sudah default tanpa perlu di-qualify.
884
+ const schemaName = model.schemaName || null;
885
+ const table = isQualifyingSchema(schemaName) ? (model.qualifiedName || model.tableName) : model.tableName;
864
886
  const primaryKey = Array.isArray(model.primaryKey) ? model.primaryKey : [];
865
887
 
866
888
  const fks = [];
867
889
  for (const rel of Object.values(model.relations || {})) {
868
890
  if (rel.type !== 'belongsTo' || !rel.localKey || !rel.target) continue;
891
+ // Konvensi SDF (restforge-handbook/catalogs/sdf/multi-schema.md): target
892
+ // relasi ditulis bare bila parent di schema YANG SAMA dengan child, dan
893
+ // fully-qualified hanya bila cross-schema. Qualify bare target dengan
894
+ // schema child di sini supaya konsisten dengan `table` qualified di atas
895
+ // (byTable/parentTables dibangun dari nilai ini, lihat ctx.byTable).
896
+ const parentTable = rel.target.includes('.')
897
+ ? rel.target
898
+ : (isQualifyingSchema(schemaName) ? `${schemaName}.${rel.target}` : rel.target);
869
899
  fks.push({
870
900
  childCol: rel.localKey,
871
- parentTable: rel.target,
901
+ parentTable,
872
902
  parentCol: rel.references || null
873
903
  });
874
904
  }
@@ -879,7 +909,17 @@ function loadModels(schemaDir) {
879
909
  return !isPk && !AUDIT_COLS.has(name) && /(code|name)/i.test(name);
880
910
  });
881
911
 
882
- entries.push({ kebab: tableToKebab(table), table, fks, displayCols });
912
+ // `kebab` (qualified, mis. 'myschema-guest-book') HARUS dipakai untuk
913
+ // mencocokkan nama file RDF/UDF di disk (`payload generate` menulis
914
+ // baseFilename dari `--table=` literal, jadi ikut prefix schema).
915
+ // `resourceName` (bare, mis. 'guest-book') dipakai khusus untuk identitas
916
+ // REST endpoint (`endpoint create --name=`): endpoint TIDAK mengenal
917
+ // schema (itu murni konsep koneksi database), dan `payload migrate`
918
+ // (RDF -> UDF) sendiri sudah men-strip schema saat menurunkan apiPath/
919
+ // pageId (lihat backend-payload-migrator.js: cleanTable = tableName.split('.').pop()).
920
+ // Memakai `kebab` qualified untuk nama endpoint akan membuat route REST
921
+ // tidak sinkron dengan apiPath yang dipanggil frontend.
922
+ entries.push({ kebab: tableToKebab(table), resourceName: tableToKebab(model.tableName), table, fks, displayCols });
883
923
  }
884
924
  entries.sort((a, b) => a.table.localeCompare(b.table));
885
925
  return entries;
@@ -894,13 +934,24 @@ function buildTableEntries(schemaDir) {
894
934
  * Turunkan daftar `--fk-columns` untuk `payload sync --expand-fk` dari SDF:
895
935
  * `<parentTable>.<displayCol>` untuk tiap kolom display (code/name) tiap parent.
896
936
  * Kosong bila tidak ada kolom display terdeteksi (jatuh ke mode AUTO command).
937
+ *
938
+ * `parentTable` di sini WAJIB bare (tanpa prefix schema), berbeda dari
939
+ * `fk.parentTable` yang dipakai untuk lookup `byTable` (qualified). Alasannya:
940
+ * `payload-runner.js parseFkColumns()` mem-validasi setiap entri persis 2 segmen
941
+ * (`table.column`), dan nilainya dicocokkan terhadap `getForeignKeys().references.table`
942
+ * hasil introspeksi DB — yang SELALU bare (`pg_class.relname`, schema ada di field
943
+ * terpisah `references.schema`). Mengirim `sch02.company.company_name` (3 segmen)
944
+ * ditolak validator; mengirim bare `company.company_name` cocok dengan hasil introspeksi.
897
945
  */
898
946
  function fkColumnsForEntry(entry, byTable) {
899
947
  const cols = [];
900
948
  for (const fk of entry.fks) {
901
949
  const parent = byTable.get(fk.parentTable);
902
950
  const disp = parent ? parent.displayCols : [];
903
- for (const dc of disp) cols.push(`${fk.parentTable}.${dc}`);
951
+ const bareParentTable = fk.parentTable.includes('.')
952
+ ? fk.parentTable.split('.').pop()
953
+ : fk.parentTable;
954
+ for (const dc of disp) cols.push(`${bareParentTable}.${dc}`);
904
955
  }
905
956
  return cols;
906
957
  }
@@ -974,7 +1025,7 @@ function runBackendPipeline(ctx) {
974
1025
  // Mode --overwrite: drop tabel lalu re-create (destruktif). Tanpa --overwrite:
975
1026
  // CREATE TABLE IF NOT EXISTS (tabel existing dilewati).
976
1027
  const dropFlag = ctx.overwrite ? ' --drop=true' : '';
977
- run(`npx restforge schema migrate --path=${ctx.schemaFlag} ${cfgArg} --auto-create-db${dropFlag}`, ctx.cwd);
1028
+ run(`npx restforge schema migrate --schema-path=${ctx.schemaFlag} ${cfgArg} --auto-create-db${dropFlag}`, ctx.cwd);
978
1029
 
979
1030
  phase('[3/4] Payload RDF (generate)');
980
1031
  for (const t of ctx.tableEntries) {
@@ -998,7 +1049,9 @@ function runBackendPipeline(ctx) {
998
1049
 
999
1050
  phase('[4/4] REST endpoints');
1000
1051
  for (const t of ctx.tableEntries) {
1001
- run(`npx restforge endpoint create --project=${ctx.project} --name=${t.kebab} --payload=${t.kebab}.json ${cfgArg} --database=${dbFlag} --force`, ctx.cwd);
1052
+ // --name= = identitas REST endpoint (bare, lihat resourceName di loadModels).
1053
+ // --payload= = nama file RDF di disk (qualified/kebab, ikut prefix schema).
1054
+ run(`npx restforge endpoint create --project=${ctx.project} --name=${t.resourceName} --payload=${t.kebab}.json ${cfgArg} --database=${dbFlag} --force`, ctx.cwd);
1002
1055
  }
1003
1056
  }
1004
1057
 
@@ -1185,36 +1238,36 @@ async function maybeRunFrontend(ctx, ask) {
1185
1238
 
1186
1239
  module.exports = {
1187
1240
  verb: 'fast-track',
1188
- description: 'Generate REST API + frontend app dari SDF (eksekusi nyata) + opsi runtime server',
1241
+ description: 'Generate REST API + frontend app from SDF (real execution) with optional runtime server',
1189
1242
  category: 'generation',
1190
1243
  flags: {
1191
1244
  project: {
1192
1245
  type: 'string',
1193
1246
  required: true,
1194
- description: 'Nama project/aplikasi (mis. visitors-app)'
1247
+ description: 'Project/application name (e.g., visitors-app)'
1195
1248
  },
1196
1249
  'schema-path': {
1197
1250
  type: 'string',
1198
1251
  required: true,
1199
- description: 'Folder berisi SDF aplikasi (relatif cwd)'
1252
+ description: 'Folder containing the application SDF (relative to cwd)'
1200
1253
  },
1201
1254
  config: {
1202
1255
  type: 'string',
1203
1256
  required: false,
1204
1257
  default: null,
1205
- description: 'Nama file env target di folder config/. Bila kosong, fast-track mengikuti file config yang ada: 1 file dipakai langsung, >1 file pakai config get-default'
1258
+ description: 'Target env filename in config/ folder. If empty, fast-track uses the existing config file: 1 file is used directly, >1 files use config get-default'
1206
1259
  },
1207
1260
  license: {
1208
1261
  type: 'string',
1209
1262
  required: false,
1210
1263
  default: null,
1211
- description: 'License key (XXXX-XXXX-XXXX-XXXX). Bila diisi dipakai sebagai default prompt LICENSE'
1264
+ description: 'License key (XXXX-XXXX-XXXX-XXXX). If provided, used as the default for the LICENSE prompt'
1212
1265
  },
1213
1266
  overwrite: {
1214
1267
  type: 'boolean',
1215
1268
  required: false,
1216
1269
  default: false,
1217
- description: 'Mode destruktif: drop table & regenerate (perlu konfirmasi y/N)'
1270
+ description: 'Destructive mode: drop table & regenerate (requires y/N confirmation)'
1218
1271
  }
1219
1272
  },
1220
1273
  examples: [
@@ -288,14 +288,14 @@ async function runInteractive(workingDir, prompter) {
288
288
 
289
289
  module.exports = {
290
290
  verb: 'init',
291
- description: 'Generate starter config file (config/db-connection.env) di working directory. Interaktif di terminal; non-interaktif dengan --force',
291
+ description: 'Generate a starter config file (config/db-connection.env) in the working directory. Interactive in terminal; non-interactive with --force',
292
292
  category: 'utility',
293
293
  flags: {
294
294
  force: {
295
295
  type: 'boolean',
296
296
  required: false,
297
297
  default: false,
298
- description: 'Timpa file existing tanpa konfirmasi'
298
+ description: 'Overwrite existing file without confirmation'
299
299
  }
300
300
  },
301
301
  examples: [