@restforgejs/platform 5.2.12 → 5.2.16
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/drift-check-linux +0 -0
- package/bin/sdf-tools-linux +0 -0
- 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/fast-track.js +8 -9
- package/generators/cli/project/auth.js +209 -0
- package/generators/lib/auth/component-generator.js +58 -0
- package/generators/lib/auth/dependency-checker.js +102 -0
- package/generators/lib/auth/env-injector.js +81 -0
- package/generators/lib/auth/migrate-runner.js +111 -0
- package/generators/lib/auth/prefix.js +22 -0
- package/generators/lib/auth/processor-generator.js +55 -0
- package/generators/lib/auth/sdf-generator.js +102 -0
- package/generators/lib/auth/template-renderer.js +29 -0
- package/generators/lib/auth/templates/processor/login.js.tmpl +152 -0
- package/generators/lib/auth/templates/processor/logout.js.tmpl +58 -0
- package/generators/lib/auth/templates/processor/me.js.tmpl +64 -0
- package/generators/lib/auth/templates/processor/refresh.js.tmpl +134 -0
- package/generators/lib/auth/templates/processor/register.js.tmpl +77 -0
- package/generators/lib/auth/templates/processor/reset-password.js.tmpl +106 -0
- package/generators/lib/auth/templates/rfx_auth-middleware.js.tmpl +79 -0
- package/generators/lib/auth/templates/rfx_auth.js.tmpl +104 -0
- package/generators/lib/dbschema-kit/schema-printer.js +10 -1
- 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
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* CMD baru (Windows).
|
|
17
17
|
*
|
|
18
18
|
* Scope Frontend (dan bagian frontend pada ALL) juga dieksekusi NYATA: payload
|
|
19
|
-
* migrate (RDF -> UDF) per tabel -> restforge-designer
|
|
19
|
+
* migrate (RDF -> UDF) per tabel -> restforge-designer generate.
|
|
20
20
|
*
|
|
21
21
|
* Catatan: contract ini global verb (snapshot key = `fast-track`), file berada
|
|
22
22
|
* di root `generators/cli/` sehingga ter-discover otomatis sejajar dengan `init`.
|
|
@@ -385,7 +385,9 @@ async function collectConfig(args, ask, fileCfg = {}) {
|
|
|
385
385
|
console.log(' SQLite mode: DB_HOST, DB_PORT, DB_USER, DB_PASSWORD are ignored.');
|
|
386
386
|
console.log(' The database file path is set in DB_FILE.');
|
|
387
387
|
console.log('');
|
|
388
|
-
|
|
388
|
+
// fileCfg.DB_NAME: file legacy hasil `restforge init` menyimpan path
|
|
389
|
+
// sqlite di DB_NAME, bukan DB_FILE (lihat init.js & server.js runtime).
|
|
390
|
+
cfg.DB_FILE = await askField('DB_FILE (.db file path)', fileCfg.DB_FILE || fileCfg.DB_NAME || DEFAULTS.DB_FILE);
|
|
389
391
|
cfg.DB_NAME = cfg.DB_FILE;
|
|
390
392
|
} else {
|
|
391
393
|
const dbDef = DB_TYPE_DEFAULTS[cfg.DB_TYPE] || {};
|
|
@@ -415,7 +417,7 @@ function defaultCfgFromFile(args, fileCfg = {}) {
|
|
|
415
417
|
cfg.DB_TYPE = (fileCfg.DB_TYPE || DEFAULTS.DB_TYPE).toLowerCase();
|
|
416
418
|
|
|
417
419
|
if (cfg.DB_TYPE === 'sqlite') {
|
|
418
|
-
cfg.DB_FILE = fileCfg.DB_FILE || DEFAULTS.DB_FILE;
|
|
420
|
+
cfg.DB_FILE = fileCfg.DB_FILE || fileCfg.DB_NAME || DEFAULTS.DB_FILE;
|
|
419
421
|
cfg.DB_NAME = cfg.DB_FILE;
|
|
420
422
|
} else {
|
|
421
423
|
const dbDef = DB_TYPE_DEFAULTS[cfg.DB_TYPE] || {};
|
|
@@ -1207,7 +1209,7 @@ function runBackendPipeline(ctx) {
|
|
|
1207
1209
|
|
|
1208
1210
|
/**
|
|
1209
1211
|
* Pipeline frontend nyata: migrate RDF->UDF per tabel (agregator di-akumulasi),
|
|
1210
|
-
* lalu designer
|
|
1212
|
+
* lalu designer generate. Urutan mengikuti fast-track.mjs/quick-start.
|
|
1211
1213
|
* appCode default = project, sehingga agregator = frontend/payload/<project>.json.
|
|
1212
1214
|
*/
|
|
1213
1215
|
function runFrontendPipeline(ctx) {
|
|
@@ -1218,7 +1220,7 @@ function runFrontendPipeline(ctx) {
|
|
|
1218
1220
|
const plugin = ctx.plugin || DESIGNER_DEFAULT_PLUGIN;
|
|
1219
1221
|
const pluginArg = `--plugin=${plugin}`;
|
|
1220
1222
|
|
|
1221
|
-
phase('[F1/
|
|
1223
|
+
phase('[F1/2] Migrate RDF -> UDF (per tabel, agregator di-akumulasi)');
|
|
1222
1224
|
fs.mkdirSync(path.join(frontendDir, 'payload'), { recursive: true });
|
|
1223
1225
|
for (const t of ctx.tableEntries) {
|
|
1224
1226
|
// Lewati tabel yang murni FK-parent (tanpa FK sendiri): page-nya dibuat
|
|
@@ -1241,10 +1243,7 @@ function runFrontendPipeline(ctx) {
|
|
|
1241
1243
|
: ` [WARN] could not inject auth block into ${aggregatorPath}; app will generate without auth`);
|
|
1242
1244
|
}
|
|
1243
1245
|
|
|
1244
|
-
phase('[F2/
|
|
1245
|
-
run(`restforge-designer activate --key=${ctx.cfg.LICENSE}`, frontendDir, { allowNonZero: true });
|
|
1246
|
-
|
|
1247
|
-
phase('[F3/3] Generate frontend application');
|
|
1246
|
+
phase('[F2/2] Generate frontend application');
|
|
1248
1247
|
// Hapus index.html lama agar landing page diregenerasi sesuai set page terbaru.
|
|
1249
1248
|
// Pakai fs langsung (bukan shell command) supaya portable Windows/Linux/macOS.
|
|
1250
1249
|
try {
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Contract: project auth
|
|
5
|
+
*
|
|
6
|
+
* Memasang "auth extension" (SDF, tabel, component, processor) ke project
|
|
7
|
+
* RESTForge yang sudah ada. Setelah validasi prasyarat (phase 00), handler
|
|
8
|
+
* menulis dua file SDF auth ber-prefix `rfx` ke `--schema-path` (Fungsi 1),
|
|
9
|
+
* lalu membuat tabelnya di DB via primitif dbschema-kit langsung (Fungsi 2),
|
|
10
|
+
* lalu menulis component middleware + router auth tanpa google (Fungsi 3a),
|
|
11
|
+
* lalu menulis keenam processor auth tanpa google (Fungsi 3b), lalu
|
|
12
|
+
* menginjeksi variabel env auth ke `--config` dan memverifikasi/mencatat
|
|
13
|
+
* dependency runtime `bcrypt`+`jsonwebtoken` (Fungsi tambahan, phase 05),
|
|
14
|
+
* lalu mencetak ringkasan akhir.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs');
|
|
18
|
+
const path = require('node:path');
|
|
19
|
+
const { validateSafeName } = require('../../lib/utils/path-validator');
|
|
20
|
+
const projectRegistry = require('../../lib/utils/project-registry');
|
|
21
|
+
const { PREFIX } = require('../../lib/auth/prefix');
|
|
22
|
+
const { generateAuthSdf } = require('../../lib/auth/sdf-generator');
|
|
23
|
+
const { runAuthMigrate } = require('../../lib/auth/migrate-runner');
|
|
24
|
+
const { generateAuthComponents } = require('../../lib/auth/component-generator');
|
|
25
|
+
const { generateAuthProcessors } = require('../../lib/auth/processor-generator');
|
|
26
|
+
const { injectAuthEnv } = require('../../lib/auth/env-injector');
|
|
27
|
+
const { ensureAuthDependencies } = require('../../lib/auth/dependency-checker');
|
|
28
|
+
|
|
29
|
+
function projectExists(workingDir, projectName) {
|
|
30
|
+
const modulePath = path.join(workingDir, 'src', 'modules', `${projectName}.js`);
|
|
31
|
+
if (fs.existsSync(modulePath)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const registry = projectRegistry.loadProjectRegistry();
|
|
36
|
+
return Boolean(registry.projects && registry.projects[projectName]);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
resource: 'project',
|
|
41
|
+
verb: 'auth',
|
|
42
|
+
description: 'Install auth extension (SDF, tabel, component, processor) ke project existing',
|
|
43
|
+
category: 'generation',
|
|
44
|
+
flags: {
|
|
45
|
+
create: {
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
required: false,
|
|
48
|
+
default: false,
|
|
49
|
+
description: 'Trigger eksekusi instalasi auth extension (wajib disertakan)'
|
|
50
|
+
},
|
|
51
|
+
project: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
required: false,
|
|
54
|
+
default: null,
|
|
55
|
+
description: 'Nama project target (kanonik; alias: --name)'
|
|
56
|
+
},
|
|
57
|
+
name: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
required: false,
|
|
60
|
+
default: null,
|
|
61
|
+
description: 'Alias dari --project'
|
|
62
|
+
},
|
|
63
|
+
'schema-path': {
|
|
64
|
+
type: 'string',
|
|
65
|
+
required: false,
|
|
66
|
+
default: './schema',
|
|
67
|
+
description: 'Folder output file SDF auth'
|
|
68
|
+
},
|
|
69
|
+
config: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
required: false,
|
|
72
|
+
default: 'config/db-connection.env',
|
|
73
|
+
description: 'File konfigurasi koneksi DB untuk langkah migrate'
|
|
74
|
+
},
|
|
75
|
+
force: {
|
|
76
|
+
type: 'boolean',
|
|
77
|
+
required: false,
|
|
78
|
+
default: false,
|
|
79
|
+
description: 'Timpa file yang sudah ada (backup tetap dibuat)'
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
examples: [
|
|
83
|
+
'npx restforge project auth --create --project=myapp',
|
|
84
|
+
'npx restforge project auth --create --name=myapp --schema-path=./schema'
|
|
85
|
+
],
|
|
86
|
+
async handler(args) {
|
|
87
|
+
if (args.create !== true) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
'Flag --create wajib disertakan untuk memicu instalasi auth extension. ' +
|
|
90
|
+
'Contoh: npx restforge project auth --create --project=<nama-project>'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const rawName = args.project || args.name;
|
|
95
|
+
if (!rawName) {
|
|
96
|
+
throw new Error('Salah satu dari --project atau --name wajib diisi dengan nama project target');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const projectName = validateSafeName(rawName, 'project');
|
|
100
|
+
const workingDir = process.cwd();
|
|
101
|
+
|
|
102
|
+
if (!projectExists(workingDir, projectName)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Project "${projectName}" tidak ditemukan (src/modules/${projectName}.js tidak ada). ` +
|
|
105
|
+
'Buat project lebih dulu (mis. "npx restforge endpoint create") sebelum menjalankan project auth.'
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const schemaPath = path.resolve(workingDir, args['schema-path'] || './schema');
|
|
110
|
+
const { written, skipped } = generateAuthSdf({ schemaPath, force: args.force === true });
|
|
111
|
+
|
|
112
|
+
console.log('');
|
|
113
|
+
console.log(`Prasyarat OK untuk project "${projectName}" (prefix artefak: ${PREFIX}).`);
|
|
114
|
+
if (written.length > 0) {
|
|
115
|
+
console.log(`SDF auth ditulis: ${written.map((p) => path.basename(p)).join(', ')}`);
|
|
116
|
+
}
|
|
117
|
+
if (skipped.length > 0) {
|
|
118
|
+
console.log(
|
|
119
|
+
`SDF auth sudah ada, dilewati (gunakan --force untuk overwrite): ${skipped.map((p) => path.basename(p)).join(', ')}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const configPath = args.config || 'config/db-connection.env';
|
|
124
|
+
const migrateResult = await runAuthMigrate({ schemaPath, configPath });
|
|
125
|
+
console.log(
|
|
126
|
+
`Tabel auth siap: ${migrateResult.tables.join(', ')} ` +
|
|
127
|
+
`(dialect: ${migrateResult.dialect}, ${migrateResult.statementsApplied} statement diterapkan).`
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const middlewareDir = path.join(workingDir, 'src', 'components', 'handlers');
|
|
131
|
+
const routerDir = path.join(workingDir, 'src', 'modules', projectName);
|
|
132
|
+
const { written: componentsWritten, skipped: componentsSkipped } = generateAuthComponents({
|
|
133
|
+
middlewareDir,
|
|
134
|
+
routerDir,
|
|
135
|
+
projectName,
|
|
136
|
+
force: args.force === true
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (componentsWritten.length > 0) {
|
|
140
|
+
console.log(
|
|
141
|
+
`Component/router auth ditulis: ${componentsWritten.map((p) => path.relative(workingDir, p)).join(', ')}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (componentsSkipped.length > 0) {
|
|
145
|
+
console.log(
|
|
146
|
+
`Component/router auth sudah ada, dilewati (gunakan --force untuk overwrite): ` +
|
|
147
|
+
`${componentsSkipped.map((p) => path.relative(workingDir, p)).join(', ')}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const processorDir = path.join(workingDir, 'src', 'modules', projectName, 'processor', 'auth');
|
|
152
|
+
const { written: processorsWritten, skipped: processorsSkipped } = generateAuthProcessors({
|
|
153
|
+
processorDir,
|
|
154
|
+
force: args.force === true
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (processorsWritten.length > 0) {
|
|
158
|
+
console.log(
|
|
159
|
+
`Processor auth ditulis: ${processorsWritten.map((p) => path.relative(workingDir, p)).join(', ')}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
if (processorsSkipped.length > 0) {
|
|
163
|
+
console.log(
|
|
164
|
+
`Processor auth sudah ada, dilewati (gunakan --force untuk overwrite): ` +
|
|
165
|
+
`${processorsSkipped.map((p) => path.relative(workingDir, p)).join(', ')}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
const envResult = injectAuthEnv({ configPath });
|
|
169
|
+
const dependencyResult = ensureAuthDependencies({ workingDir });
|
|
170
|
+
|
|
171
|
+
console.log('');
|
|
172
|
+
console.log(`Environment auth (${path.relative(workingDir, envResult.filePath) || envResult.filePath}):`);
|
|
173
|
+
if (envResult.added.length > 0) {
|
|
174
|
+
console.log(` ditambahkan: ${envResult.added.join(', ')}`);
|
|
175
|
+
}
|
|
176
|
+
if (envResult.skipped.length > 0) {
|
|
177
|
+
console.log(` sudah ada, dilewati (nilai existing dipertahankan): ${envResult.skipped.join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log('Dependency runtime (bcrypt, jsonwebtoken):');
|
|
181
|
+
for (const [depName, info] of Object.entries(dependencyResult.resolution)) {
|
|
182
|
+
console.log(` ${depName}: ${info.resolvable ? `resolvable (${info.resolvedPath})` : 'TIDAK resolvable dari project target'}`);
|
|
183
|
+
}
|
|
184
|
+
if (dependencyResult.packageJson.hasPackageJson) {
|
|
185
|
+
if (dependencyResult.packageJson.added.length > 0) {
|
|
186
|
+
console.log(` package.json diperbarui, dependencies ditambahkan: ${dependencyResult.packageJson.added.join(', ')}`);
|
|
187
|
+
} else {
|
|
188
|
+
console.log(' package.json project sudah mencantumkan bcrypt & jsonwebtoken (tidak diubah)');
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
console.log(' package.json tidak ditemukan di project target, tidak dicatat otomatis');
|
|
192
|
+
}
|
|
193
|
+
if (dependencyResult.needsInstallInstruction) {
|
|
194
|
+
console.log(' Jalankan "npm install bcrypt jsonwebtoken" di project target sebelum start server.');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log('');
|
|
198
|
+
console.log('Auth extension terpasang.');
|
|
199
|
+
console.log('Langkah lanjutan:');
|
|
200
|
+
if (envResult.jwtSecretGenerated) {
|
|
201
|
+
console.log(' - JWT_SECRET baru di-generate acak; rotate berkala sesuai kebijakan keamanan bila perlu.');
|
|
202
|
+
}
|
|
203
|
+
if (dependencyResult.needsInstallInstruction) {
|
|
204
|
+
console.log(' - Jalankan npm install agar bcrypt/jsonwebtoken terpasang sebelum start server.');
|
|
205
|
+
}
|
|
206
|
+
console.log(' - Restart server agar perubahan environment dan route auth termuat.');
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generator component middleware + router auth (Fungsi 3a). Merender aset
|
|
5
|
+
* template di `templates/` via template-renderer, lalu menulis ke lokasi
|
|
6
|
+
* target memakai writeFileWithBackup — perilaku force/skip identik Fungsi 1
|
|
7
|
+
* (sdf-generator.js): tanpa --force file existing di-skip, dengan --force
|
|
8
|
+
* di-overwrite + backup.
|
|
9
|
+
*
|
|
10
|
+
* Processor (Fungsi 3b, Phase 04) TIDAK ditulis di sini.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const { renderTemplate } = require('./template-renderer');
|
|
17
|
+
const FileUtils = require('../utils/file-utils');
|
|
18
|
+
const { AUTH_MIDDLEWARE_NAME, AUTH_ROUTER_NAME } = require('./prefix');
|
|
19
|
+
|
|
20
|
+
const TEMPLATES_DIR = path.join(__dirname, 'templates');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {{ middlewareDir: string, routerDir: string, projectName: string, force?: boolean }} options
|
|
24
|
+
* @returns {{ written: string[], skipped: string[] }}
|
|
25
|
+
*/
|
|
26
|
+
function generateAuthComponents({ middlewareDir, routerDir, projectName, force = false }) {
|
|
27
|
+
const targets = [
|
|
28
|
+
{
|
|
29
|
+
templateFile: 'rfx_auth-middleware.js.tmpl',
|
|
30
|
+
targetPath: path.join(middlewareDir, `${AUTH_MIDDLEWARE_NAME}.js`),
|
|
31
|
+
params: {}
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
templateFile: 'rfx_auth.js.tmpl',
|
|
35
|
+
targetPath: path.join(routerDir, `${AUTH_ROUTER_NAME}.js`),
|
|
36
|
+
params: { PROJECT_NAME: projectName }
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const written = [];
|
|
41
|
+
const skipped = [];
|
|
42
|
+
|
|
43
|
+
for (const target of targets) {
|
|
44
|
+
if (fs.existsSync(target.targetPath) && !force) {
|
|
45
|
+
skipped.push(target.targetPath);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const templatePath = path.join(TEMPLATES_DIR, target.templateFile);
|
|
50
|
+
const content = renderTemplate(templatePath, target.params);
|
|
51
|
+
FileUtils.writeFileWithBackup(target.targetPath, content, true);
|
|
52
|
+
written.push(target.targetPath);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return { written, skipped };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { generateAuthComponents };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verifikasi + pencatatan dependency runtime auth extension (Fungsi tambahan,
|
|
5
|
+
* Phase 05, menutup keputusan #6 campaign): middleware butuh `jsonwebtoken`,
|
|
6
|
+
* processor butuh `bcrypt`.
|
|
7
|
+
*
|
|
8
|
+
* Verifikasi resolvability memakai `require.resolve(pkg, { paths: [...] })`
|
|
9
|
+
* persis algoritma resolusi Node — bukan sekadar cek folder `node_modules/`,
|
|
10
|
+
* agar hasilnya benar walau dependency ter-hoist ke level lain.
|
|
11
|
+
*
|
|
12
|
+
* Pencatatan ke `package.json` project bersifat idempoten (tidak menimpa
|
|
13
|
+
* versi yang sudah ada) dan TIDAK pernah menjalankan `npm install`.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
|
|
19
|
+
const PLATFORM_PACKAGE_JSON = require('../../../package.json');
|
|
20
|
+
|
|
21
|
+
const REQUIRED_DEPENDENCIES = {
|
|
22
|
+
bcrypt: PLATFORM_PACKAGE_JSON.dependencies.bcrypt,
|
|
23
|
+
jsonwebtoken: PLATFORM_PACKAGE_JSON.dependencies.jsonwebtoken
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} pkgName
|
|
28
|
+
* @param {string} fromDir
|
|
29
|
+
* @returns {string|null} Resolved entry path, atau null bila tidak resolvable.
|
|
30
|
+
*/
|
|
31
|
+
function resolvePackage(pkgName, fromDir) {
|
|
32
|
+
try {
|
|
33
|
+
return require.resolve(pkgName, { paths: [fromDir] });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Tambahkan `bcrypt`/`jsonwebtoken` ke `dependencies` package.json project
|
|
41
|
+
* bila belum ada. Tidak pernah menurunkan/menimpa versi yang sudah di-set.
|
|
42
|
+
*
|
|
43
|
+
* @param {string} workingDir
|
|
44
|
+
* @returns {{ hasPackageJson: boolean, pkgPath: string, updated: boolean, added: string[] }}
|
|
45
|
+
*/
|
|
46
|
+
function ensurePackageJsonDependencies(workingDir) {
|
|
47
|
+
const pkgPath = path.join(workingDir, 'package.json');
|
|
48
|
+
|
|
49
|
+
if (!fs.existsSync(pkgPath)) {
|
|
50
|
+
return { hasPackageJson: false, pkgPath, updated: false, added: [] };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const raw = fs.readFileSync(pkgPath, 'utf8');
|
|
54
|
+
let pkg;
|
|
55
|
+
try {
|
|
56
|
+
pkg = JSON.parse(raw);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw new Error(`Gagal parse ${pkgPath}: ${err.message}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
62
|
+
const added = [];
|
|
63
|
+
|
|
64
|
+
for (const [name, version] of Object.entries(REQUIRED_DEPENDENCIES)) {
|
|
65
|
+
if (!Object.prototype.hasOwnProperty.call(pkg.dependencies, name)) {
|
|
66
|
+
pkg.dependencies[name] = version;
|
|
67
|
+
added.push(name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (added.length > 0) {
|
|
72
|
+
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf8');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { hasPackageJson: true, pkgPath, updated: added.length > 0, added };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {{ workingDir?: string }} options
|
|
80
|
+
* @returns {{
|
|
81
|
+
* resolution: Record<string, { resolvable: boolean, resolvedPath: string|null }>,
|
|
82
|
+
* allResolvable: boolean,
|
|
83
|
+
* packageJson: { hasPackageJson: boolean, pkgPath: string, updated: boolean, added: string[] },
|
|
84
|
+
* needsInstallInstruction: boolean
|
|
85
|
+
* }}
|
|
86
|
+
*/
|
|
87
|
+
function ensureAuthDependencies({ workingDir = process.cwd() } = {}) {
|
|
88
|
+
const resolution = {};
|
|
89
|
+
for (const name of Object.keys(REQUIRED_DEPENDENCIES)) {
|
|
90
|
+
const resolvedPath = resolvePackage(name, workingDir);
|
|
91
|
+
resolution[name] = { resolvable: Boolean(resolvedPath), resolvedPath };
|
|
92
|
+
}
|
|
93
|
+
const allResolvable = Object.values(resolution).every((r) => r.resolvable);
|
|
94
|
+
|
|
95
|
+
const packageJson = ensurePackageJsonDependencies(workingDir);
|
|
96
|
+
|
|
97
|
+
const needsInstallInstruction = !allResolvable || !packageJson.hasPackageJson;
|
|
98
|
+
|
|
99
|
+
return { resolution, allResolvable, packageJson, needsInstallInstruction };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = { ensureAuthDependencies, REQUIRED_DEPENDENCIES, resolvePackage };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Injeksi variabel env auth (Fungsi tambahan, Phase 05) ke file `--config`,
|
|
5
|
+
* meniru blok Auth/JWT pada prototype `myapp-with-auth/config/db-connection.env`.
|
|
6
|
+
* Idempoten: hanya menambahkan key yang belum ada di file; tidak pernah
|
|
7
|
+
* menimpa nilai existing (termasuk JWT_SECRET yang sudah di-set user).
|
|
8
|
+
*
|
|
9
|
+
* Resolusi path config memakai `resolveConfig()` yang sama dipakai
|
|
10
|
+
* migrate-runner.js, agar blok Auth/JWT ditambahkan ke file yang sama dengan
|
|
11
|
+
* yang dipakai langkah migrate (cascade lookup cwd -> config/ -> +.env).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const crypto = require('node:crypto');
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
|
|
17
|
+
const { readEnvFile, writeEnvFile } = require('../utils/env-manager');
|
|
18
|
+
const { resolveConfig } = require('../utils/config-resolver');
|
|
19
|
+
|
|
20
|
+
const AUTH_ENV_DEFAULTS = {
|
|
21
|
+
JWT_ALGORITHM: 'HS256',
|
|
22
|
+
ACCESS_TOKEN_EXPIRY_MIN: '60',
|
|
23
|
+
REFRESH_TOKEN_EXPIRY_DAYS: '30',
|
|
24
|
+
GOOGLE_CLIENT_ID: ''
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const AUTH_ENV_KEYS = [
|
|
28
|
+
'JWT_SECRET',
|
|
29
|
+
'JWT_ALGORITHM',
|
|
30
|
+
'ACCESS_TOKEN_EXPIRY_MIN',
|
|
31
|
+
'REFRESH_TOKEN_EXPIRY_DAYS',
|
|
32
|
+
'GOOGLE_CLIENT_ID'
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const AUTH_ENV_HEADER_COMMENT = '# Auth / JWT Configuration (rfx_auth, generated by "project auth")';
|
|
36
|
+
|
|
37
|
+
function generateJwtSecret() {
|
|
38
|
+
return crypto.randomBytes(48).toString('hex');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {{ configPath: string, workingDir?: string }} options
|
|
43
|
+
* @returns {{
|
|
44
|
+
* filePath: string,
|
|
45
|
+
* added: string[],
|
|
46
|
+
* skipped: string[],
|
|
47
|
+
* jwtSecretGenerated: boolean
|
|
48
|
+
* }}
|
|
49
|
+
*/
|
|
50
|
+
function injectAuthEnv({ configPath, workingDir = process.cwd() } = {}) {
|
|
51
|
+
const resolved = resolveConfig(configPath, workingDir);
|
|
52
|
+
const filePath = resolved ? resolved.path : path.resolve(workingDir, configPath || 'config/db-connection.env');
|
|
53
|
+
|
|
54
|
+
const { data, lines } = readEnvFile(filePath);
|
|
55
|
+
const added = [];
|
|
56
|
+
const skipped = [];
|
|
57
|
+
|
|
58
|
+
for (const key of AUTH_ENV_KEYS) {
|
|
59
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
60
|
+
skipped.push(key);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
data[key] = key === 'JWT_SECRET' ? generateJwtSecret() : AUTH_ENV_DEFAULTS[key];
|
|
65
|
+
added.push(key);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (added.length > 0) {
|
|
69
|
+
const nextLines = lines.length > 0 ? [...lines, '', AUTH_ENV_HEADER_COMMENT] : [AUTH_ENV_HEADER_COMMENT];
|
|
70
|
+
writeEnvFile(filePath, data, nextLines);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
filePath,
|
|
75
|
+
added,
|
|
76
|
+
skipped,
|
|
77
|
+
jwtSecretGenerated: added.includes('JWT_SECRET')
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = { injectAuthEnv, AUTH_ENV_KEYS };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migrate runner auth extension (Fungsi 2). Memuat kedua SDF auth (`rfx_auth_user`
|
|
5
|
+
* & `rfx_auth_refresh_token`) dari `--schema-path`, memvalidasi cross-model (FK
|
|
6
|
+
* refresh_token -> user), men-generate DDL, lalu apply ke DB via primitif
|
|
7
|
+
* `dbschema-kit` langsung (in-process). TIDAK menyentuh `generators/cli/schema/migrate.js`
|
|
8
|
+
* (keputusan #3 campaign project-auth-command-v1) — primitif dipanggil ulang di sini.
|
|
9
|
+
*
|
|
10
|
+
* Test seam: sama seperti migrate.js, executor dimuat lewat loadApplyExecutor()
|
|
11
|
+
* yang menghormati DBSCHEMA_KIT_TEST_APPLY_STUB.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
const { loadSchemaPath } = require('../dbschema-kit/loader');
|
|
17
|
+
const { validateCrossModel } = require('../dbschema-kit/validator/cross-model-validator');
|
|
18
|
+
const { generateDDL } = require('../dbschema-kit/ddl-generator');
|
|
19
|
+
const { loadConfig } = require('../dbschema-kit/connection');
|
|
20
|
+
const { splitStatements } = require('../dbschema-kit/statement-splitter');
|
|
21
|
+
const { applyIfNotExistsModifier } = require('../dbschema-kit/statement-modifier');
|
|
22
|
+
const { resolveConfig } = require('../utils/config-resolver');
|
|
23
|
+
const { AUTH_USER_TABLE, AUTH_REFRESH_TOKEN_TABLE } = require('./prefix');
|
|
24
|
+
|
|
25
|
+
function loadApplyExecutor() {
|
|
26
|
+
const stubPath = process.env.DBSCHEMA_KIT_TEST_APPLY_STUB;
|
|
27
|
+
if (stubPath) {
|
|
28
|
+
return require(path.resolve(stubPath));
|
|
29
|
+
}
|
|
30
|
+
return require('../dbschema-kit/apply-executor');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Muat kedua SDF auth dari `schemaPath` ke satu Map gabungan, agar
|
|
35
|
+
* validateCrossModel bisa memverifikasi FK lintas model.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} schemaPath
|
|
38
|
+
* @returns {Map<string, object>}
|
|
39
|
+
*/
|
|
40
|
+
function loadAuthModels(schemaPath) {
|
|
41
|
+
const models = new Map();
|
|
42
|
+
for (const tableName of [AUTH_USER_TABLE, AUTH_REFRESH_TOKEN_TABLE]) {
|
|
43
|
+
const filePath = path.join(schemaPath, `${tableName}.js`);
|
|
44
|
+
const fileModels = loadSchemaPath(filePath);
|
|
45
|
+
for (const [qualified, ir] of fileModels) {
|
|
46
|
+
models.set(qualified, ir);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return models;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {{ schemaPath: string, configPath: string }} options
|
|
54
|
+
* @returns {Promise<{ tables: string[], dialect: string, statementsApplied: number, result: object }>}
|
|
55
|
+
*/
|
|
56
|
+
async function runAuthMigrate({ schemaPath, configPath }) {
|
|
57
|
+
const resolved = resolveConfig(configPath, process.cwd());
|
|
58
|
+
if (!resolved) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'Migrate auth gagal: --config=<file> tidak ditemukan. Set default config ' +
|
|
61
|
+
"('npx restforge config set-default --config=<file>') atau sediakan --config eksplisit."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let config;
|
|
66
|
+
try {
|
|
67
|
+
config = loadConfig(resolved.path);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
throw new Error(`Migrate auth gagal memuat config DB (${resolved.path}): ${err.message}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let models;
|
|
73
|
+
try {
|
|
74
|
+
models = loadAuthModels(schemaPath);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
throw new Error(`Migrate auth gagal memuat SDF auth dari '${schemaPath}': ${err.message}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const crossModelIssues = validateCrossModel(models);
|
|
80
|
+
const crossModelErrors = crossModelIssues.filter((issue) => issue.severity === 'error');
|
|
81
|
+
if (crossModelErrors.length > 0) {
|
|
82
|
+
const messages = crossModelErrors.map((issue) => issue.message).join('; ');
|
|
83
|
+
throw new Error(`Migrate auth gagal: validasi cross-model menemukan error: ${messages}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ddl = generateDDL(models, { dialect: config.dialect, drop: false });
|
|
87
|
+
const statements = splitStatements(ddl, config.dialect)
|
|
88
|
+
.map((statement) => applyIfNotExistsModifier(statement, config.dialect));
|
|
89
|
+
|
|
90
|
+
const executor = loadApplyExecutor();
|
|
91
|
+
|
|
92
|
+
let result;
|
|
93
|
+
try {
|
|
94
|
+
result = await executor.applyStatements({ statements, dialect: config.dialect, config });
|
|
95
|
+
} catch (err) {
|
|
96
|
+
throw new Error(`Migrate auth gagal menerapkan tabel ke database: ${err.message}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!result || result.status !== 'SUCCESS') {
|
|
100
|
+
throw new Error(`Migrate auth tidak SUCCESS (status: ${result ? result.status : 'UNKNOWN'}).`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
tables: [AUTH_USER_TABLE, AUTH_REFRESH_TOKEN_TABLE],
|
|
105
|
+
dialect: config.dialect,
|
|
106
|
+
statementsApplied: statements.length,
|
|
107
|
+
result
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { runAuthMigrate, loadAuthModels };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Konstanta prefix `rfx` (RestForge eXtension) untuk seluruh artefak auth
|
|
5
|
+
* extension. Satu sumber dipakai ulang oleh Phase 01 (SDF), Phase 02
|
|
6
|
+
* (tabel hasil migrate), dan Phase 03-04 (component/router/processor).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const PREFIX = 'rfx';
|
|
10
|
+
|
|
11
|
+
const AUTH_USER_TABLE = `${PREFIX}_auth_user`;
|
|
12
|
+
const AUTH_REFRESH_TOKEN_TABLE = `${PREFIX}_auth_refresh_token`;
|
|
13
|
+
const AUTH_MIDDLEWARE_NAME = `${PREFIX}_auth-middleware`;
|
|
14
|
+
const AUTH_ROUTER_NAME = `${PREFIX}_auth`;
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
PREFIX,
|
|
18
|
+
AUTH_USER_TABLE,
|
|
19
|
+
AUTH_REFRESH_TOKEN_TABLE,
|
|
20
|
+
AUTH_MIDDLEWARE_NAME,
|
|
21
|
+
AUTH_ROUTER_NAME
|
|
22
|
+
};
|