@restforgejs/platform 5.1.20 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build-info.json +2 -2
- package/cli/consumer-deploy.js +1 -1
- package/cli/consumer.js +1 -1
- package/generators/cli/catalog/dashboard.js +1 -1
- package/generators/cli/catalog/dbschema.js +3 -3
- package/generators/cli/catalog/field-validation.js +1 -1
- package/generators/cli/catalog/query-declarative.js +1 -1
- package/generators/cli/config/clear-default.js +1 -1
- package/generators/cli/config/get-default.js +1 -1
- package/generators/cli/config/list.js +1 -1
- package/generators/cli/config/schema.js +1 -1
- package/generators/cli/config/set-default.js +2 -2
- package/generators/cli/config/template.js +1 -1
- package/generators/cli/dashboard/create.js +7 -7
- package/generators/cli/data/pull.js +12 -12
- package/generators/cli/data/push.js +9 -9
- package/generators/cli/endpoint/create.js +11 -11
- package/generators/cli/endpoint/list.js +3 -3
- package/generators/cli/fast-track.js +7 -7
- package/generators/cli/init.js +2 -2
- package/generators/cli/kafka/consumer-create.js +5 -5
- package/generators/cli/key/generate.js +3 -3
- package/generators/cli/key/list.js +2 -2
- package/generators/cli/key/revoke.js +3 -3
- package/generators/cli/payload/diff.js +3 -3
- package/generators/cli/payload/generate.js +5 -5
- package/generators/cli/payload/sync.js +5 -5
- package/generators/cli/payload/validate.js +3 -3
- package/generators/cli/processor/create.js +7 -7
- package/generators/cli/processor/list.js +3 -3
- package/generators/cli/project/delete.js +2 -2
- package/generators/cli/project/list.js +1 -1
- package/generators/cli/query/validate.js +3 -3
- package/generators/cli/schema/apply.js +13 -13
- package/generators/cli/schema/describe.js +6 -6
- package/generators/cli/schema/diff.js +10 -10
- package/generators/cli/schema/generate-ddl.js +11 -11
- package/generators/cli/schema/init.js +95 -95
- package/generators/cli/schema/introspect.js +8 -8
- package/generators/cli/schema/list.js +6 -6
- package/generators/cli/schema/migrate.js +91 -13
- package/generators/cli/schema/models.js +6 -6
- package/generators/cli/schema/template.js +223 -222
- package/generators/cli/schema/validate.js +6 -6
- package/generators/cli/test/generate.js +6 -6
- package/generators/lib/dbschema-kit/apply-executor.js +20 -0
- package/generators/lib/dbschema-kit/introspect-mapper.js +20 -0
- package/generators/lib/generators/processor-validation-generator.js +4 -1
- package/generators/lib/migrate/field-type-resolver.js +23 -0
- package/generators/lib/payload/payload-runner.js +17 -3
- package/generators/lib/templates/dashboard-catalog.js +1 -1
- package/generators/lib/templates/db-connection-env.js +1 -1
- package/generators/lib/templates/dbschema-catalog.js +1 -1
- package/generators/lib/templates/field-validation-catalog.js +1 -1
- package/generators/lib/templates/mysql-template.js +1 -1
- package/generators/lib/templates/oracle-template.js +1 -1
- package/generators/lib/templates/postgres-template.js +1 -1
- package/generators/lib/templates/query-declarative-catalog.js +1 -1
- package/generators/lib/templates/sqlite-template.js +1 -1
- package/integrity-manifest.json +18 -18
- package/package.json +1 -1
- package/scripts/verify-integrity.js +1 -1
- package/server.js +1 -1
- package/src/components/handlers/adjust_handler.js +1 -1
- package/src/components/handlers/audit_handler.js +1 -1
- package/src/components/handlers/delete_handler.js +1 -1
- package/src/components/handlers/export_handler.js +1 -1
- package/src/components/handlers/import_handler.js +1 -1
- package/src/components/handlers/insert_handler.js +1 -1
- package/src/components/handlers/update_handler.js +1 -1
- package/src/components/handlers/upload_handler.js +1 -1
- package/src/components/handlers/workflow_handler.js +1 -1
- package/src/components/integrations/webhook.js +1 -1
- package/src/consumers/baseConsumer.js +1 -1
- package/src/consumers/declarativeMapper.js +1 -1
- package/src/consumers/handlers/apiHandler.js +1 -1
- package/src/consumers/handlers/consoleHandler.js +1 -1
- package/src/consumers/handlers/databaseHandler.js +1 -1
- package/src/consumers/handlers/index.js +1 -1
- package/src/consumers/handlers/kafkaHandler.js +1 -1
- package/src/consumers/index.js +1 -1
- package/src/consumers/messageTransformer.js +1 -1
- package/src/consumers/validator.js +1 -1
- package/src/core/db/dialect/base-dialect.js +1 -1
- package/src/core/db/dialect/index.js +1 -1
- package/src/core/db/dialect/mysql-dialect.js +1 -1
- package/src/core/db/dialect/oracle-dialect.js +1 -1
- package/src/core/db/dialect/postgres-dialect.js +1 -1
- package/src/core/db/dialect/sqlite-dialect.js +1 -1
- package/src/core/db/flatten-helper.js +1 -1
- package/src/core/db/query-builder-error.js +1 -1
- package/src/core/db/query-builder.js +1 -1
- package/src/core/db/relation-helper.js +1 -1
- package/src/core/handlers/delete_handler.js +1 -1
- package/src/core/handlers/insert_handler.js +1 -1
- package/src/core/handlers/update_handler.js +1 -1
- package/src/core/models/base-model.js +1 -1
- package/src/core/utils/cache-manager.js +1 -1
- package/src/core/utils/component-engine.js +1 -1
- package/src/core/utils/context-builder.js +1 -1
- package/src/core/utils/datetime-formatter.js +1 -1
- package/src/core/utils/datetime-parser.js +1 -1
- package/src/core/utils/db.js +1 -1
- package/src/core/utils/logger.js +1 -1
- package/src/core/utils/payload-loader.js +1 -1
- package/src/core/utils/security-checks.js +1 -1
- package/src/middleware/body-options.js +1 -1
- package/src/middleware/cors.js +1 -1
- package/src/middleware/idempotency.js +1 -1
- package/src/middleware/rate-limiter.js +1 -1
- package/src/middleware/request-logger.js +1 -1
- package/src/middleware/security-headers.js +1 -1
- package/src/models/base-model-mysql.js +1 -1
- package/src/models/base-model-oracle.js +1 -1
- package/src/models/base-model-sqlite.js +1 -1
- package/src/models/base-model.js +1 -1
- package/src/pro/caching/redis-client.js +1 -1
- package/src/pro/caching/redis-helper.js +1 -1
- package/src/pro/consumers/baseConsumer.js +1 -1
- package/src/pro/consumers/declarativeMapper.js +1 -1
- package/src/pro/consumers/handlers/apiHandler.js +1 -1
- package/src/pro/consumers/handlers/consoleHandler.js +1 -1
- package/src/pro/consumers/handlers/databaseHandler.js +1 -1
- package/src/pro/consumers/handlers/index.js +1 -1
- package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
- package/src/pro/consumers/index.js +1 -1
- package/src/pro/consumers/messageTransformer.js +1 -1
- package/src/pro/consumers/validator.js +1 -1
- package/src/pro/database/base-model-mysql.js +1 -1
- package/src/pro/database/base-model-oracle.js +1 -1
- package/src/pro/database/base-model-sqlite.js +1 -1
- package/src/pro/database/db-mysql.js +1 -1
- package/src/pro/database/db-oracle.js +1 -1
- package/src/pro/database/db-sqlite.js +1 -1
- package/src/pro/excel/excel-generator.js +1 -1
- package/src/pro/excel/excel-parser.js +1 -1
- package/src/pro/excel/export-service.js +1 -1
- package/src/pro/excel/export_handler.js +1 -1
- package/src/pro/excel/import-service.js +1 -1
- package/src/pro/excel/import-validator.js +1 -1
- package/src/pro/excel/import_handler.js +1 -1
- package/src/pro/excel/upsert-builder.js +1 -1
- package/src/pro/idgen/idgen-routes.js +1 -1
- package/src/pro/integrations/lookup-resolver.js +1 -1
- package/src/pro/integrations/upload-handler-v2.js +1 -1
- package/src/pro/integrations/upload-handler.js +1 -1
- package/src/pro/integrations/webhook.js +1 -1
- package/src/pro/locking/lock-routes.js +1 -1
- package/src/pro/locking/resource-lock-manager.js +1 -1
- package/src/pro/messaging/kafkaConsumerService.js +1 -1
- package/src/pro/messaging/kafkaService.js +1 -1
- package/src/pro/messaging/messagehubService.js +1 -1
- package/src/pro/messaging/rabbitmqService.js +1 -1
- package/src/pro/scheduler/job-manager.js +1 -1
- package/src/pro/scheduler/job-routes.js +1 -1
- package/src/pro/scheduler/job-validator.js +1 -1
- package/src/pro/storage/base-storage-provider.js +1 -1
- package/src/pro/storage/file-metadata-helper.js +1 -1
- package/src/pro/storage/index.js +1 -1
- package/src/pro/storage/local-storage-provider.js +1 -1
- package/src/pro/storage/s3-storage-provider.js +1 -1
- package/src/pro/storage/upload-cleanup-job.js +1 -1
- package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
- package/src/pro/storage/upload-pending-tracker.js +1 -1
- package/src/pro/websocket/broadcast-helper.js +1 -1
- package/src/pro/websocket/index.js +1 -1
- package/src/pro/websocket/livesync-server.js +1 -1
- package/src/pro/websocket/ws-broadcaster.js +1 -1
- package/src/services/export-service.js +1 -1
- package/src/services/import-service.js +1 -1
- package/src/services/kafkaConsumerService.js +1 -1
- package/src/services/kafkaService.js +1 -1
- package/src/services/messagehubService.js +1 -1
- package/src/services/rabbitmqService.js +1 -1
- package/src/utils/cache-invalidation-registry.js +1 -1
- package/src/utils/cache-manager.js +1 -1
- package/src/utils/component-engine.js +1 -1
- package/src/utils/config-extractor.js +1 -1
- package/src/utils/consumerLogger.js +1 -1
- package/src/utils/context-builder.js +1 -1
- package/src/utils/dashboard-helpers.js +1 -1
- package/src/utils/dateHelper.js +1 -1
- package/src/utils/datetime-formatter.js +1 -1
- package/src/utils/datetime-parser.js +1 -1
- package/src/utils/db-bootstrap.js +1 -1
- package/src/utils/db-mysql.js +1 -1
- package/src/utils/db-oracle.js +1 -1
- package/src/utils/db-sqlite.js +1 -1
- package/src/utils/db.js +1 -1
- package/src/utils/demo-generator.js +1 -1
- package/src/utils/excel-generator.js +1 -1
- package/src/utils/excel-parser.js +1 -1
- package/src/utils/file-watcher.js +1 -1
- package/src/utils/id-generator.js +1 -1
- package/src/utils/idempotency-manager.js +1 -1
- package/src/utils/import-validator.js +1 -1
- package/src/utils/license-client.js +1 -1
- package/src/utils/lock-manager.js +1 -1
- package/src/utils/logger.js +1 -1
- package/src/utils/lookup-resolver.js +1 -1
- package/src/utils/payload-loader.js +1 -1
- package/src/utils/processor-response.js +1 -1
- package/src/utils/rabbitmq.js +1 -1
- package/src/utils/redis-client.js +1 -1
- package/src/utils/redis-helper.js +1 -1
- package/src/utils/request-scope.js +1 -1
- package/src/utils/security-checks.js +1 -1
- package/src/utils/service-resolver.js +1 -1
- package/src/utils/shutdown-coordinator.js +1 -1
- package/src/utils/soft-delete-dashboard-guard.js +1 -1
- package/src/utils/sql-table-extractor.js +1 -1
- package/src/utils/trusted-keys.js +1 -1
- package/src/utils/upload-handler.js +1 -1
- package/src/utils/upsert-builder.js +1 -1
- package/src/utils/workflow-hook-executor.js +1 -1
|
@@ -1,222 +1,223 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Contract: schema template
|
|
5
|
-
*
|
|
6
|
-
* Browse, preview, dan generate template schema dari koleksi RestForge Schema
|
|
7
|
-
* Reference (85 template, 30 domain, 33 section). Verb ini bertindak sebagai
|
|
8
|
-
* wrapper terhadap binary native `sdf-tools.exe` yang di-ship melalui folder
|
|
9
|
-
* bin/. Semua filter dan display flag diteruskan ke binary; help text di sisi
|
|
10
|
-
* Node mempertahankan kontrak CLI (contract validator + help generator).
|
|
11
|
-
*
|
|
12
|
-
* Binary lookup: <package-root>/bin/sdf-tools.exe relatif terhadap file ini
|
|
13
|
-
* (resolusi sama untuk source workspace dan installation di node_modules).
|
|
14
|
-
*
|
|
15
|
-
* Platform: saat ini hanya Windows (sdf-tools.exe). Pemanggilan di non-Windows
|
|
16
|
-
* akan return error eksplisit, bukan crash diam-diam.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const fs = require('fs');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
const { spawnSync } = require('child_process');
|
|
23
|
-
|
|
24
|
-
const VALUE_FLAGS = ['domain', 'table', 'category', 'pattern', 'section', 'lang', '
|
|
25
|
-
const BOOLEAN_FLAGS = [
|
|
26
|
-
'has-sdf',
|
|
27
|
-
'no-sdf',
|
|
28
|
-
'show',
|
|
29
|
-
'example',
|
|
30
|
-
'generate',
|
|
31
|
-
'force',
|
|
32
|
-
'list-domains',
|
|
33
|
-
'list-categories',
|
|
34
|
-
'list-sections',
|
|
35
|
-
'stats'
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
function resolveBinaryPath() {
|
|
39
|
-
if (os.platform() !== 'win32') return null;
|
|
40
|
-
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools.exe');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function buildBinaryArgs(args) {
|
|
44
|
-
const out = [];
|
|
45
|
-
for (const name of VALUE_FLAGS) {
|
|
46
|
-
const value = args[name];
|
|
47
|
-
if (value === undefined || value === null || value === '') continue;
|
|
48
|
-
out.push(`--${name}=${value}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
'npx restforge schema template
|
|
176
|
-
'npx restforge schema template --domain=erp
|
|
177
|
-
'npx restforge schema template --
|
|
178
|
-
'npx restforge schema template --table=sales_order --show
|
|
179
|
-
'npx restforge schema template --table=sales_order --
|
|
180
|
-
'npx restforge schema template --
|
|
181
|
-
'npx restforge schema template --
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
err
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
err
|
|
218
|
-
err.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contract: schema template
|
|
5
|
+
*
|
|
6
|
+
* Browse, preview, dan generate template schema dari koleksi RestForge Schema
|
|
7
|
+
* Reference (85 template, 30 domain, 33 section). Verb ini bertindak sebagai
|
|
8
|
+
* wrapper terhadap binary native `sdf-tools.exe` yang di-ship melalui folder
|
|
9
|
+
* bin/. Semua filter dan display flag diteruskan ke binary; help text di sisi
|
|
10
|
+
* Node mempertahankan kontrak CLI (contract validator + help generator).
|
|
11
|
+
*
|
|
12
|
+
* Binary lookup: <package-root>/bin/sdf-tools.exe relatif terhadap file ini
|
|
13
|
+
* (resolusi sama untuk source workspace dan installation di node_modules).
|
|
14
|
+
*
|
|
15
|
+
* Platform: saat ini hanya Windows (sdf-tools.exe). Pemanggilan di non-Windows
|
|
16
|
+
* akan return error eksplisit, bukan crash diam-diam.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { spawnSync } = require('child_process');
|
|
23
|
+
|
|
24
|
+
const VALUE_FLAGS = ['domain', 'table', 'category', 'pattern', 'section', 'lang', 'format'];
|
|
25
|
+
const BOOLEAN_FLAGS = [
|
|
26
|
+
'has-sdf',
|
|
27
|
+
'no-sdf',
|
|
28
|
+
'show',
|
|
29
|
+
'example',
|
|
30
|
+
'generate',
|
|
31
|
+
'force',
|
|
32
|
+
'list-domains',
|
|
33
|
+
'list-categories',
|
|
34
|
+
'list-sections',
|
|
35
|
+
'stats'
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
function resolveBinaryPath() {
|
|
39
|
+
if (os.platform() !== 'win32') return null;
|
|
40
|
+
return path.resolve(__dirname, '..', '..', '..', 'bin', 'sdf-tools.exe');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildBinaryArgs(args) {
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const name of VALUE_FLAGS) {
|
|
46
|
+
const value = args[name];
|
|
47
|
+
if (value === undefined || value === null || value === '') continue;
|
|
48
|
+
out.push(`--${name}=${value}`);
|
|
49
|
+
}
|
|
50
|
+
if (args['schema-path']) out.push(`--path=${args['schema-path']}`);
|
|
51
|
+
for (const name of BOOLEAN_FLAGS) {
|
|
52
|
+
if (args[name] === true) {
|
|
53
|
+
out.push(`--${name}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = {
|
|
60
|
+
resource: 'schema',
|
|
61
|
+
verb: 'template',
|
|
62
|
+
description: 'Browse, preview, and generate schema templates from the RestForge Schema Reference collection',
|
|
63
|
+
category: 'utility',
|
|
64
|
+
flags: {
|
|
65
|
+
domain: {
|
|
66
|
+
type: 'string',
|
|
67
|
+
required: false,
|
|
68
|
+
default: null,
|
|
69
|
+
description: 'Filter by domain (csv, e.g., erp or erp,finance)'
|
|
70
|
+
},
|
|
71
|
+
table: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
required: false,
|
|
74
|
+
default: null,
|
|
75
|
+
description: 'Filter by table name (wildcard glob: sales*, *_invoice)'
|
|
76
|
+
},
|
|
77
|
+
category: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
required: false,
|
|
80
|
+
default: null,
|
|
81
|
+
description: 'Filter by category: master-data or transactional'
|
|
82
|
+
},
|
|
83
|
+
pattern: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
required: false,
|
|
86
|
+
default: null,
|
|
87
|
+
description: 'Filter by pattern: single-table or master-detail'
|
|
88
|
+
},
|
|
89
|
+
section: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
required: false,
|
|
92
|
+
default: null,
|
|
93
|
+
description: 'Filter by section code (see --list-sections)'
|
|
94
|
+
},
|
|
95
|
+
'has-sdf': {
|
|
96
|
+
type: 'boolean',
|
|
97
|
+
required: false,
|
|
98
|
+
default: false,
|
|
99
|
+
description: 'Filter only templates that have an SDF version'
|
|
100
|
+
},
|
|
101
|
+
'no-sdf': {
|
|
102
|
+
type: 'boolean',
|
|
103
|
+
required: false,
|
|
104
|
+
default: false,
|
|
105
|
+
description: 'Filter only templates that do not have an SDF version (gap analysis)'
|
|
106
|
+
},
|
|
107
|
+
show: {
|
|
108
|
+
type: 'boolean',
|
|
109
|
+
required: false,
|
|
110
|
+
default: false,
|
|
111
|
+
description: 'Print schema template (requires --table=<specific_name>)'
|
|
112
|
+
},
|
|
113
|
+
example: {
|
|
114
|
+
type: 'boolean',
|
|
115
|
+
required: false,
|
|
116
|
+
default: false,
|
|
117
|
+
description: 'Include sample data section (use with --show)'
|
|
118
|
+
},
|
|
119
|
+
lang: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
required: false,
|
|
122
|
+
default: null,
|
|
123
|
+
description: 'Schema format: sdf (default) or sql'
|
|
124
|
+
},
|
|
125
|
+
generate: {
|
|
126
|
+
type: 'boolean',
|
|
127
|
+
required: false,
|
|
128
|
+
default: false,
|
|
129
|
+
description: 'Generate template to filesystem (requires --table and --schema-path)'
|
|
130
|
+
},
|
|
131
|
+
'schema-path': {
|
|
132
|
+
type: 'string',
|
|
133
|
+
required: false,
|
|
134
|
+
default: null,
|
|
135
|
+
description: 'Destination path for --generate (directory or file)'
|
|
136
|
+
},
|
|
137
|
+
force: {
|
|
138
|
+
type: 'boolean',
|
|
139
|
+
required: false,
|
|
140
|
+
default: false,
|
|
141
|
+
description: 'Overwrite existing destination file when using --generate'
|
|
142
|
+
},
|
|
143
|
+
'list-domains': {
|
|
144
|
+
type: 'boolean',
|
|
145
|
+
required: false,
|
|
146
|
+
default: false,
|
|
147
|
+
description: 'List all available application domains'
|
|
148
|
+
},
|
|
149
|
+
'list-categories': {
|
|
150
|
+
type: 'boolean',
|
|
151
|
+
required: false,
|
|
152
|
+
default: false,
|
|
153
|
+
description: 'List all template categories'
|
|
154
|
+
},
|
|
155
|
+
'list-sections': {
|
|
156
|
+
type: 'boolean',
|
|
157
|
+
required: false,
|
|
158
|
+
default: false,
|
|
159
|
+
description: 'List all sections with their categories'
|
|
160
|
+
},
|
|
161
|
+
stats: {
|
|
162
|
+
type: 'boolean',
|
|
163
|
+
required: false,
|
|
164
|
+
default: false,
|
|
165
|
+
description: 'Show collection statistics (per category, pattern, domain, section)'
|
|
166
|
+
},
|
|
167
|
+
format: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
required: false,
|
|
170
|
+
default: null,
|
|
171
|
+
description: 'Output format: table (default), plain, or json'
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
examples: [
|
|
175
|
+
'npx restforge schema template',
|
|
176
|
+
'npx restforge schema template --domain=erp',
|
|
177
|
+
'npx restforge schema template --domain=erp,inventory --category=master-data',
|
|
178
|
+
'npx restforge schema template --table=sales_order --show',
|
|
179
|
+
'npx restforge schema template --table=sales_order --show --lang=sql',
|
|
180
|
+
'npx restforge schema template --table=sales_order --generate --schema-path=./schema --lang=sdf',
|
|
181
|
+
'npx restforge schema template --stats',
|
|
182
|
+
'npx restforge schema template --list-domains'
|
|
183
|
+
],
|
|
184
|
+
async handler(args) {
|
|
185
|
+
const binaryPath = resolveBinaryPath();
|
|
186
|
+
if (!binaryPath) {
|
|
187
|
+
const err = new Error(
|
|
188
|
+
`schema template hanya tersedia di Windows (sdf-tools.exe). Platform saat ini: ${os.platform()}`
|
|
189
|
+
);
|
|
190
|
+
err.exitCode = 3;
|
|
191
|
+
throw err;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!fs.existsSync(binaryPath)) {
|
|
195
|
+
const err = new Error(
|
|
196
|
+
`sdf-tools.exe tidak ditemukan di ${binaryPath}. ` +
|
|
197
|
+
'Pastikan binary sudah di-build dan tersedia di folder bin/ package.'
|
|
198
|
+
);
|
|
199
|
+
err.exitCode = 3;
|
|
200
|
+
throw err;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const binaryArgs = buildBinaryArgs(args);
|
|
204
|
+
const result = spawnSync(binaryPath, binaryArgs, {
|
|
205
|
+
stdio: 'inherit',
|
|
206
|
+
windowsHide: true
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (result.error) {
|
|
210
|
+
const err = new Error(`Gagal menjalankan sdf-tools.exe: ${result.error.message}`);
|
|
211
|
+
err.exitCode = 1;
|
|
212
|
+
throw err;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const status = typeof result.status === 'number' ? result.status : 1;
|
|
216
|
+
if (status !== 0) {
|
|
217
|
+
const err = new Error(`sdf-tools.exe exit code ${status}`);
|
|
218
|
+
err.exitCode = status;
|
|
219
|
+
err.silent = true;
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
@@ -63,21 +63,21 @@ function printSuccessLines(absPath, models) {
|
|
|
63
63
|
module.exports = {
|
|
64
64
|
resource: 'schema',
|
|
65
65
|
verb: 'validate',
|
|
66
|
-
description: '
|
|
66
|
+
description: 'Validate schema definition files (single-model and cross-model)',
|
|
67
67
|
category: 'introspection',
|
|
68
68
|
flags: {
|
|
69
|
-
path: {
|
|
69
|
+
'schema-path': {
|
|
70
70
|
type: 'string',
|
|
71
71
|
required: true,
|
|
72
|
-
description: 'Path file
|
|
72
|
+
description: 'Path to schema file or directory (e.g., ./schema or ./schema/users.js)'
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
75
|
examples: [
|
|
76
|
-
'npx restforge schema validate --path=./schema',
|
|
77
|
-
'npx restforge schema validate --path=./my-schema'
|
|
76
|
+
'npx restforge schema validate --schema-path=./schema',
|
|
77
|
+
'npx restforge schema validate --schema-path=./my-schema'
|
|
78
78
|
],
|
|
79
79
|
async handler(args) {
|
|
80
|
-
const schemaPath = args
|
|
80
|
+
const schemaPath = args['schema-path'];
|
|
81
81
|
const absPath = path.resolve(process.cwd(), schemaPath);
|
|
82
82
|
|
|
83
83
|
let models;
|
|
@@ -145,36 +145,36 @@ function handleInit(args) {
|
|
|
145
145
|
module.exports = {
|
|
146
146
|
resource: 'test',
|
|
147
147
|
verb: 'generate',
|
|
148
|
-
description: 'Generate integration test file (Jest + Supertest)
|
|
148
|
+
description: 'Generate an integration test file (Jest + Supertest) for an endpoint',
|
|
149
149
|
category: 'generation',
|
|
150
150
|
flags: {
|
|
151
151
|
project: {
|
|
152
152
|
type: 'string',
|
|
153
153
|
required: true,
|
|
154
|
-
description: '
|
|
154
|
+
description: 'Target project name'
|
|
155
155
|
},
|
|
156
156
|
endpoint: {
|
|
157
157
|
type: 'string',
|
|
158
158
|
required: true,
|
|
159
|
-
description: '
|
|
159
|
+
description: 'Endpoint name to test'
|
|
160
160
|
},
|
|
161
161
|
port: {
|
|
162
162
|
type: 'number',
|
|
163
163
|
required: false,
|
|
164
164
|
default: 3000,
|
|
165
|
-
description: '
|
|
165
|
+
description: 'Server port when running tests'
|
|
166
166
|
},
|
|
167
167
|
init: {
|
|
168
168
|
type: 'boolean',
|
|
169
169
|
required: false,
|
|
170
170
|
default: false,
|
|
171
|
-
description: '
|
|
171
|
+
description: 'Initialize test-data.json configuration (global + per-endpoint if endpoint is provided)'
|
|
172
172
|
},
|
|
173
173
|
force: {
|
|
174
174
|
type: 'boolean',
|
|
175
175
|
required: false,
|
|
176
176
|
default: false,
|
|
177
|
-
description: '
|
|
177
|
+
description: 'Overwrite existing test files'
|
|
178
178
|
}
|
|
179
179
|
},
|
|
180
180
|
examples: [
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
3
6
|
const { loadDriver } = require('./driver-loader');
|
|
4
7
|
|
|
5
8
|
const VALID_DIALECTS = ['postgres', 'mysql', 'oracle', 'sqlite'];
|
|
@@ -90,8 +93,25 @@ async function connectOracle(driver, config) {
|
|
|
90
93
|
};
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Pastikan folder parent dari path file SQLite ada. Skip untuk database
|
|
98
|
+
* in-memory (:memory:) dan path tanpa folder (file di cwd). Idempoten:
|
|
99
|
+
* mkdir recursive tidak error bila folder sudah ada.
|
|
100
|
+
*/
|
|
101
|
+
function ensureSqliteParentDir(file) {
|
|
102
|
+
if (!file || file === ':memory:') return;
|
|
103
|
+
const dir = path.dirname(file);
|
|
104
|
+
if (!dir || dir === '.' || dir === path.dirname(dir)) return;
|
|
105
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
|
|
93
108
|
async function connectSqlite(driver, config) {
|
|
94
109
|
const SqliteCtor = driver;
|
|
110
|
+
// SQLite membuat file database otomatis, tetapi TIDAK membuat folder
|
|
111
|
+
// parent-nya. Bila path mengandung folder yang belum ada (mis.
|
|
112
|
+
// ./data/app.db dengan ./data belum dibuat), buka koneksi gagal dengan
|
|
113
|
+
// SQLITE_CANTOPEN. Buat folder parent lebih dulu (skip untuk :memory:).
|
|
114
|
+
ensureSqliteParentDir(config.file);
|
|
95
115
|
const db = new SqliteCtor(config.file);
|
|
96
116
|
return {
|
|
97
117
|
exec: async (sql) => db.exec(sql),
|
|
@@ -599,6 +599,26 @@ function parseCheckExpression(rawExpr) {
|
|
|
599
599
|
}
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
+
// PostgreSQL normalises IN-list CHECKs to: (col)::type = ANY ((ARRAY['a'::type, ...]::type[]))
|
|
603
|
+
// This form appears verbatim in pg_get_constraintdef output and is semantically identical to IN (...).
|
|
604
|
+
const pgAnyRe = /^\(?([A-Za-z_][A-Za-z0-9_]*)\)?(?:::\w+(?:\s+\w+)*)?\s*=\s*ANY\s*\((.+)\)\s*$/i;
|
|
605
|
+
const pgAnyM = e.match(pgAnyRe);
|
|
606
|
+
if (pgAnyM) {
|
|
607
|
+
const field = pgAnyM[1].toLowerCase();
|
|
608
|
+
const anyArg = pgAnyM[2];
|
|
609
|
+
const arrOpen = anyArg.toUpperCase().indexOf('ARRAY[');
|
|
610
|
+
if (arrOpen !== -1) {
|
|
611
|
+
const arrClose = anyArg.indexOf(']', arrOpen + 6);
|
|
612
|
+
if (arrClose !== -1) {
|
|
613
|
+
const raw = anyArg.slice(arrOpen + 6, arrClose);
|
|
614
|
+
// strip per-element type casts like ::character varying before parsing
|
|
615
|
+
const stripped = raw.replace(/::\w+(?:\s+\w+)*/g, '');
|
|
616
|
+
const values = parseValueList(stripped);
|
|
617
|
+
if (values) return { field, op: 'in', value: values };
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
602
622
|
return { _unparsable: true, expression: rawExpr };
|
|
603
623
|
}
|
|
604
624
|
|
|
@@ -21,7 +21,7 @@ const SOURCES = ['body', 'params', 'headers'];
|
|
|
21
21
|
|
|
22
22
|
// Tipe yang didukung oleh validator (harus sinkron dengan validatePayloadV2).
|
|
23
23
|
const VALID_TYPES = new Set([
|
|
24
|
-
'string', 'number', 'integer', 'boolean',
|
|
24
|
+
'string', 'text', 'number', 'integer', 'boolean',
|
|
25
25
|
'uuid', 'date', 'datetime', 'array', 'object'
|
|
26
26
|
]);
|
|
27
27
|
|
|
@@ -126,6 +126,9 @@ function buildFollowUpChecks(inputField, messagePrefix, fieldDef) {
|
|
|
126
126
|
if (type && VALID_TYPES.has(type)) {
|
|
127
127
|
switch (type) {
|
|
128
128
|
case 'string':
|
|
129
|
+
case 'text':
|
|
130
|
+
// text divalidasi identik dengan string (unbounded string); pemetaan UI
|
|
131
|
+
// (→ textarea) bukan urusan lapisan validasi ini.
|
|
129
132
|
checks.push({
|
|
130
133
|
condition: `typeof input['${safeField}'] !== 'string'`,
|
|
131
134
|
message: `${messagePrefix} must be a string`
|
|
@@ -311,6 +311,29 @@ class FieldTypeResolver {
|
|
|
311
311
|
};
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
// Rule 8.5: Textarea type-driven (tipe `text` first-class dari RDF).
|
|
315
|
+
// Tipe `text` bersifat UNBOUNDED (phase-01 sengaja tidak menurunkan maxLength),
|
|
316
|
+
// jadi `maxlength` HANYA disertakan bila constraints.maxLength ada nilainya.
|
|
317
|
+
// Tidak memaksa default cap agar konsisten dengan semantik unbounded.
|
|
318
|
+
if (valType === 'text') {
|
|
319
|
+
const extra = { rows: 3 };
|
|
320
|
+
if (typeof constraints.maxLength === 'number') {
|
|
321
|
+
extra.maxlength = constraints.maxLength;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
name: fieldName,
|
|
325
|
+
label,
|
|
326
|
+
fieldType: 'textarea',
|
|
327
|
+
skip: false,
|
|
328
|
+
required,
|
|
329
|
+
inTable,
|
|
330
|
+
tableOrder,
|
|
331
|
+
tableField: null,
|
|
332
|
+
defaultValue: extractDefault(constraints),
|
|
333
|
+
extra
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
314
337
|
// Rule 9: Default → text
|
|
315
338
|
const maxlen = (typeof constraints.maxLength === 'number')
|
|
316
339
|
? constraints.maxLength
|