@restforgejs/platform 4.2.8 → 4.3.2
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 +1 -1
- 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 +3 -2
- package/generators/cli/schema/describe.js +3 -2
- package/generators/cli/schema/diff.js +3 -2
- package/generators/cli/schema/introspect.js +3 -2
- package/generators/cli/schema/list.js +3 -2
- package/generators/cli/schema/migrate.js +3 -2
- package/generators/lib/migration/audit-table-runner.js +213 -215
- package/generators/lib/payload/payload-runner.js +1 -1
- 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/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
|
@@ -1,437 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Authoritative source for dashboard-catalog content.
|
|
3
|
-
* Used by:
|
|
4
|
-
* - cli/dashboard-catalog.js (CLI introspection command)
|
|
5
|
-
* - (future) MCP server tool 'codegen_get_dashboard_catalog'
|
|
6
|
-
*
|
|
7
|
-
* SINGLE SOURCE OF TRUTH: Modify only this file when adding/changing
|
|
8
|
-
* dashboard payload schema, widget spec, param spec, scalar collapse rules,
|
|
9
|
-
* naming/URL/file/placeholder conventions. Keep in sync with:
|
|
10
|
-
* - feat-dashboard.md spec
|
|
11
|
-
* - dashboard-validator.js implementation
|
|
12
|
-
*
|
|
13
|
-
* Reference document (human-readable): feat-dashboard.md
|
|
14
|
-
* Public documentation URL: https://restforge.dev/docs/server/query-data/dashboard
|
|
15
|
-
*
|
|
16
|
-
* @module lib/templates/dashboard-catalog
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// SHARED CONSTANTS (single source — referenced multiple places below)
|
|
21
|
-
// ============================================================================
|
|
22
|
-
|
|
23
|
-
const FORBIDDEN_FRONTEND_FIELDS = ['widgetType', 'layout', 'title', 'subtitle', 'color'];
|
|
24
|
-
const ALLOWED_PARAM_TYPES = ['string', 'number', 'boolean', 'date'];
|
|
25
|
-
|
|
26
|
-
const FRONTEND_CONCERN_REASONS = {
|
|
27
|
-
widgetType: 'Visual variant (donut, bar, pie, area) is a frontend rendering concern (separation of concerns).',
|
|
28
|
-
layout: 'Layout is a frontend rendering concern.',
|
|
29
|
-
title: 'UI label is a frontend rendering concern.',
|
|
30
|
-
subtitle: 'UI label is a frontend rendering concern.',
|
|
31
|
-
color: 'Visual color is a frontend rendering concern.'
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// PAYLOAD SHAPE
|
|
36
|
-
// ============================================================================
|
|
37
|
-
|
|
38
|
-
const PAYLOAD_SHAPE = {
|
|
39
|
-
discriminator: {
|
|
40
|
-
field: 'widgets',
|
|
41
|
-
presentMeans: 'dashboard payload',
|
|
42
|
-
absentMeans: 'Not a dashboard payload (likely CRUD with tableName, or invalid)',
|
|
43
|
-
conflictsWith: 'tableName',
|
|
44
|
-
conflictRationale: "A payload with both 'widgets' and 'tableName' is rejected by DashboardValidator. Pick one shape."
|
|
45
|
-
},
|
|
46
|
-
topLevelAllowed: [
|
|
47
|
-
{
|
|
48
|
-
name: 'widgets',
|
|
49
|
-
type: 'array',
|
|
50
|
-
required: true,
|
|
51
|
-
minItems: 1,
|
|
52
|
-
description: 'List of widget definitions. Order is informational only (response keys are by widget id, not array index).'
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
name: 'params',
|
|
56
|
-
type: 'object',
|
|
57
|
-
required: false,
|
|
58
|
-
description: 'Parameter contract for the dashboard. Each key is a param name; values describe type/required/default. Placeholders inside widget SQL must reference declared param names.'
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: 'cache',
|
|
62
|
-
type: 'object',
|
|
63
|
-
required: false,
|
|
64
|
-
description: "Optional cache configuration. See cacheSpec for details."
|
|
65
|
-
}
|
|
66
|
-
],
|
|
67
|
-
topLevelForbidden: [
|
|
68
|
-
{
|
|
69
|
-
name: 'tableName',
|
|
70
|
-
category: 'shape-conflict',
|
|
71
|
-
reason: "Reserved for CRUD payloads. A dashboard payload must declare 'widgets' instead."
|
|
72
|
-
},
|
|
73
|
-
...FORBIDDEN_FRONTEND_FIELDS.map(name => ({
|
|
74
|
-
name,
|
|
75
|
-
category: 'frontend-concern',
|
|
76
|
-
reason: FRONTEND_CONCERN_REASONS[name]
|
|
77
|
-
}))
|
|
78
|
-
]
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// ============================================================================
|
|
82
|
-
// WIDGET SPEC
|
|
83
|
-
// ============================================================================
|
|
84
|
-
|
|
85
|
-
const WIDGET_SPEC = {
|
|
86
|
-
requiredFields: [
|
|
87
|
-
{
|
|
88
|
-
name: 'id',
|
|
89
|
-
type: 'string',
|
|
90
|
-
constraint: 'non-empty, unique across widgets in the same payload',
|
|
91
|
-
description: 'Widget identifier; used as the response key in the dashboard envelope.'
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
exclusiveQueryFields: {
|
|
95
|
-
rule: "A widget MUST declare exactly one of: 'query' OR 'queries'. Both or neither is rejected.",
|
|
96
|
-
options: [
|
|
97
|
-
{
|
|
98
|
-
name: 'query',
|
|
99
|
-
type: 'string',
|
|
100
|
-
format: 'file:relative/path/to/query.sql',
|
|
101
|
-
description: 'Single SQL query for the widget.',
|
|
102
|
-
responseShape: 'Always { items: [...] } regardless of SQL result shape.'
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: 'queries',
|
|
106
|
-
type: 'object',
|
|
107
|
-
format: 'key→file:relative/path/to/query.sql',
|
|
108
|
-
minKeys: 1,
|
|
109
|
-
description: 'Multi-SQL widget. Each key becomes a key in the response object.',
|
|
110
|
-
responseShape: 'Per-key based on scalarCollapseRules below.'
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
},
|
|
114
|
-
forbiddenFields: FORBIDDEN_FRONTEND_FIELDS
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
// ============================================================================
|
|
118
|
-
// PARAM SPEC
|
|
119
|
-
// ============================================================================
|
|
120
|
-
|
|
121
|
-
const PARAM_SPEC = {
|
|
122
|
-
container: "top-level 'params' object",
|
|
123
|
-
keyConvention: 'Param name must match the placeholder regex `[a-zA-Z_][a-zA-Z0-9_]*` (alphanumeric + underscore, must start with letter or underscore).',
|
|
124
|
-
perEntryFields: [
|
|
125
|
-
{
|
|
126
|
-
name: 'type',
|
|
127
|
-
required: true,
|
|
128
|
-
allowedValues: ALLOWED_PARAM_TYPES,
|
|
129
|
-
description: 'Param data type. Validates request body and shapes runtime parameter binding.'
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
name: 'required',
|
|
133
|
-
required: false,
|
|
134
|
-
type: 'boolean',
|
|
135
|
-
default: false,
|
|
136
|
-
description: 'When true, the request body MUST include this param (otherwise 400).'
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: 'default',
|
|
140
|
-
required: false,
|
|
141
|
-
type: "any (must be compatible with declared 'type')",
|
|
142
|
-
description: "Default value applied when the request omits this param. Validator does NOT strictly type-check default; runtime is responsible for compatibility."
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// ============================================================================
|
|
148
|
-
// SCALAR COLLAPSE RULES
|
|
149
|
-
// ============================================================================
|
|
150
|
-
|
|
151
|
-
const SCALAR_COLLAPSE_RULES = [
|
|
152
|
-
{
|
|
153
|
-
appliesTo: 'widget.query (singular)',
|
|
154
|
-
rule: 'Always wrap as { items: [...] } regardless of SQL result shape.',
|
|
155
|
-
exampleSqlShape: 'any (1 row × 1 col, N rows × M cols, etc.)',
|
|
156
|
-
exampleResponse: '"shopping_categories": { "items": [{ "name": "Lands" }, { "name": "Houses" }] }'
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
appliesTo: 'widget.queries.<key> with SQL returning 1 row × 1 column',
|
|
160
|
-
rule: 'Collapse to scalar primitive (the value of the single column).',
|
|
161
|
-
exampleSqlShape: "1 row × 1 col, output column 'value'",
|
|
162
|
-
exampleResponse: '"value": "69700"'
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
appliesTo: 'widget.queries.<key> with SQL returning 1 row × multiple columns',
|
|
166
|
-
rule: 'Collapse to object whose keys are SQL column names (lowercased).',
|
|
167
|
-
exampleSqlShape: "1 row × 2 cols, output columns 'direction', 'pct'",
|
|
168
|
-
exampleResponse: '"trend": { "direction": "up", "pct": "2.2" }'
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
appliesTo: 'widget.queries.<key> with SQL returning N rows',
|
|
172
|
-
rule: 'Return as array of objects (no collapse).',
|
|
173
|
-
exampleSqlShape: 'N rows × M cols',
|
|
174
|
-
exampleResponse: '"items": [{ "label": "Shoes", "value": "7660" }, ...]'
|
|
175
|
-
}
|
|
176
|
-
];
|
|
177
|
-
|
|
178
|
-
// ============================================================================
|
|
179
|
-
// COMMON WIDGET PATTERNS
|
|
180
|
-
// ============================================================================
|
|
181
|
-
|
|
182
|
-
const COMMON_WIDGET_PATTERNS = [
|
|
183
|
-
{
|
|
184
|
-
id: 'metric_donut_breakdown',
|
|
185
|
-
name: 'Metric + Donut Breakdown',
|
|
186
|
-
useCase: "Headline metric with trend chip and breakdown across categories. Suitable for widgets like 'Expected Earnings' that show total value, percentage change, and per-category contribution.",
|
|
187
|
-
payloadShape: {
|
|
188
|
-
id: '<widget_id>',
|
|
189
|
-
queries: {
|
|
190
|
-
value: 'file:query/<path>/value.sql',
|
|
191
|
-
trend: 'file:query/<path>/trend.sql',
|
|
192
|
-
items: 'file:query/<path>/breakdown.sql'
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
sqlShapesPerKey: [
|
|
196
|
-
{
|
|
197
|
-
key: 'value',
|
|
198
|
-
shape: '1 row × 1 column',
|
|
199
|
-
outputColumns: ['value'],
|
|
200
|
-
collapseRule: 'scalar primitive'
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
key: 'trend',
|
|
204
|
-
shape: '1 row × 2 columns',
|
|
205
|
-
outputColumns: ['direction', 'pct'],
|
|
206
|
-
collapseRule: 'object'
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
key: 'items',
|
|
210
|
-
shape: 'N rows × 2 columns',
|
|
211
|
-
outputColumns: ['label', 'value'],
|
|
212
|
-
collapseRule: 'array of objects'
|
|
213
|
-
}
|
|
214
|
-
],
|
|
215
|
-
responseShape: {
|
|
216
|
-
value: '"69700"',
|
|
217
|
-
trend: '{ "direction": "up", "pct": "2.2" }',
|
|
218
|
-
items: '[{ "label": "Shoes", "value": "7660" }, { "label": "Gaming", "value": "2820" }, { "label": "Others", "value": "45257" }]'
|
|
219
|
-
},
|
|
220
|
-
referenceWidgetId: 'expected_earnings',
|
|
221
|
-
socNotes: "Frontend determines donut/pie variant, color per category, and label order. If per-category percentage is needed for the donut arc, frontend computes it from items[i].value / sum(items[*].value). No need to send 'pct' from backend unless the figure is a stable business calculation independent of visual rendering."
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
id: 'metric_sparkline',
|
|
225
|
-
name: 'Metric + Sparkline',
|
|
226
|
-
useCase: "Headline metric with trend chip and sparkline mini-chart for short windows (7 days, 12 months, etc.). Suitable for widgets like 'Average Daily Sales'.",
|
|
227
|
-
payloadShape: {
|
|
228
|
-
id: '<widget_id>',
|
|
229
|
-
queries: {
|
|
230
|
-
value: 'file:query/<path>/value.sql',
|
|
231
|
-
trend: 'file:query/<path>/trend.sql',
|
|
232
|
-
points: 'file:query/<path>/points.sql'
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
sqlShapesPerKey: [
|
|
236
|
-
{
|
|
237
|
-
key: 'value',
|
|
238
|
-
shape: '1 row × 1 column',
|
|
239
|
-
outputColumns: ['value'],
|
|
240
|
-
collapseRule: 'scalar primitive'
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
key: 'trend',
|
|
244
|
-
shape: '1 row × 2 columns',
|
|
245
|
-
outputColumns: ['direction', 'pct'],
|
|
246
|
-
collapseRule: 'object'
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
key: 'points',
|
|
250
|
-
shape: 'N rows × 2 columns',
|
|
251
|
-
outputColumns: ['period', 'value'],
|
|
252
|
-
collapseRule: 'array of objects'
|
|
253
|
-
}
|
|
254
|
-
],
|
|
255
|
-
responseShape: {
|
|
256
|
-
value: '"2420"',
|
|
257
|
-
trend: '{ "direction": "up", "pct": "2.6" }',
|
|
258
|
-
points: '[{ "period": "2026-04-24", "value": "1850" }, ... ]'
|
|
259
|
-
},
|
|
260
|
-
referenceWidgetId: 'avg_daily_sales',
|
|
261
|
-
socNotes: "Sparkline libraries (ApexCharts, Chartist, etc.) typically need a plain number array. Frontend maps points.map(p => p.value). The 'period' field stays for tooltip and gap-resilience against missing days. Use generate_series in SQL to ensure consistent row count even for days with no transactions."
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
id: 'metric_progress_to_goal',
|
|
265
|
-
name: 'Metric + Progress to Goal',
|
|
266
|
-
useCase: "Headline metric with trend chip and progress bar against a period target. Suitable for widgets like 'Orders This Month'.",
|
|
267
|
-
payloadShape: {
|
|
268
|
-
id: '<widget_id>',
|
|
269
|
-
queries: {
|
|
270
|
-
value: 'file:query/<path>/current.sql',
|
|
271
|
-
trend: 'file:query/<path>/trend.sql',
|
|
272
|
-
target: 'file:query/<path>/target.sql'
|
|
273
|
-
}
|
|
274
|
-
},
|
|
275
|
-
sqlShapesPerKey: [
|
|
276
|
-
{
|
|
277
|
-
key: 'value',
|
|
278
|
-
shape: '1 row × 1 column',
|
|
279
|
-
outputColumns: ['value (or current)'],
|
|
280
|
-
collapseRule: 'scalar primitive'
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
key: 'trend',
|
|
284
|
-
shape: '1 row × 2 columns',
|
|
285
|
-
outputColumns: ['direction', 'pct'],
|
|
286
|
-
collapseRule: 'object'
|
|
287
|
-
},
|
|
288
|
-
{
|
|
289
|
-
key: 'target',
|
|
290
|
-
shape: '1 row × 1 column',
|
|
291
|
-
outputColumns: ['target'],
|
|
292
|
-
collapseRule: 'scalar primitive'
|
|
293
|
-
}
|
|
294
|
-
],
|
|
295
|
-
responseShape: {
|
|
296
|
-
value: '"1836"',
|
|
297
|
-
trend: '{ "direction": "down", "pct": "2.2" }',
|
|
298
|
-
target: '"2884"'
|
|
299
|
-
},
|
|
300
|
-
referenceWidgetId: 'orders_this_month',
|
|
301
|
-
socNotes: "Frontend computes to_goal = target - value and pct = round(value / target * 100) for the progress bar. Visual width is presentational and must NOT live in the backend payload. If progress involves complex business rules (e.g. exclude weekends, prorated workdays), use a single multi-column query so 'pct' is a stable business fact rather than visual width."
|
|
302
|
-
}
|
|
303
|
-
];
|
|
304
|
-
|
|
305
|
-
// ============================================================================
|
|
306
|
-
// NAMING CONVENTION
|
|
307
|
-
// ============================================================================
|
|
308
|
-
|
|
309
|
-
const NAMING_CONVENTION = {
|
|
310
|
-
dashboardName: {
|
|
311
|
-
constraint: "MUST start with 'dash-' prefix",
|
|
312
|
-
minLength: 6,
|
|
313
|
-
maxLength: 50,
|
|
314
|
-
regex: '^dash-[a-zA-Z0-9_-]+$',
|
|
315
|
-
examples: ['dash-sales', 'dash-inbound', 'dash-author-stats'],
|
|
316
|
-
rationale: 'The prefix becomes part of the URL segment. The reserved scheme keeps dashboard endpoints visually distinct from CRUD endpoints in the URL space and allows future routing differentiation.'
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
// ============================================================================
|
|
321
|
-
// URL PATTERN
|
|
322
|
-
// ============================================================================
|
|
323
|
-
|
|
324
|
-
const URL_PATTERN = {
|
|
325
|
-
method: 'POST',
|
|
326
|
-
path: '/api/{project}/{name}/dashboard',
|
|
327
|
-
exampleFull: 'POST /api/mini-inventory/dash-inbound/dashboard',
|
|
328
|
-
requestBodyShape: {
|
|
329
|
-
params: 'object — values for declared params (validated against params contract; missing required → 400, type mismatch → 400)',
|
|
330
|
-
widgets: 'array<string>, optional — subset of widget IDs to execute. Omit to execute all declared widgets.'
|
|
331
|
-
},
|
|
332
|
-
responseShape: {
|
|
333
|
-
envelope: '{ success: boolean, data: { <widgetId>: <perWidgetResponse>, ... } }',
|
|
334
|
-
perWidgetResponse: "Determined by scalarCollapseRules. Failed widgets produce { error: '...' } block with top-level success still true (one widget failure does NOT fail the dashboard)."
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
// ============================================================================
|
|
339
|
-
// FILE REFERENCE CONVENTION
|
|
340
|
-
// ============================================================================
|
|
341
|
-
|
|
342
|
-
const FILE_REFERENCE_CONVENTION = {
|
|
343
|
-
format: 'file:relative/path/to/query.sql',
|
|
344
|
-
pathRelativeTo: 'payload JSON file location',
|
|
345
|
-
fileExtensionPolicy: 'free; .sql recommended for editor highlight',
|
|
346
|
-
resolvedAt: 'generation time (NOT runtime)',
|
|
347
|
-
embedStrategy: 'SQL file content is embedded as JavaScript template literal inside the generated module file. Runtime performs zero disk I/O per request — all SQL is in memory after module load.',
|
|
348
|
-
implication: "Updating an SQL file requires regenerating the dashboard module ('codegen_create_dashboard') for changes to take effect."
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
// ============================================================================
|
|
352
|
-
// PLACEHOLDER CONVENTION
|
|
353
|
-
// ============================================================================
|
|
354
|
-
|
|
355
|
-
const PLACEHOLDER_CONVENTION = {
|
|
356
|
-
format: ':paramName',
|
|
357
|
-
regex: '(?<!:):([a-zA-Z_][a-zA-Z0-9_]*)',
|
|
358
|
-
regexNotes: "Negative lookbehind prevents matching '::' (Postgres cast syntax) as a placeholder.",
|
|
359
|
-
scanScope: "All widget SQL — both 'query' (singular) and every 'queries.<key>'.",
|
|
360
|
-
constraint: 'Every placeholder used in SQL MUST be declared in \'params\'. Validator throws Error with message format: "Widget \'<id>\' query \'<label>\' uses undeclared placeholder \':<token>\' (declare in \'params\')".',
|
|
361
|
-
exampleSql: 'SELECT * FROM stock_inbound WHERE EXTRACT(YEAR FROM inbound_date) = :year',
|
|
362
|
-
exampleParamDeclaration: '{ "params": { "year": { "type": "number", "required": true } } }'
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// ============================================================================
|
|
366
|
-
// CACHE SPEC
|
|
367
|
-
// ============================================================================
|
|
368
|
-
|
|
369
|
-
const CACHE_SPEC = {
|
|
370
|
-
container: "top-level 'cache' object",
|
|
371
|
-
optional: true,
|
|
372
|
-
rationale: "Dashboard endpoint may opt-in to Redis-based cache. Pattern follows processor cache (see feat-cache.md). Cache scope is the full response envelope; one cache entry per (params + widgets[] subset) combination.",
|
|
373
|
-
fields: [
|
|
374
|
-
{
|
|
375
|
-
name: 'enabled',
|
|
376
|
-
type: 'boolean',
|
|
377
|
-
required: true,
|
|
378
|
-
description: 'Toggle cache feature for this dashboard.'
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
name: 'ttl',
|
|
382
|
-
type: 'number',
|
|
383
|
-
required: false,
|
|
384
|
-
constraint: '>= 0 (seconds)',
|
|
385
|
-
default: 'inherits CACHE_TTL env',
|
|
386
|
-
description: 'Time-to-live in seconds. 0 effectively disables cache for this entry.'
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
name: 'invalidates',
|
|
390
|
-
type: 'array<string>',
|
|
391
|
-
required: false,
|
|
392
|
-
default: '[]',
|
|
393
|
-
description: 'List of CRUD table names that, when written, will trigger invalidation of this dashboard cache.'
|
|
394
|
-
}
|
|
395
|
-
],
|
|
396
|
-
validation: {
|
|
397
|
-
sqlCrossReference: 'When cache.enabled === true and invalidates is non-empty: validator extracts table candidates from widget SQL (regex FROM/JOIN), cross-references with metadata/{project}.json (endpoints[*].tableName where type === "module"), and asserts equality of expected vs declared sets. Mismatches are reported per category (missing, extra, unmatched).',
|
|
398
|
-
errorOn: [
|
|
399
|
-
'Table appears in SQL AND in metadata project, but missing from invalidates (cache stale risk)',
|
|
400
|
-
'Table declared in invalidates, but not detected in any widget SQL (typo or dead entry)'
|
|
401
|
-
],
|
|
402
|
-
warningOn: [
|
|
403
|
-
'Table detected in SQL, but not registered as CRUD endpoint in metadata project (likely a view, CTE alias, or cross-project table — cascade will not fire)'
|
|
404
|
-
]
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
// ============================================================================
|
|
409
|
-
// FINAL CATALOG
|
|
410
|
-
// ============================================================================
|
|
411
|
-
|
|
412
|
-
const DOCUMENTATION_URL = 'https://restforge.dev/docs/server/query-data/dashboard';
|
|
413
|
-
|
|
414
|
-
const DASHBOARD_CATALOG = {
|
|
415
|
-
schemaVersion: '1.0',
|
|
416
|
-
source: 'dashboard-catalog',
|
|
417
|
-
summary: {
|
|
418
|
-
totalAllowedTopLevelFields: PAYLOAD_SHAPE.topLevelAllowed.length,
|
|
419
|
-
totalForbiddenFrontendFields: FORBIDDEN_FRONTEND_FIELDS.length,
|
|
420
|
-
totalParamTypes: ALLOWED_PARAM_TYPES.length,
|
|
421
|
-
totalScalarCollapseRules: SCALAR_COLLAPSE_RULES.length,
|
|
422
|
-
totalCommonWidgetPatterns: COMMON_WIDGET_PATTERNS.length
|
|
423
|
-
},
|
|
424
|
-
payloadShape: PAYLOAD_SHAPE,
|
|
425
|
-
widgetSpec: WIDGET_SPEC,
|
|
426
|
-
paramSpec: PARAM_SPEC,
|
|
427
|
-
scalarCollapseRules: SCALAR_COLLAPSE_RULES,
|
|
428
|
-
commonWidgetPatterns: COMMON_WIDGET_PATTERNS,
|
|
429
|
-
namingConvention: NAMING_CONVENTION,
|
|
430
|
-
urlPattern: URL_PATTERN,
|
|
431
|
-
fileReferenceConvention: FILE_REFERENCE_CONVENTION,
|
|
432
|
-
placeholderConvention: PLACEHOLDER_CONVENTION,
|
|
433
|
-
cacheSpec: CACHE_SPEC,
|
|
434
|
-
documentationUrl: DOCUMENTATION_URL
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
module.exports = { DASHBOARD_CATALOG };
|
|
1
|
+
function a0_0x163f(_0x2fff76,_0x3dad32){_0x2fff76=_0x2fff76-0x160;const _0x38bfad=a0_0x38bf();let _0x163fb2=_0x38bfad[_0x2fff76];if(a0_0x163f['SAJaCv']===undefined){var _0xe116b1=function(_0x1825a5){const _0x2aec6a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2b8fe5='',_0x2d0f21='';for(let _0x53cfad=0x0,_0x13283a,_0xeaa967,_0x5b14df=0x0;_0xeaa967=_0x1825a5['charAt'](_0x5b14df++);~_0xeaa967&&(_0x13283a=_0x53cfad%0x4?_0x13283a*0x40+_0xeaa967:_0xeaa967,_0x53cfad++%0x4)?_0x2b8fe5+=String['fromCharCode'](0xff&_0x13283a>>(-0x2*_0x53cfad&0x6)):0x0){_0xeaa967=_0x2aec6a['indexOf'](_0xeaa967);}for(let _0x571693=0x0,_0x279c6a=_0x2b8fe5['length'];_0x571693<_0x279c6a;_0x571693++){_0x2d0f21+='%'+('00'+_0x2b8fe5['charCodeAt'](_0x571693)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2d0f21);};a0_0x163f['pKrfaV']=_0xe116b1,a0_0x163f['kVtkIC']={},a0_0x163f['SAJaCv']=!![];}const _0x2e82a7=_0x38bfad[0x0],_0x3ae501=_0x2fff76+_0x2e82a7,_0x217380=a0_0x163f['kVtkIC'][_0x3ae501];return!_0x217380?(_0x163fb2=a0_0x163f['pKrfaV'](_0x163fb2),a0_0x163f['kVtkIC'][_0x3ae501]=_0x163fb2):_0x163fb2=_0x217380,_0x163fb2;}function a0_0x38bf(){const _0x444f17=['Cgf5Bg9Hzcbku09oigzPBguGBg9JyxrPB24','rgfZAgjVyxjKigvUzhbVAw50ig1HEsbVChqTAw4GDg8GuMvKAxmTyMfZzwqGy2fJAguUifbHDhrLCM4GzM9SBg93CYbWCM9JzxnZB3iGy2fJAguGkhnLzsbMzwf0lwnHy2HLlM1Kks4Gq2fJAguGC2nVCguGAxmGDgHLigz1BgWGCMvZCg9UC2uGzw52zwXVCgu7ig9UzsbJywnOzsbLBNrYEsbWzxiGkhbHCMfTCYaRihDPzgDLDhnBxsbZDwjZzxqPignVBwjPBMf0Aw9UlG','w3SGiNbLCMLVzci6iciYmdi2lta0lti0iIWGiNzHBhvLiJOGiJe4ntaIih0Sic4UlIbD','mti1nZa5mMvUvxLRDa','twv0CMLJicSGuhjVz3jLC3mGDg8Gr29HBa','yxjYyxKGB2yGB2jQzwn0CW','msbYB3CGW5CGmIbJB2X1Bw5Z','A2v54OAszMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','l2fWAs97ChjVAMvJDh0VE25HBwv9l2rHC2HIB2fYza','DgfYz2v0','yxjYyxK8C3rYAw5NpIWGB3b0Aw9UywWG4Ocuihn1yNnLDcbVzIb3AwrNzxqGsurZihrVigv4zwn1DguUie9TAxqGDg8GzxHLy3v0zsbHBgWGzgvJBgfYzwqGD2LKz2v0CY4','zgvMyxvSDa','pJ0GmcaOC2vJB25KCYK','yM9VBgvHBG','mti0ntyYowPwwvnMEa','zw5HyMXLza','zMLSztPXDwvYEs88Cgf0Ad4VDhjLBMqUC3fS','v2LKz2v0igLKzw50AwzPzxi7ihvZzwqGyxmGDgHLihjLC3bVBNnLigTLEsbPBIb0AguGzgfZAgjVyxjKigvUDMvSB3bLlG','yxzNx2rHAwX5x3nHBgvZ','zMLSztPXDwvYEs88Cgf0Ad4VCg9PBNrZlNnXBa','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGChjVz3jLC3mGyMfYigfNywLUC3qGysbWzxjPB2qGDgfYz2v0lIbtDwL0ywjSzsbMB3iGD2LKz2v0CYbSAwTLicDpCMrLCNmGvgHPCYbnB250AcCU','ugfYyw0Gzgf0ysb0ExbLlIbwywXPzgf0zxmGCMvXDwvZDcbIB2r5igfUzcbZAgfWzxmGCNvUDgLTzsbWyxjHBwv0zxiGyMLUzgLUzY4','mJa3u0HlyxPI','Bgf5B3v0','EYaIzgLYzwn0Aw9UiJOGiMrVD24IlcaICgn0iJOGiJiUmIiGFq','Cg9PBNrZ','C2nHBgfYihbYAw1PDgL2zq','uMvZzxj2zwqGzM9YiensvuqGCgf5Bg9HzhmUieeGzgfZAgjVyxjKihbHEwXVywqGBxvZDcbKzwnSyxjLicD3AwrNzxrZjYbPBNn0zwfKlG','rNjVBNrLBMqGy29TChv0zxmGDg9Fz29HBca9ihrHCMDLDcaTihzHBhvLigfUzcbWy3qGpsbYB3vUzcH2ywX1zsaVihrHCMDLDcaQideWmcKGzM9YihrOzsbWCM9NCMvZCYbIyxiUifzPC3vHBcb3Awr0AcbPCYbWCMvZzw50yxrPB25HBcbHBMqGBxvZDcbot1qGBgL2zsbPBIb0AguGyMfJA2vUzcbWyxLSB2fKlIbjzIbWCM9NCMvZCYbPBNzVBhzLCYbJB21WBgv4igj1C2LUzxnZihj1BgvZicHLlMCUigv4y2X1zguGD2vLA2vUzhmSihbYB3jHDgvKihDVCMTKyxLZksWGDxnLigeGC2LUz2XLig11BhrPlwnVBhvTBIbXDwvYEsbZBYaNCgn0jYbPCYbHihn0ywjSzsbIDxnPBMvZCYbMywn0ihjHDgHLCIb0AgfUihzPC3vHBcb3Awr0Ac4','ue9tvcaVyxbPl21PBMKTAw52zw50B3j5l2rHC2GTAw5IB3vUzc9KyxnOyM9HCMq','q29SBgfWC2uGDg8GC2nHBgfYihbYAw1PDgL2zsaODgHLihzHBhvLig9MihrOzsbZAw5NBguGy29SDw1Uks4','zNjLztSGlNnXBcbYzwnVBw1LBMrLzcbMB3iGzwrPDg9YigHPz2HSAwDODa','C2HHCguTy29UzMXPy3q','C3rYAw5N','BgvUz3rO','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','CxvLCMLLCW','vuKGBgfIzwWGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBI4','tIbYB3DZimoxidiGy29SDw1UCW','ugfYyw1LDgvYignVBNrYywn0igzVCIb0AguGzgfZAgjVyxjKlIbfywnOigTLEsbPCYbHihbHCMfTig5HBwu7ihzHBhvLCYbKzxnJCMLIzsb0ExbLl3jLCxvPCMvKl2rLzMf1BhqUifbSywnLAg9SzgvYCYbPBNnPzguGD2LKz2v0ifnrtcbTDxn0ihjLzMvYzw5JzsbKzwnSyxjLzcbWyxjHBsbUyw1LCY4','u1fmigzPBguGy29UDgvUDcbPCYbLBwjLzgrLzcbHCYbkyxzHu2nYAxb0ihrLBxbSyxrLigXPDgvYywWGAw5ZAwrLihrOzsbNzw5LCMf0zwqGBw9KDwXLigzPBguUifj1BNrPBwuGCgvYzM9YBxmGEMvYBYbKAxnRieKVtYbWzxiGCMvXDwvZDcdIGjqGywXSifnrtcbPCYbPBIbTzw1VCNKGywz0zxiGBw9KDwXLigXVywqU','u3bHCMTSAw5LigXPyNjHCMLLCYaOqxbLEenOyxj0CYWGq2HHCNrPC3qSigv0yY4Pihr5CgLJywXSEsbUzwvKigeGCgXHAw4GBNvTyMvYigfYCMf5lIbgCM9UDgvUzcbTyxbZihbVAw50CY5TyxaOCca9pIbWlNzHBhvLks4GvgHLicDWzxjPB2qNigzPzwXKihn0yxLZigzVCIb0B29SDgLWigfUzcbNyxaTCMvZAwXPzw5JzsbHz2fPBNn0ig1PC3nPBMCGzgf5CY4GvxnLigDLBMvYyxrLx3nLCMLLCYbPBIbtuuWGDg8Gzw5ZDxjLignVBNnPC3rLBNqGCM93ignVDw50igv2zw4GzM9YigrHExmGD2L0AcbUBYb0CMfUC2fJDgLVBNmU','Dg9WlwXLDMvSicDWyxjHBxmNig9IAMvJDa','DhjLBMq','zgLYzwn0Aw9U','iNzHBhvLiJOGiJy5nZaWiG','mJKWotKXmMrqEu1UBa','CgvYAw9K','zgfZAgjVyxjKihbHEwXVywq','ndC3otC1mgr6DfnRsG','vMLZDwfSignVBg9YigLZigeGzNjVBNrLBMqGCMvUzgvYAw5NignVBMnLCM4U','D2LKz2v0CW','Cgn0','C3vIDgL0Bgu','B2jQzwn0','yxjYyxK8C3rYAw5NpG','B3jKzxjZx3rOAxnFBw9UDgG','zgf0zq','v2HLBIb0CNvLlcb0AguGCMvXDwvZDcbIB2r5ie1vu1qGAw5JBhvKzsb0AgLZihbHCMfTicHVDgHLCNDPC2uGndaWks4','ntiWnZG1nLLfy2P5rW','CxvLCNK','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJyIih0','u0vmrunuicOGrLjptsbZDg9JA19PBMjVDw5KifDirvjfievyvfjbq1qOwuvbuIbguK9nigLUyM91BMrFzgf0zsKGpsa6EwvHCG','iJi0mJaI','DMfSDwu','zgfZAc1HDxrOB3iTC3rHDhm','AxrLBxm','Ahr0Chm6lY9Yzxn0zM9Yz2uUzgv2l2rVy3mVC2vYDMvYl3f1zxj5lwrHDgeVzgfZAgjVyxjK','zMLSztPXDwvYEs88Cgf0Ad4VDMfSDwuUC3fS','iJe4mZyI','tvvtvcbZDgfYDcb3AxrOicDKyxnOlsCGChjLzML4','nZK1nZG1D0P1yMzT','kd88itOPoIHBys16qs1Ax11Bys16qs1Amc05x10Qkq','msbYB3CGW5CGmsbJB2X1Bw4','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','BgfIzwW','DgL0Bgu','tgLZDcbVzIbduLveihrHyMXLig5HBwvZihrOyxqSihDOzw4GD3jPDhrLBIWGD2LSBcb0CMLNz2vYigLUDMfSAwrHDgLVBIbVzIb0AgLZigrHC2HIB2fYzcbJywnOzs4','EYaICgfYyw1ZiJOGEYaIEwvHCIi6ihSGiNr5CguIoIaIBNvTyMvYiIWGiNjLCxvPCMvKiJOGDhj1zsb9ih0GFq','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJiIih0','Dg9Wtgv2zwXbBgXVD2vK','zxHWB3j0CW','CgfYyw1Z','BNvTyMvY','yxjYyxK','zgfZAc1ZywXLCW','oNbHCMfTtMfTzq','EYbZDwnJzxnZoIbIB29SzwfUlcbKyxrHoIb7idX3AwrNzxrjzd46idXWzxjxAwrNzxrszxnWB25Zzt4Sic4UlIb9ih0','qsb3AwrNzxqGtvvtvcbKzwnSyxjLigv4ywn0BhKGB25Lig9MoIaNCxvLCNKNie9sicDXDwvYAwvZjY4GqM90AcbVCIbUzwL0AgvYigLZihjLAMvJDgvKlG','mtK0otC2ELnvuwvH','u2LUz2XLifnrtcbXDwvYEsbMB3iGDgHLihDPzgDLDc4','m3HmBeXjzq','phDPzgDLDf9Pzd4'];a0_0x38bf=function(){return _0x444f17;};return a0_0x38bf();}const a0_0xaeedec=a0_0x163f;(function(_0x292394,_0x4f6702){const _0x24b504=a0_0x163f,_0x4569f4=_0x292394();while(!![]){try{const _0x599420=parseInt(_0x24b504(0x19c))/0x1+-parseInt(_0x24b504(0x1b5))/0x2+parseInt(_0x24b504(0x1b0))/0x3*(-parseInt(_0x24b504(0x183))/0x4)+parseInt(_0x24b504(0x186))/0x5+parseInt(_0x24b504(0x190))/0x6+-parseInt(_0x24b504(0x163))/0x7+-parseInt(_0x24b504(0x1ae))/0x8*(parseInt(_0x24b504(0x16b))/0x9);if(_0x599420===_0x4f6702)break;else _0x4569f4['push'](_0x4569f4['shift']());}catch(_0x2a3107){_0x4569f4['push'](_0x4569f4['shift']());}}}(a0_0x38bf,0x80380));const FORBIDDEN_FRONTEND_FIELDS=['widgetType',a0_0xaeedec(0x16c),a0_0xaeedec(0x1a1),a0_0xaeedec(0x18a),'color'],ALLOWED_PARAM_TYPES=['string','number','boolean',a0_0xaeedec(0x18e)],FRONTEND_CONCERN_REASONS={'widgetType':'Visual\x20variant\x20(donut,\x20bar,\x20pie,\x20area)\x20is\x20a\x20frontend\x20rendering\x20concern\x20(separation\x20of\x20concerns).','layout':'Layout\x20is\x20a\x20frontend\x20rendering\x20concern.','title':a0_0xaeedec(0x17a),'subtitle':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','color':a0_0xaeedec(0x187)},PAYLOAD_SHAPE={'discriminator':{'field':a0_0xaeedec(0x188),'presentMeans':a0_0xaeedec(0x185),'absentMeans':'Not\x20a\x20dashboard\x20payload\x20(likely\x20CRUD\x20with\x20tableName,\x20or\x20invalid)','conflictsWith':'tableName','conflictRationale':'A\x20payload\x20with\x20both\x20\x27widgets\x27\x20and\x20\x27tableName\x27\x20is\x20rejected\x20by\x20DashboardValidator.\x20Pick\x20one\x20shape.'},'topLevelAllowed':[{'name':'widgets','type':a0_0xaeedec(0x1a9),'required':!![],'minItems':0x1,'description':'List\x20of\x20widget\x20definitions.\x20Order\x20is\x20informational\x20only\x20(response\x20keys\x20are\x20by\x20widget\x20id,\x20not\x20array\x20index).'},{'name':a0_0xaeedec(0x1a7),'type':a0_0xaeedec(0x18b),'required':![],'description':a0_0xaeedec(0x17c)},{'name':'cache','type':'object','required':![],'description':'Optional\x20cache\x20configuration.\x20See\x20cacheSpec\x20for\x20details.'}],'topLevelForbidden':[{'name':'tableName','category':a0_0xaeedec(0x175),'reason':a0_0xaeedec(0x170)},...FORBIDDEN_FRONTEND_FIELDS['map'](_0x2b8fe5=>({'name':_0x2b8fe5,'category':'frontend-concern','reason':FRONTEND_CONCERN_REASONS[_0x2b8fe5]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':a0_0xaeedec(0x176),'constraint':'non-empty,\x20unique\x20across\x20widgets\x20in\x20the\x20same\x20payload','description':a0_0xaeedec(0x166)}],'exclusiveQueryFields':{'rule':a0_0xaeedec(0x1ad),'options':[{'name':a0_0xaeedec(0x191),'type':a0_0xaeedec(0x176),'format':a0_0xaeedec(0x178),'description':a0_0xaeedec(0x1af),'responseShape':'Always\x20{\x20items:\x20[...]\x20}\x20regardless\x20of\x20SQL\x20result\x20shape.'},{'name':a0_0xaeedec(0x179),'type':'object','format':a0_0xaeedec(0x1b9),'minKeys':0x1,'description':'Multi-SQL\x20widget.\x20Each\x20key\x20becomes\x20a\x20key\x20in\x20the\x20response\x20object.','responseShape':'Per-key\x20based\x20on\x20scalarCollapseRules\x20below.'}]},'forbiddenFields':FORBIDDEN_FRONTEND_FIELDS},PARAM_SPEC={'container':a0_0xaeedec(0x17f),'keyConvention':'Param\x20name\x20must\x20match\x20the\x20placeholder\x20regex\x20`[a-zA-Z_][a-zA-Z0-9_]*`\x20(alphanumeric\x20+\x20underscore,\x20must\x20start\x20with\x20letter\x20or\x20underscore).','perEntryFields':[{'name':'type','required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':a0_0xaeedec(0x16a)},{'name':'required','required':![],'type':'boolean','default':![],'description':a0_0xaeedec(0x18f)},{'name':a0_0xaeedec(0x160),'required':![],'type':'any\x20(must\x20be\x20compatible\x20with\x20declared\x20\x27type\x27)','description':'Default\x20value\x20applied\x20when\x20the\x20request\x20omits\x20this\x20param.\x20Validator\x20does\x20NOT\x20strictly\x20type-check\x20default;\x20runtime\x20is\x20responsible\x20for\x20compatibility.'}]},SCALAR_COLLAPSE_RULES=[{'appliesTo':'widget.query\x20(singular)','rule':'Always\x20wrap\x20as\x20{\x20items:\x20[...]\x20}\x20regardless\x20of\x20SQL\x20result\x20shape.','exampleSqlShape':'any\x20(1\x20row\x20×\x201\x20col,\x20N\x20rows\x20×\x20M\x20cols,\x20etc.)','exampleResponse':'\x22shopping_categories\x22:\x20{\x20\x22items\x22:\x20[{\x20\x22name\x22:\x20\x22Lands\x22\x20},\x20{\x20\x22name\x22:\x20\x22Houses\x22\x20}]\x20}'},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x201\x20row\x20×\x201\x20column','rule':a0_0xaeedec(0x173),'exampleSqlShape':'1\x20row\x20×\x201\x20col,\x20output\x20column\x20\x27value\x27','exampleResponse':a0_0xaeedec(0x182)},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x201\x20row\x20×\x20multiple\x20columns','rule':'Collapse\x20to\x20object\x20whose\x20keys\x20are\x20SQL\x20column\x20names\x20(lowercased).','exampleSqlShape':'1\x20row\x20×\x202\x20cols,\x20output\x20columns\x20\x27direction\x27,\x20\x27pct\x27','exampleResponse':'\x22trend\x22:\x20{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}'},{'appliesTo':'widget.queries.<key>\x20with\x20SQL\x20returning\x20N\x20rows','rule':'Return\x20as\x20array\x20of\x20objects\x20(no\x20collapse).','exampleSqlShape':'N\x20rows\x20×\x20M\x20cols','exampleResponse':'\x22items\x22:\x20[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20...]'}],COMMON_WIDGET_PATTERNS=[{'id':'metric_donut_breakdown','name':'Metric\x20+\x20Donut\x20Breakdown','useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20breakdown\x20across\x20categories.\x20Suitable\x20for\x20widgets\x20like\x20\x27Expected\x20Earnings\x27\x20that\x20show\x20total\x20value,\x20percentage\x20change,\x20and\x20per-category\x20contribution.','payloadShape':{'id':a0_0xaeedec(0x1b1),'queries':{'value':'file:query/<path>/value.sql','trend':a0_0xaeedec(0x165),'items':'file:query/<path>/breakdown.sql'}},'sqlShapesPerKey':[{'key':a0_0xaeedec(0x195),'shape':a0_0xaeedec(0x19e),'outputColumns':['value'],'collapseRule':a0_0xaeedec(0x16f)},{'key':'trend','shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction',a0_0xaeedec(0x189)],'collapseRule':'object'},{'key':a0_0xaeedec(0x197),'shape':a0_0xaeedec(0x17b),'outputColumns':[a0_0xaeedec(0x1a0),a0_0xaeedec(0x195)],'collapseRule':'array\x20of\x20objects'}],'responseShape':{'value':'\x2269700\x22','trend':a0_0xaeedec(0x1a4),'items':'[{\x20\x22label\x22:\x20\x22Shoes\x22,\x20\x22value\x22:\x20\x227660\x22\x20},\x20{\x20\x22label\x22:\x20\x22Gaming\x22,\x20\x22value\x22:\x20\x222820\x22\x20},\x20{\x20\x22label\x22:\x20\x22Others\x22,\x20\x22value\x22:\x20\x2245257\x22\x20}]'},'referenceWidgetId':'expected_earnings','socNotes':'Frontend\x20determines\x20donut/pie\x20variant,\x20color\x20per\x20category,\x20and\x20label\x20order.\x20If\x20per-category\x20percentage\x20is\x20needed\x20for\x20the\x20donut\x20arc,\x20frontend\x20computes\x20it\x20from\x20items[i].value\x20/\x20sum(items[*].value).\x20No\x20need\x20to\x20send\x20\x27pct\x27\x20from\x20backend\x20unless\x20the\x20figure\x20is\x20a\x20stable\x20business\x20calculation\x20independent\x20of\x20visual\x20rendering.'},{'id':'metric_sparkline','name':'Metric\x20+\x20Sparkline','useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20sparkline\x20mini-chart\x20for\x20short\x20windows\x20(7\x20days,\x2012\x20months,\x20etc.).\x20Suitable\x20for\x20widgets\x20like\x20\x27Average\x20Daily\x20Sales\x27.','payloadShape':{'id':a0_0xaeedec(0x1b1),'queries':{'value':a0_0xaeedec(0x199),'trend':a0_0xaeedec(0x165),'points':a0_0xaeedec(0x168)}},'sqlShapesPerKey':[{'key':a0_0xaeedec(0x195),'shape':'1\x20row\x20×\x201\x20column','outputColumns':[a0_0xaeedec(0x195)],'collapseRule':a0_0xaeedec(0x16f)},{'key':a0_0xaeedec(0x180),'shape':a0_0xaeedec(0x1b8),'outputColumns':[a0_0xaeedec(0x181),'pct'],'collapseRule':'object'},{'key':a0_0xaeedec(0x16e),'shape':'N\x20rows\x20×\x202\x20columns','outputColumns':[a0_0xaeedec(0x184),a0_0xaeedec(0x195)],'collapseRule':a0_0xaeedec(0x1b7)}],'responseShape':{'value':a0_0xaeedec(0x194),'trend':a0_0xaeedec(0x192),'points':a0_0xaeedec(0x1b4)},'referenceWidgetId':a0_0xaeedec(0x167),'socNotes':a0_0xaeedec(0x17e)},{'id':'metric_progress_to_goal','name':a0_0xaeedec(0x1b6),'useCase':a0_0xaeedec(0x169),'payloadShape':{'id':'<widget_id>','queries':{'value':a0_0xaeedec(0x19f),'trend':a0_0xaeedec(0x165),'target':'file:query/<path>/target.sql'}},'sqlShapesPerKey':[{'key':'value','shape':a0_0xaeedec(0x19e),'outputColumns':['value\x20(or\x20current)'],'collapseRule':a0_0xaeedec(0x16f)},{'key':'trend','shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction','pct'],'collapseRule':'object'},{'key':a0_0xaeedec(0x1bb),'shape':'1\x20row\x20×\x201\x20column','outputColumns':['target'],'collapseRule':a0_0xaeedec(0x16f)}],'responseShape':{'value':a0_0xaeedec(0x19a),'trend':a0_0xaeedec(0x16d),'target':'\x222884\x22'},'referenceWidgetId':a0_0xaeedec(0x18d),'socNotes':a0_0xaeedec(0x171)}],NAMING_CONVENTION={'dashboardName':{'constraint':a0_0xaeedec(0x19b),'minLength':0x6,'maxLength':0x32,'regex':'^dash-[a-zA-Z0-9_-]+$','examples':[a0_0xaeedec(0x1aa),'dash-inbound',a0_0xaeedec(0x196)],'rationale':'The\x20prefix\x20becomes\x20part\x20of\x20the\x20URL\x20segment.\x20The\x20reserved\x20scheme\x20keeps\x20dashboard\x20endpoints\x20visually\x20distinct\x20from\x20CRUD\x20endpoints\x20in\x20the\x20URL\x20space\x20and\x20allows\x20future\x20routing\x20differentiation.'}},URL_PATTERN={'method':'POST','path':a0_0xaeedec(0x1ba),'exampleFull':a0_0xaeedec(0x172),'requestBodyShape':{'params':'object\x20—\x20values\x20for\x20declared\x20params\x20(validated\x20against\x20params\x20contract;\x20missing\x20required\x20→\x20400,\x20type\x20mismatch\x20→\x20400)','widgets':a0_0xaeedec(0x1bc)},'responseShape':{'envelope':a0_0xaeedec(0x1ac),'perWidgetResponse':'Determined\x20by\x20scalarCollapseRules.\x20Failed\x20widgets\x20produce\x20{\x20error:\x20\x27...\x27\x20}\x20block\x20with\x20top-level\x20success\x20still\x20true\x20(one\x20widget\x20failure\x20does\x20NOT\x20fail\x20the\x20dashboard).'}},FILE_REFERENCE_CONVENTION={'format':'file:relative/path/to/query.sql','pathRelativeTo':a0_0xaeedec(0x1b2),'fileExtensionPolicy':a0_0xaeedec(0x174),'resolvedAt':'generation\x20time\x20(NOT\x20runtime)','embedStrategy':a0_0xaeedec(0x17d),'implication':'Updating\x20an\x20SQL\x20file\x20requires\x20regenerating\x20the\x20dashboard\x20module\x20(\x27codegen_create_dashboard\x27)\x20for\x20changes\x20to\x20take\x20effect.'},PLACEHOLDER_CONVENTION={'format':a0_0xaeedec(0x1ab),'regex':a0_0xaeedec(0x19d),'regexNotes':'Negative\x20lookbehind\x20prevents\x20matching\x20\x27::\x27\x20(Postgres\x20cast\x20syntax)\x20as\x20a\x20placeholder.','scanScope':'All\x20widget\x20SQL\x20—\x20both\x20\x27query\x27\x20(singular)\x20and\x20every\x20\x27queries.<key>\x27.','constraint':'Every\x20placeholder\x20used\x20in\x20SQL\x20MUST\x20be\x20declared\x20in\x20\x27params\x27.\x20Validator\x20throws\x20Error\x20with\x20message\x20format:\x20\x22Widget\x20\x27<id>\x27\x20query\x20\x27<label>\x27\x20uses\x20undeclared\x20placeholder\x20\x27:<token>\x27\x20(declare\x20in\x20\x27params\x27)\x22.','exampleSql':a0_0xaeedec(0x193),'exampleParamDeclaration':a0_0xaeedec(0x1a3)},CACHE_SPEC={'container':'top-level\x20\x27cache\x27\x20object','optional':!![],'rationale':a0_0xaeedec(0x1b3),'fields':[{'name':a0_0xaeedec(0x164),'type':a0_0xaeedec(0x162),'required':!![],'description':'Toggle\x20cache\x20feature\x20for\x20this\x20dashboard.'},{'name':'ttl','type':a0_0xaeedec(0x1a8),'required':![],'constraint':a0_0xaeedec(0x161),'default':'inherits\x20CACHE_TTL\x20env','description':'Time-to-live\x20in\x20seconds.\x200\x20effectively\x20disables\x20cache\x20for\x20this\x20entry.'},{'name':'invalidates','type':a0_0xaeedec(0x18c),'required':![],'default':'[]','description':a0_0xaeedec(0x1a2)}],'validation':{'sqlCrossReference':'When\x20cache.enabled\x20===\x20true\x20and\x20invalidates\x20is\x20non-empty:\x20validator\x20extracts\x20table\x20candidates\x20from\x20widget\x20SQL\x20(regex\x20FROM/JOIN),\x20cross-references\x20with\x20metadata/{project}.json\x20(endpoints[*].tableName\x20where\x20type\x20===\x20\x22module\x22),\x20and\x20asserts\x20equality\x20of\x20expected\x20vs\x20declared\x20sets.\x20Mismatches\x20are\x20reported\x20per\x20category\x20(missing,\x20extra,\x20unmatched).','errorOn':['Table\x20appears\x20in\x20SQL\x20AND\x20in\x20metadata\x20project,\x20but\x20missing\x20from\x20invalidates\x20(cache\x20stale\x20risk)','Table\x20declared\x20in\x20invalidates,\x20but\x20not\x20detected\x20in\x20any\x20widget\x20SQL\x20(typo\x20or\x20dead\x20entry)'],'warningOn':['Table\x20detected\x20in\x20SQL,\x20but\x20not\x20registered\x20as\x20CRUD\x20endpoint\x20in\x20metadata\x20project\x20(likely\x20a\x20view,\x20CTE\x20alias,\x20or\x20cross-project\x20table\x20—\x20cascade\x20will\x20not\x20fire)']}},DOCUMENTATION_URL=a0_0xaeedec(0x198),DASHBOARD_CATALOG={'schemaVersion':'1.0','source':'dashboard-catalog','summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE[a0_0xaeedec(0x1a5)]['length'],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS['length'],'totalParamTypes':ALLOWED_PARAM_TYPES[a0_0xaeedec(0x177)],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES['length'],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS['length']},'payloadShape':PAYLOAD_SHAPE,'widgetSpec':WIDGET_SPEC,'paramSpec':PARAM_SPEC,'scalarCollapseRules':SCALAR_COLLAPSE_RULES,'commonWidgetPatterns':COMMON_WIDGET_PATTERNS,'namingConvention':NAMING_CONVENTION,'urlPattern':URL_PATTERN,'fileReferenceConvention':FILE_REFERENCE_CONVENTION,'placeholderConvention':PLACEHOLDER_CONVENTION,'cacheSpec':CACHE_SPEC,'documentationUrl':DOCUMENTATION_URL};module[a0_0xaeedec(0x1a6)]={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};
|