@dotdo/postgres 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +868 -0
- package/dist/cdc/change-stream.d.ts +44 -0
- package/dist/cdc/change-stream.d.ts.map +1 -0
- package/dist/cdc/change-stream.js +95 -0
- package/dist/cdc/change-stream.js.map +1 -0
- package/dist/cdc/filter.d.ts +58 -0
- package/dist/cdc/filter.d.ts.map +1 -0
- package/dist/cdc/filter.js +520 -0
- package/dist/cdc/filter.js.map +1 -0
- package/dist/cdc/index.d.ts +47 -0
- package/dist/cdc/index.d.ts.map +1 -0
- package/dist/cdc/index.js +50 -0
- package/dist/cdc/index.js.map +1 -0
- package/dist/cdc/resume-token.d.ts +60 -0
- package/dist/cdc/resume-token.d.ts.map +1 -0
- package/dist/cdc/resume-token.js +228 -0
- package/dist/cdc/resume-token.js.map +1 -0
- package/dist/cdc/transport/index.d.ts +7 -0
- package/dist/cdc/transport/index.d.ts.map +1 -0
- package/dist/cdc/transport/index.js +7 -0
- package/dist/cdc/transport/index.js.map +1 -0
- package/dist/cdc/transport/sse.d.ts +120 -0
- package/dist/cdc/transport/sse.d.ts.map +1 -0
- package/dist/cdc/transport/sse.js +590 -0
- package/dist/cdc/transport/sse.js.map +1 -0
- package/dist/cdc/transport/websocket.d.ts +130 -0
- package/dist/cdc/transport/websocket.d.ts.map +1 -0
- package/dist/cdc/transport/websocket.js +688 -0
- package/dist/cdc/transport/websocket.js.map +1 -0
- package/dist/cdc/types.d.ts +306 -0
- package/dist/cdc/types.d.ts.map +1 -0
- package/dist/cdc/types.js +8 -0
- package/dist/cdc/types.js.map +1 -0
- package/dist/config/index.d.ts +25 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +25 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/memory.d.ts +139 -0
- package/dist/config/memory.d.ts.map +1 -0
- package/dist/config/memory.js +157 -0
- package/dist/config/memory.js.map +1 -0
- package/dist/config/storage.d.ts +157 -0
- package/dist/config/storage.d.ts.map +1 -0
- package/dist/config/storage.js +178 -0
- package/dist/config/storage.js.map +1 -0
- package/dist/config/streaming.d.ts +117 -0
- package/dist/config/streaming.d.ts.map +1 -0
- package/dist/config/streaming.js +132 -0
- package/dist/config/streaming.js.map +1 -0
- package/dist/config/timeouts.d.ts +168 -0
- package/dist/config/timeouts.d.ts.map +1 -0
- package/dist/config/timeouts.js +192 -0
- package/dist/config/timeouts.js.map +1 -0
- package/dist/extensions/config.d.ts +89 -0
- package/dist/extensions/config.d.ts.map +1 -0
- package/dist/extensions/config.js +216 -0
- package/dist/extensions/config.js.map +1 -0
- package/dist/extensions/geo.d.ts +452 -0
- package/dist/extensions/geo.d.ts.map +1 -0
- package/dist/extensions/geo.js +583 -0
- package/dist/extensions/geo.js.map +1 -0
- package/dist/extensions/index.d.ts +167 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +99 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/loader.d.ts +226 -0
- package/dist/extensions/loader.d.ts.map +1 -0
- package/dist/extensions/loader.js +456 -0
- package/dist/extensions/loader.js.map +1 -0
- package/dist/extensions/pgmq-lite.d.ts +330 -0
- package/dist/extensions/pgmq-lite.d.ts.map +1 -0
- package/dist/extensions/pgmq-lite.js +648 -0
- package/dist/extensions/pgmq-lite.js.map +1 -0
- package/dist/extensions/plugins.d.ts +260 -0
- package/dist/extensions/plugins.d.ts.map +1 -0
- package/dist/extensions/plugins.js +535 -0
- package/dist/extensions/plugins.js.map +1 -0
- package/dist/extensions/registry.d.ts +93 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/extensions/registry.js +182 -0
- package/dist/extensions/registry.js.map +1 -0
- package/dist/extensions/vector.d.ts +106 -0
- package/dist/extensions/vector.d.ts.map +1 -0
- package/dist/extensions/vector.js +129 -0
- package/dist/extensions/vector.js.map +1 -0
- package/dist/iceberg/analytics.d.ts +279 -0
- package/dist/iceberg/analytics.d.ts.map +1 -0
- package/dist/iceberg/analytics.js +448 -0
- package/dist/iceberg/analytics.js.map +1 -0
- package/dist/iceberg/catalog-api.d.ts +39 -0
- package/dist/iceberg/catalog-api.d.ts.map +1 -0
- package/dist/iceberg/catalog-api.js +388 -0
- package/dist/iceberg/catalog-api.js.map +1 -0
- package/dist/iceberg/catalog.d.ts +401 -0
- package/dist/iceberg/catalog.d.ts.map +1 -0
- package/dist/iceberg/catalog.js +677 -0
- package/dist/iceberg/catalog.js.map +1 -0
- package/dist/iceberg/duckdb-wasm.d.ts +447 -0
- package/dist/iceberg/duckdb-wasm.d.ts.map +1 -0
- package/dist/iceberg/duckdb-wasm.js +600 -0
- package/dist/iceberg/duckdb-wasm.js.map +1 -0
- package/dist/iceberg/index.d.ts +92 -0
- package/dist/iceberg/index.d.ts.map +1 -0
- package/dist/iceberg/index.js +119 -0
- package/dist/iceberg/index.js.map +1 -0
- package/dist/iceberg/metadata.d.ts +214 -0
- package/dist/iceberg/metadata.d.ts.map +1 -0
- package/dist/iceberg/metadata.js +535 -0
- package/dist/iceberg/metadata.js.map +1 -0
- package/dist/iceberg/optimizer.d.ts +296 -0
- package/dist/iceberg/optimizer.d.ts.map +1 -0
- package/dist/iceberg/optimizer.js +889 -0
- package/dist/iceberg/optimizer.js.map +1 -0
- package/dist/iceberg/parquet.d.ts +447 -0
- package/dist/iceberg/parquet.d.ts.map +1 -0
- package/dist/iceberg/parquet.js +1225 -0
- package/dist/iceberg/parquet.js.map +1 -0
- package/dist/iceberg/r2-organization.d.ts +422 -0
- package/dist/iceberg/r2-organization.d.ts.map +1 -0
- package/dist/iceberg/r2-organization.js +672 -0
- package/dist/iceberg/r2-organization.js.map +1 -0
- package/dist/iceberg/scheduler-do-example.d.ts +158 -0
- package/dist/iceberg/scheduler-do-example.d.ts.map +1 -0
- package/dist/iceberg/scheduler-do-example.js +261 -0
- package/dist/iceberg/scheduler-do-example.js.map +1 -0
- package/dist/iceberg/scheduler.d.ts +434 -0
- package/dist/iceberg/scheduler.d.ts.map +1 -0
- package/dist/iceberg/scheduler.js +818 -0
- package/dist/iceberg/scheduler.js.map +1 -0
- package/dist/iceberg/schema.d.ts +149 -0
- package/dist/iceberg/schema.d.ts.map +1 -0
- package/dist/iceberg/schema.js +525 -0
- package/dist/iceberg/schema.js.map +1 -0
- package/dist/iceberg/snapshot-manager.d.ts +406 -0
- package/dist/iceberg/snapshot-manager.d.ts.map +1 -0
- package/dist/iceberg/snapshot-manager.js +934 -0
- package/dist/iceberg/snapshot-manager.js.map +1 -0
- package/dist/iceberg/sql-router.d.ts +194 -0
- package/dist/iceberg/sql-router.d.ts.map +1 -0
- package/dist/iceberg/sql-router.js +180 -0
- package/dist/iceberg/sql-router.js.map +1 -0
- package/dist/iceberg/test-fixtures.d.ts +151 -0
- package/dist/iceberg/test-fixtures.d.ts.map +1 -0
- package/dist/iceberg/test-fixtures.js +446 -0
- package/dist/iceberg/test-fixtures.js.map +1 -0
- package/dist/iceberg/time-travel-api.d.ts +102 -0
- package/dist/iceberg/time-travel-api.d.ts.map +1 -0
- package/dist/iceberg/time-travel-api.js +437 -0
- package/dist/iceberg/time-travel-api.js.map +1 -0
- package/dist/iceberg/time-travel.d.ts +293 -0
- package/dist/iceberg/time-travel.d.ts.map +1 -0
- package/dist/iceberg/time-travel.js +689 -0
- package/dist/iceberg/time-travel.js.map +1 -0
- package/dist/iceberg/transformer.d.ts +356 -0
- package/dist/iceberg/transformer.d.ts.map +1 -0
- package/dist/iceberg/transformer.js +770 -0
- package/dist/iceberg/transformer.js.map +1 -0
- package/dist/iceberg/types.d.ts +318 -0
- package/dist/iceberg/types.d.ts.map +1 -0
- package/dist/iceberg/types.js +9 -0
- package/dist/iceberg/types.js.map +1 -0
- package/dist/iceberg/writer.d.ts +144 -0
- package/dist/iceberg/writer.d.ts.map +1 -0
- package/dist/iceberg/writer.js +452 -0
- package/dist/iceberg/writer.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/lineage/index.d.ts +11 -0
- package/dist/lineage/index.d.ts.map +1 -0
- package/dist/lineage/index.js +11 -0
- package/dist/lineage/index.js.map +1 -0
- package/dist/lineage/integration.d.ts +134 -0
- package/dist/lineage/integration.d.ts.map +1 -0
- package/dist/lineage/integration.js +258 -0
- package/dist/lineage/integration.js.map +1 -0
- package/dist/lineage/tracker.d.ts +189 -0
- package/dist/lineage/tracker.d.ts.map +1 -0
- package/dist/lineage/tracker.js +1352 -0
- package/dist/lineage/tracker.js.map +1 -0
- package/dist/lineage/types.d.ts +318 -0
- package/dist/lineage/types.d.ts.map +1 -0
- package/dist/lineage/types.js +9 -0
- package/dist/lineage/types.js.map +1 -0
- package/dist/middleware/index.d.ts +11 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +16 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/rate-limit.d.ts +397 -0
- package/dist/middleware/rate-limit.d.ts.map +1 -0
- package/dist/middleware/rate-limit.js +507 -0
- package/dist/middleware/rate-limit.js.map +1 -0
- package/dist/migration-tooling/external-migration.d.ts +601 -0
- package/dist/migration-tooling/external-migration.d.ts.map +1 -0
- package/dist/migration-tooling/external-migration.js +1612 -0
- package/dist/migration-tooling/external-migration.js.map +1 -0
- package/dist/migration-tooling/index.d.ts +19 -0
- package/dist/migration-tooling/index.d.ts.map +1 -0
- package/dist/migration-tooling/index.js +19 -0
- package/dist/migration-tooling/index.js.map +1 -0
- package/dist/migrations/auto-migrator.d.ts +289 -0
- package/dist/migrations/auto-migrator.d.ts.map +1 -0
- package/dist/migrations/auto-migrator.js +396 -0
- package/dist/migrations/auto-migrator.js.map +1 -0
- package/dist/migrations/bulk-orchestrator.d.ts +403 -0
- package/dist/migrations/bulk-orchestrator.d.ts.map +1 -0
- package/dist/migrations/bulk-orchestrator.js +646 -0
- package/dist/migrations/bulk-orchestrator.js.map +1 -0
- package/dist/migrations/compatibility.d.ts +216 -0
- package/dist/migrations/compatibility.d.ts.map +1 -0
- package/dist/migrations/compatibility.js +651 -0
- package/dist/migrations/compatibility.js.map +1 -0
- package/dist/migrations/do-migrations.d.ts +101 -0
- package/dist/migrations/do-migrations.d.ts.map +1 -0
- package/dist/migrations/do-migrations.js +1060 -0
- package/dist/migrations/do-migrations.js.map +1 -0
- package/dist/migrations/do-migrations.types.d.ts +550 -0
- package/dist/migrations/do-migrations.types.d.ts.map +1 -0
- package/dist/migrations/do-migrations.types.js +15 -0
- package/dist/migrations/do-migrations.types.js.map +1 -0
- package/dist/migrations/drizzle-compat.d.ts +163 -0
- package/dist/migrations/drizzle-compat.d.ts.map +1 -0
- package/dist/migrations/drizzle-compat.js +273 -0
- package/dist/migrations/drizzle-compat.js.map +1 -0
- package/dist/migrations/index.d.ts +109 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +127 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migration-api.d.ts +161 -0
- package/dist/migrations/migration-api.d.ts.map +1 -0
- package/dist/migrations/migration-api.js +499 -0
- package/dist/migrations/migration-api.js.map +1 -0
- package/dist/migrations/progress-tracker-do.d.ts +195 -0
- package/dist/migrations/progress-tracker-do.d.ts.map +1 -0
- package/dist/migrations/progress-tracker-do.js +339 -0
- package/dist/migrations/progress-tracker-do.js.map +1 -0
- package/dist/migrations/progress-tracker-kv.d.ts +103 -0
- package/dist/migrations/progress-tracker-kv.d.ts.map +1 -0
- package/dist/migrations/progress-tracker-kv.js +231 -0
- package/dist/migrations/progress-tracker-kv.js.map +1 -0
- package/dist/migrations/progress-tracker.d.ts +320 -0
- package/dist/migrations/progress-tracker.d.ts.map +1 -0
- package/dist/migrations/progress-tracker.js +443 -0
- package/dist/migrations/progress-tracker.js.map +1 -0
- package/dist/migrations/registry.d.ts +231 -0
- package/dist/migrations/registry.d.ts.map +1 -0
- package/dist/migrations/registry.js +376 -0
- package/dist/migrations/registry.js.map +1 -0
- package/dist/migrations/runner.d.ts +197 -0
- package/dist/migrations/runner.d.ts.map +1 -0
- package/dist/migrations/runner.js +1167 -0
- package/dist/migrations/runner.js.map +1 -0
- package/dist/migrations/schema-generator.d.ts +111 -0
- package/dist/migrations/schema-generator.d.ts.map +1 -0
- package/dist/migrations/schema-generator.js +335 -0
- package/dist/migrations/schema-generator.js.map +1 -0
- package/dist/migrations/testing.d.ts +321 -0
- package/dist/migrations/testing.d.ts.map +1 -0
- package/dist/migrations/testing.js +645 -0
- package/dist/migrations/testing.js.map +1 -0
- package/dist/migrations/types.d.ts +503 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +11 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/migrations/validator.d.ts +215 -0
- package/dist/migrations/validator.d.ts.map +1 -0
- package/dist/migrations/validator.js +494 -0
- package/dist/migrations/validator.js.map +1 -0
- package/dist/observability/alerting.d.ts +116 -0
- package/dist/observability/alerting.d.ts.map +1 -0
- package/dist/observability/alerting.js +353 -0
- package/dist/observability/alerting.js.map +1 -0
- package/dist/observability/analytics-engine.d.ts +357 -0
- package/dist/observability/analytics-engine.d.ts.map +1 -0
- package/dist/observability/analytics-engine.js +430 -0
- package/dist/observability/analytics-engine.js.map +1 -0
- package/dist/observability/cost-metrics.d.ts +269 -0
- package/dist/observability/cost-metrics.d.ts.map +1 -0
- package/dist/observability/cost-metrics.js +560 -0
- package/dist/observability/cost-metrics.js.map +1 -0
- package/dist/observability/cross-do-tracing.d.ts +305 -0
- package/dist/observability/cross-do-tracing.d.ts.map +1 -0
- package/dist/observability/cross-do-tracing.js +431 -0
- package/dist/observability/cross-do-tracing.js.map +1 -0
- package/dist/observability/error-rate-collector.d.ts +163 -0
- package/dist/observability/error-rate-collector.d.ts.map +1 -0
- package/dist/observability/error-rate-collector.js +306 -0
- package/dist/observability/error-rate-collector.js.map +1 -0
- package/dist/observability/exporters.d.ts +231 -0
- package/dist/observability/exporters.d.ts.map +1 -0
- package/dist/observability/exporters.js +479 -0
- package/dist/observability/exporters.js.map +1 -0
- package/dist/observability/health-check.d.ts +106 -0
- package/dist/observability/health-check.d.ts.map +1 -0
- package/dist/observability/health-check.js +243 -0
- package/dist/observability/health-check.js.map +1 -0
- package/dist/observability/index.d.ts +297 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +455 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/instrumentation.d.ts +222 -0
- package/dist/observability/instrumentation.d.ts.map +1 -0
- package/dist/observability/instrumentation.js +532 -0
- package/dist/observability/instrumentation.js.map +1 -0
- package/dist/observability/memory-metrics.d.ts +227 -0
- package/dist/observability/memory-metrics.d.ts.map +1 -0
- package/dist/observability/memory-metrics.js +688 -0
- package/dist/observability/memory-metrics.js.map +1 -0
- package/dist/observability/metrics-endpoint.d.ts +91 -0
- package/dist/observability/metrics-endpoint.d.ts.map +1 -0
- package/dist/observability/metrics-endpoint.js +246 -0
- package/dist/observability/metrics-endpoint.js.map +1 -0
- package/dist/observability/metrics.d.ts +88 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +253 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/observability-features.d.ts +488 -0
- package/dist/observability/observability-features.d.ts.map +1 -0
- package/dist/observability/observability-features.js +773 -0
- package/dist/observability/observability-features.js.map +1 -0
- package/dist/observability/prometheus.d.ts +39 -0
- package/dist/observability/prometheus.d.ts.map +1 -0
- package/dist/observability/prometheus.js +120 -0
- package/dist/observability/prometheus.js.map +1 -0
- package/dist/observability/propagation.d.ts +126 -0
- package/dist/observability/propagation.d.ts.map +1 -0
- package/dist/observability/propagation.js +234 -0
- package/dist/observability/propagation.js.map +1 -0
- package/dist/observability/query-latency.d.ts +243 -0
- package/dist/observability/query-latency.d.ts.map +1 -0
- package/dist/observability/query-latency.js +292 -0
- package/dist/observability/query-latency.js.map +1 -0
- package/dist/observability/query-performance.d.ts +169 -0
- package/dist/observability/query-performance.d.ts.map +1 -0
- package/dist/observability/query-performance.js +290 -0
- package/dist/observability/query-performance.js.map +1 -0
- package/dist/observability/storage-tier-metrics.d.ts +174 -0
- package/dist/observability/storage-tier-metrics.d.ts.map +1 -0
- package/dist/observability/storage-tier-metrics.js +306 -0
- package/dist/observability/storage-tier-metrics.js.map +1 -0
- package/dist/observability/tier-cost-optimizer.d.ts +155 -0
- package/dist/observability/tier-cost-optimizer.d.ts.map +1 -0
- package/dist/observability/tier-cost-optimizer.js +536 -0
- package/dist/observability/tier-cost-optimizer.js.map +1 -0
- package/dist/observability/tracer.d.ts +149 -0
- package/dist/observability/tracer.d.ts.map +1 -0
- package/dist/observability/tracer.js +435 -0
- package/dist/observability/tracer.js.map +1 -0
- package/dist/observability/types.d.ts +402 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +103 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/pglite/workers-pglite.d.ts +138 -0
- package/dist/pglite/workers-pglite.d.ts.map +1 -0
- package/dist/pglite/workers-pglite.js +143 -0
- package/dist/pglite/workers-pglite.js.map +1 -0
- package/dist/pglite-assets/pglite.data +0 -0
- package/dist/pglite-assets/pglite.wasm +0 -0
- package/dist/playground/index.d.ts +52 -0
- package/dist/playground/index.d.ts.map +1 -0
- package/dist/playground/index.js +55 -0
- package/dist/playground/index.js.map +1 -0
- package/dist/playground/keyboard-shortcuts.d.ts +116 -0
- package/dist/playground/keyboard-shortcuts.d.ts.map +1 -0
- package/dist/playground/keyboard-shortcuts.js +588 -0
- package/dist/playground/keyboard-shortcuts.js.map +1 -0
- package/dist/playground/playground.d.ts +82 -0
- package/dist/playground/playground.d.ts.map +1 -0
- package/dist/playground/playground.js +271 -0
- package/dist/playground/playground.js.map +1 -0
- package/dist/playground/query-executor.d.ts +115 -0
- package/dist/playground/query-executor.d.ts.map +1 -0
- package/dist/playground/query-executor.js +558 -0
- package/dist/playground/query-executor.js.map +1 -0
- package/dist/playground/query-history.d.ts +92 -0
- package/dist/playground/query-history.d.ts.map +1 -0
- package/dist/playground/query-history.js +259 -0
- package/dist/playground/query-history.js.map +1 -0
- package/dist/playground/result-formatter.d.ts +59 -0
- package/dist/playground/result-formatter.d.ts.map +1 -0
- package/dist/playground/result-formatter.js +341 -0
- package/dist/playground/result-formatter.js.map +1 -0
- package/dist/playground/sample-datasets.d.ts +77 -0
- package/dist/playground/sample-datasets.d.ts.map +1 -0
- package/dist/playground/sample-datasets.js +641 -0
- package/dist/playground/sample-datasets.js.map +1 -0
- package/dist/playground/sample-queries.d.ts +73 -0
- package/dist/playground/sample-queries.d.ts.map +1 -0
- package/dist/playground/sample-queries.js +1095 -0
- package/dist/playground/sample-queries.js.map +1 -0
- package/dist/playground/schema-explorer.d.ts +55 -0
- package/dist/playground/schema-explorer.d.ts.map +1 -0
- package/dist/playground/schema-explorer.js +473 -0
- package/dist/playground/schema-explorer.js.map +1 -0
- package/dist/playground/types.d.ts +430 -0
- package/dist/playground/types.d.ts.map +1 -0
- package/dist/playground/types.js +10 -0
- package/dist/playground/types.js.map +1 -0
- package/dist/readonly/cache-reader.d.ts +145 -0
- package/dist/readonly/cache-reader.d.ts.map +1 -0
- package/dist/readonly/cache-reader.js +198 -0
- package/dist/readonly/cache-reader.js.map +1 -0
- package/dist/readonly/config.d.ts +74 -0
- package/dist/readonly/config.d.ts.map +1 -0
- package/dist/readonly/config.js +67 -0
- package/dist/readonly/config.js.map +1 -0
- package/dist/readonly/index.d.ts +22 -0
- package/dist/readonly/index.d.ts.map +1 -0
- package/dist/readonly/index.js +17 -0
- package/dist/readonly/index.js.map +1 -0
- package/dist/readonly/pglite-wrapper.d.ts +82 -0
- package/dist/readonly/pglite-wrapper.d.ts.map +1 -0
- package/dist/readonly/pglite-wrapper.js +123 -0
- package/dist/readonly/pglite-wrapper.js.map +1 -0
- package/dist/readonly/worker.d.ts +142 -0
- package/dist/readonly/worker.d.ts.map +1 -0
- package/dist/readonly/worker.js +187 -0
- package/dist/readonly/worker.js.map +1 -0
- package/dist/readonly/write-blocker.d.ts +47 -0
- package/dist/readonly/write-blocker.d.ts.map +1 -0
- package/dist/readonly/write-blocker.js +136 -0
- package/dist/readonly/write-blocker.js.map +1 -0
- package/dist/recovery/disaster-recovery.d.ts +326 -0
- package/dist/recovery/disaster-recovery.d.ts.map +1 -0
- package/dist/recovery/disaster-recovery.js +799 -0
- package/dist/recovery/disaster-recovery.js.map +1 -0
- package/dist/recovery/index.d.ts +12 -0
- package/dist/recovery/index.d.ts.map +1 -0
- package/dist/recovery/index.js +12 -0
- package/dist/recovery/index.js.map +1 -0
- package/dist/recovery/parquet-parser.d.ts +321 -0
- package/dist/recovery/parquet-parser.d.ts.map +1 -0
- package/dist/recovery/parquet-parser.js +797 -0
- package/dist/recovery/parquet-parser.js.map +1 -0
- package/dist/retention/index.d.ts +50 -0
- package/dist/retention/index.d.ts.map +1 -0
- package/dist/retention/index.js +50 -0
- package/dist/retention/index.js.map +1 -0
- package/dist/retention/policy.d.ts +344 -0
- package/dist/retention/policy.d.ts.map +1 -0
- package/dist/retention/policy.js +472 -0
- package/dist/retention/policy.js.map +1 -0
- package/dist/retention/purger.d.ts +187 -0
- package/dist/retention/purger.d.ts.map +1 -0
- package/dist/retention/purger.js +411 -0
- package/dist/retention/purger.js.map +1 -0
- package/dist/rls/auth-integration.d.ts +280 -0
- package/dist/rls/auth-integration.d.ts.map +1 -0
- package/dist/rls/auth-integration.js +399 -0
- package/dist/rls/auth-integration.js.map +1 -0
- package/dist/rls/generator.d.ts +249 -0
- package/dist/rls/generator.d.ts.map +1 -0
- package/dist/rls/generator.js +495 -0
- package/dist/rls/generator.js.map +1 -0
- package/dist/rls/index.d.ts +26 -0
- package/dist/rls/index.d.ts.map +1 -0
- package/dist/rls/index.js +58 -0
- package/dist/rls/index.js.map +1 -0
- package/dist/rls/policy.d.ts +116 -0
- package/dist/rls/policy.d.ts.map +1 -0
- package/dist/rls/policy.js +77 -0
- package/dist/rls/policy.js.map +1 -0
- package/dist/rls/validator.d.ts +155 -0
- package/dist/rls/validator.d.ts.map +1 -0
- package/dist/rls/validator.js +792 -0
- package/dist/rls/validator.js.map +1 -0
- package/dist/routing/adaptive-router.d.ts +317 -0
- package/dist/routing/adaptive-router.d.ts.map +1 -0
- package/dist/routing/adaptive-router.js +554 -0
- package/dist/routing/adaptive-router.js.map +1 -0
- package/dist/routing/circuit-breaker.d.ts +339 -0
- package/dist/routing/circuit-breaker.d.ts.map +1 -0
- package/dist/routing/circuit-breaker.js +620 -0
- package/dist/routing/circuit-breaker.js.map +1 -0
- package/dist/routing/cost-metrics.d.ts +133 -0
- package/dist/routing/cost-metrics.d.ts.map +1 -0
- package/dist/routing/cost-metrics.js +259 -0
- package/dist/routing/cost-metrics.js.map +1 -0
- package/dist/routing/do-connection-pool.d.ts +243 -0
- package/dist/routing/do-connection-pool.d.ts.map +1 -0
- package/dist/routing/do-connection-pool.js +572 -0
- package/dist/routing/do-connection-pool.js.map +1 -0
- package/dist/routing/index.d.ts +59 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +59 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/routing/query-complexity-estimator.d.ts +73 -0
- package/dist/routing/query-complexity-estimator.d.ts.map +1 -0
- package/dist/routing/query-complexity-estimator.js +327 -0
- package/dist/routing/query-complexity-estimator.js.map +1 -0
- package/dist/routing/request-coalescing.d.ts +178 -0
- package/dist/routing/request-coalescing.d.ts.map +1 -0
- package/dist/routing/request-coalescing.js +325 -0
- package/dist/routing/request-coalescing.js.map +1 -0
- package/dist/routing/runtime-router.d.ts +107 -0
- package/dist/routing/runtime-router.d.ts.map +1 -0
- package/dist/routing/runtime-router.js +246 -0
- package/dist/routing/runtime-router.js.map +1 -0
- package/dist/routing/tenant-router.d.ts +848 -0
- package/dist/routing/tenant-router.d.ts.map +1 -0
- package/dist/routing/tenant-router.js +1056 -0
- package/dist/routing/tenant-router.js.map +1 -0
- package/dist/routing/websocket-pool.d.ts +119 -0
- package/dist/routing/websocket-pool.d.ts.map +1 -0
- package/dist/routing/websocket-pool.js +436 -0
- package/dist/routing/websocket-pool.js.map +1 -0
- package/dist/storage/cache-layer.d.ts +159 -0
- package/dist/storage/cache-layer.d.ts.map +1 -0
- package/dist/storage/cache-layer.js +245 -0
- package/dist/storage/cache-layer.js.map +1 -0
- package/dist/storage/cost-aware-tiering.d.ts +258 -0
- package/dist/storage/cost-aware-tiering.d.ts.map +1 -0
- package/dist/storage/cost-aware-tiering.js +526 -0
- package/dist/storage/cost-aware-tiering.js.map +1 -0
- package/dist/storage/index.d.ts +87 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +78 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/interfaces.d.ts +856 -0
- package/dist/storage/interfaces.d.ts.map +1 -0
- package/dist/storage/interfaces.js +69 -0
- package/dist/storage/interfaces.js.map +1 -0
- package/dist/storage/r2-layer.d.ts +226 -0
- package/dist/storage/r2-layer.d.ts.map +1 -0
- package/dist/storage/r2-layer.js +307 -0
- package/dist/storage/r2-layer.js.map +1 -0
- package/dist/storage/r2-overflow.d.ts +344 -0
- package/dist/storage/r2-overflow.d.ts.map +1 -0
- package/dist/storage/r2-overflow.js +730 -0
- package/dist/storage/r2-overflow.js.map +1 -0
- package/dist/storage/r2-page-vfs.d.ts +374 -0
- package/dist/storage/r2-page-vfs.d.ts.map +1 -0
- package/dist/storage/r2-page-vfs.js +754 -0
- package/dist/storage/r2-page-vfs.js.map +1 -0
- package/dist/storage/swr-cache.d.ts +181 -0
- package/dist/storage/swr-cache.d.ts.map +1 -0
- package/dist/storage/swr-cache.js +295 -0
- package/dist/storage/swr-cache.js.map +1 -0
- package/dist/storage/tiered-orchestrator.d.ts +951 -0
- package/dist/storage/tiered-orchestrator.d.ts.map +1 -0
- package/dist/storage/tiered-orchestrator.js +1731 -0
- package/dist/storage/tiered-orchestrator.js.map +1 -0
- package/dist/storage/tiered-vfs-swr.d.ts +279 -0
- package/dist/storage/tiered-vfs-swr.d.ts.map +1 -0
- package/dist/storage/tiered-vfs-swr.js +584 -0
- package/dist/storage/tiered-vfs-swr.js.map +1 -0
- package/dist/storage/tiered-vfs.d.ts +405 -0
- package/dist/storage/tiered-vfs.d.ts.map +1 -0
- package/dist/storage/tiered-vfs.js +833 -0
- package/dist/storage/tiered-vfs.js.map +1 -0
- package/dist/streaming/backpressure-controller.d.ts +173 -0
- package/dist/streaming/backpressure-controller.d.ts.map +1 -0
- package/dist/streaming/backpressure-controller.js +344 -0
- package/dist/streaming/backpressure-controller.js.map +1 -0
- package/dist/streaming/buffer-pool.d.ts +241 -0
- package/dist/streaming/buffer-pool.d.ts.map +1 -0
- package/dist/streaming/buffer-pool.js +381 -0
- package/dist/streaming/buffer-pool.js.map +1 -0
- package/dist/streaming/cdc-iceberg-connector.d.ts +272 -0
- package/dist/streaming/cdc-iceberg-connector.d.ts.map +1 -0
- package/dist/streaming/cdc-iceberg-connector.js +408 -0
- package/dist/streaming/cdc-iceberg-connector.js.map +1 -0
- package/dist/streaming/index.d.ts +111 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +128 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming/live-cdc-stream.d.ts +400 -0
- package/dist/streaming/live-cdc-stream.d.ts.map +1 -0
- package/dist/streaming/live-cdc-stream.js +703 -0
- package/dist/streaming/live-cdc-stream.js.map +1 -0
- package/dist/streaming/memory-bounded-stream.d.ts +207 -0
- package/dist/streaming/memory-bounded-stream.d.ts.map +1 -0
- package/dist/streaming/memory-bounded-stream.js +340 -0
- package/dist/streaming/memory-bounded-stream.js.map +1 -0
- package/dist/streaming/query-streamer.d.ts +379 -0
- package/dist/streaming/query-streamer.d.ts.map +1 -0
- package/dist/streaming/query-streamer.js +495 -0
- package/dist/streaming/query-streamer.js.map +1 -0
- package/dist/streaming/response-streaming.d.ts +203 -0
- package/dist/streaming/response-streaming.d.ts.map +1 -0
- package/dist/streaming/response-streaming.js +449 -0
- package/dist/streaming/response-streaming.js.map +1 -0
- package/dist/types/branded.d.ts +859 -0
- package/dist/types/branded.d.ts.map +1 -0
- package/dist/types/branded.js +891 -0
- package/dist/types/branded.js.map +1 -0
- package/dist/types/utilities.d.ts +757 -0
- package/dist/types/utilities.d.ts.map +1 -0
- package/dist/types/utilities.js +447 -0
- package/dist/types/utilities.js.map +1 -0
- package/dist/wal/replay-engine.d.ts +344 -0
- package/dist/wal/replay-engine.d.ts.map +1 -0
- package/dist/wal/replay-engine.js +975 -0
- package/dist/wal/replay-engine.js.map +1 -0
- package/dist/worker/__mocks__/capnweb.d.ts +13 -0
- package/dist/worker/__mocks__/capnweb.d.ts.map +1 -0
- package/dist/worker/__mocks__/capnweb.js +15 -0
- package/dist/worker/__mocks__/capnweb.js.map +1 -0
- package/dist/worker/__mocks__/cloudflare-workers.d.ts +31 -0
- package/dist/worker/__mocks__/cloudflare-workers.d.ts.map +1 -0
- package/dist/worker/__mocks__/cloudflare-workers.js +33 -0
- package/dist/worker/__mocks__/cloudflare-workers.js.map +1 -0
- package/dist/worker/__mocks__/pglite.data.d.ts +3 -0
- package/dist/worker/__mocks__/pglite.data.d.ts.map +1 -0
- package/dist/worker/__mocks__/pglite.data.js +20 -0
- package/dist/worker/__mocks__/pglite.data.js.map +1 -0
- package/dist/worker/__mocks__/pglite.wasm.d.ts +3 -0
- package/dist/worker/__mocks__/pglite.wasm.d.ts.map +1 -0
- package/dist/worker/__mocks__/pglite.wasm.js +30 -0
- package/dist/worker/__mocks__/pglite.wasm.js.map +1 -0
- package/dist/worker/auth-rate-limiter.d.ts +270 -0
- package/dist/worker/auth-rate-limiter.d.ts.map +1 -0
- package/dist/worker/auth-rate-limiter.js +332 -0
- package/dist/worker/auth-rate-limiter.js.map +1 -0
- package/dist/worker/auth.d.ts +345 -0
- package/dist/worker/auth.d.ts.map +1 -0
- package/dist/worker/auth.js +837 -0
- package/dist/worker/auth.js.map +1 -0
- package/dist/worker/cdc-backpressure.d.ts +338 -0
- package/dist/worker/cdc-backpressure.d.ts.map +1 -0
- package/dist/worker/cdc-backpressure.js +619 -0
- package/dist/worker/cdc-backpressure.js.map +1 -0
- package/dist/worker/cdc-sse.d.ts +277 -0
- package/dist/worker/cdc-sse.d.ts.map +1 -0
- package/dist/worker/cdc-sse.js +528 -0
- package/dist/worker/cdc-sse.js.map +1 -0
- package/dist/worker/cdc-websocket.d.ts +252 -0
- package/dist/worker/cdc-websocket.d.ts.map +1 -0
- package/dist/worker/cdc-websocket.js +940 -0
- package/dist/worker/cdc-websocket.js.map +1 -0
- package/dist/worker/cdc.d.ts +95 -0
- package/dist/worker/cdc.d.ts.map +1 -0
- package/dist/worker/cdc.js +211 -0
- package/dist/worker/cdc.js.map +1 -0
- package/dist/worker/concerns/auth-concern.d.ts +50 -0
- package/dist/worker/concerns/auth-concern.d.ts.map +1 -0
- package/dist/worker/concerns/auth-concern.js +131 -0
- package/dist/worker/concerns/auth-concern.js.map +1 -0
- package/dist/worker/concerns/cdc-concern.d.ts +99 -0
- package/dist/worker/concerns/cdc-concern.d.ts.map +1 -0
- package/dist/worker/concerns/cdc-concern.js +137 -0
- package/dist/worker/concerns/cdc-concern.js.map +1 -0
- package/dist/worker/concerns/index.d.ts +22 -0
- package/dist/worker/concerns/index.d.ts.map +1 -0
- package/dist/worker/concerns/index.js +13 -0
- package/dist/worker/concerns/index.js.map +1 -0
- package/dist/worker/concerns/query-execution-concern.d.ts +104 -0
- package/dist/worker/concerns/query-execution-concern.d.ts.map +1 -0
- package/dist/worker/concerns/query-execution-concern.js +95 -0
- package/dist/worker/concerns/query-execution-concern.js.map +1 -0
- package/dist/worker/concerns/storage-orchestration-concern.d.ts +78 -0
- package/dist/worker/concerns/storage-orchestration-concern.d.ts.map +1 -0
- package/dist/worker/concerns/storage-orchestration-concern.js +240 -0
- package/dist/worker/concerns/storage-orchestration-concern.js.map +1 -0
- package/dist/worker/do-auth-manager.d.ts +108 -0
- package/dist/worker/do-auth-manager.d.ts.map +1 -0
- package/dist/worker/do-auth-manager.js +212 -0
- package/dist/worker/do-auth-manager.js.map +1 -0
- package/dist/worker/do-pglite-manager.d.ts +137 -0
- package/dist/worker/do-pglite-manager.d.ts.map +1 -0
- package/dist/worker/do-pglite-manager.js +228 -0
- package/dist/worker/do-pglite-manager.js.map +1 -0
- package/dist/worker/do.d.ts +556 -0
- package/dist/worker/do.d.ts.map +1 -0
- package/dist/worker/do.js +1441 -0
- package/dist/worker/do.js.map +1 -0
- package/dist/worker/entry.d.ts +23 -0
- package/dist/worker/entry.d.ts.map +1 -0
- package/dist/worker/entry.js +362 -0
- package/dist/worker/entry.js.map +1 -0
- package/dist/worker/errors.d.ts +106 -0
- package/dist/worker/errors.d.ts.map +1 -0
- package/dist/worker/errors.js +178 -0
- package/dist/worker/errors.js.map +1 -0
- package/dist/worker/health-check-manager.d.ts +141 -0
- package/dist/worker/health-check-manager.d.ts.map +1 -0
- package/dist/worker/health-check-manager.js +145 -0
- package/dist/worker/health-check-manager.js.map +1 -0
- package/dist/worker/index.d.ts +60 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +67 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/memory-pressure.d.ts +892 -0
- package/dist/worker/memory-pressure.d.ts.map +1 -0
- package/dist/worker/memory-pressure.js +1990 -0
- package/dist/worker/memory-pressure.js.map +1 -0
- package/dist/worker/migration-manager.d.ts +153 -0
- package/dist/worker/migration-manager.d.ts.map +1 -0
- package/dist/worker/migration-manager.js +461 -0
- package/dist/worker/migration-manager.js.map +1 -0
- package/dist/worker/plugin-manager.d.ts +147 -0
- package/dist/worker/plugin-manager.d.ts.map +1 -0
- package/dist/worker/plugin-manager.js +408 -0
- package/dist/worker/plugin-manager.js.map +1 -0
- package/dist/worker/proxy.d.ts +330 -0
- package/dist/worker/proxy.d.ts.map +1 -0
- package/dist/worker/proxy.js +504 -0
- package/dist/worker/proxy.js.map +1 -0
- package/dist/worker/query-execution-manager.d.ts +107 -0
- package/dist/worker/query-execution-manager.d.ts.map +1 -0
- package/dist/worker/query-execution-manager.js +155 -0
- package/dist/worker/query-execution-manager.js.map +1 -0
- package/dist/worker/query-executor.d.ts +163 -0
- package/dist/worker/query-executor.d.ts.map +1 -0
- package/dist/worker/query-executor.js +413 -0
- package/dist/worker/query-executor.js.map +1 -0
- package/dist/worker/query-stats-manager.d.ts +117 -0
- package/dist/worker/query-stats-manager.d.ts.map +1 -0
- package/dist/worker/query-stats-manager.js +162 -0
- package/dist/worker/query-stats-manager.js.map +1 -0
- package/dist/worker/result-handler.d.ts +192 -0
- package/dist/worker/result-handler.d.ts.map +1 -0
- package/dist/worker/result-handler.js +346 -0
- package/dist/worker/result-handler.js.map +1 -0
- package/dist/worker/routes.d.ts +135 -0
- package/dist/worker/routes.d.ts.map +1 -0
- package/dist/worker/routes.js +460 -0
- package/dist/worker/routes.js.map +1 -0
- package/dist/worker/rpc-methods-manager.d.ts +142 -0
- package/dist/worker/rpc-methods-manager.d.ts.map +1 -0
- package/dist/worker/rpc-methods-manager.js +195 -0
- package/dist/worker/rpc-methods-manager.js.map +1 -0
- package/dist/worker/rpc.d.ts +259 -0
- package/dist/worker/rpc.d.ts.map +1 -0
- package/dist/worker/rpc.js +398 -0
- package/dist/worker/rpc.js.map +1 -0
- package/dist/worker/schema-version.d.ts +209 -0
- package/dist/worker/schema-version.d.ts.map +1 -0
- package/dist/worker/schema-version.js +450 -0
- package/dist/worker/schema-version.js.map +1 -0
- package/dist/worker/session-manager.d.ts +282 -0
- package/dist/worker/session-manager.d.ts.map +1 -0
- package/dist/worker/session-manager.js +523 -0
- package/dist/worker/session-manager.js.map +1 -0
- package/dist/worker/shutdown-manager.d.ts +188 -0
- package/dist/worker/shutdown-manager.d.ts.map +1 -0
- package/dist/worker/shutdown-manager.js +347 -0
- package/dist/worker/shutdown-manager.js.map +1 -0
- package/dist/worker/sql-transform.d.ts +61 -0
- package/dist/worker/sql-transform.d.ts.map +1 -0
- package/dist/worker/sql-transform.js +312 -0
- package/dist/worker/sql-transform.js.map +1 -0
- package/dist/worker/types.d.ts +738 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/types.js +6 -0
- package/dist/worker/types.js.map +1 -0
- package/dist/worker/user-routes.d.ts +76 -0
- package/dist/worker/user-routes.d.ts.map +1 -0
- package/dist/worker/user-routes.js +188 -0
- package/dist/worker/user-routes.js.map +1 -0
- package/dist/worker/wal-facade.d.ts +138 -0
- package/dist/worker/wal-facade.d.ts.map +1 -0
- package/dist/worker/wal-facade.js +184 -0
- package/dist/worker/wal-facade.js.map +1 -0
- package/dist/worker/wal-r2.d.ts +271 -0
- package/dist/worker/wal-r2.d.ts.map +1 -0
- package/dist/worker/wal-r2.js +689 -0
- package/dist/worker/wal-r2.js.map +1 -0
- package/dist/worker/wal-replay.d.ts +361 -0
- package/dist/worker/wal-replay.d.ts.map +1 -0
- package/dist/worker/wal-replay.js +628 -0
- package/dist/worker/wal-replay.js.map +1 -0
- package/dist/worker/wal-retention.d.ts +389 -0
- package/dist/worker/wal-retention.d.ts.map +1 -0
- package/dist/worker/wal-retention.js +763 -0
- package/dist/worker/wal-retention.js.map +1 -0
- package/dist/worker/wal.d.ts +278 -0
- package/dist/worker/wal.d.ts.map +1 -0
- package/dist/worker/wal.js +467 -0
- package/dist/worker/wal.js.map +1 -0
- package/dist/worker/websocket.d.ts +85 -0
- package/dist/worker/websocket.d.ts.map +1 -0
- package/dist/worker/websocket.js +227 -0
- package/dist/worker/websocket.js.map +1 -0
- package/package.json +108 -0
- package/src/cdc/change-stream.ts +137 -0
- package/src/cdc/filter.ts +646 -0
- package/src/cdc/index.ts +112 -0
- package/src/cdc/resume-token.ts +280 -0
- package/src/cdc/transport/index.ts +7 -0
- package/src/cdc/transport/sse.ts +723 -0
- package/src/cdc/transport/websocket.ts +873 -0
- package/src/cdc/types.ts +346 -0
- package/src/config/index.ts +25 -0
- package/src/config/memory.ts +177 -0
- package/src/config/storage.ts +204 -0
- package/src/config/streaming.ts +147 -0
- package/src/config/timeouts.ts +221 -0
- package/src/extensions/config.test.ts +187 -0
- package/src/extensions/config.ts +278 -0
- package/src/extensions/geo.test.ts +455 -0
- package/src/extensions/geo.ts +858 -0
- package/src/extensions/index.test.ts +259 -0
- package/src/extensions/index.ts +227 -0
- package/src/extensions/loader.test.ts +555 -0
- package/src/extensions/loader.ts +588 -0
- package/src/extensions/pgmq-lite.test.ts +727 -0
- package/src/extensions/pgmq-lite.ts +770 -0
- package/src/extensions/plugins.test.ts +528 -0
- package/src/extensions/plugins.ts +718 -0
- package/src/extensions/registry.test.ts +202 -0
- package/src/extensions/registry.ts +267 -0
- package/src/extensions/vector.test.ts +195 -0
- package/src/extensions/vector.ts +217 -0
- package/src/iceberg/SCHEDULER.md +580 -0
- package/src/iceberg/analytics.test.ts +703 -0
- package/src/iceberg/analytics.ts +727 -0
- package/src/iceberg/catalog-api.test.ts +838 -0
- package/src/iceberg/catalog-api.ts +520 -0
- package/src/iceberg/catalog.test.ts +680 -0
- package/src/iceberg/catalog.ts +1007 -0
- package/src/iceberg/iceberg.test.ts +705 -0
- package/src/iceberg/index.ts +406 -0
- package/src/iceberg/metadata.test.ts +632 -0
- package/src/iceberg/metadata.ts +649 -0
- package/src/iceberg/optimizer.test.ts +868 -0
- package/src/iceberg/optimizer.ts +1287 -0
- package/src/iceberg/parquet.test.ts +899 -0
- package/src/iceberg/parquet.ts +1640 -0
- package/src/iceberg/r2-organization.test.ts +615 -0
- package/src/iceberg/r2-organization.ts +951 -0
- package/src/iceberg/scheduler-do-example.ts +364 -0
- package/src/iceberg/scheduler.test.ts +861 -0
- package/src/iceberg/scheduler.ts +1201 -0
- package/src/iceberg/schema.test.ts +547 -0
- package/src/iceberg/schema.ts +616 -0
- package/src/iceberg/snapshot-manager.test.ts +919 -0
- package/src/iceberg/snapshot-manager.ts +1369 -0
- package/src/iceberg/sql-router.test.ts +334 -0
- package/src/iceberg/sql-router.ts +337 -0
- package/src/iceberg/test-fixtures.ts +605 -0
- package/src/iceberg/time-travel-api.test.ts +1029 -0
- package/src/iceberg/time-travel-api.ts +731 -0
- package/src/iceberg/time-travel.test.ts +1218 -0
- package/src/iceberg/time-travel.ts +1052 -0
- package/src/iceberg/transformer.test.ts +689 -0
- package/src/iceberg/transformer.ts +1029 -0
- package/src/iceberg/types.ts +373 -0
- package/src/iceberg/writer.test.ts +716 -0
- package/src/iceberg/writer.ts +590 -0
- package/src/index.ts +212 -0
- package/src/lineage/index.ts +42 -0
- package/src/lineage/integration.ts +334 -0
- package/src/lineage/tracker.ts +1618 -0
- package/src/lineage/types.ts +354 -0
- package/src/middleware/index.ts +36 -0
- package/src/middleware/rate-limit-concurrent.test.ts +794 -0
- package/src/middleware/rate-limit.test.ts +1568 -0
- package/src/middleware/rate-limit.ts +840 -0
- package/src/migration-tooling/external-migration.test.ts +1864 -0
- package/src/migration-tooling/external-migration.ts +2355 -0
- package/src/migration-tooling/index.ts +19 -0
- package/src/migrations/ARCHITECTURE.md +474 -0
- package/src/migrations/PROGRESS_TRACKING.md +485 -0
- package/src/migrations/auto-migrator.test.ts +732 -0
- package/src/migrations/auto-migrator.ts +531 -0
- package/src/migrations/bulk-orchestrator.test.ts +801 -0
- package/src/migrations/bulk-orchestrator.ts +1039 -0
- package/src/migrations/compatibility.test.ts +958 -0
- package/src/migrations/compatibility.ts +902 -0
- package/src/migrations/do-migrations.test.ts +2620 -0
- package/src/migrations/do-migrations.ts +1289 -0
- package/src/migrations/do-migrations.types.ts +715 -0
- package/src/migrations/drizzle-compat.test.ts +210 -0
- package/src/migrations/drizzle-compat.ts +337 -0
- package/src/migrations/index.ts +334 -0
- package/src/migrations/migration-api.test.ts +438 -0
- package/src/migrations/migration-api.ts +704 -0
- package/src/migrations/progress-tracker-do.ts +518 -0
- package/src/migrations/progress-tracker-kv.ts +305 -0
- package/src/migrations/progress-tracker.test.ts +937 -0
- package/src/migrations/progress-tracker.ts +665 -0
- package/src/migrations/registry.test.ts +331 -0
- package/src/migrations/registry.ts +468 -0
- package/src/migrations/rollback.test.ts +644 -0
- package/src/migrations/runner.test.ts +807 -0
- package/src/migrations/runner.test.ts.backup +759 -0
- package/src/migrations/runner.ts +1459 -0
- package/src/migrations/schema-generator.test.ts +649 -0
- package/src/migrations/schema-generator.ts +513 -0
- package/src/migrations/testing.ts +1037 -0
- package/src/migrations/types.ts +573 -0
- package/src/migrations/validator.test.ts +660 -0
- package/src/migrations/validator.ts +741 -0
- package/src/observability/alerting.test.ts +1133 -0
- package/src/observability/alerting.ts +455 -0
- package/src/observability/analytics-engine.ts +733 -0
- package/src/observability/cost-metrics.ts +804 -0
- package/src/observability/cross-do-tracing.test.ts +516 -0
- package/src/observability/cross-do-tracing.ts +588 -0
- package/src/observability/dashboards/postgres-do-overview.json +1656 -0
- package/src/observability/error-rate-collector.test.ts +977 -0
- package/src/observability/error-rate-collector.ts +518 -0
- package/src/observability/exporters.test.ts +365 -0
- package/src/observability/exporters.ts +650 -0
- package/src/observability/health-check.test.ts +353 -0
- package/src/observability/health-check.ts +341 -0
- package/src/observability/index.test.ts +298 -0
- package/src/observability/index.ts +885 -0
- package/src/observability/instrumentation.test.ts +428 -0
- package/src/observability/instrumentation.ts +788 -0
- package/src/observability/memory-metrics.test.ts +355 -0
- package/src/observability/memory-metrics.ts +990 -0
- package/src/observability/metrics-endpoint.test.ts +402 -0
- package/src/observability/metrics-endpoint.ts +374 -0
- package/src/observability/metrics.test.ts +291 -0
- package/src/observability/metrics.ts +315 -0
- package/src/observability/observability-features.ts +1296 -0
- package/src/observability/prometheus.test.ts +292 -0
- package/src/observability/prometheus.ts +170 -0
- package/src/observability/propagation.test.ts +417 -0
- package/src/observability/propagation.ts +294 -0
- package/src/observability/query-latency.ts +586 -0
- package/src/observability/query-performance.test.ts +406 -0
- package/src/observability/query-performance.ts +491 -0
- package/src/observability/storage-tier-metrics.test.ts +633 -0
- package/src/observability/storage-tier-metrics.ts +570 -0
- package/src/observability/tier-cost-optimizer.ts +740 -0
- package/src/observability/tracer.test.ts +346 -0
- package/src/observability/tracer.ts +585 -0
- package/src/observability/types.test.ts +726 -0
- package/src/observability/types.ts +434 -0
- package/src/pglite/auto-demotion.test.ts +477 -0
- package/src/pglite/auto-demotion.ts +385 -0
- package/src/pglite/auto-promotion.test.ts +824 -0
- package/src/pglite/auto-promotion.ts +547 -0
- package/src/pglite/cache-layer.test.ts +469 -0
- package/src/pglite/cache-layer.ts +271 -0
- package/src/pglite/cold-start-manager.ts +1260 -0
- package/src/pglite/cold-start-optimizer.test.ts +937 -0
- package/src/pglite/cold-start-optimizer.ts +1895 -0
- package/src/pglite/dovfs-adapter.ts +1122 -0
- package/src/pglite/dovfs.ts +1258 -0
- package/src/pglite/etag-cache.test.ts +844 -0
- package/src/pglite/etag-cache.ts +526 -0
- package/src/pglite/index.ts +442 -0
- package/src/pglite/init.test.ts +455 -0
- package/src/pglite/init.ts +574 -0
- package/src/pglite/lifecycle.test.ts +599 -0
- package/src/pglite/lifecycle.ts +704 -0
- package/src/pglite/parallel-loader.test.ts +586 -0
- package/src/pglite/parallel-loader.ts +481 -0
- package/src/pglite/production-pglite.test.ts +666 -0
- package/src/pglite/production-pglite.ts +537 -0
- package/src/pglite/query-executor.ts +614 -0
- package/src/pglite/r2-layer.test.ts +501 -0
- package/src/pglite/r2-layer.ts +322 -0
- package/src/pglite/tiered-init.test.ts +725 -0
- package/src/pglite/tiered-init.ts +556 -0
- package/src/pglite/tiered-vfs.test.ts +726 -0
- package/src/pglite/tiered-vfs.ts +33 -0
- package/src/pglite/tiering-stats.test.ts +531 -0
- package/src/pglite/tiering-stats.ts +407 -0
- package/src/pglite/transaction-hooks.ts +343 -0
- package/src/pglite/warm-loader.test.ts +1701 -0
- package/src/pglite/warm-loader.ts +528 -0
- package/src/pglite/workers-pglite.ts +224 -0
- package/src/pglite-assets/pglite.data +0 -0
- package/src/pglite-assets/pglite.wasm +0 -0
- package/src/pglite.d.ts +47 -0
- package/src/playground/index.ts +137 -0
- package/src/playground/keyboard-shortcuts.ts +677 -0
- package/src/playground/playground.ts +323 -0
- package/src/playground/query-executor.ts +669 -0
- package/src/playground/query-history.ts +328 -0
- package/src/playground/result-formatter.ts +420 -0
- package/src/playground/sample-datasets.ts +674 -0
- package/src/playground/sample-queries.ts +1168 -0
- package/src/playground/schema-explorer.ts +558 -0
- package/src/playground/types.ts +518 -0
- package/src/readonly/cache-reader.test.ts +460 -0
- package/src/readonly/cache-reader.ts +313 -0
- package/src/readonly/config.test.ts +187 -0
- package/src/readonly/config.ts +128 -0
- package/src/readonly/index.ts +50 -0
- package/src/readonly/pglite-wrapper.test.ts +278 -0
- package/src/readonly/pglite-wrapper.ts +184 -0
- package/src/readonly/worker.test.ts +533 -0
- package/src/readonly/worker.ts +341 -0
- package/src/readonly/write-blocker.test.ts +459 -0
- package/src/readonly/write-blocker.ts +175 -0
- package/src/recovery/disaster-recovery.test.ts +618 -0
- package/src/recovery/disaster-recovery.ts +1181 -0
- package/src/recovery/index.ts +43 -0
- package/src/recovery/parquet-parser.ts +974 -0
- package/src/retention/index.ts +74 -0
- package/src/retention/policy.test.ts +571 -0
- package/src/retention/policy.ts +774 -0
- package/src/retention/purger.test.ts +465 -0
- package/src/retention/purger.ts +558 -0
- package/src/rls/auth-integration.test.ts +752 -0
- package/src/rls/auth-integration.ts +533 -0
- package/src/rls/generator.test.ts +829 -0
- package/src/rls/generator.ts +573 -0
- package/src/rls/index.ts +128 -0
- package/src/rls/policy.ts +208 -0
- package/src/rls/rls.test.ts +1071 -0
- package/src/rls/validator.test.ts +930 -0
- package/src/rls/validator.ts +895 -0
- package/src/routing/adaptive-router.test.ts +884 -0
- package/src/routing/adaptive-router.ts +845 -0
- package/src/routing/circuit-breaker.test.ts +1505 -0
- package/src/routing/circuit-breaker.ts +852 -0
- package/src/routing/cost-metrics.test.ts +565 -0
- package/src/routing/cost-metrics.ts +408 -0
- package/src/routing/do-connection-pool.test.ts +1109 -0
- package/src/routing/do-connection-pool.ts +828 -0
- package/src/routing/index.ts +158 -0
- package/src/routing/query-complexity-estimator.test.ts +356 -0
- package/src/routing/query-complexity-estimator.ts +444 -0
- package/src/routing/request-coalescing.test.ts +738 -0
- package/src/routing/request-coalescing.ts +475 -0
- package/src/routing/runtime-router.test.ts +436 -0
- package/src/routing/runtime-router.ts +357 -0
- package/src/routing/tenant-router.test.ts +2493 -0
- package/src/routing/tenant-router.ts +1908 -0
- package/src/routing/websocket-pool.test.ts +551 -0
- package/src/routing/websocket-pool.ts +577 -0
- package/src/storage/access-pattern-tracker.test.ts +874 -0
- package/src/storage/cache-layer.test.ts +560 -0
- package/src/storage/cache-layer.ts +328 -0
- package/src/storage/cost-aware-tiering.test.ts +652 -0
- package/src/storage/cost-aware-tiering.ts +794 -0
- package/src/storage/do-sqlite-blobs.test.ts +937 -0
- package/src/storage/index.ts +272 -0
- package/src/storage/interfaces.ts +974 -0
- package/src/storage/r2-layer.test.ts +653 -0
- package/src/storage/r2-layer.ts +434 -0
- package/src/storage/r2-overflow.ts +920 -0
- package/src/storage/r2-page-vfs.test.ts +2348 -0
- package/src/storage/r2-page-vfs.ts +1054 -0
- package/src/storage/swr-cache.test.ts +832 -0
- package/src/storage/swr-cache.ts +398 -0
- package/src/storage/swr-tiered-integration.test.ts +617 -0
- package/src/storage/tiered-orchestrator.test.ts +2441 -0
- package/src/storage/tiered-orchestrator.ts +2081 -0
- package/src/storage/tiered-vfs-swr.test.ts +736 -0
- package/src/storage/tiered-vfs-swr.ts +735 -0
- package/src/storage/tiered-vfs.test.ts +793 -0
- package/src/storage/tiered-vfs.ts +1082 -0
- package/src/streaming/backpressure-controller.ts +452 -0
- package/src/streaming/buffer-pool.ts +484 -0
- package/src/streaming/cdc-iceberg-connector.ts +605 -0
- package/src/streaming/index.ts +225 -0
- package/src/streaming/live-cdc-stream.ts +985 -0
- package/src/streaming/memory-bounded-stream.ts +443 -0
- package/src/streaming/query-streamer.ts +662 -0
- package/src/streaming/response-streaming.ts +557 -0
- package/src/types/branded.ts +1075 -0
- package/src/types/branded.ts.backup +273 -0
- package/src/types/utilities.ts +1023 -0
- package/src/types/wasm.d.ts +30 -0
- package/src/validation/typed-errors.test.ts +420 -0
- package/src/wal/replay-engine.ts +1264 -0
- package/src/worker/__mocks__/capnweb.ts +15 -0
- package/src/worker/__mocks__/pglite.data.ts +22 -0
- package/src/worker/__mocks__/pglite.wasm.ts +33 -0
- package/src/worker/auth-rate-limiter.test.ts +272 -0
- package/src/worker/auth-rate-limiter.ts +448 -0
- package/src/worker/auth.security-red.test.ts +1236 -0
- package/src/worker/auth.security.test.ts +822 -0
- package/src/worker/auth.test.ts +469 -0
- package/src/worker/auth.ts +1104 -0
- package/src/worker/cdc-backpressure.test.ts +726 -0
- package/src/worker/cdc-backpressure.ts +866 -0
- package/src/worker/cdc-sse.test.ts +780 -0
- package/src/worker/cdc-sse.ts +728 -0
- package/src/worker/cdc-websocket.ts +1229 -0
- package/src/worker/cdc-ws.test.ts +1009 -0
- package/src/worker/cdc.test.ts +327 -0
- package/src/worker/cdc.ts +289 -0
- package/src/worker/concerns/auth-concern.ts +179 -0
- package/src/worker/concerns/cdc-concern.ts +247 -0
- package/src/worker/concerns/index.ts +58 -0
- package/src/worker/concerns/query-execution-concern.ts +194 -0
- package/src/worker/concerns/storage-orchestration-concern.ts +373 -0
- package/src/worker/discriminated-types.test.ts +280 -0
- package/src/worker/do-auth-manager.ts +257 -0
- package/src/worker/do-decomposition.test.ts +1236 -0
- package/src/worker/do-pglite-manager.ts +302 -0
- package/src/worker/do.test.ts +2254 -0
- package/src/worker/do.ts +1878 -0
- package/src/worker/entry.ts +417 -0
- package/src/worker/errors.ts +285 -0
- package/src/worker/health-check-manager.test.ts +261 -0
- package/src/worker/health-check-manager.ts +231 -0
- package/src/worker/index.ts +389 -0
- package/src/worker/memory-pressure.test.ts +1460 -0
- package/src/worker/memory-pressure.ts +2650 -0
- package/src/worker/migration-manager.ts +582 -0
- package/src/worker/neon-compat.test.ts +332 -0
- package/src/worker/plugin-manager.ts +485 -0
- package/src/worker/postgres.do-rpc.d.ts +76 -0
- package/src/worker/proxy.ts +694 -0
- package/src/worker/query-execution-manager.test.ts +303 -0
- package/src/worker/query-execution-manager.ts +219 -0
- package/src/worker/query-executor.test.ts +282 -0
- package/src/worker/query-executor.ts +560 -0
- package/src/worker/query-stats-manager.ts +229 -0
- package/src/worker/result-handler.test.ts +364 -0
- package/src/worker/result-handler.ts +510 -0
- package/src/worker/routes.test.ts +795 -0
- package/src/worker/routes.ts +650 -0
- package/src/worker/rpc-methods-manager.test.ts +326 -0
- package/src/worker/rpc-methods-manager.ts +276 -0
- package/src/worker/rpc.ts +524 -0
- package/src/worker/schema-version.ts +605 -0
- package/src/worker/session-manager.test.ts +506 -0
- package/src/worker/session-manager.ts +732 -0
- package/src/worker/shutdown-manager.ts +469 -0
- package/src/worker/sql-transform.test.ts +286 -0
- package/src/worker/sql-transform.ts +368 -0
- package/src/worker/supabase-compat.test.ts +621 -0
- package/src/worker/types.test.ts +292 -0
- package/src/worker/types.ts +873 -0
- package/src/worker/user-routes.test.ts +703 -0
- package/src/worker/user-routes.ts +303 -0
- package/src/worker/wal-facade.ts +235 -0
- package/src/worker/wal-r2.test.ts +570 -0
- package/src/worker/wal-r2.ts +930 -0
- package/src/worker/wal-replay.test.ts +845 -0
- package/src/worker/wal-replay.ts +897 -0
- package/src/worker/wal-retention.test.ts +758 -0
- package/src/worker/wal-retention.ts +1075 -0
- package/src/worker/wal.test.ts +618 -0
- package/src/worker/wal.ts +697 -0
- package/src/worker/websocket.test.ts +296 -0
- package/src/worker/websocket.ts +284 -0
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hostname-based Multi-tenant DO Routing
|
|
3
|
+
*
|
|
4
|
+
* Purpose: Route incoming requests to the correct Durable Object based on
|
|
5
|
+
* tenant identification extracted from hostname, path, or headers.
|
|
6
|
+
*
|
|
7
|
+
* This module provides a flexible tenant routing system that supports:
|
|
8
|
+
* - Subdomain-based tenancy (tenant1.app.com)
|
|
9
|
+
* - Path-based tenancy (/tenant1/api/...)
|
|
10
|
+
* - Header-based tenancy (X-Tenant-ID)
|
|
11
|
+
* - Custom extraction functions
|
|
12
|
+
* - Blocked tenant lists
|
|
13
|
+
* - Tenant isolation guarantees
|
|
14
|
+
*/
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Constants
|
|
17
|
+
// =============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Standard HTTP header names used by the tenant router
|
|
20
|
+
*/
|
|
21
|
+
export const HEADERS = {
|
|
22
|
+
/** Header containing the tenant identifier */
|
|
23
|
+
TENANT_ID: 'X-Tenant-ID',
|
|
24
|
+
/** Header containing the correlation/request ID */
|
|
25
|
+
CORRELATION_ID: 'X-Correlation-ID',
|
|
26
|
+
/** Header containing the trace ID for distributed tracing */
|
|
27
|
+
TRACE_ID: 'X-Trace-ID',
|
|
28
|
+
/** Header containing the span ID for distributed tracing */
|
|
29
|
+
SPAN_ID: 'X-Span-ID',
|
|
30
|
+
/** Header containing the parent span ID for distributed tracing */
|
|
31
|
+
PARENT_SPAN_ID: 'X-Parent-Span-ID',
|
|
32
|
+
/** Header indicating whether the trace is sampled */
|
|
33
|
+
TRACE_SAMPLED: 'X-Trace-Sampled',
|
|
34
|
+
};
|
|
35
|
+
export const DEFAULT_HEADER_NAME = HEADERS.TENANT_ID;
|
|
36
|
+
export const DEFAULT_PATH_PREFIX = '/';
|
|
37
|
+
export const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
38
|
+
// Tenant ID validation constants
|
|
39
|
+
const TENANT_ID_MAX_LENGTH = 128;
|
|
40
|
+
// Must start with alphanumeric, followed by alphanumeric, underscore, or hyphen
|
|
41
|
+
const TENANT_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
42
|
+
/**
|
|
43
|
+
* Normalize a path prefix to ensure consistent format.
|
|
44
|
+
* - Ensures path starts with '/'
|
|
45
|
+
* - Removes trailing '/' (except for root '/')
|
|
46
|
+
*
|
|
47
|
+
* @param prefix The path prefix to normalize
|
|
48
|
+
* @returns Normalized path prefix
|
|
49
|
+
*/
|
|
50
|
+
function normalizePathPrefix(prefix) {
|
|
51
|
+
let normalized = prefix;
|
|
52
|
+
if (!normalized.startsWith('/')) {
|
|
53
|
+
normalized = '/' + normalized;
|
|
54
|
+
}
|
|
55
|
+
if (normalized.endsWith('/') && normalized.length > 1) {
|
|
56
|
+
normalized = normalized.slice(0, -1);
|
|
57
|
+
}
|
|
58
|
+
return normalized;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate that a tenant ID is safe and well-formed.
|
|
62
|
+
*
|
|
63
|
+
* Security requirements:
|
|
64
|
+
* - Non-empty and within length limits
|
|
65
|
+
* - Starts with alphanumeric character
|
|
66
|
+
* - Contains only alphanumeric, underscore, or hyphen
|
|
67
|
+
* - No control characters (including null bytes)
|
|
68
|
+
* - No path traversal sequences
|
|
69
|
+
*
|
|
70
|
+
* @param tenantId The tenant ID to validate
|
|
71
|
+
* @returns true if the tenant ID is valid, false otherwise
|
|
72
|
+
*/
|
|
73
|
+
export function isValidTenantId(tenantId) {
|
|
74
|
+
// Check length bounds
|
|
75
|
+
if (tenantId.length === 0 || tenantId.length > TENANT_ID_MAX_LENGTH) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
// Check pattern (alphanumeric start, alphanumeric/underscore/hyphen continuation)
|
|
79
|
+
if (!TENANT_ID_PATTERN.test(tenantId)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
// Check for control characters (ASCII 0-31 and 127)
|
|
83
|
+
for (let i = 0; i < tenantId.length; i++) {
|
|
84
|
+
const charCode = tenantId.charCodeAt(i);
|
|
85
|
+
if (charCode < 32 || charCode === 127) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Preset Extractors
|
|
93
|
+
// =============================================================================
|
|
94
|
+
/**
|
|
95
|
+
* Preset tenant extraction functions
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* // Use preset extractors with createTenantRouter
|
|
100
|
+
* const router = createTenantRouter({
|
|
101
|
+
* doNamespace: env.TENANT_DO,
|
|
102
|
+
* extractTenant: 'subdomain', // Uses extractors.subdomain internally
|
|
103
|
+
* baseDomain: 'myapp.com',
|
|
104
|
+
* })
|
|
105
|
+
*
|
|
106
|
+
* // Or use extractors directly
|
|
107
|
+
* const subdomainExtractor = extractors.subdomain('myapp.com')
|
|
108
|
+
* const tenantId = subdomainExtractor(request) // 'acme' from acme.myapp.com
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export const extractors = {
|
|
112
|
+
/**
|
|
113
|
+
* Extract tenant from subdomain
|
|
114
|
+
* e.g., tenant1.app.com -> tenant1
|
|
115
|
+
*
|
|
116
|
+
* @param baseDomain Optional base domain for proper TLD handling
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const extractor = extractors.subdomain('myapp.com')
|
|
121
|
+
*
|
|
122
|
+
* // acme.myapp.com -> 'acme'
|
|
123
|
+
* // www.myapp.com -> null (apex domain)
|
|
124
|
+
* // myapp.com -> null (apex domain)
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
subdomain: (baseDomain) => (request) => {
|
|
128
|
+
const url = new URL(request.url);
|
|
129
|
+
let hostname = url.hostname.toLowerCase();
|
|
130
|
+
// Handle IP addresses - return null
|
|
131
|
+
if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname)) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
// Remove port if present (for localhost:8787 cases)
|
|
135
|
+
hostname = hostname.split(':')[0] ?? hostname;
|
|
136
|
+
// If baseDomain is provided, use it to determine subdomain
|
|
137
|
+
if (baseDomain) {
|
|
138
|
+
const normalizedBaseDomain = baseDomain.toLowerCase();
|
|
139
|
+
// Check if hostname ends with the base domain
|
|
140
|
+
if (hostname === normalizedBaseDomain) {
|
|
141
|
+
// This is the apex domain
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
if (hostname.endsWith('.' + normalizedBaseDomain)) {
|
|
145
|
+
// Extract subdomain part
|
|
146
|
+
const subdomainPart = hostname.slice(0, -(normalizedBaseDomain.length + 1));
|
|
147
|
+
const segments = subdomainPart.split('.');
|
|
148
|
+
// Handle www prefix
|
|
149
|
+
let firstSegment = segments[0];
|
|
150
|
+
if (firstSegment === 'www' && segments.length > 1) {
|
|
151
|
+
firstSegment = segments[1];
|
|
152
|
+
}
|
|
153
|
+
return firstSegment || null;
|
|
154
|
+
}
|
|
155
|
+
// Hostname doesn't match base domain
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
// Without baseDomain, parse generically
|
|
159
|
+
const parts = hostname.split('.');
|
|
160
|
+
// Handle localhost
|
|
161
|
+
if (parts.length === 1) {
|
|
162
|
+
return null; // Just "localhost" or similar
|
|
163
|
+
}
|
|
164
|
+
// Handle common patterns
|
|
165
|
+
// For two-part domains like "app.com", return null (apex)
|
|
166
|
+
if (parts.length === 2) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
// For three or more parts, first segment is tenant (unless it's www)
|
|
170
|
+
let tenantSegment = parts[0];
|
|
171
|
+
if (tenantSegment === 'www' && parts.length > 3) {
|
|
172
|
+
tenantSegment = parts[1];
|
|
173
|
+
}
|
|
174
|
+
else if (tenantSegment === 'www') {
|
|
175
|
+
return null; // www.app.com is still apex
|
|
176
|
+
}
|
|
177
|
+
return tenantSegment || null;
|
|
178
|
+
},
|
|
179
|
+
/**
|
|
180
|
+
* Extract tenant from URL path
|
|
181
|
+
* e.g., /tenant1/api/users -> tenant1
|
|
182
|
+
*
|
|
183
|
+
* @param prefix Path prefix before tenant segment
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const extractor = extractors.path('/orgs')
|
|
188
|
+
*
|
|
189
|
+
* // /orgs/acme/users -> 'acme'
|
|
190
|
+
* // /orgs/bigcorp/api/data -> 'bigcorp'
|
|
191
|
+
* // /api/users -> null (no match)
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
path: (prefix = '/') => (request) => {
|
|
195
|
+
const url = new URL(request.url);
|
|
196
|
+
let pathname = url.pathname;
|
|
197
|
+
const normalizedPrefix = normalizePathPrefix(prefix);
|
|
198
|
+
// Check if pathname starts with the prefix
|
|
199
|
+
if (normalizedPrefix !== '/' && !pathname.startsWith(normalizedPrefix)) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
// Get the path after the prefix
|
|
203
|
+
let pathAfterPrefix;
|
|
204
|
+
if (normalizedPrefix === '/') {
|
|
205
|
+
pathAfterPrefix = pathname;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
pathAfterPrefix = pathname.slice(normalizedPrefix.length);
|
|
209
|
+
}
|
|
210
|
+
// pathAfterPrefix should now start with / or be empty
|
|
211
|
+
if (!pathAfterPrefix || pathAfterPrefix === '/') {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
// Remove leading slash
|
|
215
|
+
if (pathAfterPrefix.startsWith('/')) {
|
|
216
|
+
pathAfterPrefix = pathAfterPrefix.slice(1);
|
|
217
|
+
}
|
|
218
|
+
// Get the first segment (tenant)
|
|
219
|
+
const slashIndex = pathAfterPrefix.indexOf('/');
|
|
220
|
+
let tenantSegment;
|
|
221
|
+
if (slashIndex === -1) {
|
|
222
|
+
tenantSegment = pathAfterPrefix;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
tenantSegment = pathAfterPrefix.slice(0, slashIndex);
|
|
226
|
+
}
|
|
227
|
+
// Decode URL encoding
|
|
228
|
+
try {
|
|
229
|
+
tenantSegment = decodeURIComponent(tenantSegment);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// If decoding fails, use as-is
|
|
233
|
+
}
|
|
234
|
+
// Return null for empty string
|
|
235
|
+
if (!tenantSegment) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
return tenantSegment;
|
|
239
|
+
},
|
|
240
|
+
/**
|
|
241
|
+
* Extract tenant from HTTP header
|
|
242
|
+
* e.g., X-Tenant-ID: tenant1 -> tenant1
|
|
243
|
+
*
|
|
244
|
+
* @param headerName The header to extract from
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* const extractor = extractors.header('X-Org-ID')
|
|
249
|
+
*
|
|
250
|
+
* // Request with header 'X-Org-ID: acme' -> 'acme'
|
|
251
|
+
* // Request without header -> null
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
header: (headerName = DEFAULT_HEADER_NAME) => (request) => {
|
|
255
|
+
// Headers.get() is case-insensitive per HTTP spec
|
|
256
|
+
const value = request.headers.get(headerName);
|
|
257
|
+
if (value === null) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
// Trim whitespace
|
|
261
|
+
const trimmed = value.trim();
|
|
262
|
+
// Return null for empty string
|
|
263
|
+
if (!trimmed) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
return trimmed;
|
|
267
|
+
},
|
|
268
|
+
/**
|
|
269
|
+
* Try multiple extractors in order
|
|
270
|
+
* Returns first successful extraction
|
|
271
|
+
*
|
|
272
|
+
* @param extractorFns Array of extractors to try
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* // Try subdomain first, then fall back to header
|
|
277
|
+
* const extractor = extractors.combined([
|
|
278
|
+
* extractors.subdomain('myapp.com'),
|
|
279
|
+
* extractors.header('X-Tenant-ID'),
|
|
280
|
+
* ])
|
|
281
|
+
*
|
|
282
|
+
* // acme.myapp.com -> 'acme' (from subdomain)
|
|
283
|
+
* // myapp.com with X-Tenant-ID: bigcorp -> 'bigcorp' (from header)
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
combined: (extractorFns) => async (request) => {
|
|
287
|
+
for (const extractor of extractorFns) {
|
|
288
|
+
const result = await extractor(request);
|
|
289
|
+
if (result !== null) {
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
// =============================================================================
|
|
297
|
+
// Factory Function
|
|
298
|
+
// =============================================================================
|
|
299
|
+
/**
|
|
300
|
+
* Create a new TenantRouter instance
|
|
301
|
+
*
|
|
302
|
+
* @param config Router configuration
|
|
303
|
+
* @returns A configured TenantRouter
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* // Subdomain-based routing
|
|
308
|
+
* const router = createTenantRouter({
|
|
309
|
+
* doNamespace: env.TENANT_DO,
|
|
310
|
+
* extractTenant: 'subdomain',
|
|
311
|
+
* baseDomain: 'myapp.com',
|
|
312
|
+
* })
|
|
313
|
+
*
|
|
314
|
+
* // Path-based routing
|
|
315
|
+
* const router = createTenantRouter({
|
|
316
|
+
* doNamespace: env.TENANT_DO,
|
|
317
|
+
* extractTenant: 'path',
|
|
318
|
+
* pathPrefix: '/api/tenants',
|
|
319
|
+
* })
|
|
320
|
+
*
|
|
321
|
+
* // Header-based routing
|
|
322
|
+
* const router = createTenantRouter({
|
|
323
|
+
* doNamespace: env.TENANT_DO,
|
|
324
|
+
* extractTenant: 'header',
|
|
325
|
+
* headerName: 'X-Org-ID',
|
|
326
|
+
* })
|
|
327
|
+
*
|
|
328
|
+
* // Custom extractor
|
|
329
|
+
* const router = createTenantRouter({
|
|
330
|
+
* doNamespace: env.TENANT_DO,
|
|
331
|
+
* extractTenant: (req) => {
|
|
332
|
+
* const url = new URL(req.url)
|
|
333
|
+
* return url.searchParams.get('tenant')
|
|
334
|
+
* },
|
|
335
|
+
* })
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
export function createTenantRouter(config) {
|
|
339
|
+
const { doNamespace, extractTenant, headerName = DEFAULT_HEADER_NAME, pathPrefix = DEFAULT_PATH_PREFIX, stripTenantFromPath = true, blockedTenants = [], blockedTenantCallback, isBlocked: legacyIsBlockedCallback, // deprecated
|
|
340
|
+
transformTenant, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, errorResponseFormatter, formatError: legacyFormatError, // deprecated
|
|
341
|
+
baseDomain,
|
|
342
|
+
// Nested sub-configs
|
|
343
|
+
observability, rateLimit: _rateLimit, // reserved for future use
|
|
344
|
+
domainCache: _domainCache, // reserved for future use
|
|
345
|
+
// Legacy flat observability options (deprecated)
|
|
346
|
+
metricsCollector: legacyMetricsCollector, logger: legacyLogger, traceContextExtractor: legacyTraceContextExtractor, propagateTraceContext: legacyPropagateTraceContext, } = config;
|
|
347
|
+
// Resolve observability config: prefer nested config, fall back to legacy flat options
|
|
348
|
+
const metricsCollector = observability?.metricsCollector ?? legacyMetricsCollector;
|
|
349
|
+
const logger = observability?.logger ?? legacyLogger;
|
|
350
|
+
const traceContextExtractor = observability?.traceContextExtractor ?? legacyTraceContextExtractor;
|
|
351
|
+
const propagateTraceContext = observability?.propagateTraceContext ?? legacyPropagateTraceContext ?? true;
|
|
352
|
+
// Resolve blocked tenant callback: prefer new name, fall back to legacy
|
|
353
|
+
const isBlockedCallback = blockedTenantCallback ?? legacyIsBlockedCallback;
|
|
354
|
+
// Resolve error formatter: prefer new name, fall back to legacy
|
|
355
|
+
const formatError = errorResponseFormatter ?? legacyFormatError;
|
|
356
|
+
// Build the tenant extractor function
|
|
357
|
+
let tenantExtractor;
|
|
358
|
+
if (typeof extractTenant === 'string') {
|
|
359
|
+
// Preset extractor type
|
|
360
|
+
switch (extractTenant) {
|
|
361
|
+
case 'subdomain':
|
|
362
|
+
tenantExtractor = extractors.subdomain(baseDomain);
|
|
363
|
+
break;
|
|
364
|
+
case 'path':
|
|
365
|
+
tenantExtractor = extractors.path(pathPrefix);
|
|
366
|
+
break;
|
|
367
|
+
case 'header':
|
|
368
|
+
tenantExtractor = extractors.header(headerName);
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
throw new Error(`Invalid extractTenant value: ${extractTenant}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else if (typeof extractTenant === 'function') {
|
|
375
|
+
tenantExtractor = extractTenant;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
throw new Error('extractTenant must be a string or function');
|
|
379
|
+
}
|
|
380
|
+
// Helper to generate correlation ID
|
|
381
|
+
function generateCorrelationId() {
|
|
382
|
+
return crypto.randomUUID();
|
|
383
|
+
}
|
|
384
|
+
// Helper to check if tenant matches a blocked pattern
|
|
385
|
+
function matchesBlockedPattern(tenantId, pattern) {
|
|
386
|
+
if (pattern.endsWith('*')) {
|
|
387
|
+
const prefix = pattern.slice(0, -1);
|
|
388
|
+
return tenantId.startsWith(prefix);
|
|
389
|
+
}
|
|
390
|
+
return tenantId === pattern;
|
|
391
|
+
}
|
|
392
|
+
// Default error formatter
|
|
393
|
+
function defaultFormatError(status, message, correlationId, _tenantId) {
|
|
394
|
+
return new Response(JSON.stringify({
|
|
395
|
+
error: message,
|
|
396
|
+
correlationId,
|
|
397
|
+
}), {
|
|
398
|
+
status,
|
|
399
|
+
headers: {
|
|
400
|
+
'Content-Type': 'application/json',
|
|
401
|
+
[HEADERS.CORRELATION_ID]: correlationId,
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
const errorFormatter = formatError || defaultFormatError;
|
|
406
|
+
// Implementation of the TenantRouter interface
|
|
407
|
+
const router = {
|
|
408
|
+
async extractTenant(request) {
|
|
409
|
+
const url = new URL(request.url);
|
|
410
|
+
const originalHostname = url.hostname;
|
|
411
|
+
// Determine extraction source based on config
|
|
412
|
+
let source = 'custom';
|
|
413
|
+
if (typeof extractTenant === 'string') {
|
|
414
|
+
source = extractTenant;
|
|
415
|
+
}
|
|
416
|
+
// Call the extractor
|
|
417
|
+
let extractionResult = await tenantExtractor(request);
|
|
418
|
+
// Check if it's a full TenantExtractionResult or just a string/null
|
|
419
|
+
if (extractionResult !== null &&
|
|
420
|
+
typeof extractionResult === 'object' &&
|
|
421
|
+
'tenantId' in extractionResult) {
|
|
422
|
+
// It's a full TenantExtractionResult
|
|
423
|
+
return extractionResult;
|
|
424
|
+
}
|
|
425
|
+
// It's a SimpleTenantExtractor result (string | null)
|
|
426
|
+
let tenantId = extractionResult;
|
|
427
|
+
// Apply transformation if configured
|
|
428
|
+
if (tenantId !== null && transformTenant) {
|
|
429
|
+
tenantId = transformTenant(tenantId);
|
|
430
|
+
}
|
|
431
|
+
// Build modified path for path-based extraction
|
|
432
|
+
let modifiedPath;
|
|
433
|
+
if (source === 'path' && tenantId !== null && stripTenantFromPath) {
|
|
434
|
+
let pathname = url.pathname;
|
|
435
|
+
const normalizedPrefix = normalizePathPrefix(pathPrefix);
|
|
436
|
+
// Remove prefix and tenant segment from path
|
|
437
|
+
let pathAfterPrefix;
|
|
438
|
+
if (normalizedPrefix === '/') {
|
|
439
|
+
pathAfterPrefix = pathname;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
pathAfterPrefix = pathname.slice(normalizedPrefix.length);
|
|
443
|
+
}
|
|
444
|
+
// Remove leading slash and tenant segment
|
|
445
|
+
if (pathAfterPrefix.startsWith('/')) {
|
|
446
|
+
pathAfterPrefix = pathAfterPrefix.slice(1);
|
|
447
|
+
}
|
|
448
|
+
const slashIndex = pathAfterPrefix.indexOf('/');
|
|
449
|
+
if (slashIndex === -1) {
|
|
450
|
+
modifiedPath = '/';
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
modifiedPath = pathAfterPrefix.slice(slashIndex);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
tenantId,
|
|
458
|
+
source,
|
|
459
|
+
originalHostname,
|
|
460
|
+
modifiedPath,
|
|
461
|
+
};
|
|
462
|
+
},
|
|
463
|
+
async getTenantId(request) {
|
|
464
|
+
const result = await router.extractTenant(request);
|
|
465
|
+
return result.tenantId;
|
|
466
|
+
},
|
|
467
|
+
async isBlocked(tenantId, request) {
|
|
468
|
+
// Check static blocked list
|
|
469
|
+
for (const pattern of blockedTenants) {
|
|
470
|
+
if (matchesBlockedPattern(tenantId, pattern)) {
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// Check dynamic callback
|
|
475
|
+
if (isBlockedCallback) {
|
|
476
|
+
return await isBlockedCallback(tenantId, request);
|
|
477
|
+
}
|
|
478
|
+
return false;
|
|
479
|
+
},
|
|
480
|
+
getStub(tenantId) {
|
|
481
|
+
const doId = doNamespace.idFromName(tenantId);
|
|
482
|
+
return doNamespace.get(doId);
|
|
483
|
+
},
|
|
484
|
+
async route(request) {
|
|
485
|
+
const correlationId = generateCorrelationId();
|
|
486
|
+
const startTime = Date.now();
|
|
487
|
+
const requestUrl = new URL(request.url);
|
|
488
|
+
// Extract trace context from incoming request
|
|
489
|
+
let traceContext = null;
|
|
490
|
+
if (traceContextExtractor) {
|
|
491
|
+
traceContext = traceContextExtractor(request);
|
|
492
|
+
}
|
|
493
|
+
// Log debug: routing decision starting
|
|
494
|
+
if (logger) {
|
|
495
|
+
logger.debug('Starting tenant routing', {
|
|
496
|
+
correlationId,
|
|
497
|
+
path: requestUrl.pathname,
|
|
498
|
+
method: request.method,
|
|
499
|
+
traceId: traceContext?.traceId,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
let tenantId = null;
|
|
503
|
+
let status = 500;
|
|
504
|
+
try {
|
|
505
|
+
// Extract tenant
|
|
506
|
+
const extraction = await router.extractTenant(request);
|
|
507
|
+
if (extraction.tenantId === null) {
|
|
508
|
+
// Log extraction failure
|
|
509
|
+
if (logger) {
|
|
510
|
+
logger.warn('Tenant extraction failed', {
|
|
511
|
+
correlationId,
|
|
512
|
+
path: requestUrl.pathname,
|
|
513
|
+
method: request.method,
|
|
514
|
+
source: extraction.source,
|
|
515
|
+
hostname: extraction.originalHostname,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
status = 400;
|
|
519
|
+
return errorFormatter(400, 'Tenant identifier not found in request', correlationId);
|
|
520
|
+
}
|
|
521
|
+
tenantId = extraction.tenantId;
|
|
522
|
+
// Log debug: tenant extracted
|
|
523
|
+
if (logger) {
|
|
524
|
+
logger.debug('Tenant routing decision', {
|
|
525
|
+
correlationId,
|
|
526
|
+
tenantId,
|
|
527
|
+
source: extraction.source,
|
|
528
|
+
path: requestUrl.pathname,
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
// Validate tenant ID format - comprehensive security validation
|
|
532
|
+
if (!isValidTenantId(tenantId)) {
|
|
533
|
+
status = 400;
|
|
534
|
+
return errorFormatter(400, 'Invalid tenant identifier format', correlationId);
|
|
535
|
+
}
|
|
536
|
+
// Check if blocked
|
|
537
|
+
if (await router.isBlocked(tenantId, request)) {
|
|
538
|
+
status = 404;
|
|
539
|
+
return errorFormatter(404, 'Not Found', correlationId, tenantId);
|
|
540
|
+
}
|
|
541
|
+
// Get DO stub
|
|
542
|
+
const stub = router.getStub(tenantId);
|
|
543
|
+
// If path-based and stripping tenant, use modified path
|
|
544
|
+
if (extraction.source === 'path' && stripTenantFromPath && extraction.modifiedPath) {
|
|
545
|
+
requestUrl.pathname = extraction.modifiedPath;
|
|
546
|
+
}
|
|
547
|
+
// Clone headers and add tenant ID
|
|
548
|
+
const headers = new Headers(request.headers);
|
|
549
|
+
headers.set(HEADERS.TENANT_ID, tenantId);
|
|
550
|
+
headers.set(HEADERS.CORRELATION_ID, correlationId);
|
|
551
|
+
// Handle trace context propagation
|
|
552
|
+
if (propagateTraceContext && traceContext) {
|
|
553
|
+
// Propagate trace context headers
|
|
554
|
+
headers.set(HEADERS.TRACE_ID, traceContext.traceId);
|
|
555
|
+
headers.set(HEADERS.SPAN_ID, traceContext.spanId);
|
|
556
|
+
if (traceContext.parentSpanId) {
|
|
557
|
+
headers.set(HEADERS.PARENT_SPAN_ID, traceContext.parentSpanId);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
else if (!propagateTraceContext) {
|
|
561
|
+
// Remove trace context headers when propagation is disabled
|
|
562
|
+
headers.delete(HEADERS.TRACE_ID);
|
|
563
|
+
headers.delete(HEADERS.SPAN_ID);
|
|
564
|
+
headers.delete(HEADERS.PARENT_SPAN_ID);
|
|
565
|
+
headers.delete(HEADERS.TRACE_SAMPLED);
|
|
566
|
+
}
|
|
567
|
+
// Create new request with modified URL and headers
|
|
568
|
+
const forwardedRequest = new Request(requestUrl.toString(), {
|
|
569
|
+
method: request.method,
|
|
570
|
+
headers,
|
|
571
|
+
body: request.body,
|
|
572
|
+
// @ts-expect-error - duplex is needed for streaming bodies
|
|
573
|
+
duplex: request.body ? 'half' : undefined,
|
|
574
|
+
});
|
|
575
|
+
// Forward to DO with timeout
|
|
576
|
+
const controller = new AbortController();
|
|
577
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
578
|
+
const doStartTime = Date.now();
|
|
579
|
+
try {
|
|
580
|
+
const response = await stub.fetch(forwardedRequest, {
|
|
581
|
+
signal: controller.signal,
|
|
582
|
+
});
|
|
583
|
+
clearTimeout(timeoutId);
|
|
584
|
+
const doResponseTimeMs = Date.now() - doStartTime;
|
|
585
|
+
const routingLatencyMs = Date.now() - startTime;
|
|
586
|
+
status = response.status;
|
|
587
|
+
// Emit metrics
|
|
588
|
+
if (metricsCollector) {
|
|
589
|
+
metricsCollector.incrementRequestCount(tenantId);
|
|
590
|
+
metricsCollector.recordLatency(tenantId, routingLatencyMs);
|
|
591
|
+
metricsCollector.recordDoResponseTime(tenantId, doResponseTimeMs);
|
|
592
|
+
metricsCollector.recordRequest({
|
|
593
|
+
tenantId,
|
|
594
|
+
method: request.method,
|
|
595
|
+
path: requestUrl.pathname,
|
|
596
|
+
status: response.status,
|
|
597
|
+
routingLatencyMs,
|
|
598
|
+
doResponseTimeMs,
|
|
599
|
+
timestamp: startTime,
|
|
600
|
+
correlationId,
|
|
601
|
+
traceId: traceContext?.traceId,
|
|
602
|
+
spanId: traceContext?.spanId,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
return response;
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
clearTimeout(timeoutId);
|
|
609
|
+
if (error instanceof Error) {
|
|
610
|
+
if (error.name === 'AbortError') {
|
|
611
|
+
throw new TenantTimeoutError(tenantId, requestTimeoutMs);
|
|
612
|
+
}
|
|
613
|
+
throw new TenantUnavailableError(tenantId, error);
|
|
614
|
+
}
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
const routingLatencyMs = Date.now() - startTime;
|
|
620
|
+
// Emit error metrics
|
|
621
|
+
if (metricsCollector && tenantId) {
|
|
622
|
+
metricsCollector.incrementRequestCount(tenantId);
|
|
623
|
+
metricsCollector.recordLatency(tenantId, routingLatencyMs);
|
|
624
|
+
metricsCollector.recordRequest({
|
|
625
|
+
tenantId,
|
|
626
|
+
method: request.method,
|
|
627
|
+
path: requestUrl.pathname,
|
|
628
|
+
status,
|
|
629
|
+
routingLatencyMs,
|
|
630
|
+
doResponseTimeMs: 0,
|
|
631
|
+
timestamp: startTime,
|
|
632
|
+
correlationId,
|
|
633
|
+
traceId: traceContext?.traceId,
|
|
634
|
+
spanId: traceContext?.spanId,
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
if (error instanceof TenantNotFoundError) {
|
|
638
|
+
return errorFormatter(400, 'Tenant identifier not found in request', correlationId);
|
|
639
|
+
}
|
|
640
|
+
if (error instanceof TenantBlockedError) {
|
|
641
|
+
return errorFormatter(404, 'Not Found', correlationId, error.tenantId);
|
|
642
|
+
}
|
|
643
|
+
if (error instanceof InvalidTenantIdError) {
|
|
644
|
+
return errorFormatter(400, 'Invalid tenant identifier format', correlationId);
|
|
645
|
+
}
|
|
646
|
+
if (error instanceof TenantTimeoutError) {
|
|
647
|
+
return errorFormatter(504, 'Gateway Timeout', correlationId, error.tenantId);
|
|
648
|
+
}
|
|
649
|
+
if (error instanceof TenantUnavailableError) {
|
|
650
|
+
return errorFormatter(502, 'Bad Gateway', correlationId, error.tenantId);
|
|
651
|
+
}
|
|
652
|
+
// Generic error - don't expose details
|
|
653
|
+
return errorFormatter(500, 'Internal Server Error', correlationId);
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
async routeWithResult(request) {
|
|
657
|
+
const startTimestamp = Date.now();
|
|
658
|
+
const correlationId = generateCorrelationId();
|
|
659
|
+
// Extract tenant with timing
|
|
660
|
+
const extractionStartTime = Date.now();
|
|
661
|
+
const extraction = await router.extractTenant(request);
|
|
662
|
+
const extractionTimeMs = Date.now() - extractionStartTime;
|
|
663
|
+
if (extraction.tenantId === null) {
|
|
664
|
+
throw new TenantNotFoundError('Tenant identifier not found in request', request);
|
|
665
|
+
}
|
|
666
|
+
const tenantId = extraction.tenantId;
|
|
667
|
+
// Validate tenant ID format - comprehensive security validation
|
|
668
|
+
if (!isValidTenantId(tenantId)) {
|
|
669
|
+
throw new InvalidTenantIdError(tenantId);
|
|
670
|
+
}
|
|
671
|
+
// Check if blocked
|
|
672
|
+
if (await router.isBlocked(tenantId, request)) {
|
|
673
|
+
throw new TenantBlockedError(tenantId);
|
|
674
|
+
}
|
|
675
|
+
// Get DO stub and ID
|
|
676
|
+
const doId = doNamespace.idFromName(tenantId);
|
|
677
|
+
const stub = doNamespace.get(doId);
|
|
678
|
+
// Build forwarded request
|
|
679
|
+
const url = new URL(request.url);
|
|
680
|
+
// If path-based and stripping tenant, use modified path
|
|
681
|
+
if (extraction.source === 'path' && stripTenantFromPath && extraction.modifiedPath) {
|
|
682
|
+
url.pathname = extraction.modifiedPath;
|
|
683
|
+
}
|
|
684
|
+
// Clone headers and add tenant ID
|
|
685
|
+
const headers = new Headers(request.headers);
|
|
686
|
+
headers.set(HEADERS.TENANT_ID, tenantId);
|
|
687
|
+
headers.set(HEADERS.CORRELATION_ID, correlationId);
|
|
688
|
+
// Create new request with modified URL and headers
|
|
689
|
+
const forwardedRequest = new Request(url.toString(), {
|
|
690
|
+
method: request.method,
|
|
691
|
+
headers,
|
|
692
|
+
body: request.body,
|
|
693
|
+
// @ts-expect-error - duplex is needed for streaming bodies
|
|
694
|
+
duplex: request.body ? 'half' : undefined,
|
|
695
|
+
});
|
|
696
|
+
// Forward to DO with timeout
|
|
697
|
+
const controller = new AbortController();
|
|
698
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
699
|
+
const routingStartTime = Date.now();
|
|
700
|
+
try {
|
|
701
|
+
const response = await stub.fetch(forwardedRequest, {
|
|
702
|
+
signal: controller.signal,
|
|
703
|
+
});
|
|
704
|
+
clearTimeout(timeoutId);
|
|
705
|
+
const routingTimeMs = Date.now() - routingStartTime;
|
|
706
|
+
const totalTimeMs = Date.now() - startTimestamp;
|
|
707
|
+
return {
|
|
708
|
+
response,
|
|
709
|
+
routingMetadata: {
|
|
710
|
+
extractorType: extraction.source,
|
|
711
|
+
doId: doId.toString(),
|
|
712
|
+
},
|
|
713
|
+
timing: {
|
|
714
|
+
extractionTimeMs,
|
|
715
|
+
routingTimeMs,
|
|
716
|
+
totalTimeMs,
|
|
717
|
+
startTimestamp,
|
|
718
|
+
},
|
|
719
|
+
tenantContext: {
|
|
720
|
+
tenantId,
|
|
721
|
+
source: extraction.source,
|
|
722
|
+
metadata: extraction.metadata,
|
|
723
|
+
},
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
catch (error) {
|
|
727
|
+
clearTimeout(timeoutId);
|
|
728
|
+
if (error instanceof Error) {
|
|
729
|
+
if (error.name === 'AbortError') {
|
|
730
|
+
throw new TenantTimeoutError(tenantId, requestTimeoutMs);
|
|
731
|
+
}
|
|
732
|
+
throw new TenantUnavailableError(tenantId, error);
|
|
733
|
+
}
|
|
734
|
+
throw error;
|
|
735
|
+
}
|
|
736
|
+
},
|
|
737
|
+
};
|
|
738
|
+
return router;
|
|
739
|
+
}
|
|
740
|
+
// =============================================================================
|
|
741
|
+
// Error Types
|
|
742
|
+
// =============================================================================
|
|
743
|
+
/**
|
|
744
|
+
* Error thrown when tenant cannot be identified
|
|
745
|
+
*/
|
|
746
|
+
export class TenantNotFoundError extends Error {
|
|
747
|
+
request;
|
|
748
|
+
constructor(message = 'Tenant identifier not found in request', request) {
|
|
749
|
+
super(message);
|
|
750
|
+
this.request = request;
|
|
751
|
+
this.name = 'TenantNotFoundError';
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Error thrown when tenant is blocked
|
|
756
|
+
*/
|
|
757
|
+
export class TenantBlockedError extends Error {
|
|
758
|
+
tenantId;
|
|
759
|
+
constructor(tenantId, message = 'Tenant is blocked') {
|
|
760
|
+
super(message);
|
|
761
|
+
this.tenantId = tenantId;
|
|
762
|
+
this.name = 'TenantBlockedError';
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Error thrown when tenant ID format is invalid
|
|
767
|
+
*/
|
|
768
|
+
export class InvalidTenantIdError extends Error {
|
|
769
|
+
tenantId;
|
|
770
|
+
constructor(tenantId, message = 'Invalid tenant identifier format') {
|
|
771
|
+
super(message);
|
|
772
|
+
this.tenantId = tenantId;
|
|
773
|
+
this.name = 'InvalidTenantIdError';
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Error thrown when DO request times out
|
|
778
|
+
*/
|
|
779
|
+
export class TenantTimeoutError extends Error {
|
|
780
|
+
tenantId;
|
|
781
|
+
timeoutMs;
|
|
782
|
+
constructor(tenantId, timeoutMs, message = 'Tenant DO request timed out') {
|
|
783
|
+
super(message);
|
|
784
|
+
this.tenantId = tenantId;
|
|
785
|
+
this.timeoutMs = timeoutMs;
|
|
786
|
+
this.name = 'TenantTimeoutError';
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Error thrown when DO is unreachable
|
|
791
|
+
*/
|
|
792
|
+
export class TenantUnavailableError extends Error {
|
|
793
|
+
tenantId;
|
|
794
|
+
cause;
|
|
795
|
+
constructor(tenantId, cause, message = 'Tenant DO is unavailable') {
|
|
796
|
+
super(message);
|
|
797
|
+
this.tenantId = tenantId;
|
|
798
|
+
this.cause = cause;
|
|
799
|
+
this.name = 'TenantUnavailableError';
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* In-memory rate limiter for per-tenant request tracking
|
|
804
|
+
*/
|
|
805
|
+
export class TenantRateLimiter {
|
|
806
|
+
state = new Map();
|
|
807
|
+
maxRequests;
|
|
808
|
+
windowMs;
|
|
809
|
+
bypassTenants;
|
|
810
|
+
bypassCallback;
|
|
811
|
+
constructor(config) {
|
|
812
|
+
this.maxRequests = config.maxRequests;
|
|
813
|
+
this.windowMs = config.windowMs ?? 60_000;
|
|
814
|
+
this.bypassTenants = new Set(config.bypassTenants ?? []);
|
|
815
|
+
this.bypassCallback = config.bypassCallback;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Check if a request should be allowed for the given tenant
|
|
819
|
+
*/
|
|
820
|
+
async check(tenantId, request) {
|
|
821
|
+
// Periodic cleanup of expired entries (1% chance per request)
|
|
822
|
+
if (Math.random() < 0.01) {
|
|
823
|
+
this.cleanupExpiredEntries();
|
|
824
|
+
}
|
|
825
|
+
// Check bypass list first
|
|
826
|
+
if (this.bypassTenants.has(tenantId)) {
|
|
827
|
+
return {
|
|
828
|
+
allowed: true,
|
|
829
|
+
currentCount: 0,
|
|
830
|
+
maxRequests: this.maxRequests,
|
|
831
|
+
retryAfterSeconds: 0,
|
|
832
|
+
bypassed: true,
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
// Check bypass callback
|
|
836
|
+
if (this.bypassCallback) {
|
|
837
|
+
const shouldBypass = await this.bypassCallback(tenantId, request);
|
|
838
|
+
if (shouldBypass) {
|
|
839
|
+
return {
|
|
840
|
+
allowed: true,
|
|
841
|
+
currentCount: 0,
|
|
842
|
+
maxRequests: this.maxRequests,
|
|
843
|
+
retryAfterSeconds: 0,
|
|
844
|
+
bypassed: true,
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const now = Date.now();
|
|
849
|
+
let tenantState = this.state.get(tenantId);
|
|
850
|
+
// Initialize or reset window if expired
|
|
851
|
+
if (!tenantState || now - tenantState.windowStart >= this.windowMs) {
|
|
852
|
+
tenantState = {
|
|
853
|
+
requestCount: 0,
|
|
854
|
+
windowStart: now,
|
|
855
|
+
};
|
|
856
|
+
this.state.set(tenantId, tenantState);
|
|
857
|
+
}
|
|
858
|
+
// Calculate retry-after
|
|
859
|
+
const windowEnd = tenantState.windowStart + this.windowMs;
|
|
860
|
+
const retryAfterSeconds = Math.ceil((windowEnd - now) / 1000);
|
|
861
|
+
// Check if limit exceeded
|
|
862
|
+
if (tenantState.requestCount >= this.maxRequests) {
|
|
863
|
+
return {
|
|
864
|
+
allowed: false,
|
|
865
|
+
currentCount: tenantState.requestCount,
|
|
866
|
+
maxRequests: this.maxRequests,
|
|
867
|
+
retryAfterSeconds,
|
|
868
|
+
bypassed: false,
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
// Increment and allow
|
|
872
|
+
tenantState.requestCount++;
|
|
873
|
+
return {
|
|
874
|
+
allowed: true,
|
|
875
|
+
currentCount: tenantState.requestCount,
|
|
876
|
+
maxRequests: this.maxRequests,
|
|
877
|
+
retryAfterSeconds,
|
|
878
|
+
bypassed: false,
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Get the current state for a tenant (for testing/debugging)
|
|
883
|
+
*/
|
|
884
|
+
getState(tenantId) {
|
|
885
|
+
return this.state.get(tenantId);
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Reset rate limit state for a tenant
|
|
889
|
+
*/
|
|
890
|
+
reset(tenantId) {
|
|
891
|
+
this.state.delete(tenantId);
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Reset all rate limit state
|
|
895
|
+
*/
|
|
896
|
+
resetAll() {
|
|
897
|
+
this.state.clear();
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Clean up expired entries from the rate limit state map
|
|
901
|
+
* Removes entries that are 2x past their window to prevent unbounded memory growth
|
|
902
|
+
*/
|
|
903
|
+
cleanupExpiredEntries() {
|
|
904
|
+
const now = Date.now();
|
|
905
|
+
for (const [tenantId, state] of this.state.entries()) {
|
|
906
|
+
// Remove entries that are 2x past their window
|
|
907
|
+
if (now - state.windowStart >= this.windowMs * 2) {
|
|
908
|
+
this.state.delete(tenantId);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Get the current number of tracked tenants (for monitoring/debugging)
|
|
914
|
+
*/
|
|
915
|
+
getTrackedTenantCount() {
|
|
916
|
+
return this.state.size;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Error thrown when rate limit is exceeded
|
|
921
|
+
*/
|
|
922
|
+
export class TenantRateLimitError extends Error {
|
|
923
|
+
tenantId;
|
|
924
|
+
retryAfterSeconds;
|
|
925
|
+
constructor(tenantId, retryAfterSeconds, message = 'Rate limit exceeded') {
|
|
926
|
+
super(message);
|
|
927
|
+
this.tenantId = tenantId;
|
|
928
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
929
|
+
this.name = 'TenantRateLimitError';
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Create a new domain mapping cache
|
|
934
|
+
*
|
|
935
|
+
* @param config Cache configuration
|
|
936
|
+
* @returns A DomainMappingCache instance
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```typescript
|
|
940
|
+
* const cache = createDomainMappingCache({ ttlMs: 300000 }) // 5 minute TTL
|
|
941
|
+
*
|
|
942
|
+
* // Set a mapping
|
|
943
|
+
* cache.set('custom.example.com', 'tenant1')
|
|
944
|
+
*
|
|
945
|
+
* // Get a mapping (returns null if expired or not found)
|
|
946
|
+
* const entry = cache.get('custom.example.com')
|
|
947
|
+
* if (entry) {
|
|
948
|
+
* console.log(entry.tenantId) // 'tenant1'
|
|
949
|
+
* }
|
|
950
|
+
*
|
|
951
|
+
* // Warm cache on startup
|
|
952
|
+
* cache.warm({
|
|
953
|
+
* 'acme.com': 'acme-inc',
|
|
954
|
+
* 'bigcorp.io': 'bigcorp',
|
|
955
|
+
* })
|
|
956
|
+
*
|
|
957
|
+
* // Invalidate on config change
|
|
958
|
+
* cache.invalidate('acme.com')
|
|
959
|
+
* // or invalidate all
|
|
960
|
+
* cache.invalidateAll()
|
|
961
|
+
* ```
|
|
962
|
+
*/
|
|
963
|
+
export function createDomainMappingCache(config) {
|
|
964
|
+
const { ttlMs, maxEntries = 10000 } = config;
|
|
965
|
+
const cache = new Map();
|
|
966
|
+
let hits = 0;
|
|
967
|
+
let misses = 0;
|
|
968
|
+
let invalidations = 0;
|
|
969
|
+
// Helper to check if an entry is expired
|
|
970
|
+
function isExpired(entry) {
|
|
971
|
+
return Date.now() - entry.cachedAt > ttlMs;
|
|
972
|
+
}
|
|
973
|
+
// Helper to evict oldest entries if over capacity
|
|
974
|
+
function evictIfNeeded() {
|
|
975
|
+
if (cache.size <= maxEntries)
|
|
976
|
+
return;
|
|
977
|
+
// Find and remove oldest entries
|
|
978
|
+
const entries = Array.from(cache.entries());
|
|
979
|
+
entries.sort((a, b) => a[1].cachedAt - b[1].cachedAt);
|
|
980
|
+
const toRemove = entries.slice(0, cache.size - maxEntries);
|
|
981
|
+
for (const [key] of toRemove) {
|
|
982
|
+
cache.delete(key);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return {
|
|
986
|
+
get(domain) {
|
|
987
|
+
const normalizedDomain = domain.toLowerCase();
|
|
988
|
+
const entry = cache.get(normalizedDomain);
|
|
989
|
+
if (!entry) {
|
|
990
|
+
misses++;
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
if (isExpired(entry)) {
|
|
994
|
+
cache.delete(normalizedDomain);
|
|
995
|
+
misses++;
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
hits++;
|
|
999
|
+
return entry;
|
|
1000
|
+
},
|
|
1001
|
+
set(domain, tenantId, metadata) {
|
|
1002
|
+
const normalizedDomain = domain.toLowerCase();
|
|
1003
|
+
cache.set(normalizedDomain, {
|
|
1004
|
+
tenantId,
|
|
1005
|
+
cachedAt: Date.now(),
|
|
1006
|
+
metadata,
|
|
1007
|
+
});
|
|
1008
|
+
evictIfNeeded();
|
|
1009
|
+
},
|
|
1010
|
+
invalidate(domain) {
|
|
1011
|
+
const normalizedDomain = domain.toLowerCase();
|
|
1012
|
+
if (cache.delete(normalizedDomain)) {
|
|
1013
|
+
invalidations++;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
invalidateAll() {
|
|
1017
|
+
const count = cache.size;
|
|
1018
|
+
cache.clear();
|
|
1019
|
+
invalidations += count;
|
|
1020
|
+
},
|
|
1021
|
+
has(domain) {
|
|
1022
|
+
const normalizedDomain = domain.toLowerCase();
|
|
1023
|
+
const entry = cache.get(normalizedDomain);
|
|
1024
|
+
if (!entry)
|
|
1025
|
+
return false;
|
|
1026
|
+
if (isExpired(entry)) {
|
|
1027
|
+
cache.delete(normalizedDomain);
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
return true;
|
|
1031
|
+
},
|
|
1032
|
+
warm(mappings) {
|
|
1033
|
+
const now = Date.now();
|
|
1034
|
+
for (const [domain, tenantId] of Object.entries(mappings)) {
|
|
1035
|
+
const normalizedDomain = domain.toLowerCase();
|
|
1036
|
+
cache.set(normalizedDomain, {
|
|
1037
|
+
tenantId,
|
|
1038
|
+
cachedAt: now,
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
evictIfNeeded();
|
|
1042
|
+
},
|
|
1043
|
+
size() {
|
|
1044
|
+
return cache.size;
|
|
1045
|
+
},
|
|
1046
|
+
stats() {
|
|
1047
|
+
return {
|
|
1048
|
+
hits,
|
|
1049
|
+
misses,
|
|
1050
|
+
size: cache.size,
|
|
1051
|
+
invalidations,
|
|
1052
|
+
};
|
|
1053
|
+
},
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
//# sourceMappingURL=tenant-router.js.map
|