@restforgejs/platform 4.1.1 → 4.3.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/SECURITY.md +83 -4
- 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/dashboard/create.js +4 -1
- package/generators/cli/endpoint/create.js +43 -4
- package/generators/cli/key/generate.js +2 -1
- package/generators/cli/key/revoke.js +2 -1
- package/generators/cli/payload/diff.js +3 -2
- package/generators/cli/payload/generate.js +3 -2
- package/generators/cli/payload/sync.js +3 -2
- package/generators/cli/payload/validate.js +3 -2
- package/generators/cli/processor/create.js +14 -3
- package/generators/cli/project/delete.js +2 -1
- package/generators/cli/query/validate.js +3 -2
- package/generators/cli/schema/apply.js +526 -0
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +322 -0
- package/generators/cli/schema/generate-ddl.js +7 -10
- package/generators/cli/schema/init.js +95 -172
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +13 -18
- package/generators/cli/schema/models.js +8 -12
- package/generators/cli/schema/template.js +222 -0
- package/generators/cli/schema/validate.js +8 -12
- package/generators/cli-entry.js +17 -2
- package/generators/lib/dbschema-kit/apply-engine.js +582 -0
- package/generators/lib/dbschema-kit/diff-engine.js +703 -0
- package/generators/lib/dbschema-kit/diff-reporter.js +272 -0
- package/generators/lib/dbschema-kit/emitters/alter-table.js +275 -0
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/endpoint-schema-validator.js +171 -0
- package/generators/lib/payload/payload-runner.js +137 -220
- package/generators/lib/payload/schema-diff.js +277 -0
- package/generators/lib/templates/dashboard-catalog.js +1 -437
- package/generators/lib/templates/db-connection-env.js +1 -212
- package/generators/lib/templates/dbschema-catalog.js +1 -489
- package/generators/lib/templates/field-validation-catalog.js +1 -531
- package/generators/lib/templates/mysql-template.js +1 -3863
- package/generators/lib/templates/oracle-template.js +1 -3915
- package/generators/lib/templates/postgres-template.js +1 -5838
- package/generators/lib/templates/query-declarative-catalog.js +1 -199
- package/generators/lib/templates/sqlite-template.js +1 -3440
- package/generators/lib/utils/audit-columns.js +181 -0
- package/generators/lib/utils/cli-output.js +17 -0
- package/generators/lib/utils/database-introspector.js +16 -13
- package/generators/lib/utils/env-manager.js +6 -0
- package/generators/lib/utils/path-validator.js +71 -0
- package/generators/lib/validators/payload-validator.js +1 -2
- package/integrity-manifest.json +28 -10
- package/package.json +11 -3
- 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/metadata/global.json +0 -58
- package/generators/metadata/test-mysql-workbench.json +0 -118
- package/generators/metadata/test-mysql.json +0 -56
- package/generators/metadata/test-oracle-workbench.json +0 -118
- package/generators/metadata/test-oracle.json +0 -56
- package/generators/metadata/test-pg-workbench.json +0 -118
- package/generators/metadata/test-pg.json +0 -56
- package/generators/scripts/obfuscate-source.js +0 -356
- package/generators/scripts/validate-catalog.js +0 -430
- package/generators/scripts/validate-dbschema-catalog.js +0 -708
- package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
- package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
- package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
- package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
- package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
- package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
- package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
- package/generators/tests/fixtures/payloads/order-process.json +0 -52
- package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
- package/generators/tests/integration-tahap4b/README.md +0 -145
- package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
- package/generators/tests/integration-tahap4b/seed.sql +0 -53
- package/generators/tests/integration-tahap4b/verify.sql +0 -110
- package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
- package/generators/tests/unit/cli/create-processor.test.js +0 -319
- package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
- package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
- package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
- package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
- package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
- package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
- package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
- package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
- package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
- package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
- package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
- package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
- package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
- package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
- package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
- package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
- package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
- package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
- package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
- package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
- package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
- package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
- package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
- package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
- package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
- package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
- package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
- package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
- package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
- package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
- package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
- package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
- package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
- package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
- package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
- package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
- package/scripts/generate-integrity-manifest.js +0 -124
- package/scripts/snapshot-cli-contracts.js +0 -194
- package/scripts/verify-publish.js +0 -56
package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js
DELETED
|
@@ -1,740 +0,0 @@
|
|
|
1
|
-
const express = require('express');
|
|
2
|
-
const router = express.Router();
|
|
3
|
-
const itemModel = require('../../models/mini-inventory/item');
|
|
4
|
-
let componentEngine = null;
|
|
5
|
-
let ContextBuilder = null;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Item Submodule - MySQL Database
|
|
9
|
-
* Generated: 2026-04-25T07:54:01.306Z
|
|
10
|
-
*
|
|
11
|
-
* MySQL-optimized endpoints untuk item
|
|
12
|
-
* Actions: datatables, create, update, delete, lookup, read
|
|
13
|
-
* Table: core.item
|
|
14
|
-
* Database: MySQL
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
// Primary key untuk endpoint ini
|
|
18
|
-
const primaryKey = 'id';
|
|
19
|
-
|
|
20
|
-
// Component configuration untuk export/import (parsed oleh config-extractor — jangan dimodifikasi)
|
|
21
|
-
const componentConfig = {
|
|
22
|
-
tableName: 'core.item',
|
|
23
|
-
fieldName: ["item_id","item_code","item_name","description","uom","unit_price","weight","is_active","created_at","created_by","updated_at","updated_by"],
|
|
24
|
-
exportQuery: null,
|
|
25
|
-
columnFormats: null,
|
|
26
|
-
fieldLabels: null,
|
|
27
|
-
importConfig: null,
|
|
28
|
-
adjustConfig: null,
|
|
29
|
-
uploadConfig: null,
|
|
30
|
-
requestScope: null
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// CORS ditangani di level app oleh cors middleware (lihat konfigurasi CORS_ENABLED dan CORS_ORIGINS di .env)
|
|
34
|
-
|
|
35
|
-
// Request ID untuk tracing — support correlation ID dari upstream
|
|
36
|
-
router.use((req, res, next) => {
|
|
37
|
-
req.mysqlRequestId = req.headers['x-correlation-id'] || `mysql_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
38
|
-
res.setHeader('X-Correlation-ID', req.mysqlRequestId);
|
|
39
|
-
res.setHeader('X-MySQL-Request-ID', req.mysqlRequestId);
|
|
40
|
-
next();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Middleware untuk validasi payload MySQL
|
|
46
|
-
router.use((req, res, next) => {
|
|
47
|
-
if (req.method === 'POST') {
|
|
48
|
-
// Skip validation untuk endpoint export/import (ditangani oleh centralized handler)
|
|
49
|
-
if (req.path.startsWith('/import') || req.path.startsWith('/export')) {
|
|
50
|
-
return next();
|
|
51
|
-
}
|
|
52
|
-
try {
|
|
53
|
-
if (!req.body || Object.keys(req.body).length === 0) {
|
|
54
|
-
return res.status(400).json({
|
|
55
|
-
success: false,
|
|
56
|
-
error: 'Missing payload',
|
|
57
|
-
message: 'Payload cannot be empty',
|
|
58
|
-
timestamp: new Date().toISOString()
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const endpoint = req.path.substring(1);
|
|
63
|
-
|
|
64
|
-
if (endpoint === 'first') {
|
|
65
|
-
if (Array.isArray(req.body.where) && req.body.where.length === 1) {
|
|
66
|
-
req.body.where = req.body.where[0];
|
|
67
|
-
}
|
|
68
|
-
if (!req.body.where || typeof req.body.where !== 'object' || Array.isArray(req.body.where)) {
|
|
69
|
-
return res.status(400).json({
|
|
70
|
-
success: false,
|
|
71
|
-
error: 'Invalid payload',
|
|
72
|
-
message: 'Where must be a single condition {key, value}',
|
|
73
|
-
example: {
|
|
74
|
-
"where": { "key": "field_name", "value": "field_value" },
|
|
75
|
-
"select": ["field1", "field2"]
|
|
76
|
-
},
|
|
77
|
-
timestamp: new Date().toISOString()
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
if (req.body.where.conditions || req.body.where.logic) {
|
|
81
|
-
return res.status(400).json({
|
|
82
|
-
success: false,
|
|
83
|
-
error: 'Invalid payload',
|
|
84
|
-
message: 'Advanced where format is not supported in /first endpoint. Use /read endpoint for complex queries',
|
|
85
|
-
example: {
|
|
86
|
-
"where": { "key": "field_name", "value": "field_value" }
|
|
87
|
-
},
|
|
88
|
-
timestamp: new Date().toISOString()
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (endpoint === 'delete' && (!req.body.where)) {
|
|
94
|
-
return res.status(400).json({
|
|
95
|
-
success: false,
|
|
96
|
-
error: 'Invalid payload',
|
|
97
|
-
message: 'DELETE payload must include a where property',
|
|
98
|
-
example: {
|
|
99
|
-
"where": [{ "key": "id", "value": "your-value" }]
|
|
100
|
-
},
|
|
101
|
-
timestamp: new Date().toISOString()
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
} catch (error) {
|
|
105
|
-
console.error(`Error validating MySQL payload for ${req.path}:`, error);
|
|
106
|
-
return res.status(400).json({
|
|
107
|
-
success: false,
|
|
108
|
-
error: 'Invalid payload',
|
|
109
|
-
message: 'Invalid payload format',
|
|
110
|
-
details: error.message,
|
|
111
|
-
timestamp: new Date().toISOString()
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
next();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// POST /api/mini-inventory/item/datatables - Data untuk DataTables
|
|
119
|
-
router.post('/datatables', async (req, res) => {
|
|
120
|
-
try {
|
|
121
|
-
const options = {
|
|
122
|
-
searchValue: req.body.search?.value || req.body.searchValue || req.body.search_value || '',
|
|
123
|
-
searchBy: req.body.searchBy || req.body.search_by || 'all',
|
|
124
|
-
perPage: Math.min(parseInt(req.body.length || req.body.pagination?.perpage || 10, 10), 1000),
|
|
125
|
-
start: Math.max(parseInt(req.body.start || 0, 10), 0),
|
|
126
|
-
draw: req.body.draw || '1'
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
// Handle sort_columns
|
|
130
|
-
if (req.body.sort_columns && Array.isArray(req.body.sort_columns) && req.body.sort_columns.length > 0) {
|
|
131
|
-
options.sort_columns = req.body.sort_columns.map(item => ({
|
|
132
|
-
column: item.column,
|
|
133
|
-
direction: (item.direction || 'ASC').toUpperCase()
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Fallback: Handle DataTables standard format (order[0][column] dan order[0][dir])
|
|
138
|
-
if (req.body['order[0][column]'] !== undefined) {
|
|
139
|
-
options['order[0][column]'] = req.body['order[0][column]'];
|
|
140
|
-
}
|
|
141
|
-
if (req.body['order[0][dir]'] !== undefined) {
|
|
142
|
-
options['order[0][dir]'] = req.body['order[0][dir]'];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Handle filters dengan sanitasi
|
|
146
|
-
if (req.body.filters && typeof req.body.filters === 'object') {
|
|
147
|
-
const sanitizedFilters = {};
|
|
148
|
-
for (const [key, value] of Object.entries(req.body.filters)) {
|
|
149
|
-
if (value !== null && value !== undefined && value !== '' && value !== 'all' && value !== '-') {
|
|
150
|
-
sanitizedFilters[key] = value;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (Object.keys(sanitizedFilters).length > 0) {
|
|
154
|
-
options.filters = sanitizedFilters;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Support WHERE conditions
|
|
159
|
-
if (req.body.where) {
|
|
160
|
-
options.where = req.body.where;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Advanced filters support
|
|
164
|
-
if (req.body.advanced_filters && Array.isArray(req.body.advanced_filters)) {
|
|
165
|
-
options.advancedFilters = req.body.advanced_filters;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Gunakan model untuk mendapatkan data
|
|
169
|
-
const result = await itemModel.getDatatables(options);
|
|
170
|
-
|
|
171
|
-
// Menambahkan nomor baris untuk DataTables
|
|
172
|
-
if (result.data && Array.isArray(result.data)) {
|
|
173
|
-
result.data = result.data.map((item, index) => ({
|
|
174
|
-
...item,
|
|
175
|
-
rownumerator: options.start + index + 1
|
|
176
|
-
}));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return res.json(result);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error('Error in item datatables:', error);
|
|
182
|
-
const statusCode = error.statusCode || 500;
|
|
183
|
-
return res.status(statusCode).json({
|
|
184
|
-
success: false,
|
|
185
|
-
error: statusCode === 400 ? 'Bad Request' : 'Internal Server Error',
|
|
186
|
-
message: statusCode === 400 ? error.message : 'An error occurred while fetching item data',
|
|
187
|
-
details: process.env.NODE_ENV === 'development' ? error.message : undefined,
|
|
188
|
-
timestamp: new Date().toISOString()
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
// GET /api/mini-inventory/item/lookup - MySQL Dynamic Lookup
|
|
194
|
-
router.get('/lookup', async (req, res) => {
|
|
195
|
-
const mysqlRequestId = req.mysqlRequestId;
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
const requestMode = req.headers['x-request-mode'];
|
|
199
|
-
|
|
200
|
-
if (requestMode !== 'dynamic') {
|
|
201
|
-
return res.status(400).json({
|
|
202
|
-
success: false,
|
|
203
|
-
error: 'Invalid Request Mode',
|
|
204
|
-
message: 'X-Request-Mode header must be set to dynamic',
|
|
205
|
-
timestamp: new Date().toISOString()
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
let search = req.query.search || '';
|
|
210
|
-
if (Array.isArray(search)) {
|
|
211
|
-
search = search[0] || '';
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Search length validation
|
|
215
|
-
if (search.length > 100) {
|
|
216
|
-
return res.status(400).json({
|
|
217
|
-
success: false,
|
|
218
|
-
error: 'Search Too Long',
|
|
219
|
-
message: 'Search parameter must not exceed 100 characters',
|
|
220
|
-
timestamp: new Date().toISOString()
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
console.log(`[MySQL-LKP] ${mysqlRequestId} dynamic search: ${search}`);
|
|
225
|
-
|
|
226
|
-
// Collect extra filters dari query params
|
|
227
|
-
const extraFilters = {};
|
|
228
|
-
for (const [key, value] of Object.entries(req.query)) {
|
|
229
|
-
if (key !== 'search' && itemModel.validFields.includes(key) && value) {
|
|
230
|
-
extraFilters[key] = value;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const startTime = Date.now();
|
|
235
|
-
const list = Object.keys(extraFilters).length > 0 ?
|
|
236
|
-
await itemModel.getLookupDataDynamic(search, extraFilters) :
|
|
237
|
-
await itemModel.getLookupData(search);
|
|
238
|
-
const lookupTime = Date.now() - startTime;
|
|
239
|
-
|
|
240
|
-
console.log(`[MySQL-LKP] ${mysqlRequestId} found ${list.length} results in ${lookupTime}ms`);
|
|
241
|
-
|
|
242
|
-
return res.json({
|
|
243
|
-
success: true,
|
|
244
|
-
count: list.length,
|
|
245
|
-
data: list,
|
|
246
|
-
search: search,
|
|
247
|
-
_mysql: { requestId: mysqlRequestId, queryTime: lookupTime, timestamp: new Date().toISOString() }
|
|
248
|
-
});
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error(`[MySQL-LKP] Error ${mysqlRequestId}:`, error);
|
|
251
|
-
return res.status(500).json({
|
|
252
|
-
success: false,
|
|
253
|
-
error: 'Internal Server Error',
|
|
254
|
-
message: 'An error occurred while looking up item data',
|
|
255
|
-
details: error.message,
|
|
256
|
-
timestamp: new Date().toISOString()
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
// POST /api/mini-inventory/item/lookup - MySQL Static Lookup
|
|
262
|
-
router.post('/lookup', async (req, res) => {
|
|
263
|
-
const mysqlRequestId = req.mysqlRequestId;
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
const requestMode = req.headers['x-request-mode'];
|
|
267
|
-
|
|
268
|
-
if (requestMode !== 'static') {
|
|
269
|
-
return res.status(400).json({
|
|
270
|
-
success: false,
|
|
271
|
-
error: 'Invalid Request Mode',
|
|
272
|
-
message: 'X-Request-Mode header must be set to static for POST lookup',
|
|
273
|
-
timestamp: new Date().toISOString()
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
console.log(`[MySQL-LKP] ${mysqlRequestId} static lookup:`, JSON.stringify(req.body, null, 2));
|
|
278
|
-
|
|
279
|
-
const startTime = Date.now();
|
|
280
|
-
let list;
|
|
281
|
-
|
|
282
|
-
if (req.body.where) {
|
|
283
|
-
// New format dengan where clause + optional select dan order
|
|
284
|
-
list = await itemModel.getLookupDataWithFilter(req.body);
|
|
285
|
-
} else {
|
|
286
|
-
// Legacy format dengan selected_tag
|
|
287
|
-
const selectedTag = req.body.selected_tag || '';
|
|
288
|
-
list = await itemModel.getStaticLookupData(selectedTag);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const lookupTime = Date.now() - startTime;
|
|
292
|
-
console.log(`[MySQL-LKP] ${mysqlRequestId} found ${list.length} results in ${lookupTime}ms`);
|
|
293
|
-
|
|
294
|
-
return res.json({
|
|
295
|
-
success: true,
|
|
296
|
-
count: list.length,
|
|
297
|
-
data: list,
|
|
298
|
-
_mysql: { requestId: mysqlRequestId, queryTime: lookupTime, timestamp: new Date().toISOString() }
|
|
299
|
-
});
|
|
300
|
-
} catch (error) {
|
|
301
|
-
console.error(`[MySQL-LKP] Error ${mysqlRequestId}:`, error);
|
|
302
|
-
return res.status(500).json({
|
|
303
|
-
success: false,
|
|
304
|
-
error: 'Internal Server Error',
|
|
305
|
-
message: 'An error occurred while looking up item data',
|
|
306
|
-
details: error.message,
|
|
307
|
-
timestamp: new Date().toISOString()
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// POST /api/mini-inventory/item/create - MySQL Insert
|
|
313
|
-
router.post('/create', async (req, res) => {
|
|
314
|
-
try {
|
|
315
|
-
if (!req.body || Object.keys(req.body).length === 0) {
|
|
316
|
-
return res.status(400).json({
|
|
317
|
-
success: false,
|
|
318
|
-
error: 'Invalid payload',
|
|
319
|
-
message: 'Payload cannot be empty',
|
|
320
|
-
timestamp: new Date().toISOString()
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Validasi data
|
|
325
|
-
if (typeof itemModel.validateData === 'function') {
|
|
326
|
-
const validation = await itemModel.validateData(req.body, 'insert');
|
|
327
|
-
if (!validation.isValid) {
|
|
328
|
-
return res.status(400).json({
|
|
329
|
-
success: false,
|
|
330
|
-
error: 'Validation failed',
|
|
331
|
-
message: 'Invalid data',
|
|
332
|
-
errors: validation.errors,
|
|
333
|
-
timestamp: new Date().toISOString()
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
req.body = { ...req.body, ...validation.sanitizedData };
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
var result = await itemModel.addData(req.body, { additionalContext: { requestId: req.id || null } });
|
|
342
|
-
console.log('[FALLBACK] INSERT completed without events');
|
|
343
|
-
} catch (error) {
|
|
344
|
-
console.error('[FALLBACK] INSERT failed:', error.message);
|
|
345
|
-
throw error;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
console.log(`item data added successfully: ${result.id || 'new record'}`);
|
|
349
|
-
|
|
350
|
-
return res.status(201).json({
|
|
351
|
-
success: true,
|
|
352
|
-
message: 'item data successfully added',
|
|
353
|
-
data: result,
|
|
354
|
-
timestamp: new Date().toISOString()
|
|
355
|
-
});
|
|
356
|
-
} catch (error) {
|
|
357
|
-
console.error('Error saat menambahkan data item:', error);
|
|
358
|
-
|
|
359
|
-
if (error.code === 'ER_DUP_ENTRY' || error.errno === 1062) {
|
|
360
|
-
return res.status(409).json({
|
|
361
|
-
success: false,
|
|
362
|
-
error: 'Duplicate entry',
|
|
363
|
-
message: 'A record with this value already exists',
|
|
364
|
-
timestamp: new Date().toISOString()
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (error.code === 'ER_NO_REFERENCED_ROW_2' || error.errno === 1452) {
|
|
369
|
-
return res.status(400).json({
|
|
370
|
-
success: false,
|
|
371
|
-
error: 'Foreign key constraint',
|
|
372
|
-
message: 'Referenced data not found',
|
|
373
|
-
timestamp: new Date().toISOString()
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return res.status(500).json({
|
|
378
|
-
success: false,
|
|
379
|
-
error: 'Internal Server Error',
|
|
380
|
-
message: 'An error occurred while adding item data',
|
|
381
|
-
details: process.env.NODE_ENV === 'development' ? error.message : undefined,
|
|
382
|
-
timestamp: new Date().toISOString()
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
// POST /api/mini-inventory/item/update - MySQL Update
|
|
388
|
-
router.post('/update', async (req, res) => {
|
|
389
|
-
try {
|
|
390
|
-
// Validasi payload
|
|
391
|
-
if (!req.body || Object.keys(req.body).length === 0) {
|
|
392
|
-
return res.status(400).json({
|
|
393
|
-
success: false,
|
|
394
|
-
error: 'Invalid payload',
|
|
395
|
-
message: 'Payload cannot be empty',
|
|
396
|
-
timestamp: new Date().toISOString()
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
// Validasi primary key
|
|
401
|
-
const primaryKey = 'id';
|
|
402
|
-
if (!req.body[primaryKey]) {
|
|
403
|
-
return res.status(400).json({
|
|
404
|
-
success: false,
|
|
405
|
-
error: 'Missing required field',
|
|
406
|
-
message: `Primary key (${primaryKey}) is required for update`,
|
|
407
|
-
timestamp: new Date().toISOString()
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// Validasi data dengan model jika tersedia
|
|
412
|
-
if (typeof itemModel.validateData === 'function') {
|
|
413
|
-
const validation = await itemModel.validateData(req.body, 'update');
|
|
414
|
-
if (!validation.isValid) {
|
|
415
|
-
return res.status(400).json({
|
|
416
|
-
success: false,
|
|
417
|
-
error: 'Validation failed',
|
|
418
|
-
message: 'Invalid data',
|
|
419
|
-
errors: validation.errors,
|
|
420
|
-
timestamp: new Date().toISOString()
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
req.body = { ...req.body, ...validation.sanitizedData };
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
let responseData = null;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
// Fallback: mode tanpa events
|
|
430
|
-
try {
|
|
431
|
-
responseData = await itemModel.updateData(req.body, { additionalContext: { requestId: req.id || null } });
|
|
432
|
-
console.log('[FALLBACK] UPDATE completed without events');
|
|
433
|
-
} catch (error) {
|
|
434
|
-
console.error('[FALLBACK] UPDATE failed:', error.message);
|
|
435
|
-
throw error;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Log successful operation
|
|
439
|
-
console.log(`item data updated successfully: id=${req.body['id']}`);
|
|
440
|
-
|
|
441
|
-
return res.status(200).json({
|
|
442
|
-
success: true,
|
|
443
|
-
message: 'item data successfully updated',
|
|
444
|
-
data: responseData,
|
|
445
|
-
timestamp: new Date().toISOString()
|
|
446
|
-
});
|
|
447
|
-
} catch (error) {
|
|
448
|
-
console.error('Error saat mengupdate data item:', error);
|
|
449
|
-
|
|
450
|
-
if (error.message === 'Data tidak ditemukan' || error.message.includes('not found')) {
|
|
451
|
-
return res.status(404).json({
|
|
452
|
-
success: false,
|
|
453
|
-
error: 'Data not found',
|
|
454
|
-
message: 'item data not found',
|
|
455
|
-
timestamp: new Date().toISOString()
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (error.code === 'ER_DUP_ENTRY' || error.errno === 1062) {
|
|
460
|
-
return res.status(409).json({
|
|
461
|
-
success: false,
|
|
462
|
-
error: 'Duplicate entry',
|
|
463
|
-
message: 'A record with this value already exists',
|
|
464
|
-
timestamp: new Date().toISOString()
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
return res.status(500).json({
|
|
469
|
-
success: false,
|
|
470
|
-
error: 'Internal Server Error',
|
|
471
|
-
message: 'An error occurred while updating item data',
|
|
472
|
-
details: process.env.NODE_ENV === 'development' ? error.message : undefined,
|
|
473
|
-
timestamp: new Date().toISOString()
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// POST /api/mini-inventory/item/delete - MySQL Delete
|
|
479
|
-
router.post('/delete', async (req, res) => {
|
|
480
|
-
try {
|
|
481
|
-
// Validasi request body
|
|
482
|
-
if (!req.body || Object.keys(req.body).length === 0) {
|
|
483
|
-
return res.status(400).json({
|
|
484
|
-
success: false,
|
|
485
|
-
error: 'Invalid payload',
|
|
486
|
-
message: 'Payload cannot be empty',
|
|
487
|
-
timestamp: new Date().toISOString()
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (!req.body.where) {
|
|
492
|
-
return res.status(400).json({
|
|
493
|
-
success: false,
|
|
494
|
-
error: 'Missing required field',
|
|
495
|
-
message: 'Invalid request format: where parameter is required',
|
|
496
|
-
example: {
|
|
497
|
-
"where": [{ "key": "id", "value": "your-id-value" }]
|
|
498
|
-
},
|
|
499
|
-
timestamp: new Date().toISOString()
|
|
500
|
-
});
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Validasi format where
|
|
504
|
-
if (!Array.isArray(req.body.where) && !req.body.where.conditions) {
|
|
505
|
-
return res.status(400).json({
|
|
506
|
-
success: false,
|
|
507
|
-
error: 'Invalid where format',
|
|
508
|
-
message: 'Invalid where format',
|
|
509
|
-
example: {
|
|
510
|
-
"where": [
|
|
511
|
-
{ "key": "id", "value": "your-id-value" }
|
|
512
|
-
]
|
|
513
|
-
},
|
|
514
|
-
timestamp: new Date().toISOString()
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
let responseData = null;
|
|
519
|
-
|
|
520
|
-
// Cek apakah data exist sebelum delete dan ambil old data untuk event lifecycle
|
|
521
|
-
// Menggunakan SELECT * dari tabel utama (tanpa explicit select) karena fieldName
|
|
522
|
-
// bisa mengandung kolom dari JOIN (mis. city_name) yang tidak ada di tabel utama
|
|
523
|
-
if (req.body.where && Array.isArray(req.body.where) && req.body.where.length > 0) {
|
|
524
|
-
const firstCondition = req.body.where[0];
|
|
525
|
-
try {
|
|
526
|
-
const existingData = await itemModel.getData({
|
|
527
|
-
where: [{ key: firstCondition.key, value: firstCondition.value }]
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
if (!existingData.success || !existingData.data || existingData.data.length === 0) {
|
|
531
|
-
return res.status(404).json({
|
|
532
|
-
success: false,
|
|
533
|
-
error: 'Data not found',
|
|
534
|
-
message: 'item data not found',
|
|
535
|
-
timestamp: new Date().toISOString()
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
} catch (checkError) {
|
|
539
|
-
return res.status(500).json({
|
|
540
|
-
success: false,
|
|
541
|
-
error: 'Verification Failed',
|
|
542
|
-
message: 'Could not verify data existence before delete',
|
|
543
|
-
details: process.env.NODE_ENV === 'development' ? checkError.message : undefined,
|
|
544
|
-
timestamp: new Date().toISOString()
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// Fallback: mode tanpa events
|
|
551
|
-
try {
|
|
552
|
-
responseData = await itemModel.deleteData(req.body, { additionalContext: { requestId: req.id || null } });
|
|
553
|
-
console.log('[FALLBACK] DELETE completed without events');
|
|
554
|
-
} catch (error) {
|
|
555
|
-
console.error('[FALLBACK] DELETE failed:', error.message);
|
|
556
|
-
throw error;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// Log successful operation
|
|
560
|
-
console.log(`item data deleted successfully`);
|
|
561
|
-
|
|
562
|
-
return res.json({
|
|
563
|
-
...responseData,
|
|
564
|
-
timestamp: new Date().toISOString()
|
|
565
|
-
});
|
|
566
|
-
} catch (error) {
|
|
567
|
-
console.error('Error saat menghapus data item:', error);
|
|
568
|
-
|
|
569
|
-
if (error.code === 'ER_ROW_IS_REFERENCED_2' || error.errno === 1451) {
|
|
570
|
-
return res.status(409).json({
|
|
571
|
-
success: false,
|
|
572
|
-
error: 'Foreign key constraint',
|
|
573
|
-
message: 'Cannot delete: record is still referenced by other data',
|
|
574
|
-
timestamp: new Date().toISOString()
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return res.status(500).json({
|
|
579
|
-
success: false,
|
|
580
|
-
error: 'Internal Server Error',
|
|
581
|
-
message: 'An error occurred while deleting item data',
|
|
582
|
-
details: process.env.NODE_ENV === 'development' ? error.message : undefined,
|
|
583
|
-
timestamp: new Date().toISOString()
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
// POST /api/mini-inventory/item/read - Manual pagination endpoint
|
|
589
|
-
router.post('/read', async (req, res) => {
|
|
590
|
-
try {
|
|
591
|
-
// Deteksi mode: paginasi (page dikirim) atau non-paginasi (page tidak dikirim)
|
|
592
|
-
const paginate = req.body.page !== undefined;
|
|
593
|
-
const page = paginate ? parseInt(req.body.page, 10) : null;
|
|
594
|
-
const perPage = paginate ? Math.min(parseInt(req.body.per_page || 10, 10), 100) : null;
|
|
595
|
-
const limit = !paginate ? Math.min(Math.max(parseInt(req.body.limit || 1000, 10), 1), 5000) : null;
|
|
596
|
-
const searchValue = req.body.search_value || '';
|
|
597
|
-
const searchBy = req.body.search_by || 'all';
|
|
598
|
-
|
|
599
|
-
// Parse sort_columns
|
|
600
|
-
let sort_columns = [];
|
|
601
|
-
if (req.body.sort_columns && Array.isArray(req.body.sort_columns) && req.body.sort_columns.length > 0) {
|
|
602
|
-
sort_columns = req.body.sort_columns.map(item => ({
|
|
603
|
-
column: item.column,
|
|
604
|
-
direction: (item.direction || 'ASC').toUpperCase()
|
|
605
|
-
}));
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Validasi parameter paginasi (hanya jika mode paginasi)
|
|
609
|
-
if (paginate && page < 1) {
|
|
610
|
-
return res.status(400).json({
|
|
611
|
-
success: false,
|
|
612
|
-
error: 'Invalid page',
|
|
613
|
-
message: 'Page must be greater than 0',
|
|
614
|
-
timestamp: new Date().toISOString()
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
// Proses parameter where dengan format advanced conditions
|
|
619
|
-
let where = null;
|
|
620
|
-
if (req.body.where && typeof req.body.where === 'object') {
|
|
621
|
-
if (Array.isArray(req.body.where) || (req.body.where.conditions && Array.isArray(req.body.where.conditions))) {
|
|
622
|
-
where = req.body.where;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Proses parameter select untuk kolom selektif
|
|
627
|
-
const validFields = ["item_id","item_code","item_name","description","uom","unit_price","weight","is_active","created_at","created_by","updated_at","updated_by"];
|
|
628
|
-
let select = null;
|
|
629
|
-
if (req.body.select && Array.isArray(req.body.select)) {
|
|
630
|
-
const invalidFields = req.body.select.filter(field => !validFields.includes(field));
|
|
631
|
-
if (invalidFields.length > 0) {
|
|
632
|
-
return res.status(400).json({
|
|
633
|
-
success: false,
|
|
634
|
-
error: 'Invalid select fields',
|
|
635
|
-
message: 'Invalid field(s): ' + invalidFields.join(', '),
|
|
636
|
-
validFields: validFields,
|
|
637
|
-
timestamp: new Date().toISOString()
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
select = req.body.select;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
const options = {
|
|
644
|
-
searchValue,
|
|
645
|
-
searchBy,
|
|
646
|
-
sort_columns,
|
|
647
|
-
where: where,
|
|
648
|
-
select: select
|
|
649
|
-
};
|
|
650
|
-
|
|
651
|
-
if (paginate) {
|
|
652
|
-
options.page = page;
|
|
653
|
-
options.perPage = perPage;
|
|
654
|
-
} else {
|
|
655
|
-
options.limit = limit;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
const result = await itemModel.getList(options);
|
|
659
|
-
|
|
660
|
-
// Format response berdasarkan mode
|
|
661
|
-
if (paginate) {
|
|
662
|
-
return res.json({
|
|
663
|
-
success: true,
|
|
664
|
-
data: result.data,
|
|
665
|
-
count: result.data ? result.data.length : 0,
|
|
666
|
-
pagination: result.pagination,
|
|
667
|
-
message: 'Data retrieved successfully'
|
|
668
|
-
});
|
|
669
|
-
} else {
|
|
670
|
-
return res.json({
|
|
671
|
-
success: true,
|
|
672
|
-
data: result.data,
|
|
673
|
-
count: result.data ? result.data.length : 0
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
} catch (error) {
|
|
677
|
-
console.error('Error in item list:', error);
|
|
678
|
-
const statusCode = error.statusCode || 500;
|
|
679
|
-
return res.status(statusCode).json({
|
|
680
|
-
success: false,
|
|
681
|
-
error: statusCode === 400 ? 'Bad Request' : 'Internal Server Error',
|
|
682
|
-
message: statusCode === 400 ? error.message : 'An error occurred while fetching item list data',
|
|
683
|
-
details: process.env.NODE_ENV === 'development' ? error.message : undefined,
|
|
684
|
-
timestamp: new Date().toISOString()
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
|
|
689
|
-
// MySQL endpoint information — self-documenting API
|
|
690
|
-
router.get('/info', async (req, res) => {
|
|
691
|
-
try {
|
|
692
|
-
const actions = {"datatables":true,"read":true,"first":false,"create":true,"update":true,"delete":true,"lookup":true,"export":false,"import":false,"info":true};
|
|
693
|
-
const modelInfo = await itemModel.getModelInfo(actions);
|
|
694
|
-
|
|
695
|
-
res.json({
|
|
696
|
-
success: true,
|
|
697
|
-
endpoint: 'item',
|
|
698
|
-
module: 'mini-inventory',
|
|
699
|
-
table: modelInfo.table,
|
|
700
|
-
fields: modelInfo.fields,
|
|
701
|
-
querySources: modelInfo.querySources,
|
|
702
|
-
actions: actions,
|
|
703
|
-
databaseType: 'mysql',
|
|
704
|
-
generated: '2026-04-25T07:54:01.306Z',
|
|
705
|
-
timestamp: new Date().toISOString()
|
|
706
|
-
});
|
|
707
|
-
} catch (error) {
|
|
708
|
-
console.error('MySQL info error:', error);
|
|
709
|
-
res.status(500).json({
|
|
710
|
-
success: false,
|
|
711
|
-
error: 'Info Error',
|
|
712
|
-
message: 'An error occurred while fetching endpoint info',
|
|
713
|
-
timestamp: new Date().toISOString()
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
// MySQL health check
|
|
718
|
-
router.get('/health', async (req, res) => {
|
|
719
|
-
try {
|
|
720
|
-
const connectionInfo = await itemModel.getConnectionInfo();
|
|
721
|
-
|
|
722
|
-
res.json({
|
|
723
|
-
status: connectionInfo ? 'healthy' : 'unknown',
|
|
724
|
-
endpoint: 'item',
|
|
725
|
-
database: 'mysql',
|
|
726
|
-
connection: connectionInfo ? 'active' : 'unknown',
|
|
727
|
-
timestamp: new Date().toISOString()
|
|
728
|
-
});
|
|
729
|
-
} catch (error) {
|
|
730
|
-
res.status(503).json({
|
|
731
|
-
status: 'unhealthy',
|
|
732
|
-
endpoint: 'item',
|
|
733
|
-
database: 'mysql',
|
|
734
|
-
error: error.message,
|
|
735
|
-
timestamp: new Date().toISOString()
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
module.exports = router;
|