@restforgejs/platform 4.2.8 → 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.
Files changed (324) hide show
  1. package/SECURITY.md +83 -4
  2. package/bin/sdf-tools.exe +0 -0
  3. package/build-info.json +2 -2
  4. package/cli/consumer-deploy.js +1 -1
  5. package/cli/consumer.js +1 -1
  6. package/generators/cli/dashboard/create.js +4 -1
  7. package/generators/cli/endpoint/create.js +1 -1
  8. package/generators/cli/key/generate.js +2 -1
  9. package/generators/cli/key/revoke.js +2 -1
  10. package/generators/cli/payload/diff.js +3 -2
  11. package/generators/cli/payload/generate.js +3 -2
  12. package/generators/cli/payload/sync.js +3 -2
  13. package/generators/cli/payload/validate.js +3 -2
  14. package/generators/cli/processor/create.js +14 -3
  15. package/generators/cli/project/delete.js +2 -1
  16. package/generators/cli/query/validate.js +3 -2
  17. package/generators/cli/schema/apply.js +3 -2
  18. package/generators/cli/schema/describe.js +3 -2
  19. package/generators/cli/schema/diff.js +3 -2
  20. package/generators/cli/schema/introspect.js +3 -2
  21. package/generators/cli/schema/list.js +3 -2
  22. package/generators/cli/schema/migrate.js +3 -2
  23. package/generators/lib/migration/audit-table-runner.js +213 -215
  24. package/generators/lib/templates/dashboard-catalog.js +1 -437
  25. package/generators/lib/templates/db-connection-env.js +1 -212
  26. package/generators/lib/templates/dbschema-catalog.js +1 -489
  27. package/generators/lib/templates/field-validation-catalog.js +1 -531
  28. package/generators/lib/templates/mysql-template.js +1 -3863
  29. package/generators/lib/templates/oracle-template.js +1 -3915
  30. package/generators/lib/templates/postgres-template.js +1 -5838
  31. package/generators/lib/templates/query-declarative-catalog.js +1 -199
  32. package/generators/lib/templates/sqlite-template.js +1 -3440
  33. package/generators/lib/utils/env-manager.js +6 -0
  34. package/generators/lib/utils/path-validator.js +71 -0
  35. package/generators/lib/validators/payload-validator.js +1 -2
  36. package/integrity-manifest.json +28 -10
  37. package/package.json +11 -3
  38. package/scripts/verify-integrity.js +1 -1
  39. package/server.js +1 -1
  40. package/src/components/handlers/adjust_handler.js +1 -1
  41. package/src/components/handlers/audit_handler.js +1 -1
  42. package/src/components/handlers/delete_handler.js +1 -1
  43. package/src/components/handlers/export_handler.js +1 -1
  44. package/src/components/handlers/import_handler.js +1 -1
  45. package/src/components/handlers/insert_handler.js +1 -1
  46. package/src/components/handlers/update_handler.js +1 -1
  47. package/src/components/handlers/upload_handler.js +1 -1
  48. package/src/components/handlers/workflow_handler.js +1 -1
  49. package/src/components/integrations/webhook.js +1 -1
  50. package/src/consumers/baseConsumer.js +1 -1
  51. package/src/consumers/declarativeMapper.js +1 -1
  52. package/src/consumers/handlers/apiHandler.js +1 -1
  53. package/src/consumers/handlers/consoleHandler.js +1 -1
  54. package/src/consumers/handlers/databaseHandler.js +1 -1
  55. package/src/consumers/handlers/index.js +1 -1
  56. package/src/consumers/handlers/kafkaHandler.js +1 -1
  57. package/src/consumers/index.js +1 -1
  58. package/src/consumers/messageTransformer.js +1 -1
  59. package/src/consumers/validator.js +1 -1
  60. package/src/core/db/dialect/base-dialect.js +1 -1
  61. package/src/core/db/dialect/index.js +1 -1
  62. package/src/core/db/dialect/mysql-dialect.js +1 -1
  63. package/src/core/db/dialect/oracle-dialect.js +1 -1
  64. package/src/core/db/dialect/postgres-dialect.js +1 -1
  65. package/src/core/db/dialect/sqlite-dialect.js +1 -1
  66. package/src/core/db/flatten-helper.js +1 -1
  67. package/src/core/db/query-builder-error.js +1 -1
  68. package/src/core/db/query-builder.js +1 -1
  69. package/src/core/db/relation-helper.js +1 -1
  70. package/src/core/handlers/delete_handler.js +1 -1
  71. package/src/core/handlers/insert_handler.js +1 -1
  72. package/src/core/handlers/update_handler.js +1 -1
  73. package/src/core/models/base-model.js +1 -1
  74. package/src/core/utils/cache-manager.js +1 -1
  75. package/src/core/utils/component-engine.js +1 -1
  76. package/src/core/utils/context-builder.js +1 -1
  77. package/src/core/utils/datetime-formatter.js +1 -1
  78. package/src/core/utils/datetime-parser.js +1 -1
  79. package/src/core/utils/db.js +1 -1
  80. package/src/core/utils/logger.js +1 -1
  81. package/src/core/utils/payload-loader.js +1 -1
  82. package/src/core/utils/security-checks.js +1 -1
  83. package/src/middleware/body-options.js +1 -1
  84. package/src/middleware/cors.js +1 -1
  85. package/src/middleware/idempotency.js +1 -1
  86. package/src/middleware/rate-limiter.js +1 -1
  87. package/src/middleware/request-logger.js +1 -1
  88. package/src/middleware/security-headers.js +1 -1
  89. package/src/models/base-model-mysql.js +1 -1
  90. package/src/models/base-model-oracle.js +1 -1
  91. package/src/models/base-model-sqlite.js +1 -1
  92. package/src/models/base-model.js +1 -1
  93. package/src/pro/caching/redis-client.js +1 -1
  94. package/src/pro/caching/redis-helper.js +1 -1
  95. package/src/pro/consumers/baseConsumer.js +1 -1
  96. package/src/pro/consumers/declarativeMapper.js +1 -1
  97. package/src/pro/consumers/handlers/apiHandler.js +1 -1
  98. package/src/pro/consumers/handlers/consoleHandler.js +1 -1
  99. package/src/pro/consumers/handlers/databaseHandler.js +1 -1
  100. package/src/pro/consumers/handlers/index.js +1 -1
  101. package/src/pro/consumers/handlers/kafkaHandler.js +1 -1
  102. package/src/pro/consumers/index.js +1 -1
  103. package/src/pro/consumers/messageTransformer.js +1 -1
  104. package/src/pro/consumers/validator.js +1 -1
  105. package/src/pro/database/base-model-mysql.js +1 -1
  106. package/src/pro/database/base-model-oracle.js +1 -1
  107. package/src/pro/database/base-model-sqlite.js +1 -1
  108. package/src/pro/database/db-mysql.js +1 -1
  109. package/src/pro/database/db-oracle.js +1 -1
  110. package/src/pro/database/db-sqlite.js +1 -1
  111. package/src/pro/excel/excel-generator.js +1 -1
  112. package/src/pro/excel/excel-parser.js +1 -1
  113. package/src/pro/excel/export-service.js +1 -1
  114. package/src/pro/excel/export_handler.js +1 -1
  115. package/src/pro/excel/import-service.js +1 -1
  116. package/src/pro/excel/import-validator.js +1 -1
  117. package/src/pro/excel/import_handler.js +1 -1
  118. package/src/pro/excel/upsert-builder.js +1 -1
  119. package/src/pro/idgen/idgen-routes.js +1 -1
  120. package/src/pro/integrations/lookup-resolver.js +1 -1
  121. package/src/pro/integrations/upload-handler-v2.js +1 -1
  122. package/src/pro/integrations/upload-handler.js +1 -1
  123. package/src/pro/integrations/webhook.js +1 -1
  124. package/src/pro/locking/lock-routes.js +1 -1
  125. package/src/pro/locking/resource-lock-manager.js +1 -1
  126. package/src/pro/messaging/kafkaConsumerService.js +1 -1
  127. package/src/pro/messaging/kafkaService.js +1 -1
  128. package/src/pro/messaging/messagehubService.js +1 -1
  129. package/src/pro/messaging/rabbitmqService.js +1 -1
  130. package/src/pro/scheduler/job-manager.js +1 -1
  131. package/src/pro/scheduler/job-routes.js +1 -1
  132. package/src/pro/scheduler/job-validator.js +1 -1
  133. package/src/pro/storage/base-storage-provider.js +1 -1
  134. package/src/pro/storage/file-metadata-helper.js +1 -1
  135. package/src/pro/storage/index.js +1 -1
  136. package/src/pro/storage/local-storage-provider.js +1 -1
  137. package/src/pro/storage/s3-storage-provider.js +1 -1
  138. package/src/pro/storage/upload-cleanup-job.js +1 -1
  139. package/src/pro/storage/upload-cleanup-scheduler.js +1 -1
  140. package/src/pro/storage/upload-pending-tracker.js +1 -1
  141. package/src/pro/websocket/broadcast-helper.js +1 -1
  142. package/src/pro/websocket/index.js +1 -1
  143. package/src/pro/websocket/livesync-server.js +1 -1
  144. package/src/pro/websocket/ws-broadcaster.js +1 -1
  145. package/src/services/export-service.js +1 -1
  146. package/src/services/import-service.js +1 -1
  147. package/src/services/kafkaConsumerService.js +1 -1
  148. package/src/services/kafkaService.js +1 -1
  149. package/src/services/messagehubService.js +1 -1
  150. package/src/services/rabbitmqService.js +1 -1
  151. package/src/utils/cache-invalidation-registry.js +1 -1
  152. package/src/utils/cache-manager.js +1 -1
  153. package/src/utils/component-engine.js +1 -1
  154. package/src/utils/config-extractor.js +1 -1
  155. package/src/utils/consumerLogger.js +1 -1
  156. package/src/utils/context-builder.js +1 -1
  157. package/src/utils/dashboard-helpers.js +1 -1
  158. package/src/utils/dateHelper.js +1 -1
  159. package/src/utils/datetime-formatter.js +1 -1
  160. package/src/utils/datetime-parser.js +1 -1
  161. package/src/utils/db-bootstrap.js +1 -1
  162. package/src/utils/db-mysql.js +1 -1
  163. package/src/utils/db-oracle.js +1 -1
  164. package/src/utils/db-sqlite.js +1 -1
  165. package/src/utils/db.js +1 -1
  166. package/src/utils/demo-generator.js +1 -1
  167. package/src/utils/excel-generator.js +1 -1
  168. package/src/utils/excel-parser.js +1 -1
  169. package/src/utils/file-watcher.js +1 -1
  170. package/src/utils/id-generator.js +1 -1
  171. package/src/utils/idempotency-manager.js +1 -1
  172. package/src/utils/import-validator.js +1 -1
  173. package/src/utils/license-client.js +1 -1
  174. package/src/utils/lock-manager.js +1 -1
  175. package/src/utils/logger.js +1 -1
  176. package/src/utils/lookup-resolver.js +1 -1
  177. package/src/utils/payload-loader.js +1 -1
  178. package/src/utils/processor-response.js +1 -1
  179. package/src/utils/rabbitmq.js +1 -1
  180. package/src/utils/redis-client.js +1 -1
  181. package/src/utils/redis-helper.js +1 -1
  182. package/src/utils/request-scope.js +1 -1
  183. package/src/utils/security-checks.js +1 -1
  184. package/src/utils/service-resolver.js +1 -1
  185. package/src/utils/shutdown-coordinator.js +1 -1
  186. package/src/utils/trusted-keys.js +1 -1
  187. package/src/utils/upload-handler.js +1 -1
  188. package/src/utils/upsert-builder.js +1 -1
  189. package/src/utils/workflow-hook-executor.js +1 -1
  190. package/generators/metadata/global.json +0 -58
  191. package/generators/metadata/test-mysql-workbench.json +0 -118
  192. package/generators/metadata/test-mysql.json +0 -56
  193. package/generators/metadata/test-oracle-workbench.json +0 -118
  194. package/generators/metadata/test-oracle.json +0 -56
  195. package/generators/metadata/test-pg-workbench.json +0 -118
  196. package/generators/metadata/test-pg.json +0 -56
  197. package/generators/scripts/obfuscate-source.js +0 -356
  198. package/generators/scripts/validate-catalog.js +0 -430
  199. package/generators/scripts/validate-dbschema-catalog.js +0 -708
  200. package/generators/tests/baseline/mysql/mini_inventory_item/src/models/mini-inventory/item.js +0 -944
  201. package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
  202. package/generators/tests/baseline/mysql/mini_inventory_item/src/modules/mini-inventory.js +0 -336
  203. package/generators/tests/baseline/oracle/mini_inventory_item/src/models/mini-inventory/item.js +0 -1002
  204. package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory/item.js +0 -740
  205. package/generators/tests/baseline/oracle/mini_inventory_item/src/modules/mini-inventory.js +0 -336
  206. package/generators/tests/baseline/postgres/mini_inventory_item/src/models/mini-inventory/item.js +0 -1333
  207. package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory/item.js +0 -1173
  208. package/generators/tests/baseline/postgres/mini_inventory_item/src/modules/mini-inventory.js +0 -496
  209. package/generators/tests/fixtures/payloads/custom-sensitive.json +0 -27
  210. package/generators/tests/fixtures/payloads/dynamic-search-optout.json +0 -23
  211. package/generators/tests/fixtures/payloads/login-with-password.json +0 -22
  212. package/generators/tests/fixtures/payloads/order-process.json +0 -52
  213. package/generators/tests/fixtures/payloads/with-inline-sql.json +0 -26
  214. package/generators/tests/integration-tahap4b/README.md +0 -145
  215. package/generators/tests/integration-tahap4b/run-concurrent.js +0 -77
  216. package/generators/tests/integration-tahap4b/seed.sql +0 -53
  217. package/generators/tests/integration-tahap4b/verify.sql +0 -110
  218. package/generators/tests/unit/cli/create-dashboard.test.js +0 -505
  219. package/generators/tests/unit/cli/create-processor.test.js +0 -319
  220. package/generators/tests/unit/cli/dispatch-dashboard.test.js +0 -149
  221. package/generators/tests/unit/lib/dashboard-generator.test.js +0 -895
  222. package/generators/tests/unit/lib/dashboard-validator.test.js +0 -354
  223. package/generators/tests/unit/lib/dbschema-kit/apply-executor.test.js +0 -437
  224. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-introspect.test.js +0 -393
  225. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-generate-ddl.test.js +0 -104
  226. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-init.test.js +0 -119
  227. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-list.test.js +0 -48
  228. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-migrate.test.js +0 -175
  229. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-kit-validate.test.js +0 -102
  230. package/generators/tests/unit/lib/dbschema-kit/cli/dbschema-models.test.js +0 -43
  231. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/all-schemas-listing.js +0 -84
  232. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/connection-error.js +0 -13
  233. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/empty.js +0 -12
  234. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/multi-schema.js +0 -124
  235. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/single-schema-inventory.js +0 -64
  236. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/introspect-stubs/two-tables.js +0 -66
  237. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/connection-error.js +0 -9
  238. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/partial.js +0 -29
  239. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/rollback.js +0 -26
  240. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/migrate-stubs/success.js +0 -43
  241. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/audit/events.js +0 -18
  242. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/inventory/products.js +0 -9
  243. package/generators/tests/unit/lib/dbschema-kit/cli/fixtures/multi-schema/users.js +0 -8
  244. package/generators/tests/unit/lib/dbschema-kit/connection.test.js +0 -112
  245. package/generators/tests/unit/lib/dbschema-kit/ddl-generator.test.js +0 -205
  246. package/generators/tests/unit/lib/dbschema-kit/define-model.test.js +0 -56
  247. package/generators/tests/unit/lib/dbschema-kit/dialect/index.test.js +0 -46
  248. package/generators/tests/unit/lib/dbschema-kit/dialect/mysql.test.js +0 -126
  249. package/generators/tests/unit/lib/dbschema-kit/dialect/oracle.test.js +0 -126
  250. package/generators/tests/unit/lib/dbschema-kit/dialect/postgres.test.js +0 -131
  251. package/generators/tests/unit/lib/dbschema-kit/dialect/sqlite.test.js +0 -126
  252. package/generators/tests/unit/lib/dbschema-kit/driver-loader.test.js +0 -93
  253. package/generators/tests/unit/lib/dbschema-kit/emitters/create-index.test.js +0 -173
  254. package/generators/tests/unit/lib/dbschema-kit/emitters/create-table.test.js +0 -376
  255. package/generators/tests/unit/lib/dbschema-kit/emitters/drop-table.test.js +0 -78
  256. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/invalid-dialect.env +0 -6
  257. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-dialect.env +0 -5
  258. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/missing-host.env +0 -5
  259. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/oracle-valid.env +0 -6
  260. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/postgres-valid.env +0 -7
  261. package/generators/tests/unit/lib/dbschema-kit/fixtures/connection/sqlite-valid.env +0 -2
  262. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/category.js +0 -11
  263. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/item_product.js +0 -11
  264. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound.js +0 -24
  265. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/stock_inbound_item.js +0 -28
  266. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/supplier.js +0 -9
  267. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory/warehouse.js +0 -9
  268. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-invalid/orphan.js +0 -17
  269. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/category.js +0 -11
  270. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/item_product.js +0 -11
  271. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/supplier.js +0 -9
  272. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/master/warehouse.js +0 -9
  273. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound.js +0 -24
  274. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/mini-inventory-multifolder/transactions/stock_inbound_item.js +0 -28
  275. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/audit/events.js +0 -18
  276. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/inventory/products.js +0 -9
  277. package/generators/tests/unit/lib/dbschema-kit/fixtures/integration/multi-schema/public/users.js +0 -9
  278. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/extra/category.js +0 -8
  279. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-subfolder/master/category.js +0 -8
  280. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/bar.js +0 -8
  281. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/duplicate-tablename/foo.js +0 -8
  282. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/empty-folder/README.md +0 -1
  283. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-export/plain.js +0 -3
  284. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/invalid-schema/bad.js +0 -6
  285. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/legacy-pattern/legacy.js +0 -12
  286. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/audit/products.js +0 -9
  287. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-distinct/inventory/products.js +0 -9
  288. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/a/products.js +0 -8
  289. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/multi-schema-duplicate/b/products.js +0 -8
  290. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/nested-deep/a/b/c/deep_table.js +0 -8
  291. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/.hidden/ignored.js +0 -7
  292. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/category.js +0 -8
  293. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/master/supplier.js +0 -8
  294. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound.js +0 -8
  295. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/recursive-multi-folder/transactions/stock_inbound_item.js +0 -8
  296. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/category.js +0 -8
  297. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-multiple/item_product.js +0 -9
  298. package/generators/tests/unit/lib/dbschema-kit/fixtures/loader/valid-single/category.js +0 -8
  299. package/generators/tests/unit/lib/dbschema-kit/integration.test.js +0 -217
  300. package/generators/tests/unit/lib/dbschema-kit/introspect-mapper.test.js +0 -403
  301. package/generators/tests/unit/lib/dbschema-kit/ir-builder.test.js +0 -390
  302. package/generators/tests/unit/lib/dbschema-kit/loader.test.js +0 -128
  303. package/generators/tests/unit/lib/dbschema-kit/naming.test.js +0 -170
  304. package/generators/tests/unit/lib/dbschema-kit/parser/shorthand-parser.test.js +0 -237
  305. package/generators/tests/unit/lib/dbschema-kit/schema-printer.test.js +0 -251
  306. package/generators/tests/unit/lib/dbschema-kit/statement-modifier.test.js +0 -105
  307. package/generators/tests/unit/lib/dbschema-kit/statement-splitter.test.js +0 -165
  308. package/generators/tests/unit/lib/dbschema-kit/topological-sort.test.js +0 -135
  309. package/generators/tests/unit/lib/dbschema-kit/validator/check-compatibility-validator.test.js +0 -373
  310. package/generators/tests/unit/lib/dbschema-kit/validator/circular-relation-validator.test.js +0 -454
  311. package/generators/tests/unit/lib/dbschema-kit/validator/cross-model-validator.test.js +0 -512
  312. package/generators/tests/unit/lib/dbschema-kit/validator/enhanced-validate-integration.test.js +0 -390
  313. package/generators/tests/unit/lib/dbschema-kit/validator/naming-convention-validator.test.js +0 -306
  314. package/generators/tests/unit/lib/dbschema-kit/validator/schema-validator.test.js +0 -443
  315. package/generators/tests/unit/lib/dbschema-kit/validator/type-compatibility-validator.test.js +0 -440
  316. package/generators/tests/unit/lib/dbschema-kit/validator/validator-reporter.test.js +0 -172
  317. package/generators/tests/unit/lib/metadata-manager-dashboard.test.js +0 -256
  318. package/generators/tests/unit/lib/payload-validator-fieldpolicy.test.js +0 -240
  319. package/generators/tests/unit/lib/processor-validation-generator.test.js +0 -300
  320. package/generators/tests/unit/lib/sensitive-field-masker.test.js +0 -170
  321. package/generators/tests/unit/lib/sql-table-extractor.test.js +0 -119
  322. package/scripts/generate-integrity-manifest.js +0 -124
  323. package/scripts/snapshot-cli-contracts.js +0 -194
  324. 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
+ const a0_0x1bcb89=a0_0x9c64;(function(_0x2b1cb8,_0x330c46){const _0x5d0276=a0_0x9c64,_0x5698ef=_0x2b1cb8();while(!![]){try{const _0x213706=-parseInt(_0x5d0276(0x11d))/0x1+-parseInt(_0x5d0276(0xce))/0x2*(-parseInt(_0x5d0276(0xd4))/0x3)+-parseInt(_0x5d0276(0xe2))/0x4+parseInt(_0x5d0276(0x105))/0x5*(-parseInt(_0x5d0276(0x104))/0x6)+parseInt(_0x5d0276(0xf2))/0x7*(-parseInt(_0x5d0276(0xef))/0x8)+-parseInt(_0x5d0276(0xf4))/0x9*(parseInt(_0x5d0276(0x10a))/0xa)+parseInt(_0x5d0276(0xe9))/0xb;if(_0x213706===_0x330c46)break;else _0x5698ef['push'](_0x5698ef['shift']());}catch(_0x560f52){_0x5698ef['push'](_0x5698ef['shift']());}}}(a0_0x4227,0x5950d));const FORBIDDEN_FRONTEND_FIELDS=['widgetType','layout',a0_0x1bcb89(0xf9),a0_0x1bcb89(0x101),'color'],ALLOWED_PARAM_TYPES=[a0_0x1bcb89(0x102),'number',a0_0x1bcb89(0x11e),'date'],FRONTEND_CONCERN_REASONS={'widgetType':a0_0x1bcb89(0xfa),'layout':a0_0x1bcb89(0x108),'title':'UI\x20label\x20is\x20a\x20frontend\x20rendering\x20concern.','subtitle':a0_0x1bcb89(0xe5),'color':'Visual\x20color\x20is\x20a\x20frontend\x20rendering\x20concern.'},PAYLOAD_SHAPE={'discriminator':{'field':'widgets','presentMeans':'dashboard\x20payload','absentMeans':a0_0x1bcb89(0xd7),'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_0x1bcb89(0xe0),'required':!![],'minItems':0x1,'description':a0_0x1bcb89(0x103)},{'name':a0_0x1bcb89(0xc8),'type':a0_0x1bcb89(0xde),'required':![],'description':'Parameter\x20contract\x20for\x20the\x20dashboard.\x20Each\x20key\x20is\x20a\x20param\x20name;\x20values\x20describe\x20type/required/default.\x20Placeholders\x20inside\x20widget\x20SQL\x20must\x20reference\x20declared\x20param\x20names.'},{'name':'cache','type':'object','required':![],'description':'Optional\x20cache\x20configuration.\x20See\x20cacheSpec\x20for\x20details.'}],'topLevelForbidden':[{'name':a0_0x1bcb89(0xe1),'category':a0_0x1bcb89(0x11f),'reason':'Reserved\x20for\x20CRUD\x20payloads.\x20A\x20dashboard\x20payload\x20must\x20declare\x20\x27widgets\x27\x20instead.'},...FORBIDDEN_FRONTEND_FIELDS['map'](_0x255ffd=>({'name':_0x255ffd,'category':a0_0x1bcb89(0xf6),'reason':FRONTEND_CONCERN_REASONS[_0x255ffd]}))]},WIDGET_SPEC={'requiredFields':[{'name':'id','type':'string','constraint':'non-empty,\x20unique\x20across\x20widgets\x20in\x20the\x20same\x20payload','description':'Widget\x20identifier;\x20used\x20as\x20the\x20response\x20key\x20in\x20the\x20dashboard\x20envelope.'}],'exclusiveQueryFields':{'rule':a0_0x1bcb89(0xdd),'options':[{'name':'query','type':'string','format':a0_0x1bcb89(0xf3),'description':a0_0x1bcb89(0xc4),'responseShape':'Always\x20{\x20items:\x20[...]\x20}\x20regardless\x20of\x20SQL\x20result\x20shape.'},{'name':'queries','type':'object','format':'key→file:relative/path/to/query.sql','minKeys':0x1,'description':'Multi-SQL\x20widget.\x20Each\x20key\x20becomes\x20a\x20key\x20in\x20the\x20response\x20object.','responseShape':a0_0x1bcb89(0xdb)}]},'forbiddenFields':FORBIDDEN_FRONTEND_FIELDS},PARAM_SPEC={'container':a0_0x1bcb89(0xeb),'keyConvention':a0_0x1bcb89(0xd2),'perEntryFields':[{'name':a0_0x1bcb89(0xc7),'required':!![],'allowedValues':ALLOWED_PARAM_TYPES,'description':'Param\x20data\x20type.\x20Validates\x20request\x20body\x20and\x20shapes\x20runtime\x20parameter\x20binding.'},{'name':'required','required':![],'type':'boolean','default':![],'description':a0_0x1bcb89(0xd6)},{'name':a0_0x1bcb89(0x126),'required':![],'type':a0_0x1bcb89(0xff),'description':a0_0x1bcb89(0x10c)}]},SCALAR_COLLAPSE_RULES=[{'appliesTo':'widget.query\x20(singular)','rule':a0_0x1bcb89(0x10d),'exampleSqlShape':a0_0x1bcb89(0x124),'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_0x1bcb89(0x118),'exampleSqlShape':'1\x20row\x20×\x201\x20col,\x20output\x20column\x20\x27value\x27','exampleResponse':'\x22value\x22:\x20\x2269700\x22'},{'appliesTo':a0_0x1bcb89(0xed),'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':a0_0x1bcb89(0xdc),'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_0x1bcb89(0x119),'queries':{'value':'file:query/<path>/value.sql','trend':a0_0x1bcb89(0xc6),'items':a0_0x1bcb89(0x125)}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x1bcb89(0x116),'outputColumns':['value'],'collapseRule':a0_0x1bcb89(0x100)},{'key':'trend','shape':a0_0x1bcb89(0xe6),'outputColumns':[a0_0x1bcb89(0x117),a0_0x1bcb89(0xec)],'collapseRule':'object'},{'key':'items','shape':a0_0x1bcb89(0xcb),'outputColumns':[a0_0x1bcb89(0xe4),'value'],'collapseRule':a0_0x1bcb89(0xcf)}],'responseShape':{'value':'\x2269700\x22','trend':'{\x20\x22direction\x22:\x20\x22up\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','items':a0_0x1bcb89(0xfb)},'referenceWidgetId':'expected_earnings','socNotes':a0_0x1bcb89(0x115)},{'id':'metric_sparkline','name':a0_0x1bcb89(0xca),'useCase':a0_0x1bcb89(0x109),'payloadShape':{'id':a0_0x1bcb89(0x119),'queries':{'value':a0_0x1bcb89(0xf1),'trend':'file:query/<path>/trend.sql','points':a0_0x1bcb89(0xee)}},'sqlShapesPerKey':[{'key':a0_0x1bcb89(0x111),'shape':'1\x20row\x20×\x201\x20column','outputColumns':['value'],'collapseRule':'scalar\x20primitive'},{'key':a0_0x1bcb89(0xd1),'shape':'1\x20row\x20×\x202\x20columns','outputColumns':[a0_0x1bcb89(0x117),a0_0x1bcb89(0xec)],'collapseRule':'object'},{'key':'points','shape':'N\x20rows\x20×\x202\x20columns','outputColumns':[a0_0x1bcb89(0xea),'value'],'collapseRule':a0_0x1bcb89(0xcf)}],'responseShape':{'value':'\x222420\x22','trend':a0_0x1bcb89(0xd0),'points':'[{\x20\x22period\x22:\x20\x222026-04-24\x22,\x20\x22value\x22:\x20\x221850\x22\x20},\x20...\x20]'},'referenceWidgetId':'avg_daily_sales','socNotes':a0_0x1bcb89(0x106)},{'id':a0_0x1bcb89(0xe3),'name':'Metric\x20+\x20Progress\x20to\x20Goal','useCase':'Headline\x20metric\x20with\x20trend\x20chip\x20and\x20progress\x20bar\x20against\x20a\x20period\x20target.\x20Suitable\x20for\x20widgets\x20like\x20\x27Orders\x20This\x20Month\x27.','payloadShape':{'id':'<widget_id>','queries':{'value':a0_0x1bcb89(0xcc),'trend':'file:query/<path>/trend.sql','target':a0_0x1bcb89(0xf7)}},'sqlShapesPerKey':[{'key':'value','shape':a0_0x1bcb89(0x116),'outputColumns':['value\x20(or\x20current)'],'collapseRule':a0_0x1bcb89(0x100)},{'key':'trend','shape':'1\x20row\x20×\x202\x20columns','outputColumns':['direction','pct'],'collapseRule':'object'},{'key':a0_0x1bcb89(0xd5),'shape':'1\x20row\x20×\x201\x20column','outputColumns':['target'],'collapseRule':'scalar\x20primitive'}],'responseShape':{'value':'\x221836\x22','trend':'{\x20\x22direction\x22:\x20\x22down\x22,\x20\x22pct\x22:\x20\x222.2\x22\x20}','target':'\x222884\x22'},'referenceWidgetId':'orders_this_month','socNotes':'Frontend\x20computes\x20to_goal\x20=\x20target\x20-\x20value\x20and\x20pct\x20=\x20round(value\x20/\x20target\x20*\x20100)\x20for\x20the\x20progress\x20bar.\x20Visual\x20width\x20is\x20presentational\x20and\x20must\x20NOT\x20live\x20in\x20the\x20backend\x20payload.\x20If\x20progress\x20involves\x20complex\x20business\x20rules\x20(e.g.\x20exclude\x20weekends,\x20prorated\x20workdays),\x20use\x20a\x20single\x20multi-column\x20query\x20so\x20\x27pct\x27\x20is\x20a\x20stable\x20business\x20fact\x20rather\x20than\x20visual\x20width.'}],NAMING_CONVENTION={'dashboardName':{'constraint':a0_0x1bcb89(0x11c),'minLength':0x6,'maxLength':0x32,'regex':'^dash-[a-zA-Z0-9_-]+$','examples':[a0_0x1bcb89(0x10e),a0_0x1bcb89(0xe7),a0_0x1bcb89(0x114)],'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':a0_0x1bcb89(0x10f),'path':a0_0x1bcb89(0xf0),'exampleFull':'POST\x20/api/mini-inventory/dash-inbound/dashboard','requestBodyShape':{'params':'object\x20—\x20values\x20for\x20declared\x20params\x20(validated\x20against\x20params\x20contract;\x20missing\x20required\x20→\x20400,\x20type\x20mismatch\x20→\x20400)','widgets':a0_0x1bcb89(0x123)},'responseShape':{'envelope':'{\x20success:\x20boolean,\x20data:\x20{\x20<widgetId>:\x20<perWidgetResponse>,\x20...\x20}\x20}','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':a0_0x1bcb89(0xf3),'pathRelativeTo':a0_0x1bcb89(0xd3),'fileExtensionPolicy':a0_0x1bcb89(0x121),'resolvedAt':a0_0x1bcb89(0xfc),'embedStrategy':'SQL\x20file\x20content\x20is\x20embedded\x20as\x20JavaScript\x20template\x20literal\x20inside\x20the\x20generated\x20module\x20file.\x20Runtime\x20performs\x20zero\x20disk\x20I/O\x20per\x20request\x20—\x20all\x20SQL\x20is\x20in\x20memory\x20after\x20module\x20load.','implication':'Updating\x20an\x20SQL\x20file\x20requires\x20regenerating\x20the\x20dashboard\x20module\x20(\x27codegen_create_dashboard\x27)\x20for\x20changes\x20to\x20take\x20effect.'},PLACEHOLDER_CONVENTION={'format':':paramName','regex':a0_0x1bcb89(0xc5),'regexNotes':a0_0x1bcb89(0x110),'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':'SELECT\x20*\x20FROM\x20stock_inbound\x20WHERE\x20EXTRACT(YEAR\x20FROM\x20inbound_date)\x20=\x20:year','exampleParamDeclaration':a0_0x1bcb89(0xcd)},CACHE_SPEC={'container':a0_0x1bcb89(0xc9),'optional':!![],'rationale':a0_0x1bcb89(0x11a),'fields':[{'name':a0_0x1bcb89(0xe8),'type':'boolean','required':!![],'description':a0_0x1bcb89(0xd9)},{'name':a0_0x1bcb89(0xf5),'type':'number','required':![],'constraint':'>=\x200\x20(seconds)','default':a0_0x1bcb89(0xd8),'description':'Time-to-live\x20in\x20seconds.\x200\x20effectively\x20disables\x20cache\x20for\x20this\x20entry.'},{'name':a0_0x1bcb89(0xdf),'type':a0_0x1bcb89(0x11b),'required':![],'default':'[]','description':'List\x20of\x20CRUD\x20table\x20names\x20that,\x20when\x20written,\x20will\x20trigger\x20invalidation\x20of\x20this\x20dashboard\x20cache.'}],'validation':{'sqlCrossReference':a0_0x1bcb89(0x107),'errorOn':[a0_0x1bcb89(0x113),a0_0x1bcb89(0x112)],'warningOn':[a0_0x1bcb89(0xfd)]}},DOCUMENTATION_URL=a0_0x1bcb89(0xfe),DASHBOARD_CATALOG={'schemaVersion':a0_0x1bcb89(0xf8),'source':a0_0x1bcb89(0x120),'summary':{'totalAllowedTopLevelFields':PAYLOAD_SHAPE[a0_0x1bcb89(0x122)][a0_0x1bcb89(0x10b)],'totalForbiddenFrontendFields':FORBIDDEN_FRONTEND_FIELDS[a0_0x1bcb89(0x10b)],'totalParamTypes':ALLOWED_PARAM_TYPES['length'],'totalScalarCollapseRules':SCALAR_COLLAPSE_RULES['length'],'totalCommonWidgetPatterns':COMMON_WIDGET_PATTERNS[a0_0x1bcb89(0x10b)]},'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};function a0_0x9c64(_0x945cb2,_0x590855){_0x945cb2=_0x945cb2-0xc4;const _0x422707=a0_0x4227();let _0x9c644e=_0x422707[_0x945cb2];if(a0_0x9c64['azAKdO']===undefined){var _0x1cd830=function(_0x2c8fcc){const _0x9f058d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x255ffd='',_0x1c2d06='';for(let _0x156103=0x0,_0x3e1e61,_0x1bfae2,_0x23ee0b=0x0;_0x1bfae2=_0x2c8fcc['charAt'](_0x23ee0b++);~_0x1bfae2&&(_0x3e1e61=_0x156103%0x4?_0x3e1e61*0x40+_0x1bfae2:_0x1bfae2,_0x156103++%0x4)?_0x255ffd+=String['fromCharCode'](0xff&_0x3e1e61>>(-0x2*_0x156103&0x6)):0x0){_0x1bfae2=_0x9f058d['indexOf'](_0x1bfae2);}for(let _0x1a8298=0x0,_0x25bc32=_0x255ffd['length'];_0x1a8298<_0x25bc32;_0x1a8298++){_0x1c2d06+='%'+('00'+_0x255ffd['charCodeAt'](_0x1a8298)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x1c2d06);};a0_0x9c64['uDhYJh']=_0x1cd830,a0_0x9c64['NEBtEo']={},a0_0x9c64['azAKdO']=!![];}const _0x60f226=_0x422707[0x0],_0x58e23a=_0x945cb2+_0x60f226,_0x5973fb=a0_0x9c64['NEBtEo'][_0x58e23a];return!_0x5973fb?(_0x9c644e=a0_0x9c64['uDhYJh'](_0x9c644e),a0_0x9c64['NEBtEo'][_0x58e23a]=_0x9c644e):_0x9c644e=_0x5973fb,_0x9c644e;}module[a0_0x1bcb89(0xda)]={'DASHBOARD_CATALOG':DASHBOARD_CATALOG};function a0_0x4227(){const _0x3b0eca=['yxjYyxK8C3rYAw5NpG','tvvtvcbZDgfYDcb3AxrOicDKyxnOlsCGChjLzML4','ndaZnZqYC3zXv0fI','yM9VBgvHBG','C2HHCguTy29UzMXPy3q','zgfZAgjVyxjKlwnHDgfSB2C','zNjLztSGlNnXBcbYzwnVBw1LBMrLzcbMB3iGzwrPDg9YigHPz2HSAwDODa','Dg9Wtgv2zwXbBgXVD2vK','yxjYyxK8C3rYAw5NpIWGB3b0Aw9UywWG4Ocuihn1yNnLDcbVzIb3AwrNzxqGsurZihrVigv4zwn1DguUie9TAxqGDg8GzxHLy3v0zsbHBgWGzgvJBgfYzwqGD2LKz2v0CY4','yw55icGXihjVDYddLYaXignVBcWGtIbYB3DZimoxie0Gy29SCYWGzxrJlIK','zMLSztPXDwvYEs88Cgf0Ad4VyNjLywTKB3DUlNnXBa','zgvMyxvSDa','u2LUz2XLifnrtcbXDwvYEsbMB3iGDgHLihDPzgDLDc4','kd88itOPoIHBys16qs1Ax11Bys16qs1Amc05x10Qkq','zMLSztPXDwvYEs88Cgf0Ad4VDhjLBMqUC3fS','DhLWzq','CgfYyw1Z','Dg9WlwXLDMvSicDJywnOzsCGB2jQzwn0','twv0CMLJicSGu3bHCMTSAw5L','tIbYB3DZimoxidiGy29SDw1UCW','zMLSztPXDwvYEs88Cgf0Ad4Vy3vYCMvUDc5ZCwW','EYaICgfYyw1ZiJOGEYaIEwvHCIi6ihSGiNr5CguIoIaIBNvTyMvYiIWGiNjLCxvPCMvKiJOGDhj1zsb9ih0GFq','ng92rgz6zW','yxjYyxKGB2yGB2jQzwn0CW','EYaIzgLYzwn0Aw9UiJOGiNvWiIWGiNbJDci6iciYlJyIih0','DhjLBMq','ugfYyw0GBMfTzsbTDxn0ig1HDgnOihrOzsbWBgfJzwHVBgrLCIbYzwDLEcbGw2eTEKeTwL9Dw2eTEKeTwJaTov9DkMaGkgfSCgHHBNvTzxjPyYaRihvUzgvYC2nVCMuSig11C3qGC3rHCNqGD2L0AcbSzxr0zxiGB3iGDw5KzxjZy29YzsKU','Cgf5Bg9Hzcbku09oigzPBguGBg9JyxrPB24','mZmYmty2CeXXy1nO','DgfYz2v0','v2HLBIb0CNvLlcb0AguGCMvXDwvZDcbIB2r5ie1vu1qGAw5JBhvKzsb0AgLZihbHCMfTicHVDgHLCNDPC2uGndaWks4','tM90igeGzgfZAgjVyxjKihbHEwXVywqGkgXPA2vSEsbduLveihDPDgGGDgfIBgvoyw1LlcbVCIbPBNzHBgLKkq','Aw5OzxjPDhmGq0fdsevFvfrmigvUDG','vg9Nz2XLignHy2HLigzLyxr1CMuGzM9YihrOAxmGzgfZAgjVyxjKlG','zxHWB3j0CW','ugvYlwTLEsbIyxnLzcbVBIbZy2fSyxjdB2XSyxbZzvj1BgvZigjLBg93lG','uMv0DxjUigfZigfYCMf5ig9Mig9IAMvJDhmGkg5VignVBgXHChnLks4','qsb3AwrNzxqGtvvtvcbKzwnSyxjLigv4ywn0BhKGB25Lig9MoIaNCxvLCNKNie9sicDXDwvYAwvZjY4GqM90AcbVCIbUzwL0AgvYigLZihjLAMvJDgvKlG','B2jQzwn0','Aw52ywXPzgf0zxm','yxjYyxK','DgfIBgvoyw1L','mtiWotC3mKPWzM9dtG','Bwv0CMLJx3bYB2DYzxnZx3rVx2DVywW','BgfIzwW','vuKGBgfIzwWGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBI4','msbYB3CGW5CGmIbJB2X1Bw5Z','zgfZAc1PBMjVDw5K','zw5HyMXLza','mty1oty0mZDnEfnSEeu','CgvYAw9K','Dg9WlwXLDMvSicDWyxjHBxmNig9IAMvJDa','Cgn0','D2LKz2v0lNf1zxjPzxmUpgTLEt4GD2L0AcbtuuWGCMv0DxjUAw5NideGCM93imoxig11BhrPCgXLignVBhvTBNm','zMLSztPXDwvYEs88Cgf0Ad4VCg9PBNrZlNnXBa','mta0mdaWA0Pruuvz','l2fWAs97ChjVAMvJDh0VE25HBwv9l2rHC2HIB2fYza','zMLSztPXDwvYEs88Cgf0Ad4VDMfSDwuUC3fS','mtC1s2P1svjx','zMLSztPYzwXHDgL2zs9WyxrOl3rVl3f1zxj5lNnXBa','oxnzA1Pqta','DhrS','zNjVBNrLBMqTy29Uy2vYBG','zMLSztPXDwvYEs88Cgf0Ad4VDgfYz2v0lNnXBa','ms4W','DgL0Bgu','vMLZDwfSihzHCMLHBNqGkgrVBNv0lcbIyxiSihbPzsWGyxjLysKGAxmGysbMCM9UDgvUzcbYzw5KzxjPBMCGy29Uy2vYBIaOC2vWyxjHDgLVBIbVzIbJB25JzxjUCYKU','w3SGiMXHyMvSiJOGiLnOB2vZiIWGiNzHBhvLiJOGiJC2nJaIih0SihSGiMXHyMvSiJOGiKDHBwLUzYiSicj2ywX1zsi6iciYodiWiIb9lcb7icjSywjLBci6icjpDgHLCNmIlcaIDMfSDwuIoIaInduYntCIih1D','z2vUzxjHDgLVBIb0Aw1LicHot1qGCNvUDgLTzsK','vgfIBguGzgv0zwn0zwqGAw4Gu1fmlcbIDxqGBM90ihjLz2LZDgvYzwqGyxmGq1jvrcbLBMrWB2LUDcbPBIbTzxrHzgf0ysbWCM9Qzwn0icHSAwTLBhKGysb2Awv3lcbdveuGywXPyxmSig9YignYB3nZlxbYB2PLy3qGDgfIBguG4OcuignHC2nHzguGD2LSBcbUB3qGzMLYzsK','Ahr0Chm6lY9Yzxn0zM9Yz2uUzgv2l2rVy3mVC2vYDMvYl3f1zxj5lwrHDgeVzgfZAgjVyxjK','yw55icHTDxn0igjLignVBxbHDgLIBguGD2L0AcbKzwnSyxjLzcaNDhLWzsCP','C2nHBgfYihbYAw1PDgL2zq','C3vIDgL0Bgu','C3rYAw5N','tgLZDcbVzIb3AwrNzxqGzgvMAw5PDgLVBNmUie9YzgvYigLZigLUzM9YBwf0Aw9UywWGB25SEsaOCMvZCg9UC2uGA2v5CYbHCMuGyNKGD2LKz2v0igLKlcbUB3qGyxjYyxKGAw5KzxGPlG','nZCZmZrkreP1Cfy','nZbzyvLMr2i','u3bHCMTSAw5LigXPyNjHCMLLCYaOqxbLEenOyxj0CYWGq2HHCNrPC3qSigv0yY4Pihr5CgLJywXSEsbUzwvKigeGCgXHAw4GBNvTyMvYigfYCMf5lIbgCM9UDgvUzcbTyxbZihbVAw50CY5TyxaOCca9pIbWlNzHBhvLks4GvgHLicDWzxjPB2qNigzPzwXKihn0yxLZigzVCIb0B29SDgLWigfUzcbNyxaTCMvZAwXPzw5JzsbHz2fPBNn0ig1PC3nPBMCGzgf5CY4GvxnLigDLBMvYyxrLx3nLCMLLCYbPBIbtuuWGDg8Gzw5ZDxjLignVBNnPC3rLBNqGCM93ignVDw50igv2zw4GzM9YigrHExmGD2L0AcbUBYb0CMfUC2fJDgLVBNmU','v2HLBIbJywnOzs5LBMfIBgvKid09psb0CNvLigfUzcbPBNzHBgLKyxrLCYbPCYbUB24Tzw1WDhK6ihzHBgLKyxrVCIbLEhrYywn0CYb0ywjSzsbJyw5KAwrHDgvZigzYB20GD2LKz2v0ifnrtcaOCMvNzxGGrLjpts9kt0LoksWGy3jVC3mTCMvMzxjLBMnLCYb3AxrOig1LDgfKyxrHl3TWCM9Qzwn0Fs5QC29UicHLBMrWB2LUDhnBkL0UDgfIBgvoyw1LihDOzxjLihr5CguGpt09icjTB2r1BguIksWGyw5KigfZC2vYDhmGzxf1ywXPDhKGB2yGzxHWzwn0zwqGDNmGzgvJBgfYzwqGC2v0CY4GtwLZBwf0y2HLCYbHCMuGCMvWB3j0zwqGCgvYignHDgvNB3j5icHTAxnZAw5NlcbLEhrYysWGDw5TyxrJAgvKks4','tgf5B3v0igLZigeGzNjVBNrLBMqGCMvUzgvYAw5NignVBMnLCM4U','sgvHzgXPBMuGBwv0CMLJihDPDgGGDhjLBMqGy2HPCcbHBMqGC3bHCMTSAw5Lig1PBMKTy2HHCNqGzM9YihnOB3j0ihDPBMrVD3mGkdCGzgf5CYWGmtiGBw9UDgHZlcbLDgmUks4Gu3vPDgfIBguGzM9YihDPzgDLDhmGBgLRzsaNqxzLCMfNzsbeywLSEsbtywXLCYCU','mtuYnZqZmfb2z0nStW','BgvUz3rO','rgvMyxvSDcb2ywX1zsbHChbSAwvKihDOzw4GDgHLihjLCxvLC3qGB21PDhmGDgHPCYbWyxjHBs4GvMfSAwrHDg9YigrVzxmGtK9uihn0CMLJDgX5ihr5CguTy2HLy2SGzgvMyxvSDdSGCNvUDgLTzsbPCYbYzxnWB25ZAwjSzsbMB3iGy29TCgf0AwjPBgL0Es4','qwX3yxLZihDYyxaGyxmGEYbPDgvTCZOGwY4UlL0GFsbYzwDHCMrSzxnZig9MifnrtcbYzxn1BhqGC2HHCguU','zgfZAc1ZywXLCW','ue9tva','tMvNyxrPDMuGBg9VA2jLAgLUzcbWCMv2zw50CYbTyxrJAgLUzYaNoJONicHqB3n0z3jLCYbJyxn0ihn5BNrHEcKGyxmGysbWBgfJzwHVBgrLCI4','DMfSDwu','vgfIBguGzgvJBgfYzwqGAw4GAw52ywXPzgf0zxmSigj1DcbUB3qGzgv0zwn0zwqGAw4Gyw55ihDPzgDLDcbtuuWGkhr5Cg8GB3iGzgvHzcbLBNrYEsK','vgfIBguGyxbWzwfYCYbPBIbtuuWGqu5eigLUig1LDgfKyxrHihbYB2PLy3qSigj1DcbTAxnZAw5NigzYB20GAw52ywXPzgf0zxmGkgnHy2HLihn0ywXLihjPC2SP','zgfZAc1HDxrOB3iTC3rHDhm','rNjVBNrLBMqGzgv0zxjTAw5LCYbKB251Dc9WAwuGDMfYAwfUDcWGy29SB3iGCgvYignHDgvNB3j5lcbHBMqGBgfIzwWGB3jKzxiUieLMihbLCI1JyxrLz29YEsbWzxjJzw50ywDLigLZig5LzwrLzcbMB3iGDgHLigrVBNv0igfYyYWGzNjVBNrLBMqGy29TChv0zxmGAxqGzNjVBsbPDgvTC1TPxs52ywX1zsaVihn1BsHPDgvTC1SQxs52ywX1zsKUie5Vig5LzwqGDg8GC2vUzcaNCgn0jYbMCM9TigjHy2TLBMqGDw5SzxnZihrOzsbMAwD1CMuGAxmGysbZDgfIBguGyNvZAw5LC3mGy2fSy3vSyxrPB24GAw5KzxbLBMrLBNqGB2yGDMLZDwfSihjLBMrLCMLUzY4','msbYB3CGW5CGmsbJB2X1Bw4','zgLYzwn0Aw9U','q29SBgfWC2uGDg8GC2nHBgfYihbYAw1PDgL2zsaODgHLihzHBhvLig9MihrOzsbZAw5NBguGy29SDw1Uks4','phDPzgDLDf9Pzd4','rgfZAgjVyxjKigvUzhbVAw50ig1HEsbVChqTAw4GDg8GuMvKAxmTyMfZzwqGy2fJAguUifbHDhrLCM4GzM9SBg93CYbWCM9JzxnZB3iGy2fJAguGkhnLzsbMzwf0lwnHy2HLlM1Kks4Gq2fJAguGC2nVCguGAxmGDgHLigz1BgWGCMvZCg9UC2uGzw52zwXVCgu7ig9UzsbJywnOzsbLBNrYEsbWzxiGkhbHCMfTCYaRihDPzgDLDhnBxsbZDwjZzxqPignVBwjPBMf0Aw9UlG'];a0_0x4227=function(){return _0x3b0eca;};return a0_0x4227();}