@restforgejs/platform 5.1.4 → 5.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/build-info.json +2 -2
  2. package/cli/consumer-deploy.js +1 -1
  3. package/cli/consumer.js +1 -1
  4. package/generators/cli/data/pull.js +16 -7
  5. package/generators/cli/data/push.js +17 -7
  6. package/generators/cli/fast-track.js +63 -43
  7. package/generators/cli/init.js +347 -97
  8. package/generators/lib/data/data-scope.js +138 -0
  9. package/generators/lib/data/envelope.js +25 -9
  10. package/generators/lib/data/pull-runner.js +44 -37
  11. package/generators/lib/data/push-runner.js +64 -46
  12. package/generators/lib/templates/dashboard-catalog.js +1 -1
  13. package/generators/lib/templates/db-connection-env.js +1 -1
  14. package/generators/lib/templates/dbschema-catalog.js +1 -1
  15. package/generators/lib/templates/field-validation-catalog.js +1 -1
  16. package/generators/lib/templates/mysql-template.js +1 -1
  17. package/generators/lib/templates/oracle-template.js +1 -1
  18. package/generators/lib/templates/postgres-template.js +1 -1
  19. package/generators/lib/templates/query-declarative-catalog.js +1 -1
  20. package/generators/lib/templates/sqlite-template.js +1 -1
  21. package/integrity-manifest.json +18 -18
  22. package/package.json +1 -1
  23. package/scripts/verify-integrity.js +1 -1
  24. package/server.js +1 -1
  25. package/src/components/handlers/adjust_handler.js +1 -1
  26. package/src/components/handlers/audit_handler.js +1 -1
  27. package/src/components/handlers/delete_handler.js +1 -1
  28. package/src/components/handlers/export_handler.js +1 -1
  29. package/src/components/handlers/import_handler.js +1 -1
  30. package/src/components/handlers/insert_handler.js +1 -1
  31. package/src/components/handlers/update_handler.js +1 -1
  32. package/src/components/handlers/upload_handler.js +1 -1
  33. package/src/components/handlers/workflow_handler.js +1 -1
  34. package/src/components/integrations/webhook.js +1 -1
  35. package/src/consumers/baseConsumer.js +1 -1
  36. package/src/consumers/declarativeMapper.js +1 -1
  37. package/src/consumers/handlers/apiHandler.js +1 -1
  38. package/src/consumers/handlers/consoleHandler.js +1 -1
  39. package/src/consumers/handlers/databaseHandler.js +1 -1
  40. package/src/consumers/handlers/index.js +1 -1
  41. package/src/consumers/handlers/kafkaHandler.js +1 -1
  42. package/src/consumers/index.js +1 -1
  43. package/src/consumers/messageTransformer.js +1 -1
  44. package/src/consumers/validator.js +1 -1
  45. package/src/core/db/dialect/base-dialect.js +1 -1
  46. package/src/core/db/dialect/index.js +1 -1
  47. package/src/core/db/dialect/mysql-dialect.js +1 -1
  48. package/src/core/db/dialect/oracle-dialect.js +1 -1
  49. package/src/core/db/dialect/postgres-dialect.js +1 -1
  50. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  51. package/src/core/db/flatten-helper.js +1 -1
  52. package/src/core/db/query-builder-error.js +1 -1
  53. package/src/core/db/query-builder.js +1 -1
  54. package/src/core/db/relation-helper.js +1 -1
  55. package/src/core/handlers/delete_handler.js +1 -1
  56. package/src/core/handlers/insert_handler.js +1 -1
  57. package/src/core/handlers/update_handler.js +1 -1
  58. package/src/core/models/base-model.js +1 -1
  59. package/src/core/utils/cache-manager.js +1 -1
  60. package/src/core/utils/component-engine.js +1 -1
  61. package/src/core/utils/context-builder.js +1 -1
  62. package/src/core/utils/datetime-formatter.js +1 -1
  63. package/src/core/utils/datetime-parser.js +1 -1
  64. package/src/core/utils/db.js +1 -1
  65. package/src/core/utils/logger.js +1 -1
  66. package/src/core/utils/payload-loader.js +1 -1
  67. package/src/core/utils/security-checks.js +1 -1
  68. package/src/middleware/body-options.js +1 -1
  69. package/src/middleware/cors.js +1 -1
  70. package/src/middleware/idempotency.js +1 -1
  71. package/src/middleware/rate-limiter.js +1 -1
  72. package/src/middleware/request-logger.js +1 -1
  73. package/src/middleware/security-headers.js +1 -1
  74. package/src/models/base-model-mysql.js +1 -1
  75. package/src/models/base-model-oracle.js +1 -1
  76. package/src/models/base-model-sqlite.js +1 -1
  77. package/src/models/base-model.js +1 -1
  78. package/src/pro/caching/redis-client.js +1 -1
  79. package/src/pro/caching/redis-helper.js +1 -1
  80. package/src/pro/consumers/baseConsumer.js +1 -1
  81. package/src/pro/consumers/declarativeMapper.js +1 -1
  82. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  83. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  84. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  85. package/src/pro/consumers/handlers/index.js +1 -1
  86. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  87. package/src/pro/consumers/index.js +1 -1
  88. package/src/pro/consumers/messageTransformer.js +1 -1
  89. package/src/pro/consumers/validator.js +1 -1
  90. package/src/pro/database/base-model-mysql.js +1 -1
  91. package/src/pro/database/base-model-oracle.js +1 -1
  92. package/src/pro/database/base-model-sqlite.js +1 -1
  93. package/src/pro/database/db-mysql.js +1 -1
  94. package/src/pro/database/db-oracle.js +1 -1
  95. package/src/pro/database/db-sqlite.js +1 -1
  96. package/src/pro/excel/excel-generator.js +1 -1
  97. package/src/pro/excel/excel-parser.js +1 -1
  98. package/src/pro/excel/export-service.js +1 -1
  99. package/src/pro/excel/export_handler.js +1 -1
  100. package/src/pro/excel/import-service.js +1 -1
  101. package/src/pro/excel/import-validator.js +1 -1
  102. package/src/pro/excel/import_handler.js +1 -1
  103. package/src/pro/excel/upsert-builder.js +1 -1
  104. package/src/pro/idgen/idgen-routes.js +1 -1
  105. package/src/pro/integrations/lookup-resolver.js +1 -1
  106. package/src/pro/integrations/upload-handler-v2.js +1 -1
  107. package/src/pro/integrations/upload-handler.js +1 -1
  108. package/src/pro/integrations/webhook.js +1 -1
  109. package/src/pro/locking/lock-routes.js +1 -1
  110. package/src/pro/locking/resource-lock-manager.js +1 -1
  111. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  112. package/src/pro/messaging/kafkaService.js +1 -1
  113. package/src/pro/messaging/messagehubService.js +1 -1
  114. package/src/pro/messaging/rabbitmqService.js +1 -1
  115. package/src/pro/scheduler/job-manager.js +1 -1
  116. package/src/pro/scheduler/job-routes.js +1 -1
  117. package/src/pro/scheduler/job-validator.js +1 -1
  118. package/src/pro/storage/base-storage-provider.js +1 -1
  119. package/src/pro/storage/file-metadata-helper.js +1 -1
  120. package/src/pro/storage/index.js +1 -1
  121. package/src/pro/storage/local-storage-provider.js +1 -1
  122. package/src/pro/storage/s3-storage-provider.js +1 -1
  123. package/src/pro/storage/upload-cleanup-job.js +1 -1
  124. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  125. package/src/pro/storage/upload-pending-tracker.js +1 -1
  126. package/src/pro/websocket/broadcast-helper.js +1 -1
  127. package/src/pro/websocket/index.js +1 -1
  128. package/src/pro/websocket/livesync-server.js +1 -1
  129. package/src/pro/websocket/ws-broadcaster.js +1 -1
  130. package/src/services/export-service.js +1 -1
  131. package/src/services/import-service.js +1 -1
  132. package/src/services/kafkaConsumerService.js +1 -1
  133. package/src/services/kafkaService.js +1 -1
  134. package/src/services/messagehubService.js +1 -1
  135. package/src/services/rabbitmqService.js +1 -1
  136. package/src/utils/cache-invalidation-registry.js +1 -1
  137. package/src/utils/cache-manager.js +1 -1
  138. package/src/utils/component-engine.js +1 -1
  139. package/src/utils/config-extractor.js +1 -1
  140. package/src/utils/consumerLogger.js +1 -1
  141. package/src/utils/context-builder.js +1 -1
  142. package/src/utils/dashboard-helpers.js +1 -1
  143. package/src/utils/dateHelper.js +1 -1
  144. package/src/utils/datetime-formatter.js +1 -1
  145. package/src/utils/datetime-parser.js +1 -1
  146. package/src/utils/db-bootstrap.js +1 -1
  147. package/src/utils/db-mysql.js +1 -1
  148. package/src/utils/db-oracle.js +1 -1
  149. package/src/utils/db-sqlite.js +1 -1
  150. package/src/utils/db.js +1 -1
  151. package/src/utils/demo-generator.js +1 -1
  152. package/src/utils/excel-generator.js +1 -1
  153. package/src/utils/excel-parser.js +1 -1
  154. package/src/utils/file-watcher.js +1 -1
  155. package/src/utils/id-generator.js +1 -1
  156. package/src/utils/idempotency-manager.js +1 -1
  157. package/src/utils/import-validator.js +1 -1
  158. package/src/utils/license-client.js +1 -1
  159. package/src/utils/lock-manager.js +1 -1
  160. package/src/utils/logger.js +1 -1
  161. package/src/utils/lookup-resolver.js +1 -1
  162. package/src/utils/payload-loader.js +1 -1
  163. package/src/utils/processor-response.js +1 -1
  164. package/src/utils/rabbitmq.js +1 -1
  165. package/src/utils/redis-client.js +1 -1
  166. package/src/utils/redis-helper.js +1 -1
  167. package/src/utils/request-scope.js +1 -1
  168. package/src/utils/security-checks.js +1 -1
  169. package/src/utils/service-resolver.js +1 -1
  170. package/src/utils/shutdown-coordinator.js +1 -1
  171. package/src/utils/trusted-keys.js +1 -1
  172. package/src/utils/upload-handler.js +1 -1
  173. package/src/utils/upsert-builder.js +1 -1
  174. package/src/utils/workflow-hook-executor.js +1 -1
@@ -11,14 +11,17 @@
11
11
  * (amandemen arah B, lihat docs/plan/data-pull-push/data-pull-push-09-amendments.md).
12
12
  * Handler tetap tipis: seluruh logika berada di lib/data/pull-runner.js.
13
13
  *
14
- * Catatan: flag `--schema` (namespace) TIDAK dideklarasikan namespace tabel
15
- * diambil dari SDF IR (amandemen A4). Lokasi SDF ditentukan `--schema-path`.
14
+ * Catatan: scope tabel dipilih lewat tepat satu dari `--table` / `--schema` /
15
+ * `--all-schemas`. Flag `--schema` di sini adalah FILTER scope (bukan penentu
16
+ * namespace) — namespace tabel tetap diambil dari SDF IR (amandemen A4). Lokasi
17
+ * SDF ditentukan `--schema-path`. Layout output: bersarang `<schema>/<table>.json`
18
+ * untuk tabel ber-schema, flat `<table>.json` untuk tabel tanpa schema.
16
19
  */
17
20
 
18
21
  module.exports = {
19
22
  resource: 'data',
20
23
  verb: 'pull',
21
- description: 'Export isi tabel database ke file envelope JSON (data-storage/<table>.json) berdasarkan metadata SDF',
24
+ description: 'Export isi tabel database ke file envelope JSON (data-storage/<schema>/<table>.json) berdasarkan metadata SDF',
22
25
  category: 'introspection',
23
26
  flags: {
24
27
  table: {
@@ -27,11 +30,17 @@ module.exports = {
27
30
  default: null,
28
31
  description: 'Nama tabel sumber yang akan di-pull (harus terdaftar di SDF)'
29
32
  },
30
- 'all-tables': {
33
+ schema: {
34
+ type: 'string',
35
+ required: false,
36
+ default: null,
37
+ description: 'Filter schema: satu atau comma-separated (mutual-exclusive dengan --table/--all-schemas)'
38
+ },
39
+ 'all-schemas': {
31
40
  type: 'boolean',
32
41
  required: false,
33
42
  default: false,
34
- description: 'Pull seluruh tabel yang terdaftar di --schema-path (mutual-exclusive dengan --table)'
43
+ description: 'Pull seluruh tabel di semua schema (mutual-exclusive dengan --table/--schema)'
35
44
  },
36
45
  config: {
37
46
  type: 'string',
@@ -84,8 +93,8 @@ module.exports = {
84
93
  },
85
94
  examples: [
86
95
  'npx restforge data pull --table=visitors',
87
- 'npx restforge data pull --all-tables --config=db.env',
88
- 'npx restforge data pull --all-tables --config=db.env --json',
96
+ 'npx restforge data pull --schema=public --config=db.env',
97
+ 'npx restforge data pull --all-schemas --config=db.env --json',
89
98
  'npx restforge data pull --table=visitors --config=db.env --limit=500',
90
99
  'npx restforge data pull --table=visitors --config=db.env --json'
91
100
  ],
@@ -19,14 +19,18 @@
19
19
  * commit per batch). `--mode=...`/`--force` kini menjadi unknown flag → ditolak
20
20
  * arg-parser dengan exit 2 (perilaku standar).
21
21
  *
22
- * Catatan: flag `--schema` (namespace) TIDAK dideklarasikan namespace tabel
23
- * diambil dari SDF IR (amandemen A4). Lokasi SDF ditentukan `--schema-path`.
22
+ * Catatan: scope tabel dipilih lewat tepat satu dari `--table` / `--schema` /
23
+ * `--all-schemas`. Flag `--schema` adalah FILTER scope (bukan penentu namespace)
24
+ * namespace tabel tetap diambil dari SDF IR (amandemen A4). Lokasi SDF ditentukan
25
+ * `--schema-path`. Path input mengikuti aturan IDENTIK pull (bersarang
26
+ * `<schema>/<table>.json` untuk tabel ber-schema, flat `<table>.json` untuk tabel
27
+ * tanpa schema).
24
28
  */
25
29
 
26
30
  module.exports = {
27
31
  resource: 'data',
28
32
  verb: 'push',
29
- description: 'Muat isi file envelope JSON (data-storage/<table>.json) ke tabel tujuan via INSERT batch berdasarkan metadata SDF',
33
+ description: 'Muat isi file envelope JSON (data-storage/<schema>/<table>.json) ke tabel tujuan via INSERT batch berdasarkan metadata SDF',
30
34
  category: 'management',
31
35
  flags: {
32
36
  table: {
@@ -35,11 +39,17 @@ module.exports = {
35
39
  default: null,
36
40
  description: 'Nama tabel tujuan yang akan di-push (harus terdaftar di SDF)'
37
41
  },
38
- 'all-tables': {
42
+ schema: {
43
+ type: 'string',
44
+ required: false,
45
+ default: null,
46
+ description: 'Filter schema: satu atau comma-separated (mutual-exclusive dengan --table/--all-schemas)'
47
+ },
48
+ 'all-schemas': {
39
49
  type: 'boolean',
40
50
  required: false,
41
51
  default: false,
42
- description: 'Push seluruh tabel yang punya file di --storage-path, urut topological FK parent→child (mutual-exclusive dengan --table)'
52
+ description: 'Push seluruh tabel di semua schema, urut topological FK parent→child (mutual-exclusive dengan --table/--schema)'
43
53
  },
44
54
  config: {
45
55
  type: 'string',
@@ -74,8 +84,8 @@ module.exports = {
74
84
  },
75
85
  examples: [
76
86
  'npx restforge data push --table=visitors',
77
- 'npx restforge data push --all-tables --config=db.env',
78
- 'npx restforge data push --all-tables --config=db.env --json',
87
+ 'npx restforge data push --schema=public --config=db.env',
88
+ 'npx restforge data push --all-schemas --config=db.env --json',
79
89
  'npx restforge data push --table=visitors --config=db.env --batch-size=500',
80
90
  'npx restforge data push --table=visitors --config=db.env --json'
81
91
  ],
@@ -28,6 +28,11 @@ const http = require('node:http');
28
28
  const readline = require('node:readline');
29
29
  const { spawnSync } = require('node:child_process');
30
30
 
31
+ // Loader SDF yang SAMA dengan `schema migrate`. Bersifat rekursif sehingga
32
+ // struktur per-schema (mis. `schema/public/visitors.js`) ikut terbaca, dan
33
+ // mengembalikan IR model dengan relasi ter-normalisasi (sumber FK yang andal).
34
+ const { loadSchemaPath } = require('../lib/dbschema-kit/loader');
35
+
31
36
  // ---------------------------------------------------------------------------
32
37
  // Default konfigurasi (selaras dengan restforge-playbook/fast-track.mjs)
33
38
  // ---------------------------------------------------------------------------
@@ -207,9 +212,11 @@ const FALLBACK_TABLES = [
207
212
  ];
208
213
 
209
214
  /**
210
- * Mengumpulkan nama tabel dari folder schema bila ada; bila tidak, memakai
215
+ * Mengumpulkan nama tabel dari folder schema bila ada (rekursif, termasuk
216
+ * subfolder per schema seperti `schema/public/*.js`); bila tidak, memakai
211
217
  * daftar fallback yang dipadkan sampai 30 entri agar contoh kanonik (30 tabel)
212
- * tetap dapat dirender.
218
+ * tetap dapat dirender. Nama yang dikumpulkan adalah kebab tabel agar count
219
+ * preview konsisten dengan file payload/endpoint yang akan dibuat.
213
220
  */
214
221
  function collectTables(schemaDir) {
215
222
  let names = [];
@@ -217,10 +224,7 @@ function collectTables(schemaDir) {
217
224
 
218
225
  try {
219
226
  if (schemaDir && fs.existsSync(schemaDir) && fs.statSync(schemaDir).isDirectory()) {
220
- names = fs.readdirSync(schemaDir)
221
- .filter((f) => f.endsWith('.js') && !f.startsWith('_') && !f.endsWith('.test.js'))
222
- .map((f) => f.slice(0, -3))
223
- .sort();
227
+ names = loadModels(schemaDir).map((m) => m.kebab).sort();
224
228
  if (names.length > 0) realSchema = true;
225
229
  }
226
230
  } catch (_err) {
@@ -497,48 +501,64 @@ function ensureEnv(ctx) {
497
501
  const AUDIT_COLS = new Set(['created_at', 'created_by', 'updated_at', 'updated_by']);
498
502
 
499
503
  /**
500
- * Parse satu file SDF menjadi descriptor model. Deterministik dari SDF (tanpa DB):
501
- * { kebab, table, pk, fields[{name,isPk,isAudit,fk}], fks[{childCol,parentTable,parentCol}], displayCols }
502
- * displayCols = kolom yang mengandung `code`/`name`, di luar PK & kolom audit
503
- * (dipakai sebagai kolom display saat tabel ini menjadi parent FK).
504
+ * Turunkan kebab dari NAMA TABEL (bukan nama file) dengan normalisasi
505
+ * `[._]` -> `-`, identik dengan penamaan file output `payload generate`
506
+ * (payload-runner: baseFilename = table.replace(/[._]/g, '-')). Dengan ini
507
+ * `endpoint create --payload=<kebab>.json` dan `payload migrate --name=<kebab>.json`
508
+ * menemukan file payload yang benar, baik untuk SDF bernama underscore (hasil
509
+ * `schema introspect`, mis. `visitor_categories.js`) maupun kebab.
510
+ */
511
+ function tableToKebab(table) {
512
+ return table.replace(/[._]/g, '-');
513
+ }
514
+
515
+ /**
516
+ * Muat seluruh SDF di folder memakai loader dbschema-kit yang SAMA dengan
517
+ * `schema migrate`. Loader bersifat REKURSIF sehingga struktur per-schema
518
+ * (mis. `schema/public/visitors.js`) ikut terbaca; flat readdir lama hanya
519
+ * membaca top-level sehingga subfolder schema tidak dikenali.
520
+ *
521
+ * Mengembalikan descriptor per tabel (deterministik dari SDF, tanpa DB):
522
+ * { kebab, table, fks[{childCol,parentTable,parentCol}], displayCols }
523
+ *
524
+ * FK dibaca dari `relations` (belongsTo) pada IR model. IR menormalkan KEDUA
525
+ * gaya format: blok `relations:` eksplisit (gaya `schema introspect`) DAN inline
526
+ * `fk:<parent>.<col>` pada field (di-auto-promote ke relations oleh ir-builder).
527
+ * displayCols = kolom code/name di luar PK & kolom audit, dipakai sebagai kolom
528
+ * display saat tabel ini menjadi parent FK (untuk `payload sync --expand-fk`).
504
529
  */
505
- function parseModel(absFile, kebab) {
506
- let content = '';
507
- try { content = fs.readFileSync(absFile, 'utf8'); } catch (_err) { /* kosong */ }
508
- const table = (content.match(/defineModel\(\s*['"]([^'"]+)['"]/) || [, kebab.replace(/-/g, '_')])[1];
509
- const block = (content.match(/fields\s*:\s*\{([\s\S]*?)\}/) || [, ''])[1];
510
-
511
- const fields = [];
512
- const re = /(\w+)\s*:\s*'([^']*)'/g;
513
- let m;
514
- while ((m = re.exec(block)) !== null) {
515
- const name = m[1];
516
- const spec = m[2];
517
- const fkMatch = spec.match(/fk:(\w+)\.(\w+)/);
518
- fields.push({
519
- name,
520
- isPk: /\bpk\b/.test(spec),
521
- isAudit: AUDIT_COLS.has(name),
522
- fk: fkMatch ? { parentTable: fkMatch[1], parentCol: fkMatch[2] } : null
530
+ function loadModels(schemaDir) {
531
+ const models = loadSchemaPath(schemaDir);
532
+ const entries = [];
533
+ for (const model of models.values()) {
534
+ const table = model.tableName;
535
+ const primaryKey = Array.isArray(model.primaryKey) ? model.primaryKey : [];
536
+
537
+ const fks = [];
538
+ for (const rel of Object.values(model.relations || {})) {
539
+ if (rel.type !== 'belongsTo' || !rel.localKey || !rel.target) continue;
540
+ fks.push({
541
+ childCol: rel.localKey,
542
+ parentTable: rel.target,
543
+ parentCol: rel.references || null
544
+ });
545
+ }
546
+
547
+ const displayCols = Object.keys(model.fields || {}).filter((name) => {
548
+ const field = model.fields[name];
549
+ const isPk = (field && field.pk === true) || primaryKey.includes(name);
550
+ return !isPk && !AUDIT_COLS.has(name) && /(code|name)/i.test(name);
523
551
  });
524
- }
525
- const pk = (fields.find((f) => f.isPk) || {}).name || null;
526
- const displayCols = fields
527
- .filter((f) => !f.isPk && !f.isAudit && /(code|name)/i.test(f.name))
528
- .map((f) => f.name);
529
- const fks = fields
530
- .filter((f) => f.fk)
531
- .map((f) => ({ childCol: f.name, parentTable: f.fk.parentTable, parentCol: f.fk.parentCol }));
532
552
 
533
- return { kebab, table, pk, fields, fks, displayCols };
553
+ entries.push({ kebab: tableToKebab(table), table, fks, displayCols });
554
+ }
555
+ entries.sort((a, b) => a.table.localeCompare(b.table));
556
+ return entries;
534
557
  }
535
558
 
536
- /** Bangun daftar model dari folder schema. */
559
+ /** Bangun daftar model dari folder schema (rekursif, via loader bersama). */
537
560
  function buildTableEntries(schemaDir) {
538
- const files = fs.readdirSync(schemaDir)
539
- .filter((f) => f.endsWith('.js') && !f.startsWith('_') && !f.endsWith('.test.js'))
540
- .sort();
541
- return files.map((f) => parseModel(path.join(schemaDir, f), f.slice(0, -3)));
561
+ return loadModels(schemaDir);
542
562
  }
543
563
 
544
564
  /**
@@ -946,5 +966,5 @@ module.exports = {
946
966
  // terpisah tanpa menjalankan pipeline penuh. Pada penggunaan CLI normal env ini
947
967
  // tidak di-set sehingga export tetap berupa contract murni.
948
968
  if (process.env.FASTTRACK_TEST === '1') {
949
- module.exports.__test = { parseModel, buildTableEntries, fkColumnsForEntry };
969
+ module.exports.__test = { loadModels, buildTableEntries, fkColumnsForEntry, tableToKebab };
950
970
  }