@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,1701 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Warm WASM Loader Pattern
|
|
3
|
+
*
|
|
4
|
+
* Tests cover:
|
|
5
|
+
* - Singleton pattern within isolate
|
|
6
|
+
* - Cold start initialization
|
|
7
|
+
* - Warm start (cached instance) retrieval
|
|
8
|
+
* - Statistics tracking
|
|
9
|
+
* - Reset functionality
|
|
10
|
+
* - Concurrent access handling
|
|
11
|
+
* - Error handling and recovery
|
|
12
|
+
* - Resource cleanup
|
|
13
|
+
*
|
|
14
|
+
* @module pglite/warm-loader.test
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
18
|
+
import {
|
|
19
|
+
createWarmPGliteLoader,
|
|
20
|
+
type WarmPGliteLoader,
|
|
21
|
+
type WarmLoaderConfig,
|
|
22
|
+
type WarmLoaderStats,
|
|
23
|
+
} from './warm-loader'
|
|
24
|
+
import type { PGlite } from '@dotdo/pglite'
|
|
25
|
+
import {
|
|
26
|
+
delay,
|
|
27
|
+
createMockWasmModule,
|
|
28
|
+
createMockFsBundle,
|
|
29
|
+
createMockPGlite as createBaseMockPGlite,
|
|
30
|
+
CI_MULTIPLIER,
|
|
31
|
+
} from '../__tests__/test-utils'
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Mock Factories (using shared utilities + local extensions)
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a mock PGlite instance with full interface for warm-loader tests
|
|
39
|
+
*/
|
|
40
|
+
function createMockPGlite(): PGlite {
|
|
41
|
+
const baseMock = createBaseMockPGlite()
|
|
42
|
+
return {
|
|
43
|
+
...baseMock,
|
|
44
|
+
query: vi.fn().mockResolvedValue({ rows: [], fields: [] }),
|
|
45
|
+
exec: vi.fn().mockResolvedValue([]),
|
|
46
|
+
} as unknown as PGlite
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function createMockConfig(overrides?: Partial<WarmLoaderConfig>): WarmLoaderConfig {
|
|
50
|
+
return {
|
|
51
|
+
wasmModule: createMockWasmModule(),
|
|
52
|
+
fsBundle: createMockFsBundle(),
|
|
53
|
+
...overrides,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Tests
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
describe('WarmPGliteLoader', () => {
|
|
62
|
+
let loader: WarmPGliteLoader
|
|
63
|
+
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
loader = createWarmPGliteLoader()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
afterEach(async () => {
|
|
69
|
+
// Clean up loader instance after each test
|
|
70
|
+
if (loader.isWarm()) {
|
|
71
|
+
await loader.reset()
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// ==========================================================================
|
|
76
|
+
// Singleton Pattern Tests
|
|
77
|
+
// ==========================================================================
|
|
78
|
+
|
|
79
|
+
describe('singleton pattern', () => {
|
|
80
|
+
it('should return same instance across multiple calls', async () => {
|
|
81
|
+
const mockPGlite = createMockPGlite()
|
|
82
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
83
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
84
|
+
const config = createMockConfig()
|
|
85
|
+
|
|
86
|
+
const pglite1 = await loader.get(config)
|
|
87
|
+
const pglite2 = await loader.get(config)
|
|
88
|
+
|
|
89
|
+
expect(pglite1).toBe(pglite2) // reference equality
|
|
90
|
+
await loader.close()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('should only initialize PGlite once per isolate', async () => {
|
|
94
|
+
const mockPGlite = createMockPGlite()
|
|
95
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
96
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
97
|
+
const config = createMockConfig()
|
|
98
|
+
|
|
99
|
+
await loader.get(config)
|
|
100
|
+
await loader.get(config)
|
|
101
|
+
await loader.get(config)
|
|
102
|
+
|
|
103
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
104
|
+
await loader.close()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should handle concurrent initialization requests', async () => {
|
|
108
|
+
const mockPGlite = createMockPGlite()
|
|
109
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
110
|
+
await delay(50) // Simulate slow initialization
|
|
111
|
+
return mockPGlite
|
|
112
|
+
})
|
|
113
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
114
|
+
const config = createMockConfig()
|
|
115
|
+
|
|
116
|
+
const [pglite1, pglite2, pglite3] = await Promise.all([
|
|
117
|
+
loader.get(config),
|
|
118
|
+
loader.get(config),
|
|
119
|
+
loader.get(config),
|
|
120
|
+
])
|
|
121
|
+
|
|
122
|
+
expect(pglite1).toBe(pglite2)
|
|
123
|
+
expect(pglite2).toBe(pglite3)
|
|
124
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
125
|
+
await loader.close()
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('should ignore config on warm start (use original config)', async () => {
|
|
129
|
+
const mockPGlite = createMockPGlite()
|
|
130
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
131
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
132
|
+
|
|
133
|
+
const configA = createMockConfig({ dataDir: 'idb://configA' })
|
|
134
|
+
const configB = createMockConfig({ dataDir: 'idb://configB' })
|
|
135
|
+
|
|
136
|
+
await loader.get(configA)
|
|
137
|
+
await loader.get(configB)
|
|
138
|
+
|
|
139
|
+
// Factory should be called only once with configA
|
|
140
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
141
|
+
expect(factory).toHaveBeenCalledWith(configA)
|
|
142
|
+
await loader.close()
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should maintain singleton across different config objects', async () => {
|
|
146
|
+
const mockPGlite = createMockPGlite()
|
|
147
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
148
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
149
|
+
|
|
150
|
+
// Two structurally identical but different config objects
|
|
151
|
+
const config1 = createMockConfig()
|
|
152
|
+
const config2 = createMockConfig()
|
|
153
|
+
|
|
154
|
+
const pglite1 = await loader.get(config1)
|
|
155
|
+
const pglite2 = await loader.get(config2)
|
|
156
|
+
|
|
157
|
+
expect(pglite1).toBe(pglite2)
|
|
158
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
159
|
+
await loader.close()
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
// ==========================================================================
|
|
164
|
+
// Cold Start Tests
|
|
165
|
+
// ==========================================================================
|
|
166
|
+
|
|
167
|
+
describe('cold start', () => {
|
|
168
|
+
it('should load WASM module on first request', async () => {
|
|
169
|
+
const mockPGlite = createMockPGlite()
|
|
170
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
171
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
172
|
+
const wasmModule = createMockWasmModule()
|
|
173
|
+
const config = createMockConfig({ wasmModule })
|
|
174
|
+
|
|
175
|
+
expect(loader.isWarm()).toBe(false)
|
|
176
|
+
|
|
177
|
+
await loader.get(config)
|
|
178
|
+
|
|
179
|
+
expect(loader.isWarm()).toBe(true)
|
|
180
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ wasmModule }))
|
|
181
|
+
await loader.close()
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('should load filesystem bundle', async () => {
|
|
185
|
+
const mockPGlite = createMockPGlite()
|
|
186
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
187
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
188
|
+
const fsBundle = createMockFsBundle(2048)
|
|
189
|
+
const config = createMockConfig({ fsBundle })
|
|
190
|
+
|
|
191
|
+
await loader.get(config)
|
|
192
|
+
|
|
193
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ fsBundle }))
|
|
194
|
+
await loader.close()
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('should initialize PGlite with provided config', async () => {
|
|
198
|
+
const mockPGlite = createMockPGlite()
|
|
199
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
200
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
201
|
+
const config = createMockConfig({
|
|
202
|
+
dataDir: 'idb://custom',
|
|
203
|
+
readOnly: true,
|
|
204
|
+
pgliteOptions: { debug: 1 },
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
await loader.get(config)
|
|
208
|
+
|
|
209
|
+
expect(factory).toHaveBeenCalledWith(
|
|
210
|
+
expect.objectContaining({
|
|
211
|
+
dataDir: 'idb://custom',
|
|
212
|
+
readOnly: true,
|
|
213
|
+
pgliteOptions: { debug: 1 },
|
|
214
|
+
})
|
|
215
|
+
)
|
|
216
|
+
await loader.close()
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should report cold start in stats', async () => {
|
|
220
|
+
const mockPGlite = createMockPGlite()
|
|
221
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
222
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
223
|
+
const config = createMockConfig()
|
|
224
|
+
|
|
225
|
+
await loader.get(config)
|
|
226
|
+
const stats = loader.getStats()
|
|
227
|
+
|
|
228
|
+
expect(stats.coldStarts).toBe(1)
|
|
229
|
+
expect(stats.warmStarts).toBe(0)
|
|
230
|
+
await loader.close()
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('should handle ArrayBuffer fsBundle', async () => {
|
|
234
|
+
const mockPGlite = createMockPGlite()
|
|
235
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
236
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
237
|
+
const fsBundle = new ArrayBuffer(1024)
|
|
238
|
+
const config = createMockConfig({ fsBundle })
|
|
239
|
+
|
|
240
|
+
const pglite = await loader.get(config)
|
|
241
|
+
|
|
242
|
+
expect(pglite).toBe(mockPGlite)
|
|
243
|
+
await loader.close()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('should handle Blob fsBundle', async () => {
|
|
247
|
+
const mockPGlite = createMockPGlite()
|
|
248
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
249
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
250
|
+
const fsBundle = new Blob([new ArrayBuffer(1024)])
|
|
251
|
+
const config: WarmLoaderConfig = {
|
|
252
|
+
wasmModule: createMockWasmModule(),
|
|
253
|
+
fsBundle,
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const pglite = await loader.get(config)
|
|
257
|
+
|
|
258
|
+
expect(pglite).toBe(mockPGlite)
|
|
259
|
+
await loader.close()
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('should initialize with extensions when provided', async () => {
|
|
263
|
+
const mockPGlite = createMockPGlite()
|
|
264
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
265
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
266
|
+
const extensions = { vector: {}, pgcrypto: {} }
|
|
267
|
+
const config = createMockConfig({ extensions })
|
|
268
|
+
|
|
269
|
+
await loader.get(config)
|
|
270
|
+
|
|
271
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ extensions }))
|
|
272
|
+
await loader.close()
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('should use default options when not specified', async () => {
|
|
276
|
+
const mockPGlite = createMockPGlite()
|
|
277
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
278
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
279
|
+
const config = createMockConfig() // minimal config
|
|
280
|
+
|
|
281
|
+
await loader.get(config)
|
|
282
|
+
|
|
283
|
+
// Factory should be called with the minimal config (defaults handled inside factory)
|
|
284
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
285
|
+
const calledConfig = factory.mock.calls[0][0]
|
|
286
|
+
expect(calledConfig.wasmModule).toBeDefined()
|
|
287
|
+
expect(calledConfig.fsBundle).toBeDefined()
|
|
288
|
+
await loader.close()
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
it('should timeout if initialization takes too long', async () => {
|
|
292
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
293
|
+
await delay(500) // Slow initialization
|
|
294
|
+
return createMockPGlite()
|
|
295
|
+
})
|
|
296
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
297
|
+
const config = createMockConfig({ initTimeoutMs: 50 }) // Short timeout
|
|
298
|
+
|
|
299
|
+
await expect(loader.get(config)).rejects.toThrow(/timed out/)
|
|
300
|
+
|
|
301
|
+
// Loader should be in clean state (can retry)
|
|
302
|
+
expect(loader.isWarm()).toBe(false)
|
|
303
|
+
await loader.close()
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should track initialization duration accurately', async () => {
|
|
307
|
+
const initDelay = 50
|
|
308
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
309
|
+
await delay(initDelay)
|
|
310
|
+
return createMockPGlite()
|
|
311
|
+
})
|
|
312
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
313
|
+
const config = createMockConfig()
|
|
314
|
+
|
|
315
|
+
await loader.get(config)
|
|
316
|
+
const stats = loader.getStats()
|
|
317
|
+
|
|
318
|
+
// Should be close to initDelay (with some tolerance)
|
|
319
|
+
expect(stats.lastInitDurationMs).toBeGreaterThanOrEqual(initDelay - 10)
|
|
320
|
+
expect(stats.lastInitDurationMs).toBeLessThan(initDelay + 100)
|
|
321
|
+
await loader.close()
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
// ==========================================================================
|
|
326
|
+
// Warm Start Tests
|
|
327
|
+
// ==========================================================================
|
|
328
|
+
|
|
329
|
+
describe('warm start', () => {
|
|
330
|
+
it('should return cached instance immediately', async () => {
|
|
331
|
+
const mockPGlite = createMockPGlite()
|
|
332
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
333
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
334
|
+
const config = createMockConfig()
|
|
335
|
+
|
|
336
|
+
const pglite1 = await loader.get(config)
|
|
337
|
+
const pglite2 = await loader.get(config)
|
|
338
|
+
|
|
339
|
+
expect(pglite2).toBe(pglite1)
|
|
340
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
341
|
+
await loader.close()
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('should complete in <1ms for warm starts', async () => {
|
|
345
|
+
const mockPGlite = createMockPGlite()
|
|
346
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
347
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
348
|
+
const config = createMockConfig()
|
|
349
|
+
|
|
350
|
+
// Cold start first
|
|
351
|
+
await loader.get(config)
|
|
352
|
+
|
|
353
|
+
// Warm start timing
|
|
354
|
+
const start = performance.now()
|
|
355
|
+
await loader.get(config)
|
|
356
|
+
const duration = performance.now() - start
|
|
357
|
+
|
|
358
|
+
expect(duration).toBeLessThan(1 * CI_MULTIPLIER)
|
|
359
|
+
await loader.close()
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('should report warm start in stats', async () => {
|
|
363
|
+
const mockPGlite = createMockPGlite()
|
|
364
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
365
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
366
|
+
const config = createMockConfig()
|
|
367
|
+
|
|
368
|
+
await loader.get(config) // cold start
|
|
369
|
+
await loader.get(config) // warm start 1
|
|
370
|
+
await loader.get(config) // warm start 2
|
|
371
|
+
|
|
372
|
+
const stats = loader.getStats()
|
|
373
|
+
expect(stats.coldStarts).toBe(1)
|
|
374
|
+
expect(stats.warmStarts).toBe(2)
|
|
375
|
+
await loader.close()
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('should not re-initialize on warm start', async () => {
|
|
379
|
+
const mockPGlite = createMockPGlite()
|
|
380
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
381
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
382
|
+
const config = createMockConfig()
|
|
383
|
+
|
|
384
|
+
await loader.get(config)
|
|
385
|
+
await loader.get(config)
|
|
386
|
+
await loader.get(config)
|
|
387
|
+
await loader.get(config)
|
|
388
|
+
|
|
389
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
390
|
+
await loader.close()
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('should work correctly after many warm starts', async () => {
|
|
394
|
+
const mockPGlite = createMockPGlite()
|
|
395
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
396
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
397
|
+
const config = createMockConfig()
|
|
398
|
+
|
|
399
|
+
// Cold start
|
|
400
|
+
const first = await loader.get(config)
|
|
401
|
+
|
|
402
|
+
// 999 warm starts
|
|
403
|
+
for (let i = 0; i < 999; i++) {
|
|
404
|
+
const instance = await loader.get(config)
|
|
405
|
+
expect(instance).toBe(first)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const stats = loader.getStats()
|
|
409
|
+
expect(stats.warmStarts).toBe(999)
|
|
410
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
411
|
+
await loader.close()
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
it('should handle warm start during concurrent requests', async () => {
|
|
415
|
+
const mockPGlite = createMockPGlite()
|
|
416
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
417
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
418
|
+
const config = createMockConfig()
|
|
419
|
+
|
|
420
|
+
// Cold start first
|
|
421
|
+
const first = await loader.get(config)
|
|
422
|
+
|
|
423
|
+
// Many concurrent warm starts
|
|
424
|
+
const instances = await Promise.all(
|
|
425
|
+
Array.from({ length: 100 }, () => loader.get(config))
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
instances.forEach((instance) => {
|
|
429
|
+
expect(instance).toBe(first)
|
|
430
|
+
})
|
|
431
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
432
|
+
await loader.close()
|
|
433
|
+
})
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
// ==========================================================================
|
|
437
|
+
// Stats Tests
|
|
438
|
+
// ==========================================================================
|
|
439
|
+
|
|
440
|
+
describe('stats', () => {
|
|
441
|
+
it('should track cold start count', async () => {
|
|
442
|
+
const mockPGlite = createMockPGlite()
|
|
443
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
444
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
445
|
+
const config = createMockConfig()
|
|
446
|
+
|
|
447
|
+
await loader.get(config)
|
|
448
|
+
expect(loader.getStats().coldStarts).toBe(1)
|
|
449
|
+
|
|
450
|
+
await loader.reset()
|
|
451
|
+
await loader.get(config)
|
|
452
|
+
expect(loader.getStats().coldStarts).toBe(2)
|
|
453
|
+
|
|
454
|
+
await loader.reset()
|
|
455
|
+
await loader.get(config)
|
|
456
|
+
expect(loader.getStats().coldStarts).toBe(3)
|
|
457
|
+
|
|
458
|
+
await loader.close()
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it('should track warm start count', async () => {
|
|
462
|
+
const mockPGlite = createMockPGlite()
|
|
463
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
464
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
465
|
+
const config = createMockConfig()
|
|
466
|
+
|
|
467
|
+
await loader.get(config) // cold start
|
|
468
|
+
expect(loader.getStats().warmStarts).toBe(0)
|
|
469
|
+
|
|
470
|
+
await loader.get(config) // warm start 1
|
|
471
|
+
expect(loader.getStats().warmStarts).toBe(1)
|
|
472
|
+
|
|
473
|
+
await loader.get(config) // warm start 2
|
|
474
|
+
expect(loader.getStats().warmStarts).toBe(2)
|
|
475
|
+
|
|
476
|
+
await loader.get(config) // warm start 3
|
|
477
|
+
expect(loader.getStats().warmStarts).toBe(3)
|
|
478
|
+
|
|
479
|
+
await loader.close()
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
it('should track last init duration', async () => {
|
|
483
|
+
const mockPGlite = createMockPGlite()
|
|
484
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
485
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
486
|
+
const config = createMockConfig()
|
|
487
|
+
|
|
488
|
+
await loader.get(config)
|
|
489
|
+
const stats = loader.getStats()
|
|
490
|
+
|
|
491
|
+
expect(stats.lastInitDurationMs).toBeGreaterThan(0)
|
|
492
|
+
expect(stats.lastInitDurationMs).toBeLessThan(1000) // Reasonable upper bound
|
|
493
|
+
await loader.close()
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
it('should track isolate age', async () => {
|
|
497
|
+
const mockPGlite = createMockPGlite()
|
|
498
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
499
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
500
|
+
|
|
501
|
+
const statsInitial = loader.getStats()
|
|
502
|
+
await delay(50)
|
|
503
|
+
const statsAfter = loader.getStats()
|
|
504
|
+
|
|
505
|
+
expect(statsAfter.isolateAgeMs).toBeGreaterThanOrEqual(statsInitial.isolateAgeMs + 40)
|
|
506
|
+
await loader.close()
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
it('should track isolate start time', async () => {
|
|
510
|
+
const now = Date.now()
|
|
511
|
+
const mockPGlite = createMockPGlite()
|
|
512
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
513
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
514
|
+
|
|
515
|
+
const stats = loader.getStats()
|
|
516
|
+
|
|
517
|
+
// Should be close to now (within 100ms)
|
|
518
|
+
expect(stats.isolateStartedAt).toBeGreaterThanOrEqual(now - 100)
|
|
519
|
+
expect(stats.isolateStartedAt).toBeLessThanOrEqual(now + 100)
|
|
520
|
+
await loader.close()
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
it('should track last cold start time', async () => {
|
|
524
|
+
const mockPGlite = createMockPGlite()
|
|
525
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
526
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
527
|
+
const config = createMockConfig()
|
|
528
|
+
|
|
529
|
+
await loader.get(config)
|
|
530
|
+
const firstColdStartAt = loader.getStats().lastColdStartAt
|
|
531
|
+
|
|
532
|
+
await delay(50)
|
|
533
|
+
await loader.reset()
|
|
534
|
+
await loader.get(config)
|
|
535
|
+
const secondColdStartAt = loader.getStats().lastColdStartAt
|
|
536
|
+
|
|
537
|
+
expect(secondColdStartAt).toBeGreaterThan(firstColdStartAt)
|
|
538
|
+
await loader.close()
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
it('should calculate estimated time saved', async () => {
|
|
542
|
+
const initDelay = 20
|
|
543
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
544
|
+
await delay(initDelay)
|
|
545
|
+
return createMockPGlite()
|
|
546
|
+
})
|
|
547
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
548
|
+
const config = createMockConfig()
|
|
549
|
+
|
|
550
|
+
await loader.get(config) // cold start
|
|
551
|
+
await loader.get(config) // warm start 1
|
|
552
|
+
await loader.get(config) // warm start 2
|
|
553
|
+
await loader.get(config) // warm start 3
|
|
554
|
+
|
|
555
|
+
const stats = loader.getStats()
|
|
556
|
+
expect(stats.estimatedTimeSavedMs).toBe(stats.warmStarts * stats.lastInitDurationMs)
|
|
557
|
+
await loader.close()
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
it('should report isWarm correctly in stats', async () => {
|
|
561
|
+
const mockPGlite = createMockPGlite()
|
|
562
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
563
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
564
|
+
const config = createMockConfig()
|
|
565
|
+
|
|
566
|
+
expect(loader.getStats().isWarm).toBe(false)
|
|
567
|
+
|
|
568
|
+
await loader.get(config)
|
|
569
|
+
expect(loader.getStats().isWarm).toBe(true)
|
|
570
|
+
|
|
571
|
+
await loader.reset()
|
|
572
|
+
expect(loader.getStats().isWarm).toBe(false)
|
|
573
|
+
|
|
574
|
+
await loader.close()
|
|
575
|
+
})
|
|
576
|
+
|
|
577
|
+
it('should return snapshot not live reference', async () => {
|
|
578
|
+
const mockPGlite = createMockPGlite()
|
|
579
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
580
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
581
|
+
const config = createMockConfig()
|
|
582
|
+
|
|
583
|
+
await loader.get(config)
|
|
584
|
+
|
|
585
|
+
const stats1 = loader.getStats()
|
|
586
|
+
const originalColdStarts = stats1.coldStarts
|
|
587
|
+
|
|
588
|
+
// Modify the returned object
|
|
589
|
+
stats1.coldStarts = 999
|
|
590
|
+
|
|
591
|
+
// Get stats again - should have original value
|
|
592
|
+
const stats2 = loader.getStats()
|
|
593
|
+
expect(stats2.coldStarts).toBe(originalColdStarts)
|
|
594
|
+
|
|
595
|
+
await loader.close()
|
|
596
|
+
})
|
|
597
|
+
|
|
598
|
+
it('should maintain stats across reset', async () => {
|
|
599
|
+
const mockPGlite = createMockPGlite()
|
|
600
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
601
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
602
|
+
const config = createMockConfig()
|
|
603
|
+
|
|
604
|
+
await loader.get(config) // cold start 1
|
|
605
|
+
await loader.get(config) // warm start 1
|
|
606
|
+
await loader.get(config) // warm start 2
|
|
607
|
+
|
|
608
|
+
await loader.reset()
|
|
609
|
+
|
|
610
|
+
await loader.get(config) // cold start 2
|
|
611
|
+
await loader.get(config) // warm start 3
|
|
612
|
+
|
|
613
|
+
const stats = loader.getStats()
|
|
614
|
+
expect(stats.coldStarts).toBe(2)
|
|
615
|
+
expect(stats.warmStarts).toBe(3)
|
|
616
|
+
|
|
617
|
+
await loader.close()
|
|
618
|
+
})
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
// ==========================================================================
|
|
622
|
+
// Reset Tests
|
|
623
|
+
// ==========================================================================
|
|
624
|
+
|
|
625
|
+
describe('reset', () => {
|
|
626
|
+
it('should allow forced re-initialization', async () => {
|
|
627
|
+
const mockPGlite = createMockPGlite()
|
|
628
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
629
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
630
|
+
const config = createMockConfig()
|
|
631
|
+
|
|
632
|
+
await loader.get(config)
|
|
633
|
+
expect(loader.isWarm()).toBe(true)
|
|
634
|
+
|
|
635
|
+
await loader.reset()
|
|
636
|
+
expect(loader.isWarm()).toBe(false)
|
|
637
|
+
|
|
638
|
+
await loader.get(config) // Should trigger another cold start
|
|
639
|
+
expect(factory).toHaveBeenCalledTimes(2)
|
|
640
|
+
|
|
641
|
+
await loader.close()
|
|
642
|
+
})
|
|
643
|
+
|
|
644
|
+
it('should close existing instance before reset', async () => {
|
|
645
|
+
const mockPGlite = createMockPGlite()
|
|
646
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
647
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
648
|
+
const config = createMockConfig()
|
|
649
|
+
|
|
650
|
+
await loader.get(config)
|
|
651
|
+
await loader.reset()
|
|
652
|
+
|
|
653
|
+
expect(mockPGlite.close).toHaveBeenCalled()
|
|
654
|
+
await loader.close()
|
|
655
|
+
})
|
|
656
|
+
|
|
657
|
+
it('should handle reset when not initialized', async () => {
|
|
658
|
+
const mockPGlite = createMockPGlite()
|
|
659
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
660
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
661
|
+
|
|
662
|
+
// Reset without any get() call
|
|
663
|
+
await expect(loader.reset()).resolves.toBeUndefined()
|
|
664
|
+
expect(loader.isWarm()).toBe(false)
|
|
665
|
+
await loader.close()
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
it('should handle concurrent reset calls', async () => {
|
|
669
|
+
const mockPGlite = createMockPGlite()
|
|
670
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
671
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
672
|
+
const config = createMockConfig()
|
|
673
|
+
|
|
674
|
+
await loader.get(config)
|
|
675
|
+
|
|
676
|
+
// Multiple concurrent resets
|
|
677
|
+
await Promise.all([loader.reset(), loader.reset(), loader.reset()])
|
|
678
|
+
|
|
679
|
+
expect(loader.isWarm()).toBe(false)
|
|
680
|
+
await loader.close()
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
it('should allow new initialization after reset', async () => {
|
|
684
|
+
const mockPGlite1 = createMockPGlite()
|
|
685
|
+
const mockPGlite2 = createMockPGlite()
|
|
686
|
+
let callCount = 0
|
|
687
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
688
|
+
callCount++
|
|
689
|
+
return callCount === 1 ? mockPGlite1 : mockPGlite2
|
|
690
|
+
})
|
|
691
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
692
|
+
|
|
693
|
+
const configA = createMockConfig({ dataDir: 'idb://configA' })
|
|
694
|
+
const configB = createMockConfig({ dataDir: 'idb://configB' })
|
|
695
|
+
|
|
696
|
+
const instance1 = await loader.get(configA)
|
|
697
|
+
expect(instance1).toBe(mockPGlite1)
|
|
698
|
+
|
|
699
|
+
await loader.reset()
|
|
700
|
+
|
|
701
|
+
const instance2 = await loader.get(configB)
|
|
702
|
+
expect(instance2).toBe(mockPGlite2)
|
|
703
|
+
expect(factory).toHaveBeenLastCalledWith(expect.objectContaining({ dataDir: 'idb://configB' }))
|
|
704
|
+
|
|
705
|
+
await loader.close()
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
it('should update stats after reset', async () => {
|
|
709
|
+
const mockPGlite = createMockPGlite()
|
|
710
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
711
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
712
|
+
const config = createMockConfig()
|
|
713
|
+
|
|
714
|
+
await loader.get(config)
|
|
715
|
+
const firstColdStartAt = loader.getStats().lastColdStartAt
|
|
716
|
+
|
|
717
|
+
await delay(20)
|
|
718
|
+
await loader.reset()
|
|
719
|
+
await loader.get(config)
|
|
720
|
+
|
|
721
|
+
const stats = loader.getStats()
|
|
722
|
+
expect(stats.coldStarts).toBe(2)
|
|
723
|
+
expect(stats.lastColdStartAt).toBeGreaterThan(firstColdStartAt)
|
|
724
|
+
|
|
725
|
+
await loader.close()
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
it('should handle reset during initialization', async () => {
|
|
729
|
+
const mockPGlite = createMockPGlite()
|
|
730
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
731
|
+
await delay(100)
|
|
732
|
+
return mockPGlite
|
|
733
|
+
})
|
|
734
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
735
|
+
const config = createMockConfig()
|
|
736
|
+
|
|
737
|
+
// Start initialization
|
|
738
|
+
const getPromise = loader.get(config)
|
|
739
|
+
|
|
740
|
+
// Reset during initialization (should wait for init to complete)
|
|
741
|
+
await delay(10)
|
|
742
|
+
await loader.reset()
|
|
743
|
+
|
|
744
|
+
// The original get should have completed
|
|
745
|
+
await expect(getPromise).resolves.toBe(mockPGlite)
|
|
746
|
+
|
|
747
|
+
// Loader should be in clean state after reset
|
|
748
|
+
expect(loader.isWarm()).toBe(false)
|
|
749
|
+
|
|
750
|
+
await loader.close()
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
it('should handle reset with pending get() calls', async () => {
|
|
754
|
+
const mockPGlite1 = createMockPGlite()
|
|
755
|
+
const mockPGlite2 = createMockPGlite()
|
|
756
|
+
let callCount = 0
|
|
757
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
758
|
+
callCount++
|
|
759
|
+
await delay(50)
|
|
760
|
+
return callCount === 1 ? mockPGlite1 : mockPGlite2
|
|
761
|
+
})
|
|
762
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
763
|
+
const config = createMockConfig()
|
|
764
|
+
|
|
765
|
+
// First get starts initialization
|
|
766
|
+
const get1Promise = loader.get(config)
|
|
767
|
+
|
|
768
|
+
// Reset is called
|
|
769
|
+
await delay(10)
|
|
770
|
+
const resetPromise = loader.reset()
|
|
771
|
+
|
|
772
|
+
// First get should complete with first instance
|
|
773
|
+
const result1 = await get1Promise
|
|
774
|
+
expect(result1).toBe(mockPGlite1)
|
|
775
|
+
|
|
776
|
+
// Wait for reset to complete
|
|
777
|
+
await resetPromise
|
|
778
|
+
|
|
779
|
+
// Subsequent get should trigger new initialization
|
|
780
|
+
const result2 = await loader.get(config)
|
|
781
|
+
expect(result2).toBe(mockPGlite2)
|
|
782
|
+
|
|
783
|
+
await loader.close()
|
|
784
|
+
})
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
// ==========================================================================
|
|
788
|
+
// Error Handling Tests
|
|
789
|
+
// ==========================================================================
|
|
790
|
+
|
|
791
|
+
describe('error handling', () => {
|
|
792
|
+
it('should handle initialization failure', async () => {
|
|
793
|
+
const factory = vi.fn().mockRejectedValue(new Error('Init failed'))
|
|
794
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
795
|
+
const config = createMockConfig()
|
|
796
|
+
|
|
797
|
+
await expect(loader.get(config)).rejects.toThrow('Init failed')
|
|
798
|
+
expect(loader.isWarm()).toBe(false)
|
|
799
|
+
await loader.close()
|
|
800
|
+
})
|
|
801
|
+
|
|
802
|
+
it('should allow retry after initialization failure', async () => {
|
|
803
|
+
const mockPGlite = createMockPGlite()
|
|
804
|
+
let callCount = 0
|
|
805
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
806
|
+
callCount++
|
|
807
|
+
if (callCount === 1) {
|
|
808
|
+
throw new Error('First attempt failed')
|
|
809
|
+
}
|
|
810
|
+
return mockPGlite
|
|
811
|
+
})
|
|
812
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
813
|
+
const config = createMockConfig()
|
|
814
|
+
|
|
815
|
+
// First attempt fails
|
|
816
|
+
await expect(loader.get(config)).rejects.toThrow('First attempt failed')
|
|
817
|
+
|
|
818
|
+
// Second attempt succeeds
|
|
819
|
+
const result = await loader.get(config)
|
|
820
|
+
expect(result).toBe(mockPGlite)
|
|
821
|
+
expect(loader.isWarm()).toBe(true)
|
|
822
|
+
|
|
823
|
+
await loader.close()
|
|
824
|
+
})
|
|
825
|
+
|
|
826
|
+
it('should handle invalid WASM module', async () => {
|
|
827
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
828
|
+
if (!config.wasmModule || Object.keys(config.wasmModule).length === 0) {
|
|
829
|
+
throw new Error('Invalid WASM module')
|
|
830
|
+
}
|
|
831
|
+
return createMockPGlite()
|
|
832
|
+
})
|
|
833
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
834
|
+
const config = createMockConfig({ wasmModule: {} as WebAssembly.Module })
|
|
835
|
+
|
|
836
|
+
await expect(loader.get(config)).rejects.toThrow('Invalid WASM module')
|
|
837
|
+
await loader.close()
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
it('should handle invalid fsBundle', async () => {
|
|
841
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
842
|
+
if (!config.fsBundle || (config.fsBundle as ArrayBuffer).byteLength === 0) {
|
|
843
|
+
throw new Error('Invalid fsBundle')
|
|
844
|
+
}
|
|
845
|
+
return createMockPGlite()
|
|
846
|
+
})
|
|
847
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
848
|
+
const config = createMockConfig({ fsBundle: new ArrayBuffer(0) })
|
|
849
|
+
|
|
850
|
+
await expect(loader.get(config)).rejects.toThrow('Invalid fsBundle')
|
|
851
|
+
await loader.close()
|
|
852
|
+
})
|
|
853
|
+
|
|
854
|
+
it('should handle close() failure gracefully', async () => {
|
|
855
|
+
const mockPGlite = createMockPGlite()
|
|
856
|
+
;(mockPGlite.close as ReturnType<typeof vi.fn>).mockRejectedValue(
|
|
857
|
+
new Error('Close failed')
|
|
858
|
+
)
|
|
859
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
860
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
861
|
+
const config = createMockConfig()
|
|
862
|
+
|
|
863
|
+
await loader.get(config)
|
|
864
|
+
|
|
865
|
+
// Reset should complete even if close fails
|
|
866
|
+
await expect(loader.reset()).resolves.toBeUndefined()
|
|
867
|
+
expect(loader.isWarm()).toBe(false)
|
|
868
|
+
|
|
869
|
+
await loader.close()
|
|
870
|
+
})
|
|
871
|
+
|
|
872
|
+
it('should handle concurrent get() when one fails', async () => {
|
|
873
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
874
|
+
await delay(50)
|
|
875
|
+
throw new Error('Init failed for all')
|
|
876
|
+
})
|
|
877
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
878
|
+
const config = createMockConfig()
|
|
879
|
+
|
|
880
|
+
// Multiple concurrent get() calls
|
|
881
|
+
const results = await Promise.allSettled([
|
|
882
|
+
loader.get(config),
|
|
883
|
+
loader.get(config),
|
|
884
|
+
loader.get(config),
|
|
885
|
+
])
|
|
886
|
+
|
|
887
|
+
// All should fail with the same error
|
|
888
|
+
results.forEach((result) => {
|
|
889
|
+
expect(result.status).toBe('rejected')
|
|
890
|
+
if (result.status === 'rejected') {
|
|
891
|
+
expect(result.reason.message).toBe('Init failed for all')
|
|
892
|
+
}
|
|
893
|
+
})
|
|
894
|
+
|
|
895
|
+
await loader.close()
|
|
896
|
+
})
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
// ==========================================================================
|
|
900
|
+
// Close Tests
|
|
901
|
+
// ==========================================================================
|
|
902
|
+
|
|
903
|
+
describe('close', () => {
|
|
904
|
+
it('should close PGlite instance', async () => {
|
|
905
|
+
const mockPGlite = createMockPGlite()
|
|
906
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
907
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
908
|
+
const config = createMockConfig()
|
|
909
|
+
|
|
910
|
+
await loader.get(config)
|
|
911
|
+
await loader.close()
|
|
912
|
+
|
|
913
|
+
expect(mockPGlite.close).toHaveBeenCalled()
|
|
914
|
+
})
|
|
915
|
+
|
|
916
|
+
it('should prevent further get() calls after close', async () => {
|
|
917
|
+
const mockPGlite = createMockPGlite()
|
|
918
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
919
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
920
|
+
const config = createMockConfig()
|
|
921
|
+
|
|
922
|
+
await loader.get(config)
|
|
923
|
+
await loader.close()
|
|
924
|
+
|
|
925
|
+
await expect(loader.get(config)).rejects.toThrow('Loader is closed')
|
|
926
|
+
})
|
|
927
|
+
|
|
928
|
+
it('should handle close when not initialized', async () => {
|
|
929
|
+
const mockPGlite = createMockPGlite()
|
|
930
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
931
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
932
|
+
|
|
933
|
+
// Close without any get() call
|
|
934
|
+
await expect(loader.close()).resolves.toBeUndefined()
|
|
935
|
+
})
|
|
936
|
+
|
|
937
|
+
it('should handle multiple close() calls', async () => {
|
|
938
|
+
const mockPGlite = createMockPGlite()
|
|
939
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
940
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
941
|
+
const config = createMockConfig()
|
|
942
|
+
|
|
943
|
+
await loader.get(config)
|
|
944
|
+
await loader.close()
|
|
945
|
+
await loader.close()
|
|
946
|
+
await loader.close()
|
|
947
|
+
|
|
948
|
+
// Should not throw, idempotent
|
|
949
|
+
expect(mockPGlite.close).toHaveBeenCalledTimes(1)
|
|
950
|
+
})
|
|
951
|
+
|
|
952
|
+
it('should reject pending get() calls on close', async () => {
|
|
953
|
+
const mockPGlite = createMockPGlite()
|
|
954
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
955
|
+
await delay(100)
|
|
956
|
+
return mockPGlite
|
|
957
|
+
})
|
|
958
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
959
|
+
const config = createMockConfig()
|
|
960
|
+
|
|
961
|
+
// Start slow initialization
|
|
962
|
+
const getPromise = loader.get(config)
|
|
963
|
+
|
|
964
|
+
// Close during initialization
|
|
965
|
+
await delay(10)
|
|
966
|
+
await loader.close()
|
|
967
|
+
|
|
968
|
+
// The get should have completed before close finished waiting
|
|
969
|
+
// (close waits for pending initialization)
|
|
970
|
+
const result = await getPromise
|
|
971
|
+
expect(result).toBe(mockPGlite)
|
|
972
|
+
|
|
973
|
+
// But further calls should fail
|
|
974
|
+
await expect(loader.get(config)).rejects.toThrow('Loader is closed')
|
|
975
|
+
})
|
|
976
|
+
})
|
|
977
|
+
|
|
978
|
+
// ==========================================================================
|
|
979
|
+
// Concurrency Tests
|
|
980
|
+
// ==========================================================================
|
|
981
|
+
|
|
982
|
+
describe('concurrency', () => {
|
|
983
|
+
it('should serialize initialization requests', async () => {
|
|
984
|
+
const mockPGlite = createMockPGlite()
|
|
985
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
986
|
+
await delay(50)
|
|
987
|
+
return mockPGlite
|
|
988
|
+
})
|
|
989
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
990
|
+
const config = createMockConfig()
|
|
991
|
+
|
|
992
|
+
// Many concurrent get() calls
|
|
993
|
+
const promises = Array.from({ length: 10 }, () => loader.get(config))
|
|
994
|
+
const results = await Promise.all(promises)
|
|
995
|
+
|
|
996
|
+
// All should get the same instance
|
|
997
|
+
results.forEach((result) => expect(result).toBe(mockPGlite))
|
|
998
|
+
|
|
999
|
+
// Factory should only be called once
|
|
1000
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
1001
|
+
|
|
1002
|
+
await loader.close()
|
|
1003
|
+
})
|
|
1004
|
+
|
|
1005
|
+
it('should not deadlock under high concurrency', async () => {
|
|
1006
|
+
const mockPGlite = createMockPGlite()
|
|
1007
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1008
|
+
await delay(5)
|
|
1009
|
+
return mockPGlite
|
|
1010
|
+
})
|
|
1011
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1012
|
+
const config = createMockConfig()
|
|
1013
|
+
|
|
1014
|
+
// Many concurrent operations
|
|
1015
|
+
const operations: Promise<unknown>[] = []
|
|
1016
|
+
for (let i = 0; i < 20; i++) {
|
|
1017
|
+
operations.push(loader.get(config))
|
|
1018
|
+
if (i % 5 === 0) {
|
|
1019
|
+
operations.push(loader.reset())
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// All should complete without hanging (timeout would fail the test)
|
|
1024
|
+
await Promise.all(operations)
|
|
1025
|
+
|
|
1026
|
+
await loader.close()
|
|
1027
|
+
})
|
|
1028
|
+
|
|
1029
|
+
it('should handle interleaved get/reset calls', async () => {
|
|
1030
|
+
const mockPGlite = createMockPGlite()
|
|
1031
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1032
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1033
|
+
const config = createMockConfig()
|
|
1034
|
+
|
|
1035
|
+
// Rapid get/reset pattern
|
|
1036
|
+
await loader.get(config)
|
|
1037
|
+
await loader.reset()
|
|
1038
|
+
await loader.get(config)
|
|
1039
|
+
await loader.reset()
|
|
1040
|
+
await loader.get(config)
|
|
1041
|
+
await loader.reset()
|
|
1042
|
+
await loader.get(config)
|
|
1043
|
+
|
|
1044
|
+
// Should complete without errors
|
|
1045
|
+
expect(factory).toHaveBeenCalledTimes(4)
|
|
1046
|
+
expect(loader.isWarm()).toBe(true)
|
|
1047
|
+
|
|
1048
|
+
await loader.close()
|
|
1049
|
+
})
|
|
1050
|
+
|
|
1051
|
+
it('should handle get() during reset()', async () => {
|
|
1052
|
+
const mockPGlite1 = createMockPGlite()
|
|
1053
|
+
const mockPGlite2 = createMockPGlite()
|
|
1054
|
+
let callCount = 0
|
|
1055
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1056
|
+
callCount++
|
|
1057
|
+
await delay(30)
|
|
1058
|
+
return callCount === 1 ? mockPGlite1 : mockPGlite2
|
|
1059
|
+
})
|
|
1060
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1061
|
+
const config = createMockConfig()
|
|
1062
|
+
|
|
1063
|
+
// Get first instance
|
|
1064
|
+
await loader.get(config)
|
|
1065
|
+
|
|
1066
|
+
// Start reset (which will wait for any pending init)
|
|
1067
|
+
const resetPromise = loader.reset()
|
|
1068
|
+
|
|
1069
|
+
// Immediately try to get (should wait for reset then trigger new init)
|
|
1070
|
+
await resetPromise
|
|
1071
|
+
|
|
1072
|
+
// Now get should trigger new initialization
|
|
1073
|
+
const result = await loader.get(config)
|
|
1074
|
+
expect(result).toBe(mockPGlite2)
|
|
1075
|
+
|
|
1076
|
+
await loader.close()
|
|
1077
|
+
})
|
|
1078
|
+
})
|
|
1079
|
+
|
|
1080
|
+
// ==========================================================================
|
|
1081
|
+
// Memory Pressure Handling Tests
|
|
1082
|
+
// ==========================================================================
|
|
1083
|
+
|
|
1084
|
+
describe('memory pressure handling', () => {
|
|
1085
|
+
it('should handle simulated memory pressure during WASM loading', async () => {
|
|
1086
|
+
const mockPGlite = createMockPGlite()
|
|
1087
|
+
let attemptCount = 0
|
|
1088
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1089
|
+
attemptCount++
|
|
1090
|
+
if (attemptCount === 1) {
|
|
1091
|
+
// Simulate memory pressure on first attempt
|
|
1092
|
+
const memoryError = new Error('WebAssembly.Memory(): could not allocate memory')
|
|
1093
|
+
memoryError.name = 'RangeError'
|
|
1094
|
+
throw memoryError
|
|
1095
|
+
}
|
|
1096
|
+
return mockPGlite
|
|
1097
|
+
})
|
|
1098
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1099
|
+
const config = createMockConfig()
|
|
1100
|
+
|
|
1101
|
+
// First attempt fails with memory error
|
|
1102
|
+
await expect(loader.get(config)).rejects.toThrow('could not allocate memory')
|
|
1103
|
+
|
|
1104
|
+
// Retry after memory pressure subsides should succeed
|
|
1105
|
+
const result = await loader.get(config)
|
|
1106
|
+
expect(result).toBe(mockPGlite)
|
|
1107
|
+
expect(attemptCount).toBe(2)
|
|
1108
|
+
await loader.close()
|
|
1109
|
+
})
|
|
1110
|
+
|
|
1111
|
+
it('should track memory-related failures in stats', async () => {
|
|
1112
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1113
|
+
const memoryError = new Error('Out of memory')
|
|
1114
|
+
throw memoryError
|
|
1115
|
+
})
|
|
1116
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1117
|
+
const config = createMockConfig()
|
|
1118
|
+
|
|
1119
|
+
await expect(loader.get(config)).rejects.toThrow('Out of memory')
|
|
1120
|
+
|
|
1121
|
+
const stats = loader.getStats()
|
|
1122
|
+
expect(stats.coldStarts).toBe(0) // Failed initialization doesn't count as cold start
|
|
1123
|
+
expect(loader.isWarm()).toBe(false)
|
|
1124
|
+
await loader.close()
|
|
1125
|
+
})
|
|
1126
|
+
|
|
1127
|
+
it('should handle large WASM modules gracefully', async () => {
|
|
1128
|
+
const mockPGlite = createMockPGlite()
|
|
1129
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1130
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1131
|
+
|
|
1132
|
+
// Simulate a large WASM module (realistic size for PGlite)
|
|
1133
|
+
const largeWasmModule = createMockWasmModule()
|
|
1134
|
+
const largeFsBundle = createMockFsBundle(50 * 1024 * 1024) // 50MB
|
|
1135
|
+
const config = createMockConfig({ wasmModule: largeWasmModule, fsBundle: largeFsBundle })
|
|
1136
|
+
|
|
1137
|
+
const result = await loader.get(config)
|
|
1138
|
+
expect(result).toBe(mockPGlite)
|
|
1139
|
+
expect(loader.isWarm()).toBe(true)
|
|
1140
|
+
await loader.close()
|
|
1141
|
+
})
|
|
1142
|
+
})
|
|
1143
|
+
|
|
1144
|
+
// ==========================================================================
|
|
1145
|
+
// Multiple WASM Module Versions Tests
|
|
1146
|
+
// ==========================================================================
|
|
1147
|
+
|
|
1148
|
+
describe('multiple WASM module versions in same isolate', () => {
|
|
1149
|
+
it('should use original WASM module version after warm start', async () => {
|
|
1150
|
+
const mockPGlite1 = createMockPGlite()
|
|
1151
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite1)
|
|
1152
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1153
|
+
|
|
1154
|
+
const wasmModuleV1 = createMockWasmModule()
|
|
1155
|
+
const wasmModuleV2 = createMockWasmModule()
|
|
1156
|
+
|
|
1157
|
+
// Initialize with v1
|
|
1158
|
+
const configV1 = createMockConfig({ wasmModule: wasmModuleV1 })
|
|
1159
|
+
await loader.get(configV1)
|
|
1160
|
+
|
|
1161
|
+
// Try to get with v2 - should still use v1's cached instance
|
|
1162
|
+
const configV2 = createMockConfig({ wasmModule: wasmModuleV2 })
|
|
1163
|
+
await loader.get(configV2)
|
|
1164
|
+
|
|
1165
|
+
// Factory should only be called once with v1
|
|
1166
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
1167
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ wasmModule: wasmModuleV1 }))
|
|
1168
|
+
await loader.close()
|
|
1169
|
+
})
|
|
1170
|
+
|
|
1171
|
+
it('should allow different WASM version after reset', async () => {
|
|
1172
|
+
const mockPGlite1 = createMockPGlite()
|
|
1173
|
+
const mockPGlite2 = createMockPGlite()
|
|
1174
|
+
let callCount = 0
|
|
1175
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1176
|
+
callCount++
|
|
1177
|
+
return callCount === 1 ? mockPGlite1 : mockPGlite2
|
|
1178
|
+
})
|
|
1179
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1180
|
+
|
|
1181
|
+
const wasmModuleV1 = createMockWasmModule()
|
|
1182
|
+
const wasmModuleV2 = createMockWasmModule()
|
|
1183
|
+
|
|
1184
|
+
// Initialize with v1
|
|
1185
|
+
const configV1 = createMockConfig({ wasmModule: wasmModuleV1 })
|
|
1186
|
+
const instance1 = await loader.get(configV1)
|
|
1187
|
+
expect(instance1).toBe(mockPGlite1)
|
|
1188
|
+
|
|
1189
|
+
// Reset and initialize with v2
|
|
1190
|
+
await loader.reset()
|
|
1191
|
+
const configV2 = createMockConfig({ wasmModule: wasmModuleV2 })
|
|
1192
|
+
const instance2 = await loader.get(configV2)
|
|
1193
|
+
|
|
1194
|
+
expect(instance2).toBe(mockPGlite2)
|
|
1195
|
+
expect(factory).toHaveBeenCalledTimes(2)
|
|
1196
|
+
expect(factory).toHaveBeenLastCalledWith(expect.objectContaining({ wasmModule: wasmModuleV2 }))
|
|
1197
|
+
await loader.close()
|
|
1198
|
+
})
|
|
1199
|
+
|
|
1200
|
+
it('should isolate different loader instances with different WASM versions', async () => {
|
|
1201
|
+
const mockPGlite1 = createMockPGlite()
|
|
1202
|
+
const mockPGlite2 = createMockPGlite()
|
|
1203
|
+
const factory1 = vi.fn().mockResolvedValue(mockPGlite1)
|
|
1204
|
+
const factory2 = vi.fn().mockResolvedValue(mockPGlite2)
|
|
1205
|
+
|
|
1206
|
+
const loader1 = createWarmPGliteLoader({ pgliteFactory: factory1 })
|
|
1207
|
+
const loader2 = createWarmPGliteLoader({ pgliteFactory: factory2 })
|
|
1208
|
+
|
|
1209
|
+
const wasmModuleV1 = createMockWasmModule()
|
|
1210
|
+
const wasmModuleV2 = createMockWasmModule()
|
|
1211
|
+
|
|
1212
|
+
const configV1 = createMockConfig({ wasmModule: wasmModuleV1 })
|
|
1213
|
+
const configV2 = createMockConfig({ wasmModule: wasmModuleV2 })
|
|
1214
|
+
|
|
1215
|
+
const instance1 = await loader1.get(configV1)
|
|
1216
|
+
const instance2 = await loader2.get(configV2)
|
|
1217
|
+
|
|
1218
|
+
expect(instance1).toBe(mockPGlite1)
|
|
1219
|
+
expect(instance2).toBe(mockPGlite2)
|
|
1220
|
+
expect(factory1).toHaveBeenCalledWith(expect.objectContaining({ wasmModule: wasmModuleV1 }))
|
|
1221
|
+
expect(factory2).toHaveBeenCalledWith(expect.objectContaining({ wasmModule: wasmModuleV2 }))
|
|
1222
|
+
|
|
1223
|
+
await loader1.close()
|
|
1224
|
+
await loader2.close()
|
|
1225
|
+
})
|
|
1226
|
+
})
|
|
1227
|
+
|
|
1228
|
+
// ==========================================================================
|
|
1229
|
+
// Extension Loading Failures Tests
|
|
1230
|
+
// ==========================================================================
|
|
1231
|
+
|
|
1232
|
+
describe('extension loading failures', () => {
|
|
1233
|
+
it('should handle extension loading failure gracefully', async () => {
|
|
1234
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1235
|
+
if (config.extensions && Object.keys(config.extensions).length > 0) {
|
|
1236
|
+
throw new Error('Failed to load extension: vector')
|
|
1237
|
+
}
|
|
1238
|
+
return createMockPGlite()
|
|
1239
|
+
})
|
|
1240
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1241
|
+
const config = createMockConfig({ extensions: { vector: {} } })
|
|
1242
|
+
|
|
1243
|
+
await expect(loader.get(config)).rejects.toThrow('Failed to load extension: vector')
|
|
1244
|
+
expect(loader.isWarm()).toBe(false)
|
|
1245
|
+
await loader.close()
|
|
1246
|
+
})
|
|
1247
|
+
|
|
1248
|
+
it('should allow retry after extension loading failure', async () => {
|
|
1249
|
+
const mockPGlite = createMockPGlite()
|
|
1250
|
+
let callCount = 0
|
|
1251
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1252
|
+
callCount++
|
|
1253
|
+
if (callCount === 1 && config.extensions?.vector) {
|
|
1254
|
+
throw new Error('Extension vector not available')
|
|
1255
|
+
}
|
|
1256
|
+
return mockPGlite
|
|
1257
|
+
})
|
|
1258
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1259
|
+
|
|
1260
|
+
// First attempt with extension fails
|
|
1261
|
+
const configWithExt = createMockConfig({ extensions: { vector: {} } })
|
|
1262
|
+
await expect(loader.get(configWithExt)).rejects.toThrow('Extension vector not available')
|
|
1263
|
+
|
|
1264
|
+
// Second attempt without extension succeeds
|
|
1265
|
+
const configWithoutExt = createMockConfig()
|
|
1266
|
+
const result = await loader.get(configWithoutExt)
|
|
1267
|
+
expect(result).toBe(mockPGlite)
|
|
1268
|
+
await loader.close()
|
|
1269
|
+
})
|
|
1270
|
+
|
|
1271
|
+
it('should handle partial extension loading (some succeed, some fail)', async () => {
|
|
1272
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1273
|
+
if (config.extensions?.badExtension) {
|
|
1274
|
+
throw new Error('Extension badExtension failed to load')
|
|
1275
|
+
}
|
|
1276
|
+
return createMockPGlite()
|
|
1277
|
+
})
|
|
1278
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1279
|
+
|
|
1280
|
+
// Config with problematic extension
|
|
1281
|
+
const config = createMockConfig({
|
|
1282
|
+
extensions: { pgcrypto: {}, badExtension: {} },
|
|
1283
|
+
})
|
|
1284
|
+
|
|
1285
|
+
await expect(loader.get(config)).rejects.toThrow('Extension badExtension failed to load')
|
|
1286
|
+
expect(loader.isWarm()).toBe(false)
|
|
1287
|
+
await loader.close()
|
|
1288
|
+
})
|
|
1289
|
+
|
|
1290
|
+
it('should handle extension initialization timeout', async () => {
|
|
1291
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1292
|
+
if (config.extensions?.slowExtension) {
|
|
1293
|
+
await delay(500) // Simulate slow extension loading
|
|
1294
|
+
}
|
|
1295
|
+
return createMockPGlite()
|
|
1296
|
+
})
|
|
1297
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1298
|
+
const config = createMockConfig({
|
|
1299
|
+
extensions: { slowExtension: {} },
|
|
1300
|
+
initTimeoutMs: 50, // Short timeout
|
|
1301
|
+
})
|
|
1302
|
+
|
|
1303
|
+
await expect(loader.get(config)).rejects.toThrow(/timed out/)
|
|
1304
|
+
expect(loader.isWarm()).toBe(false)
|
|
1305
|
+
await loader.close()
|
|
1306
|
+
})
|
|
1307
|
+
|
|
1308
|
+
it('should handle extension with invalid WASM module', async () => {
|
|
1309
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1310
|
+
if (config.extensions?.corruptExtension) {
|
|
1311
|
+
const error = new Error('WebAssembly.instantiate(): invalid module')
|
|
1312
|
+
error.name = 'CompileError'
|
|
1313
|
+
throw error
|
|
1314
|
+
}
|
|
1315
|
+
return createMockPGlite()
|
|
1316
|
+
})
|
|
1317
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1318
|
+
const config = createMockConfig({
|
|
1319
|
+
extensions: { corruptExtension: {} },
|
|
1320
|
+
})
|
|
1321
|
+
|
|
1322
|
+
await expect(loader.get(config)).rejects.toThrow('invalid module')
|
|
1323
|
+
expect(loader.isWarm()).toBe(false)
|
|
1324
|
+
await loader.close()
|
|
1325
|
+
})
|
|
1326
|
+
})
|
|
1327
|
+
|
|
1328
|
+
// ==========================================================================
|
|
1329
|
+
// Graceful Degradation Tests
|
|
1330
|
+
// ==========================================================================
|
|
1331
|
+
|
|
1332
|
+
describe('graceful degradation when FS bundle is missing', () => {
|
|
1333
|
+
it('should handle undefined fsBundle in config', async () => {
|
|
1334
|
+
const mockPGlite = createMockPGlite()
|
|
1335
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1336
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1337
|
+
const config: WarmLoaderConfig = {
|
|
1338
|
+
wasmModule: createMockWasmModule(),
|
|
1339
|
+
fsBundle: undefined,
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
const result = await loader.get(config)
|
|
1343
|
+
expect(result).toBe(mockPGlite)
|
|
1344
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ fsBundle: undefined }))
|
|
1345
|
+
await loader.close()
|
|
1346
|
+
})
|
|
1347
|
+
|
|
1348
|
+
it('should handle null fsBundle gracefully', async () => {
|
|
1349
|
+
const mockPGlite = createMockPGlite()
|
|
1350
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1351
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1352
|
+
const config: WarmLoaderConfig = {
|
|
1353
|
+
wasmModule: createMockWasmModule(),
|
|
1354
|
+
fsBundle: null as unknown as ArrayBuffer,
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// Factory should be called with the null value - how it handles it is up to the implementation
|
|
1358
|
+
const result = await loader.get(config)
|
|
1359
|
+
expect(result).toBe(mockPGlite)
|
|
1360
|
+
await loader.close()
|
|
1361
|
+
})
|
|
1362
|
+
|
|
1363
|
+
it('should fail gracefully when fsBundle fetch fails', async () => {
|
|
1364
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1365
|
+
if (!config.fsBundle || (config.fsBundle as ArrayBuffer).byteLength === 0) {
|
|
1366
|
+
throw new Error('FS bundle required but not provided or empty')
|
|
1367
|
+
}
|
|
1368
|
+
return createMockPGlite()
|
|
1369
|
+
})
|
|
1370
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1371
|
+
const config = createMockConfig({ fsBundle: new ArrayBuffer(0) })
|
|
1372
|
+
|
|
1373
|
+
await expect(loader.get(config)).rejects.toThrow('FS bundle required but not provided or empty')
|
|
1374
|
+
expect(loader.isWarm()).toBe(false)
|
|
1375
|
+
await loader.close()
|
|
1376
|
+
})
|
|
1377
|
+
|
|
1378
|
+
it('should handle corrupted fsBundle data', async () => {
|
|
1379
|
+
const factory = vi.fn().mockImplementation(async (config: WarmLoaderConfig) => {
|
|
1380
|
+
// Simulate validation of fsBundle content
|
|
1381
|
+
if (config.fsBundle instanceof ArrayBuffer) {
|
|
1382
|
+
const view = new Uint8Array(config.fsBundle)
|
|
1383
|
+
// Check for a magic header (simplified validation)
|
|
1384
|
+
if (view.length > 0 && view[0] === 0xFF) {
|
|
1385
|
+
throw new Error('Corrupted FS bundle: invalid header')
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
return createMockPGlite()
|
|
1389
|
+
})
|
|
1390
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1391
|
+
|
|
1392
|
+
// Create an ArrayBuffer with invalid header
|
|
1393
|
+
const corruptedBundle = new ArrayBuffer(1024)
|
|
1394
|
+
const view = new Uint8Array(corruptedBundle)
|
|
1395
|
+
view[0] = 0xFF // Invalid header marker
|
|
1396
|
+
const config = createMockConfig({ fsBundle: corruptedBundle })
|
|
1397
|
+
|
|
1398
|
+
await expect(loader.get(config)).rejects.toThrow('Corrupted FS bundle: invalid header')
|
|
1399
|
+
await loader.close()
|
|
1400
|
+
})
|
|
1401
|
+
})
|
|
1402
|
+
|
|
1403
|
+
// ==========================================================================
|
|
1404
|
+
// Graceful Degradation with Minimal Config Tests
|
|
1405
|
+
// ==========================================================================
|
|
1406
|
+
|
|
1407
|
+
describe('graceful degradation when config is minimal', () => {
|
|
1408
|
+
it('should initialize with only required wasmModule and fsBundle', async () => {
|
|
1409
|
+
const mockPGlite = createMockPGlite()
|
|
1410
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1411
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1412
|
+
const minimalConfig: WarmLoaderConfig = {
|
|
1413
|
+
wasmModule: createMockWasmModule(),
|
|
1414
|
+
fsBundle: createMockFsBundle(),
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
const result = await loader.get(minimalConfig)
|
|
1418
|
+
expect(result).toBe(mockPGlite)
|
|
1419
|
+
expect(loader.isWarm()).toBe(true)
|
|
1420
|
+
await loader.close()
|
|
1421
|
+
})
|
|
1422
|
+
|
|
1423
|
+
it('should use sensible defaults when optional fields are omitted', async () => {
|
|
1424
|
+
const mockPGlite = createMockPGlite()
|
|
1425
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1426
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1427
|
+
const minimalConfig: WarmLoaderConfig = {
|
|
1428
|
+
wasmModule: createMockWasmModule(),
|
|
1429
|
+
fsBundle: createMockFsBundle(),
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
await loader.get(minimalConfig)
|
|
1433
|
+
|
|
1434
|
+
// Factory should be called with the minimal config (defaults applied internally)
|
|
1435
|
+
const calledConfig = factory.mock.calls[0][0]
|
|
1436
|
+
expect(calledConfig.wasmModule).toBeDefined()
|
|
1437
|
+
expect(calledConfig.fsBundle).toBeDefined()
|
|
1438
|
+
// Optional fields should be undefined (not set to invalid values)
|
|
1439
|
+
expect(calledConfig.dataDir).toBeUndefined()
|
|
1440
|
+
expect(calledConfig.readOnly).toBeUndefined()
|
|
1441
|
+
expect(calledConfig.extensions).toBeUndefined()
|
|
1442
|
+
await loader.close()
|
|
1443
|
+
})
|
|
1444
|
+
|
|
1445
|
+
it('should work without pgliteOptions', async () => {
|
|
1446
|
+
const mockPGlite = createMockPGlite()
|
|
1447
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1448
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1449
|
+
const config: WarmLoaderConfig = {
|
|
1450
|
+
wasmModule: createMockWasmModule(),
|
|
1451
|
+
fsBundle: createMockFsBundle(),
|
|
1452
|
+
// pgliteOptions intentionally omitted
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
const result = await loader.get(config)
|
|
1456
|
+
expect(result).toBe(mockPGlite)
|
|
1457
|
+
|
|
1458
|
+
const calledConfig = factory.mock.calls[0][0]
|
|
1459
|
+
expect(calledConfig.pgliteOptions).toBeUndefined()
|
|
1460
|
+
await loader.close()
|
|
1461
|
+
})
|
|
1462
|
+
})
|
|
1463
|
+
|
|
1464
|
+
// ==========================================================================
|
|
1465
|
+
// Integration Scenarios
|
|
1466
|
+
// ==========================================================================
|
|
1467
|
+
|
|
1468
|
+
describe('integration scenarios', () => {
|
|
1469
|
+
it('should work with typical Worker request pattern', async () => {
|
|
1470
|
+
const mockPGlite = createMockPGlite()
|
|
1471
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1472
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1473
|
+
const config = createMockConfig()
|
|
1474
|
+
|
|
1475
|
+
// Simulate multiple Worker requests
|
|
1476
|
+
await loader.get(config) // Request 1 - cold start
|
|
1477
|
+
await loader.get(config) // Request 2 - warm start
|
|
1478
|
+
await loader.get(config) // Request 3 - warm start
|
|
1479
|
+
await loader.get(config) // Request 4 - warm start
|
|
1480
|
+
await loader.get(config) // Request 5 - warm start
|
|
1481
|
+
|
|
1482
|
+
const stats = loader.getStats()
|
|
1483
|
+
expect(stats.coldStarts).toBe(1)
|
|
1484
|
+
expect(stats.warmStarts).toBe(4)
|
|
1485
|
+
expect(factory).toHaveBeenCalledTimes(1)
|
|
1486
|
+
|
|
1487
|
+
await loader.close()
|
|
1488
|
+
})
|
|
1489
|
+
|
|
1490
|
+
it('should handle isolate recycling pattern', async () => {
|
|
1491
|
+
const mockPGlite = createMockPGlite()
|
|
1492
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1493
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1494
|
+
const config = createMockConfig()
|
|
1495
|
+
|
|
1496
|
+
// First isolate lifetime
|
|
1497
|
+
await loader.get(config)
|
|
1498
|
+
await loader.get(config)
|
|
1499
|
+
|
|
1500
|
+
// Simulate isolate recycle
|
|
1501
|
+
await loader.reset()
|
|
1502
|
+
|
|
1503
|
+
// Second isolate lifetime
|
|
1504
|
+
await loader.get(config)
|
|
1505
|
+
await loader.get(config)
|
|
1506
|
+
|
|
1507
|
+
const stats = loader.getStats()
|
|
1508
|
+
expect(stats.coldStarts).toBe(2)
|
|
1509
|
+
expect(stats.warmStarts).toBe(2)
|
|
1510
|
+
|
|
1511
|
+
await loader.close()
|
|
1512
|
+
})
|
|
1513
|
+
|
|
1514
|
+
it('should provide accurate metrics for observability', async () => {
|
|
1515
|
+
const initDelay = 25
|
|
1516
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1517
|
+
await delay(initDelay)
|
|
1518
|
+
return createMockPGlite()
|
|
1519
|
+
})
|
|
1520
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1521
|
+
const config = createMockConfig()
|
|
1522
|
+
|
|
1523
|
+
const startTime = Date.now()
|
|
1524
|
+
|
|
1525
|
+
// Cold start
|
|
1526
|
+
await loader.get(config)
|
|
1527
|
+
const statsAfterCold = loader.getStats()
|
|
1528
|
+
|
|
1529
|
+
expect(statsAfterCold.coldStarts).toBe(1)
|
|
1530
|
+
expect(statsAfterCold.warmStarts).toBe(0)
|
|
1531
|
+
expect(statsAfterCold.lastInitDurationMs).toBeGreaterThanOrEqual(initDelay - 10)
|
|
1532
|
+
expect(statsAfterCold.isWarm).toBe(true)
|
|
1533
|
+
expect(statsAfterCold.isolateStartedAt).toBeLessThanOrEqual(startTime + 100)
|
|
1534
|
+
expect(statsAfterCold.lastColdStartAt).toBeGreaterThanOrEqual(startTime)
|
|
1535
|
+
|
|
1536
|
+
// Warm starts
|
|
1537
|
+
await loader.get(config)
|
|
1538
|
+
await loader.get(config)
|
|
1539
|
+
|
|
1540
|
+
const statsAfterWarm = loader.getStats()
|
|
1541
|
+
expect(statsAfterWarm.warmStarts).toBe(2)
|
|
1542
|
+
expect(statsAfterWarm.estimatedTimeSavedMs).toBe(
|
|
1543
|
+
statsAfterWarm.warmStarts * statsAfterWarm.lastInitDurationMs
|
|
1544
|
+
)
|
|
1545
|
+
expect(statsAfterWarm.isolateAgeMs).toBeGreaterThan(0)
|
|
1546
|
+
|
|
1547
|
+
await loader.close()
|
|
1548
|
+
})
|
|
1549
|
+
|
|
1550
|
+
it('should work with read-only configuration', async () => {
|
|
1551
|
+
const mockPGlite = createMockPGlite()
|
|
1552
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1553
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1554
|
+
const config = createMockConfig({ readOnly: true })
|
|
1555
|
+
|
|
1556
|
+
await loader.get(config)
|
|
1557
|
+
|
|
1558
|
+
expect(factory).toHaveBeenCalledWith(expect.objectContaining({ readOnly: true }))
|
|
1559
|
+
|
|
1560
|
+
await loader.close()
|
|
1561
|
+
})
|
|
1562
|
+
|
|
1563
|
+
it('should work with custom dataDir', async () => {
|
|
1564
|
+
const mockPGlite = createMockPGlite()
|
|
1565
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1566
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1567
|
+
const config = createMockConfig({ dataDir: 'idb://custom-database' })
|
|
1568
|
+
|
|
1569
|
+
await loader.get(config)
|
|
1570
|
+
|
|
1571
|
+
expect(factory).toHaveBeenCalledWith(
|
|
1572
|
+
expect.objectContaining({ dataDir: 'idb://custom-database' })
|
|
1573
|
+
)
|
|
1574
|
+
|
|
1575
|
+
await loader.close()
|
|
1576
|
+
})
|
|
1577
|
+
})
|
|
1578
|
+
})
|
|
1579
|
+
|
|
1580
|
+
// ============================================================================
|
|
1581
|
+
// isWarm Tests (standalone function tests)
|
|
1582
|
+
// ============================================================================
|
|
1583
|
+
|
|
1584
|
+
describe('isWarm', () => {
|
|
1585
|
+
it('should return false on fresh loader', () => {
|
|
1586
|
+
const mockPGlite = createMockPGlite()
|
|
1587
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1588
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1589
|
+
|
|
1590
|
+
expect(loader.isWarm()).toBe(false)
|
|
1591
|
+
})
|
|
1592
|
+
|
|
1593
|
+
it('should return true after successful get()', async () => {
|
|
1594
|
+
const mockPGlite = createMockPGlite()
|
|
1595
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1596
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1597
|
+
const config = createMockConfig()
|
|
1598
|
+
|
|
1599
|
+
await loader.get(config)
|
|
1600
|
+
|
|
1601
|
+
expect(loader.isWarm()).toBe(true)
|
|
1602
|
+
await loader.close()
|
|
1603
|
+
})
|
|
1604
|
+
|
|
1605
|
+
it('should return false after reset()', async () => {
|
|
1606
|
+
const mockPGlite = createMockPGlite()
|
|
1607
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1608
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1609
|
+
const config = createMockConfig()
|
|
1610
|
+
|
|
1611
|
+
await loader.get(config)
|
|
1612
|
+
await loader.reset()
|
|
1613
|
+
|
|
1614
|
+
expect(loader.isWarm()).toBe(false)
|
|
1615
|
+
await loader.close()
|
|
1616
|
+
})
|
|
1617
|
+
|
|
1618
|
+
it('should return false after close()', async () => {
|
|
1619
|
+
const mockPGlite = createMockPGlite()
|
|
1620
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1621
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1622
|
+
const config = createMockConfig()
|
|
1623
|
+
|
|
1624
|
+
await loader.get(config)
|
|
1625
|
+
await loader.close()
|
|
1626
|
+
|
|
1627
|
+
expect(loader.isWarm()).toBe(false)
|
|
1628
|
+
})
|
|
1629
|
+
|
|
1630
|
+
it('should return false during initialization', async () => {
|
|
1631
|
+
const mockPGlite = createMockPGlite()
|
|
1632
|
+
const factory = vi.fn().mockImplementation(async () => {
|
|
1633
|
+
await delay(100)
|
|
1634
|
+
return mockPGlite
|
|
1635
|
+
})
|
|
1636
|
+
const loader = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1637
|
+
const config = createMockConfig()
|
|
1638
|
+
|
|
1639
|
+
// Start initialization but don't await
|
|
1640
|
+
const getPromise = loader.get(config)
|
|
1641
|
+
|
|
1642
|
+
// Check isWarm during initialization
|
|
1643
|
+
expect(loader.isWarm()).toBe(false)
|
|
1644
|
+
|
|
1645
|
+
// Wait for initialization to complete
|
|
1646
|
+
await getPromise
|
|
1647
|
+
|
|
1648
|
+
// Now should be warm
|
|
1649
|
+
expect(loader.isWarm()).toBe(true)
|
|
1650
|
+
|
|
1651
|
+
await loader.close()
|
|
1652
|
+
})
|
|
1653
|
+
})
|
|
1654
|
+
|
|
1655
|
+
// ============================================================================
|
|
1656
|
+
// Factory Function Tests
|
|
1657
|
+
// ============================================================================
|
|
1658
|
+
|
|
1659
|
+
describe('createWarmPGliteLoader', () => {
|
|
1660
|
+
it('should create independent loader instances', async () => {
|
|
1661
|
+
const mockPGlite = createMockPGlite()
|
|
1662
|
+
const factory = vi.fn().mockResolvedValue(mockPGlite)
|
|
1663
|
+
|
|
1664
|
+
const loader1 = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1665
|
+
const loader2 = createWarmPGliteLoader({ pgliteFactory: factory })
|
|
1666
|
+
const config = createMockConfig()
|
|
1667
|
+
|
|
1668
|
+
await loader1.get(config)
|
|
1669
|
+
|
|
1670
|
+
expect(loader1.isWarm()).toBe(true)
|
|
1671
|
+
expect(loader2.isWarm()).toBe(false)
|
|
1672
|
+
|
|
1673
|
+
await loader1.close()
|
|
1674
|
+
await loader2.close()
|
|
1675
|
+
})
|
|
1676
|
+
|
|
1677
|
+
it('should return object with all interface methods', () => {
|
|
1678
|
+
const loader = createWarmPGliteLoader()
|
|
1679
|
+
|
|
1680
|
+
expect(typeof loader.get).toBe('function')
|
|
1681
|
+
expect(typeof loader.isWarm).toBe('function')
|
|
1682
|
+
expect(typeof loader.getStats).toBe('function')
|
|
1683
|
+
expect(typeof loader.reset).toBe('function')
|
|
1684
|
+
expect(typeof loader.close).toBe('function')
|
|
1685
|
+
})
|
|
1686
|
+
|
|
1687
|
+
it('should create loader with clean initial stats', () => {
|
|
1688
|
+
const loader = createWarmPGliteLoader()
|
|
1689
|
+
|
|
1690
|
+
const stats = loader.getStats()
|
|
1691
|
+
|
|
1692
|
+
expect(stats.coldStarts).toBe(0)
|
|
1693
|
+
expect(stats.warmStarts).toBe(0)
|
|
1694
|
+
expect(stats.lastInitDurationMs).toBe(0)
|
|
1695
|
+
expect(stats.lastColdStartAt).toBe(0)
|
|
1696
|
+
expect(stats.isWarm).toBe(false)
|
|
1697
|
+
expect(stats.estimatedTimeSavedMs).toBe(0)
|
|
1698
|
+
expect(stats.isolateStartedAt).toBeGreaterThan(0)
|
|
1699
|
+
expect(stats.isolateAgeMs).toBeGreaterThanOrEqual(0)
|
|
1700
|
+
})
|
|
1701
|
+
})
|