mq-bridge-py-basic 0.3.7__tar.gz → 0.3.9__tar.gz

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 (263) hide show
  1. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.gitignore +4 -0
  2. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/CLAUDE.md +1 -1
  3. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/Cargo.lock +30 -10
  4. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/Cargo.toml +2 -2
  5. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/PKG-INFO +1 -1
  6. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/README.md +9 -4
  7. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/REFERENCE.md +107 -33
  8. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/benches/ETL_BENCHMARKS.md +5 -5
  9. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq-bridge.schema.json +54 -5
  10. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq_bridge/config.py +2 -0
  11. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq_bridge/config.pyi +37 -0
  12. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/Cargo.toml +17 -2
  13. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/src/lib.rs +70 -9
  14. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/httparena/README.md +1 -1
  15. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/server.py +1 -1
  16. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/checkpoint.rs +24 -5
  17. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/clickhouse.rs +4 -3
  18. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/file/mod.rs +222 -57
  19. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/file/tests.rs +275 -0
  20. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/publisher.rs +23 -1
  21. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/stream.rs +9 -5
  22. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/framed.rs +81 -13
  23. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mod.rs +3 -2
  24. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/consumer.rs +14 -9
  25. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/readers.rs +24 -13
  26. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/nats.rs +33 -2
  27. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/object_store.rs +31 -24
  28. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/mod.rs +69 -21
  29. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/replication.rs +83 -23
  30. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/redis_streams.rs +130 -19
  31. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/dedup.rs +23 -3
  32. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/mod.rs +160 -40
  33. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/tests.rs +40 -0
  34. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/reader.rs +17 -2
  35. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/stream_buffer.rs +34 -13
  36. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/omq.rs +12 -3
  37. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/zmq.rs +25 -0
  38. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/errors.rs +18 -2
  39. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/lib.rs +4 -1
  40. mq_bridge_py_basic-0.3.9/src/middleware/compression.rs +314 -0
  41. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/deduplication.rs +187 -14
  42. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/dlq.rs +141 -2
  43. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/encryption.rs +133 -24
  44. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/mod.rs +8 -0
  45. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/retry.rs +90 -5
  46. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/schema.rs +3 -5
  47. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/models.rs +161 -4
  48. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/route.rs +34 -2
  49. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/support/compression.rs +1 -1
  50. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/support/connection_registry.rs +3 -3
  51. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/support/crypto.rs +3 -5
  52. mq_bridge_py_basic-0.3.9/src/support/crypto_envelope.rs +17 -0
  53. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/support/mod.rs +1 -0
  54. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/traits.rs +6 -0
  55. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mariadb.rs +16 -0
  56. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mod.rs +32 -0
  57. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb.rs +40 -1
  58. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mysql.rs +137 -0
  59. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/nats.rs +48 -0
  60. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/object_store.rs +102 -0
  61. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/postgres_cdc.rs +113 -0
  62. mq_bridge_py_basic-0.3.9/tests/integration/redis_streams.rs +434 -0
  63. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration_test.rs +95 -0
  64. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/reference_docs_test.rs +134 -175
  65. mq_bridge_py_basic-0.3.7/tests/integration/redis_streams.rs +0 -227
  66. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  67. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  68. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  69. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/benchmark.yml +0 -0
  70. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/ci.yml +0 -0
  71. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/ibm-mq.yml +0 -0
  72. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/node.yml +0 -0
  73. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/publish-node.yml +0 -0
  74. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/publish-python.yml +0 -0
  75. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/python.yml +0 -0
  76. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/release.yml +0 -0
  77. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/.github/workflows/test-matrix.yml +0 -0
  78. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/ARCHITECTURE.md +0 -0
  79. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/CONFIGURATION.md +0 -0
  80. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/CONTRIBUTING.md +0 -0
  81. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/LICENSE +0 -0
  82. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/LICENSE.python +0 -0
  83. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/benches/performance_bench.rs +0 -0
  84. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/benches/router_bench.rs +0 -0
  85. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/benches/zeromq_backends.rs +0 -0
  86. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/bindings-common/Cargo.toml +0 -0
  87. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/bindings-common/src/lib.rs +0 -0
  88. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/bindings-common/src/logging.rs +0 -0
  89. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/build.rs +0 -0
  90. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/examples/ipc_worker_queue.yaml +0 -0
  91. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq_bridge/__init__.py +0 -0
  92. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq_bridge/__init__.pyi +0 -0
  93. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/mq_bridge/py.typed +0 -0
  94. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/package-lock.json +0 -0
  95. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/pyproject.toml +0 -0
  96. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/LICENSE.python +0 -0
  97. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/README.md +0 -0
  98. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/analysis/bench_http_native.py +0 -0
  99. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/example.py +0 -0
  100. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/bench_memory.py +0 -0
  101. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/bench_memory.yaml +0 -0
  102. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/consume_pull.py +0 -0
  103. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/dlt_source.py +0 -0
  104. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/json_route.py +0 -0
  105. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/memory.yaml +0 -0
  106. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/raw_route.py +0 -0
  107. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/pyproject-basic.toml +0 -0
  108. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/pyproject-reduced.toml +0 -0
  109. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/scripts/gen_config_types.py +0 -0
  110. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_config_types.py +0 -0
  111. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_logging.py +0 -0
  112. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_packaging.py +0 -0
  113. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_performance_smoke.py +0 -0
  114. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_public_api.py +0 -0
  115. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_routes.py +0 -0
  116. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/uv.lock +0 -0
  117. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/benches/metadata_bench.rs +0 -0
  118. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/debug_ibm_mq_tls.rs +0 -0
  119. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/analyze_xctrace_time_profile.py +0 -0
  120. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/http_flamegraph.py +0 -0
  121. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/mq_bridge_http_profile.rs +0 -0
  122. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/run_http_ladder.sh +0 -0
  123. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/ci/format_bench_output.sh +0 -0
  124. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/Dockerfile +0 -0
  125. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/meta.json +0 -0
  126. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/README.md +0 -0
  127. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/benchmark_config.json +0 -0
  128. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/mq-bridge-py.dockerfile +0 -0
  129. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/server.py +0 -0
  130. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/README.md +0 -0
  131. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/postgres.yml +0 -0
  132. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/seed.sql +0 -0
  133. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/techempower/verify.sh +0 -0
  134. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/README.md +0 -0
  135. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/config.yaml +0 -0
  136. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/pyproject.toml +0 -0
  137. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/server.py +0 -0
  138. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/canonical_message.rs +0 -0
  139. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/command_handler.rs +0 -0
  140. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/amqp.rs +0 -0
  141. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/aws.rs +0 -0
  142. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/grpc.proto +0 -0
  143. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/grpc.rs +0 -0
  144. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/mod.rs +0 -0
  145. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/tests.rs +0 -0
  146. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/ibm_mq.rs +0 -0
  147. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/kafka.rs +0 -0
  148. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/endpoint.rs +0 -0
  149. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/ipc_unix.rs +0 -0
  150. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/ipc_windows.rs +0 -0
  151. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/memory_transport.rs +0 -0
  152. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/mod.rs +0 -0
  153. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/transport.rs +0 -0
  154. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/dedup.rs +0 -0
  155. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/mod.rs +0 -0
  156. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/publisher.rs +0 -0
  157. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/tests.rs +0 -0
  158. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/mqtt.rs +0 -0
  159. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/poll.rs +0 -0
  160. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/VENDORED.md +0 -0
  161. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/decoder.rs +0 -0
  162. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/messages.rs +0 -0
  163. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/mod.rs +0 -0
  164. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/registry.rs +0 -0
  165. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/values.rs +0 -0
  166. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/state.rs +0 -0
  167. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/sled.rs +0 -0
  168. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/fanout.rs +0 -0
  169. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/mod.rs +0 -0
  170. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/null.rs +0 -0
  171. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/request.rs +0 -0
  172. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/response.rs +0 -0
  173. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/static_endpoint.rs +0 -0
  174. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/switch.rs +0 -0
  175. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/websocket.rs +0 -0
  176. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/codec.rs +0 -0
  177. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/mod.rs +0 -0
  178. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/event_handler.rs +0 -0
  179. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/event_store.rs +0 -0
  180. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/extensions.rs +0 -0
  181. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/buffer.rs +0 -0
  182. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/cookie_jar.rs +0 -0
  183. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/delay.rs +0 -0
  184. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/limiter.rs +0 -0
  185. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/metrics.rs +0 -0
  186. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/random_panic.rs +0 -0
  187. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/coerce.rs +0 -0
  188. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/compiled.rs +0 -0
  189. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/error.rs +0 -0
  190. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/mod.rs +0 -0
  191. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/path.rs +0 -0
  192. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/tests.rs +0 -0
  193. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/middleware/weak_join.rs +0 -0
  194. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/outcomes.rs +0 -0
  195. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/publisher.rs +0 -0
  196. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/response.rs +0 -0
  197. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/support/interpolation.rs +0 -0
  198. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/test_utils.rs +0 -0
  199. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/src/type_handler.rs +0 -0
  200. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/README.md +0 -0
  201. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/armature_integration.rs +0 -0
  202. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/amqp.rs +0 -0
  203. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/aws.rs +0 -0
  204. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/clickhouse.rs +0 -0
  205. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/config.toml +0 -0
  206. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/amqp.yml +0 -0
  207. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/aws.yml +0 -0
  208. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/clickhouse.yml +0 -0
  209. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.crl +0 -0
  210. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.kdb +0 -0
  211. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.p12 +0 -0
  212. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.rdb +0 -0
  213. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.sth +0 -0
  214. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm_mq.yml +0 -0
  215. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm_mq_tls.yml +0 -0
  216. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/kafka-tls.yml +0 -0
  217. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/kafka.yml +0 -0
  218. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mariadb.yml +0 -0
  219. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb-replica.yml +0 -0
  220. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb-tls.yml +0 -0
  221. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb.yml +0 -0
  222. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto.conf +0 -0
  223. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto_performance.conf +0 -0
  224. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto_persistence.conf +0 -0
  225. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mq_init.mqsc +0 -0
  226. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mq_init_tls.mqsc +0 -0
  227. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mqtt.yml +0 -0
  228. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mqtt_performance.yml +0 -0
  229. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mysql.yml +0 -0
  230. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/nats.yml +0 -0
  231. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/object_store.yml +0 -0
  232. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/postgres.yml +0 -0
  233. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/postgres_cdc.yml +0 -0
  234. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/redis.yml +0 -0
  235. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/file.rs +0 -0
  236. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/grpc.rs +0 -0
  237. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/grpc_tls.rs +0 -0
  238. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/http.rs +0 -0
  239. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/http_tls.rs +0 -0
  240. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/ibm_mq.rs +0 -0
  241. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/ibm_mq_tls.rs +0 -0
  242. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/ipc.rs +0 -0
  243. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/kafka.rs +0 -0
  244. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/kafka_tls.rs +0 -0
  245. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/logic_test.rs +0 -0
  246. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/memory.rs +0 -0
  247. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb_raw.rs +0 -0
  248. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb_tls.rs +0 -0
  249. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/mqtt.rs +0 -0
  250. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/performance_static.rs +0 -0
  251. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/postgres.rs +0 -0
  252. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/route.rs +0 -0
  253. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/scripts/gen_certs.sh +0 -0
  254. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/sqlite.rs +0 -0
  255. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/tls_helpers.rs +0 -0
  256. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/websocket.rs +0 -0
  257. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/integration/zeromq.rs +0 -0
  258. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/memory_leak_test.rs +0 -0
  259. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/ref_test.rs +0 -0
  260. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/sqlite_test.rs +0 -0
  261. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/tls_example.rs +0 -0
  262. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/unit_tests.md +0 -0
  263. {mq_bridge_py_basic-0.3.7 → mq_bridge_py_basic-0.3.9}/tests/websocket_test.rs +0 -0
@@ -48,3 +48,7 @@ tests/**/*.pkcs12
48
48
  .pytest_cache/
49
49
  python/mq-bridge-py/.venv/
50
50
  python/mq-bridge-py/dist/
51
+
52
+ # Local build setup (shared cargo target dir with mq-bridge-app), not for git
53
+ .cargo/
54
+ .vscode/
@@ -3,7 +3,7 @@
3
3
  > **Looking for what middleware or structural endpoints exist, and how to configure them?**
4
4
  > [REFERENCE.md](REFERENCE.md) is the complete, authoritative list — every middleware
5
5
  > (`retry`, `dlq`, `transform`, `deduplication`, `weak_join`, `buffer`, `limiter`, `delay`,
6
- > `cookie_jar`, `encryption`, `metrics`, `random_panic`, `custom`) and every structural endpoint (`ref`,
6
+ > `cookie_jar`, `encryption`, `compression`, `metrics`, `random_panic`, `custom`) and every structural endpoint (`ref`,
7
7
  > `fanout`, `switch`, `request`, `response`, `reader`, `static`, `stream_buffer`, `null`,
8
8
  > `custom`), each with its fields, defaults, and a working YAML example. Do not infer these
9
9
  > from the enum definitions in `models.rs`; the reference records the behaviour and the
@@ -2976,6 +2976,15 @@ dependencies = [
2976
2976
  "windows-link",
2977
2977
  ]
2978
2978
 
2979
+ [[package]]
2980
+ name = "libmimalloc-sys"
2981
+ version = "0.1.49"
2982
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2983
+ checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
2984
+ dependencies = [
2985
+ "cc",
2986
+ ]
2987
+
2979
2988
  [[package]]
2980
2989
  name = "libmqm-constants"
2981
2990
  version = "0.8.4"
@@ -3200,6 +3209,15 @@ dependencies = [
3200
3209
  "sketches-ddsketch",
3201
3210
  ]
3202
3211
 
3212
+ [[package]]
3213
+ name = "mimalloc"
3214
+ version = "0.1.52"
3215
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3216
+ checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
3217
+ dependencies = [
3218
+ "libmimalloc-sys",
3219
+ ]
3220
+
3203
3221
  [[package]]
3204
3222
  name = "mime"
3205
3223
  version = "0.3.17"
@@ -3330,7 +3348,7 @@ dependencies = [
3330
3348
 
3331
3349
  [[package]]
3332
3350
  name = "mq-bridge"
3333
- version = "0.3.7"
3351
+ version = "0.3.9"
3334
3352
  dependencies = [
3335
3353
  "aes-gcm",
3336
3354
  "anyhow",
@@ -3411,7 +3429,7 @@ dependencies = [
3411
3429
 
3412
3430
  [[package]]
3413
3431
  name = "mq-bridge-bindings-common"
3414
- version = "0.3.7"
3432
+ version = "0.3.9"
3415
3433
  dependencies = [
3416
3434
  "anyhow",
3417
3435
  "fast-uuid-v7",
@@ -3425,12 +3443,13 @@ dependencies = [
3425
3443
 
3426
3444
  [[package]]
3427
3445
  name = "mq-bridge-node"
3428
- version = "0.3.7"
3446
+ version = "0.3.9"
3429
3447
  dependencies = [
3430
3448
  "anyhow",
3431
3449
  "async-trait",
3432
3450
  "bytes",
3433
3451
  "fast-uuid-v7",
3452
+ "mimalloc",
3434
3453
  "mq-bridge",
3435
3454
  "mq-bridge-bindings-common",
3436
3455
  "napi",
@@ -3446,12 +3465,13 @@ dependencies = [
3446
3465
 
3447
3466
  [[package]]
3448
3467
  name = "mq-bridge-py"
3449
- version = "0.3.7"
3468
+ version = "0.3.9"
3450
3469
  dependencies = [
3451
3470
  "anyhow",
3452
3471
  "async-trait",
3453
3472
  "bytes",
3454
3473
  "fast-uuid-v7",
3474
+ "mimalloc",
3455
3475
  "mq-bridge",
3456
3476
  "mq-bridge-bindings-common",
3457
3477
  "pyo3",
@@ -3725,9 +3745,9 @@ dependencies = [
3725
3745
 
3726
3746
  [[package]]
3727
3747
  name = "omq-proto"
3728
- version = "0.24.1"
3748
+ version = "0.25.0"
3729
3749
  source = "registry+https://github.com/rust-lang/crates.io-index"
3730
- checksum = "c9335ef21d570294464c491837af5477caddb05cf3c7223af1c4341a127e6035"
3750
+ checksum = "856d18f6b58f39153fcf0b574efe3f04362ff44d3a46829eb984c1f9ef2d121c"
3731
3751
  dependencies = [
3732
3752
  "bytes",
3733
3753
  "patricia_tree",
@@ -3739,9 +3759,9 @@ dependencies = [
3739
3759
 
3740
3760
  [[package]]
3741
3761
  name = "omq-tokio"
3742
- version = "0.20.1"
3762
+ version = "0.20.3"
3743
3763
  source = "registry+https://github.com/rust-lang/crates.io-index"
3744
- checksum = "4a9d9c6caa88d29df5b9dc9638ea9f0f33b087ecc0f149b70e61149f97bcdb80"
3764
+ checksum = "98aaa33702e7d723de268dd9fe725f93d469afef3f1bedb14cfa7f579f61a7b7"
3745
3765
  dependencies = [
3746
3766
  "arc-swap",
3747
3767
  "bytes",
@@ -7191,9 +7211,9 @@ dependencies = [
7191
7211
 
7192
7212
  [[package]]
7193
7213
  name = "yring"
7194
- version = "0.3.10"
7214
+ version = "0.3.11"
7195
7215
  source = "registry+https://github.com/rust-lang/crates.io-index"
7196
- checksum = "39146d2147cfb9f71b9f071f93f7b5dbcfb28eee528dafcaf5f500f4917cb69f"
7216
+ checksum = "f8545becda6379f37e13fbdf5d9de464849bdd1565a995368648f11fe9d96d13"
7197
7217
  dependencies = [
7198
7218
  "loom",
7199
7219
  ]
@@ -16,7 +16,7 @@ members = ["bindings-common", "python/mq-bridge-py"]
16
16
  resolver = "2"
17
17
 
18
18
  [workspace.package]
19
- version = "0.3.7"
19
+ version = "0.3.9"
20
20
 
21
21
  [workspace.dependencies]
22
22
  anyhow = "1.0"
@@ -210,7 +210,7 @@ float-roundtrip = ["serde_json/float_roundtrip"]
210
210
  # runtime the client is loaded lazily only when an ibm-mq endpoint is opened
211
211
  # (clear error if the client isn't installed). Use `ibm-mq-static` instead for
212
212
  # static linking.
213
- full = ["middleware", "mongodb", "kafka", "amqp", "nats", "mqtt", "http", "aws", "zeromq", "redis-streams", "sled", "grpc", "sqlx", "clickhouse", "websocket", "postgres-cdc", "object-store", "rustls-aws-lc", "ibm-mq"]
213
+ full = ["middleware", "mongodb", "kafka", "amqp", "nats", "mqtt", "http", "aws", "zeromq", "zeromq-omq", "redis-streams", "sled", "grpc", "sqlx", "clickhouse", "websocket", "postgres-cdc", "object-store", "rustls-aws-lc", "ibm-mq"]
214
214
 
215
215
  # Endpoints that build across most OS targets (glibc/musl/Alpine, macOS,
216
216
  # Windows, aarch64/armv7) without a special toolchain — no librdkafka, protoc,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mq-bridge-py-basic
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: License :: OSI Approved :: MIT License
6
6
  Classifier: Programming Language :: Python :: 3
@@ -33,7 +33,7 @@ If you need to move data reliably between systems and you write code (Rust, Pyth
33
33
  * **TLS everywhere, one config shape**: a single `TlsConfig` block (CA bundle, client cert/key for mTLS, insecure-skip) is reused across transports.
34
34
  * **Self-hosted, no daemon**: generate config in the optional UI, paste it into your code, run it in-process. No hosted control plane, no separate scheduler.
35
35
 
36
- > **Throughput & footprint.** In our own benchmarks, the same engine — driven the zero-code way through [`mq-bridge-app`](https://github.com/marcomq/mq-bridge-app) — sustained ~267,000 rows/s copying 1,000,000 rows from Postgres to JSONL on commodity hardware at **~20 MiB peak RSS**, keeping it well in the range of dedicated data-movement tools. On a CSV→JSONL file conversion (1,000,000 mixed-type rows, ~116 MiB), it sustained **833,333 rows/s** at the same ~20 MiB, about **~43x faster** and **~22x leaner in memory** than Meltano (`tap-csv` → `target-jsonl`, ~19,500 rows/s / ~444 MiB). Full setup, methodology, and the exact parameters are in [`benches/ETL_BENCHMARKS.md`](benches/ETL_BENCHMARKS.md).
36
+ > **Throughput & footprint.** In our own benchmarks, the same engine — driven the zero-code way through [`mq-bridge-app`](https://github.com/marcomq/mq-bridge-app) — on a CSV→JSONL file conversion (1,000,000 mixed-type rows, ~116 MiB) sustained **1,133,786 rows/s** at ~22 MiB, about **~58x faster** and **~20x leaner in memory** than Meltano (`tap-csv` → `target-jsonl`, ~19,500 rows/s / ~444 MiB). Full setup, methodology, and the exact parameters are in [`benches/ETL_BENCHMARKS.md`](benches/ETL_BENCHMARKS.md).
37
37
 
38
38
 
39
39
  ## Language Bindings
@@ -306,9 +306,14 @@ server-side (default one-hour window) — `insert_deduplication_token` lets you
306
306
  mq-bridge does not set one, so rely on `ReplacingMergeTree` for logical dedup and treat block-level
307
307
  dedup only as retry-safety.
308
308
 
309
- **Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source already resumes from a
310
- durable LSN checkpoint (no re-delivery on clean restart). For the crash window (row written, then a
311
- crash before the checkpoint flush) it is at-least-once, so make the sink idempotent. Each change event
309
+ **Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source resumes from the slot's
310
+ durable `confirmed_flush_lsn`. In-band standby feedback is asynchronous and is *not* flushed when the
311
+ stream stops, so the last acks are made durable by the consumer's `Drop`, which stops the stream and
312
+ advances the slot synchronously. Re-delivery is therefore avoided only on a restart that actually runs
313
+ that teardown — a host process that exits without dropping the route (or one on a current-thread Tokio
314
+ runtime, where the blocking advance is skipped) replays everything since the last asynchronous feedback
315
+ tick. Set `checkpoint_store` to a `file://` path for a second, per-ack durable position that survives
316
+ teardown regardless. Treat the source as at-least-once and make the sink idempotent. Each change event
312
317
  carries the full row (so the primary key is in the payload), `postgres.lsn` (a monotonic version),
313
318
  `postgres.operation`/`schema`/`table`, and — when the table has a primary key / replica identity —
314
319
  `postgres.key` (the key value). The event's `message_id` is a stable hash of `schema.table + key +
@@ -17,7 +17,7 @@ endpoints, shape routing, or terminate a request. Data endpoints (`kafka`, `nats
17
17
  Middleware attaches to an endpoint via a `middlewares:` list, on the **input**, the
18
18
  **output**, or both:
19
19
 
20
- ```yaml
20
+ ```yaml route
21
21
  my_route:
22
22
  input:
23
23
  middlewares:
@@ -38,6 +38,11 @@ layer and sees the failures of the ones before it.** Put `dlq` last.
38
38
  **Input (consumer) middlewares are applied in reverse, so the *first* entry is outermost**
39
39
  and runs first on an incoming message.
40
40
 
41
+ **Consequence: a route that reads back what another route wrote needs the *reversed* list.**
42
+ Writing with `[compression, encryption]` produces `compress(encrypt(payload))`; a reader
43
+ given that same list would try to decrypt first and fail. The reading route must say
44
+ `[encryption, compression]`. The lists mirror — they are not copied.
45
+
41
46
  > This is asserted by `route::tests::test_dlq_and_retry_batch_integration`,
42
47
  > `middleware::transform::tests::test_rejected_message_reaches_the_dlq_through_the_config_wiring`,
43
48
  > and `reference_docs_test::publisher_middleware_wraps_last_entry_outermost`, and is
@@ -58,17 +63,28 @@ middlewares:
58
63
  | [`retry`](#retry) | – | ✅ | – | Exponential-backoff retry of failed sends |
59
64
  | [`dlq`](#dlq) | – | ✅ | – | Route permanently-failed messages to another endpoint |
60
65
  | [`transform`](#transform) | ✅ | ✅ | – | Declarative JSON mapping, coercion, validation |
61
- | [`deduplication`](#deduplication) | ✅ | – | `dedup` | Drop repeated message IDs within a TTL |
66
+ | [`deduplication`](#deduplication) | ✅ | – | `dedup` | Drop repeated keys within a TTL |
62
67
  | [`weak_join`](#weak_join) | ✅ | – | – | Correlate and join related messages |
63
68
  | [`buffer`](#buffer) | ✅ | ✅ | – | Coalesce single sends into batches |
64
69
  | [`limiter`](#limiter) | ✅ | ✅ | – | Cap throughput to a message rate |
65
70
  | [`delay`](#delay) | ✅ | ✅ | – | Fixed delay per receive/send |
66
71
  | [`cookie_jar`](#cookie_jar) | ✅ | ✅ | – | Persist HTTP cookies / session values across messages |
67
72
  | [`encryption`](#encryption) | ✅ | ✅ | `encryption` | AEAD-encrypt payloads on send, decrypt on receive |
73
+ | [`compression`](#compression) | ✅ | ✅ | `compression` | Compress payloads on send, decompress on receive |
68
74
  | [`metrics`](#metrics) | ✅ | ✅ | `metrics` | Emit throughput/latency/error metrics |
69
75
  | [`random_panic`](#random_panic) | ✅ | ✅ | – | Fault injection for testing |
70
76
  | [`custom`](#custom-middleware) | ✅ | ✅ | – | Your own middleware via a registered factory |
71
77
 
78
+ > **Two kinds of compression.** The [`compression`](#compression) *middleware* compresses
79
+ > each message **payload** on any transport and decompresses it on the far side. Separately,
80
+ > the batch `compression` *field* on the `file` and `object_store` endpoints (`none` / `gzip`
81
+ > / `lz4` / `zstd`, same `compression` feature) compresses whole write batches so the file
82
+ > stays decodable with `zcat` / `lz4 -d`. Use the field for CLI-readable data at rest, the
83
+ > middleware for over-the-wire payloads. Don't stack either compression with the
84
+ > [`encryption`](#encryption) middleware on the same route — ciphertext does not compress; for
85
+ > compressed-and-encrypted data at rest use the endpoints' own `compression`/`encryption`
86
+ > fields (compress-then-encrypt per batch).
87
+
72
88
  **Putting a middleware on the wrong side behaves in two different ways**, so check the table
73
89
  above rather than assuming:
74
90
 
@@ -92,7 +108,7 @@ Retries failed sends with exponential backoff. Output only.
92
108
  | `max_interval_ms` | integer | `5000` |
93
109
  | `multiplier` | float | `2.0` |
94
110
 
95
- ```yaml
111
+ ```yaml middleware
96
112
  - retry: { max_attempts: 5, initial_interval_ms: 200, max_interval_ms: 10000, multiplier: 2.0 }
97
113
  ```
98
114
 
@@ -108,7 +124,7 @@ Sends permanently-failed messages to a separate endpoint instead of failing the
108
124
  |---|---|---|
109
125
  | `endpoint` | Endpoint | yes |
110
126
 
111
- ```yaml
127
+ ```yaml middleware
112
128
  - dlq:
113
129
  endpoint:
114
130
  file: { path: "dead-letters.jsonl" }
@@ -150,7 +166,7 @@ validation — over a single parse. Input and output.
150
166
  `schema` and `schema_file` are mutually exclusive. A mapping rule is either a bare path
151
167
  string or `{ path, default, required }`.
152
168
 
153
- ```yaml
169
+ ```yaml middleware
154
170
  - transform:
155
171
  mapping:
156
172
  firstName: "$.first_name"
@@ -174,7 +190,7 @@ lossless ones: `string → integer`, `string → number`, `string → boolean` (
174
190
  A field carrying a JSON document as a string is decoded by `contentMediaType`, following
175
191
  JSON Schema 2020-12:
176
192
 
177
- ```yaml
193
+ ```yaml middleware
178
194
  - transform:
179
195
  schema:
180
196
  type: object
@@ -216,7 +232,7 @@ with neither stage configured leaves the payload untouched without parsing it.
216
232
 
217
233
  ### `deduplication`
218
234
 
219
- Drops messages whose ID was already seen within the TTL. Input only. Requires the `dedup`
235
+ Drops messages whose key was already seen within the TTL. Input only. Requires the `dedup`
220
236
  feature (pulls `sled`).
221
237
 
222
238
  | Field | Type | Required |
@@ -224,13 +240,22 @@ feature (pulls `sled`).
224
240
  | `store` | string | one of `store`/`sled_path` |
225
241
  | `sled_path` | string | one of `store`/`sled_path` |
226
242
  | `ttl_seconds` | integer | yes |
243
+ | `key` | string | no (defaults to `message_id`) |
244
+
245
+ `key` is an interpolation template (see `${namespace:selector}`), typically
246
+ `"${payload:order_id}"`. Without it the key is the `message_id`, which most sources
247
+ regenerate on every read — so re-reading the same source deduplicates nothing and only
248
+ in-flight redeliveries are suppressed. Set `key` to a business key whenever you need
249
+ dedup to survive a re-read.
227
250
 
228
251
  `store` selects the backend by URL scheme:
229
252
 
230
253
  - `sled:///path` (or a bare path) — a local sled database; per-process, not cluster-wide.
231
254
  - `mongodb://host/db[/collection]` — a shared collection, so multiple instances of a route
232
- deduplicate against one another. Requires the `mongodb` feature. Entries expire via a
233
- MongoDB TTL index; the collection defaults to `mqb_dedup_<route>`. Point it at the same
255
+ deduplicate against one another. Requires the `mongodb` feature. Expiry is judged on read,
256
+ so a `ttl_seconds` boundary is honoured exactly; the TTL index only reclaims space
257
+ afterwards (MongoDB's sweep can lag by up to a minute). The collection defaults to
258
+ `mqb_dedup_<route>`. Point it at the same
234
259
  deployment your sink already uses to avoid running extra infrastructure.
235
260
  - `postgres|mysql|mariadb|sqlite://…[/table]` — a shared SQL table (`dedup_key` PK,
236
261
  `expire_at`), so multiple instances deduplicate against one another. Requires the `sqlx`
@@ -239,18 +264,22 @@ feature (pulls `sled`).
239
264
 
240
265
  `sled_path` is the legacy spelling of a local sled store and is equivalent to `store: "sled://<path>"`.
241
266
 
242
- ```yaml
267
+ ```yaml middleware
243
268
  - deduplication: { store: "sled:///var/lib/mq-bridge/dedup", ttl_seconds: 3600 }
244
269
  ```
245
270
 
246
- ```yaml
271
+ ```yaml middleware
247
272
  - deduplication: { store: "mongodb://localhost:27017/etl", ttl_seconds: 3600 }
248
273
  ```
249
274
 
250
- ```yaml
275
+ ```yaml middleware
251
276
  - deduplication: { store: "postgres://user:pass@localhost/etl", ttl_seconds: 3600 }
252
277
  ```
253
278
 
279
+ ```yaml middleware
280
+ - deduplication: { store: "sled:///var/lib/mq-bridge/dedup", ttl_seconds: 3600, key: "${payload:order_id}" }
281
+ ```
282
+
254
283
  When MongoDB is your sink and messages carry a business key, prefer the sink's own unique
255
284
  index (`id_field` on the mongodb output) over this middleware — the target collection then
256
285
  *is* the deduplication authority, with no second write. See the idempotency notes in README.
@@ -268,7 +297,7 @@ Correlates messages by a metadata key and emits them as one joined message. Inpu
268
297
  | `required` | list of branch names | `[]` |
269
298
  | `on_timeout` | `fire` \| `discard` | `fire` |
270
299
 
271
- ```yaml
300
+ ```yaml middleware
272
301
  # Count mode: wait for any 3 messages sharing a correlation_id, emit a JSON array.
273
302
  - weak_join: { group_by: "correlation_id", expected_count: 3, timeout_ms: 5000 }
274
303
 
@@ -296,7 +325,7 @@ Accumulates single sends and forwards them as one batch. Input and output.
296
325
  | `max_messages` | integer | yes |
297
326
  | `max_delay_ms` | integer | yes |
298
327
 
299
- ```yaml
328
+ ```yaml middleware
300
329
  - buffer: { max_messages: 500, max_delay_ms: 20 }
301
330
  ```
302
331
 
@@ -311,7 +340,7 @@ Paces throughput to a target rate. Input and output.
311
340
  |---|---|---|
312
341
  | `messages_per_second` | float (> 0) | yes |
313
342
 
314
- ```yaml
343
+ ```yaml middleware
315
344
  - limiter: { messages_per_second: 250 }
316
345
  ```
317
346
 
@@ -325,7 +354,7 @@ Sleeps a fixed duration before each receive or send. Input and output.
325
354
  |---|---|---|
326
355
  | `delay_ms` | integer | yes |
327
356
 
328
- ```yaml
357
+ ```yaml middleware
329
358
  - delay: { delay_ms: 100 }
330
359
  ```
331
360
 
@@ -345,7 +374,7 @@ Persists HTTP cookies and arbitrary session values across messages. Input and ou
345
374
  | `export_metadata_prefix` | string | – |
346
375
  | `inject_metadata` | map string→string | `{}` |
347
376
 
348
- ```yaml
377
+ ```yaml middleware
349
378
  - cookie_jar:
350
379
  shared_scope: "login-session"
351
380
  capture_metadata_keys: ["x-csrf-token"]
@@ -369,7 +398,7 @@ output. Requires the `encryption` feature.
369
398
  | `key` | string — base64-encoded 32-byte key; `${env:VAR}` reads it from the environment | required |
370
399
  | `decrypt_keys` | map key_id → key | `{}` |
371
400
 
372
- ```yaml
401
+ ```yaml middleware
373
402
  - encryption: { key: "${env:MQB_ENC_KEY}" }
374
403
  ```
375
404
 
@@ -391,7 +420,7 @@ Do **not** combine this middleware with a sink's batch `compression` on the same
391
420
  ciphertext does not compress. For compressed *and* encrypted data at rest, use the `file` /
392
421
  `object_store` endpoints' own fields instead, which apply compress-then-encrypt per batch:
393
422
 
394
- ```yaml
423
+ ```yaml endpoint
395
424
  output:
396
425
  file:
397
426
  path: "data.enc"
@@ -421,12 +450,39 @@ sniffing the leading magic bytes, so raw compressed bytes are never emitted as m
421
450
  > `double precision` column can change the last bit. Build with the `float-roundtrip` feature
422
451
  > for bit-exact float parsing across every endpoint (it trades a little parse speed for it).
423
452
 
453
+ ### `compression`
454
+
455
+ Compresses each message **payload** on the output side and decompresses it on the input
456
+ side. Metadata and routing keys are untouched. Input and output. Requires the `compression`
457
+ feature.
458
+
459
+ | Field | Type | Default |
460
+ |---|---|---|
461
+ | `algorithm` | `none` \| `gzip` \| `lz4` \| `zstd` | `zstd` |
462
+ | `max_decompressed_bytes` | integer — reject a payload that decompresses larger than this (bomb guard); consumer side only | unset (no limit) |
463
+
464
+ ```yaml middleware
465
+ - compression: { algorithm: zstd }
466
+ ```
467
+
468
+ Each payload is compressed independently into a single self-contained member, so this works
469
+ over any transport, not just files. `algorithm: none` is a passthrough. A truncated or
470
+ corrupt frame is a **permanent** consumer error (the poison message is not re-read
471
+ indefinitely), as is a payload that exceeds `max_decompressed_bytes`. Put the same
472
+ `algorithm` on both the input and output side of a route.
473
+
474
+ Unlike the `file` / `object_store` batch `compression` field — which keeps whole write
475
+ batches decodable with `zcat` / `lz4 -d` — this middleware frames per message and is only
476
+ readable through a matching consumer. Do not combine it with the [`encryption`](#encryption)
477
+ middleware (ciphertext does not compress); for compressed-and-encrypted data at rest, use the
478
+ endpoints' own `compression`/`encryption` fields instead.
479
+
424
480
  ### `metrics`
425
481
 
426
482
  Emits throughput, latency and error metrics for the endpoint. Input and output. Requires the
427
483
  `metrics` feature. Takes no options; its presence enables collection.
428
484
 
429
- ```yaml
485
+ ```yaml middleware
430
486
  - metrics: {}
431
487
  ```
432
488
 
@@ -442,7 +498,7 @@ Deliberate fault injection for testing recovery paths. Input and output.
442
498
  | `trigger_on_message` | integer (1-indexed) | – (every message) |
443
499
  | `enabled` | bool | `true` |
444
500
 
445
- ```yaml
501
+ ```yaml middleware
446
502
  - random_panic: { mode: disconnect, trigger_on_message: 500 }
447
503
  ```
448
504
 
@@ -450,6 +506,24 @@ Deliberate fault injection for testing recovery paths. Input and output.
450
506
  non-retryable one — useful for exercising a `dlq`. Keep `enabled: false` in committed configs
451
507
  rather than deleting the block.
452
508
 
509
+ The middleware block alone is **not** enough: fault injection is gated per route by
510
+ `allow_fault_injection`, which defaults to `false`. Copying only the snippet above leaves the
511
+ middleware inert (the route logs that it is disabled). A complete, working configuration:
512
+
513
+ ```yaml route
514
+ flaky_test_route:
515
+ allow_fault_injection: true
516
+ input:
517
+ memory: { topic: "in" }
518
+ middlewares:
519
+ - random_panic: { mode: disconnect, trigger_on_message: 500 }
520
+ output:
521
+ memory: { topic: "out" }
522
+ ```
523
+
524
+ `allow_fault_injection: true` is intended for test configurations only. Do not enable it — or
525
+ the `random_panic` middleware — in production configs.
526
+
453
527
  ### `custom` (middleware)
454
528
 
455
529
  Delegates to a factory you registered programmatically.
@@ -459,7 +533,7 @@ Delegates to a factory you registered programmatically.
459
533
  | `name` | string | yes |
460
534
  | `config` | any JSON | yes |
461
535
 
462
- ```yaml
536
+ ```yaml middleware
463
537
  - custom:
464
538
  name: "my_enricher"
465
539
  config: { lookup_url: "http://enrich.internal" }
@@ -507,7 +581,7 @@ use mq_bridge::route::register_endpoint;
507
581
  register_endpoint("common_queue", Endpoint::new_memory("shared_memory_topic", 100));
508
582
  ```
509
583
 
510
- ```yaml
584
+ ```yaml route
511
585
  enrich:
512
586
  input: { ref: "common_queue" }
513
587
  output: { nats: { subject: "enriched", url: "nats://localhost:4222" } }
@@ -526,7 +600,7 @@ nesting depth is bounded.
526
600
 
527
601
  Publishes each message to every listed endpoint. Output only.
528
602
 
529
- ```yaml
603
+ ```yaml endpoint
530
604
  output:
531
605
  fanout:
532
606
  - kafka: { topic: "audit", url: "localhost:9092" }
@@ -547,7 +621,7 @@ Content-based routing: picks a destination by the value of a **metadata key**.
547
621
  | `cases` | map value → Endpoint | yes |
548
622
  | `default` | Endpoint | no |
549
623
 
550
- ```yaml
624
+ ```yaml endpoint
551
625
  output:
552
626
  switch:
553
627
  metadata_key: "http_status_code"
@@ -573,7 +647,7 @@ turning a request/reply exchange into a one-way flow.
573
647
  | `to` | Endpoint (request-capable) | yes |
574
648
  | `forward_to` | Endpoint | yes |
575
649
 
576
- ```yaml
650
+ ```yaml endpoint
577
651
  output:
578
652
  request:
579
653
  to: { http: { url: "https://api.internal/score" } }
@@ -590,7 +664,7 @@ status key such as `http_status_code`.
590
664
  Replies to the origin of the current request. Output only, and the recommended way to build
591
665
  request/reply routes.
592
666
 
593
- ```yaml
667
+ ```yaml route
594
668
  http_echo:
595
669
  input: { http: { url: "0.0.0.0:8080" } }
596
670
  output: { response: {} }
@@ -606,7 +680,7 @@ pipeline. See [README.md](README.md#patterns-request-response).
606
680
  An output endpoint that **ignores the incoming payload** and instead reads one message from
607
681
  the wrapped consumer, returning it as the response. The inbound message is purely a trigger.
608
682
 
609
- ```yaml
683
+ ```yaml route
610
684
  # HTTP GET pulls the next message off a Kafka topic.
611
685
  poll_api:
612
686
  input: { http: { url: "0.0.0.0:8080", method: "GET" } }
@@ -632,7 +706,7 @@ source).
632
706
 
633
707
  Accepts either a bare string or the full map form:
634
708
 
635
- ```yaml
709
+ ```yaml endpoint
636
710
  output: { static: "OK" } # shorthand, body JSON-encoded
637
711
 
638
712
  output:
@@ -669,7 +743,7 @@ structure — append `| raw` to a token to splice it verbatim. To emit a literal
669
743
  `${…}`, write `$${…}` (a bare `$$` is left as-is); any `${…}` with an unknown namespace is also
670
744
  left untouched.
671
745
 
672
- ```yaml
746
+ ```yaml endpoint
673
747
  output:
674
748
  static:
675
749
  body: '{"error":"not found","id":"${message:id}","at":"${gen:now}"}'
@@ -688,7 +762,7 @@ bodies between routes.
688
762
  | `correlation_id` | string | **required on consumers, must be unset on publishers** |
689
763
  | `capacity` | integer | default `100`, per partition |
690
764
 
691
- ```yaml
765
+ ```yaml endpoint
692
766
  output:
693
767
  stream_buffer: { topic: "responses" } # publisher: no correlation_id
694
768
 
@@ -703,7 +777,7 @@ and ignores it. Primarily wired up via `HttpConfig::stream_response_to`.
703
777
 
704
778
  Discards every message. Output only. This is the **default output** when a route omits one.
705
779
 
706
- ```yaml
780
+ ```yaml route
707
781
  drain:
708
782
  input: { kafka: { topic: "noisy", url: "localhost:9092" } }
709
783
  output: null # a bare YAML null
@@ -724,7 +798,7 @@ Delegates to a factory you registered programmatically.
724
798
  | `name` | string | yes |
725
799
  | `config` | any JSON | yes |
726
800
 
727
- ```yaml
801
+ ```yaml endpoint
728
802
  output:
729
803
  custom:
730
804
  name: "my_sink"
@@ -72,7 +72,7 @@ theirs. The run brief lives in [`mq-bridge-app-benchmark-prompt.md`](mq-bridge-a
72
72
 
73
73
  | Scenario | Payload | Batch | Concurrency | Source → Sink | Result |
74
74
  | --- | --- | --- | --- | --- | --- |
75
- | Bulk-copy throughput | 7-col mixed-type rows, 1,000,000 rows | 1024 | 4 | postgres (keyset cursor) → file (JSONL) | **303,398 rows/s** (3.296 s) |
75
+ | Bulk-copy throughput | 7-col mixed-type rows, 1,000,000 rows | 1024 | 4 | postgres (keyset cursor) → file (JSONL) | **384,615 rows/s** (2.600 s) |
76
76
 
77
77
  Command: `mq-bridge-app copy --from postgres://…?table=…&cursor_column=id --to file://…?format=raw --drain --batch-size 1024 --concurrency 4`, wall-clocked. Requires an index on the cursor column (`CREATE INDEX ON <table>(id)`) — without it the keyset-pagination reader (`WHERE id > $cursor ORDER BY id LIMIT batch`) does a full scan per batch (near-quadratic).
78
78
 
@@ -82,10 +82,10 @@ Same source table (`bench`: 1,000,000 rows, 7 mixed-type columns), same Postgres
82
82
 
83
83
  | Scenario | Payload | Batch | Concurrency | Source → Sink | Throughput | Peak RSS |
84
84
  | --- | --- | --- | --- | --- | --- | --- |
85
- | mq-bridge-app `copy` | 7-col, 1,000,000 rows | 1024 | 1 | postgres (keyset cursor) → file (JSONL) | **266,951 rows/s** | 19.9 MiB |
85
+ | mq-bridge-app `copy` | 7-col, 1,000,000 rows | 1024 | 1 | postgres (keyset cursor) → file (JSONL) | **338,066 rows/s** | 39.8 MiB |
86
86
  | Meltano (`tap-postgres` → `target-jsonl`) | 7-col, 1,000,000 rows | default Singer config | — | postgres → JSONL | 15,356 rows/s | 599.7 MiB |
87
87
 
88
- **~17.4x faster and ~30x leaner in peak memory** than Meltano in this scenario. Full setup (including the Meltano project config) is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#5--postgres--jsonl-vs-meltano-tap-postgres--target-jsonl).
88
+ **~22x faster and ~15x leaner in peak memory** than Meltano in this scenario. Full setup (including the Meltano project config) is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#5--postgres--jsonl-vs-meltano-tap-postgres--target-jsonl).
89
89
 
90
90
  ### Preliminary run — CSV → JSONL vs. Meltano
91
91
 
@@ -93,10 +93,10 @@ Same seeded dataset both sides, same machine, one-shot full-file CSV → local J
93
93
 
94
94
  | Scenario | Payload | Batch | Concurrency | Source → Sink | Throughput | Peak RSS |
95
95
  | --- | --- | --- | --- | --- | --- | --- |
96
- | mq-bridge-app `copy` | 7-col mixed-type, 1,000,000 rows (~116 MiB) | 1024 | 1 | file (CSV) → file (JSONL) | **833,333 rows/s** | 20.0 MiB |
96
+ | mq-bridge-app `copy` | 7-col mixed-type, 1,000,000 rows (~116 MiB) | 1024 | 1 | file (CSV) → file (JSONL) | **1,133,786 rows/s** | 21.9 MiB |
97
97
  | Meltano (`tap-csv` → `target-jsonl`) | 7-col mixed-type, 1,000,000 rows | default Singer config | — | file (CSV) → JSONL | ~19,500 rows/s | 443.8 MiB |
98
98
 
99
- **~43x faster and ~22x leaner in peak memory** than Meltano in this scenario. Full setup is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#6--csv--jsonl-vs-meltano).
99
+ **~58x faster and ~20x leaner in peak memory** than Meltano in this scenario. Full setup is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#6--csv--jsonl-vs-meltano).
100
100
 
101
101
  ## Status
102
102