@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,1104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication middleware for PostgresDO Worker routes
|
|
3
|
+
* Integrates with oauth.do for token validation and user-scoped database access
|
|
4
|
+
*
|
|
5
|
+
* Security features:
|
|
6
|
+
* - JWT structure validation (3 segments)
|
|
7
|
+
* - Algorithm validation (rejects alg:none)
|
|
8
|
+
* - Token expiration checking (exp/nbf claims)
|
|
9
|
+
* - Empty signature rejection
|
|
10
|
+
* - Rate limiting for auth failures
|
|
11
|
+
* - SQL injection prevention in database IDs
|
|
12
|
+
* - Token length limits (DoS prevention)
|
|
13
|
+
*/
|
|
14
|
+
import type { Context, Next, MiddlewareHandler } from 'hono'
|
|
15
|
+
|
|
16
|
+
// Re-export Env for external use
|
|
17
|
+
export type { Env } from './types'
|
|
18
|
+
import {
|
|
19
|
+
TokenCache,
|
|
20
|
+
type TokenCacheConfig,
|
|
21
|
+
type CacheStats,
|
|
22
|
+
// Re-export shared auth types and utilities
|
|
23
|
+
type AuthenticatedUser,
|
|
24
|
+
type AuthTokenValidationResult as TokenValidationResult,
|
|
25
|
+
extractBearerToken,
|
|
26
|
+
generateDatabaseId as sharedGenerateDatabaseId,
|
|
27
|
+
validateToken as sharedValidateToken,
|
|
28
|
+
DEFAULT_OAUTH_URL,
|
|
29
|
+
DEFAULT_TOKEN_CACHE_TTL,
|
|
30
|
+
} from '@dotdo/postgres-shared'
|
|
31
|
+
|
|
32
|
+
// Re-export for backwards compatibility
|
|
33
|
+
export type { AuthenticatedUser, TokenValidationResult }
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Security Constants
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Maximum allowed JWT token length in bytes.
|
|
41
|
+
*
|
|
42
|
+
* @security Prevents DoS attacks via oversized tokens that could exhaust memory
|
|
43
|
+
* or CPU during parsing. 8KB is generous for legitimate JWTs while
|
|
44
|
+
* blocking maliciously large payloads.
|
|
45
|
+
*
|
|
46
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7519 - JWT specification
|
|
47
|
+
*/
|
|
48
|
+
const MAX_TOKEN_LENGTH = 8192
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Maximum allowed clock skew between server and token issuer in seconds.
|
|
52
|
+
*
|
|
53
|
+
* @security Allows for reasonable time differences between systems while
|
|
54
|
+
* preventing replay attacks with expired tokens. 60 seconds is
|
|
55
|
+
* standard practice for distributed systems.
|
|
56
|
+
*
|
|
57
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4 - exp claim
|
|
58
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5 - nbf claim
|
|
59
|
+
*/
|
|
60
|
+
const MAX_CLOCK_SKEW_SECONDS = 60
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Time window for rate limiting in milliseconds (1 minute).
|
|
64
|
+
*
|
|
65
|
+
* @security Sliding window for tracking authentication failures per token prefix.
|
|
66
|
+
* Balances security (blocking brute force) with usability (not too short).
|
|
67
|
+
*/
|
|
68
|
+
const RATE_LIMIT_WINDOW_MS = 60000
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Maximum authentication failures allowed per rate limit window.
|
|
72
|
+
*
|
|
73
|
+
* @security Prevents brute force and credential stuffing attacks. 10 failures
|
|
74
|
+
* per minute is strict enough to stop automated attacks while allowing
|
|
75
|
+
* for legitimate user errors.
|
|
76
|
+
*/
|
|
77
|
+
const RATE_LIMIT_MAX_FAILURES = 10
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Prefix for rate limit tracking keys.
|
|
81
|
+
*
|
|
82
|
+
* @security Uses token prefix (first 20 chars) to prevent attackers from
|
|
83
|
+
* evading rate limits by rotating tokens while keeping signature.
|
|
84
|
+
*/
|
|
85
|
+
const RATE_LIMIT_KEY_PREFIX = 'token:'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Number of token characters used for rate limit key generation.
|
|
89
|
+
*
|
|
90
|
+
* @security 20 characters is enough to identify unique tokens without
|
|
91
|
+
* storing full tokens in memory for rate limiting.
|
|
92
|
+
*/
|
|
93
|
+
const RATE_LIMIT_KEY_LENGTH = 20
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Maximum number of rate limit entries to store in memory.
|
|
97
|
+
*
|
|
98
|
+
* @security Prevents memory exhaustion attacks where an attacker sends requests
|
|
99
|
+
* with many unique token prefixes to grow the Map unboundedly.
|
|
100
|
+
* 10,000 entries at ~100 bytes each = ~1MB memory budget.
|
|
101
|
+
*/
|
|
102
|
+
const RATE_LIMIT_MAX_ENTRIES = 10000
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Interval for cleaning up expired rate limit entries in milliseconds.
|
|
106
|
+
*
|
|
107
|
+
* @security Periodic cleanup prevents memory leaks from expired entries.
|
|
108
|
+
* Every 5 minutes balances cleanup overhead with memory efficiency.
|
|
109
|
+
*/
|
|
110
|
+
const RATE_LIMIT_CLEANUP_INTERVAL_MS = 300000
|
|
111
|
+
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Error Codes - Consistent error response codes
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Standardized error codes for authentication failures.
|
|
118
|
+
* These codes are exposed in API responses to help clients understand failures.
|
|
119
|
+
*/
|
|
120
|
+
export const AUTH_ERROR_CODES = {
|
|
121
|
+
/** No token provided */
|
|
122
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
123
|
+
/** Token failed validation */
|
|
124
|
+
INVALID_TOKEN: 'INVALID_TOKEN',
|
|
125
|
+
/** Too many failed attempts */
|
|
126
|
+
RATE_LIMITED: 'RATE_LIMITED',
|
|
127
|
+
} as const
|
|
128
|
+
|
|
129
|
+
export type AuthErrorCode = (typeof AUTH_ERROR_CODES)[keyof typeof AUTH_ERROR_CODES]
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Standardized error messages for authentication failures.
|
|
133
|
+
* Consistent messages improve security by not leaking implementation details.
|
|
134
|
+
*/
|
|
135
|
+
export const AUTH_ERROR_MESSAGES = {
|
|
136
|
+
[AUTH_ERROR_CODES.UNAUTHORIZED]: 'Missing authentication token',
|
|
137
|
+
[AUTH_ERROR_CODES.INVALID_TOKEN]: 'Invalid authentication token',
|
|
138
|
+
[AUTH_ERROR_CODES.RATE_LIMITED]: 'Too many authentication failures. Please try again later.',
|
|
139
|
+
} as const
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Performs a timing-safe comparison of two strings.
|
|
143
|
+
*
|
|
144
|
+
* @security This function uses constant-time comparison to prevent timing attacks.
|
|
145
|
+
* Timing attacks can leak information about the secret by measuring
|
|
146
|
+
* how long the comparison takes.
|
|
147
|
+
*
|
|
148
|
+
* @param a - First string to compare
|
|
149
|
+
* @param b - Second string to compare
|
|
150
|
+
* @returns true if strings are equal, false otherwise
|
|
151
|
+
*/
|
|
152
|
+
export function timingSafeEqual(a: string, b: string): boolean {
|
|
153
|
+
if (a.length !== b.length) {
|
|
154
|
+
// Still do comparison to prevent timing leaks on length difference
|
|
155
|
+
let result = 0
|
|
156
|
+
for (let i = 0; i < a.length; i++) {
|
|
157
|
+
result |= a.charCodeAt(i) ^ (b.charCodeAt(i % b.length) || 0)
|
|
158
|
+
}
|
|
159
|
+
return false
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let result = 0
|
|
163
|
+
for (let i = 0; i < a.length; i++) {
|
|
164
|
+
result |= a.charCodeAt(i) ^ b.charCodeAt(i)
|
|
165
|
+
}
|
|
166
|
+
return result === 0
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Default Configuration Values
|
|
171
|
+
// ============================================================================
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Default paths that bypass authentication.
|
|
175
|
+
*
|
|
176
|
+
* @security These paths expose minimal information and are required for
|
|
177
|
+
* health checks and load balancer probes. No sensitive data
|
|
178
|
+
* should ever be exposed on these endpoints.
|
|
179
|
+
*/
|
|
180
|
+
const DEFAULT_PUBLIC_PATHS = ['/ping', '/health']
|
|
181
|
+
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Rate Limiting
|
|
184
|
+
// ============================================================================
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Tracks authentication failures within a sliding time window.
|
|
188
|
+
*/
|
|
189
|
+
interface RateLimitEntry {
|
|
190
|
+
/** Number of failures in the current window */
|
|
191
|
+
count: number
|
|
192
|
+
/** Timestamp when the current window started */
|
|
193
|
+
windowStart: number
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* In-memory rate limiter for authentication failures.
|
|
198
|
+
*
|
|
199
|
+
* @security This is a simple sliding window rate limiter. In production with
|
|
200
|
+
* multiple Workers, consider using Durable Objects or external
|
|
201
|
+
* storage for distributed rate limiting.
|
|
202
|
+
*
|
|
203
|
+
* @note Keys are token prefixes, not full tokens, to prevent memory exhaustion
|
|
204
|
+
* while still providing per-token-family rate limiting.
|
|
205
|
+
*
|
|
206
|
+
* Memory bounds:
|
|
207
|
+
* - Max entries: 10,000 (RATE_LIMIT_MAX_ENTRIES)
|
|
208
|
+
* - Periodic cleanup: every 5 minutes (RATE_LIMIT_CLEANUP_INTERVAL_MS)
|
|
209
|
+
* - LRU-style eviction when at capacity
|
|
210
|
+
*/
|
|
211
|
+
const authFailureRateLimiter = new Map<string, RateLimitEntry>()
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Timestamp of the last cleanup operation.
|
|
215
|
+
* Used to track when periodic cleanup should run.
|
|
216
|
+
*/
|
|
217
|
+
let lastCleanupTime = Date.now()
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Performs cleanup of expired rate limit entries.
|
|
221
|
+
* Called lazily during checkRateLimit to avoid needing a timer.
|
|
222
|
+
*
|
|
223
|
+
* @security This prevents memory leaks from accumulated expired entries.
|
|
224
|
+
* Uses lazy cleanup during normal operations instead of a timer
|
|
225
|
+
* to work better with Cloudflare Workers' event-driven model.
|
|
226
|
+
*
|
|
227
|
+
* @returns Number of entries removed
|
|
228
|
+
*/
|
|
229
|
+
function cleanupExpiredRateLimitEntries(): number {
|
|
230
|
+
const now = Date.now()
|
|
231
|
+
let removed = 0
|
|
232
|
+
|
|
233
|
+
// Remove entries older than the rate limit window
|
|
234
|
+
for (const [key, entry] of authFailureRateLimiter) {
|
|
235
|
+
if (now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
236
|
+
authFailureRateLimiter.delete(key)
|
|
237
|
+
removed++
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
lastCleanupTime = now
|
|
242
|
+
return removed
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Evicts oldest entries when rate limiter is at capacity.
|
|
247
|
+
* Uses Map iteration order (insertion order) for LRU-like eviction.
|
|
248
|
+
*
|
|
249
|
+
* @security Prevents memory exhaustion from attackers creating many unique
|
|
250
|
+
* rate limit keys. Evicts 10% of entries to amortize eviction cost.
|
|
251
|
+
*/
|
|
252
|
+
function evictOldestEntries(): void {
|
|
253
|
+
// Evict 10% of max entries to amortize eviction overhead
|
|
254
|
+
const evictCount = Math.ceil(RATE_LIMIT_MAX_ENTRIES / 10)
|
|
255
|
+
let evicted = 0
|
|
256
|
+
|
|
257
|
+
for (const key of authFailureRateLimiter.keys()) {
|
|
258
|
+
if (evicted >= evictCount) break
|
|
259
|
+
authFailureRateLimiter.delete(key)
|
|
260
|
+
evicted++
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Checks if a request should be rate limited based on prior failures.
|
|
266
|
+
*
|
|
267
|
+
* Uses a sliding window algorithm:
|
|
268
|
+
* 1. If no entry exists or window expired, start a new window with count=1
|
|
269
|
+
* 2. Otherwise, increment the failure count
|
|
270
|
+
* 3. Return true if count exceeds the threshold
|
|
271
|
+
*
|
|
272
|
+
* Memory safety:
|
|
273
|
+
* - Runs periodic cleanup every RATE_LIMIT_CLEANUP_INTERVAL_MS
|
|
274
|
+
* - Evicts oldest entries when at RATE_LIMIT_MAX_ENTRIES capacity
|
|
275
|
+
*
|
|
276
|
+
* @security Prevents brute force attacks by limiting authentication attempts.
|
|
277
|
+
* Attack vector: Attacker tries many passwords/tokens in rapid succession.
|
|
278
|
+
* Mitigation: After 10 failures in 60 seconds, all requests with that
|
|
279
|
+
* token prefix are blocked.
|
|
280
|
+
*
|
|
281
|
+
* @param key - Rate limit key (typically "token:" + first 20 chars of token)
|
|
282
|
+
* @returns true if the request should be rate limited, false otherwise
|
|
283
|
+
*/
|
|
284
|
+
function checkRateLimit(key: string): boolean {
|
|
285
|
+
const now = Date.now()
|
|
286
|
+
|
|
287
|
+
// Lazy cleanup: run periodically during normal operations
|
|
288
|
+
// This avoids needing a timer which doesn't work well in Workers
|
|
289
|
+
if (now - lastCleanupTime > RATE_LIMIT_CLEANUP_INTERVAL_MS) {
|
|
290
|
+
cleanupExpiredRateLimitEntries()
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Check if we need to evict before adding a new entry
|
|
294
|
+
if (!authFailureRateLimiter.has(key) && authFailureRateLimiter.size >= RATE_LIMIT_MAX_ENTRIES) {
|
|
295
|
+
evictOldestEntries()
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const entry = authFailureRateLimiter.get(key)
|
|
299
|
+
|
|
300
|
+
if (!entry || now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
301
|
+
authFailureRateLimiter.set(key, { count: 1, windowStart: now })
|
|
302
|
+
return false
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
entry.count++
|
|
306
|
+
return entry.count > RATE_LIMIT_MAX_FAILURES
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Clears all rate limit state. Intended for testing only.
|
|
311
|
+
*
|
|
312
|
+
* @security In production, this should never be exposed to external callers.
|
|
313
|
+
* Only exported for use in test cleanup between test cases.
|
|
314
|
+
*/
|
|
315
|
+
export function clearRateLimitState(): void {
|
|
316
|
+
authFailureRateLimiter.clear()
|
|
317
|
+
lastCleanupTime = Date.now()
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get rate limiter statistics for monitoring.
|
|
322
|
+
*
|
|
323
|
+
* @returns Current rate limiter stats including size and last cleanup time
|
|
324
|
+
*/
|
|
325
|
+
export function getRateLimiterStats(): { size: number; maxSize: number; lastCleanupTime: number } {
|
|
326
|
+
return {
|
|
327
|
+
size: authFailureRateLimiter.size,
|
|
328
|
+
maxSize: RATE_LIMIT_MAX_ENTRIES,
|
|
329
|
+
lastCleanupTime,
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ============================================================================
|
|
334
|
+
// JWT Security Validation
|
|
335
|
+
// ============================================================================
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Result of JWT security validation.
|
|
339
|
+
*/
|
|
340
|
+
interface JWTSecurityResult {
|
|
341
|
+
/** Whether the token passed all security checks */
|
|
342
|
+
valid: boolean
|
|
343
|
+
/** Human-readable error message if validation failed */
|
|
344
|
+
error?: string
|
|
345
|
+
/** Decoded JWT header if parsing succeeded */
|
|
346
|
+
header?: Record<string, unknown>
|
|
347
|
+
/** Decoded JWT payload if parsing succeeded */
|
|
348
|
+
payload?: Record<string, unknown>
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Validates a JWT token against security requirements BEFORE cryptographic verification.
|
|
353
|
+
*
|
|
354
|
+
* This function performs structural and timing validation to reject obviously
|
|
355
|
+
* invalid or malicious tokens without incurring the cost of signature verification.
|
|
356
|
+
*
|
|
357
|
+
* @security This function prevents the following attack vectors:
|
|
358
|
+
*
|
|
359
|
+
* 1. **DoS via oversized tokens**: Attackers send huge tokens to exhaust memory/CPU.
|
|
360
|
+
* Mitigation: Reject tokens > 8KB before any parsing.
|
|
361
|
+
*
|
|
362
|
+
* 2. **Algorithm confusion (alg:none)**: Attacker crafts unsigned token with alg:none.
|
|
363
|
+
* Mitigation: Explicitly reject none/None/NONE algorithms.
|
|
364
|
+
* @see https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
|
365
|
+
*
|
|
366
|
+
* 3. **Replay attacks with expired tokens**: Attacker captures and replays old tokens.
|
|
367
|
+
* Mitigation: Check exp claim with 60-second clock skew tolerance.
|
|
368
|
+
*
|
|
369
|
+
* 4. **Future-dated tokens**: Attacker creates tokens with nbf far in the future.
|
|
370
|
+
* Mitigation: Check nbf claim with 60-second clock skew tolerance.
|
|
371
|
+
*
|
|
372
|
+
* 5. **SQL injection via claims**: Attacker embeds SQL in sub claim to attack database.
|
|
373
|
+
* Mitigation: Validate sub claim against SQL injection patterns.
|
|
374
|
+
*
|
|
375
|
+
* 6. **Empty signature bypass**: Attacker sends token with empty signature segment.
|
|
376
|
+
* Mitigation: Explicitly check signature is non-empty.
|
|
377
|
+
*
|
|
378
|
+
* @param token - Raw JWT string from Authorization header
|
|
379
|
+
* @returns Validation result with decoded header/payload if successful
|
|
380
|
+
*
|
|
381
|
+
* @example
|
|
382
|
+
* ```typescript
|
|
383
|
+
* const result = validateJWTSecurity(token)
|
|
384
|
+
* if (!result.valid) {
|
|
385
|
+
* return unauthorized(result.error)
|
|
386
|
+
* }
|
|
387
|
+
* // Proceed to cryptographic verification
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
function validateJWTSecurity(token: string): JWTSecurityResult {
|
|
391
|
+
// SECURITY: Prevent DoS via oversized tokens
|
|
392
|
+
if (token.length > MAX_TOKEN_LENGTH) {
|
|
393
|
+
return { valid: false, error: 'Token exceeds maximum length' }
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// SECURITY: JWT must have exactly 3 segments (header.payload.signature)
|
|
397
|
+
const parts = token.split('.')
|
|
398
|
+
if (parts.length !== 3) {
|
|
399
|
+
return { valid: false, error: 'Invalid JWT structure - must have 3 segments' }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const [headerB64, payloadB64, signature] = parts
|
|
403
|
+
|
|
404
|
+
// SECURITY: Empty segments indicate malformed or crafted tokens
|
|
405
|
+
if (!headerB64 || !payloadB64) {
|
|
406
|
+
return { valid: false, error: 'Invalid JWT - empty header or payload' }
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// SECURITY: Empty signature indicates unsigned token (potential alg:none bypass)
|
|
410
|
+
if (!signature || signature.length === 0) {
|
|
411
|
+
return { valid: false, error: 'Invalid JWT - empty signature' }
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Parse and validate header
|
|
415
|
+
let header: Record<string, unknown>
|
|
416
|
+
try {
|
|
417
|
+
header = JSON.parse(atob(headerB64))
|
|
418
|
+
} catch {
|
|
419
|
+
return { valid: false, error: 'Invalid JWT header encoding' }
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// SECURITY: Explicitly reject alg:none and common case variations
|
|
423
|
+
// This is a critical security check - the alg:none attack is well-documented
|
|
424
|
+
const alg = header.alg
|
|
425
|
+
if (!alg || alg === 'none' || alg === 'None' || alg === 'NONE') {
|
|
426
|
+
return { valid: false, error: 'Invalid algorithm - alg:none not allowed' }
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Parse and validate payload
|
|
430
|
+
let payload: Record<string, unknown>
|
|
431
|
+
try {
|
|
432
|
+
payload = JSON.parse(atob(payloadB64))
|
|
433
|
+
} catch {
|
|
434
|
+
return { valid: false, error: 'Invalid JWT payload encoding' }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const now = Math.floor(Date.now() / 1000)
|
|
438
|
+
|
|
439
|
+
// SECURITY: Validate exp claim type and value
|
|
440
|
+
if (payload.exp !== undefined) {
|
|
441
|
+
// exp must be a finite number (not string, array, object, NaN, or Infinity)
|
|
442
|
+
if (typeof payload.exp !== 'number' || !Number.isFinite(payload.exp)) {
|
|
443
|
+
return { valid: false, error: 'Invalid exp claim - must be a finite number' }
|
|
444
|
+
}
|
|
445
|
+
const exp = payload.exp
|
|
446
|
+
// Reject tokens at or past their expiration (exp === now means expired)
|
|
447
|
+
if (exp + MAX_CLOCK_SKEW_SECONDS <= now) {
|
|
448
|
+
return { valid: false, error: 'Token has expired' }
|
|
449
|
+
}
|
|
450
|
+
// SECURITY: Reject tokens with unreasonably long lifetime (max 7 days)
|
|
451
|
+
const maxFutureExp = now + 7 * 24 * 60 * 60
|
|
452
|
+
if (exp > maxFutureExp) {
|
|
453
|
+
return { valid: false, error: 'Token expiration too far in future' }
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// SECURITY: Validate nbf claim type and value
|
|
458
|
+
if (payload.nbf !== undefined) {
|
|
459
|
+
if (typeof payload.nbf !== 'number' || !Number.isFinite(payload.nbf)) {
|
|
460
|
+
return { valid: false, error: 'Invalid nbf claim - must be a finite number' }
|
|
461
|
+
}
|
|
462
|
+
const nbf = payload.nbf
|
|
463
|
+
// Reject tokens at exactly the skew boundary (strict)
|
|
464
|
+
if (nbf - MAX_CLOCK_SKEW_SECONDS >= now) {
|
|
465
|
+
return { valid: false, error: 'Token not yet valid' }
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// SECURITY: Validate iat claim type and check for future-dated tokens
|
|
470
|
+
if (payload.iat !== undefined) {
|
|
471
|
+
if (typeof payload.iat !== 'number' || !Number.isFinite(payload.iat)) {
|
|
472
|
+
return { valid: false, error: 'Invalid iat claim - must be a finite number' }
|
|
473
|
+
}
|
|
474
|
+
const iat = payload.iat
|
|
475
|
+
// Reject tokens issued too far in the future (clock manipulation)
|
|
476
|
+
if (iat - MAX_CLOCK_SKEW_SECONDS > now) {
|
|
477
|
+
return { valid: false, error: 'Token issued in the future' }
|
|
478
|
+
}
|
|
479
|
+
// SECURITY: Reject tokens with iat set far in the past (lifetime manipulation)
|
|
480
|
+
const maxPastIat = now - 365 * 24 * 60 * 60 // Max 1 year ago
|
|
481
|
+
if (iat < maxPastIat) {
|
|
482
|
+
return { valid: false, error: 'Token issued too long ago' }
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// SECURITY: Validate that exp > nbf when both are present
|
|
487
|
+
if (payload.exp !== undefined && payload.nbf !== undefined) {
|
|
488
|
+
if (payload.exp <= payload.nbf) {
|
|
489
|
+
return { valid: false, error: 'Invalid token - exp must be greater than nbf' }
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// SECURITY: Check sub claim - must be a string if present
|
|
494
|
+
const sub = payload.sub
|
|
495
|
+
if (sub !== undefined && typeof sub !== 'string') {
|
|
496
|
+
return { valid: false, error: 'Invalid sub claim - must be a string' }
|
|
497
|
+
}
|
|
498
|
+
// SECURITY: Check sub claim for SQL injection patterns
|
|
499
|
+
if (typeof sub === 'string' && containsSQLInjection(sub)) {
|
|
500
|
+
return { valid: false, error: 'Invalid user ID - contains forbidden characters' }
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// SECURITY: Check email claim for SQL injection patterns
|
|
504
|
+
const email = payload.email
|
|
505
|
+
if (email !== undefined) {
|
|
506
|
+
if (typeof email !== 'string') {
|
|
507
|
+
return { valid: false, error: 'Invalid email claim - must be a string' }
|
|
508
|
+
}
|
|
509
|
+
if (containsSQLInjection(email)) {
|
|
510
|
+
return { valid: false, error: 'Invalid email - contains forbidden characters' }
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return { valid: true, header, payload }
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* SQL injection patterns to detect in user-controlled input.
|
|
519
|
+
*
|
|
520
|
+
* @security Each pattern targets a specific SQL injection technique:
|
|
521
|
+
*
|
|
522
|
+
* - `--` : SQL comment syntax, used to truncate queries
|
|
523
|
+
* - `;` : Statement terminator, enables multi-statement injection
|
|
524
|
+
* - `'` : String delimiter, enables string escaping attacks
|
|
525
|
+
* - `"` : Identifier delimiter, enables identifier injection
|
|
526
|
+
* - `/*` : Block comment start, used to obfuscate injections
|
|
527
|
+
* - `* /`: Block comment end, paired with start for injection
|
|
528
|
+
* - `DROP/DELETE/INSERT/UPDATE/SELECT/UNION`: Destructive or data-exfiltrating keywords
|
|
529
|
+
*
|
|
530
|
+
* @note This is a defense-in-depth measure. Primary SQL injection prevention
|
|
531
|
+
* should use parameterized queries. This catches malicious data before
|
|
532
|
+
* it reaches the database layer.
|
|
533
|
+
*/
|
|
534
|
+
const SQL_INJECTION_PATTERNS: readonly RegExp[] = [
|
|
535
|
+
/--/, // SQL line comment - truncates query
|
|
536
|
+
/;/, // Statement terminator - allows chaining
|
|
537
|
+
/'/, // String delimiter - escaping attacks
|
|
538
|
+
/"/, // Identifier delimiter - injection
|
|
539
|
+
/\/\*/, // Block comment start - obfuscation
|
|
540
|
+
/\*\//, // Block comment end - obfuscation
|
|
541
|
+
/\bDROP\b/i, // DDL - data destruction
|
|
542
|
+
/\bDELETE\b/i, // DML - data deletion
|
|
543
|
+
/\bINSERT\b/i, // DML - unauthorized inserts
|
|
544
|
+
/\bUPDATE\b/i, // DML - data modification
|
|
545
|
+
/\bSELECT\b/i, // DQL - data exfiltration
|
|
546
|
+
/\bUNION\b/i, // Set operator - query manipulation
|
|
547
|
+
] as const
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Detects potential SQL injection patterns in a string.
|
|
551
|
+
*
|
|
552
|
+
* @security This is a blocklist-based detection. It catches common SQL injection
|
|
553
|
+
* patterns but should NOT be the only line of defense. Always use
|
|
554
|
+
* parameterized queries for database operations.
|
|
555
|
+
*
|
|
556
|
+
* @param value - String to check for SQL injection patterns
|
|
557
|
+
* @returns true if any SQL injection pattern is detected
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```typescript
|
|
561
|
+
* containsSQLInjection("user123") // false - safe
|
|
562
|
+
* containsSQLInjection("admin'--") // true - comment injection
|
|
563
|
+
* containsSQLInjection("1; DROP TABLE") // true - statement chaining
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
566
|
+
function containsSQLInjection(value: string): boolean {
|
|
567
|
+
return SQL_INJECTION_PATTERNS.some((pattern) => pattern.test(value))
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Generates a safe, deterministic database identifier from a user ID.
|
|
572
|
+
*
|
|
573
|
+
* @security This function provides defense-in-depth sanitization before
|
|
574
|
+
* generating the database ID. Even though validateJWTSecurity
|
|
575
|
+
* already checks for SQL injection, this ensures any user ID
|
|
576
|
+
* that reaches the database layer is safe.
|
|
577
|
+
*
|
|
578
|
+
* Sanitization rules:
|
|
579
|
+
* - `--` -> `_` : Prevents SQL comment injection
|
|
580
|
+
* - `/*` -> `_` : Prevents block comment start
|
|
581
|
+
* - `* /`-> `_` : Prevents block comment end
|
|
582
|
+
* - `;` -> `_` : Prevents statement chaining
|
|
583
|
+
* - `'` -> `_` : Prevents string delimiter attacks
|
|
584
|
+
* - `"` -> `_` : Prevents identifier injection
|
|
585
|
+
*
|
|
586
|
+
* @param userId - User identifier from JWT sub claim
|
|
587
|
+
* @returns Safe database identifier in format "user_{sanitized_id}"
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* ```typescript
|
|
591
|
+
* generateDatabaseId("user123") // "user_user123"
|
|
592
|
+
* generateDatabaseId("admin'--") // "user_admin___"
|
|
593
|
+
* generateDatabaseId("test@example.com") // "user_test_example_com"
|
|
594
|
+
* ```
|
|
595
|
+
*/
|
|
596
|
+
export function generateDatabaseId(userId: string): string {
|
|
597
|
+
// SECURITY: Ensure userId is a string (defense-in-depth)
|
|
598
|
+
if (typeof userId !== 'string') {
|
|
599
|
+
throw new Error('Invalid userId - must be a string')
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// SECURITY: Replace all non-alphanumeric characters with underscores
|
|
603
|
+
// This is the most secure approach - only allow safe characters
|
|
604
|
+
const sanitized = userId
|
|
605
|
+
// First handle null bytes and control characters
|
|
606
|
+
.replace(/\x00/g, '_') // Null byte
|
|
607
|
+
.replace(/[\x01-\x1f\x7f]/g, '_') // Control characters
|
|
608
|
+
// Handle common SQL injection patterns
|
|
609
|
+
.replace(/--/g, '_') // SQL comment
|
|
610
|
+
.replace(/\/\*/g, '_') // Block comment start
|
|
611
|
+
.replace(/\*\//g, '_') // Block comment end
|
|
612
|
+
// Handle shell injection patterns
|
|
613
|
+
.replace(/\$/g, '_') // Shell variable
|
|
614
|
+
.replace(/`/g, '_') // Shell backtick
|
|
615
|
+
.replace(/\|/g, '_') // Pipe
|
|
616
|
+
.replace(/&/g, '_') // Background/AND
|
|
617
|
+
// Handle individual dangerous characters
|
|
618
|
+
.replace(/;/g, '_') // Statement terminator / shell separator
|
|
619
|
+
.replace(/'/g, '_') // String delimiter
|
|
620
|
+
.replace(/"/g, '_') // Identifier delimiter
|
|
621
|
+
.replace(/\\/g, '_') // Escape character
|
|
622
|
+
.replace(/\n/g, '_') // Newline
|
|
623
|
+
.replace(/\r/g, '_') // Carriage return
|
|
624
|
+
// Final sanitization: only allow alphanumeric, underscore, hyphen, dot, @
|
|
625
|
+
// Then replace anything else
|
|
626
|
+
.replace(/[^a-zA-Z0-9_\-\.@]/g, '_')
|
|
627
|
+
|
|
628
|
+
return sharedGenerateDatabaseId(sanitized)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Configuration for the token validation cache.
|
|
633
|
+
*
|
|
634
|
+
* @security Caching reduces load on the OAuth provider but introduces a
|
|
635
|
+
* window where revoked tokens may still be accepted. Balance
|
|
636
|
+
* TTL based on your security requirements.
|
|
637
|
+
*/
|
|
638
|
+
export interface AuthTokenCacheConfig {
|
|
639
|
+
/** Maximum number of tokens to cache (default: 1000) */
|
|
640
|
+
maxSize?: number
|
|
641
|
+
/** Cache TTL in milliseconds (default: 60000 = 1 minute) */
|
|
642
|
+
ttl?: number
|
|
643
|
+
/** Interval for cleanup of expired entries in ms (default: 60000) */
|
|
644
|
+
cleanupInterval?: number
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* Configuration options for the authentication middleware.
|
|
649
|
+
*
|
|
650
|
+
* @security Review all options carefully - incorrect configuration can
|
|
651
|
+
* create security vulnerabilities.
|
|
652
|
+
*/
|
|
653
|
+
export interface AuthConfig {
|
|
654
|
+
/**
|
|
655
|
+
* OAuth provider URL for token validation.
|
|
656
|
+
* @default 'https://oauth.do'
|
|
657
|
+
*/
|
|
658
|
+
oauthUrl?: string
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* How long to cache valid tokens in milliseconds.
|
|
662
|
+
* @default 60000 (1 minute)
|
|
663
|
+
* @security Lower values improve security (faster revocation) at cost of
|
|
664
|
+
* more OAuth provider requests. Higher values improve performance
|
|
665
|
+
* but delay token revocation.
|
|
666
|
+
*/
|
|
667
|
+
tokenCacheTTL?: number
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Advanced cache configuration options.
|
|
671
|
+
* Overrides tokenCacheTTL if ttl is specified.
|
|
672
|
+
*/
|
|
673
|
+
cacheConfig?: AuthTokenCacheConfig
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Custom token validation function.
|
|
677
|
+
* Use this to integrate with custom OAuth providers or add additional validation.
|
|
678
|
+
*
|
|
679
|
+
* @security Your validator MUST verify the cryptographic signature.
|
|
680
|
+
* Returning valid:true without signature verification is a
|
|
681
|
+
* critical vulnerability.
|
|
682
|
+
*/
|
|
683
|
+
validateToken?: (token: string) => Promise<TokenValidationResult>
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Allow requests without authentication tokens.
|
|
687
|
+
* @default false
|
|
688
|
+
* @security Only enable if your application explicitly handles anonymous users.
|
|
689
|
+
* Anonymous users should have minimal permissions.
|
|
690
|
+
*/
|
|
691
|
+
allowAnonymous?: boolean
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Paths that bypass authentication entirely.
|
|
695
|
+
* @default ['/ping', '/health']
|
|
696
|
+
* @security Keep this list minimal. Only include endpoints that expose
|
|
697
|
+
* no sensitive data and are needed for infrastructure (health checks).
|
|
698
|
+
*/
|
|
699
|
+
publicPaths?: string[]
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Custom handler for unauthorized requests.
|
|
703
|
+
* Use to customize error responses or redirect to login pages.
|
|
704
|
+
*/
|
|
705
|
+
onUnauthorized?: (c: Context) => Response
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Authentication context available in request handlers.
|
|
710
|
+
*
|
|
711
|
+
* Access via `getAuth(c)` or `c.get('auth')`.
|
|
712
|
+
*/
|
|
713
|
+
export interface AuthContext {
|
|
714
|
+
/** Authenticated user info, null if not authenticated */
|
|
715
|
+
user: AuthenticatedUser | null
|
|
716
|
+
/** Raw JWT token, null if not provided */
|
|
717
|
+
token: string | null
|
|
718
|
+
/** True if user is authenticated */
|
|
719
|
+
isAuthenticated: boolean
|
|
720
|
+
/** Database ID for this user's isolated database, null if not authenticated */
|
|
721
|
+
databaseId: string | null
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Default cache configuration values.
|
|
726
|
+
*
|
|
727
|
+
* @security These defaults balance security and performance:
|
|
728
|
+
* - 1000 entries: Limits memory usage
|
|
729
|
+
* - 60s TTL: Quick revocation while reducing OAuth provider load
|
|
730
|
+
* - 60s cleanup: Regular purging of expired entries
|
|
731
|
+
*/
|
|
732
|
+
const DEFAULT_CACHE_CONFIG: TokenCacheConfig = {
|
|
733
|
+
maxSize: 1000,
|
|
734
|
+
defaultTTL: 60000,
|
|
735
|
+
cleanupInterval: 60000,
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Global token validation cache instance.
|
|
740
|
+
* @internal
|
|
741
|
+
*/
|
|
742
|
+
let tokenCache = new TokenCache(DEFAULT_CACHE_CONFIG)
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Reconfigures the global token cache with new settings.
|
|
746
|
+
* Disposes the existing cache and creates a new one.
|
|
747
|
+
*
|
|
748
|
+
* @param config - New cache configuration
|
|
749
|
+
*
|
|
750
|
+
* @example
|
|
751
|
+
* ```typescript
|
|
752
|
+
* configureTokenCache({
|
|
753
|
+
* maxSize: 5000, // More entries for high-traffic apps
|
|
754
|
+
* defaultTTL: 30000, // 30 second TTL for faster revocation
|
|
755
|
+
* })
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
export function configureTokenCache(config: TokenCacheConfig): void {
|
|
759
|
+
tokenCache.dispose()
|
|
760
|
+
tokenCache = new TokenCache({
|
|
761
|
+
...DEFAULT_CACHE_CONFIG,
|
|
762
|
+
...config,
|
|
763
|
+
})
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Returns current token cache statistics for monitoring.
|
|
768
|
+
*
|
|
769
|
+
* @returns Cache stats including hits, misses, and size
|
|
770
|
+
*/
|
|
771
|
+
export function getTokenCacheStats(): CacheStats {
|
|
772
|
+
return tokenCache.stats
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/**
|
|
776
|
+
* Clears all cached tokens. Intended for testing only.
|
|
777
|
+
*
|
|
778
|
+
* @security In production, avoid clearing the cache as it will cause
|
|
779
|
+
* a thundering herd to the OAuth provider.
|
|
780
|
+
*/
|
|
781
|
+
export function clearTokenCache(): void {
|
|
782
|
+
tokenCache.clear()
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
export { extractBearerToken }
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Creates a Hono middleware handler that validates JWT tokens.
|
|
789
|
+
*
|
|
790
|
+
* This middleware:
|
|
791
|
+
* 1. Skips authentication for public paths
|
|
792
|
+
* 2. Extracts Bearer token from Authorization header
|
|
793
|
+
* 3. Applies rate limiting for failed attempts
|
|
794
|
+
* 4. Validates JWT structure and security claims
|
|
795
|
+
* 5. Validates token with OAuth provider (with caching)
|
|
796
|
+
* 6. Sets authenticated user context
|
|
797
|
+
*
|
|
798
|
+
* @security The middleware applies multiple layers of validation in order
|
|
799
|
+
* of computational cost - cheap checks first (structure, rate limit)
|
|
800
|
+
* before expensive checks (OAuth provider validation).
|
|
801
|
+
*
|
|
802
|
+
* @param config - Authentication configuration options
|
|
803
|
+
* @returns Hono middleware handler
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```typescript
|
|
807
|
+
* const app = new Hono()
|
|
808
|
+
* app.use('*', createAuthMiddleware({
|
|
809
|
+
* publicPaths: ['/ping', '/health', '/docs'],
|
|
810
|
+
* tokenCacheTTL: 30000, // 30 second cache
|
|
811
|
+
* }))
|
|
812
|
+
* ```
|
|
813
|
+
*/
|
|
814
|
+
export function createAuthMiddleware(config: AuthConfig = {}): MiddlewareHandler {
|
|
815
|
+
const {
|
|
816
|
+
oauthUrl = DEFAULT_OAUTH_URL,
|
|
817
|
+
tokenCacheTTL = DEFAULT_TOKEN_CACHE_TTL,
|
|
818
|
+
cacheConfig,
|
|
819
|
+
validateToken,
|
|
820
|
+
allowAnonymous = false,
|
|
821
|
+
publicPaths = DEFAULT_PUBLIC_PATHS,
|
|
822
|
+
onUnauthorized,
|
|
823
|
+
} = config
|
|
824
|
+
|
|
825
|
+
if (cacheConfig) {
|
|
826
|
+
// Build config without undefined values for exactOptionalPropertyTypes
|
|
827
|
+
// Use explicit default values to avoid assigning potentially-undefined optional properties
|
|
828
|
+
const tokenCacheConfig: TokenCacheConfig = {
|
|
829
|
+
maxSize: cacheConfig.maxSize ?? 1000,
|
|
830
|
+
defaultTTL: cacheConfig.ttl ?? tokenCacheTTL,
|
|
831
|
+
cleanupInterval: cacheConfig.cleanupInterval ?? 60000,
|
|
832
|
+
}
|
|
833
|
+
configureTokenCache(tokenCacheConfig)
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
return async (c: Context, next: Next) => {
|
|
837
|
+
const path = new URL(c.req.url).pathname
|
|
838
|
+
if (publicPaths.some((p) => path === p || path.startsWith(p + '/'))) {
|
|
839
|
+
c.set('auth', {
|
|
840
|
+
user: null,
|
|
841
|
+
token: null,
|
|
842
|
+
isAuthenticated: false,
|
|
843
|
+
databaseId: null,
|
|
844
|
+
} as AuthContext)
|
|
845
|
+
return next()
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
const token = extractBearerToken(c.req.raw)
|
|
849
|
+
|
|
850
|
+
if (!token) {
|
|
851
|
+
if (allowAnonymous) {
|
|
852
|
+
c.set('auth', {
|
|
853
|
+
user: null,
|
|
854
|
+
token: null,
|
|
855
|
+
isAuthenticated: false,
|
|
856
|
+
databaseId: null,
|
|
857
|
+
} as AuthContext)
|
|
858
|
+
return next()
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
if (onUnauthorized) {
|
|
862
|
+
return onUnauthorized(c)
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return c.json(
|
|
866
|
+
{
|
|
867
|
+
error: true,
|
|
868
|
+
code: AUTH_ERROR_CODES.UNAUTHORIZED,
|
|
869
|
+
message: 'Missing authentication token',
|
|
870
|
+
},
|
|
871
|
+
401
|
|
872
|
+
)
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// SECURITY: Use token prefix for rate limit key to prevent evasion
|
|
876
|
+
const rateLimitKey = RATE_LIMIT_KEY_PREFIX + token.slice(0, RATE_LIMIT_KEY_LENGTH)
|
|
877
|
+
|
|
878
|
+
if (checkRateLimit(rateLimitKey)) {
|
|
879
|
+
return c.json(
|
|
880
|
+
{
|
|
881
|
+
error: true,
|
|
882
|
+
code: AUTH_ERROR_CODES.RATE_LIMITED,
|
|
883
|
+
message: 'Too many authentication failures. Please try again later.',
|
|
884
|
+
},
|
|
885
|
+
429
|
|
886
|
+
)
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
const securityCheck = validateJWTSecurity(token)
|
|
890
|
+
if (!securityCheck.valid) {
|
|
891
|
+
if (onUnauthorized) {
|
|
892
|
+
return onUnauthorized(c)
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
return c.json(
|
|
896
|
+
{
|
|
897
|
+
error: true,
|
|
898
|
+
code: AUTH_ERROR_CODES.INVALID_TOKEN,
|
|
899
|
+
message: securityCheck.error || 'Token failed security validation',
|
|
900
|
+
},
|
|
901
|
+
401
|
|
902
|
+
)
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
let validationResult = tokenCache.get(token)
|
|
906
|
+
|
|
907
|
+
if (!validationResult) {
|
|
908
|
+
validationResult = validateToken
|
|
909
|
+
? await validateToken(token)
|
|
910
|
+
: await sharedValidateToken(token, { oauthUrl })
|
|
911
|
+
|
|
912
|
+
if (validationResult.valid) {
|
|
913
|
+
tokenCache.set(token, validationResult, tokenCacheTTL)
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
if (!validationResult.valid) {
|
|
918
|
+
if (onUnauthorized) {
|
|
919
|
+
return onUnauthorized(c)
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return c.json(
|
|
923
|
+
{
|
|
924
|
+
error: true,
|
|
925
|
+
code: AUTH_ERROR_CODES.INVALID_TOKEN,
|
|
926
|
+
message: validationResult.error || 'Invalid authentication token',
|
|
927
|
+
},
|
|
928
|
+
401
|
|
929
|
+
)
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const user = validationResult.user!
|
|
933
|
+
c.set('auth', {
|
|
934
|
+
user,
|
|
935
|
+
token,
|
|
936
|
+
isAuthenticated: true,
|
|
937
|
+
databaseId: generateDatabaseId(user.id),
|
|
938
|
+
} as AuthContext)
|
|
939
|
+
|
|
940
|
+
return next()
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Creates a middleware that enforces authentication.
|
|
946
|
+
*
|
|
947
|
+
* Use this on routes that MUST have an authenticated user.
|
|
948
|
+
* For routes that work with optional authentication, use
|
|
949
|
+
* createAuthMiddleware with allowAnonymous:true instead.
|
|
950
|
+
*
|
|
951
|
+
* @returns Hono middleware handler
|
|
952
|
+
*
|
|
953
|
+
* @example
|
|
954
|
+
* ```typescript
|
|
955
|
+
* app.get('/api/private', requireAuth(), (c) => {
|
|
956
|
+
* const user = requireUser(c)
|
|
957
|
+
* return c.json({ userId: user.id })
|
|
958
|
+
* })
|
|
959
|
+
* ```
|
|
960
|
+
*/
|
|
961
|
+
export function requireAuth(): MiddlewareHandler {
|
|
962
|
+
return async (c: Context, next: Next) => {
|
|
963
|
+
const auth = c.get('auth') as AuthContext | undefined
|
|
964
|
+
|
|
965
|
+
if (!auth?.isAuthenticated) {
|
|
966
|
+
return c.json(
|
|
967
|
+
{
|
|
968
|
+
error: true,
|
|
969
|
+
code: AUTH_ERROR_CODES.UNAUTHORIZED,
|
|
970
|
+
message: 'Authentication required',
|
|
971
|
+
},
|
|
972
|
+
401
|
|
973
|
+
)
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
return next()
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Retrieves the authentication context from a request.
|
|
982
|
+
*
|
|
983
|
+
* Returns a default unauthenticated context if none is set.
|
|
984
|
+
* This is safe to call on any route, even those without auth middleware.
|
|
985
|
+
*
|
|
986
|
+
* @param c - Hono context
|
|
987
|
+
* @returns Authentication context
|
|
988
|
+
*
|
|
989
|
+
* @example
|
|
990
|
+
* ```typescript
|
|
991
|
+
* app.get('/api/data', (c) => {
|
|
992
|
+
* const auth = getAuth(c)
|
|
993
|
+
* if (auth.isAuthenticated) {
|
|
994
|
+
* return c.json({ user: auth.user })
|
|
995
|
+
* }
|
|
996
|
+
* return c.json({ guest: true })
|
|
997
|
+
* })
|
|
998
|
+
* ```
|
|
999
|
+
*/
|
|
1000
|
+
export function getAuth(c: Context): AuthContext {
|
|
1001
|
+
const auth = c.get('auth') as AuthContext | undefined
|
|
1002
|
+
return (
|
|
1003
|
+
auth || {
|
|
1004
|
+
user: null,
|
|
1005
|
+
token: null,
|
|
1006
|
+
isAuthenticated: false,
|
|
1007
|
+
databaseId: null,
|
|
1008
|
+
}
|
|
1009
|
+
)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Retrieves the authenticated user or throws an error.
|
|
1014
|
+
*
|
|
1015
|
+
* Use this in routes protected by requireAuth() where you need
|
|
1016
|
+
* the user object and want TypeScript to know it's non-null.
|
|
1017
|
+
*
|
|
1018
|
+
* @param c - Hono context
|
|
1019
|
+
* @returns Authenticated user
|
|
1020
|
+
* @throws Error if user is not authenticated
|
|
1021
|
+
*
|
|
1022
|
+
* @example
|
|
1023
|
+
* ```typescript
|
|
1024
|
+
* app.get('/api/profile', requireAuth(), (c) => {
|
|
1025
|
+
* const user = requireUser(c) // Type: AuthenticatedUser (not null)
|
|
1026
|
+
* return c.json({ email: user.email })
|
|
1027
|
+
* })
|
|
1028
|
+
* ```
|
|
1029
|
+
*/
|
|
1030
|
+
export function requireUser(c: Context): AuthenticatedUser {
|
|
1031
|
+
const auth = getAuth(c)
|
|
1032
|
+
if (!auth.user) {
|
|
1033
|
+
throw new Error('User not authenticated')
|
|
1034
|
+
}
|
|
1035
|
+
return auth.user
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Retrieves the database ID for the authenticated user or throws an error.
|
|
1040
|
+
*
|
|
1041
|
+
* The database ID is a sanitized, deterministic identifier derived from
|
|
1042
|
+
* the user ID. Use this to access the user's isolated database.
|
|
1043
|
+
*
|
|
1044
|
+
* @param c - Hono context
|
|
1045
|
+
* @returns Database ID string (e.g., "user_abc123")
|
|
1046
|
+
* @throws Error if user is not authenticated
|
|
1047
|
+
*
|
|
1048
|
+
* @example
|
|
1049
|
+
* ```typescript
|
|
1050
|
+
* app.get('/api/data', requireAuth(), (c) => {
|
|
1051
|
+
* const dbId = getDatabaseId(c)
|
|
1052
|
+
* const db = await getDatabase(dbId)
|
|
1053
|
+
* // ...
|
|
1054
|
+
* })
|
|
1055
|
+
* ```
|
|
1056
|
+
*/
|
|
1057
|
+
export function getDatabaseId(c: Context): string {
|
|
1058
|
+
const auth = getAuth(c)
|
|
1059
|
+
if (!auth.databaseId) {
|
|
1060
|
+
throw new Error('User not authenticated - no database ID')
|
|
1061
|
+
}
|
|
1062
|
+
return auth.databaseId
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* Gets the Durable Object ID for a user's database.
|
|
1067
|
+
*
|
|
1068
|
+
* @param namespace - Durable Object namespace binding
|
|
1069
|
+
* @param userId - User identifier from JWT
|
|
1070
|
+
* @returns Durable Object ID for the user's database
|
|
1071
|
+
*
|
|
1072
|
+
* @example
|
|
1073
|
+
* ```typescript
|
|
1074
|
+
* const doId = getUserDOId(env.POSTGRES_DO, user.id)
|
|
1075
|
+
* const stub = env.POSTGRES_DO.get(doId)
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
export function getUserDOId(namespace: DurableObjectNamespace, userId: string): DurableObjectId {
|
|
1079
|
+
const databaseId = generateDatabaseId(userId)
|
|
1080
|
+
return namespace.idFromName(databaseId)
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Gets a Durable Object stub for a user's database.
|
|
1085
|
+
*
|
|
1086
|
+
* Convenience function that combines getUserDOId and namespace.get().
|
|
1087
|
+
*
|
|
1088
|
+
* @param namespace - Durable Object namespace binding
|
|
1089
|
+
* @param userId - User identifier from JWT
|
|
1090
|
+
* @returns Durable Object stub for the user's database
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* ```typescript
|
|
1094
|
+
* const stub = getUserDOStub(env.POSTGRES_DO, user.id)
|
|
1095
|
+
* const response = await stub.fetch(request)
|
|
1096
|
+
* ```
|
|
1097
|
+
*/
|
|
1098
|
+
export function getUserDOStub(
|
|
1099
|
+
namespace: DurableObjectNamespace,
|
|
1100
|
+
userId: string
|
|
1101
|
+
): DurableObjectStub {
|
|
1102
|
+
const id = getUserDOId(namespace, userId)
|
|
1103
|
+
return namespace.get(id)
|
|
1104
|
+
}
|