@restforgejs/platform 4.3.8 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/sdf-tools.exe +0 -0
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/init.js +4 -104
- package/generators/cli/payload/migrate.js +96 -96
- package/generators/cli/schema/list.js +82 -18
- package/generators/cli/schema/migrate.js +23 -3
- package/generators/lib/dbschema-kit/apply-engine.js +211 -46
- package/generators/lib/dbschema-kit/diff-engine.js +715 -703
- package/generators/lib/dbschema-kit/emitters/alter-table.js +96 -2
- package/generators/lib/dbschema-kit/introspect-mapper.js +9 -0
- package/generators/lib/migrate/backend-payload-migrator.js +221 -221
- package/generators/lib/migrate/field-type-resolver.js +325 -319
- package/generators/lib/migrate/label-generator.js +38 -38
- package/generators/lib/migrate/migrate-runner.js +244 -38
- package/generators/lib/migrate/naming.js +52 -43
- package/generators/lib/migrate/sql-parser.js +124 -124
- package/generators/lib/templates/dashboard-catalog.js +1 -1
- package/generators/lib/templates/db-connection-env.js +1 -1
- package/generators/lib/templates/dbschema-catalog.js +1 -1
- package/generators/lib/templates/field-validation-catalog.js +1 -1
- package/generators/lib/templates/mysql-template.js +1 -1
- package/generators/lib/templates/oracle-template.js +1 -1
- package/generators/lib/templates/postgres-template.js +1 -1
- package/generators/lib/templates/query-declarative-catalog.js +1 -1
- package/generators/lib/templates/sqlite-template.js +1 -1
- package/integrity-manifest.json +18 -18
- package/node_modules/brace-expansion/index.js +1 -1
- package/node_modules/brace-expansion/package.json +1 -1
- package/node_modules/dayjs/CHANGELOG.md +7 -0
- package/node_modules/dayjs/README.md +12 -10
- package/node_modules/dayjs/dayjs.min.js +1 -1
- package/node_modules/dayjs/esm/constant.js +1 -1
- package/node_modules/dayjs/esm/plugin/duration/index.js +5 -4
- package/node_modules/dayjs/locale.json +1 -1
- package/node_modules/dayjs/package.json +2 -2
- package/node_modules/dayjs/plugin/duration.js +1 -1
- package/node_modules/tmp/lib/tmp.js +37 -7
- package/node_modules/tmp/package.json +4 -16
- package/package.json +1 -1
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
package/generators/cli/init.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Contract: init (verb global)
|
|
5
5
|
*
|
|
6
|
-
* Generate
|
|
7
|
-
*
|
|
8
|
-
* `payload/query/samples-datatables.sql` sebagai template starting point.
|
|
6
|
+
* Generate starter config file di working directory. Membuat
|
|
7
|
+
* `config/db-connection.env` sebagai template starting point.
|
|
9
8
|
*
|
|
10
9
|
* Inline migration v4.0.0: business logic asli dari `init.js` di-inline
|
|
11
10
|
* langsung ke handler. Adapter `process.argv` override dihapus. `process.exit()`
|
|
@@ -21,88 +20,9 @@ const path = require('node:path');
|
|
|
21
20
|
const fs = require('node:fs');
|
|
22
21
|
const { DB_CONNECTION_ENV_TEMPLATE: TEMPLATE_ENV } = require('../lib/templates/db-connection-env');
|
|
23
22
|
|
|
24
|
-
const TEMPLATE_PAYLOAD = JSON.stringify({
|
|
25
|
-
"tableName": "contact",
|
|
26
|
-
"primaryKey": "contact_id",
|
|
27
|
-
"fieldName": [
|
|
28
|
-
"contact_id",
|
|
29
|
-
"contact_name",
|
|
30
|
-
"email",
|
|
31
|
-
"address",
|
|
32
|
-
"is_active",
|
|
33
|
-
"created_at",
|
|
34
|
-
"created_by",
|
|
35
|
-
"updated_at",
|
|
36
|
-
"updated_by"
|
|
37
|
-
],
|
|
38
|
-
"fieldValidation": [
|
|
39
|
-
{
|
|
40
|
-
"name": "contact_id",
|
|
41
|
-
"type": "string",
|
|
42
|
-
"constraints": {
|
|
43
|
-
"primaryKey": true,
|
|
44
|
-
"autoGenerate": true,
|
|
45
|
-
"required": true
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"name": "contact_name",
|
|
50
|
-
"type": "string",
|
|
51
|
-
"constraints": {
|
|
52
|
-
"required": true
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"name": "email",
|
|
57
|
-
"type": "string",
|
|
58
|
-
"constraints": {}
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"name": "is_active",
|
|
62
|
-
"type": "boolean",
|
|
63
|
-
"constraints": {}
|
|
64
|
-
}
|
|
65
|
-
],
|
|
66
|
-
"fieldNameLookup": {
|
|
67
|
-
"id": "contact_id",
|
|
68
|
-
"text": "contact_name||' - '||email as display_text"
|
|
69
|
-
},
|
|
70
|
-
"datatablesQuery": "file:query/samples-datatables.sql",
|
|
71
|
-
"datatablesWhere": [
|
|
72
|
-
"contact_name",
|
|
73
|
-
"email",
|
|
74
|
-
"address",
|
|
75
|
-
"all"
|
|
76
|
-
],
|
|
77
|
-
"action": {
|
|
78
|
-
"datatables": true,
|
|
79
|
-
"create": true,
|
|
80
|
-
"update": true,
|
|
81
|
-
"delete": true,
|
|
82
|
-
"first": true,
|
|
83
|
-
"lookup": true,
|
|
84
|
-
"read": true,
|
|
85
|
-
"export": true,
|
|
86
|
-
"import": true,
|
|
87
|
-
"adjust": false,
|
|
88
|
-
"aggregate": false,
|
|
89
|
-
"createComposite": false,
|
|
90
|
-
"updateComposite": false,
|
|
91
|
-
"readComposite": false
|
|
92
|
-
}
|
|
93
|
-
}, null, 4) + '\n';
|
|
94
|
-
|
|
95
|
-
const TEMPLATE_SQL = `SELECT a.contact_id,
|
|
96
|
-
a.contact_name,
|
|
97
|
-
a.email,
|
|
98
|
-
a.address,
|
|
99
|
-
a.is_active
|
|
100
|
-
FROM contact a
|
|
101
|
-
`;
|
|
102
|
-
|
|
103
23
|
module.exports = {
|
|
104
24
|
verb: 'init',
|
|
105
|
-
description: 'Generate
|
|
25
|
+
description: 'Generate starter config file (config/db-connection.env) di working directory',
|
|
106
26
|
category: 'utility',
|
|
107
27
|
flags: {
|
|
108
28
|
force: {
|
|
@@ -128,14 +48,6 @@ module.exports = {
|
|
|
128
48
|
{
|
|
129
49
|
relativePath: path.join('config', 'db-connection.env'),
|
|
130
50
|
content: TEMPLATE_ENV
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
relativePath: path.join('payload', 'samples.json'),
|
|
134
|
-
content: TEMPLATE_PAYLOAD
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
relativePath: path.join('payload', 'query', 'samples-datatables.sql'),
|
|
138
|
-
content: TEMPLATE_SQL
|
|
139
51
|
}
|
|
140
52
|
];
|
|
141
53
|
|
|
@@ -159,9 +71,7 @@ module.exports = {
|
|
|
159
71
|
}
|
|
160
72
|
|
|
161
73
|
const dirs = [
|
|
162
|
-
path.resolve(workingDir, 'config')
|
|
163
|
-
path.resolve(workingDir, 'payload'),
|
|
164
|
-
path.resolve(workingDir, 'payload', 'query')
|
|
74
|
+
path.resolve(workingDir, 'config')
|
|
165
75
|
];
|
|
166
76
|
|
|
167
77
|
for (const dir of dirs) {
|
|
@@ -183,15 +93,5 @@ module.exports = {
|
|
|
183
93
|
console.log(' 1. Edit config/db-connection.env');
|
|
184
94
|
console.log(' Update database credentials (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME)');
|
|
185
95
|
console.log('');
|
|
186
|
-
console.log(' 2. Edit payload/samples.json');
|
|
187
|
-
console.log(' Adjust tableName, fieldName, and action as needed');
|
|
188
|
-
console.log('');
|
|
189
|
-
console.log(' 3. Generate module:');
|
|
190
|
-
console.log(' npx restforge endpoint create --project=my-project --name=contact \\');
|
|
191
|
-
console.log(' --payload=payload/samples.json --config=config/db-connection.env');
|
|
192
|
-
console.log('');
|
|
193
|
-
console.log(' 4. Start server:');
|
|
194
|
-
console.log(' npx restforge serve --project=my-project --config=config/db-connection.env');
|
|
195
|
-
console.log('');
|
|
196
96
|
}
|
|
197
97
|
};
|
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Contract: payload migrate
|
|
5
|
-
*
|
|
6
|
-
* Konversi file payload backend (RDF / RESTForge consumer) menjadi file payload
|
|
7
|
-
* frontend (UDF / designer). Port dari `rfd migrate` di packages/designer/.
|
|
8
|
-
*
|
|
9
|
-
* Perbedaan dengan `rfd migrate`:
|
|
10
|
-
* - `apiBaseUrl` di-construct dari SERVER_ADDRESS + SERVER_PORT (db-connection.env)
|
|
11
|
-
* + --project sehingga sesuai dengan runtime server actual
|
|
12
|
-
* - Port di-baca dari db-connection.env (SERVER_PORT), bukan hard-coded 3000
|
|
13
|
-
* - Primary key (constraints.primaryKey=true) di-skip dari fields[] apapun
|
|
14
|
-
* tipenya (uuid/string/integer), karena PK adalah identifier teknis dan
|
|
15
|
-
* tidak perlu di-render di UI form
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const runner = require('../../lib/migrate/migrate-runner');
|
|
19
|
-
|
|
20
|
-
module.exports = {
|
|
21
|
-
resource: 'payload',
|
|
22
|
-
verb: 'migrate',
|
|
23
|
-
description: 'Convert backend payload (RDF) file into frontend payload (UDF) for the designer',
|
|
24
|
-
category: 'generation',
|
|
25
|
-
flags: {
|
|
26
|
-
name: {
|
|
27
|
-
type: 'string',
|
|
28
|
-
required: true,
|
|
29
|
-
description: 'Backend payload file name (e.g. visitors.json). Relative to cwd or cwd/payload/.'
|
|
30
|
-
},
|
|
31
|
-
output: {
|
|
32
|
-
type: 'string',
|
|
33
|
-
required: false,
|
|
34
|
-
default: null,
|
|
35
|
-
description: 'Output directory (the file will be written with the same name as --name inside it). If ending with `.json`, treated as an explicit file path. Default: frontend/payload/'
|
|
36
|
-
},
|
|
37
|
-
config: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
required: false,
|
|
40
|
-
default: null,
|
|
41
|
-
description: 'Database config file (.env). Used to read SERVER_ADDRESS and SERVER_PORT. Falls back to `.restforge/defaults.json`.'
|
|
42
|
-
},
|
|
43
|
-
project: {
|
|
44
|
-
type: 'string',
|
|
45
|
-
required: true,
|
|
46
|
-
description: 'Project name (kebab-case code) used as the path segment in apiBaseUrl: http://{host}:{port}/api/{project}'
|
|
47
|
-
},
|
|
48
|
-
'app-name': {
|
|
49
|
-
type: 'string',
|
|
50
|
-
required: false,
|
|
51
|
-
default: null,
|
|
52
|
-
description: 'Application name (default: "
|
|
53
|
-
},
|
|
54
|
-
'app-code': {
|
|
55
|
-
type: 'string',
|
|
56
|
-
required: false,
|
|
57
|
-
default: null,
|
|
58
|
-
description: 'Application code in kebab-case (default: follows --project)'
|
|
59
|
-
},
|
|
60
|
-
plugin: {
|
|
61
|
-
type: 'string',
|
|
62
|
-
required: false,
|
|
63
|
-
default: null,
|
|
64
|
-
description: 'Designer plugin ID (default: "vanilla-js-basic")'
|
|
65
|
-
},
|
|
66
|
-
port: {
|
|
67
|
-
type: 'number',
|
|
68
|
-
required: false,
|
|
69
|
-
default: null,
|
|
70
|
-
description: 'Frontend application port written to appConfig.port (default: 8000). Independent from the backend port used in apiBaseUrl.'
|
|
71
|
-
},
|
|
72
|
-
overwrite: {
|
|
73
|
-
type: 'boolean',
|
|
74
|
-
required: false,
|
|
75
|
-
default: false,
|
|
76
|
-
description: 'Overwrite the output file if it already exists'
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
examples: [
|
|
80
|
-
'npx restforge payload migrate --name=visitors.json --output=..\\sandbox\\frontend\\payload --config=db.env --project=myapp',
|
|
81
|
-
'npx restforge payload migrate --name=visitors.json --project=myapp --overwrite'
|
|
82
|
-
],
|
|
83
|
-
async handler(args) {
|
|
84
|
-
await runner.run({
|
|
85
|
-
name: args.name,
|
|
86
|
-
output: args.output || null,
|
|
87
|
-
config: args.config || null,
|
|
88
|
-
project: args.project,
|
|
89
|
-
appName: args['app-name'] || null,
|
|
90
|
-
appCode: args['app-code'] || null,
|
|
91
|
-
plugin: args.plugin || null,
|
|
92
|
-
port: typeof args.port === 'number' ? args.port : null,
|
|
93
|
-
overwrite: args.overwrite === true
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contract: payload migrate
|
|
5
|
+
*
|
|
6
|
+
* Konversi file payload backend (RDF / RESTForge consumer) menjadi file payload
|
|
7
|
+
* frontend (UDF / designer). Port dari `rfd migrate` di packages/designer/.
|
|
8
|
+
*
|
|
9
|
+
* Perbedaan dengan `rfd migrate`:
|
|
10
|
+
* - `apiBaseUrl` di-construct dari SERVER_ADDRESS + SERVER_PORT (db-connection.env)
|
|
11
|
+
* + --project sehingga sesuai dengan runtime server actual
|
|
12
|
+
* - Port di-baca dari db-connection.env (SERVER_PORT), bukan hard-coded 3000
|
|
13
|
+
* - Primary key (constraints.primaryKey=true) di-skip dari fields[] apapun
|
|
14
|
+
* tipenya (uuid/string/integer), karena PK adalah identifier teknis dan
|
|
15
|
+
* tidak perlu di-render di UI form
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const runner = require('../../lib/migrate/migrate-runner');
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
resource: 'payload',
|
|
22
|
+
verb: 'migrate',
|
|
23
|
+
description: 'Convert backend payload (RDF) file into frontend payload (UDF) for the designer',
|
|
24
|
+
category: 'generation',
|
|
25
|
+
flags: {
|
|
26
|
+
name: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
required: true,
|
|
29
|
+
description: 'Backend payload file name (e.g. visitors.json). Relative to cwd or cwd/payload/.'
|
|
30
|
+
},
|
|
31
|
+
output: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
required: false,
|
|
34
|
+
default: null,
|
|
35
|
+
description: 'Output directory (the file will be written with the same name as --name inside it). If ending with `.json`, treated as an explicit file path. Default: frontend/payload/'
|
|
36
|
+
},
|
|
37
|
+
config: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
required: false,
|
|
40
|
+
default: null,
|
|
41
|
+
description: 'Database config file (.env). Used to read SERVER_ADDRESS and SERVER_PORT. Falls back to `.restforge/defaults.json`.'
|
|
42
|
+
},
|
|
43
|
+
project: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
required: true,
|
|
46
|
+
description: 'Project name (kebab-case code) used as the path segment in apiBaseUrl: http://{host}:{port}/api/{project}'
|
|
47
|
+
},
|
|
48
|
+
'app-name': {
|
|
49
|
+
type: 'string',
|
|
50
|
+
required: false,
|
|
51
|
+
default: null,
|
|
52
|
+
description: 'Application name (default: derived from --project in Title Case, e.g. "visitors-app" -> "Visitors App")'
|
|
53
|
+
},
|
|
54
|
+
'app-code': {
|
|
55
|
+
type: 'string',
|
|
56
|
+
required: false,
|
|
57
|
+
default: null,
|
|
58
|
+
description: 'Application code in kebab-case (default: follows --project)'
|
|
59
|
+
},
|
|
60
|
+
plugin: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
required: false,
|
|
63
|
+
default: null,
|
|
64
|
+
description: 'Designer plugin ID (default: "vanilla-js-basic")'
|
|
65
|
+
},
|
|
66
|
+
port: {
|
|
67
|
+
type: 'number',
|
|
68
|
+
required: false,
|
|
69
|
+
default: null,
|
|
70
|
+
description: 'Frontend application port written to appConfig.port (default: 8000). Independent from the backend port used in apiBaseUrl.'
|
|
71
|
+
},
|
|
72
|
+
overwrite: {
|
|
73
|
+
type: 'boolean',
|
|
74
|
+
required: false,
|
|
75
|
+
default: false,
|
|
76
|
+
description: 'Overwrite the output file if it already exists'
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
examples: [
|
|
80
|
+
'npx restforge payload migrate --name=visitors.json --output=..\\sandbox\\frontend\\payload --config=db.env --project=myapp',
|
|
81
|
+
'npx restforge payload migrate --name=visitors.json --project=myapp --overwrite'
|
|
82
|
+
],
|
|
83
|
+
async handler(args) {
|
|
84
|
+
await runner.run({
|
|
85
|
+
name: args.name,
|
|
86
|
+
output: args.output || null,
|
|
87
|
+
config: args.config || null,
|
|
88
|
+
project: args.project,
|
|
89
|
+
appName: args['app-name'] || null,
|
|
90
|
+
appCode: args['app-code'] || null,
|
|
91
|
+
plugin: args.plugin || null,
|
|
92
|
+
port: typeof args.port === 'number' ? args.port : null,
|
|
93
|
+
overwrite: args.overwrite === true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Live database schema discovery: list semua tabel (dan view) dari database
|
|
7
7
|
* yang ter-konfigurasi di file .env. Agnostic terhadap PostgreSQL, MySQL, dan
|
|
8
|
-
* Oracle.
|
|
8
|
+
* Oracle.
|
|
9
|
+
*
|
|
10
|
+
* Output default berupa table human-readable yang di-group per schema. Output
|
|
11
|
+
* JSON (untuk konsumsi AI agent / mcp-server) tersedia via `--format=json`.
|
|
9
12
|
*
|
|
10
13
|
* Inline migration v4.0.0: business logic dari dbschema-list.js
|
|
11
14
|
* dipindah ke handler. parseArguments/showHelp/process.exit dihilangkan
|
|
@@ -15,6 +18,52 @@
|
|
|
15
18
|
const { DatabaseIntrospector } = require('../../lib/utils/database-introspector');
|
|
16
19
|
const { resolveConfig, printDefaultConfigWarning } = require('../../lib/utils/config-resolver');
|
|
17
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Render daftar tabel ke format table human-readable, di-group per schema.
|
|
23
|
+
* @param {{schema:string,name:string,type:string}[]} tables
|
|
24
|
+
* @param {string[]} schemas
|
|
25
|
+
* @param {string} dbType
|
|
26
|
+
*/
|
|
27
|
+
function renderHumanTable(tables, schemas, dbType) {
|
|
28
|
+
const lines = [];
|
|
29
|
+
|
|
30
|
+
if (tables.length === 0) {
|
|
31
|
+
lines.push('');
|
|
32
|
+
lines.push(`No tables found (database: ${dbType}).`);
|
|
33
|
+
lines.push('');
|
|
34
|
+
return lines.join('\n');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const COL_NAME = 36;
|
|
38
|
+
const COL_TYPE = 8;
|
|
39
|
+
|
|
40
|
+
for (const schema of schemas) {
|
|
41
|
+
const inSchema = tables.filter(t => t.schema === schema);
|
|
42
|
+
if (inSchema.length === 0) continue;
|
|
43
|
+
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push(`schema: ${schema}`);
|
|
46
|
+
lines.push('');
|
|
47
|
+
lines.push('Object Name'.padEnd(COL_NAME) + '| Type');
|
|
48
|
+
lines.push('-'.repeat(COL_NAME) + '+' + '-'.repeat(COL_TYPE));
|
|
49
|
+
|
|
50
|
+
for (const t of inSchema) {
|
|
51
|
+
const name = t.name.length > COL_NAME - 1
|
|
52
|
+
? t.name.substring(0, COL_NAME - 3) + '..'
|
|
53
|
+
: t.name;
|
|
54
|
+
lines.push(name.padEnd(COL_NAME) + '| ' + t.type);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const schemaWord = schemas.length === 1 ? 'schema' : 'schemas';
|
|
59
|
+
const tableWord = tables.length === 1 ? 'table' : 'tables';
|
|
60
|
+
lines.push('');
|
|
61
|
+
lines.push(`Total: ${tables.length} ${tableWord} in ${schemas.length} ${schemaWord} (database: ${dbType})`);
|
|
62
|
+
lines.push('');
|
|
63
|
+
|
|
64
|
+
return lines.join('\n');
|
|
65
|
+
}
|
|
66
|
+
|
|
18
67
|
module.exports = {
|
|
19
68
|
resource: 'schema',
|
|
20
69
|
verb: 'list',
|
|
@@ -39,16 +88,23 @@ module.exports = {
|
|
|
39
88
|
default: false,
|
|
40
89
|
description: 'Sertakan system schemas'
|
|
41
90
|
},
|
|
91
|
+
format: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
required: false,
|
|
94
|
+
default: 'table',
|
|
95
|
+
description: 'Format output: `table` (human-readable, di-group per schema) atau `json` (untuk AI agent / mcp-server)'
|
|
96
|
+
},
|
|
42
97
|
pretty: {
|
|
43
98
|
type: 'boolean',
|
|
44
99
|
required: false,
|
|
45
100
|
default: true,
|
|
46
|
-
description: 'Pretty-print output JSON'
|
|
101
|
+
description: 'Pretty-print output JSON (hanya berlaku saat --format=json)'
|
|
47
102
|
}
|
|
48
103
|
},
|
|
49
104
|
examples: [
|
|
50
105
|
'npx restforge schema list --config=db.env',
|
|
51
|
-
'npx restforge schema list --config=db.env --schema=public'
|
|
106
|
+
'npx restforge schema list --config=db.env --schema=public',
|
|
107
|
+
'npx restforge schema list --config=db.env --format=json'
|
|
52
108
|
],
|
|
53
109
|
async handler(args) {
|
|
54
110
|
const resolved = resolveConfig(args.config, process.cwd());
|
|
@@ -89,21 +145,29 @@ module.exports = {
|
|
|
89
145
|
type: t.type
|
|
90
146
|
}));
|
|
91
147
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
148
|
+
const format = (args.format || 'table').toLowerCase();
|
|
149
|
+
|
|
150
|
+
if (format === 'json') {
|
|
151
|
+
const output = {
|
|
152
|
+
schemaVersion: '1.0',
|
|
153
|
+
source: 'dbschema-list',
|
|
154
|
+
summary: {
|
|
155
|
+
totalTables: tablesOut.length,
|
|
156
|
+
schemas,
|
|
157
|
+
database: introspector.dbType
|
|
158
|
+
},
|
|
159
|
+
tables: tablesOut
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const json = args.pretty
|
|
163
|
+
? JSON.stringify(output, null, 2)
|
|
164
|
+
: JSON.stringify(output);
|
|
165
|
+
process.stdout.write(json + '\n');
|
|
166
|
+
} else {
|
|
167
|
+
process.stdout.write(
|
|
168
|
+
renderHumanTable(tablesOut, schemas, introspector.dbType) + '\n'
|
|
169
|
+
);
|
|
170
|
+
}
|
|
107
171
|
} catch (error) {
|
|
108
172
|
console.error(`Error: ${error.message}`);
|
|
109
173
|
if (process.env.DEBUG) {
|
|
@@ -208,9 +208,11 @@ module.exports = {
|
|
|
208
208
|
console.log('');
|
|
209
209
|
}
|
|
210
210
|
console.log('Dry-run complete. No changes applied.');
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
211
|
+
// Dry-run sukses: selesai bersih (exit 0) tanpa melempar error.
|
|
212
|
+
// Sebelumnya throw exitCode=2 dipakai sebagai sinyal "no changes",
|
|
213
|
+
// tetapi menampilkan baris "Error: ..." menyesatkan user padahal
|
|
214
|
+
// tidak ada kegagalan.
|
|
215
|
+
return;
|
|
214
216
|
}
|
|
215
217
|
|
|
216
218
|
if (statements.length === 0) {
|
|
@@ -218,6 +220,24 @@ module.exports = {
|
|
|
218
220
|
return;
|
|
219
221
|
}
|
|
220
222
|
|
|
223
|
+
// ------------------------------------------------------------------
|
|
224
|
+
// Konfirmasi destruktif untuk mode --drop (apply nyata saja; dry-run
|
|
225
|
+
// sudah return di atas). Dialog y/N hanya ditampilkan di terminal
|
|
226
|
+
// interaktif (TTY) dengan default No. Pada mode non-interaktif (CI/pipe)
|
|
227
|
+
// prompt dilewati agar proses tidak hang, perilaku apply tetap seperti
|
|
228
|
+
// sebelumnya.
|
|
229
|
+
// ------------------------------------------------------------------
|
|
230
|
+
if (args.drop === true) {
|
|
231
|
+
const { isInteractive, promptYesNo } = require('../../../src/utils/db-bootstrap');
|
|
232
|
+
if (isInteractive()) {
|
|
233
|
+
const confirmed = await promptYesNo('Drop and re-create all tables now? Existing data will be lost. (y/N): ');
|
|
234
|
+
if (!confirmed) {
|
|
235
|
+
console.log('Aborted by user. No changes applied.');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
221
241
|
// ------------------------------------------------------------------
|
|
222
242
|
// Pre-check database existence (khusus postgres/mysql).
|
|
223
243
|
// Bila database tujuan tidak ada, tawarkan pembuatan otomatis via
|